| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- // app.js
- const api = require('./api/index.js');
- App({
- globalData: {
- socketTask: null,
- isConnected: false,
- reconnectTimer: null,
- heartbeatTimer: null,
- currentWorkorderId: '',
- userInfo: wx.getStorageSync('user') || {}
- },
-
- onLaunch() {
- this.initWebSocketService();
- wx.onAppShow(() => this.handleAppShow());
- wx.onAppHide(() => this.handleAppHide());
-
- this.locationService = {
- isTracking: false,
- currentWorkorderId: '',
- isLocationUpdateStarted: false
- };
-
- // 司机自动启动【普通实时定位上传】
- const { operationRole } = this.globalData.userInfo;
- if (operationRole === 4) {
- this.startDriverRealTimeLocation();
- }
- },
-
- initWebSocketService() {
- if (!this.wsService) {
- this.wsService = {
- connect: (url) => {
- const that = this;
- if (that.globalData.socketTask) {
- that.wsService.close();
- }
-
- const socketTask = wx.connectSocket({ url, header: { 'content-type': 'application/json' } });
-
- socketTask.onOpen(() => {
- that.globalData.isConnected = true;
- that.globalData.socketTask = socketTask;
- that.clearReconnectTimer();
- if (that.globalData.currentWorkorderId) {
- that.wsService.send({ type: 'subscribe', workorderId: that.globalData.currentWorkorderId });
- }
- wx.$emit('socketOpen');
- });
-
- socketTask.onMessage((res) => {
- try {
- const message = JSON.parse(res.data);
- wx.$emit('wsMessage', message);
- } catch (err) { }
- });
-
- socketTask.onClose((res) => {
- that.globalData.isConnected = false;
- that.globalData.socketTask = null;
- that.stopHeartbeat();
- if (res.code !== 1000) that.startReconnect();
- });
-
- socketTask.onError((err) => {
- that.globalData.isConnected = false;
- that.globalData.socketTask = null;
- that.stopHeartbeat();
- });
- },
-
- send: (data) => {
- const that = this;
- if (that.globalData.isConnected && that.globalData.socketTask) {
- that.globalData.socketTask.send({
- data: JSON.stringify(data),
- fail: (err) => console.error('发送失败', err)
- });
- }
- },
-
- close: (code = 1000, reason = 'normal close') => {
- const that = this;
- if (that.globalData.socketTask) {
- that.globalData.socketTask.close({ code, reason });
- }
- }
- };
- }
- },
-
- handleAppShow() {
- const that = this;
- if (!that.globalData.isConnected && !that.globalData.reconnectTimer) {
- const { operationId } = that.globalData.userInfo;
- if (!operationId) return;
- const wsUrl = `wss://esos-iot.com:9443/communication/update/${operationId}`;
- that.wsService.connect(wsUrl);
- }
- },
-
- handleAppHide() { },
-
- startHeartbeat() {
- const that = this;
- that.stopHeartbeat();
- that.heartbeatTimer = setInterval(() => {
- if (that.globalData.isConnected) {
- that.wsService.send({ type: 'heartbeat', timestamp: Date.now() });
- }
- }, 5000);
- },
-
- stopHeartbeat() {
- if (this.heartbeatTimer) {
- clearInterval(this.heartbeatTimer);
- this.heartbeatTimer = null;
- }
- },
-
- startReconnect() {
- const that = this;
- that.clearReconnectTimer();
- let delay = 1000;
- that.globalData.reconnectTimer = setInterval(() => {
- if (!that.globalData.isConnected) {
- const { operationId } = that.globalData.userInfo;
- if (operationId) {
- const wsUrl = `wss://esos-iot.com:9443/communication/update/${operationId}`;
- that.wsService.connect(wsUrl);
- }
- delay = Math.min(delay * 2, 8000);
- } else {
- that.clearReconnectTimer();
- }
- }, delay);
- },
-
- clearReconnectTimer() {
- if (this.globalData.reconnectTimer) {
- clearInterval(this.globalData.reconnectTimer);
- this.globalData.reconnectTimer = null;
- }
- },
-
- /****************************************************************************
- * 1. 司机【普通实时定位】(一直上传,不绑定工单)
- ***************************************************************************/
- startDriverRealTimeLocation() {
- const { operationRole } = this.globalData.userInfo;
- if (operationRole !== 4) return;
-
- const service = this.locationService;
- this._removeLocationListener();
-
- const startLocationApi = wx.startLocationUpdateBackground || wx.startLocationUpdate;
- startLocationApi({
- type: 'gcj02',
- success: () => {
- service.isLocationUpdateStarted = true;
- let lastLocation = null;
- const DISTANCE_THRESHOLD = 5;
-
- wx.onLocationChange((location) => {
- // 距离过滤
- if (lastLocation) {
- const distance = this.calculateDistance(
- lastLocation.latitude, lastLocation.longitude,
- location.latitude, location.longitude
- );
- if (distance < DISTANCE_THRESHOLD) return;
- }
- lastLocation = location;
-
- // 统一上传:实时位置 + 有工单就工单一起传
- this._uploadRealTimeLocation(location);
- if (service.currentWorkorderId) {
- this._uploadWorkorderLocation(location, service.currentWorkorderId);
- }
- });
- }
- });
- },
-
- /****************************************************************************
- * 2. 司机【开始执行工单】(绑定工单,额外上传工单位置)
- ***************************************************************************/
- startDriverWorkorderLocation(workorderId) {
- if (!workorderId) return;
- const service = this.locationService;
- service.currentWorkorderId = workorderId;
- },
-
- /****************************************************************************
- * 3. 停止工单定位(只停止工单,不影响实时定位上传)
- ***************************************************************************/
- stopDriverWorkorderLocation() {
- const service = this.locationService;
- service.currentWorkorderId = '';
- },
-
- /****************************************************************************
- * 上传:司机实时位置(一直传)
- ***************************************************************************/
- _uploadRealTimeLocation(location) {
- const { operationRole } = this.globalData.userInfo;
- if (operationRole !== 4) return;
-
- const latOk = location.latitude >= 3.86 && location.latitude <= 53.55;
- const lngOk = location.longitude >= 73.66 && location.longitude <= 135.05;
- if (!latOk || !lngOk) return;
-
- const data = {
- userType: operationRole,
- latitude: location.latitude,
- longitude: location.longitude,
- accuracy: location.accuracy,
- createTime: Date.now()
- };
- api.request('/sysoperation/inseroperationlocation', 'post', data, { isPublic: false })
- .catch(err => console.error('实时位置上传失败', err));
- },
-
- /****************************************************************************
- * 上传:工单位置(执行工单时才传)
- ***************************************************************************/
- _uploadWorkorderLocation(location, workorderId) {
- const latOk = location.latitude >= 3.86 && location.latitude <= 53.55;
- const lngOk = location.longitude >= 73.66 && location.longitude <= 135.05;
- if (!latOk || !lngOk) return;
-
- const data = {
- workorderId: workorderId,
- latitude: location.latitude,
- longitude: location.longitude,
- createTime: Date.now(),
- accuracy: location.accuracy
- };
- api.request('/sysworkorder/insercoordinateredis', 'post', data, { isPublic: false })
- .catch(err => console.error('工单位置上传失败', err));
- },
-
- calculateDistance(lat1, lng1, lat2, lng2) {
- const R = 6371000;
- const radLat1 = lat1 * Math.PI / 180;
- const radLat2 = lat2 * Math.PI / 180;
- const dLat = radLat2 - radLat1;
- const dLng = (lng2 - lng1) * Math.PI / 180;
- const a = Math.sin(dLat / 2) ** 2 + Math.cos(radLat1) * Math.cos(radLat2) * Math.sin(dLng / 2) ** 2;
- return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- },
-
- _removeLocationListener() {
- if (wx.offLocationChange) wx.offLocationChange();
- }
- });
-
- // 全局事件总线
- wx.$on = function (eventName, callback) {
- if (!this.$events) this.$events = {};
- if (!this.$events[eventName]) this.$events[eventName] = [];
- this.$events[eventName].push(callback);
- };
- wx.$emit = function (eventName, data) {
- if (!this.$events || !this.$events[eventName]) return;
- this.$events[eventName].forEach(cb => cb(data));
- };
- wx.$off = function (eventName, callback) {
- if (!this.$events || !this.$events[eventName]) return;
- if (callback) this.$events[eventName] = this.$events[eventName].filter(cb => cb !== callback);
- else this.$events[eventName] = [];
- };
|