From 4d38a8f59a7b39d6a9fcbc1ebf62520fa123aaf3 Mon Sep 17 00:00:00 2001 From: pengyuthon Date: Mon, 26 Jan 2026 22:34:30 +0800 Subject: [PATCH] =?UTF-8?q?=E8=96=AA=E8=B5=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k_ry_mobile_form/README.md | 54 --- k_ry_mobile_form/__init__.py | 1 - k_ry_mobile_form/__manifest__.py | 33 -- .../static/src/js/status_bar_buttons.js | 382 ------------------ .../static/src/scss/status_bar_buttons.scss | 241 ----------- .../static/src/xml/status_bar_buttons.xml | 23 -- 6 files changed, 734 deletions(-) delete mode 100644 k_ry_mobile_form/README.md delete mode 100644 k_ry_mobile_form/__init__.py delete mode 100644 k_ry_mobile_form/__manifest__.py delete mode 100644 k_ry_mobile_form/static/src/js/status_bar_buttons.js delete mode 100644 k_ry_mobile_form/static/src/scss/status_bar_buttons.scss delete mode 100644 k_ry_mobile_form/static/src/xml/status_bar_buttons.xml diff --git a/k_ry_mobile_form/README.md b/k_ry_mobile_form/README.md deleted file mode 100644 index 3cb50c564..000000000 --- a/k_ry_mobile_form/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# k_ry_mobile_form - 科瑞移动端表单优化模块 - -## 功能说明 - -此模块为 Odoo 17 的 form 视图添加移动端优化功能: -- 在手机浏览器中,form 视图 header 的工具按钮栏会悬浮在屏幕底部 -- 提供类似正常 APP 的底部按钮栏体验 -- 桌面端不受影响,保持原有显示方式 - -## 依赖 - -- `base` -- `web` - -## 安装 - -1. 将模块放置在 Odoo 的 addons 目录下 -2. 更新应用列表 -3. 安装 `k_ry_mobile_form` 模块 - -## 技术实现 - -### 文件结构 - -``` -k_ry_mobile_form/ -├── __init__.py -├── __manifest__.py -├── README.md -└── static/ - └── src/ - ├── js/ - │ └── status_bar_buttons.js # 覆盖 StatusBarButtons 组件模板 - ├── xml/ - │ └── status_bar_buttons.xml # 新的模板定义 - └── scss/ - └── status_bar_buttons.scss # 移动端底部悬浮栏样式 -``` - -### 实现原理 - -1. **JavaScript 覆盖**:使用 `patch` 方法覆盖 `StatusBarButtons` 组件的模板 -2. **模板替换**:提供新的模板,根据 `env.isSmall` 判断显示方式 -3. **样式隔离**:使用媒体查询确保移动端和桌面端样式互不影响 - -## 使用说明 - -安装模块后,无需额外配置。在手机浏览器中打开任何包含 header 的 form 视图时,工具按钮栏会自动显示在底部。 - -## 注意事项 - -- 此模块只影响 form 视图的 header 按钮栏 -- 桌面端完全不受影响 -- 支持 iOS 设备的底部安全区域(safe area) diff --git a/k_ry_mobile_form/__init__.py b/k_ry_mobile_form/__init__.py deleted file mode 100644 index 40a96afc6..000000000 --- a/k_ry_mobile_form/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/k_ry_mobile_form/__manifest__.py b/k_ry_mobile_form/__manifest__.py deleted file mode 100644 index c2e17aa32..000000000 --- a/k_ry_mobile_form/__manifest__.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -{ - 'name': "k_ry_mobile_form", - - 'summary': "移动端表单优化", - - 'description': """ - 移动端表单优化模块 - """, - 'author': "josh.feng", - 'website': "", - 'category': '界面优化', - 'version': '17.0.0.1', - - # any module necessary for this one to work correctly - 'depends': ['base', 'web'], - - # always loaded - 'data': [ - ], - 'assets': { - 'web.assets_backend': [ - 'k_ry_mobile_form/static/src/js/status_bar_buttons.js', - 'k_ry_mobile_form/static/src/xml/status_bar_buttons.xml', - 'k_ry_mobile_form/static/src/scss/status_bar_buttons.scss', - ], - }, - 'application': False, - 'installable': True, - 'auto_install': False, - 'license': 'LGPL-3', - -} 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 deleted file mode 100644 index 57f149006..000000000 --- a/k_ry_mobile_form/static/src/js/status_bar_buttons.js +++ /dev/null @@ -1,382 +0,0 @@ -/** @odoo-module **/ - -import { StatusBarButtons } from "@web/views/form/status_bar_buttons/status_bar_buttons"; -import { patch } from "@web/core/utils/patch"; -import { useEffect } from "@odoo/owl"; - -// 检测是否为移动设备(包括iOS Safari) -const isMobileDevice = () => { - if (typeof window === 'undefined') return false; - - // 检测触摸设备 - const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0; - - // 检测用户代理(iOS设备) - const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; - - // 检测屏幕宽度 - const isSmallScreen = window.innerWidth <= 767; - - // 检测是否为移动设备(综合考虑) - return hasTouch && (isIOS || isSmallScreen); -}; - -// 覆盖 StatusBarButtons 组件,添加移动端检测逻辑 -patch(StatusBarButtons, { - template: "k_ry_mobile_form.StatusBarButtons", - setup() { - // 如果 env.isSmall 判断不准确,强制显示移动端按钮 - if (typeof window !== 'undefined') { - useEffect(() => { - const checkAndFixMobileButtons = () => { - 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); - - // 监听窗口大小变化 - const handleResize = () => { - setTimeout(checkAndFixMobileButtons, 100); - }; - window.addEventListener('resize', handleResize); - - return () => { - window.removeEventListener('resize', handleResize); - }; - }); - } - }, -}); - -// 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 = () => { - try { - // 确保移动端按钮容器可见 - const containers = document.querySelectorAll('.o_statusbar_buttons_mobile_fixed'); - if (containers.length === 0) return; - - 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); - } - }); - - // 在移动设备上,确保原始状态栏中的按钮被隐藏 - 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 = () => { - 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, { once: true }); - } else { - // 使用setTimeout确保DOM完全准备好,不阻塞页面加载 - setTimeout(initIOSButtonFix, 100); - } - - // 监听窗口大小变化和方向变化(iOS Safari 横竖屏切换) - window.addEventListener('resize', () => { - debouncedFixIOSButtons(); - }, { passive: true }); - - window.addEventListener('orientationchange', () => { - 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 deleted file mode 100644 index 74a2c302f..000000000 --- a/k_ry_mobile_form/static/src/scss/status_bar_buttons.scss +++ /dev/null @@ -1,241 +0,0 @@ -// Mobile: 底部悬浮栏样式 -// 使用高优先级选择器,防止被其他主题样式覆盖 -.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)) !important; - // iOS Safari 修复:确保元素可交互 - -webkit-transform: translateZ(0) !important; - transform: translateZ(0) !important; - // iOS Safari 修复:防止滚动时fixed定位失效 - -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% !important; - width: 100% !important; - // iOS Safari 修复:确保容器可交互 - pointer-events: auto !important; - -webkit-transform: translateZ(0) !important; - transform: translateZ(0) !important; - // 强制显示 - display: flex !important; - visibility: visible !important; - opacity: 1 !important; - - > * { - flex: 1 !important; - min-width: 0 !important; - // iOS Safari 修复:确保子元素可交互 - pointer-events: auto !important; - // 强制显示 - display: block !important; - visibility: visible !important; - opacity: 1 !important; - - > button, - > a, - > .btn { - width: 100% !important; - white-space: nowrap !important; - overflow: hidden !important; - text-overflow: ellipsis !important; - // 确保按钮有足够的点击区域 - min-height: 44px !important; - // iOS Safari 修复:确保按钮可点击 - cursor: pointer !important; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1) !important; - touch-action: manipulation !important; - // iOS Safari 修复:防止文本选择影响点击 - -webkit-user-select: none !important; - user-select: none !important; - -webkit-touch-callout: none !important; - // iOS Safari 修复:确保按钮在层级之上 - position: relative !important; - z-index: 1 !important; - // iOS Safari 修复:确保pointer-events正确 - pointer-events: auto !important; - // iOS Safari 修复:防止transform影响点击 - -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, - body .o_statusbar_buttons_mobile_fixed, - html body .o_statusbar_buttons_mobile_fixed { - // 只在非触摸设备上隐藏(桌面浏览器) - @media (hover: hover) and (pointer: fine) { - display: none !important; - } - } -} - -// 移动端隐藏原始状态栏中的按钮(避免重复显示) -@include media-breakpoint-down(md) { - .o_form_statusbar { - // 隐藏状态栏中的按钮容器,但保留字段等其他内容 - > .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons) { - display: none !important; - } - } - - // 为 form view 添加底部 padding,避免内容被底部悬浮栏遮挡 - .o_form_view { - padding-bottom: 80px; // 为底部悬浮栏预留空间 - } -} - -// iOS Safari 特殊处理:确保在 iOS 设备上按钮可见 -// 使用高优先级选择器,防止被其他主题样式覆盖 -@media (hover: none) and (pointer: coarse) { - .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), - 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; - } - } -} diff --git a/k_ry_mobile_form/static/src/xml/status_bar_buttons.xml b/k_ry_mobile_form/static/src/xml/status_bar_buttons.xml deleted file mode 100644 index 8dc0df7f1..000000000 --- a/k_ry_mobile_form/static/src/xml/status_bar_buttons.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - -
-
- - - -
-
- -
- - - -
-
- -