This commit is contained in:
1 2025-06-06 06:23:49 +08:00
parent 1e81272e9a
commit a875eeba11
8 changed files with 3180 additions and 190 deletions

View File

@ -1,4 +1,13 @@
{ {
"uni.picker.cancel": "取消",
"uni.picker.done": "确定",
"uni.picker.select": "请选择",
"uni.picker.year": "年",
"uni.picker.month": "月",
"uni.picker.day": "日",
"uni.picker.hour": "时",
"uni.picker.minute": "分",
"uni.picker.second": "秒",
"locale.en-US": "English", "locale.en-US": "English",
"locale.zh-CN": "简体中文", "locale.zh-CN": "简体中文",
"navBar.login": "登录", "navBar.login": "登录",
@ -870,4 +879,5 @@
} }
} }

View File

@ -126,7 +126,7 @@
}, },
"quickapp": {}, "quickapp": {},
"mp-weixin": { "mp-weixin": {
"appid" : "wx735fe3b42677d2ac", "appid": "wx52ca113738fb0f64",
"setting": { "setting": {
"urlCheck": false, "urlCheck": false,
"minified": true, "minified": true,

118
node_modules/.vue-global-types/vue_99_0_0_0.d.ts generated vendored Normal file
View File

@ -0,0 +1,118 @@
// @ts-nocheck
export {};
; declare global {
const __VLS_intrinsicElements: __VLS_IntrinsicElements;
const __VLS_directiveBindingRestFields: { instance: null, oldValue: null, modifiers: any, dir: any };
const __VLS_unref: typeof import('vue').unref;
const __VLS_placeholder: any;
type __VLS_NativeElements = __VLS_SpreadMerge<SVGElementTagNameMap, HTMLElementTagNameMap>;
type __VLS_IntrinsicElements = import('vue/jsx-runtime').JSX.IntrinsicElements;
type __VLS_Element = import('vue/jsx-runtime').JSX.Element;
type __VLS_GlobalComponents = import('vue').GlobalComponents;
type __VLS_GlobalDirectives = import('vue').GlobalDirectives;
type __VLS_IsAny<T> = 0 extends 1 & T ? true : false;
type __VLS_PickNotAny<A, B> = __VLS_IsAny<A> extends true ? B : A;
type __VLS_SpreadMerge<A, B> = Omit<A, keyof B> & B;
type __VLS_WithComponent<N0 extends string, LocalComponents, Self, N1 extends string, N2 extends string, N3 extends string> =
N1 extends keyof LocalComponents ? N1 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N1] } :
N2 extends keyof LocalComponents ? N2 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N2] } :
N3 extends keyof LocalComponents ? N3 extends N0 ? Pick<LocalComponents, N0 extends keyof LocalComponents ? N0 : never> : { [K in N0]: LocalComponents[N3] } :
Self extends object ? { [K in N0]: Self } :
N1 extends keyof __VLS_GlobalComponents ? N1 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N1] } :
N2 extends keyof __VLS_GlobalComponents ? N2 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N2] } :
N3 extends keyof __VLS_GlobalComponents ? N3 extends N0 ? Pick<__VLS_GlobalComponents, N0 extends keyof __VLS_GlobalComponents ? N0 : never> : { [K in N0]: __VLS_GlobalComponents[N3] } :
{ [K in N0]: unknown };
type __VLS_FunctionalComponentProps<T, K> =
'__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: { props?: infer P } } ? NonNullable<P> : never
: T extends (props: infer P, ...args: any) => any ? P :
{};
type __VLS_IsFunction<T, K> = K extends keyof T
? __VLS_IsAny<T[K]> extends false
? unknown extends T[K]
? false
: true
: false
: false;
type __VLS_NormalizeComponentEvent<Props, Events, onEvent extends keyof Props, Event extends keyof Events, CamelizedEvent extends keyof Events> = (
__VLS_IsFunction<Props, onEvent> extends true
? Props
: __VLS_IsFunction<Events, Event> extends true
? { [K in onEvent]?: Events[Event] }
: __VLS_IsFunction<Events, CamelizedEvent> extends true
? { [K in onEvent]?: Events[CamelizedEvent] }
: Props
) & Record<string, unknown>;
// fix https://github.com/vuejs/language-tools/issues/926
type __VLS_UnionToIntersection<U> = (U extends unknown ? (arg: U) => unknown : never) extends ((arg: infer P) => unknown) ? P : never;
type __VLS_OverloadUnionInner<T, U = unknown> = U & T extends (...args: infer A) => infer R
? U extends T
? never
: __VLS_OverloadUnionInner<T, Pick<T, keyof T> & U & ((...args: A) => R)> | ((...args: A) => R)
: never;
type __VLS_OverloadUnion<T> = Exclude<
__VLS_OverloadUnionInner<(() => never) & T>,
T extends () => never ? never : () => never
>;
type __VLS_ConstructorOverloads<T> = __VLS_OverloadUnion<T> extends infer F
? F extends (event: infer E, ...args: infer A) => any
? { [K in E & string]: (...args: A) => void; }
: never
: never;
type __VLS_NormalizeEmits<T> = __VLS_PrettifyGlobal<
__VLS_UnionToIntersection<
__VLS_ConstructorOverloads<T> & {
[K in keyof T]: T[K] extends any[] ? { (...args: T[K]): void } : never
}
>
>;
type __VLS_PrettifyGlobal<T> = { [K in keyof T]: T[K]; } & {};
type __VLS_PickFunctionalComponentCtx<T, K> = NonNullable<__VLS_PickNotAny<
'__ctx' extends keyof __VLS_PickNotAny<K, {}> ? K extends { __ctx?: infer Ctx } ? Ctx : never : any
, T extends (props: any, ctx: infer Ctx) => any ? Ctx : any
>>;
type __VLS_UseTemplateRef<T> = Readonly<import('vue').ShallowRef<T | null>>;
function __VLS_getVForSourceType<T extends number | string | any[] | Iterable<any>>(source: T): [
item: T extends number ? number
: T extends string ? string
: T extends any[] ? T[number]
: T extends Iterable<infer T1> ? T1
: any,
index: number,
][];
function __VLS_getVForSourceType<T>(source: T): [
item: T[keyof T],
key: keyof T,
index: number,
][];
// @ts-ignore
function __VLS_getSlotParams<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>;
// @ts-ignore
function __VLS_getSlotParam<T>(slot: T): Parameters<__VLS_PickNotAny<NonNullable<T>, (...args: any[]) => any>>[0];
function __VLS_asFunctionalDirective<T>(dir: T): T extends import('vue').ObjectDirective
? NonNullable<T['created' | 'beforeMount' | 'mounted' | 'beforeUpdate' | 'updated' | 'beforeUnmount' | 'unmounted']>
: T extends (...args: any) => any
? T
: (arg1: unknown, arg2: unknown, arg3: unknown, arg4: unknown) => void;
function __VLS_makeOptional<T>(t: T): { [K in keyof T]?: T[K] };
function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
T extends new (...args: any) => any
? (props: (K extends { $props: infer Props } ? Props : any) & Record<string, unknown>, ctx?: any) => __VLS_Element & {
__ctx?: {
attrs?: any;
slots?: K extends { $slots: infer Slots } ? Slots : any;
emit?: K extends { $emit: infer Emit } ? Emit : any;
expose?(exposed: K): void;
props?: (K extends { $props: infer Props } ? Props : any) & Record<string, unknown>;
}
}
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
: T extends (...args: any) => any ? T
: (_: {} & Record<string, unknown>, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {} & Record<string, unknown> } };
function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : [];
function __VLS_asFunctionalElement<T>(tag: T, endTag?: T): (attrs: T & Record<string, unknown>) => void;
function __VLS_asFunctionalSlot<S>(slot: S): S extends () => infer R ? (props: {}) => R : NonNullable<S>;
function __VLS_tryAsConstant<const T>(t: T): T;
}

