-
+
未处理违约金
¥245,890.00
@@ -19,14 +19,14 @@
-
+
已收回违约金
¥1,320,560.00
▲ 8.2% 较上月
-
+
@@ -111,6 +111,15 @@
+
+
+
+
+
diff --git a/yuthon_report/views/att_report_view.xml b/yuthon_report/views/att_report_view.xml
index 03e459840..3e2ac39ea 100644
--- a/yuthon_report/views/att_report_view.xml
+++ b/yuthon_report/views/att_report_view.xml
@@ -23,7 +23,7 @@
{"headerName": "申请原因", "field": "申请原因", "flex": 1},
{"headerName": "发起时间", "field": "发起时间", "flex": 1},
{"headerName": "最后操作时间", "field": "最后操作时间", "flex": 1},
- {"headerName": "审批状态", "field": "审批状态", "flex": 1}
+ {"headerName": "审批状态", "field": "审批状态", "flex": 1,'rowGroup':true}
]
}
}
From 49997ef05c491c746535b70e85be73cd0358996d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 15:37:59 +0800
Subject: [PATCH 22/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../static/src/js/status_bar_buttons.js | 379 ++++++++++++++----
.../static/src/scss/status_bar_buttons.scss | 224 +++++++++--
2 files changed, 490 insertions(+), 113 deletions(-)
diff --git a/k_ry_mobile_form/static/src/js/status_bar_buttons.js b/k_ry_mobile_form/static/src/js/status_bar_buttons.js
index 38d937f80..bb88a0866 100644
--- a/k_ry_mobile_form/static/src/js/status_bar_buttons.js
+++ b/k_ry_mobile_form/static/src/js/status_bar_buttons.js
@@ -29,25 +29,108 @@ patch(StatusBarButtons, {
if (typeof window !== 'undefined') {
useEffect(() => {
const checkAndFixMobileButtons = () => {
- // 如果是移动设备但 env.isSmall 为 false,强制显示移动端按钮
- if (isMobileDevice()) {
- const mobileContainers = document.querySelectorAll('.o_statusbar_buttons_mobile_fixed');
- mobileContainers.forEach(container => {
- container.style.display = 'block';
- container.style.visibility = 'visible';
- container.style.opacity = '1';
- });
-
- // 隐藏桌面端按钮
- const desktopButtons = document.querySelectorAll('.o_form_statusbar > .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons)');
- desktopButtons.forEach(btn => {
- btn.style.display = 'none';
- });
+ try {
+ // 如果是移动设备但 env.isSmall 为 false,强制显示移动端按钮
+ if (isMobileDevice()) {
+ const mobileContainers = document.querySelectorAll('.o_statusbar_buttons_mobile_fixed');
+ if (mobileContainers.length === 0) return;
+
+ mobileContainers.forEach(container => {
+ try {
+ // 使用内联样式强制显示,优先级最高
+ container.style.setProperty('display', 'block', 'important');
+ container.style.setProperty('visibility', 'visible', 'important');
+ container.style.setProperty('opacity', '1', 'important');
+ container.style.setProperty('position', 'fixed', 'important');
+ container.style.setProperty('bottom', '0', 'important');
+ container.style.setProperty('left', '0', 'important');
+ container.style.setProperty('right', '0', 'important');
+ container.style.setProperty('z-index', '99999', 'important');
+ // 强制设置背景色,防止被主题覆盖
+ container.style.setProperty('background-color', '#ffffff', 'important');
+ container.style.setProperty('background', '#ffffff', 'important');
+
+ // 同时修复容器内的按钮
+ const buttons = container.querySelectorAll('button, a.btn, .btn, a[role="button"], .o_statusbar_buttons > * > button, .o_statusbar_buttons > * > a');
+ buttons.forEach(button => {
+ try {
+ // 强制设置按钮可见性
+ button.style.setProperty('visibility', 'visible', 'important');
+ button.style.setProperty('opacity', '1', 'important');
+ button.style.setProperty('display', 'inline-block', 'important');
+ button.style.setProperty('font-size', '14px', 'important');
+ button.style.setProperty('font-weight', '500', 'important');
+ // 防止文字被设置为透明
+ button.style.setProperty('text-indent', '0', 'important');
+
+ // 检查按钮颜色
+ const computedStyle = getComputedStyle(button);
+ const bgColor = computedStyle.backgroundColor;
+ const textColor = computedStyle.color;
+
+ // 如果背景色是透明或白色,且文字颜色也是白色或透明,强制设置颜色
+ const isTransparent = bgColor === 'transparent' || bgColor === 'rgba(0, 0, 0, 0)';
+ const isWhiteBg = bgColor === 'rgb(255, 255, 255)' || bgColor === '#ffffff' || bgColor === '#fff';
+ const isWhiteText = textColor === 'rgb(255, 255, 255)' || textColor === '#ffffff' || textColor === '#fff';
+ const isTransparentText = textColor === 'transparent' || textColor === 'rgba(0, 0, 0, 0)';
+
+ // 如果按钮不可见,强制设置颜色
+ if (isTransparent || (isWhiteBg && (isWhiteText || isTransparentText)) || textColor === 'rgba(0, 0, 0, 0)') {
+ // 根据按钮类型设置颜色
+ const hasPrimary = button.classList.contains('btn-primary') || button.classList.contains('o_statusbar_status');
+ const hasSecondary = button.classList.contains('btn-secondary');
+ const hasSuccess = button.classList.contains('btn-success');
+ const hasDanger = button.classList.contains('btn-danger');
+ const hasWarning = button.classList.contains('btn-warning');
+ const hasInfo = button.classList.contains('btn-info');
+
+ if (hasPrimary || hasSuccess) {
+ button.style.setProperty('background-color', '#007bff', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ } else if (hasSecondary) {
+ button.style.setProperty('background-color', '#6c757d', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ } else if (hasDanger) {
+ button.style.setProperty('background-color', '#dc3545', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ } else if (hasWarning) {
+ button.style.setProperty('background-color', '#ffc107', 'important');
+ button.style.setProperty('color', '#212529', 'important');
+ } else if (hasInfo) {
+ button.style.setProperty('background-color', '#17a2b8', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ } else {
+ // 默认蓝色按钮
+ button.style.setProperty('background-color', '#007bff', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ }
+ }
+ } catch (e) {
+ console.warn('Error fixing button in setup:', e);
+ }
+ });
+ } catch (e) {
+ console.warn('Error fixing container in setup:', e);
+ }
+ });
+
+ // 隐藏桌面端按钮
+ try {
+ const desktopButtons = document.querySelectorAll('.o_form_statusbar > .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons)');
+ desktopButtons.forEach(btn => {
+ btn.style.setProperty('display', 'none', 'important');
+ });
+ } catch (e) {
+ console.warn('Error hiding desktop buttons in setup:', e);
+ }
+ }
+ } catch (e) {
+ console.warn('Error in checkAndFixMobileButtons:', e);
}
};
- // 延迟执行,确保DOM已渲染
- setTimeout(checkAndFixMobileButtons, 100);
+ // 延迟执行,确保DOM已渲染,不阻塞页面加载
+ setTimeout(checkAndFixMobileButtons, 200);
// 监听窗口大小变化
const handleResize = () => {
@@ -66,80 +149,234 @@ patch(StatusBarButtons, {
// iOS Safari修复:确保移动端按钮在iOS上可点击和可见
// 使用MutationObserver监听DOM变化,确保新添加的按钮也能正常工作
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
+ let fixTimeout = null;
+ let observer = null;
+ let checkInterval = null;
+
+ // 防抖函数,避免频繁执行
+ const debounce = (func, wait) => {
+ return function executedFunction(...args) {
+ const later = () => {
+ clearTimeout(fixTimeout);
+ func(...args);
+ };
+ clearTimeout(fixTimeout);
+ fixTimeout = setTimeout(later, wait);
+ };
+ };
+
const fixIOSButtons = () => {
- // 确保移动端按钮容器可见
- const containers = document.querySelectorAll('.o_statusbar_buttons_mobile_fixed');
- containers.forEach(container => {
- // 如果是移动设备,确保容器可见
- if (isMobileDevice()) {
- const computedStyle = getComputedStyle(container);
- if (computedStyle.display === 'none') {
- container.style.display = 'block';
- }
- container.style.visibility = 'visible';
- container.style.opacity = '1';
- }
+ try {
+ // 确保移动端按钮容器可见
+ const containers = document.querySelectorAll('.o_statusbar_buttons_mobile_fixed');
+ if (containers.length === 0) return;
- // 修复按钮的交互性
- const buttons = container.querySelectorAll('button, a.btn, .btn, a[role="button"], .o_statusbar_buttons > * > button');
- buttons.forEach(button => {
- // 确保pointer-events正确设置
- if (getComputedStyle(button).pointerEvents === 'none') {
- button.style.pointerEvents = 'auto';
+ containers.forEach(container => {
+ try {
+ // 如果是移动设备,确保容器可见
+ if (isMobileDevice()) {
+ // 使用 setProperty 的 important 标志强制设置样式
+ container.style.setProperty('display', 'block', 'important');
+ container.style.setProperty('visibility', 'visible', 'important');
+ container.style.setProperty('opacity', '1', 'important');
+ container.style.setProperty('position', 'fixed', 'important');
+ container.style.setProperty('bottom', '0', 'important');
+ container.style.setProperty('left', '0', 'important');
+ container.style.setProperty('right', '0', 'important');
+ container.style.setProperty('z-index', '99999', 'important');
+ // 强制设置背景色,防止被主题覆盖
+ container.style.setProperty('background-color', '#ffffff', 'important');
+ container.style.setProperty('background', '#ffffff', 'important');
+ }
+
+ // 修复按钮的交互性和可见性
+ const buttons = container.querySelectorAll('button, a.btn, .btn, a[role="button"], .o_statusbar_buttons > * > button, .o_statusbar_buttons > * > a');
+ buttons.forEach(button => {
+ try {
+ // 使用 setProperty 强制设置样式
+ button.style.setProperty('pointer-events', 'auto', 'important');
+ button.style.setProperty('cursor', 'pointer', 'important');
+ button.style.setProperty('touch-action', 'manipulation', 'important');
+ button.style.setProperty('visibility', 'visible', 'important');
+ button.style.setProperty('opacity', '1', 'important');
+ button.style.setProperty('display', 'inline-block', 'important');
+ // 确保按钮有最小高度和字体大小
+ button.style.setProperty('min-height', '44px', 'important');
+ button.style.setProperty('font-size', '14px', 'important');
+ button.style.setProperty('font-weight', '500', 'important');
+ // 防止文字被设置为透明
+ button.style.setProperty('text-indent', '0', 'important');
+
+ // 检查按钮颜色
+ const computedStyle = getComputedStyle(button);
+ const bgColor = computedStyle.backgroundColor;
+ const textColor = computedStyle.color;
+
+ // 如果背景色是透明或白色,且文字颜色也是白色或透明,强制设置颜色
+ const isTransparent = bgColor === 'transparent' || bgColor === 'rgba(0, 0, 0, 0)';
+ const isWhiteBg = bgColor === 'rgb(255, 255, 255)' || bgColor === '#ffffff' || bgColor === '#fff';
+ const isWhiteText = textColor === 'rgb(255, 255, 255)' || textColor === '#ffffff' || textColor === '#fff';
+ const isTransparentText = textColor === 'transparent' || textColor === 'rgba(0, 0, 0, 0)';
+
+ // 如果按钮不可见,强制设置颜色
+ if (isTransparent || (isWhiteBg && (isWhiteText || isTransparentText)) || textColor === 'rgba(0, 0, 0, 0)') {
+ // 根据按钮类型设置颜色
+ const hasPrimary = button.classList.contains('btn-primary') || button.classList.contains('o_statusbar_status');
+ const hasSecondary = button.classList.contains('btn-secondary');
+ const hasSuccess = button.classList.contains('btn-success');
+ const hasDanger = button.classList.contains('btn-danger');
+ const hasWarning = button.classList.contains('btn-warning');
+ const hasInfo = button.classList.contains('btn-info');
+
+ if (hasPrimary || hasSuccess) {
+ button.style.setProperty('background-color', '#007bff', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ } else if (hasSecondary) {
+ button.style.setProperty('background-color', '#6c757d', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ } else if (hasDanger) {
+ button.style.setProperty('background-color', '#dc3545', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ } else if (hasWarning) {
+ button.style.setProperty('background-color', '#ffc107', 'important');
+ button.style.setProperty('color', '#212529', 'important');
+ } else if (hasInfo) {
+ button.style.setProperty('background-color', '#17a2b8', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ } else {
+ // 默认蓝色按钮
+ button.style.setProperty('background-color', '#007bff', 'important');
+ button.style.setProperty('color', '#ffffff', 'important');
+ }
+ }
+ } catch (e) {
+ console.warn('Error fixing button:', e);
+ }
+ });
+ } catch (e) {
+ console.warn('Error fixing container:', e);
}
- button.style.cursor = 'pointer';
- button.style.touchAction = 'manipulation';
- button.style.visibility = 'visible';
- button.style.opacity = '1';
- });
- });
-
- // 在移动设备上,确保原始状态栏中的按钮被隐藏
- if (isMobileDevice()) {
- const desktopButtons = document.querySelectorAll('.o_form_statusbar > .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons)');
- desktopButtons.forEach(btn => {
- btn.style.display = 'none';
});
+
+ // 在移动设备上,确保原始状态栏中的按钮被隐藏
+ if (isMobileDevice()) {
+ try {
+ const desktopButtons = document.querySelectorAll('.o_form_statusbar > .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons)');
+ desktopButtons.forEach(btn => {
+ btn.style.setProperty('display', 'none', 'important');
+ });
+ } catch (e) {
+ console.warn('Error hiding desktop buttons:', e);
+ }
+ }
+ } catch (e) {
+ console.warn('Error in fixIOSButtons:', e);
}
};
+ // 防抖版本的修复函数
+ const debouncedFixIOSButtons = debounce(fixIOSButtons, 300);
+
// 初始化函数:确保DOM准备好后再设置observer
const initIOSButtonFix = () => {
- // 先执行一次修复
- fixIOSButtons();
-
- // 确保document.body存在后再创建observer
- if (document.body) {
- // 监听DOM变化,确保动态添加的按钮也能正常工作
- const observer = new MutationObserver(() => {
- fixIOSButtons();
- });
- observer.observe(document.body, {
- childList: true,
- subtree: true,
- attributes: true,
- attributeFilter: ['style', 'class']
- });
- } else {
- // 如果body还不存在,等待DOMContentLoaded
- document.addEventListener('DOMContentLoaded', initIOSButtonFix, { once: true });
+ try {
+ // 先执行一次修复
+ fixIOSButtons();
+
+ // 确保document.body存在后再创建observer
+ if (document.body && !observer) {
+ // 监听DOM变化,确保动态添加的按钮也能正常工作
+ observer = new MutationObserver((mutations) => {
+ // 只处理相关的变化
+ const hasRelevantChange = mutations.some(mutation => {
+ if (mutation.type === 'childList') {
+ return Array.from(mutation.addedNodes).some(node =>
+ node.nodeType === 1 && (
+ node.classList?.contains('o_statusbar_buttons_mobile_fixed') ||
+ node.querySelector?.('.o_statusbar_buttons_mobile_fixed')
+ )
+ );
+ }
+ if (mutation.type === 'attributes') {
+ return mutation.target.classList?.contains('o_statusbar_buttons_mobile_fixed') ||
+ mutation.target.closest?.('.o_statusbar_buttons_mobile_fixed');
+ }
+ return false;
+ });
+
+ if (hasRelevantChange) {
+ debouncedFixIOSButtons();
+ }
+ });
+
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true,
+ attributes: true,
+ attributeFilter: ['style', 'class']
+ });
+ }
+ } catch (e) {
+ console.warn('Error initializing button fix:', e);
}
};
// 页面加载后执行
if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', initIOSButtonFix);
+ document.addEventListener('DOMContentLoaded', initIOSButtonFix, { once: true });
} else {
- // 使用setTimeout确保DOM完全准备好
- setTimeout(initIOSButtonFix, 0);
+ // 使用setTimeout确保DOM完全准备好,不阻塞页面加载
+ setTimeout(initIOSButtonFix, 100);
}
// 监听窗口大小变化和方向变化(iOS Safari 横竖屏切换)
window.addEventListener('resize', () => {
- setTimeout(fixIOSButtons, 100);
- });
+ debouncedFixIOSButtons();
+ }, { passive: true });
window.addEventListener('orientationchange', () => {
- setTimeout(fixIOSButtons, 200);
- });
+ setTimeout(debouncedFixIOSButtons, 200);
+ }, { passive: true });
+
+ // 定期检查按钮是否可见(防止被其他样式覆盖)
+ if (isMobileDevice()) {
+ // 延迟启动定时器,避免影响页面加载
+ setTimeout(() => {
+ checkInterval = setInterval(() => {
+ try {
+ const containers = document.querySelectorAll('.o_statusbar_buttons_mobile_fixed');
+ if (containers.length > 0) {
+ containers.forEach(container => {
+ try {
+ const computedStyle = getComputedStyle(container);
+ // 如果按钮被隐藏,强制显示
+ if (computedStyle.display === 'none' ||
+ computedStyle.visibility === 'hidden' ||
+ parseFloat(computedStyle.opacity) < 0.1) {
+ fixIOSButtons();
+ }
+ } catch (e) {
+ console.warn('Error checking container:', e);
+ }
+ });
+ }
+ } catch (e) {
+ console.warn('Error in interval check:', e);
+ }
+ }, 2000); // 改为每2秒检查一次,减少频率
+ }, 2000);
+
+ // 页面卸载时清除定时器和observer
+ window.addEventListener('beforeunload', () => {
+ if (checkInterval) {
+ clearInterval(checkInterval);
+ }
+ if (observer) {
+ observer.disconnect();
+ }
+ if (fixTimeout) {
+ clearTimeout(fixTimeout);
+ }
+ });
+ }
}
diff --git a/k_ry_mobile_form/static/src/scss/status_bar_buttons.scss b/k_ry_mobile_form/static/src/scss/status_bar_buttons.scss
index 56122cd5b..48d274f0d 100644
--- a/k_ry_mobile_form/static/src/scss/status_bar_buttons.scss
+++ b/k_ry_mobile_form/static/src/scss/status_bar_buttons.scss
@@ -1,70 +1,167 @@
// Mobile: 底部悬浮栏样式
-.o_statusbar_buttons_mobile_fixed {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- z-index: 1050; // 确保在其他元素之上,但低于模态框
- background-color: $o-view-background-color;
- border-top: 1px solid $border-color;
- box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
- padding: map-get($spacers, 2) map-get($spacers, 3);
+// 使用高优先级选择器,防止被其他主题样式覆盖
+.o_statusbar_buttons_mobile_fixed,
+body .o_statusbar_buttons_mobile_fixed,
+html body .o_statusbar_buttons_mobile_fixed {
+ position: fixed !important;
+ bottom: 0 !important;
+ left: 0 !important;
+ right: 0 !important;
+ z-index: 99999 !important; // 比主题的9999更高,确保在最上层
+ // 强制设置背景色,防止被主题覆盖
+ background-color: #ffffff !important;
+ background: #ffffff !important;
+ border-top: 1px solid $border-color !important;
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1) !important;
+ padding: map-get($spacers, 2) map-get($spacers, 3) !important;
// 为底部悬浮栏预留空间,避免内容被遮挡(支持 iOS safe area)
- padding-bottom: calc(#{map-get($spacers, 2)} + env(safe-area-inset-bottom, 0px));
+ padding-bottom: calc(#{map-get($spacers, 2)} + env(safe-area-inset-bottom, 0px)) !important;
// iOS Safari 修复:确保元素可交互
- -webkit-transform: translateZ(0);
- transform: translateZ(0);
+ -webkit-transform: translateZ(0) !important;
+ transform: translateZ(0) !important;
// iOS Safari 修复:防止滚动时fixed定位失效
- -webkit-backface-visibility: hidden;
- backface-visibility: hidden;
+ -webkit-backface-visibility: hidden !important;
+ backface-visibility: hidden !important;
+ // 强制显示属性
+ display: block !important;
+ visibility: visible !important;
+ opacity: 1 !important;
+ // 确保元素不会被其他样式隐藏
+ overflow: visible !important;
+ clip: auto !important;
+ clip-path: none !important;
+}
.o_statusbar_buttons {
- max-width: 100%;
- width: 100%;
+ max-width: 100% !important;
+ width: 100% !important;
// iOS Safari 修复:确保容器可交互
- pointer-events: auto;
- -webkit-transform: translateZ(0);
- transform: translateZ(0);
+ pointer-events: auto !important;
+ -webkit-transform: translateZ(0) !important;
+ transform: translateZ(0) !important;
+ // 强制显示
+ display: flex !important;
+ visibility: visible !important;
+ opacity: 1 !important;
> * {
- flex: 1;
- min-width: 0;
+ flex: 1 !important;
+ min-width: 0 !important;
// iOS Safari 修复:确保子元素可交互
- pointer-events: auto;
+ pointer-events: auto !important;
+ // 强制显示
+ display: block !important;
+ visibility: visible !important;
+ opacity: 1 !important;
> button,
> a,
> .btn {
- width: 100%;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
+ width: 100% !important;
+ white-space: nowrap !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
// 确保按钮有足够的点击区域
- min-height: 44px;
+ min-height: 44px !important;
// iOS Safari 修复:确保按钮可点击
- cursor: pointer;
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
- touch-action: manipulation;
+ cursor: pointer !important;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1) !important;
+ touch-action: manipulation !important;
// iOS Safari 修复:防止文本选择影响点击
- -webkit-user-select: none;
- user-select: none;
- -webkit-touch-callout: none;
+ -webkit-user-select: none !important;
+ user-select: none !important;
+ -webkit-touch-callout: none !important;
// iOS Safari 修复:确保按钮在层级之上
- position: relative;
- z-index: 1;
+ position: relative !important;
+ z-index: 1 !important;
// iOS Safari 修复:确保pointer-events正确
pointer-events: auto !important;
// iOS Safari 修复:防止transform影响点击
- -webkit-transform: translateZ(0);
- transform: translateZ(0);
+ -webkit-transform: translateZ(0) !important;
+ transform: translateZ(0) !important;
+ // 强制显示按钮
+ display: inline-block !important;
+ visibility: visible !important;
+ opacity: 1 !important;
+ // 确保按钮背景和文字可见,防止被主题覆盖
+ background-color: #007bff !important;
+ background: #007bff !important;
+ color: #ffffff !important;
+ // 确保字体大小可见
+ font-size: 14px !important;
+ font-weight: 500 !important;
+ // 确保有边框和内边距
+ border: 1px solid #0056b3 !important;
+ border-radius: 4px !important;
+ padding: 8px 16px !important;
+ text-align: center !important;
+ // 防止文字被设置为透明
+ text-indent: 0 !important;
+ }
+
+ // 特殊处理不同类型的按钮,确保都有可见的样式
+ > button.btn-primary,
+ > a.btn-primary,
+ > .btn-primary {
+ background-color: #007bff !important;
+ background: #007bff !important;
+ color: #ffffff !important;
+ border-color: #0056b3 !important;
+ }
+
+ > button.btn-secondary,
+ > a.btn-secondary,
+ > .btn-secondary {
+ background-color: #6c757d !important;
+ background: #6c757d !important;
+ color: #ffffff !important;
+ border-color: #545b62 !important;
+ }
+
+ > button.btn-success,
+ > a.btn-success,
+ > .btn-success {
+ background-color: #28a745 !important;
+ background: #28a745 !important;
+ color: #ffffff !important;
+ border-color: #1e7e34 !important;
+ }
+
+ > button.btn-danger,
+ > a.btn-danger,
+ > .btn-danger {
+ background-color: #dc3545 !important;
+ background: #dc3545 !important;
+ color: #ffffff !important;
+ border-color: #c82333 !important;
+ }
+
+ > button.btn-warning,
+ > a.btn-warning,
+ > .btn-warning {
+ background-color: #ffc107 !important;
+ background: #ffc107 !important;
+ color: #212529 !important;
+ border-color: #e0a800 !important;
+ }
+
+ > button.btn-info,
+ > a.btn-info,
+ > .btn-info {
+ background-color: #17a2b8 !important;
+ background: #17a2b8 !important;
+ color: #ffffff !important;
+ border-color: #117a8b !important;
}
}
}
-}
+
// 桌面端隐藏移动端悬浮栏(但保留触摸设备的显示)
@include media-breakpoint-up(md) {
- .o_statusbar_buttons_mobile_fixed {
+ .o_statusbar_buttons_mobile_fixed,
+ body .o_statusbar_buttons_mobile_fixed,
+ html body .o_statusbar_buttons_mobile_fixed {
// 只在非触摸设备上隐藏(桌面浏览器)
@media (hover: hover) and (pointer: fine) {
display: none !important;
@@ -88,14 +185,57 @@
}
// iOS Safari 特殊处理:确保在 iOS 设备上按钮可见
+// 使用高优先级选择器,防止被其他主题样式覆盖
@media (hover: none) and (pointer: coarse) {
- .o_statusbar_buttons_mobile_fixed {
+ .o_statusbar_buttons_mobile_fixed,
+ body .o_statusbar_buttons_mobile_fixed,
+ html body .o_statusbar_buttons_mobile_fixed {
display: block !important;
visibility: visible !important;
opacity: 1 !important;
+ position: fixed !important;
+ bottom: 0 !important;
+ z-index: 99999 !important;
}
- .o_form_statusbar > .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons) {
+ .o_form_statusbar > .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons),
+ body .o_form_statusbar > .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons) {
display: none !important;
}
}
+
+// 通用移动设备强制显示规则(防止被其他主题覆盖)
+@media (max-width: 767px) {
+ .o_statusbar_buttons_mobile_fixed,
+ body .o_statusbar_buttons_mobile_fixed,
+ html body .o_statusbar_buttons_mobile_fixed {
+ display: block !important;
+ visibility: visible !important;
+ opacity: 1 !important;
+ position: fixed !important;
+ bottom: 0 !important;
+ left: 0 !important;
+ right: 0 !important;
+ z-index: 99999 !important;
+ // 强制背景色,防止被主题覆盖
+ background-color: #ffffff !important;
+ background: #ffffff !important;
+ }
+
+ // 确保按钮容器内的所有按钮都可见
+ .o_statusbar_buttons_mobile_fixed .o_statusbar_buttons,
+ body .o_statusbar_buttons_mobile_fixed .o_statusbar_buttons,
+ html body .o_statusbar_buttons_mobile_fixed .o_statusbar_buttons {
+ button, a, .btn {
+ // 防止文字被设置为透明
+ color: #ffffff !important;
+ text-indent: 0 !important;
+ // 确保有背景色
+ background-color: #007bff !important;
+ background: #007bff !important;
+ // 确保字体可见
+ font-size: 14px !important;
+ font-weight: 500 !important;
+ }
+ }
+}
From cefee6c114b8e7e26fb0dcb4fed29995f5df8b7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 15:59:28 +0800
Subject: [PATCH 23/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
soong_workflow/models/soong_workflow_record.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/soong_workflow/models/soong_workflow_record.py b/soong_workflow/models/soong_workflow_record.py
index 37193b11f..d526bcf44 100644
--- a/soong_workflow/models/soong_workflow_record.py
+++ b/soong_workflow/models/soong_workflow_record.py
@@ -543,9 +543,10 @@ class SoongWorkflowRecord(models.Model):
def reminders_record(self):
record_id = self.env[self.res_model].search([('id', '=', self.res_id)])
menu_id = self.env['ir.ui.menu'].search([('name', '=', '我的流程')])
+ target_url = f'https://oa.thtzjt.com/web#aciton=4299&model=soong.workflow.record&view_type=list&cids=1-2-3-4&menu_id={menu_id.id}'
for rec in record_id.log_ids:
if rec.approval_state in ['0', '1']:
- url=f'https://oa.thtzjt.com/web#aciton=4299&model=soong.workflow.record&view_type=list&cids=1-2-3-4&menu_id={menu_id.id}'
+ url = self.sudo().env["wecom.apps"].generate_oauth_login_url(target_url, rec.done_by.id)
description = "标题: {}\n".format(record_id.name) + self.env.user.name + ' ' + str(fields.Datetime.now() + timedelta(hours=8))
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa', user_id=rec.done_by.employee_ids.wecom_userid,
title=record_id._description + '催办传阅/抄送,请尽快处理',
@@ -553,7 +554,7 @@ class SoongWorkflowRecord(models.Model):
btntxt="查看详情")
for rec in record_id.log_ids2:
if rec.approval_state == '0':
- url=f'https://oa.thtzjt.com/web#aciton=4299&model=soong.workflow.record&view_type=list&cids=1-2-3-4&menu_id={menu_id.id}'
+ url = self.sudo().env["wecom.apps"].generate_oauth_login_url(target_url, rec.done_by.id)
description = "标题: {}\n".format(record_id.name) + self.env.user.name + ' ' + str(fields.Datetime.now() + timedelta(hours=8))
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa', user_id=rec.done_by.employee_ids.wecom_userid,
title=record_id._description + '催办传阅/抄送,请尽快查看',
From 1b323a71073d3d32caa07d704f51340c09278e5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 17:08:05 +0800
Subject: [PATCH 24/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_holiday/models/inherit_hr_leave.py | 3 ++-
.../models/yuthon_vacation_reports.py | 7 +++++++
.../views/yuthon_vacation_reports_views.xml | 13 +++++++++++--
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/yuthon_holiday/models/inherit_hr_leave.py b/yuthon_holiday/models/inherit_hr_leave.py
index 3ff1a0afc..01bea667a 100644
--- a/yuthon_holiday/models/inherit_hr_leave.py
+++ b/yuthon_holiday/models/inherit_hr_leave.py
@@ -555,7 +555,8 @@ class HolidaysRequestBatch(models.Model):
if self.users_id.employee_ids.company_id.name == '集团本部':
overtime_records = self.env['vacation.over.line'].search([
('employee_id', '=', self.users_id.employee_ids.id),
- ('start_time', '>=', datetime(2026, 1, 1)),
+ ('start_time', '>=', datetime(2025, 12, 1)),
+ ('is_visible', '=', False),
('is_void', '=', False),
('text', '!=', '上月继承额度'),
], order='start_time ASC')
diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py
index 2fad93b59..88e2e0ac8 100644
--- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py
+++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py
@@ -961,6 +961,7 @@ class VacationOverline(models.Model):
department_id = fields.Many2one('hr.department', related='employee_id.department_id', string="部门")
company_id = fields.Many2one('res.company', related='employee_id.company_id', string="公司")
workflow_record_id = fields.Many2one('soong.workflow.record', string='流程')
+ is_visible = fields.Boolean(string='是否隐藏')
update_type= fields.Selection([('add', '增加'), ('reduce', '减少')], string='更新类型')
workday = fields.Float(string='工作日')
last_balance = fields.Float(string='上年结余', compute='_compute_last_balance', store=True)
@@ -1017,6 +1018,12 @@ class VacationOverline(models.Model):
if records_to_update:
records_to_update.write({'is_filing': True})
+ def update_is_visible(self):
+ over_ids = self.env["vacation.over.line"].browse(
+ self._context.get('active_ids', self._context.get('active_id')))
+ for rec in over_ids:
+ rec.is_visible = True
+
def update_line(self):
over_ids = self.env["vacation.over.line"].browse(
self._context.get('active_ids', self._context.get('active_id')))
diff --git a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml
index c962ec04c..c9eb7b82b 100644
--- a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml
+++ b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml
@@ -563,6 +563,7 @@
+
@@ -582,6 +583,7 @@
+
@@ -610,7 +612,7 @@
加班情况
vacation.over.line
tree
-
['|', ('workflow_record_id','!=', False), ('is_initial_number', '=', True), ('update_type', '=', 'add'), ('is_filing','=', False)]
+
['|', ('workflow_record_id','!=', False), ('is_initial_number', '=', True), ('update_type', '=', 'add'), ('is_filing','=', False), ('is_visible', '=', False)]
{'search_default_now_month': 1, 'search_default_group_by_employee_id':1}
@@ -619,7 +621,7 @@
加班情况(归档)
vacation.over.line
tree
-
['|', ('workflow_record_id','!=', False), ('is_initial_number', '=', True), ('update_type', '=', 'add'), ('is_filing','=', True)]
+
['|', ('workflow_record_id','!=', False), ('is_initial_number', '=', True), ('update_type', '=', 'add'), ('is_filing','=', True), ('is_visible', '=', False)]
{'search_default_group_by_employee_id':1}
@@ -631,6 +633,13 @@
code
action = model.update_line()
+
+ 一次性
+
+
+ code
+ action = model.is_visible()
+
误餐情况
vacation.meal.line
From fcb3d6ec2353e45c21aaa71c2f92d39ae77f7512 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 17:47:40 +0800
Subject: [PATCH 25/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../wizard/soong_workflow_comment_wizard.py | 2 +-
.../static/src/js/button_vacation_confirm.js | 14 ++++++++------
.../static/src/xml/button_vacation_confirm.xml | 2 +-
3 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard.py b/soong_workflow/wizard/soong_workflow_comment_wizard.py
index 2e4ea154b..a6dd004b7 100644
--- a/soong_workflow/wizard/soong_workflow_comment_wizard.py
+++ b/soong_workflow/wizard/soong_workflow_comment_wizard.py
@@ -553,7 +553,7 @@ class SoongWorkflowCommentWizard(models.TransientModel):
is_work_remind = False
current_user = self.env.user
current_datetime = fields.Datetime.now()
- is_admin = current_user.has_group('soong_workflow.group_soong_workflow_manager')
+ is_admin = current_user.has_group('base.group_system')
if is_admin:
record_id.log_ids[-1].sudo().write({
'comment': self.comment,
diff --git a/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js b/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js
index 42d44f38c..00223dbe0 100644
--- a/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js
+++ b/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js
@@ -7,12 +7,14 @@ export class CustomAttendanceVacationConfirmController extends ListController {
setup() {
super.setup();
}
- async openConfirm() {
- await this.model.orm.call(
- 'vacation.over.line',
- 'confirm',
- []
- );
+
+ async getAction(lock_type) {
+ const action = await this.orm.call('vacation.over.line', 'confirm', [lock_type], {context: this.props.context});
+ action["context"] = {
+ ...action.context,
+ ...this.model.root.context,
+ }
+ return action
}
}
diff --git a/yuthon_hr_attendance/static/src/xml/button_vacation_confirm.xml b/yuthon_hr_attendance/static/src/xml/button_vacation_confirm.xml
index dfe90d6ce..a62709af5 100644
--- a/yuthon_hr_attendance/static/src/xml/button_vacation_confirm.xml
+++ b/yuthon_hr_attendance/static/src/xml/button_vacation_confirm.xml
@@ -2,7 +2,7 @@
-
From 636d136bbeeaf0a66dcd7a9bc1ccbb81627fc4e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 18:07:30 +0800
Subject: [PATCH 26/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_issue/views/issue_party_approval_views.xml | 1 -
yuthon_salary/wizard/salary_import_wizard.py | 6 +++---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/yuthon_issue/views/issue_party_approval_views.xml b/yuthon_issue/views/issue_party_approval_views.xml
index 405f83748..359be2f7c 100644
--- a/yuthon_issue/views/issue_party_approval_views.xml
+++ b/yuthon_issue/views/issue_party_approval_views.xml
@@ -39,7 +39,6 @@
-
diff --git a/yuthon_salary/wizard/salary_import_wizard.py b/yuthon_salary/wizard/salary_import_wizard.py
index c3544d34f..65ee531f3 100644
--- a/yuthon_salary/wizard/salary_import_wizard.py
+++ b/yuthon_salary/wizard/salary_import_wizard.py
@@ -73,9 +73,9 @@ class SalaryImportWizard(models.TransientModel):
('employee_id', '=', employee.id),
], limit=1)
if not payslip:
- date_from = datetime.date(self.select_year, self.select_month, 1)
- last_day = calendar.monthrange(self.select_year, self.select_month)[1]
- date_to = datetime.date(self.select_year, self.select_month, last_day)
+ date_from = datetime.date(int(self.select_year), int(self.select_month), 1)
+ last_day = calendar.monthrange(int(self.select_year), int(self.select_month))[1]
+ date_to = datetime.date(int(self.select_year), int(self.select_month), last_day)
payslip_vals = {
'name': employee.name,
'employee_id': employee.id,
From 13182c41168e64b552f93e32707adbd06c1407b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 18:24:49 +0800
Subject: [PATCH 27/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_salary/wizard/salary_import_wizard.py | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/yuthon_salary/wizard/salary_import_wizard.py b/yuthon_salary/wizard/salary_import_wizard.py
index 65ee531f3..5c668e6fd 100644
--- a/yuthon_salary/wizard/salary_import_wizard.py
+++ b/yuthon_salary/wizard/salary_import_wizard.py
@@ -4,8 +4,7 @@ from odoo.exceptions import ValidationError, UserError
from pypinyin import pinyin, Style
import xlrd
import base64
-import datetime
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, date
import calendar
@@ -73,9 +72,11 @@ class SalaryImportWizard(models.TransientModel):
('employee_id', '=', employee.id),
], limit=1)
if not payslip:
- date_from = datetime.date(int(self.select_year), int(self.select_month), 1)
- last_day = calendar.monthrange(int(self.select_year), int(self.select_month))[1]
- date_to = datetime.date(int(self.select_year), int(self.select_month), last_day)
+ year = int(self.select_year)
+ month = int(self.select_month)
+ date_from = date(year, month, 1)
+ last_day = calendar.monthrange(year, month)[1]
+ date_to = date(year, month, last_day)
payslip_vals = {
'name': employee.name,
'employee_id': employee.id,
From a54fc200ae57b1611b9434d029df951f86a09a26 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 18:40:59 +0800
Subject: [PATCH 28/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
yuthon_salary/wizard/salary_import_wizard.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/yuthon_salary/wizard/salary_import_wizard.py b/yuthon_salary/wizard/salary_import_wizard.py
index 5c668e6fd..7cdabf384 100644
--- a/yuthon_salary/wizard/salary_import_wizard.py
+++ b/yuthon_salary/wizard/salary_import_wizard.py
@@ -96,6 +96,7 @@ class SalaryImportWizard(models.TransientModel):
current_payslip_lines = payslip.line_ids.filtered(lambda l: l.name)
current_valid_names = {line.name.strip() for line in current_payslip_lines}
global_valid_line_names.update(current_valid_names)
+ payslip.compute_sheet()
for line in payslip.line_ids:
line_name = line.name
From f2db7a627c6586315a9dd3ee37b4b5801121cf0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 18:48:48 +0800
Subject: [PATCH 29/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
soong_workflow/wizard/soong_workflow_comment_wizard_view.xml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
index bf44ab6ef..658191882 100644
--- a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
+++ b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
@@ -94,7 +94,8 @@
-
+
From e7c4a784f7150a987b49fd3602a4a53bf8b78249 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 18:51:43 +0800
Subject: [PATCH 30/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
soong_workflow/wizard/soong_workflow_comment_wizard_view.xml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
index 658191882..9c204fa9b 100644
--- a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
+++ b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
@@ -94,8 +94,7 @@
-
+
From 446481815e6114532a79949fada308e6e150bac5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Fri, 23 Jan 2026 19:06:02 +0800
Subject: [PATCH 31/31] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../wizard/soong_workflow_comment_wizard_view.xml | 2 +-
yuthon_hr_employee/views/yuthon_hr_employee_views.xml | 11 +++++++++++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
index 9c204fa9b..9f3a8e2a1 100644
--- a/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
+++ b/soong_workflow/wizard/soong_workflow_comment_wizard_view.xml
@@ -94,7 +94,7 @@
-
+
diff --git a/yuthon_hr_employee/views/yuthon_hr_employee_views.xml b/yuthon_hr_employee/views/yuthon_hr_employee_views.xml
index bf5626545..7bf7bc3c2 100644
--- a/yuthon_hr_employee/views/yuthon_hr_employee_views.xml
+++ b/yuthon_hr_employee/views/yuthon_hr_employee_views.xml
@@ -590,6 +590,17 @@
+
+
+ hr.employee.member
+ hr.employee
+
+
+
+
+
+
+
hr.employee.inherit.search
hr.employee