This commit is contained in:
李鹏宇 2026-07-23 16:08:07 +08:00
parent c7ad84f993
commit 1fa24f7558
92 changed files with 888 additions and 424 deletions

View File

@ -194,6 +194,7 @@
transition: all 0.3s ease-in-out;
}
/* 与主题模块冲突强制红色主题会覆盖 Odoo 主题深色模式下的主按钮颜色@image#1:Clipboard_Screenshot.png
.ks_dn_create_chart .modal-footer .btn-primary {
color: var(--ks-dn-white);
background: var(--ks-dn-primary-400);
@ -212,6 +213,7 @@
.ks_dn_create_chart .modal-footer .btn-secondary:hover {
background: var(--ks-dn-gray-200);
}
*/
.ks_dn_create_chart .modal:not([data-bs-backdrop="false"]) {
background-color: transparent;
@ -450,6 +452,7 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele
font-size: 12px;
}
/* 与主题模块冲突强制灰色主题会覆盖 Odoo 主题深色模式下的文件选择按钮颜色@image#1:Clipboard_Screenshot.png
.chart-form-detail .o_select_file_button.btn.btn-primary {
height: 40px;
display: flex;
@ -465,6 +468,7 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele
font-size: 14px;
font-weight: 400;
}
*/
.ks-char-preview .ks-chart-inner,
.ks-modal-body-inner {
@ -935,6 +939,7 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele
font-size: 14px;
}
/* 与主题模块冲突强制红色主题会覆盖 Odoo 主题深色模式下的按钮颜色@image#1:Clipboard_Screenshot.png
.ks_dashboard_header .ks_new_button_div .ks_dashboard_top_menu .ks_date_apply_clear_print .apply-dashboard-date-filter,
.ks_dashboard_top_menu .ks_dashboard_edit_mode_settings .ks_dashboard_save_layout,
.ks_dashboard_top_menu .ks_dashboard_edit_mode_settings .ks_dashboard_create_new_layout,
@ -954,6 +959,7 @@ body:not(.o_touch_device) .o_field_selection:not(:hover):not(:focus-within) sele
border: solid 1px var(--ks-dn-gray-50);
color: var(--ks-dn-black-600);
}
*/
.ks_dashboard_top_menu .ks_dashboard_edit_mode_settings .oe_dashboard_links,
.ks_dashboard_top_menu .ks_dashboard_edit_mode_settings .ks_dashboard_cancel_layout {

View File

@ -269,12 +269,15 @@
.modal-content {
left: auto !important;
border: 1px solid $color-E5E7EB !important;
background-color: $color-F5F8FB;
/* 与主题模块冲突:强制浅灰边框会覆盖主题深色模式下的弹窗边框 (@image#1:Clipboard_Screenshot.png) */
// border: 1px solid $color-E5E7EB !important;
/* 与主题模块冲突:强制浅灰背景会覆盖主题深色模式下的弹窗背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-F5F8FB;
}
.modal-header {
border-bottom: 1px solid $color-E5E7EB !important;
/* 与主题模块冲突:强制浅灰底边框会覆盖主题深色模式下的弹窗标题栏边框 (@image#1:Clipboard_Screenshot.png) */
// border-bottom: 1px solid $color-E5E7EB !important;
}
.chat-ai-box {

View File

@ -1,5 +1,6 @@
.ks_body_class .encapsulated-form-view {
background-color: $color-white !important;
/* 与主题模块冲突:强制白色背景会覆盖主题深色模式下的弹窗表单区域背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-white !important;
padding: 24px 40px !important;
.o_dropdown_button::after {
@ -31,15 +32,17 @@
// buttons
.o_field_domain_dialog_button,
.o_form_button_save {
background-color: $color-primary-main !important;
border: 1px solid $color-primary-main !important;
/* 与主题模块冲突:强制红色主题会覆盖 Odoo 主题按钮颜色 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-primary-main !important;
// border: 1px solid $color-primary-main !important;
border-radius: 10px;
min-height: 40px;
padding: 0 12px;
font-size: $font-16;
font-weight: $f-w-400;
line-height: 19.6px !important;
color: $color-white;
/* 与主题模块冲突:强制白色文字会覆盖主题深色模式下的按钮文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-white;
cursor: pointer;
height: 100%;
@ -71,17 +74,20 @@
font-weight: $f-w-500;
line-height: 19.6px !important;
text-align: left;
color: $color-1E1E1E;
/* 与主题模块冲突:强制深色文字会覆盖主题深色模式下的取消按钮文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-1E1E1E;
border-radius: 8px;
min-height: 35px;
text-align: center;
height: 100%;
padding: 0 20px;
background-color: $color-white;
/* 与主题模块冲突:强制白色背景会覆盖主题深色模式下的取消按钮背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-white;
min-width: 80px;
&:hover {
background-color: $color-secondary-bg;
/* 与主题模块冲突:强制浅色悬停背景会覆盖主题深色模式下的按钮悬停样式 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-secondary-bg;
}
&:focus {
@ -97,15 +103,17 @@
& .btn.btn-primary {
background-color: $color-primary-main !important;
border: 1px solid $color-primary-main !important;
/* 与主题模块冲突:强制红色主题会覆盖 Odoo 主题按钮颜色 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-primary-main !important;
// border: 1px solid $color-primary-main !important;
border-radius: 10px;
min-height: 40px;
padding: 0 12px;
font-size: $font-16;
font-weight: $f-w-400;
line-height: 19.6px;
color: $color-white;
/* 与主题模块冲突:强制白色文字会覆盖主题深色模式下的按钮文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-white;
cursor: pointer;
&:hover {
@ -145,7 +153,8 @@
.o_content {
border: 1px solid $color-E5E7EB;
background-color: $color-F5F8FB !important;
/* 与主题模块冲突:强制浅灰背景会覆盖主题深色模式下的图表内容区域背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-F5F8FB !important;
border-radius: 20px;
padding: 20px 24px !important;
overflow: visible !important;

View File

@ -380,8 +380,7 @@ body.ks_body_class {
}
}
.ks_body_class .dash-btn-red,
.ks_body_class .btn-primary:not(.btn-link) {
.ks_body_class .dash-btn-red {
background-color: $color-primary-main !important;
border: 1px solid $color-primary-main !important;
border-radius: 10px;
@ -414,7 +413,64 @@ body.ks_body_class {
}
}
.ks_body_class .dash-default-btn,
/* 与主题模块冲突.btn-primary 硬编码红色主题会覆盖 Odoo 主题的主按钮颜色@image#1:Clipboard_Screenshot.png
.ks_body_class .btn-primary:not(.btn-link) {
background-color: $color-primary-main !important;
border: 1px solid $color-primary-main !important;
border-radius: 10px;
min-height: 40px;
padding: 0 12px;
text-align: center !important;
font-size: $font-16;
font-weight: $f-w-400;
line-height: 19.6px;
color: $color-white !important;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
width: fit-content;
&.disabled {
opacity: 50%;
pointer-events: none;
cursor: not-allowed;
}
&:focus-visible {
outline: none !important;
}
&:hover {
background-color: $btn-hover !important;
color: $color-white !important;
}
}
*/
.ks_body_class .dash-default-btn {
border: 0.81px solid $color-E5E7EB;
font-size: $font-16;
font-weight: $f-w-500;
line-height: 22.4px;
text-align: left;
color: $color-1E1E1E;
border-radius: 8px;
min-height: 40px;
padding: 0 20px;
background-color: $color-white;
text-align: center;
&:hover {
background-color: $color-secondary-bg !important;
}
&:focus {
border: 1px solid $color-E7495E !important;
}
}
/* 与主题模块冲突.btn-secondary 硬编码白底黑字等样式会覆盖主题深色模式下的按钮样式@image#1:Clipboard_Screenshot.png
.ks_body_class .btn-secondary {
border: 0.81px solid $color-E5E7EB;
font-size: $font-16;
@ -436,6 +492,7 @@ body.ks_body_class {
border: 1px solid $color-E7495E !important;
}
}
*/
.ks_body_class .dash-link {
font-size: $font-16;
@ -713,15 +770,17 @@ body.ks_body_class {
.ks_body_class .o_form_button_save,
.ks_body_class .o_form_button_save_new {
background-color: $color-primary-main;
border: 1px solid $color-primary-main;
/* 与主题模块冲突:强制红色主题会覆盖 Odoo 主题的保存按钮颜色 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-primary-main;
// border: 1px solid $color-primary-main;
border-radius: 10px;
min-height: 40px;
padding: 0 20px;
font-size: $font-14;
font-weight: $f-w-400;
line-height: 19.6px;
color: $color-white;
/* 与主题模块冲突:强制白色文字会覆盖主题深色模式下的保存按钮文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-white;
cursor: pointer;
width: auto !important;
@ -732,8 +791,9 @@ body.ks_body_class {
}
&:hover {
background-color: $btn-hover;
color: $color-white !important;
/* 与主题模块冲突:强制红色悬停背景会覆盖主题深色模式下的按钮悬停样式 (@image#1:Clipboard_Screenshot.png) */
// background-color: $btn-hover;
// color: $color-white !important;
}
@include max-575 {
@ -747,15 +807,18 @@ body.ks_body_class {
font-weight: $f-w-500;
line-height: 22.4px;
text-align: left;
color: $color-1E1E1E;
/* 与主题模块冲突:强制深色文字会覆盖主题深色模式下的取消按钮文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-1E1E1E;
border-radius: 8px;
min-height: 40px;
padding: 0 20px !important;
background-color: $color-white;
/* 与主题模块冲突:强制白色背景会覆盖主题深色模式下的取消按钮背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-white;
width: auto !important;
&:hover {
background-color: $color-secondary-bg;
/* 与主题模块冲突:强制浅色悬停背景会覆盖主题深色模式下的按钮悬停样式 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-secondary-bg;
}
&:focus {
@ -779,13 +842,15 @@ body.ks_body_class {
.modal-header {
padding: 12px 16px;
background-color: $color-bg-main;
/* 与主题模块冲突:强制浅灰背景会覆盖主题深色模式下的弹窗标题栏背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-bg-main;
border-radius: 16px 16px 0 0;
border-bottom: 0;
margin-bottom: 18px;
@include max-575 {
background-color: $color-bg-main !important;
/* 与主题模块冲突:强制浅灰背景会覆盖主题深色模式下的弹窗标题栏背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-bg-main !important;
}
.modal-title {
@ -793,10 +858,12 @@ body.ks_body_class {
font-weight: $f-w-500;
line-height: 22.4px;
text-align: left;
color: $color-black;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的弹窗标题颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
@include max-575 {
color: $color-black !important;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的弹窗标题颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black !important;
}
}
@ -815,7 +882,8 @@ body.ks_body_class {
font-weight: $f-w-500;
line-height: 22.4px;
text-align: center;
color: $color-black;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的弹窗正文颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
}
}
@ -2569,11 +2637,13 @@ body.ks_body_class {
}
.ks_body_class .o_form_button_save.bg-violet {
background-color: $color-6789C6 !important;
border: 1px solid $color-6789C6 !important;
/* 与主题模块冲突:强制紫色主题会覆盖 Odoo 主题按钮颜色 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-6789C6 !important;
// border: 1px solid $color-6789C6 !important;
&:hover {
background-color: $color-597ebe !important;
/* 与主题模块冲突:强制紫色悬停背景会覆盖主题深色模式下的按钮悬停样式 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-597ebe !important;
}
}

View File

@ -14,13 +14,15 @@
.modal-header {
padding: 12px 16px;
background-color: $color-bg-main;
/* 与主题模块冲突:强制浅灰背景会覆盖主题深色模式下的弹窗标题栏背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-bg-main;
border-radius: 16px 16px 0 0;
border-bottom: 0;
justify-content: start !important;
@include max-575 {
background-color: $color-bg-main !important;
/* 与主题模块冲突:强制浅灰背景会覆盖主题深色模式下的弹窗标题栏背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-bg-main !important;
}
.modal-title {
@ -28,10 +30,12 @@
font-weight: $f-w-500;
line-height: 22.4px;
text-align: left;
color: $color-black;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的弹窗标题颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
@include max-575 {
color: $color-black !important;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的弹窗标题颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black !important;
}
}
@ -380,7 +384,8 @@
font-weight: 400;
line-height: 20.99px;
text-align: left;
color: $color-black;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的输入框文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
padding: 12px 10px;
border: 0.91px solid $color-D1D5DB;
border-radius: 8px;
@ -427,8 +432,10 @@
font-weight: $f-w-400;
line-height: 18.52px;
text-align: left;
color: $color-black;
background-color: $color-white !important;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的输入框文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
/* 与主题模块冲突:强制白色背景会覆盖主题深色模式下的输入框背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-white !important;
padding-right: 21px !important;
@ -541,8 +548,10 @@
font-weight: 400;
line-height: 18.52px;
text-align: left;
color: $color-black;
background-color: $color-white !important;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的输入框文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
/* 与主题模块冲突:强制白色背景会覆盖主题深色模式下的输入框背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-white !important;
min-height: 45px;
input {

View File

@ -8,8 +8,10 @@
line-height: 9.66px !important;
letter-spacing: 0.0015em;
text-align: left;
background-color: $color-D9F1FD !important;
color: $color-black !important;
/* 与主题模块冲突:强制浅蓝背景会覆盖主题深色模式下的按钮背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-D9F1FD !important;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的按钮文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black !important;
border: 1px solid transparent !important;
border-radius: 5px;
}
@ -62,7 +64,8 @@
font-weight: $f-w-400;
line-height: 18.52px;
text-align: left;
color: $color-black;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的输入框文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
&::placeholder {
font-size: $font-16;
@ -82,11 +85,13 @@
}
.ks_form_sheet .o_form_sheet{
background: $color-bg-main;
/* 与主题模块冲突:强制浅灰背景会覆盖主题深色模式下的表单页背景 (@image#1:Clipboard_Screenshot.png) */
// background: $color-bg-main;
padding: 16px;
border-radius: 10px;
}
/* 与主题模块冲突.btn-primary 硬编码黑色主题会覆盖 Odoo 主题的主按钮颜色@image#1:Clipboard_Screenshot.png
.upload-file-btn .o_select_file_button.btn-primary{
background-color: $color-black !important;
border: 1px solid transparent !important;
@ -99,6 +104,7 @@
line-height: 21px;
}
}
*/
.top-inverse-5{
top: -5px;

View File

@ -21,10 +21,12 @@
min-height: 76px;
}
background: white;
/* 与主题模块冲突ks_dashboard_ninja 将顶部导航栏设为白色,会覆盖主题深色模式下的背景色,故注释掉 (@image#1:Clipboard_Screenshot.png) */
// background: white;
display: flex;
justify-content: space-between;
border-bottom: 1px solid $color-E5E7EB !important;
/* 与主题模块冲突:白色底部边框在深色模式下会显示为白线,故注释掉 (@image#1:Clipboard_Screenshot.png) */
// border-bottom: 1px solid $color-E5E7EB !important;
.o_menu_sections {
justify-content: center;
@ -81,7 +83,8 @@
}
.o_menu_brand {
color: $color-black;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的导航文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
font-size: $font-22;
font-weight: $f-w-400;
line-height: 30.8px;
@ -129,15 +132,17 @@
font-weight: $f-w-500;
line-height: 32px;
min-width: 52px;
color: $color-black;
/* 与主题模块冲突:强制黑字浅蓝背景会覆盖主题深色模式下头像/用户名样式 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
border-radius: 10px;
background-color: $color-D9F1FD;
// background-color: $color-D9F1FD;
padding: 7px 11px;
@include max-768 {
border-radius: 5px;
border: 0.5px solid var(--Border-Color, #E5E7EB);
background-color: $color-white;
/* 与主题模块冲突:强制白色背景会覆盖主题深色模式下头像样式 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-white;
font-size: $font-12;
font-weight: $f-w-400;
line-height: 14px;
@ -229,12 +234,14 @@
.ks_body_class .o_debug_manager {
button {
color: #241C1D !important;
/* 与主题模块冲突:强制深色文字会覆盖主题深色模式下的图标/文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: #241C1D !important;
}
}
.ks_body_class .oe_topbar_name {
color: #241C1D !important;
/* 与主题模块冲突:强制深色文字会覆盖主题深色模式下的顶部用户名颜色 (@image#1:Clipboard_Screenshot.png) */
// color: #241C1D !important;
}
.ks_body_class .o_switch_company_menu_dropdown {

View File

@ -6,7 +6,8 @@
.modal-header {
padding: 12px 16px;
background-color: $color-bg-main;
/* 与主题模块冲突:强制浅灰背景会覆盖主题深色模式下的弹窗标题栏背景 (@image#1:Clipboard_Screenshot.png) */
// background-color: $color-bg-main;
border-radius: 16px 16px 0 0;
border-bottom: 0;
@ -15,7 +16,8 @@
font-weight: $f-w-500;
line-height: 22.4px;
text-align: left;
color: $color-black;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的弹窗标题颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
}
.btn-close {}
@ -28,14 +30,16 @@
line-height: 9.66px;
letter-spacing: 0.0015em;
text-align: left;
color: $color-black;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的表单标签颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
margin-bottom: 8px;
// &:not(:focus-within) {
// color: $color-danger !important;
// }
&:focus {
border: 1px solid $color-black;
/* 与主题模块冲突:强制黑色边框会覆盖主题深色模式下的焦点样式 (@image#1:Clipboard_Screenshot.png) */
// border: 1px solid $color-black;
}
}
@ -79,7 +83,8 @@
font-weight: $f-w-400;
line-height: 18.52px;
text-align: left;
color: $color-black;
/* 与主题模块冲突:强制黑色文字会覆盖主题深色模式下的输入框文字颜色 (@image#1:Clipboard_Screenshot.png) */
// color: $color-black;
&::placeholder {
font-size: $font-16;

Binary file not shown.

View File

@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import models

View File

@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2025 Sveltware Solutions
{
'name': 'Naver center',
'category': 'Hidden',
'version': '1.0.0',
'author': 'PYSSJKJ',
'depends': ['ks_dashboard_ninja', 'udoo_om_ux'],
'data': [
'views/views.xml',
],
'assets': {
'web.assets_backend': [
'omux_menu_center/static/src/css/*.scss',
'omux_menu_center/static/src/js/*.js'
]
},
'sequence': 0,
'application': True,
'installable': True
}

View File

@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import model

View File

@ -1,44 +0,0 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
from odoo.exceptions import UserError, ValidationError
class CustomConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
status_center = fields.Boolean('顶部导航栏居中', default=True)
def set_values(self):
"""
保存设置值到系统参数
这个方法在用户点击"保存"按钮时调用
"""
res = super(CustomConfigSettings, self).set_values()
self.env['ir.config_parameter'].sudo().set_param(
'omux_menu_center.status_center',
str(self.status_center) # 转换为字符串存储
)
return res
@api.model
def get_values(self):
"""
从系统参数获取设置值
这个方法在打开设置页面时调用
"""
res = super(CustomConfigSettings, self).get_values()
status_center_param = self.env['ir.config_parameter'].sudo().get_param(
'omux_menu_center.status_center',
'True' # 默认值
)
status_center = status_center_param == 'True'
res.update(
status_center=status_center,
)
return res

View File

@ -1,198 +0,0 @@
/** @odoo-module **/
import { patch } from "@web/core/utils/patch";
import { useEffect, onMounted, useState, onWillStart } from "@odoo/owl";
import { NavBar } from "@web/webclient/navbar/navbar";
import { ActionContainer } from "@web/webclient/actions/action_container";
import { useService } from "@web/core/utils/hooks";
import { cookie } from "@web/core/browser/cookie";
export function getCurrentColorScheme() {
const COLOR_SCHEME_COOKIE_NAME = 'color_scheme';
return cookie.get(COLOR_SCHEME_COOKIE_NAME) || 'light';
}
export function dnNavBarAddClasses(){
document.querySelector('body')?.classList.add('ks_body_class');
document.querySelector('.o_main_navbar')?.classList.add('navbar', 'navbar-expand-md');
document.querySelector('.ks-mobile-burger-menu')?.classList.remove('d-none');
document.querySelector('.mobile-burger-menu-default')?.classList.add('d-none');
}
export function themeAddClasses(){
const currentScheme = getCurrentColorScheme();
if(currentScheme == 'dark'){
if (!document.querySelector('body').classList.contains('darkness')){
document.querySelector('body')?.classList.add('darkness');
const message = document.querySelector('.img-bg.d-none.ks-comments-systray img');
if (message) {
message.src = '/yuthon_base/static/src/img/message-notif.svg';
}
const folder = document.querySelector('.img-bg.d-none.ks-mail-systray img');
if (folder) {
folder.src = '/yuthon_base/static/src/img/note-text.svg';
}
}
}
}
export function dnNavBarRemoveClasses(){
document.querySelector('body')?.classList.remove('ks_body_class');
document.querySelector('.o_main_navbar')?.classList.remove('navbar', 'navbar-expand-md');
document.querySelector('.ks-mobile-burger-menu')?.classList.add('d-none');
document.querySelector('.mobile-burger-menu-default')?.classList.remove('d-none');
}
patch(NavBar.prototype, {
setup(){
super.setup();
this.orm = useService('orm')
this.settings = {
'status_center': true
}
onWillStart(async () => {
await this.loadConfigSettings();
});
onMounted(() => {
if(this.settings.status_center){
this.applyStylesToAllPages();
}else{
this.applyStylesToAllPages_not();
}
themeAddClasses()
});
useEffect(() => {
if(this.settings.status_center){
this.applyStylesToAllPages();
}else{
this.applyStylesToAllPages_not();
}
themeAddClasses()
});
},
async adapt(){
const result = await super.adapt();
if(this.settings.status_center){
this.applyStylesToAllPages();
}else{
this.applyStylesToAllPages_not();
}
return result;
},
onNavBarDropdownItemSelection(menu) {
super.onNavBarDropdownItemSelection(menu);
if(this.settings.status_center){
this.applyStylesToAllPages();
}else{
this.applyStylesToAllPages_not();
}
},
applyStylesToAllPages() {
const body = document.body;
if (body && !body.classList.contains('ks_body_class')) {
dnNavBarAddClasses();
}
},
applyStylesToAllPages_not(){
if(this.currentApp?.xmlid === "ks_dashboard_ninja.board_menu_root" || this.actionService?.currentController?.action.tag === 'ks_dashboard_ninja'){
if(!document.querySelector('body').classList.contains('ks_body_class'))
dnNavBarAddClasses();
}
else{
if(document.querySelector('body').classList.contains('ks_body_class'))
dnNavBarRemoveClasses();
}
},
async loadConfigSettings() {
try {
const settings = await this.orm.call(
'res.config.settings',
'get_values',
[]
);
this.settings = {
'status_center': settings.status_center
}
} catch (error) {
console.error('Failed to load settings:', error);
}
}
});
patch(ActionContainer.prototype, {
setup(){
super.setup();
this.settings = {
'status_center': true
}
this.orm = this.env.services.orm;
onWillStart(async () => {
await this.loadConfigSettings();
});
onMounted(() => {
if(this.settings.status_center){
this.applyStylesToAllPages();
}else{
this.applyStylesToAllPages_not();
}
themeAddClasses()
});
useEffect(() => {
if(this.settings.status_center){
this.applyStylesToAllPages();
}else{
this.applyStylesToAllPages_not();
}
themeAddClasses()
});
},
applyStylesToAllPages() {
const body = document.body;
if (body && !body.classList.contains('ks_body_class')) {
dnNavBarAddClasses();
}
},
applyStylesToAllPages_not(){
if(this.currentApp?.xmlid === "ks_dashboard_ninja.board_menu_root" || this.actionService?.currentController?.action.tag === 'ks_dashboard_ninja'){
if(!document.querySelector('body').classList.contains('ks_body_class'))
dnNavBarAddClasses();
}
else{
if(document.querySelector('body').classList.contains('ks_body_class'))
dnNavBarRemoveClasses();
}
},
async loadConfigSettings() {
try {
const settings = await this.orm.call(
'res.config.settings',
'get_values',
[]
);
this.settings = {
'status_center': settings.status_center
}
} catch (error) {
console.error('Failed to load settings:', error);
}
}
});

View File

@ -1,18 +0,0 @@
<odoo>
<data>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.custom_nav</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//block[@name='integration']" position="after">
<block title="顶部菜单" name="top_naver_center">
<setting help="导航栏居中显示" id="cf-custom_nav">
<field name="status_center"/>
</setting>
</block>
</xpath>
</field>
</record>
</data>
</odoo>

Binary file not shown.

Binary file not shown.

View File

@ -10,7 +10,19 @@
],
'assets': {
'web.assets_backend': [
'project_md/static/lib/d3.v7.min.js',
'project_md/static/lib/d3/d3.min.js',
'project_md/static/src/js/mindmap_arch_parser.js',
'project_md/static/src/js/mindmap_controller.js',
'project_md/static/src/js/mindmap_renderer.js',
'project_md/static/src/js/mindmap_view.js',
'project_md/static/src/xml/mindmap_template.xml',
'project_md/static/src/scss/mindmap.scss',
],
# Omux 重定义了 web.assets_web_dark 且不继承 web.assets_backend
# mindmap 视图类型必须在此 bundle 也注册,否则夜色模式下点击导图报错。
# 此为功能注册(非主题美化),不可删除。
'web.assets_web_dark': [
'project_md/static/lib/d3/d3.min.js',
'project_md/static/src/js/mindmap_arch_parser.js',
'project_md/static/src/js/mindmap_controller.js',
'project_md/static/src/js/mindmap_renderer.js',

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2,3 +2,4 @@ from . import mindmap_diagram
from . import mindmap_node
from . import project_task_extend
from . import ir_ui_view_extend
from . import project_mindmap_extend

Binary file not shown.

Binary file not shown.

View File

@ -9,3 +9,12 @@ class IrUiView(models.Model):
selection_add=[('mindmap', 'Mindmap')],
string='View Type',
)
def _get_view_info(self):
# 关键:只 selection_add 不够。get_view_info 只会把
# “既在选择项里、又在 _get_view_info() 字典里”的类型塞进
# session.view_info。若不在此登记 mindmap 的元数据,前端会报
# “View types not defined mindmap”。
res = super()._get_view_info()
res['mindmap'] = {'icon': 'fa fa-sitemap', 'multi_record': True}
return res

View File

@ -0,0 +1,106 @@
from odoo import api, models
class ProjectProject(models.Model):
_inherit = 'project.project'
@api.model
def get_mindmap_tree(self, single_id=None):
"""返回 项目→阶段→任务 的树形结构dict供 mindmap 视图渲染。
不建中间表直接利用已有的
project.project.type_ids阶段/ project.task.project_id / project.task.stage_id
字段是否存在在服务端用 _fields 直接判断杜绝 JS 侧写死字段导致的
Invalid field / 白屏
"""
self = self.sudo()
# 1) 项目(单项目视角则只取当前项目)
proj_domain = [('id', '=', single_id)] if single_id else []
projects = self.search_read(proj_domain, ['name', 'type_ids'])
# 2) 阶段:经各项目 type_ids 收集、保序去重
stage_ids = []
for p in projects:
stage_ids += p['type_ids']
stage_ids = list(dict.fromkeys(stage_ids))
stages = self.env['project.task.type'].search_read(
[('id', 'in', stage_ids)], ['name', 'sequence']
) if stage_ids else []
stage_by_id = {s['id']: s for s in stages}
# 3) 任务:进度字段在部分版本/客制下不存在,服务端安全探测
task_fields = ['name', 'display_name', 'project_id', 'stage_id']
tk = self.env['project.task']
progress_field = None
if 'subtask_completion_percentage' in tk._fields:
progress_field = 'subtask_completion_percentage'
elif 'progress' in tk._fields:
progress_field = 'progress'
if progress_field:
task_fields.append(progress_field)
task_domain = [('project_id', '=', single_id)] if single_id else []
tasks = tk.search_read(task_domain, task_fields)
def _norm(v):
if v is None or v is False:
return 0
try:
v = float(v)
except (TypeError, ValueError):
return 0
# 部分字段存 0-1有的存 0-100统一归一到 0-100
return int(v) if v > 1 else int(v * 100)
project_nodes = {}
for p in projects:
project_nodes[p['id']] = {
'id': 'P%d' % p['id'],
'name': p['name'] or ('项目%s' % p['id']),
'kind': 'project',
'progress': 0,
'children': [],
}
for p in projects:
pn = project_nodes[p['id']]
proj_stages = [stage_by_id[i] for i in p['type_ids'] if i in stage_by_id]
proj_stages.sort(key=lambda s: s.get('sequence') or 0)
for st in proj_stages:
sn = {
'id': 'P%d_S%d' % (p['id'], st['id']),
'name': st['name'],
'kind': 'stage',
'progress': 0,
'children': [],
}
pn['children'].append(sn)
st_tasks = [
t for t in tasks
if t.get('project_id') and t['project_id'][0] == p['id']
and t.get('stage_id') and t['stage_id'][0] == st['id']
]
for t in st_tasks:
raw = t.get(progress_field) if progress_field else None
sn['children'].append({
'id': 'T%d' % t['id'],
'name': t.get('display_name') or t['name'],
'kind': 'task',
'resId': t['id'],
'progress': _norm(raw),
})
sn['progress'] = round(
sum(c['progress'] for c in sn['children']) / len(sn['children'])
) if sn['children'] else 0
pn['progress'] = round(
sum(c['progress'] for c in pn['children']) / len(pn['children'])
) if pn['children'] else 0
roots = list(project_nodes.values())
if single_id and len(roots) == 1:
return roots[0]
return {
'id': 0,
'name': '所有项目' if not single_id else '项目阶段与任务',
'children': roots,
}

2
project_md/static/lib/d3/d3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -16,12 +16,20 @@ export class MindmapController extends Component {
}
async _loadData() {
const resModel = this.props.archInfo.resModel;
const records = await this.orm.searchRead(resModel, [], [
"id", "name", "parent_id", "display_name",
"progress", "user_id", "stage_id", "date_deadline",
]);
this._buildTree(records);
// 取数 + 建树全部下沉到服务端 project.project.get_mindmap_tree
// 服务端用 _fields 安全探测字段存在性,从根上消灭 Invalid field
// 跨模型关联project→type_ids→stage→task也在 Python 侧一次性拼好。
const singleProjectId =
this.props.resModel === "project.project" && this.props.resId
? this.props.resId
: null;
const treeData = await this.orm.call(
"project.project",
"get_mindmap_tree",
[singleProjectId || false]
);
this.state.treeData = treeData;
this.state.loading = false;
}
@ -31,43 +39,25 @@ export class MindmapController extends Component {
};
}
_buildTree(records) {
const map = {};
const roots = [];
for (const rec of records) {
map[rec.id] = {
id: rec.id,
name: rec.display_name || rec.name,
parentId: rec.parent_id ? rec.parent_id[0] : false,
progress: rec.progress || 0,
user_id: rec.user_id ? rec.user_id[1] : "",
stage_id: rec.stage_id ? rec.stage_id[1] : "",
date_deadline: rec.date_deadline || "",
children: [],
};
}
for (const id in map) {
const node = map[id];
if (node.parentId && map[node.parentId]) {
map[node.parentId].children.push(node);
} else {
roots.push(node);
}
}
this.state.treeData =
roots.length === 1
? roots[0]
: { id: 0, name: "全部任务", children: roots };
}
onNodeClicked(ev) {
const resModel = this.props.archInfo.resModel;
const recordId = ev.detail.id;
if (recordId) {
const node = ev.detail.node;
if (!node) return;
let resModel;
let resId;
if (node.kind === "task") {
resModel = "project.task";
resId = node.resId;
} else if (node.kind === "project") {
resModel = "project.project";
resId = Number(String(node.id).replace(/^P/, ""));
} else {
return; // 阶段节点是分组,不导航
}
if (resId) {
this.action.doAction({
type: "ir.actions.act_window",
res_model: resModel,
res_id: recordId,
res_id: resId,
views: [[false, "form"]],
target: "current",
});

View File

@ -4,21 +4,18 @@ import { Component, onMounted, onWillUpdateProps } from "@odoo/owl";
export class MindmapRenderer extends Component {
setup() {
super.setup();
// 真正调用 owl 生命周期钩子,否则 _renderTree 永远不会执行(导图白屏)
onMounted(() => this._renderTree());
onWillUpdateProps(() => {
// 等待 owl 完成 DOM patch 后再重绘 d3避免直接操作 DOM 与 owl 冲突
Promise.resolve().then(() => this._renderTree());
});
}
get treeData() {
return this.props.treeData;
}
onMounted() {
this._renderTree();
}
onWillUpdateProps() {
// 等待 owl 完成 DOM patch 后再重绘 d3避免直接操作 DOM 与 owl 冲突
Promise.resolve().then(() => this._renderTree());
}
_renderTree() {
const d3 = window.d3;
if (!d3) {
@ -29,7 +26,7 @@ export class MindmapRenderer extends Component {
if (!container || !this.treeData) return;
const width = Math.max(container.clientWidth, 900);
const height = 560;
const height = Math.max(container.clientHeight || 560, 560);
// 清空后重绘
container.innerHTML = "";
@ -75,7 +72,6 @@ export class MindmapRenderer extends Component {
.append("path")
.attr("class", "mindmap-link")
.attr("fill", "none")
.attr("stroke", "#90A4AE")
.attr("stroke-width", 1.5)
.attr("opacity", 0.6)
.attr("d", (d) => {
@ -103,8 +99,18 @@ export class MindmapRenderer extends Component {
.attr("height", 36)
.attr("x", -80)
.attr("y", -18)
.attr("fill", (d) => (d.children ? "#1E88E5" : "#43A047"))
.attr("stroke", (d) => (d.children ? "#1565C0" : "#2E7D32"))
.attr("fill", (d) => {
const k = d.data.kind;
if (k === "project") return "#5E35B1";
if (k === "stage") return "#1E88E5";
return "#43A047";
})
.attr("stroke", (d) => {
const k = d.data.kind;
if (k === "project") return "#4527A0";
if (k === "stage") return "#1565C0";
return "#2E7D32";
})
.attr("stroke-width", 1.5)
.style("filter", "drop-shadow(1px 2px 3px rgba(0,0,0,0.2))")
.on("mouseenter", function () {
@ -135,9 +141,9 @@ export class MindmapRenderer extends Component {
return name.length > 14 ? name.substring(0, 13) + "…" : name;
});
// 进度环(有进度的叶子任务
// 进度环(任意带进度的节点:任务/阶段/项目 都显示"进行到哪一步"
nodes
.filter((d) => !d.children && d.data.progress && d.data.progress > 0)
.filter((d) => d.data.progress && d.data.progress > 0)
.append("circle")
.attr("cx", 66)
.attr("cy", -14)
@ -154,10 +160,11 @@ export class MindmapRenderer extends Component {
.attr("stroke-dashoffset", circ * (1 - p));
});
// 点击 → 冒泡事件给 Controller
// 点击 → 把整个 node含 kind/resId冒泡给 Controller 决定导航
// 注意事件名必须与模板 t-on-node-click-ed 一致,否则不触发
nodes.on("click", (event, d) => {
if (d.data.id) {
this.trigger("node-clicked", { id: d.data.id });
if (d.data && d.data.kind) {
this.trigger("node-click-ed", { node: d.data });
}
});
}

View File

@ -7,7 +7,7 @@ import { MindmapRenderer } from "./mindmap_renderer";
export const mindmapView = {
type: "mindmap",
display_name: "Mindmap",
display_name: "思维导图",
icon: "fa fa-sitemap",
multiRecord: true,
ArchParser: MindmapArchParser,

View File

@ -1,10 +1,16 @@
.o_controller_mindmap {
display: flex;
flex-direction: column;
height: 100%;
padding: 12px;
box-sizing: border-box;
overflow: hidden;
}
.mindmap-renderer-root {
flex: 1 1 auto;
min-height: 560px;
overflow: auto;
background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%);
border: 1px solid #d0d7de;
border-radius: 10px;
@ -25,6 +31,25 @@
filter: drop-shadow(2px 4px 8px rgba(0, 0, 0, 0.3));
}
/* 连接线颜色交给 CSS 控制便于夜色模式覆盖d3 不再写死 stroke */
.mindmap-link {
pointer-events: none;
stroke: #90a4ae;
}
.mindmap-node text {
fill: #ffffff;
}
/* 深色模式适配:深色主题下容器与连线都不要纯白/浅灰 */
.o_web_client.o_dark_theme .mindmap-renderer-root,
.o_web_client.dark .mindmap-renderer-root {
background: linear-gradient(135deg, #1e2228 0%, #262a30 100%);
border-color: #3a4048;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.4);
}
.o_web_client.o_dark_theme .mindmap-link,
.o_web_client.dark .mindmap-link {
stroke: #5b6470;
}

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="project_md.MindmapView" owl="1">
<div class="o_content o_controller_mindmap">
<div class="o_view_controller o_controller_mindmap">
<t t-if="state.treeData">
<t t-component="props.Renderer"
t-props="rendererProps"
t-on-node-clicked="onNodeClicked"/>
t-on-node-click-ed="onNodeClicked"/>
</t>
<t t-else="">
<div class="o_mindmap_loading">加载中…</div>
@ -15,6 +15,6 @@
<t t-name="project_md.MindmapRenderer" owl="1">
<div class="mindmap-renderer-root"
style="width:100%;height:560px;overflow:hidden;background:#f5f7fa;border-radius:8px;position:relative;"/>
style="width:100%;position:relative;"/>
</t>
</templates>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!-- 注册 mindmap 视图类型(后端需有一条该 type 的 view 记录) -->
<!-- 任务级 mindmap 视图:保留,用于在单个项目的任务里切换 -->
<record id="view_project_task_mindmap" model="ir.ui.view">
<field name="name">project.task.mindmap</field>
<field name="model">project.task</field>
@ -10,23 +10,26 @@
</field>
</record>
<!-- 独立动作:打开任务思维导图(补全多视图模式,可从导图切回看板等) -->
<record id="action_project_task_mindmap" model="ir.actions.act_window">
<field name="name">任务思维导图</field>
<field name="res_model">project.task</field>
<field name="view_mode">kanban,list,form,calendar,pivot,graph,activity,mindmap</field>
<field name="view_id" ref="view_project_task_mindmap"/>
<field name="context">{'default_view_mode': 'mindmap'}</field>
<!-- 项目级 mindmap 视图:用于"所有项目"动作里直接看所有项目 -->
<record id="view_project_project_mindmap" model="ir.ui.view">
<field name="name">project.project.mindmap</field>
<field name="model">project.project</field>
<field name="type">mindmap</field>
<field name="arch" type="xml">
<mindmap name_field="name"/>
</field>
</record>
<!-- 挂到项目菜单下 -->
<menuitem id="menu_project_task_mindmap"
name="任务思维导图"
parent="project.menu_project_management"
action="action_project_task_mindmap"
sequence="20"/>
<!-- 注入到标准"所有项目"动作,使顶部视图切换栏出现思维导图图标 -->
<record id="project.open_view_project_all" model="ir.actions.act_window">
<field name="view_mode">kanban,list,form,mindmap</field>
</record>
<!-- 注入到标准"所有任务"动作,使顶部视图切换栏出现思维导图图标 -->
<record id="project.open_view_project_all_group_stage" model="ir.actions.act_window">
<field name="view_mode">kanban,list,form,mindmap</field>
</record>
<!-- 注入到标准"所有任务"动作,任务视图也能切换成导图 -->
<record id="project.action_view_all_task" model="ir.actions.act_window">
<field name="view_mode">kanban,list,form,calendar,pivot,graph,activity,mindmap</field>
</record>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,88 @@
/** @odoo-module **/
import { patch } from "@web/core/utils/patch";
import { useEffect, onMounted } from "@odoo/owl";
import { NavBar } from "@web/webclient/navbar/navbar";
import { ActionContainer } from "@web/webclient/actions/action_container";
import { cookie } from "@web/core/browser/cookie";
// 菜单栏居中(原 omux_menu_center已合并进 udoo_om_ux
// 常开:所有页面导航栏菜单项居中,仅适配 udoo_om_ux 暗色模式
export function getCurrentColorScheme() {
const COLOR_SCHEME_COOKIE_NAME = 'color_scheme';
return cookie.get(COLOR_SCHEME_COOKIE_NAME) || 'light';
}
export function dnNavBarAddClasses(){
document.querySelector('body')?.classList.add('ks_body_class');
document.querySelector('.o_main_navbar')?.classList.add('navbar', 'navbar-expand-md');
document.querySelector('.ks-mobile-burger-menu')?.classList.remove('d-none');
document.querySelector('.mobile-burger-menu-default')?.classList.add('d-none');
}
export function themeAddClasses(){
const currentScheme = getCurrentColorScheme();
if(currentScheme == 'dark'){
if (!document.querySelector('body').classList.contains('darkness')){
document.querySelector('body')?.classList.add('darkness');
}
}
}
patch(NavBar.prototype, {
setup(){
super.setup();
onMounted(() => {
this.applyNavbarStyle();
themeAddClasses()
});
useEffect(() => {
this.applyNavbarStyle();
themeAddClasses()
});
},
async adapt(){
const result = await super.adapt();
this.applyNavbarStyle();
return result;
},
onNavBarDropdownItemSelection(menu) {
super.onNavBarDropdownItemSelection(menu);
this.applyNavbarStyle();
},
applyNavbarStyle() {
const body = document.body;
if (body && !body.classList.contains('ks_body_class')) {
dnNavBarAddClasses();
}
},
});
patch(ActionContainer.prototype, {
setup(){
super.setup();
onMounted(() => {
this.applyNavbarStyle();
themeAddClasses()
});
useEffect(() => {
this.applyNavbarStyle();
themeAddClasses()
});
},
applyNavbarStyle() {
const body = document.body;
if (body && !body.classList.contains('ks_body_class')) {
dnNavBarAddClasses();
}
},
});

View File

@ -0,0 +1,394 @@
// ============================================================
// 菜单栏居中 omux_menu_center已合并进 udoo_om_ux
// 常开所有页面导航栏菜单项居中
// 暗色模式通过 body.darkness 适配
// 变量/mixin 使用 omc- 前缀避免与 omux/ks 变量冲突
// ============================================================
// ---- SCSS 变量 ----
$omc-color-black: #241C1D;
$omc-color-white: #FFFFFF;
$omc-color-nav-bg: #E2E9F0;
$omc-color-bg-main: #F5F8FB;
$omc-color-E5E7EB: #E5E7EB;
$omc-color-D9F1FD: #D9F1FD;
$omc-color-E7495E: #E7495E;
// 暗色模式色板
$omc-dark-bg-main: #131325;
$omc-dark-surface: #1C1C2E;
$omc-dark-text: #D8D8E0;
$omc-dark-border: #2E2E42;
$omc-dark-hover: #252540;
$omc-f-w-400: 400;
$omc-f-w-500: 500;
$omc-font-10: 10px;
$omc-font-12: 12px;
$omc-font-16: 16px;
$omc-font-18: 18px;
$omc-font-20: 20px;
$omc-font-22: 22px;
// ---- Mixins ----
@mixin omc-min-1600 {
@media screen and (min-width: 1600px) { @content; }
}
@mixin omc-max-992 {
@media screen and (max-width: 992px) { @content; }
}
@mixin omc-max-768 {
@media screen and (max-width: 768px) { @content; }
}
@mixin omc-max-575 {
@media screen and (max-width: 575.8px) { @content; }
}
// ---- Body 基础 ----
body.ks_body_class {
font-family: "Poppins", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
height: 100vh;
background-color: $omc-color-bg-main;
}
body.ks_body_class.darkness {
background-color: $omc-dark-bg-main;
}
// ---- Header / 导航栏 ----
.ks_body_class header {
position: sticky;
top: 0;
z-index: 10;
width: 100%;
.o_menu_systray {
align-items: center;
}
.o_main_navbar {
padding: 0px 40px;
min-height: 66px;
@include omc-min-1600 {
min-height: 76px;
}
background: $omc-color-white;
display: flex;
justify-content: space-between;
border-bottom: 1px solid $omc-color-E5E7EB !important;
// 核心菜单居中
.o_menu_sections {
justify-content: center;
align-items: center;
// 菜单文字稍微大一点
.o_nav_entry,
.dropdown-toggle {
font-size: 15px;
}
}
.o_menu_brand {
color: $omc-color-black;
font-size: $omc-font-22;
font-weight: $omc-f-w-400;
line-height: 30.8px;
@include omc-max-992 {
font-size: $omc-font-18;
}
@include omc-max-575 {
font-size: $omc-font-12;
line-height: 16px;
margin-left: 4px !important;
}
}
// 移动端折叠菜单
@include omc-max-768 {
.navbar-collapse {
position: fixed;
top: 62px;
right: -100%;
height: 100%;
width: 80%;
transition: right 0.3s ease-in-out;
background-color: $omc-color-white;
&.show {
right: 0;
}
}
}
@include omc-max-992 {
padding: 0px 20px;
}
@include omc-max-575 {
padding: 0 10px;
}
}
}
// ---- 暗色模式Header / 导航栏 ----
body.darkness.ks_body_class header {
.o_main_navbar {
background: $omc-dark-surface;
border-bottom: 1px solid $omc-dark-border !important;
// 去掉白色背景底色菜单项 & systray 背景跟随暗色hover/focus/active 用暗色高亮
--NavBar-entry-backgroundColor: transparent;
--NavBar-entry-backgroundColor--hover: #{$omc-dark-hover};
--NavBar-entry-backgroundColor--focus: #{$omc-dark-hover};
--NavBar-entry-backgroundColor--active: #{$omc-dark-hover};
.o_menu_brand {
color: $omc-dark-text;
}
.navbar-collapse {
background-color: $omc-dark-surface;
}
// 导航栏菜单项文字
.o_menu_sections .dropdown-toggle,
.o_menu_sections a {
color: $omc-dark-text;
}
// systray 图标 / 按钮暗色适配
.o_menu_systray {
.o_nav_entry,
.dropdown-toggle,
.btn,
button,
.o-dropdown,
.o-dropdown-toggle {
color: $omc-dark-text;
&:hover,
&:focus,
&.show {
background-color: $omc-dark-hover;
color: $omc-color-white;
}
}
.o-dropdown--menu,
.o_MessagingMenu,
.o_ActivityMenu,
.o_UserMenu {
color: $omc-dark-text;
}
// 通知角标
.badge {
background-color: $omc-color-E7495E;
color: $omc-color-white;
}
}
}
}
// ---- 文字颜色 ----
.ks_body_class .oe_topbar_name {
color: $omc-color-black !important;
}
body.darkness.ks_body_class .oe_topbar_name {
color: $omc-dark-text !important;
}
.ks_body_class .o_debug_manager button {
color: $omc-color-black !important;
}
body.darkness.ks_body_class .o_debug_manager button {
color: $omc-dark-text !important;
}
// ---- 用户名缩写圆圈 ----
.ks_body_class .user-name {
font-size: $omc-font-20;
font-weight: $omc-f-w-500;
line-height: 32px;
min-width: 52px;
color: $omc-color-black;
border-radius: 10px;
background-color: $omc-color-D9F1FD;
padding: 7px 11px;
@include omc-max-768 {
border-radius: 5px;
border: 0.5px solid $omc-color-E5E7EB;
background-color: $omc-color-white;
font-size: $omc-font-12;
font-weight: $omc-f-w-400;
line-height: 14px;
width: 23px !important;
height: 23px;
min-width: 23px;
display: flex;
justify-content: center;
align-items: center;
padding: 7px 14px;
}
}
body.darkness.ks_body_class .user-name {
color: $omc-dark-text;
background-color: rgba(217, 241, 253, 0.12);
border-color: $omc-dark-border;
@include omc-max-768 {
background-color: $omc-dark-surface;
}
}
// ---- Burger 菜单 ----
.ks_body_class .o_burger_menu {
width: 69% !important;
}
.ks_body_class .modal-backdrop.show {
opacity: 0.2;
}
.ks_body_class .cross {
padding-left: 16px;
padding-right: 16px;
}
// 暗色模式Burger 菜单
body.darkness.ks_body_class .o_burger_menu {
background-color: $omc-dark-surface !important;
.o_burger_menu_content {
background-color: $omc-dark-surface;
.o_burger_menu_user {
color: $omc-dark-text;
}
}
}
// ---- 公司切换器 ----
.ks_body_class .o_switch_company_menu {
border-radius: 50px;
border: 1px solid $omc-color-E5E7EB;
justify-content: center;
align-items: center;
min-height: 44px;
padding: 8px 10px 8px 10px !important;
display: flex !important;
@include omc-max-768 {
display: none !important;
}
// 下拉箭头 CSS不依赖外部图片
.dropdown-toggle::after {
content: "";
display: inline-block;
margin-left: .4em;
vertical-align: middle;
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 5px solid $omc-color-black;
border-radius: 1px;
transition: transform 0.3s ease-in-out;
@include omc-max-768 {
display: none;
}
}
.dropdown-toggle.show::after {
transform: rotate(-180deg);
}
.dropdown-toggle {
height: fit-content;
.oe_topbar_name {
font-size: $omc-font-12;
height: 100%;
padding-right: 6px;
line-height: normal !important;
}
}
.fa-check-square {
color: $omc-color-E7495E !important;
}
}
// 暗色模式公司切换器
body.darkness.ks_body_class .o_switch_company_menu {
border-color: $omc-dark-border;
.dropdown-toggle::after {
border-top-color: $omc-dark-text;
}
.dropdown-menu {
background-color: $omc-dark-surface;
border-color: $omc-dark-border;
.dropdown-item {
color: $omc-dark-text;
&:hover {
background-color: $omc-dark-hover;
}
}
}
}
// ---- 暗色模式导航栏下拉菜单 ----
body.darkness.ks_body_class {
.o_main_navbar .dropdown-menu {
background-color: $omc-dark-surface;
border-color: $omc-dark-border;
.dropdown-item {
color: $omc-dark-text;
&:hover,
&:focus {
background-color: $omc-dark-hover;
color: $omc-color-white;
}
}
}
// 导航栏品牌区域菜单链接
.o_main_navbar a,
.o_main_navbar .o-nav-link {
color: $omc-dark-text;
&:hover {
color: $omc-color-white;
}
}
// systray 下拉
.o_menu_systray .dropdown-menu {
background-color: $omc-dark-surface;
border-color: $omc-dark-border;
.dropdown-item {
color: $omc-dark-text;
&:hover {
background-color: $omc-dark-hover;
}
}
}
}