View File

@ -810,6 +810,9 @@
} }
this.updateDeviceStatus(this.deviceInfo); this.updateDeviceStatus(this.deviceInfo);
this.initChart(); this.initChart();
console.log("wumoxing", JSON.stringify(this.deviceInfo.thingsModels))
} }
} }
}, },
@ -1197,6 +1200,7 @@
}, },
/**监测图表*/ /**监测图表*/
initChart() { initChart() {
console.log(111)
this.monitorChart = []; this.monitorChart = [];
if (this.deviceInfo.chartList && this.deviceInfo.chartList.length !== 0) { if (this.deviceInfo.chartList && this.deviceInfo.chartList.length !== 0) {
for (let i = 0; i < this.deviceInfo.chartList.length; i++) { for (let i = 0; i < this.deviceInfo.chartList.length; i++) {

View File

@ -0,0 +1,288 @@
<template>
<view class="gateway-container">
<!-- 设备状态卡片 -->
<view class="card">
<view class="status-titletop">{{ title }}</view>
<view style="padding:20rpx;">
<u--form labelPosition="left" labelWidth="100"
:labelStyle="{ marginRight: '16px', lineHeight: '32px', width: '50px', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', color: '#000000' }">
<view class="version-wrap">
<u-form-item :label="$tt('status.deviceVersion') || '设备版本'">
<u-row>
<u-col span="8">
<u--text :text="'Version' + (device.firmwareVersion || '')"></u--text>
</u-col>
</u-row>
</u-form-item>
</view>
</u--form>
</view>
</view>
<!-- Webview容器 -->
<view class="webview-container">
<!-- #ifdef APP-PLUS -->
<web-view :src="fullUrl" @message="handleWebviewMessage" ref="webview"></web-view>
<!-- #endif -->
<!-- #ifdef H5 -->
<iframe :src="fullUrl" frameborder="0" class="h5-iframe" @load="iframeLoaded"></iframe>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<web-view id="wxWebview" :src="fullUrl" @message="handleWebviewMessage" @load="wxWebviewLoaded"
@error="wxWebviewError"></web-view>
<!-- #endif -->
</view>
</view>
</template>
<script>
export default {
name: 'gateway-control',
props: {
device: {
type: Object,
default: () => ({
deviceId: '',
serialNumber: '',
firmwareVersion: '',
status: 0,
isShadow: 0,
thingsModels: []
}),
required: true
}
},
data() {
return {
title: '设备离线',
baseUrl: 'https://iot-xcwl.cn/h5/index.html',
wxWebviewReady: false
};
},
computed: {
fullUrl() {
if (!this.device?.deviceId || !this.device?.serialNumber) {
console.error('设备ID或序列号未定义', this.device);
return this.baseUrl;
}
const productParamModel = this.device.thingsModels?.find(model => model.id === 'productpram');
let paramData = productParamModel?.shadow || '';
if (typeof paramData === 'string' && paramData.startsWith('JSON=')) {
paramData = paramData.substring(5);
}
const paramDataString = typeof paramData === 'string' ? paramData : JSON.stringify(paramData || {});
return `${this.baseUrl}?deviceId=${encodeURIComponent(this.device.deviceId)}&serialNumber=${encodeURIComponent(this.device.serialNumber)}&initialData=${encodeURIComponent(paramDataString)}`;
}
},
mounted() {
this.updateDeviceStatus(this.device);
this.mqttCallback();
// H5
uni.$on('h5Message', this.handleH5Message);
},
beforeDestroy() {
//
uni.$off('h5Message', this.handleH5Message);
if (this.messageListener) {
window.removeEventListener('message', this.messageListener);
}
},
methods: {
// webview
wxWebviewLoaded() {
console.log('微信webview加载完成');
this.wxWebviewReady = true;
this.sendInitialDataToWebview();
},
// webview
getWebviewComponent() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
return currentPage.selectComponent('#wxWebview');
},
// webview
sendInitialDataToWebview() {
const productParamModel = this.device.thingsModels?.find(model => model.id === 'productpram');
if (!productParamModel) {
console.warn('未找到 productpram 模型');
return;
}
let paramData = productParamModel.shadow || '';
if (typeof paramData === 'string' && paramData.startsWith('JSON=')) {
paramData = paramData.substring(5);
}
const paramDataString = typeof paramData === 'string' ? paramData : JSON.stringify(paramData || {});
// #ifdef MP-WEIXIN
const component = this.getWebviewComponent();
if (component) {
component.postMessage({
type: 'initialData',
data: paramDataString,
timestamp: Date.now()
});
console.log('【微信小程序】发送初始数据成功:', paramDataString);
} else {
console.error('获取 webview 组件失败');
}
// #endif
// #ifdef APP-PLUS
if (this.$refs.webview) {
this.$refs.webview.postMessage({
type: 'initialData',
data: paramDataString,
timestamp: Date.now()
});
console.log('【APP】发送初始数据成功:', paramDataString);
}
// #endif
// #ifdef H5
const iframe = document.querySelector('.h5-iframe');
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage({
type: 'initialData',
data: paramDataString,
timestamp: Date.now()
}, '*');
console.log('【H5】发送初始数据成功:', paramDataString);
}
// #endif
},
//
handleWebviewMessage(e) {
console.log('【小程序】收到 H5 消息:', e);
let messageData = null;
//
// #ifdef MP-WEIXIN
messageData = e.detail.data; //
// #endif
// #ifdef APP-PLUS || H5
messageData = e.data || e.detail?.data?.[0] || e.detail.data;
// #endif
if (!messageData) {
console.warn('无法解析的消息格式', e);
return;
}
//
console.log('【小程序】原始消息内容:', messageData);
// 使 uni.$emit 广
uni.$emit('h5Message', messageData);
},
// H5
handleH5Message(message) {
console.log('【uni.$on】接收到 H5 消息:', message);
if (message.type === 'mqtt_data') {
console.log('处理 mqtt_data 消息:', message.payload);
// MQTT
}
},
//
updateDeviceStatus(device) {
if (!device) {
this.title = '设备未连接';
return;
}
if (device.status === 3) {
this.title = this.$tt('status.online') || '在线';
} else {
this.title = device.isShadow === 1 ?
(this.$tt('status.shadow') || '影子模式') :
(this.$tt('status.deviceOffline') || '离线');
}
},
// MQTT
mqttCallback() {
if (!this.$mqttTool?.client) {
console.warn('MQTT客户端未初始化');
return;
}
this.$mqttTool.client.removeAllListeners('message');
this.$mqttTool.client.on('message', (topic, message, buffer) => {
const topics = topic.split('/');
if (this.device.serialNumber !== topics[2]) return;
const msg = JSON.parse(message.toString());
if (topics[3] === 'status') {
this.device.status = msg.status;
this.device.isShadow = msg.isShadow;
this.device.rssi = msg.rssi;
this.updateDeviceStatus(this.device);
}
});
}
}
};
</script>
<style lang="scss" scoped>
/* 保持原有样式不变 */
.gateway-container {
padding: 20rpx;
height: 100%;
display: flex;
flex-direction: column;
.card {
background-color: #fff;
border-radius: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.webview-container {
flex: 1;
height: 0;
overflow: hidden;
border-radius: 20rpx;
background-color: #fff;
.h5-iframe {
width: 100%;
height: 600px;
}
}
.status-titletop {
font-weight: bold;
font-size: 32rpx;
color: #333333;
line-height: 42rpx;
text-align: left;
padding: 15rpx 28rpx;
}
.version-wrap {
background-color: #F7F7F7;
border-radius: 10rpx;
padding: 0 42rpx;
font-size: 28rpx;
color: #000000;
line-height: 42rpx;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -8,22 +8,22 @@
<u--text iconStyle="color: #486ff2; margin-right: 4px; font-size: 22px;" type="primary" <u--text iconStyle="color: #486ff2; margin-right: 4px; font-size: 22px;" type="primary"
prefixIcon="list-dot" align="right" text="设备详情" @click="handleGoToDeviceDetail"></u--text> prefixIcon="list-dot" align="right" text="设备详情" @click="handleGoToDeviceDetail"></u--text>
</view> </view>
<view class="running-status" v-show="current==0 && !isRelayProduct && !isVoiceProduct && !isGatewayProduct"> <view class="running-status" v-if="current==0 && !isRelayProduct && !isVoiceProduct && !isGatewayProduct">
<base-status :device="device" ref="baseStatus"></base-status> <base-status :device="device" ref="baseStatus"></base-status>
</view> </view>
<view class="deviceVariable" v-show="current==1 && !isRelayProduct && !isVoiceProduct && !isGatewayProduct"> <view class="deviceVariable" v-if="current==1 && !isRelayProduct && !isVoiceProduct && !isGatewayProduct">
<device-variable ref="deviceVariable" :device="device"></device-variable> <device-variable ref="deviceVariable" :device="device"></device-variable>
</view> </view>
<view class="relay-control" v-show="isRelayProduct"> <view class="relay-control" v-if="isRelayProduct">
<relay-control :device="device" ref="relayControl"></relay-control> <relay-control :device="device" ref="relayControl"></relay-control>
</view> </view>
<view class="voice-control" v-show="isVoiceProduct"> <view class="voice-control" v-if="isVoiceProduct">
<voice :device="device" ref="voice"></voice> <voice :device="device" ref="voice"></voice>
</view> </view>
<!-- <view class="relay-control" v-show="isRelayProduct"> <!-- <view class="relay-control" v-show="isRelayProduct">
<GRelay :device="device" ref="GRelay"></GRelay> <GRelay :device="device" ref="GRelay"></GRelay>
</view> --> </view> -->
<view class="gateway" v-show="isGatewayProduct"> <view class="gateway" v-if="isGatewayProduct">
<gateway :device="device" ref="gateway"></gateway> <gateway :device="device" ref="gateway"></gateway>
</view> </view>
</view> </view>

File diff suppressed because it is too large Load Diff