diff --git a/k_ry_mobile_form/README.md b/k_ry_mobile_form/README.md new file mode 100644 index 000000000..3cb50c564 --- /dev/null +++ b/k_ry_mobile_form/README.md @@ -0,0 +1,54 @@ +# 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/static/src/js/status_bar_buttons.js b/k_ry_mobile_form/static/src/js/status_bar_buttons.js index 6fa0ea98e..367153a10 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 @@ -7,3 +7,49 @@ import { patch } from "@web/core/utils/patch"; patch(StatusBarButtons, { template: "k_ry_mobile_form.StatusBarButtons", }); + +// iOS Safari修复:确保移动端按钮在iOS上可点击 +// 使用MutationObserver监听DOM变化,确保新添加的按钮也能正常工作 +if (typeof window !== 'undefined' && typeof document !== 'undefined') { + const fixIOSButtons = () => { + const containers = document.querySelectorAll('.o_statusbar_buttons_mobile_fixed'); + containers.forEach(container => { + 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'; + } + button.style.cursor = 'pointer'; + button.style.touchAction = 'manipulation'; + }); + }); + }; + + // 初始化函数:确保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 + }); + } else { + // 如果body还不存在,等待DOMContentLoaded + document.addEventListener('DOMContentLoaded', initIOSButtonFix, { once: true }); + } + }; + + // 页面加载后执行 + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initIOSButtonFix); + } else { + // 使用setTimeout确保DOM完全准备好 + setTimeout(initIOSButtonFix, 0); + } +} 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 d07f8d598..1b7798e08 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 @@ -11,22 +11,52 @@ padding: map-get($spacers, 2) map-get($spacers, 3); // 为底部悬浮栏预留空间,避免内容被遮挡(支持 iOS safe area) padding-bottom: calc(#{map-get($spacers, 2)} + env(safe-area-inset-bottom, 0px)); + // iOS Safari 修复:确保元素可交互 + -webkit-transform: translateZ(0); + transform: translateZ(0); + // iOS Safari 修复:防止滚动时fixed定位失效 + -webkit-backface-visibility: hidden; + backface-visibility: hidden; .o_statusbar_buttons { max-width: 100%; width: 100%; + // iOS Safari 修复:确保容器可交互 + pointer-events: auto; + -webkit-transform: translateZ(0); + transform: translateZ(0); > * { flex: 1; min-width: 0; + // iOS Safari 修复:确保子元素可交互 + pointer-events: auto; - > button { + > button, + > a, + > .btn { width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; // 确保按钮有足够的点击区域 min-height: 44px; + // iOS Safari 修复:确保按钮可点击 + cursor: pointer; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1); + touch-action: manipulation; + // iOS Safari 修复:防止文本选择影响点击 + -webkit-user-select: none; + user-select: none; + -webkit-touch-callout: none; + // iOS Safari 修复:确保按钮在层级之上 + position: relative; + z-index: 1; + // iOS Safari 修复:确保pointer-events正确 + pointer-events: auto !important; + // iOS Safari 修复:防止transform影响点击 + -webkit-transform: translateZ(0); + transform: translateZ(0); } } }