Merge pull request !8226 from 李鹏宇/dev
This commit is contained in:
李鹏宇
2026-01-23 01:40:16 +00:00
committed by Gitee
4 changed files with 124 additions and 27 deletions
@@ -2,18 +2,85 @@
import { StatusBarButtons } from "@web/views/form/status_bar_buttons/status_bar_buttons";
import { patch } from "@web/core/utils/patch";
import { useEffect } from "@odoo/owl";
// 覆盖 StatusBarButtons 组件的模板
// 检测是否为移动设备(包括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 = () => {
// 如果是移动设备但 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';
});
}
};
// 延迟执行,确保DOM已渲染
setTimeout(checkAndFixMobileButtons, 100);
// 监听窗口大小变化
const handleResize = () => {
setTimeout(checkAndFixMobileButtons, 100);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
});
}
},
});
// iOS Safari修复:确保移动端按钮在iOS上可点击
// 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 => {
// 如果是移动设备,确保容器可见
if (isMobileDevice()) {
const computedStyle = getComputedStyle(container);
if (computedStyle.display === 'none') {
container.style.display = 'block';
}
container.style.visibility = 'visible';
container.style.opacity = '1';
}
// 修复按钮的交互性
const buttons = container.querySelectorAll('button, a.btn, .btn, a[role="button"], .o_statusbar_buttons > * > button');
buttons.forEach(button => {
// 确保pointer-events正确设置
@@ -22,8 +89,18 @@ if (typeof window !== 'undefined' && typeof document !== 'undefined') {
}
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';
});
}
};
// 初始化函数:确保DOM准备好后再设置observer
@@ -34,10 +111,14 @@ if (typeof window !== 'undefined' && typeof document !== 'undefined') {
// 确保document.body存在后再创建observer
if (document.body) {
// 监听DOM变化,确保动态添加的按钮也能正常工作
const observer = new MutationObserver(fixIOSButtons);
const observer = new MutationObserver(() => {
fixIOSButtons();
});
observer.observe(document.body, {
childList: true,
subtree: true
subtree: true,
attributes: true,
attributeFilter: ['style', 'class']
});
} else {
// 如果body还不存在,等待DOMContentLoaded
@@ -52,4 +133,13 @@ if (typeof window !== 'undefined' && typeof document !== 'undefined') {
// 使用setTimeout确保DOM完全准备好
setTimeout(initIOSButtonFix, 0);
}
// 监听窗口大小变化和方向变化(iOS Safari 横竖屏切换)
window.addEventListener('resize', () => {
setTimeout(fixIOSButtons, 100);
});
window.addEventListener('orientationchange', () => {
setTimeout(fixIOSButtons, 200);
});
}
@@ -62,10 +62,13 @@
}
}
// 桌面端隐藏移动端悬浮栏
// 桌面端隐藏移动端悬浮栏(但保留触摸设备的显示)
@include media-breakpoint-up(md) {
.o_statusbar_buttons_mobile_fixed {
display: none !important;
// 只在非触摸设备上隐藏(桌面浏览器)
@media (hover: hover) and (pointer: fine) {
display: none !important;
}
}
}
@@ -74,7 +77,7 @@
.o_form_statusbar {
// 隐藏状态栏中的按钮容器,但保留字段等其他内容
> .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons) {
display: none;
display: none !important;
}
}
@@ -83,3 +86,16 @@
padding-bottom: 80px; // 为底部悬浮栏预留空间
}
}
// iOS Safari 特殊处理:确保在 iOS 设备上按钮可见
@media (hover: none) and (pointer: coarse) {
.o_statusbar_buttons_mobile_fixed {
display: block !important;
visibility: visible !important;
opacity: 1 !important;
}
.o_form_statusbar > .o_statusbar_buttons:not(.o_statusbar_buttons_mobile_fixed .o_statusbar_buttons) {
display: none !important;
}
}
@@ -4,24 +4,20 @@
<!-- 覆盖 web.StatusBarButtons 模板,实现移动端底部悬浮栏 -->
<t t-name="k_ry_mobile_form.StatusBarButtons">
<t t-set="slots" t-value="visibleSlotNames" />
<t t-if="env.isSmall">
<!-- Mobile: 底部悬浮栏 -->
<div class="o_statusbar_buttons_mobile_fixed">
<div class="o_statusbar_buttons d-flex align-items-center justify-content-center gap-2">
<t t-foreach="slots" t-as="slot" t-key="slot">
<t t-slot="{{ slot }}" />
</t>
</div>
</div>
</t>
<t t-else="">
<!-- Desktop: 正常显示 -->
<div class="o_statusbar_buttons d-flex align-items-center align-content-around flex-wrap gap-1">
<!-- 移动端:底部悬浮栏(始终渲染,通过CSS控制显示) -->
<div class="o_statusbar_buttons_mobile_fixed" t-att-style="env.isSmall ? '' : 'display: none;'">
<div class="o_statusbar_buttons d-flex align-items-center justify-content-center gap-2">
<t t-foreach="slots" t-as="slot" t-key="slot">
<t t-slot="{{ slot }}" />
</t>
</div>
</t>
</div>
<!-- 桌面端:正常显示 -->
<div class="o_statusbar_buttons d-flex align-items-center align-content-around flex-wrap gap-1" t-att-style="env.isSmall ? 'display: none;' : ''">
<t t-foreach="slots" t-as="slot" t-key="slot">
<t t-slot="{{ slot }}" />
</t>
</div>
</t>
</templates>
@@ -107,7 +107,6 @@ class AppletAttendance(Controller):
[('employee_id', '=', employee_id.id), ('current_data', '=', current_date)])
check_in = attendance_id.check_in + timedelta(hours=8) if attendance_id.check_in else ''
check_out = attendance_id.check_out + timedelta(hours=8) if attendance_id.check_out else ''
_logger.info(f"------/yuthon/att/today---------接口收到响应-------------------------------")
if attendance_id.shift_name:
shift_name = attendance_id.shift_name
else:
@@ -206,14 +205,12 @@ class AppletAttendance(Controller):
state = 'yes'
wifi = kw['wifi_name']
_logger.info(f'{wifi}---wifi可以打卡----------')
_logger.info(f'{wifi}---wifi可以打卡----------')
_logger.info(f'{wifi}---wifi可以打卡----------')
if self.is_workday(current_date):
attendance_id_class = f"{shift_name} {start_time_str}-{end_time_str}"
else:
attendance_id_class = f"{shift_name}休息"
data = {
'location': "已被禁用",
'location': " ",
'user_id': user_id.id,
'class': f"{attendance_id_class}",
'state_result': state_result,
@@ -223,8 +220,6 @@ class AppletAttendance(Controller):
'check_out_status': check_out_status,
'state': state,
},
_logger.info(f"------/yuthon/att/today---------接口收到响应--------{state}\n{state}\n{state}\n{state}\n{state}\n{state}\n{state}\n{state}\n{state}\n-----------------------")
_logger.info(f'{data}--{message}-----------')
return_data = {'data': data, 'code': '200', 'message': message, }
return json.dumps(return_data)