@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user