new
This commit is contained in:
parent
c7ad84f993
commit
1fa24f7558
BIN
ks_dashboard_ninja/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
ks_dashboard_ninja/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
ks_dashboard_ninja/models/__pycache__/Kpi_mail.cpython-314.pyc
Normal file
BIN
ks_dashboard_ninja/models/__pycache__/Kpi_mail.cpython-314.pyc
Normal file
Binary file not shown.
BIN
ks_dashboard_ninja/models/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
ks_dashboard_ninja/models/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
BIN
ks_dashboard_ninja/wizard/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
ks_dashboard_ninja/wizard/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
many2many_tags_preview/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
many2many_tags_preview/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
omux_menu_center/.DS_Store
vendored
BIN
omux_menu_center/.DS_Store
vendored
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
@ -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
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import model
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -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>
|
||||
BIN
omux_multi_tab/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
omux_multi_tab/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
omux_multi_tab/models/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
omux_multi_tab/models/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
preview_easy/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
preview_easy/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
preview_easy/controllers/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
preview_easy/controllers/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
preview_easy/controllers/__pycache__/preview.cpython-314.pyc
Normal file
BIN
preview_easy/controllers/__pycache__/preview.cpython-314.pyc
Normal file
Binary file not shown.
@ -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',
|
||||
|
||||
BIN
project_md/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
project_md/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
project_md/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
project_md/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
project_md/__pycache__/__manifest__.cpython-312.pyc
Normal file
BIN
project_md/__pycache__/__manifest__.cpython-312.pyc
Normal file
Binary file not shown.
@ -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
|
||||
|
||||
BIN
project_md/models/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
project_md/models/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
project_md/models/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
project_md/models/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
project_md/models/__pycache__/ir_ui_view_extend.cpython-312.pyc
Normal file
BIN
project_md/models/__pycache__/ir_ui_view_extend.cpython-312.pyc
Normal file
Binary file not shown.
BIN
project_md/models/__pycache__/ir_ui_view_extend.cpython-314.pyc
Normal file
BIN
project_md/models/__pycache__/ir_ui_view_extend.cpython-314.pyc
Normal file
Binary file not shown.
BIN
project_md/models/__pycache__/mindmap_diagram.cpython-312.pyc
Normal file
BIN
project_md/models/__pycache__/mindmap_diagram.cpython-312.pyc
Normal file
Binary file not shown.
BIN
project_md/models/__pycache__/mindmap_diagram.cpython-314.pyc
Normal file
BIN
project_md/models/__pycache__/mindmap_diagram.cpython-314.pyc
Normal file
Binary file not shown.
BIN
project_md/models/__pycache__/mindmap_node.cpython-312.pyc
Normal file
BIN
project_md/models/__pycache__/mindmap_node.cpython-312.pyc
Normal file
Binary file not shown.
BIN
project_md/models/__pycache__/mindmap_node.cpython-314.pyc
Normal file
BIN
project_md/models/__pycache__/mindmap_node.cpython-314.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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
|
||||
|
||||
106
project_md/models/project_mindmap_extend.py
Normal file
106
project_md/models/project_mindmap_extend.py
Normal 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
2
project_md/static/lib/d3/d3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -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",
|
||||
});
|
||||
|
||||
@ -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 });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
BIN
udoo_om_ux/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
udoo_om_ux/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
udoo_om_ux/models/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
udoo_om_ux/models/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
udoo_om_ux/models/__pycache__/ir_http.cpython-314.pyc
Normal file
BIN
udoo_om_ux/models/__pycache__/ir_http.cpython-314.pyc
Normal file
Binary file not shown.
BIN
udoo_om_ux/models/__pycache__/ir_ui_menu.cpython-314.pyc
Normal file
BIN
udoo_om_ux/models/__pycache__/ir_ui_menu.cpython-314.pyc
Normal file
Binary file not shown.
BIN
udoo_om_ux/models/__pycache__/res_company.cpython-314.pyc
Normal file
BIN
udoo_om_ux/models/__pycache__/res_company.cpython-314.pyc
Normal file
Binary file not shown.
BIN
udoo_om_ux/models/__pycache__/res_users_settings.cpython-314.pyc
Normal file
BIN
udoo_om_ux/models/__pycache__/res_users_settings.cpython-314.pyc
Normal file
Binary file not shown.
BIN
udoo_om_ux/models/__pycache__/web_editor.cpython-314.pyc
Normal file
BIN
udoo_om_ux/models/__pycache__/web_editor.cpython-314.pyc
Normal file
Binary file not shown.
88
udoo_om_ux/static/src/webclient/navbar/menu_center.js
Normal file
88
udoo_om_ux/static/src/webclient/navbar/menu_center.js
Normal 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();
|
||||
}
|
||||
},
|
||||
});
|
||||
394
udoo_om_ux/static/src/webclient/navbar/menu_center.scss
Normal file
394
udoo_om_ux/static/src/webclient/navbar/menu_center.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user