GateWay/src/views/flipScreen/flipScreen.vue

716 lines
21 KiB
Vue
Raw Normal View History

2025-04-24 16:53:10 +08:00
<template>
<div class="page-container">
<Header :title="currentTitle"></Header>
<div class="content">
<!-- Top Section - 4 buttons in 2 rows -->
<div class="control-section">
<div class="button-grid top-grid">
<div class="control-btn" @click="handlePlatformControl('up')">
<div class="btn-icon">
<van-icon name="arrow-up" />
</div>
<div class="btn-label">平台上升</div>
</div>
<div class="control-btn" @click="handlePlatformControl('down')">
<div class="btn-icon">
<van-icon name="arrow-down" />
</div>
<div class="btn-label">平台下降</div>
</div>
<div class="control-btn" @click="handleScreenControl">
<div class="btn-icon">
<van-icon name="tv-o" />
</div>
<div class="btn-label">屏幕开关</div>
</div>
<div class="control-btn" @click="showLaserModeDialog">
<div class="btn-icon">
<van-icon name="bulb-o" />
</div>
<div class="btn-label">激光模式</div>
</div>
</div>
</div>
<!-- Middle Section - 6 buttons in 2 rows -->
<div class="control-section">
<div class="button-grid middle-grid">
<div class="control-btn"
@click="handleLightControl(1)"
:class="{ 'active-light': lightStates[0] }">
<div class="btn-icon">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-deng"></use>
</svg>
</div>
<div class="btn-label">灯1</div>
</div>
<div class="control-btn"
@click="handleLightControl(2)"
:class="{ 'active-light': lightStates[1] }">
<div class="btn-icon">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-deng"></use>
</svg>
</div>
<div class="btn-label">灯2</div>
</div>
<div class="control-btn"
@click="handleLightControl(3)"
:class="{ 'active-light': lightStates[2] }">
<div class="btn-icon">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-deng"></use>
</svg>
</div>
<div class="btn-label">灯3</div>
</div>
<div class="control-btn"
@click="handleLightControl(4)"
:class="{ 'active-light': lightStates[3] }">
<div class="btn-icon">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-deng"></use>
</svg>
</div>
<div class="btn-label">灯4</div>
</div>
<div class="control-btn"
@click="handleLightControl(5)"
:class="{ 'active-light': lightStates[4] }">
<div class="btn-icon">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-deng"></use>
</svg>
</div>
<div class="btn-label">灯5</div>
</div>
<div class="control-btn"
@click="handleLightControl(6)"
:class="{ 'active-light': lightStates[5] }">
<div class="btn-icon">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-deng"></use>
</svg>
</div>
<div class="btn-label">灯6</div>
</div>
</div>
</div>
<!-- Bottom Section - 2 buttons in 1 row -->
<div class="control-section">
<div class="button-row bottom-row">
<div class="action-btn reset-btn" @click="showBrightnessDialog">
<div class="btn-icon">
<van-icon name="setting-o" />
</div>
<div class="btn-label">亮度</div>
</div>
<div class="action-btn stop-btn" @click="showProgramDialog">
<div class="btn-icon">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-jiemu"></use>
</svg>
</div>
<div class="btn-label">节目</div>
</div>
</div>
</div>
</div>
<Footer></Footer>
<!-- 激光模式选择弹窗 -->
<van-popup v-model:show="showLaserMode" position="center" round>
<div class="popup-content">
<div class="popup-title">选择激光模式</div>
<div class="mode-options">
<div class="mode-option"
v-for="mode in laserModes"
:key="mode.value"
:class="{ 'selected': lightMode === mode.value }"
@click="selectLaserMode(mode.value)">
{{ mode.label }}
</div>
</div>
</div>
</van-popup>
<!-- 亮度调节弹窗 -->
<van-popup v-model:show="showBrightness" position="center" round class="brightness-popup">
<div class="popup-content">
<div class="popup-title">调节亮度</div>
<div class="brightness-slider">
<van-slider v-model="brightness" :min="0" :max="100" @change="handleBrightnessChange" />
<div class="brightness-value">{{ brightness }}%</div>
</div>
<!-- <div class="popup-buttons">
<van-button type="primary" block @click="showBrightness = false">确定</van-button>
</div> -->
</div>
</van-popup>
<!-- 节目选择弹窗 -->
<van-popup v-model:show="showProgram" position="center" round>
<div class="popup-content">
<div class="popup-title">选择节目</div>
<div class="program-options">
<div class="program-option"
v-for="id in availablePrograms"
:key="id"
:class="{ 'selected': currentProgram === id }"
@click="selectProgram(id)">
节目 {{ id }}
</div>
</div>
</div>
</van-popup>
</div>
</template>
<script>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import Header from "../../components/Header.vue";
import Footer from "../../components/Footer.vue";
import { iconfont } from '../../assets/js/iconfont.js';
import axios from 'axios';
export default {
components: {
Header,
Footer
},
setup() {
const currentTitle = ref('翻转屏遥控');
const isLocal = ref(false);
const jsonId = ref(1);
const loading = ref(false);
const screenPower = ref('off');
const lightMode = ref('auto');
const lightStates = ref([true, false, false, false, false, false]);
const brightness = ref(70);
const currentProgram = ref(1);
const availablePrograms = ref([1, 2, 3, 4, 5]);
// 弹窗控制
const showLaserMode = ref(false);
const showBrightness = ref(false);
const showProgram = ref(false);
// 激光模式选项
const laserModes = [
{ label: '自动模式', value: 'auto' },
{ label: '手动模式', value: 'manual' },
{ label: '关闭模式', value: 'off' }
];
//环境监测部分
const checkEnvironment = () => {
if (window.location.hostname === '192.168.4.1') {
console.log('in local');
// 本地开发环境,设置 isLocal 为 true
isLocal.value = true;
} else {
// 生产环境,设置 isLocal 为 false
isLocal.value = false;
}
};
//通信部分
const MQTT_send = (send_string) => {
console.log("MQTT 发送:" + JSON.stringify(send_string));
jsonId.value++;
if (/xazn/.test(navigator.userAgent) || /uni-app/.test(navigator.userAgent)) {
uni.postMessage({
data: {
str: JSON.stringify(send_string)
}
});
} else {
window.parent.postMessage({ str: JSON.stringify(send_string) }, "*");
}
showToast('发送成功');
};
const MQTT_recv = (string) => {
loading.value = false;
console.log("MQTT 接收的json:" + string);
const data = JSON.parse(string);
parseAndFillData(data);
// 检查错误码
if (data.error_code === 0) {
showToast('操作成功');
} else {
showToast('操作失败: ' + (data.error_msg || '未知错误'));
}
console.log('Received message:', string);
};
// 解析接收到的数据并更新状态
const parseAndFillData = (data) => {
if (data.Flip_screen && data.Flip_screen.status) {
const status = data.Flip_screen.status;
// 更新平台状态
if (status.platform) {
// 可以添加平台状态更新逻辑
}
// 更新屏幕状态
if (status.screen) {
screenPower.value = status.screen.power;
brightness.value = status.screen.brightness;
}
// 更新灯光状态
if (status.lights) {
lightStates.value = status.lights.map(light => light.state === 'on');
}
// 更新节目状态
if (status.program) {
currentProgram.value = status.program.current_id;
if (status.program.available) {
availablePrograms.value = status.program.available;
}
}
// 更新灯光模式
if (status.light_mode) {
lightMode.value = status.light_mode;
}
}
};
// 发送消息的统一方法
const sendMessage = async (message) => {
loading.value = true;
if (isLocal.value) {
// 本地环境使用 axios
try {
const response = await axios.post('/api/flip-screen', message);
console.log('本地通信响应:', response.data);
parseAndFillData(response.data);
// 检查错误码
if (response.data.error_code === 0) {
showToast('操作成功');
} else {
showToast('操作失败: ' + (response.data.error_msg || '未知错误'));
}
} catch (error) {
console.error('本地通信错误:', error);
showToast('通信错误: ' + error.message);
} finally {
loading.value = false;
}
} else {
// 生产环境使用 MQTT
MQTT_send(message);
// MQTT 模式下,错误处理在 MQTT_recv 中进行
}
};
// 平台控制
const handlePlatformControl = (direction) => {
const message = {
board_id: 121,
JSON_id: jsonId.value,
Flip_screen: {
platform_control: {
direction: direction
}
}
};
sendMessage(message);
};
// 屏幕控制
const handleScreenControl = () => {
const newPower = screenPower.value === 'on' ? 'off' : 'on';
const message = {
board_id: 121,
JSON_id: jsonId.value,
Flip_screen: {
screen_control: {
power: newPower
}
}
};
sendMessage(message);
};
// 显示激光模式选择弹窗
const showLaserModeDialog = () => {
showLaserMode.value = true;
};
// 选择激光模式
const selectLaserMode = (mode) => {
lightMode.value = mode;
showLaserMode.value = false;
const message = {
board_id: 121,
JSON_id: jsonId.value,
Flip_screen: {
light_mode: {
mode: mode
}
}
};
sendMessage(message);
};
// 单个灯控制
const handleLightControl = (lightId) => {
const currentState = lightStates.value[lightId - 1];
const newState = currentState ? 'off' : 'on';
const message = {
board_id: 121,
JSON_id: jsonId.value,
Flip_screen: {
light_control: {
light_id: lightId,
state: newState
}
}
};
sendMessage(message);
};
// 显示亮度调节弹窗
const showBrightnessDialog = () => {
showBrightness.value = true;
};
// 亮度变化处理
const handleBrightnessChange = (value) => {
brightness.value = value;
const message = {
board_id: 121,
JSON_id: jsonId.value,
Flip_screen: {
brightness_control: {
value: value
}
}
};
sendMessage(message);
};
// 显示节目选择弹窗
const showProgramDialog = () => {
showProgram.value = true;
};
// 选择节目
const selectProgram = (programId) => {
currentProgram.value = programId;
showProgram.value = false;
const message = {
board_id: 121,
JSON_id: jsonId.value,
Flip_screen: {
program_control: {
program_id: programId
}
}
};
sendMessage(message);
};
// 查询设备状态
const onRefresh = () => {
const message = {
board_id: 121,
JSON_id: jsonId.value,
Flip_screen: {
status_query: {
type: "all"
}
}
};
sendMessage(message);
};
onMounted(async () => {
await checkEnvironment();
console.log(isLocal.value);
window.MQTT_recv = MQTT_recv;
onRefresh();
});
onBeforeUnmount(() => {
// 清理工作
});
return {
currentTitle,
isLocal,
checkEnvironment,
MQTT_send,
MQTT_recv,
handlePlatformControl,
handleScreenControl,
showLaserModeDialog,
selectLaserMode,
handleLightControl,
showBrightnessDialog,
handleBrightnessChange,
showProgramDialog,
selectProgram,
onRefresh,
screenPower,
lightMode,
lightStates,
brightness,
currentProgram,
availablePrograms,
loading,
showToast,
showLaserMode,
showBrightness,
showProgram,
laserModes
};
}
};
</script>
<style scoped>
.page-container {
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: #f5f6fa;
position: relative;
}
.content {
flex: 1;
padding: 20px;
margin-top: 60px;
margin-bottom: 60px;
display: flex;
flex-direction: column;
gap: 20px;
}
.control-section {
padding: 5px;
}
.button-grid {
display: grid;
gap: 15px;
width: 100%;
}
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.top-grid {
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
}
.middle-grid {
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
}
.button-row {
display: flex;
gap: 15px;
justify-content: space-between;
}
.control-btn {
position: relative;
background-color: white;
border-radius: 16px;
height: 100px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
transition: all 0.2s ease;
cursor: pointer;
overflow: hidden;
}
.control-btn:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.control-btn:active {
transform: scale(0.98);
}
.active-light {
background-color: #e6f7ff;
border: 2px solid #1890ff;
}
.action-btn {
flex: 1;
position: relative;
border-radius: 16px;
height: 100px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
transition: all 0.2s ease;
cursor: pointer;
overflow: hidden;
color: white;
}
.reset-btn {
background: linear-gradient(135deg, #3498db, #2980b9);
}
.stop-btn {
background: linear-gradient(135deg, #e74c3c, #c0392b);
}
.action-btn:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
.action-btn:active {
transform: scale(0.98);
}
.btn-icon {
font-size: 32px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12px;
color: #3498db;
transition: all 0.3s ease;
}
.control-btn:hover .btn-icon {
transform: scale(1.1);
}
.action-btn .btn-icon {
color: white;
}
.btn-label {
font-size: 16px;
font-weight: 500;
margin-top: 4px;
color: #2c3e50;
}
.action-btn .btn-label {
color: white;
}
/* 弹窗样式 */
.popup-content {
padding: 20px;
min-width: 280px;
}
.popup-title {
font-size: 18px;
font-weight: 600;
text-align: center;
margin-bottom: 20px;
color: #333;
}
.mode-options, .program-options {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
margin-bottom: 20px;
}
.mode-option, .program-option {
padding: 12px 20px;
background-color: #f5f5f5;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
transition: all 0.2s ease;
}
.mode-option:hover, .program-option:hover {
background-color: #e0e0e0;
}
.mode-option.selected, .program-option.selected {
background-color: #1890ff;
color: white;
}
.brightness-slider {
padding: 0 20px;
margin-bottom: 20px;
}
.brightness-value {
text-align: center;
margin-top: 10px;
font-size: 16px;
color: #333;
}
.popup-buttons {
margin-top: 20px;
}
.brightness-popup {
width: 90%;
max-width: 320px;
}
@media (max-width: 380px) {
.content {
padding: 15px;
gap: 20px;
}
.control-btn,
.action-btn {
height: 90px;
}
.btn-icon {
font-size: 24px;
height: 45px;
width: 45px;
}
.btn-label {
font-size: 14px;
}
}
</style>