fix: 更换日期时间组件

This commit is contained in:
Zhao Zhao Shen 2025-03-11 19:13:18 +08:00
parent d44fc687dc
commit c835e38d82
7 changed files with 366 additions and 170 deletions

View File

@ -1,4 +1,5 @@
#!/bin/bash
# 使用后端本地调用api方式部署
# 加载配置
if [ -f "./deploy.config.sh" ]; then
@ -36,13 +37,35 @@ docker build -t ${DOCKER_IMAGE_NAME} .
echo "6. 保存 Docker 镜像..."
docker save ${DOCKER_IMAGE_NAME} > ${DOCKER_IMAGE_NAME}.tar
# 7. 传输文件到服务器
echo "7. 传输文件到服务器..."
# ssh -p 22 owner@192.168.1.199
scp -v -P ${REMOTE_PORT} ${DOCKER_IMAGE_NAME}.tar ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/
# 7. 创建 nginx 配置文件
echo "7. 创建 nginx 配置文件..."
cat > nginx.conf << 'NGINX_EOF'
server {
listen 80;
server_name localhost;
# 8. 在远程服务器上执行部署
echo "8. 在远程服务器上执行部署..."
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://192.168.1.199:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
NGINX_EOF
# 8. 传输文件到服务器
echo "8. 传输文件到服务器..."
scp -v -P ${REMOTE_PORT} ${DOCKER_IMAGE_NAME}.tar ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/
scp -v -P ${REMOTE_PORT} nginx.conf ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/
# 9. 在远程服务器上执行部署
echo "9. 在远程服务器上执行部署..."
ssh -p ${REMOTE_PORT} ${REMOTE_USER}@${REMOTE_HOST} << EOF
set -e # 遇到错误立即退出
@ -51,15 +74,19 @@ ssh -p ${REMOTE_PORT} ${REMOTE_USER}@${REMOTE_HOST} << EOF
docker load < ${DOCKER_IMAGE_NAME}.tar
docker stop ${DOCKER_CONTAINER_NAME} 2>/dev/null || true
docker rm ${DOCKER_CONTAINER_NAME} 2>/dev/null || true
docker run -d \
--name ${DOCKER_CONTAINER_NAME} \
-p ${APP_PORT}:80 \
--restart unless-stopped \
docker run -d \\
--name ${DOCKER_CONTAINER_NAME} \\
-p ${APP_PORT}:80 \\
-v ${REMOTE_PATH}/nginx.conf:/etc/nginx/conf.d/default.conf \\
--restart unless-stopped \\
${DOCKER_IMAGE_NAME}
EOF
echo "部署完成!"
# echo "部署完成!"
# 清理本地临时文件
rm -f nginx.conf
rm -f ${DOCKER_IMAGE_NAME}.tar
# 10. 检查部署状态
# echo "10. 检查部署状态..."

View File

@ -3,7 +3,7 @@ import request from '@/utils/request';
// 获取点检页面当前值
export function getInspectionCurrent(deviceId, inputTime) {
return request({
url: `/Check/currunt?deviceId=${deviceId}&inputTime=${inputTime}`,
url: `/Check/currunt?deviceTypeId=${deviceId}&inputTime=${inputTime}`,
method: 'get'
});
}
@ -11,7 +11,7 @@ export function getInspectionCurrent(deviceId, inputTime) {
// 获取点检页面整点数值
export function getInspectionData(deviceId, inputTime, shift) {
return request({
url: `/Check/sharp?deviceId=${deviceId}&inputTime=${inputTime}&shift=${shift}`,
url: `/Check/sharp?deviceTypeId=${deviceId}&inputTime=${inputTime}&shift=${shift}`,
method: 'get'
});
}

View File

@ -1,66 +1,72 @@
<template>
<div class="custom-datetime-picker">
<div class="picker-header">
<span>选择日期和时间</span>
<button @click="emitDone">确定</button>
</div>
<div class="picker-body">
<input type="datetime-local" v-model="datetime" />
</div>
</div>
<el-date-picker ref="datePickerRef" v-model="internalValue" type="datetime" :clearable="false" v-bind="$attrs" format="YYYY/MM/DD HH:mm"
:disabled-minutes="disabledMinutes" popper-class="popperTime" :visible-change="visibleChange" style="display: none"
value-format="YYYY-MM-DD HH:mm:ss"></el-date-picker>
</template>
<script setup>
import { ref } from 'vue';
<script setup name="DataTime">
import { ref, nextTick } from 'vue';
import { defineExpose } from 'vue';
const datetime = ref('');
const datePickerRef = ref(null); //
const emitDone = () => {
const event = new CustomEvent('done', { detail: datetime.value });
window.dispatchEvent(event);
const internalValue = ref(null);
//
const openPicker = () => {
datePickerRef.value.focus(); // Element focus
};
defineExpose({ openPicker }); //
const disabledMinutes = () => {
hideInvalidMinutes();
return Array.from({ length: 60 }, (v, k) => k).filter(minute => ![0, 15, 30, 45].includes(minute));
};
const hideInvalidMinutes = () => {
nextTick(() => {
const minuteItems = document.querySelectorAll('.el-time-panel .el-time-spinner__wrapper:nth-child(2n) .el-time-spinner__item');
minuteItems.forEach(item => {
const minute = parseInt(item.textContent, 10);
if (![0, 15, 30, 45].includes(minute)) {
item.classList.add('is-disabled');
item.style.display = 'none';
} else {
item.classList.remove('is-disabled');
item.style.display = '';
}
});
});
};
const handleGlobalFocus = (event) => {
const target = event.target;
if (target && target.closest('.el-date-range-picker__time-picker-wrap:nth-child(2n) .el-input__inner')) {
hideInvalidMinutes();
}
};
const visibleChange = () => {
document.addEventListener('focus', handleGlobalFocus, true);
};
</script>
<style scoped>
.custom-datetime-picker {
background-color: #23233C;
padding: 1rem;
border-radius: 0.5rem;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
<style lang="css">
.popperTime {
.el-time-panel__content:after,
.el-time-panel__content:before {
content: none;
}
.el-time-spinner__list:after,
.el-time-spinner__list:before {
content: none !important;
}
.el-time-spinner__item.is-active:not(.is-disabled) {
background-color: var(--el-datepicker-active-color);
color: #fff;
}
.picker-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.picker-header span {
font-size: 1.2rem;
}
.picker-header button {
background-color: #1a1a40;
color: #fff;
border: none;
padding: 0.5rem 1rem;
border-radius: 0.25rem;
cursor: pointer;
}
.picker-body {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.picker-body input {
background-color: #1a1a40;
color: #fff;
border: none;
padding: 0.5rem;
border-radius: 0.25rem;
}
</style>

View File

@ -2,7 +2,8 @@ import axios from 'axios';
const service = axios.create({
// baseURL: 'http://192.168.1.199:8080/api', // 办公室测试接口
baseURL: 'http://39.105.9.124:8090/api', // 家用测试接口
// baseURL: 'http://39.105.9.124:8090/api', // 家用测试接口
baseURL: '/api',
timeout: 5000, // 请求超时时间
headers: {
"Access-Control-Allow-Origin": "*",

View File

@ -27,7 +27,7 @@
</template>
<script setup>
import { ref, defineProps, defineEmits } from 'vue';
import { ref, defineProps, defineEmits, onMounted } from 'vue';
import { IxButton, IxChip } from '@siemens/ix-vue';
import moment from 'moment-timezone';
@ -35,6 +35,7 @@ const props = defineProps({
itemName: String,
itemTime: String,
timezone: String,
currentStatus: String,
});
const reason = ref('');
@ -53,6 +54,13 @@ const handleSubmit = () => {
const currentTime = moment().tz(props.timezone).format('HH:mm');
emit('submit', currentTime, reason.value);
};
onMounted(() => {
if(props.currentStatus === '已处理') {
//
reason.value = '已处理';
}
});
</script>
<style scoped>

View File

@ -72,7 +72,7 @@
'highlight-cell': item.data[hour]?.checkStatus === 1,
'alarm-cell': item.data[hour]?.checkStatus === 0
}"
@click="item.data[hour]?.checkStatus === 0 ? handleAlarmInspection(hour, index) : null">
@click="item.data[hour]?.checkStatus === 0 || item.data[hour]?.checkStatus === 1 ? handleAlarmInspection(hour, index, item.data[hour]?.checkStatus) : null">
{{ item.data[hour]?.value || '--' }}
</span>
</div>
@ -81,7 +81,7 @@
</div>
</div>
<!-- 点检表单 -->
<InspectionForm v-if="showForm" :itemName="selectedItemName" :itemTime="selectedItemTime" :timezone="timezone" @close="showForm = false" @submit="(currentTime, reason) => handleFormSubmit(selectedItemIndex, reason)" />
<InspectionForm v-if="showForm" :itemName="selectedItemName" :itemTime="selectedItemTime" :timezone="timezone" :currentStatus="currentStatus" @close="showForm = false" @submit="(currentTime, reason) => handleFormSubmit(selectedItemIndex, reason)" />
</div>
</template>
@ -135,6 +135,7 @@ const formatDate = (date) => {
const day = d.getDate().toString().padStart(2, '0');
return `${year}/${month}/${day}`;
};
const currentStatus = ref('');
const currentDate = formatDate(new Date());
@ -210,10 +211,11 @@ const handleInspection = (hour, index) => {
};
//
const handleAlarmInspection = (hour, index) => {
const handleAlarmInspection = (hour, index, status) => {
selectedItemName.value = inspectionItems.value[index].label;
selectedItemTime.value = hour;
selectedItemIndex.value = index; // selectedItemIndex
currentStatus.value = status === 0 ? '未处理' : '已处理';
showForm.value = true;
};
@ -427,11 +429,11 @@ const getDeviceNameById = (id) => {
// let autoUpdateInterval = null;
// onMounted(async () => {
// await fetchDeviceList();
// fetchCurrentValues();
// fetchInspectionData();
// sendDataToParent();
onMounted(async () => {
await fetchDeviceList();
fetchCurrentValues();
fetchInspectionData();
sendDataToParent();
// const setupAutoUpdate = () => {
// if (isAutoUpdate.value) {
@ -464,7 +466,7 @@ const getDeviceNameById = (id) => {
// fetchInspectionData();
// setupAutoUpdate();
// });
// });
});
// onUnmounted(() => {
// if (autoUpdateInterval) {

View File

@ -4,25 +4,37 @@
<!-- 添加实时显示时间 -->
<div v-if="appSwitchConfig.currentAppId === 'mis-app'" class="time-display">{{ currentTime }}</div>
<!-- 确保图标按钮正确显示 -->
<!-- 报警图标 -->
<el-badge v-if="appSwitchConfig.currentAppId === 'mis-app'" :value="alarmCount" class="item">
<IxIconButton icon="alarm-bell-filled" variant="secondary" ghost></IxIconButton>
</el-badge>
<IxIconButton v-if="appSwitchConfig.currentAppId === 'mis-app'" icon="calendar-filled" variant="secondary" ghost @click="toggleDatetimePicker"></IxIconButton>
<IxIconButton v-if="appSwitchConfig.currentAppId === 'mis-app'" icon="alarm-clock-filled" variant="secondary" ghost @click="handleReset"></IxIconButton>
<!-- 时间选择器整合到日历图标按钮 -->
<IxIconButton v-if="appSwitchConfig.currentAppId === 'mis-app'" icon="calendar-filled" variant="secondary" ghost
@click="openDatePicker"></IxIconButton>
<!-- <el-date-picker v-model="selectedDatetime" type="datetime" format="YYYY-MM-DD HH:mm"
:disabled-minutes="disabledMinutes" @change="handleDatetimeChange" ref="datePickerRef"
popper-class="custom-picker-popover" style="display: none" :visible-change="visibleChange"
:popper-options="pickerOptions" :teleported="false" /> -->
<el-date-picker ref="datePickerRef" v-model="selectedDatetime" type="datetime" :clearable="false" v-bind="$attrs" format="YYYY-MM-DD HH:mm"
:disabled-minutes="disabledMinutes" popper-class="custom-picker-popover" :visible-change="visibleChange" style="display: none" @change="handleDatetimeChange" :popper-options="pickerOptions" :teleported="false"></el-date-picker>
<!--重置-->
<IxIconButton v-if="appSwitchConfig.currentAppId === 'mis-app'" icon="alarm-clock-filled" variant="secondary"
ghost @click="handleReset"></IxIconButton>
<!-- 添加遮罩层和日期选择器组件 -->
<!-- <div v-if="showDatetimePicker" class="overlay" @click="closeDatetimePicker"></div>
<div v-if="showDatetimePicker" class="datetime-picker-container">
<IxDatetimePicker v-if="appSwitchConfig.currentAppId === 'mis-app'" range="false" showSeconds="false" show-time-reference="true" @done="handleDatetimePickerDone" />
<IxDatePicker v-else range="false" @dateChange="handleDatePickerDone" style="--theme-menu--background: '#232323'"/>
<button class="close-button" @click="closeDatetimePicker">关闭</button>
</div> -->
</IxApplicationHeader>
<IxContent class="mainContent">
<router-view @update-history="updateHistory" @reset="reset" @send-data="handleDataFromChild"></router-view>
</IxContent>
<!-- 添加遮罩层和日期选择器组件 -->
<div v-if="showDatetimePicker" class="overlay" @click="closeDatetimePicker"></div>
<div v-if="showDatetimePicker" class="datetime-picker-container">
<IxDatetimePicker v-if="appSwitchConfig.currentAppId === 'mis-app'" range="false" showSeconds="false" show-time-reference="true" @done="handleDatetimePickerDone" />
<IxDatePicker v-else range="false" @dateChange="handleDatePickerDone" style="--theme-menu--background: '#232323'"/>
<button class="close-button" @click="closeDatetimePicker">关闭</button>
</div>
</IxApplication>
</template>
@ -38,7 +50,7 @@ import {
IxDatetimePicker,
IxDatePicker,
} from '@siemens/ix-vue';
import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
import { ref, onMounted, onUnmounted, watch, computed, nextTick } from 'vue';
import { useAlarmStore } from '@/stores/alarmStore'; // alarmStore
const alarmStore = useAlarmStore(); // 使 alarmStore
@ -69,6 +81,37 @@ let appSwitchConfig = {
],
};
//
const pickerOptions = {
placement: 'bottom-end',
modifiers: [
{
name: 'offset',
options: { offset: [0, 0] } //
},
{ name: 'computeStyles', options: { gpuAcceleration: false } } // GPU
]
};
const timeShortcuts = [
{
text: '最近15分钟',
value: () => {
const date = new Date();
date.setMinutes(Math.floor(date.getMinutes() / 15) * 15);
return date;
}
},
{
text: '整点时间',
value: () => {
const date = new Date();
date.setMinutes(0);
return date;
}
}
];
const currentTime = ref('');
const showDatetimePicker = ref(false);
const selectedDatetime = ref('');
@ -85,9 +128,9 @@ const updateTime = () => {
currentTime.value = `${year}-${month}-${day} ${hours}:${minutes}`;
};
const toggleDatetimePicker = () => {
showDatetimePicker.value = !showDatetimePicker.value;
};
// const toggleDatetimePicker = () => {
// showDatetimePicker.value = !showDatetimePicker.value;
// };
const handleReset = () => {
// getHistory
@ -97,69 +140,129 @@ const handleReset = () => {
isAutoUpdate.value = true; //
};
const handleDatetimePickerDone = (event) => {
selectedDatetime.value = event.detail;
showDatetimePicker.value = false;
updateHistoryWithTime(selectedDatetime.value);
isAutoUpdate.value = false; //
};
// const handleDatetimePickerDone = (event) => {
// selectedDatetime.value = event.detail;
// showDatetimePicker.value = false;
// updateHistoryWithTime(selectedDatetime.value);
// isAutoUpdate.value = false; //
// };
const handleDatePickerDone = (event) => {
selectedDatetime.value = event.detail;
showDatetimePicker.value = false;
updateHistoryWithDate(selectedDatetime.value);
isAutoUpdate.value = false; //
};
// const handleDatePickerDone = (event) => {
// selectedDatetime.value = event.detail;
// showDatetimePicker.value = false;
// updateHistoryWithDate(selectedDatetime.value);
// isAutoUpdate.value = false; //
// };
const updateHistoryWithTime = (datetime) => {
// datetime YYYY-MM-DD HH:mm:ss
const parsedDate = new Date(datetime.replace(/-/g, '/'));
if (isNaN(parsedDate.getTime())) {
console.error('Invalid datetime format:', datetime);
return;
}
const year = parsedDate.getFullYear();
const month = String(parsedDate.getMonth() + 1).padStart(2, '0');
const day = String(parsedDate.getDate()).padStart(2, '0');
const hours = String(parsedDate.getHours()).padStart(2, '0');
const minutes = String(parsedDate.getMinutes()).padStart(2, '0');
const seconds = String(parsedDate.getSeconds()).padStart(2, '0');
const formattedDatetime = `${year}-${month}-${day} ${hours}:${minutes}`;
// getHistory
const event = new CustomEvent('update-history', { detail: formattedDatetime });
// const updateHistoryWithTime = (datetime) => {
// // datetime YYYY-MM-DD HH:mm:ss
// const parsedDate = new Date(datetime.replace(/-/g, '/'));
// if (isNaN(parsedDate.getTime())) {
// console.error('Invalid datetime format:', datetime);
// return;
// }
// const year = parsedDate.getFullYear();
// const month = String(parsedDate.getMonth() + 1).padStart(2, '0');
// const day = String(parsedDate.getDate()).padStart(2, '0');
// const hours = String(parsedDate.getHours()).padStart(2, '0');
// const minutes = String(parsedDate.getMinutes()).padStart(2, '0');
// const seconds = String(parsedDate.getSeconds()).padStart(2, '0');
// const formattedDatetime = `${year}-${month}-${day} ${hours}:${minutes}`;
// // getHistory
// const event = new CustomEvent('update-history', { detail: formattedDatetime });
currentTime.value = formattedDatetime;
// currentTime.value = formattedDatetime;
window.dispatchEvent(event);
};
// window.dispatchEvent(event);
// };
const updateHistoryWithDate = (date) => {
// date YYYY-MM-DD
const { from } = date;
const parsedDate = new Date(from);
if (isNaN(parsedDate.getTime())) {
console.error('Invalid date format:', from);
return;
}
const year = parsedDate.getFullYear();
const month = String(parsedDate.getMonth() + 1).padStart(2, '0');
const day = String(parsedDate.getDate()).padStart(2, '0');
const formattedDate = `${year}-${month}-${day}`;
// getHistory
const event = new CustomEvent('update-history', { detail: formattedDate });
// const updateHistoryWithDate = (date) => {
// // date YYYY-MM-DD
// const { from } = date;
// const parsedDate = new Date(from);
// if (isNaN(parsedDate.getTime())) {
// console.error('Invalid date format:', from);
// return;
// }
// const year = parsedDate.getFullYear();
// const month = String(parsedDate.getMonth() + 1).padStart(2, '0');
// const day = String(parsedDate.getDate()).padStart(2, '0');
// const formattedDate = `${year}-${month}-${day}`;
// // getHistory
// const event = new CustomEvent('update-history', { detail: formattedDate });
currentTime.value = formattedDate;
// currentTime.value = formattedDate;
window.dispatchEvent(event);
};
// window.dispatchEvent(event);
// };
const handleDataFromChild = (data, name) => {
appName.value = data;
appSwitchConfig.currentAppId = name;
};
const closeDatetimePicker = () => {
showDatetimePicker.value = false;
// const closeDatetimePicker = () => {
// showDatetimePicker.value = false;
// };
//
const datePickerRef = ref(null);
// const selectedDatetime = ref('');
// 15
const disabledMinutes = () => {
hideInvalidMinutes();
return Array.from({ length: 60 }, (v, k) => k).filter(minute => ![0, 15, 30, 45].includes(minute));
};
const hideInvalidMinutes = () => {
nextTick(() => {
const minuteItems = document.querySelectorAll('.el-time-panel .el-time-spinner__wrapper:nth-child(2n) .el-time-spinner__item');
minuteItems.forEach(item => {
const minute = parseInt(item.textContent, 10);
if (![0, 15, 30, 45].includes(minute)) {
item.classList.add('is-disabled');
item.style.display = 'none';
} else {
item.classList.remove('is-disabled');
item.style.display = '';
}
});
});
};
const handleGlobalFocus = (event) => {
const target = event.target;
if (target && target.closest('.el-date-range-picker__time-picker-wrap:nth-child(2n) .el-input__inner')) {
hideInvalidMinutes();
}
};
const visibleChange = () => {
document.addEventListener('focus', handleGlobalFocus, true);
}
//
const openDatePicker = () => {
datePickerRef.value?.handleOpen();
};
const handleDatetimeChange = (value) => {
if (!value) return;
// 使 Element Plus Date
const formattedDatetime = `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, '0')}-${String(value.getDate()).padStart(2, '0')} ${String(value.getHours()).padStart(2, '0')}:${String(value.getMinutes()).padStart(2, '0')}`;
//
currentTime.value = formattedDatetime;
//
const event = new CustomEvent('update-history', { detail: formattedDatetime });
window.dispatchEvent(event);
//
isAutoUpdate.value = false;
};
onMounted(() => {
@ -167,13 +270,9 @@ onMounted(() => {
const interval = setInterval(() => {
if (showDatetimePicker.value || !isAutoUpdate.value) return; //
updateTime();
}, 60000); //
}, 1000); //
onUnmounted(() => clearInterval(interval)); //
});
//
setInterval(updateTime, 1000); //
</script>
<style scoped>
@ -274,8 +373,8 @@ ix-application {
}
.datetime-picker-container {
position: absolute;
top: 4rem;
position: fixed;
top: 1rem;
right: 1rem;
z-index: 1000;
background: #23233C;
@ -330,4 +429,57 @@ ix-application {
font-size: 1.2rem;
margin-right: 1rem;
}
/* 工业级时间选择器改造 */
:deep(.custom-picker-popover) {
--el-bg-color-overlay: #23233C;
inset: unset !important;
top: 2rem !important;
right: 5rem !important;
border-radius: 2px !important;
--el-border-color: #67C23A;
.el-time-panel__content:after,
.el-time-panel__content:before {
content: none;
}
.el-time-spinner__list:after,
.el-time-spinner__list:before {
content: none !important;
}
.el-time-spinner__item.is-active:not(.is-disabled) {
background-color: var(--el-datepicker-active-color);
color: #fff;
}
}
:deep(.el-picker-panel) {
color: #fff;
background: #23233C;
border: 1px solid #1384b4;
}
:deep(.el-picker-panel__icon-btn) {
color: #ffffff;
}
:deep(.el-date-picker__header-label) {
color: #ffffff;
}
:deep(.el-date-table th) {
color: #ffffff;
}
:deep(.el-time-panel) {
color: #fff;
background: #23233C;
border: 1px solid #1384b4;
}
:deep(.el-time-spinner__item) {
color: #ffffff;
--el-text-color-primary: #1384b4;
}
</style>