Compare commits
54 Commits
f5ddf1e120
...
prod
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44c54cbf3f | ||
|
|
d1133a5857 | ||
|
|
3835b910ee | ||
|
|
59709f1821 | ||
|
|
eed1e5c994 | ||
|
|
359842fad8 | ||
|
|
fdc1e55def | ||
|
|
975be330b8 | ||
|
|
cce60dd135 | ||
|
|
b1c9b6ad02 | ||
|
|
5deb6387c4 | ||
|
|
3744079098 | ||
|
|
16b6b187a9 | ||
|
|
6f32f7ab41 | ||
|
|
8e77c6a747 | ||
|
|
2301661fb5 | ||
|
|
0027510594 | ||
|
|
9952275e59 | ||
|
|
c47806f840 | ||
|
|
978ba766b3 | ||
|
|
80ddb2c3a8 | ||
|
|
10ec6d0fce | ||
|
|
c43d5a6dd5 | ||
|
|
1b65f78f71 | ||
|
|
ccb493a6a8 | ||
|
|
b106703f91 | ||
|
|
7a4ad91efa | ||
|
|
b85b7ee550 | ||
|
|
90bb60c990 | ||
|
|
fb6d80f000 | ||
|
|
1816d21e40 | ||
|
|
ea95dab832 | ||
|
|
d1e131f2df | ||
|
|
6dac8011f0 | ||
|
|
51c0703670 | ||
|
|
14b966187c | ||
|
|
718cbce591 | ||
|
|
9fc7f3aab5 | ||
|
|
029a77b00c | ||
|
|
525da17a98 | ||
|
|
d7459d4f7c | ||
|
|
4e4243d5e2 | ||
|
|
3740e7fe52 | ||
|
|
1907da5b43 | ||
|
|
3e56d4f24a | ||
|
|
0f4e12036d | ||
|
|
02f4f6ecd8 | ||
|
|
8084b705a6 | ||
|
|
54e5fa9b7e | ||
|
|
e0cdc4aebe | ||
|
|
2b60a33440 | ||
|
|
314f060359 | ||
|
|
927ff2ab36 | ||
|
|
b1bc6c174c |
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -9,6 +9,7 @@ declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
ChartFullscreen: typeof import('./src/components/other/chartFullscreen.vue')['default']
|
||||
CustomNavigationBar: typeof import('./src/components/custom-navigation-bar/index.vue')['default']
|
||||
DataQuery: typeof import('./src/components/other/dataQuery.vue')['default']
|
||||
Fish: typeof import('./src/components/other/fish.vue')['default']
|
||||
NutBadge: typeof import('@nutui/nutui-taro')['Badge']
|
||||
NutButton: typeof import('@nutui/nutui-taro')['Button']
|
||||
|
||||
@@ -58,8 +58,7 @@ const config = {
|
||||
compiler: {
|
||||
type: 'webpack5',
|
||||
prebundle: {
|
||||
enable: true,
|
||||
exclude: ['@nutui/icons-vue-taro']
|
||||
enable: false
|
||||
}
|
||||
},
|
||||
cache: {
|
||||
|
||||
50
package.json
50
package.json
@@ -40,22 +40,22 @@
|
||||
"@nutui/icons-vue-taro": "^0.0.8",
|
||||
"@nutui/nutui-taro": "^4.3.4",
|
||||
"@qiun/ucharts": "^2.5.0-20230101",
|
||||
"@tarojs/components": "3.5.10",
|
||||
"@tarojs/helper": "3.5.10",
|
||||
"@tarojs/plugin-framework-vue3": "3.5.10",
|
||||
"@tarojs/plugin-html": "3.5.10",
|
||||
"@tarojs/plugin-platform-alipay": "3.5.10",
|
||||
"@tarojs/plugin-platform-jd": "3.5.10",
|
||||
"@tarojs/plugin-platform-qq": "3.5.10",
|
||||
"@tarojs/plugin-platform-swan": "3.5.10",
|
||||
"@tarojs/plugin-platform-tt": "3.5.10",
|
||||
"@tarojs/plugin-platform-weapp": "3.5.10",
|
||||
"@tarojs/router": "3.5.10",
|
||||
"@tarojs/runtime": "3.5.10",
|
||||
"@tarojs/shared": "3.5.10",
|
||||
"@tarojs/taro": "3.5.10",
|
||||
"@tarojs/taro-h5": "3.5.10",
|
||||
"cache-loader": "^4.1.0",
|
||||
"@tarojs/components": "3.6.23",
|
||||
"@tarojs/helper": "3.6.23",
|
||||
"@tarojs/plugin-framework-vue3": "3.6.23",
|
||||
"@tarojs/plugin-html": "3.6.23",
|
||||
"@tarojs/plugin-platform-alipay": "3.6.23",
|
||||
"@tarojs/plugin-platform-h5": "^3.6.23",
|
||||
"@tarojs/plugin-platform-jd": "3.6.23",
|
||||
"@tarojs/plugin-platform-qq": "3.6.23",
|
||||
"@tarojs/plugin-platform-swan": "3.6.23",
|
||||
"@tarojs/plugin-platform-tt": "3.6.23",
|
||||
"@tarojs/plugin-platform-weapp": "3.6.23",
|
||||
"@tarojs/router": "3.6.23",
|
||||
"@tarojs/runtime": "3.6.23",
|
||||
"@tarojs/shared": "3.6.23",
|
||||
"@tarojs/taro": "3.6.23",
|
||||
"@tarojs/taro-h5": "3.6.23",
|
||||
"crypto-js": "^4.2.0",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"jsrsasign": "^11.1.0",
|
||||
@@ -67,31 +67,33 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.8.0",
|
||||
"@nutui/auto-import-resolver": "^1.0.0",
|
||||
"@tarojs/cli": "3.5.10",
|
||||
"@tarojs/plugin-framework-react": "^3.6.24",
|
||||
"@tarojs/webpack5-runner": "3.5.10",
|
||||
"@tarojs/cli": "3.6.23",
|
||||
"@tarojs/webpack5-runner": "3.6.23",
|
||||
"@types/webpack-env": "^1.13.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
||||
"@typescript-eslint/parser": "^5.20.0",
|
||||
"@vue/babel-plugin-jsx": "^1.0.6",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"babel-preset-taro": "3.5.10",
|
||||
"babel-preset-taro": "3.6.23",
|
||||
"css-loader": "3.4.2",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-config-taro": "3.5.10",
|
||||
"eslint-config-taro": "3.6.23",
|
||||
"eslint-plugin-vue": "^8.0.0",
|
||||
"style-loader": "1.3.0",
|
||||
"stylelint": "9.3.0",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"thread-loader": "^4.0.2",
|
||||
"typescript": "^3.7.0",
|
||||
"typescript": "^4.9.5",
|
||||
"unplugin-auto-import": "^0.17.5",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vue-loader": "^17.0.0",
|
||||
"webpack": "5.69.0",
|
||||
"webpack": "^5.78.0",
|
||||
"webpack-bundle-analyzer": "^4.10.1"
|
||||
},
|
||||
"overrides": {
|
||||
"@swc/core": "1.3.96"
|
||||
},
|
||||
"resolutions": {
|
||||
"@swc/core": "1.3.42"
|
||||
"@swc/core": "1.3.96"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ export const API_VERSION = {
|
||||
// 当前使用的API版本,修改此处可快速切换版本
|
||||
export const CURRENT_VERSION = API_VERSION.V2
|
||||
|
||||
// 认证配置
|
||||
export const AUTH_CONFIG = {
|
||||
CLIENT_ID: '428a8310cd442757ae699df5d894f051',
|
||||
TENANT_ID: '111111',
|
||||
}
|
||||
|
||||
/**
|
||||
* 接口路径配置
|
||||
* 结构:{ v1: 'C#接口路径', v2: 'Java接口路径' }
|
||||
@@ -26,7 +32,6 @@ const API_PATHS = {
|
||||
AUTH: {
|
||||
// 短信登录
|
||||
LOGIN_SMS: {
|
||||
v1: '/auth/login',
|
||||
v2: '/auth/login',
|
||||
},
|
||||
// 获取短信验证码
|
||||
@@ -35,13 +40,11 @@ const API_PATHS = {
|
||||
},
|
||||
// 微信手机号登录
|
||||
LOGIN_WECHAT: {
|
||||
v1: '/api/login/use_wechat',
|
||||
v2: '/fishery/login/wechat',
|
||||
v2: '/auth/wechat_login',
|
||||
},
|
||||
// 登出
|
||||
LOGOUT: {
|
||||
v1: '/api/user-center/logout',
|
||||
v2: '/fishery/auth/logout',
|
||||
v2: '/auth/logout',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -102,8 +105,7 @@ const API_PATHS = {
|
||||
},
|
||||
// 夜间防误触
|
||||
KEEP_NIGHT_OPEN: {
|
||||
v1: '/api/pond/keep_night_open',
|
||||
v2: '/fishery/pond/night-protect',
|
||||
v2: '/fishery/pond/keep_night_open',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -143,8 +145,7 @@ const API_PATHS = {
|
||||
},
|
||||
// 扫描设备编码
|
||||
SCAN: {
|
||||
v1: '/api/device/check_device_qrcode',
|
||||
v2: '/fishery/device/scan',
|
||||
v2: '/fishery/device/check_device_qrcode',
|
||||
},
|
||||
// 检测设备是否在线
|
||||
CHECK_STATUS: {
|
||||
@@ -182,6 +183,10 @@ const API_PATHS = {
|
||||
ADD_CONTROLLER: {
|
||||
v2: '/iot/device/add_device_controller',
|
||||
},
|
||||
// 添加太阳能网控
|
||||
ADD_SOLAR_DETECTOR: {
|
||||
v2: '/iot/device/add_device_solar_detector',
|
||||
},
|
||||
// 启停溶解氧
|
||||
SET_OXY_OPEN: {
|
||||
v2: '/fishery/device/set_controller_oxy_open',
|
||||
@@ -190,6 +195,10 @@ const API_PATHS = {
|
||||
VOLTAGE_CHECK: {
|
||||
v2: '/fishery/device/voltage_check_open',
|
||||
},
|
||||
// 设置电量告警下限
|
||||
SET_BATTERY_WARN: {
|
||||
v2: '/fishery/device/set_battery_warn_value',
|
||||
},
|
||||
},
|
||||
|
||||
// ==================== 联动控制 ====================
|
||||
@@ -260,23 +269,19 @@ const API_PATHS = {
|
||||
TIME_CTRL: {
|
||||
// 定时开关列表
|
||||
LIST: {
|
||||
v1: '/api/device-switch-time-ctrl/list',
|
||||
v2: '/fishery/time-ctrl/list',
|
||||
v2: '/fishery/timingCtrl/list',
|
||||
},
|
||||
// 添加定时开关
|
||||
ADD: {
|
||||
v1: '/api/device-switch-time-ctrl/add',
|
||||
v2: '/fishery/time-ctrl',
|
||||
v2: '/fishery/timingCtrl/add',
|
||||
},
|
||||
// 删除定时开关
|
||||
DELETE: {
|
||||
v1: '/api/device-switch-time-ctrl/delete',
|
||||
v2: '/fishery/time-ctrl',
|
||||
v2: '/iot/timingCtrl/delete',
|
||||
},
|
||||
// 更新定时开关
|
||||
UPDATE: {
|
||||
v1: '/api/device-switch-time-ctrl/update',
|
||||
v2: '/fishery/time-ctrl',
|
||||
v2: '/iot/timingCtrl/update',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -308,28 +313,24 @@ const API_PATHS = {
|
||||
USER: {
|
||||
// 报警电话列表
|
||||
WARN_PHONE_LIST: {
|
||||
v1: '/api/user-center/list_warn_phone',
|
||||
v2: '/fishery/user/warn-phone/list',
|
||||
v2: '/fishery/aquUser/list_warn_phone',
|
||||
},
|
||||
// 修改报警电话
|
||||
UPDATE_WARN_PHONE: {
|
||||
v1: '/api/user-center/update_warn_phone',
|
||||
v2: '/fishery/user/warn-phone',
|
||||
v2: '/fishery/aquUser/update_warn_phone',
|
||||
},
|
||||
// 修改手机号码
|
||||
UPDATE_PHONE: {
|
||||
v1: '/api/user-center/update_mobile_phone',
|
||||
v2: '/fishery/user/phone',
|
||||
v2: '/fishery/aquUser/update_mobile_phone',
|
||||
},
|
||||
// 验证验证码
|
||||
VERIFY_CODE: {
|
||||
v1: '/sms_code/verify',
|
||||
v2: '/fishery/sms/verify',
|
||||
v2: '/resource/sms/verify',
|
||||
},
|
||||
// 修改昵称
|
||||
UPDATE_NICKNAME: {
|
||||
v1: '/api/user-center/update_user_name',
|
||||
v2: '/fishery/user/nickname',
|
||||
v2: '/fishery/aquUser/update_user_name',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -337,23 +338,19 @@ const API_PATHS = {
|
||||
SUB_ACCOUNT: {
|
||||
// 获取子账号列表
|
||||
LIST: {
|
||||
v1: '/api/user-center/list_user_child',
|
||||
v2: '/fishery/user/child/list',
|
||||
v2: '/fishery/aquUser/list_user_child',
|
||||
},
|
||||
// 添加子账号
|
||||
ADD: {
|
||||
v1: '/api/user-center/add_user_child',
|
||||
v2: '/fishery/user/child',
|
||||
v2: '/fishery/aquUser/add_user_child',
|
||||
},
|
||||
// 删除子账号
|
||||
DELETE: {
|
||||
v1: '/api/user-center/delete_user_child',
|
||||
v2: '/fishery/user/child',
|
||||
v2: '/fishery/aquUser/delete_user_child',
|
||||
},
|
||||
// 获取父级账号
|
||||
PARENT: {
|
||||
v1: '/api/user-center/list_user_parent',
|
||||
v2: '/fishery/user/parent',
|
||||
v2: '/fishery/aquUser/list_user_parent',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -361,17 +358,14 @@ const API_PATHS = {
|
||||
PAY: {
|
||||
// 支付选项页面
|
||||
OPTIONS: {
|
||||
v1: '/api/tenpay/get_pay_item',
|
||||
v2: '/fishery/pay/options',
|
||||
v2: '/weixin/pay/get_pay_item',
|
||||
},
|
||||
// 创建支付订单
|
||||
CREATE_ORDER: {
|
||||
v1: '/api/tenpay/create_order',
|
||||
v2: '/fishery/pay/order',
|
||||
v2: '/weixin/pay/create_order',
|
||||
},
|
||||
// 微信支付
|
||||
WECHAT_PAY: {
|
||||
v1: 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi',
|
||||
v2: 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi', // 微信官方接口不变
|
||||
},
|
||||
},
|
||||
@@ -456,8 +450,10 @@ export const API = {
|
||||
SET_TEMP_WARN: () => getApiPath('DEVICE', 'SET_TEMP_WARN'),
|
||||
GET_SATURABILITY: () => getApiPath('DEVICE', 'GET_SATURABILITY'),
|
||||
ADD_CONTROLLER: () => getApiPath('DEVICE', 'ADD_CONTROLLER'),
|
||||
ADD_SOLAR_DETECTOR: () => getApiPath('DEVICE', 'ADD_SOLAR_DETECTOR'),
|
||||
SET_OXY_OPEN: () => getApiPath('DEVICE', 'SET_OXY_OPEN'),
|
||||
VOLTAGE_CHECK: () => getApiPath('DEVICE', 'VOLTAGE_CHECK'),
|
||||
SET_BATTERY_WARN: () => getApiPath('DEVICE', 'SET_BATTERY_WARN'),
|
||||
},
|
||||
// 联动控制
|
||||
LINKED_CTRL: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import httpService from '@/utils/request'
|
||||
import API from './config'
|
||||
import Taro from '@tarojs/taro'
|
||||
import { useRootUserStore } from '@/store/index'
|
||||
/** 设备相关接口---------------------------------------- */
|
||||
|
||||
// 设备列表
|
||||
@@ -9,17 +10,21 @@ export function allDeviceList(params) {
|
||||
}
|
||||
// 设备详情
|
||||
export function deviceInfo(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.post(`${API.DEVICE.INFO()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 解除绑定
|
||||
export function deviceUnbind(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.post(`${API.DEVICE.UNBIND()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 将设备及开关绑定到塘口
|
||||
export function bandDeviceToPond(data){
|
||||
return httpService.put(API.POND.BIND_DEVICE(), {data})
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.put(`${API.POND.BIND_DEVICE()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 设备图表数据
|
||||
export function deviceHistory(params){
|
||||
@@ -27,13 +32,15 @@ export function deviceHistory(params){
|
||||
}
|
||||
// 修改设备名称
|
||||
export function deviceUpdateName(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.put(`${API.DEVICE.UPDATE_NAME()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 修改设备关联塘口
|
||||
export function deviceUpdatePond(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
return httpService.put(`${API.DEVICE.UPDATE_POND()}?rootUserId=${userId}`, {data})
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.put(`${API.DEVICE.UPDATE_POND()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 修改设备接电方式
|
||||
export function deviceUpdateV(data){
|
||||
@@ -63,21 +70,26 @@ export function deviceCalibration(data){
|
||||
/** 水质检测仪------------------------------------------------ */
|
||||
// 添加-水质检测仪
|
||||
export function addDeviceDetector(data) {
|
||||
return httpService.post(API.DEVICE.ADD_DETECTOR(), {data})
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.post(`${API.DEVICE.ADD_DETECTOR()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 设置溶解氧/水温告警
|
||||
export function setWarnCall(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.post(`${API.DEVICE.SET_WARN_CALL()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 设置溶解氧上下限
|
||||
export function setOxyWarn(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.put(`${API.DEVICE.SET_OXY_WARN()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 设置温度上下限
|
||||
export function setTempWarn(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.put(`${API.DEVICE.SET_TEMP_WARN()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 溶解氧饱和度
|
||||
@@ -87,11 +99,20 @@ export function getSaturability(data){
|
||||
/** 控制一体机------------------------------------------------ */
|
||||
// 添加-控制一体机
|
||||
export function addDeviceController(data) {
|
||||
return httpService.post(API.DEVICE.ADD_CONTROLLER(), {data})
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.post(`${API.DEVICE.ADD_CONTROLLER()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 添加-太阳能网控
|
||||
export function addDeviceSolarDetector(data) {
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.post(`${API.DEVICE.ADD_SOLAR_DETECTOR()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 启停溶解氧
|
||||
export function setOxyOpen(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.put(`${API.DEVICE.SET_OXY_OPEN()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
/** 联动控制------------------------------------- */
|
||||
@@ -109,7 +130,8 @@ export function updateLinkerCtrl(data){
|
||||
}
|
||||
// 删除联动控制
|
||||
export function delLinkerCtrl(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
// 后端需要 /{ids} 路径参数
|
||||
return httpService.delete(`${API.LINKED_CTRL.DELETE()}/${data.id}?rootUserId=${userId}`)
|
||||
}
|
||||
@@ -149,9 +171,16 @@ export function turnPondSwitch(data){
|
||||
|
||||
// 电压告警开关 开启或关闭
|
||||
export function voltageCheckOpen(data){
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.put(`${API.DEVICE.VOLTAGE_CHECK()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 设置电量告警下限
|
||||
export function setBatteryWarn(data){
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.put(`${API.DEVICE.SET_BATTERY_WARN()}?rootUserId=${userId}`, {data})
|
||||
}
|
||||
// 电流告警开关 开启或关闭
|
||||
export function electricCheckOpen(data){
|
||||
return httpService.put(API.SWITCH.ELECTRIC_CHECK(), {data})
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import httpService from '@/utils/request'
|
||||
import API from './config'
|
||||
import Taro from '@tarojs/taro';
|
||||
import { useRootUserStore } from '@/store/index';
|
||||
|
||||
// 塘口模式1
|
||||
export function getPond1() {
|
||||
const userId = Taro.getStorageSync("UserId");
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync("UserId");
|
||||
return httpService.get(API.HOME.POND_LIST(), {
|
||||
params: {
|
||||
rootUserId: userId || undefined
|
||||
@@ -14,7 +16,8 @@ export function getPond1() {
|
||||
|
||||
// 塘口模式2
|
||||
export function getPond2(){
|
||||
const userId = Taro.getStorageSync("UserId");
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync("UserId");
|
||||
return httpService.get(API.HOME.POND_LIST_MODE2(), {
|
||||
params: {
|
||||
rootUserId: userId || undefined
|
||||
@@ -29,8 +32,9 @@ export function noticeList(){
|
||||
|
||||
// 即将到期设备列表
|
||||
export function deviceDead(){
|
||||
const userId = Taro.getStorageSync("UserId");
|
||||
return httpService.get(API.HOME.DEVICE_DEAD(), {
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync("UserId");
|
||||
return httpService.get(API.HOME.DEVICE_DEAD(), {
|
||||
params: {
|
||||
rootUserId: userId || undefined
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import httpService from '@/utils/request'
|
||||
import API from './config'
|
||||
import API, { AUTH_CONFIG } from './config'
|
||||
|
||||
// 短信登录
|
||||
export function loginSms(phonenumber, code) {
|
||||
@@ -7,8 +7,8 @@ export function loginSms(phonenumber, code) {
|
||||
phonenumber:phonenumber,
|
||||
smsCode:code,
|
||||
grantType:"sms",
|
||||
clientId:"428a8310cd442757ae699df5d894f051",
|
||||
tenantId:"111111",
|
||||
clientId: AUTH_CONFIG.CLIENT_ID,
|
||||
tenantId: AUTH_CONFIG.TENANT_ID,
|
||||
}
|
||||
return httpService.post(API.AUTH.LOGIN_SMS(), {data})
|
||||
}
|
||||
@@ -20,10 +20,15 @@ export function smsCode(phonenumber) {
|
||||
|
||||
// 微信手机号登录
|
||||
export function loginWxToPhone(data) {
|
||||
return httpService.post(API.AUTH.LOGIN_WECHAT(), {data})
|
||||
const params = {
|
||||
...data,
|
||||
clientId: AUTH_CONFIG.CLIENT_ID,
|
||||
tenantId: AUTH_CONFIG.TENANT_ID,
|
||||
}
|
||||
return httpService.post(API.AUTH.LOGIN_WECHAT(), {data: params})
|
||||
}
|
||||
|
||||
// 登出
|
||||
export function logoutFun() {
|
||||
return httpService.get(API.AUTH.LOGOUT())
|
||||
return httpService.post(API.AUTH.LOGOUT(), {})
|
||||
}
|
||||
@@ -1,25 +1,35 @@
|
||||
import httpService from '@/utils/request'
|
||||
import API from './config'
|
||||
import Taro from '@tarojs/taro'
|
||||
import { useRootUserStore } from '@/store/index'
|
||||
|
||||
// 查询充值记录
|
||||
export function msgPay(data) {
|
||||
return httpService.get(API.MESSAGE.PAY(), { params: data })
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.get(API.MESSAGE.PAY(), { params: { ...data, rootUserId: userId } })
|
||||
}
|
||||
|
||||
// 查询报警记录
|
||||
export function msgWarn(data) {
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
// 后端接口:GET /fishery/messageWarn/list,使用查询参数传递分页信息
|
||||
return httpService.get(API.MESSAGE.WARN(), { params: data })
|
||||
return httpService.get(API.MESSAGE.WARN(), { params: { ...data, rootUserId: userId } })
|
||||
}
|
||||
|
||||
// 查询开关记录
|
||||
export function msgSwitch(data) {
|
||||
return httpService.get(API.MESSAGE.SWITCH(), { params: data })
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.get(API.MESSAGE.SWITCH(), { params: { ...data, rootUserId: userId } })
|
||||
}
|
||||
|
||||
// 已读一条消息
|
||||
export function msgRead(data) {
|
||||
return httpService.put(API.MESSAGE.READ_ONE(), {data})
|
||||
|
||||
// 后端需要id作为URL参数
|
||||
return httpService.put(`${API.MESSAGE.READ_ONE()}?id=${data.id}`)
|
||||
}
|
||||
|
||||
// 已读全部
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import httpService from '@/utils/request'
|
||||
import API from './config'
|
||||
import Taro from '@tarojs/taro'
|
||||
import { useRootUserStore } from '@/store/index'
|
||||
|
||||
// 新增塘口
|
||||
export function PondAdd(data) {
|
||||
return httpService.post(API.POND.ADD(), {data})
|
||||
@@ -19,10 +22,14 @@ export function fishList(){
|
||||
}
|
||||
// 塘口基本数据
|
||||
export function pondBaseInfo(data){
|
||||
return httpService.get(API.POND.BASE_INFO() + '/' + data.id)
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
return httpService.get(`${API.POND.BASE_INFO()}/${data.id}?rootUserId=${userId}`)
|
||||
}
|
||||
// 塘口下设备信息
|
||||
export function pondDeviceInfo(data){
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
// 后端接口:GET /devices/{pondId},使用路径参数
|
||||
return httpService.get(API.POND.DEVICE_INFO() + '/' + data.id)
|
||||
return httpService.get(`${API.POND.DEVICE_INFO()}/${data.id}?rootUserId=${userId}`)
|
||||
}
|
||||
@@ -7,13 +7,13 @@ export function list_user_child() {
|
||||
}
|
||||
|
||||
// 添加
|
||||
export function add_user_child(data) {
|
||||
return httpService.post(`${API.SUB_ACCOUNT.ADD()}?mobilePhone=${data}`)
|
||||
export function add_user_child(mobilePhone) {
|
||||
return httpService.post(API.SUB_ACCOUNT.ADD(), { data: { mobilePhone } })
|
||||
}
|
||||
|
||||
// 删除
|
||||
export function delete_user_child(data) {
|
||||
return httpService.delete(API.SUB_ACCOUNT.DELETE(), {data})
|
||||
export function delete_user_child(id) {
|
||||
return httpService.delete(API.SUB_ACCOUNT.DELETE(), { data: { id } })
|
||||
}
|
||||
|
||||
// 获取父级账号
|
||||
|
||||
@@ -6,6 +6,7 @@ export default defineAppConfig({
|
||||
'pages/msg/index',
|
||||
'pages/main/my',
|
||||
'components/other/chartFullscreen',
|
||||
'components/other/dataQuery',
|
||||
],
|
||||
requiredPrivateInfos: [
|
||||
"getLocation", "chooseLocation"
|
||||
@@ -22,6 +23,7 @@ export default defineAppConfig({
|
||||
"addPond",
|
||||
"updatePond",
|
||||
"wqm",
|
||||
"solar",
|
||||
"ctr",
|
||||
"switch",
|
||||
"linkControl",
|
||||
@@ -39,6 +41,7 @@ export default defineAppConfig({
|
||||
"help",
|
||||
"alarmPhone",
|
||||
"addDetector",
|
||||
"addSolarDetector",
|
||||
"addController",
|
||||
"addDevSuccess",
|
||||
"subAccount",
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
<template>
|
||||
<view :style="{ height: statusBarHeight + 'px' }"></view>
|
||||
<view class="nav-bar" :style="{ height: navBarHeight + 'px' }">
|
||||
<view class="font_32 f_weight" @click="toParent"> {{ username }}的鱼塘</view>
|
||||
<TriangleDown
|
||||
color="#222"
|
||||
@click="toParent"
|
||||
v-if="parentList.length > 1"
|
||||
></TriangleDown>
|
||||
<view class="account-selector" @click="toParent">
|
||||
<text class="account-prefix">账号选择:</text>
|
||||
<text class="account-name">{{ username }}的鱼塘</text>
|
||||
<text class="account-type">{{ accountType }}</text>
|
||||
<TriangleDown
|
||||
color="#222"
|
||||
v-if="parentList.length > 1"
|
||||
></TriangleDown>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 选择塘口 -->
|
||||
<nut-popup v-model:visible="showParent" position="bottom">
|
||||
@@ -37,6 +40,20 @@ const navBarHeight = ref();
|
||||
const username = ref(
|
||||
Taro.getStorageSync("UserName") ? Taro.getStorageSync("UserName") : "鱼测云"
|
||||
);
|
||||
// 计算账号类型:主账号或子账号
|
||||
const accountType = computed(() => {
|
||||
const currentUserId = store.getRootUserId;
|
||||
const originalUserId = Taro.getStorageSync("UserId");
|
||||
|
||||
// 判断当前选中的是否是登录账号
|
||||
if (currentUserId === originalUserId) {
|
||||
// 登录账号始终显示为主账号
|
||||
return "(主账号)";
|
||||
} else {
|
||||
// 如果选中的是其他账号,那一定是登录账号的父账号,显示为关联账号
|
||||
return "(关联账号)";
|
||||
}
|
||||
});
|
||||
//然后计算出navBarHeight
|
||||
navBarHeight.value =
|
||||
menuButtonInfo.bottom -
|
||||
@@ -61,15 +78,21 @@ watchEffect(() => {
|
||||
/** --------------method start------------------- */
|
||||
function getParentList() {
|
||||
list_user_parent().then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
const originalUserId = Taro.getStorageSync("UserId");
|
||||
const originalUserName = Taro.getStorageSync("UserName");
|
||||
|
||||
const arr = [
|
||||
{
|
||||
userId: Taro.getStorageSync("UserId"),
|
||||
userName: Taro.getStorageSync("UserName"),
|
||||
userId: originalUserId,
|
||||
userName: `${originalUserName}(主账号)`,
|
||||
},
|
||||
];
|
||||
res.data.forEach((r) => {
|
||||
arr.push(r);
|
||||
arr.push({
|
||||
userId: r.userId,
|
||||
userName: `${r.userName}(关联账号)`,
|
||||
});
|
||||
});
|
||||
parentList.value = arr;
|
||||
}
|
||||
@@ -112,8 +135,43 @@ defineExpose({
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0 0 30px;
|
||||
// position: fixed;
|
||||
// z-index: 1000;
|
||||
|
||||
.account-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f5f6f7;
|
||||
border-radius: 8px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:active {
|
||||
background: #e8e9ea;
|
||||
}
|
||||
|
||||
.account-prefix {
|
||||
font-size: 28px;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.account-name {
|
||||
font-size: 28px;
|
||||
color: #222;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
.account-type {
|
||||
font-size: 24px;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
@@ -2,4 +2,5 @@ export default definePageConfig({
|
||||
navigationBarTitleText: '曲线图',
|
||||
navigationStyle: 'custom',
|
||||
enablePullDownRefresh: false,
|
||||
pageOrientation: 'landscape',
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="chart-fullscreen-page">
|
||||
<view class="chart-fullscreen-page" :style="pageStyle">
|
||||
<!-- 顶部标题栏 -->
|
||||
<view class="header">
|
||||
<view class="back-btn" @click="goBack">
|
||||
@@ -34,18 +34,22 @@
|
||||
</view>
|
||||
|
||||
<!-- 图表容器 -->
|
||||
<view class="chart-container">
|
||||
<view class="chart-container" :style="chartContainerStyle">
|
||||
<canvas
|
||||
class="chart-canvas"
|
||||
canvas-id="fullscreen-chart"
|
||||
type="2d"
|
||||
id="fullscreen-chart"
|
||||
:style="canvasStyle"
|
||||
@touchend="touchEnd"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
></canvas>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { deviceHistory } from '@/api/device';
|
||||
import { formatDateMin } from '@/utils/tools';
|
||||
@@ -59,8 +63,47 @@ let chartInstance: any = null;
|
||||
// 接收的参数
|
||||
const serialNum = ref('');
|
||||
const dataType = ref(1); // 1-溶解氧, 2-水温, 3-饱和度, 4-PH, 5-盐度
|
||||
const oxyWarnLower = ref<number | null>(null);
|
||||
const tempWarnUpper = ref<number | null>(null);
|
||||
const tempWarnLower = ref<number | null>(null);
|
||||
|
||||
// 屏幕尺寸
|
||||
const screenWidth = ref(375);
|
||||
const screenHeight = ref(667);
|
||||
|
||||
// 页面样式(小程序通过配置自动横屏)
|
||||
const pageStyle = computed(() => {
|
||||
return {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background: '#fff',
|
||||
display: 'flex',
|
||||
flexDirection: 'column' as const,
|
||||
};
|
||||
});
|
||||
|
||||
const chartContainerStyle = computed(() => {
|
||||
return {
|
||||
flex: '1',
|
||||
padding: '10px 15px',
|
||||
background: '#fff',
|
||||
overflow: 'hidden',
|
||||
};
|
||||
});
|
||||
|
||||
const canvasStyle = computed(() => {
|
||||
return {
|
||||
width: chartWidth.value + 'px',
|
||||
height: chartHeight.value + 'px',
|
||||
};
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// 获取屏幕尺寸
|
||||
const sysInfo = Taro.getSystemInfoSync();
|
||||
screenWidth.value = sysInfo.windowWidth;
|
||||
screenHeight.value = sysInfo.windowHeight;
|
||||
|
||||
// 获取页面参数
|
||||
const instance = Taro.getCurrentInstance();
|
||||
const params = instance.router?.params || {};
|
||||
@@ -68,6 +111,9 @@ onMounted(() => {
|
||||
serialNum.value = params.serialNum || '';
|
||||
dataType.value = Number(params.dataType) || 1;
|
||||
dayType.value = Number(params.dayType) || 1;
|
||||
oxyWarnLower.value = params.oxyWarnLower ? Number(params.oxyWarnLower) : null;
|
||||
tempWarnUpper.value = params.tempWarnUpper ? Number(params.tempWarnUpper) : null;
|
||||
tempWarnLower.value = params.tempWarnLower ? Number(params.tempWarnLower) : null;
|
||||
|
||||
// 设置标题
|
||||
const titles = ['', '溶解氧曲线图', '水温曲线图', '饱和度曲线图', 'PH曲线图', '盐度曲线图'];
|
||||
@@ -85,29 +131,24 @@ onUnmounted(() => {
|
||||
}
|
||||
});
|
||||
|
||||
// 图表尺寸
|
||||
const chartWidth = ref(0);
|
||||
const chartHeight = ref(0);
|
||||
const chartPixelRatio = ref(1);
|
||||
const chartTop = ref(0);
|
||||
const chartLeft = ref(0);
|
||||
|
||||
// 初始化图表
|
||||
function initChart() {
|
||||
// 横屏后的尺寸计算:
|
||||
// 页面宽度 = 屏幕高度(100vh)
|
||||
// 页面高度 = 屏幕宽度(100vw)
|
||||
// header(50px) + time-selector(50px) = 100px
|
||||
|
||||
const screenWidth = window.innerWidth; // 屏幕宽度
|
||||
const screenHeight = window.innerHeight; // 屏幕高度
|
||||
|
||||
// 横屏后:
|
||||
const cWidth = screenHeight - 40; // 页面宽度(100vh) - padding
|
||||
const cHeight = screenWidth - 120; // 页面高度(100vw) - header - time-selector - padding
|
||||
|
||||
console.log('📊 横屏图表尺寸计算:', {
|
||||
屏幕宽: screenWidth,
|
||||
屏幕高: screenHeight,
|
||||
图表宽: cWidth,
|
||||
图表高: cHeight
|
||||
});
|
||||
const sysInfo = Taro.getSystemInfoSync();
|
||||
// 横屏模式,windowWidth 是横屏后的宽度(较大),windowHeight 是横屏后的高度(较小)
|
||||
// header(44px) + time-selector(44px) = 88px
|
||||
chartWidth.value = sysInfo.windowWidth - 30;
|
||||
chartHeight.value = sysInfo.windowHeight - 100;
|
||||
chartPixelRatio.value = sysInfo.pixelRatio || 1;
|
||||
|
||||
// 加载数据
|
||||
loadChartData(cWidth, cHeight, 1);
|
||||
loadChartData();
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
@@ -125,18 +166,11 @@ function goHome() {
|
||||
// 切换天数
|
||||
function changeDay(day: number) {
|
||||
dayType.value = day;
|
||||
|
||||
// 重新计算尺寸
|
||||
const screenWidth = window.innerWidth;
|
||||
const screenHeight = window.innerHeight;
|
||||
const cWidth = screenHeight - 40;
|
||||
const cHeight = screenWidth - 120;
|
||||
|
||||
loadChartData(cWidth, cHeight, 1);
|
||||
loadChartData();
|
||||
}
|
||||
|
||||
// 加载图表数据
|
||||
function loadChartData(cWidth: number, cHeight: number, pixelRatio: number) {
|
||||
function loadChartData() {
|
||||
if (!serialNum.value) return;
|
||||
|
||||
const now = new Date();
|
||||
@@ -161,19 +195,22 @@ function loadChartData(cWidth: number, cHeight: number, pixelRatio: number) {
|
||||
}
|
||||
|
||||
// 绘制图表
|
||||
drawChart(cWidth, cHeight, pixelRatio);
|
||||
drawChart();
|
||||
}).catch(() => {
|
||||
Taro.hideLoading();
|
||||
});
|
||||
}
|
||||
|
||||
// 绘制图表
|
||||
function drawChart(cWidth: number, cHeight: number, pixelRatio: number) {
|
||||
function drawChart() {
|
||||
if (!chartData.value || chartData.value.length === 0) {
|
||||
console.log('❌ 数据为空');
|
||||
return;
|
||||
}
|
||||
|
||||
const cWidth = chartWidth.value;
|
||||
const cHeight = chartHeight.value;
|
||||
const pixelRatio = chartPixelRatio.value;
|
||||
|
||||
const fieldMap: any = {
|
||||
1: 'dissolvedOxygen',
|
||||
2: 'temperature',
|
||||
@@ -195,194 +232,345 @@ function drawChart(cWidth: number, cHeight: number, pixelRatio: number) {
|
||||
|
||||
const xAxisData: string[] = [];
|
||||
const seriesData: number[] = [];
|
||||
let series: any[] = [];
|
||||
|
||||
// 根据数据类型添加告警线
|
||||
if (dataType.value === 1 && oxyWarnLower.value) {
|
||||
series.push({
|
||||
name: '告警下限',
|
||||
data: [],
|
||||
color: '#c12e34',
|
||||
lineType: 'dash',
|
||||
});
|
||||
} else if (dataType.value === 2) {
|
||||
if (tempWarnLower.value) {
|
||||
series.push({
|
||||
name: '告警下限',
|
||||
data: [],
|
||||
color: '#c12e34',
|
||||
lineType: 'dash',
|
||||
});
|
||||
}
|
||||
if (tempWarnUpper.value) {
|
||||
series.push({
|
||||
name: '告警上限',
|
||||
data: [],
|
||||
color: '#e098c7',
|
||||
lineType: 'dash',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
chartData.value.forEach((item: any) => {
|
||||
const timeStr = item.time || item.createTime || '';
|
||||
const timeParts = timeStr.split(' ');
|
||||
if (timeParts.length > 1) {
|
||||
const datePart = timeParts[0]; // YYYY-MM-DD
|
||||
const timePart = timeParts[1]; // HH:mm:ss.0
|
||||
const datePart = timeParts[0];
|
||||
const timePart = timeParts[1];
|
||||
|
||||
// 提取 MM-DD HH:mm
|
||||
const dateMatch = datePart.match(/\d{4}-(\d{2})-(\d{2})/);
|
||||
const monthDay = dateMatch ? `${dateMatch[1]}-${dateMatch[2]}` : '';
|
||||
const hourMin = timePart.substring(0, 5); // HH:mm
|
||||
const hourMin = timePart.substring(0, 5);
|
||||
|
||||
const formattedTime = `${monthDay} ${hourMin}`;
|
||||
xAxisData.push(formattedTime);
|
||||
}
|
||||
const value = item[fieldName];
|
||||
seriesData.push(value !== null && value !== undefined ? Number(value) : 0);
|
||||
|
||||
// 填充告警线数据
|
||||
if (dataType.value === 1 && oxyWarnLower.value) {
|
||||
series[0].data.push(oxyWarnLower.value);
|
||||
} else if (dataType.value === 2) {
|
||||
let idx = 0;
|
||||
if (tempWarnLower.value) {
|
||||
series[idx].data.push(tempWarnLower.value);
|
||||
idx++;
|
||||
}
|
||||
if (tempWarnUpper.value) {
|
||||
series[idx].data.push(tempWarnUpper.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// H5 环境,延迟获取 Canvas 确保 DOM 渲染完成
|
||||
setTimeout(() => {
|
||||
// Taro 在 H5 下会在容器内部生成 <canvas> 标签
|
||||
const canvasElement = document.querySelector('#fullscreen-chart canvas') as HTMLCanvasElement;
|
||||
// 添加主数据系列
|
||||
series.unshift({ name: seriesName, data: seriesData });
|
||||
|
||||
Taro.nextTick(() => {
|
||||
const env = Taro.getEnv();
|
||||
|
||||
if (!canvasElement) {
|
||||
console.error('❌ Canvas 元素未找到');
|
||||
console.log('尝试查找所有 canvas...');
|
||||
const allCanvas = document.querySelectorAll('canvas');
|
||||
console.log('页面中所有 canvas:', allCanvas);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ 找到 Canvas 元素:', canvasElement);
|
||||
|
||||
const ctx = canvasElement.getContext('2d');
|
||||
if (!ctx) {
|
||||
console.error('❌ 无法获取 Canvas Context');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ 获取 Context 成功');
|
||||
|
||||
chartInstance = new uCharts({
|
||||
type: 'line',
|
||||
context: ctx,
|
||||
width: cWidth,
|
||||
height: cHeight,
|
||||
categories: xAxisData,
|
||||
series: [
|
||||
{
|
||||
name: seriesName,
|
||||
data: seriesData,
|
||||
}
|
||||
],
|
||||
pixelRatio: 1,
|
||||
dataPointShape: false,
|
||||
animation: true,
|
||||
background: '#FFFFFF',
|
||||
color: ['#1890FF'],
|
||||
padding: [15, 30, 35, 45],
|
||||
enableScroll: false,
|
||||
boundaryGap: 'justify',
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
dataLabel: false,
|
||||
xAxis: {
|
||||
disableGrid: true,
|
||||
axisLine: true,
|
||||
type: 'grid',
|
||||
gridType: 'dash',
|
||||
itemCount: 0,
|
||||
scrollShow: false,
|
||||
scrollAlign: 'left',
|
||||
labelCount: 10,
|
||||
rotateLabel: true,
|
||||
rotateAngle: 25,
|
||||
},
|
||||
yAxis: {
|
||||
disableGrid: false,
|
||||
gridType: 'dash',
|
||||
tofix: 2,
|
||||
},
|
||||
extra: {
|
||||
line: {
|
||||
type: 'curve',
|
||||
width: 2,
|
||||
activeType: 'hollow',
|
||||
linearType: 'custom',
|
||||
},
|
||||
},
|
||||
// 获取 canvas 位置
|
||||
const query = Taro.createSelectorQuery();
|
||||
query.select('#fullscreen-chart').boundingClientRect();
|
||||
query.selectViewport().scrollOffset();
|
||||
query.exec((res) => {
|
||||
if (res.length > 0 && res[0]) {
|
||||
chartTop.value = res[0].top || 0;
|
||||
chartLeft.value = res[0].left || 0;
|
||||
}
|
||||
});
|
||||
|
||||
console.log('✅ 图表绘制完成');
|
||||
}, 300);
|
||||
if (env === Taro.ENV_TYPE.WEB) {
|
||||
// H5 环境
|
||||
setTimeout(() => {
|
||||
const canvasElement = document.querySelector('#fullscreen-chart canvas') as HTMLCanvasElement;
|
||||
if (!canvasElement) return;
|
||||
|
||||
const ctx = canvasElement.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
chartInstance = new uCharts({
|
||||
type: 'line',
|
||||
context: ctx,
|
||||
width: cWidth,
|
||||
height: cHeight,
|
||||
categories: xAxisData,
|
||||
series: series,
|
||||
pixelRatio: 1,
|
||||
dataPointShape: false,
|
||||
animation: true,
|
||||
background: '#FFFFFF',
|
||||
color: ['#17B4B2'],
|
||||
padding: [15, 15, 30, 40],
|
||||
enableScroll: false,
|
||||
boundaryGap: 'justify',
|
||||
legend: { show: false },
|
||||
dataLabel: false,
|
||||
xAxis: {
|
||||
disableGrid: true,
|
||||
axisLine: true,
|
||||
type: 'grid',
|
||||
gridType: 'dash',
|
||||
scrollShow: false,
|
||||
labelCount: 8,
|
||||
rotateLabel: true,
|
||||
rotateAngle: 30,
|
||||
},
|
||||
yAxis: {
|
||||
disableGrid: false,
|
||||
gridType: 'dash',
|
||||
tofix: 2,
|
||||
},
|
||||
extra: {
|
||||
tooltip: {
|
||||
showBox: true,
|
||||
showArrow: true,
|
||||
showCategory: true,
|
||||
borderWidth: 0,
|
||||
borderRadius: 0,
|
||||
borderColor: '#000000',
|
||||
borderOpacity: 0.7,
|
||||
bgColor: '#000000',
|
||||
bgOpacity: 0.7,
|
||||
gridType: 'solid',
|
||||
dashLength: 4,
|
||||
gridColor: '#CCCCCC',
|
||||
boxPadding: 3,
|
||||
fontSize: 13,
|
||||
lineHeight: 20,
|
||||
fontColor: '#FFFFFF',
|
||||
legendShow: true,
|
||||
legendShape: 'auto',
|
||||
splitLine: true,
|
||||
labelBgColor: '#FFFFFF',
|
||||
labelBgOpacity: 0.7,
|
||||
labelFontColor: '#666666',
|
||||
},
|
||||
line: { type: 'curve', width: 2, activeType: 'hollow' },
|
||||
},
|
||||
});
|
||||
}, 300);
|
||||
} else {
|
||||
// 小程序环境
|
||||
const query = Taro.createSelectorQuery();
|
||||
query.select('#fullscreen-chart')
|
||||
.fields({ node: true, size: true })
|
||||
.exec((res) => {
|
||||
if (!res || !res[0] || !res[0].node) return;
|
||||
|
||||
const canvas = res[0].node;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
canvas.width = cWidth * pixelRatio;
|
||||
canvas.height = cHeight * pixelRatio;
|
||||
|
||||
chartInstance = new uCharts({
|
||||
type: 'line',
|
||||
context: ctx,
|
||||
width: cWidth * pixelRatio,
|
||||
height: cHeight * pixelRatio,
|
||||
categories: xAxisData,
|
||||
series: series,
|
||||
pixelRatio: pixelRatio,
|
||||
dataPointShape: false,
|
||||
animation: true,
|
||||
background: '#FFFFFF',
|
||||
color: ['#17B4B2'],
|
||||
padding: [15, 15, 30, 40],
|
||||
enableScroll: false,
|
||||
boundaryGap: 'justify',
|
||||
legend: { show: false },
|
||||
dataLabel: false,
|
||||
xAxis: {
|
||||
disableGrid: true,
|
||||
axisLine: true,
|
||||
type: 'grid',
|
||||
gridType: 'dash',
|
||||
scrollShow: false,
|
||||
labelCount: 6,
|
||||
rotateLabel: true,
|
||||
rotateAngle: 20,
|
||||
marginTop: 5,
|
||||
},
|
||||
yAxis: {
|
||||
disableGrid: false,
|
||||
gridType: 'dash',
|
||||
tofix: 2,
|
||||
},
|
||||
extra: {
|
||||
tooltip: {
|
||||
showBox: true,
|
||||
showArrow: true,
|
||||
showCategory: true,
|
||||
borderWidth: 0,
|
||||
borderRadius: 0,
|
||||
borderColor: '#000000',
|
||||
borderOpacity: 0.7,
|
||||
bgColor: '#000000',
|
||||
bgOpacity: 0.7,
|
||||
gridType: 'solid',
|
||||
dashLength: 4,
|
||||
gridColor: '#CCCCCC',
|
||||
boxPadding: 3,
|
||||
fontSize: 13,
|
||||
lineHeight: 20,
|
||||
fontColor: '#FFFFFF',
|
||||
legendShow: true,
|
||||
legendShape: 'auto',
|
||||
splitLine: true,
|
||||
labelBgColor: '#FFFFFF',
|
||||
labelBgOpacity: 0.7,
|
||||
labelFontColor: '#666666',
|
||||
},
|
||||
line: { type: 'curve', width: 2, activeType: 'hollow' },
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 触摸结束事件
|
||||
function touchEnd(e: any) {
|
||||
if (!chartInstance) return;
|
||||
|
||||
const x = e.mpEvent.changedTouches[0].clientX;
|
||||
const y = e.mpEvent.changedTouches[0].clientY;
|
||||
const tmpe = { x: x - chartLeft.value, y: y - chartTop.value };
|
||||
e.changedTouches = [tmpe];
|
||||
|
||||
if (e.touches.length == 0) {
|
||||
chartInstance.touchLegend(e);
|
||||
chartInstance.showToolTip(e, {
|
||||
formatter: (item: any) => {
|
||||
return item.name + ':' + item.data;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 触摸开始事件
|
||||
function touchStart(e: any) {
|
||||
if (!chartInstance) return;
|
||||
|
||||
const x = e.mpEvent.changedTouches[0].clientX;
|
||||
const y = e.mpEvent.changedTouches[0].clientY;
|
||||
const tmpe = { x: x - chartLeft.value, y: y - chartTop.value };
|
||||
e.changedTouches = [tmpe];
|
||||
chartInstance.scrollStart(e);
|
||||
}
|
||||
|
||||
// 触摸移动事件
|
||||
function touchMove(e: any) {
|
||||
if (!chartInstance) return;
|
||||
|
||||
const x = e.mpEvent.changedTouches[0].clientX;
|
||||
const y = e.mpEvent.changedTouches[0].clientY;
|
||||
const tmpe = { x: x - chartLeft.value, y: y - chartTop.value };
|
||||
e.changedTouches = [tmpe];
|
||||
chartInstance.scroll(e);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
<style lang="scss">
|
||||
.chart-fullscreen-page {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100vh; // 横屏后的宽度 = 屏幕高度
|
||||
height: 100vw; // 横屏后的高度 = 屏幕宽度
|
||||
transform: translate(-50%, -50%) rotate(90deg);
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 9999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 50px;
|
||||
height: 34px;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
flex-shrink: 0;
|
||||
|
||||
.back-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
font-size: 28px;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.home-btn {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.home-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.back-btn .icon {
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-right: 44px;
|
||||
}
|
||||
|
||||
.time-selector {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
gap: 12px;
|
||||
padding: 2px 5px 2px 15px;
|
||||
background: #fff;
|
||||
flex-shrink: 0;
|
||||
height: 50px;
|
||||
|
||||
.time-item {
|
||||
padding: 8px 24px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 6px;
|
||||
font-size: 24px;
|
||||
color: #666;
|
||||
|
||||
&.active {
|
||||
background: #1890FF;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
height: 34px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.time-item {
|
||||
padding: 6px 20px;
|
||||
margin: 0 5px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.time-item.active {
|
||||
background: #09B8C2;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
|
||||
.chart-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-canvas {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
5
src/components/other/dataQuery.config.ts
Normal file
5
src/components/other/dataQuery.config.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export default definePageConfig({
|
||||
navigationStyle: 'custom',
|
||||
pageOrientation: 'landscape',
|
||||
disableScroll: true,
|
||||
})
|
||||
763
src/components/other/dataQuery.vue
Normal file
763
src/components/other/dataQuery.vue
Normal file
@@ -0,0 +1,763 @@
|
||||
<template>
|
||||
<view class="data-query-page" :style="pageStyle">
|
||||
<!-- 顶部标题栏 -->
|
||||
<view class="header">
|
||||
<view class="back-btn" @click="goBack">
|
||||
<text class="icon">←</text>
|
||||
</view>
|
||||
<view class="title">{{ chartTitle }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 查询条件区域 -->
|
||||
<view class="query-section">
|
||||
<view class="query-container">
|
||||
<view class="query-item">
|
||||
<view class="query-label">开始时间</view>
|
||||
<view class="query-value" @click="showStartPicker = true">
|
||||
{{ startDate || '请选择' }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="query-item">
|
||||
<view class="query-label">结束时间</view>
|
||||
<view class="query-value" @click="showEndPicker = true">
|
||||
{{ endDate || '请选择' }}
|
||||
</view>
|
||||
</view>
|
||||
<nut-button
|
||||
type="primary"
|
||||
size="small"
|
||||
class="query-btn"
|
||||
@click="queryData"
|
||||
>
|
||||
查询
|
||||
</nut-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图表容器 -->
|
||||
<view class="chart-container" :style="chartContainerStyle">
|
||||
<view class="loading-container" v-show="loading">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
<canvas
|
||||
v-if="!loading"
|
||||
class="chart-canvas"
|
||||
type="2d"
|
||||
id="data-query-chart"
|
||||
:style="canvasStyle"
|
||||
@touchend="touchEnd"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
></canvas>
|
||||
<view v-if="!loading && (!chartData || chartData.length === 0)" class="empty-data">
|
||||
<text>暂无数据</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 开始时间选择器 -->
|
||||
<nut-popup v-model:visible="showStartPicker" position="bottom" :style="{ paddingTop: '30px' }">
|
||||
<nut-date-picker
|
||||
v-model="startDateTime"
|
||||
type="datetime"
|
||||
title="选择开始时间"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
@confirm="confirmStartDate"
|
||||
@cancel="showStartPicker = false"
|
||||
ok-text="确定"
|
||||
/>
|
||||
</nut-popup>
|
||||
|
||||
<!-- 结束时间选择器 -->
|
||||
<nut-popup v-model:visible="showEndPicker" position="bottom" :style="{ paddingTop: '30px' }">
|
||||
<nut-date-picker
|
||||
v-model="endDateTime"
|
||||
type="datetime"
|
||||
title="选择结束时间"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
@confirm="confirmEndDate"
|
||||
@cancel="showEndPicker = false"
|
||||
ok-text="确定"
|
||||
/>
|
||||
</nut-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import Taro from '@tarojs/taro';
|
||||
import { deviceHistory } from '@/api/device';
|
||||
import { formatDateMin } from '@/utils/tools';
|
||||
import uCharts from '@/utils/js-sdk/u-charts/u-charts.js';
|
||||
|
||||
const chartTitle = ref('数据查询');
|
||||
const chartData = ref<any[]>([]);
|
||||
const loading = ref(false);
|
||||
let chartInstance: any = null;
|
||||
|
||||
// 接收的参数
|
||||
const serialNum = ref('');
|
||||
const dataType = ref(1); // 1-溶解氧, 2-水温, 3-饱和度, 4-PH, 5-盐度
|
||||
const deviceName = ref('');
|
||||
const oxyWarnLower = ref<number | null>(null);
|
||||
const tempWarnUpper = ref<number | null>(null);
|
||||
const tempWarnLower = ref<number | null>(null);
|
||||
|
||||
// 时间选择
|
||||
const showStartPicker = ref(false);
|
||||
const showEndPicker = ref(false);
|
||||
const startDate = ref('');
|
||||
const endDate = ref('');
|
||||
const startDateTime = ref(new Date(new Date().getTime() - 30 * 24 * 60 * 60 * 1000));
|
||||
const endDateTime = ref(new Date());
|
||||
|
||||
// 日期范围限制(最近90天到当前)
|
||||
const minDate = computed(() => new Date(new Date().getTime() - 90 * 24 * 60 * 60 * 1000));
|
||||
const maxDate = computed(() => new Date());
|
||||
|
||||
// 屏幕尺寸
|
||||
const screenWidth = ref(375);
|
||||
const screenHeight = ref(667);
|
||||
|
||||
// 页面样式
|
||||
const pageStyle = computed(() => {
|
||||
return {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background: '#fff',
|
||||
display: 'flex',
|
||||
flexDirection: 'column' as const,
|
||||
};
|
||||
});
|
||||
|
||||
const chartContainerStyle = computed(() => {
|
||||
return {
|
||||
flex: '1',
|
||||
padding: '10px 15px',
|
||||
background: '#fff',
|
||||
overflow: 'hidden',
|
||||
position: 'relative' as const,
|
||||
};
|
||||
});
|
||||
|
||||
const canvasStyle = computed(() => {
|
||||
return {
|
||||
width: chartWidth.value + 'px',
|
||||
height: chartHeight.value + 'px',
|
||||
};
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// 获取屏幕尺寸
|
||||
const sysInfo = Taro.getSystemInfoSync();
|
||||
screenWidth.value = sysInfo.windowWidth;
|
||||
screenHeight.value = sysInfo.windowHeight;
|
||||
|
||||
// 获取页面参数
|
||||
const instance = Taro.getCurrentInstance();
|
||||
const params = instance.router?.params || {};
|
||||
|
||||
serialNum.value = params.serialNum || '';
|
||||
dataType.value = Number(params.dataType) || 1;
|
||||
deviceName.value = params.deviceName || '';
|
||||
oxyWarnLower.value = params.oxyWarnLower ? Number(params.oxyWarnLower) : null;
|
||||
tempWarnUpper.value = params.tempWarnUpper ? Number(params.tempWarnUpper) : null;
|
||||
tempWarnLower.value = params.tempWarnLower ? Number(params.tempWarnLower) : null;
|
||||
|
||||
// 设置标题
|
||||
const titles = ['', '溶解氧数据查询', '水温数据查询', '饱和度数据查询', 'PH数据查询', '盐度数据查询'];
|
||||
chartTitle.value = titles[dataType.value] || '数据查询';
|
||||
|
||||
// 初始化默认时间(最近30天)
|
||||
const now = new Date();
|
||||
const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
||||
startDate.value = formatDateMin(monthAgo);
|
||||
endDate.value = formatDateMin(now);
|
||||
|
||||
// 初始化图表尺寸
|
||||
setTimeout(() => {
|
||||
initChart();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (chartInstance) {
|
||||
chartInstance = null;
|
||||
}
|
||||
});
|
||||
|
||||
// 图表尺寸
|
||||
const chartWidth = ref(0);
|
||||
const chartHeight = ref(0);
|
||||
const chartPixelRatio = ref(1);
|
||||
const chartTop = ref(0);
|
||||
const chartLeft = ref(0);
|
||||
|
||||
// 初始化图表
|
||||
function initChart() {
|
||||
const sysInfo = Taro.getSystemInfoSync();
|
||||
// 横屏模式,header(44px) + query-section(约50px) = 94px
|
||||
chartWidth.value = sysInfo.windowWidth - 30;
|
||||
chartHeight.value = sysInfo.windowHeight - 110;
|
||||
chartPixelRatio.value = sysInfo.pixelRatio || 1;
|
||||
|
||||
// 自动加载默认数据(最近30天)
|
||||
queryData();
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
function goBack() {
|
||||
Taro.navigateBack();
|
||||
}
|
||||
|
||||
function buildDateFromPickerValue(value: unknown, fallback: Date) {
|
||||
if (value instanceof Date && !Number.isNaN(value.getTime())) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof value === 'number' || typeof value === 'string') {
|
||||
const date = new Date(value);
|
||||
if (!Number.isNaN(date.getTime())) {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(value) && value.length >= 5) {
|
||||
const [year, month, day, hour, minute] = value.map((item) => Number(item));
|
||||
const date = new Date(year, month - 1, day, hour, minute, 0);
|
||||
if (!Number.isNaN(date.getTime())) {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// 确认开始时间
|
||||
function confirmStartDate({ selectedValue }: { selectedValue: unknown }) {
|
||||
const nextDate = buildDateFromPickerValue(selectedValue, startDateTime.value);
|
||||
startDateTime.value = nextDate;
|
||||
startDate.value = formatDateMin(nextDate);
|
||||
showStartPicker.value = false;
|
||||
}
|
||||
|
||||
// 确认结束时间
|
||||
function confirmEndDate({ selectedValue }: { selectedValue: unknown }) {
|
||||
const nextDate = buildDateFromPickerValue(selectedValue, endDateTime.value);
|
||||
endDateTime.value = nextDate;
|
||||
endDate.value = formatDateMin(nextDate);
|
||||
showEndPicker.value = false;
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
function queryData() {
|
||||
if (!serialNum.value) {
|
||||
Taro.showToast({ title: '设备序列号不存在', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!startDate.value || !endDate.value) {
|
||||
Taro.showToast({ title: '请选择查询时间范围', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证时间范围
|
||||
const start = startDateTime.value;
|
||||
const end = endDateTime.value;
|
||||
|
||||
if (start.getTime() >= end.getTime()) {
|
||||
Taro.showToast({ title: '开始时间必须小于结束时间', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算天数差
|
||||
const dayDiff = Math.ceil((end.getTime() - start.getTime()) / (24 * 60 * 60 * 1000));
|
||||
|
||||
if (dayDiff > 90) {
|
||||
Taro.showToast({ title: '查询范围不能超过3个月(90天)', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据天数差确定 intervalType
|
||||
// ≤3天: intervalType = 1
|
||||
// ≤7天: intervalType = 2
|
||||
// 7-14天: intervalType = 3
|
||||
// 14-30天: intervalType = 4
|
||||
// 30-60天: intervalType = 5
|
||||
// >60天: intervalType = 6
|
||||
|
||||
let intervalType = 1;
|
||||
if (dayDiff > 3 && dayDiff <= 7) {
|
||||
intervalType = 2;
|
||||
} else if (dayDiff > 7 && dayDiff <= 14) {
|
||||
intervalType = 3;
|
||||
} else if (dayDiff > 14 && dayDiff <= 30) {
|
||||
intervalType = 4;
|
||||
} else if (dayDiff > 30 && dayDiff <= 60) {
|
||||
intervalType = 5;
|
||||
} else if (dayDiff > 60) {
|
||||
intervalType = 6;
|
||||
}
|
||||
|
||||
const params = {
|
||||
serialNum: serialNum.value,
|
||||
startTime: startDate.value,
|
||||
endTime: endDate.value,
|
||||
intervalType: intervalType,
|
||||
};
|
||||
|
||||
loading.value = true;
|
||||
|
||||
deviceHistory(params).then((res: any) => {
|
||||
loading.value = false;
|
||||
|
||||
if (Array.isArray(res)) {
|
||||
chartData.value = res;
|
||||
} else if (res.code == 200) {
|
||||
chartData.value = res.data || [];
|
||||
}
|
||||
|
||||
if (chartData.value.length === 0) {
|
||||
Taro.showToast({ title: '该时间段暂无数据', icon: 'none' });
|
||||
} else {
|
||||
// 绘制图表
|
||||
drawChart();
|
||||
}
|
||||
}).catch(() => {
|
||||
loading.value = false;
|
||||
Taro.showToast({ title: '查询失败,请重试', icon: 'none' });
|
||||
});
|
||||
}
|
||||
|
||||
// 绘制图表
|
||||
function drawChart() {
|
||||
if (!chartData.value || chartData.value.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cWidth = chartWidth.value;
|
||||
const cHeight = chartHeight.value;
|
||||
const pixelRatio = chartPixelRatio.value;
|
||||
|
||||
const fieldMap: any = {
|
||||
1: 'dissolvedOxygen',
|
||||
2: 'temperature',
|
||||
3: 'saturability',
|
||||
4: 'ph',
|
||||
5: 'salinity',
|
||||
};
|
||||
|
||||
const nameMap: any = {
|
||||
1: '溶解氧',
|
||||
2: '水温',
|
||||
3: '饱和度',
|
||||
4: 'PH',
|
||||
5: '盐度',
|
||||
};
|
||||
|
||||
const fieldName = fieldMap[dataType.value] || 'dissolvedOxygen';
|
||||
const seriesName = nameMap[dataType.value] || '溶解氧';
|
||||
|
||||
const xAxisData: string[] = [];
|
||||
const seriesData: number[] = [];
|
||||
let series: any[] = [];
|
||||
|
||||
// 根据数据类型添加告警线
|
||||
if (dataType.value === 1 && oxyWarnLower.value) {
|
||||
series.push({
|
||||
name: '告警下限',
|
||||
data: [],
|
||||
color: '#c12e34',
|
||||
lineType: 'dash',
|
||||
});
|
||||
} else if (dataType.value === 2) {
|
||||
if (tempWarnLower.value) {
|
||||
series.push({
|
||||
name: '告警下限',
|
||||
data: [],
|
||||
color: '#c12e34',
|
||||
lineType: 'dash',
|
||||
});
|
||||
}
|
||||
if (tempWarnUpper.value) {
|
||||
series.push({
|
||||
name: '告警上限',
|
||||
data: [],
|
||||
color: '#e098c7',
|
||||
lineType: 'dash',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
chartData.value.forEach((item: any) => {
|
||||
const timeStr = item.time || item.createTime || '';
|
||||
const timeParts = timeStr.split(' ');
|
||||
if (timeParts.length > 1) {
|
||||
const datePart = timeParts[0];
|
||||
const timePart = timeParts[1];
|
||||
|
||||
const dateMatch = datePart.match(/\d{4}-(\d{2})-(\d{2})/);
|
||||
const monthDay = dateMatch ? `${dateMatch[1]}-${dateMatch[2]}` : '';
|
||||
const hourMin = timePart.substring(0, 5);
|
||||
|
||||
const formattedTime = `${monthDay} ${hourMin}`;
|
||||
xAxisData.push(formattedTime);
|
||||
}
|
||||
const value = item[fieldName];
|
||||
seriesData.push(value !== null && value !== undefined ? Number(value) : 0);
|
||||
|
||||
// 填充告警线数据
|
||||
if (dataType.value === 1 && oxyWarnLower.value) {
|
||||
series[0].data.push(oxyWarnLower.value);
|
||||
} else if (dataType.value === 2) {
|
||||
let idx = 0;
|
||||
if (tempWarnLower.value) {
|
||||
series[idx].data.push(tempWarnLower.value);
|
||||
idx++;
|
||||
}
|
||||
if (tempWarnUpper.value) {
|
||||
series[idx].data.push(tempWarnUpper.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 添加主数据系列
|
||||
series.unshift({ name: seriesName, data: seriesData });
|
||||
|
||||
Taro.nextTick(() => {
|
||||
const env = Taro.getEnv();
|
||||
|
||||
if (env === Taro.ENV_TYPE.WEB) {
|
||||
// H5 环境
|
||||
setTimeout(() => {
|
||||
const canvasElement = document.querySelector('#data-query-chart canvas') as HTMLCanvasElement;
|
||||
if (!canvasElement) return;
|
||||
|
||||
const ctx = canvasElement.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
chartInstance = new uCharts({
|
||||
type: 'line',
|
||||
context: ctx,
|
||||
width: cWidth,
|
||||
height: cHeight,
|
||||
categories: xAxisData,
|
||||
series: series,
|
||||
pixelRatio: 1,
|
||||
dataPointShape: false,
|
||||
animation: true,
|
||||
background: '#FFFFFF',
|
||||
color: ['#17B4B2'],
|
||||
padding: [15, 15, 30, 40],
|
||||
enableScroll: false,
|
||||
boundaryGap: 'justify',
|
||||
legend: { show: false },
|
||||
dataLabel: false,
|
||||
xAxis: {
|
||||
disableGrid: true,
|
||||
axisLine: true,
|
||||
type: 'grid',
|
||||
gridType: 'dash',
|
||||
scrollShow: false,
|
||||
labelCount: 8,
|
||||
rotateLabel: true,
|
||||
rotateAngle: 30,
|
||||
},
|
||||
yAxis: {
|
||||
disableGrid: false,
|
||||
gridType: 'dash',
|
||||
tofix: 2,
|
||||
},
|
||||
extra: {
|
||||
tooltip: {
|
||||
showBox: true,
|
||||
showArrow: true,
|
||||
showCategory: true,
|
||||
borderWidth: 0,
|
||||
borderRadius: 0,
|
||||
borderColor: '#000000',
|
||||
borderOpacity: 0.7,
|
||||
bgColor: '#000000',
|
||||
bgOpacity: 0.7,
|
||||
gridType: 'solid',
|
||||
dashLength: 4,
|
||||
gridColor: '#CCCCCC',
|
||||
boxPadding: 3,
|
||||
fontSize: 13,
|
||||
lineHeight: 20,
|
||||
fontColor: '#FFFFFF',
|
||||
legendShow: true,
|
||||
legendShape: 'auto',
|
||||
splitLine: true,
|
||||
labelBgColor: '#FFFFFF',
|
||||
labelBgOpacity: 0.7,
|
||||
labelFontColor: '#666666',
|
||||
},
|
||||
line: { type: 'curve', width: 2, activeType: 'hollow' },
|
||||
},
|
||||
});
|
||||
|
||||
// 获取 canvas 位置
|
||||
const query = Taro.createSelectorQuery();
|
||||
query.select('#data-query-chart').boundingClientRect();
|
||||
query.exec((res) => {
|
||||
if (res.length > 0 && res[0]) {
|
||||
chartTop.value = res[0].top || 0;
|
||||
chartLeft.value = res[0].left || 0;
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
} else {
|
||||
// 小程序环境
|
||||
const query = Taro.createSelectorQuery();
|
||||
query.select('#data-query-chart')
|
||||
.fields({ node: true, size: true })
|
||||
.exec((res) => {
|
||||
if (!res || !res[0] || !res[0].node) return;
|
||||
|
||||
const canvas = res[0].node;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
canvas.width = cWidth * pixelRatio;
|
||||
canvas.height = cHeight * pixelRatio;
|
||||
|
||||
chartInstance = new uCharts({
|
||||
type: 'line',
|
||||
context: ctx,
|
||||
width: cWidth * pixelRatio,
|
||||
height: cHeight * pixelRatio,
|
||||
categories: xAxisData,
|
||||
series: series,
|
||||
pixelRatio: pixelRatio,
|
||||
dataPointShape: false,
|
||||
animation: true,
|
||||
background: '#FFFFFF',
|
||||
color: ['#17B4B2'],
|
||||
padding: [15, 15, 30, 40],
|
||||
enableScroll: false,
|
||||
boundaryGap: 'justify',
|
||||
legend: { show: false },
|
||||
dataLabel: false,
|
||||
xAxis: {
|
||||
disableGrid: true,
|
||||
axisLine: true,
|
||||
type: 'grid',
|
||||
gridType: 'dash',
|
||||
scrollShow: false,
|
||||
labelCount: 6,
|
||||
rotateLabel: true,
|
||||
rotateAngle: 20,
|
||||
marginTop: 5,
|
||||
},
|
||||
yAxis: {
|
||||
disableGrid: false,
|
||||
gridType: 'dash',
|
||||
tofix: 2,
|
||||
},
|
||||
extra: {
|
||||
tooltip: {
|
||||
showBox: true,
|
||||
showArrow: true,
|
||||
showCategory: true,
|
||||
borderWidth: 0,
|
||||
borderRadius: 0,
|
||||
borderColor: '#000000',
|
||||
borderOpacity: 0.7,
|
||||
bgColor: '#000000',
|
||||
bgOpacity: 0.7,
|
||||
gridType: 'solid',
|
||||
dashLength: 4,
|
||||
gridColor: '#CCCCCC',
|
||||
boxPadding: 3,
|
||||
fontSize: 13,
|
||||
lineHeight: 20,
|
||||
fontColor: '#FFFFFF',
|
||||
legendShow: true,
|
||||
legendShape: 'auto',
|
||||
splitLine: true,
|
||||
labelBgColor: '#FFFFFF',
|
||||
labelBgOpacity: 0.7,
|
||||
labelFontColor: '#666666',
|
||||
},
|
||||
line: { type: 'curve', width: 2, activeType: 'hollow' },
|
||||
},
|
||||
});
|
||||
|
||||
// 获取 canvas 位置
|
||||
const query = Taro.createSelectorQuery();
|
||||
query.select('#data-query-chart').boundingClientRect();
|
||||
query.exec((res) => {
|
||||
if (res.length > 0 && res[0]) {
|
||||
chartTop.value = res[0].top || 0;
|
||||
chartLeft.value = res[0].left || 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 触摸结束事件 - 显示提示框
|
||||
function touchEnd(e: any) {
|
||||
if (!chartInstance) return;
|
||||
|
||||
const x = e.mpEvent.changedTouches[0].clientX;
|
||||
const y = e.mpEvent.changedTouches[0].clientY;
|
||||
const tmpe = { x: x - chartLeft.value, y: y - chartTop.value };
|
||||
e.changedTouches = [tmpe];
|
||||
|
||||
if (e.touches.length == 0) {
|
||||
chartInstance.touchLegend(e);
|
||||
chartInstance.showToolTip(e, {
|
||||
formatter: (item: any) => {
|
||||
return item.name + ':' + item.data;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 触摸开始事件
|
||||
function touchStart(e: any) {
|
||||
if (!chartInstance) return;
|
||||
|
||||
const x = e.mpEvent.changedTouches[0].clientX;
|
||||
const y = e.mpEvent.changedTouches[0].clientY;
|
||||
const tmpe = { x: x - chartLeft.value, y: y - chartTop.value };
|
||||
e.changedTouches = [tmpe];
|
||||
chartInstance.scrollStart(e);
|
||||
}
|
||||
|
||||
// 触摸移动事件
|
||||
function touchMove(e: any) {
|
||||
if (!chartInstance) return;
|
||||
|
||||
const x = e.mpEvent.changedTouches[0].clientX;
|
||||
const y = e.mpEvent.changedTouches[0].clientY;
|
||||
const tmpe = { x: x - chartLeft.value, y: y - chartTop.value };
|
||||
e.changedTouches = [tmpe];
|
||||
chartInstance.scroll(e);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.data-query-page {
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 44px;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.back-btn .icon {
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-right: 44px;
|
||||
}
|
||||
|
||||
.query-section {
|
||||
background: #fff;
|
||||
padding: 6px 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.query-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.query-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.query-label {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.query-value {
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
padding: 4px 12px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
min-width: 150px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.query-btn {
|
||||
height: 28px;
|
||||
padding: 0 20px;
|
||||
background: linear-gradient(135deg, #09b8c2 0%, #06a0a9 100%);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
background: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chart-canvas {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.empty-data {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 日期选择器整体向下移动 - 避免与小程序关闭按钮重叠 */
|
||||
:deep(.nut-picker) {
|
||||
margin-top: 30px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -237,7 +237,21 @@ function save() {
|
||||
PondAdd(requestData).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
saveRes.value = true;
|
||||
} else {
|
||||
// 显示错误提示
|
||||
Taro.showToast({
|
||||
title: res.msg || '添加失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
// 处理网络错误等异常情况
|
||||
Taro.showToast({
|
||||
title: '网络错误,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}).finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
|
||||
@@ -206,10 +206,25 @@ function save() {
|
||||
// }
|
||||
addTimeCtrl(data)
|
||||
.then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
saveRes.value = true;
|
||||
} else {
|
||||
// 显示错误提示
|
||||
Taro.showToast({
|
||||
title: res.msg || '添加失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// 处理网络错误等异常情况
|
||||
Taro.showToast({
|
||||
title: '网络错误,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
|
||||
274
src/home/ctr.vue
274
src/home/ctr.vue
@@ -5,7 +5,8 @@
|
||||
<nut-config-provider :theme-vars="themeVars">
|
||||
<view class="body">
|
||||
<nut-row>
|
||||
<nut-col :span="24">
|
||||
<!-- 设备信息区域 -->
|
||||
<nut-col :span="24" v-if="!section || section === 'deviceInfo'">
|
||||
<nut-cell class="ctr_body">
|
||||
<nut-row>
|
||||
<nut-col :span="24" class="title"> 设备信息 </nut-col>
|
||||
@@ -68,10 +69,41 @@
|
||||
</nut-cell>
|
||||
</nut-cell-group>
|
||||
</nut-col>
|
||||
<!-- 盐度设置和设备校准 -->
|
||||
<nut-col :span="24">
|
||||
<nut-cell-group>
|
||||
<nut-cell title="盐度设置" is-link @click="setSalFunc">
|
||||
<template #desc>
|
||||
<text class="desc"
|
||||
>{{ deviceInfoRes.salinityCompensation }}‰</text
|
||||
>
|
||||
</template>
|
||||
</nut-cell>
|
||||
<nut-cell title="设备校准" is-link @click="toCalibration" />
|
||||
</nut-cell-group>
|
||||
</nut-col>
|
||||
<!-- 将解除绑定按钮移到设备信息区域内 -->
|
||||
<nut-col :span="24" :style="{ marginTop: '20rpx' }">
|
||||
<nut-button
|
||||
block
|
||||
shape="square"
|
||||
size="large"
|
||||
color="#E22323"
|
||||
:style="{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '14px !important',
|
||||
borderRadius: '10px',
|
||||
}"
|
||||
@click="unbind"
|
||||
v-if="isMainAccount"
|
||||
>解除绑定</nut-button
|
||||
>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<!-- 开关配置区域 -->
|
||||
<nut-col :span="24" v-if="!section && !hideSwitch">
|
||||
<nut-cell class="ctr_body">
|
||||
<nut-row>
|
||||
<!-- <nut-col :span="24" class="view_f_between">
|
||||
@@ -123,7 +155,8 @@
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<!-- 溶解氧配置区域(报警设置) -->
|
||||
<nut-col :span="24" v-if="!section || section === 'alarmSettings'">
|
||||
<nut-cell class="ctr_body">
|
||||
<nut-row>
|
||||
<nut-col :span="24" class="view_f_between">
|
||||
@@ -314,128 +347,12 @@
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
<nut-cell>
|
||||
<nut-row>
|
||||
<nut-col
|
||||
:span="24"
|
||||
:style="{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}"
|
||||
>
|
||||
<view class="title">联动控制</view>
|
||||
<view class="ils" @click="openLink">联动设置</view>
|
||||
</nut-col>
|
||||
<nut-col
|
||||
:span="24"
|
||||
v-if="deviceInfoRes.listLinkedCtr.length > 0"
|
||||
>
|
||||
<!-- 绘制表格 -->
|
||||
<view class="m_t_15">
|
||||
<view class="linked-table">
|
||||
<!-- 表头 -->
|
||||
<view class="table-row table-header">
|
||||
<view class="table-cell"></view>
|
||||
<view
|
||||
class="table-cell"
|
||||
v-for="(item, index) in deviceInfoRes.listLinkedCtr"
|
||||
:key="item.id"
|
||||
>
|
||||
联动{{ index + 1 }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 上限行 -->
|
||||
<view class="table-row">
|
||||
<view class="table-cell table-label">上限</view>
|
||||
<view
|
||||
class="table-cell table-value"
|
||||
v-for="item in deviceInfoRes.listLinkedCtr"
|
||||
:key="'up_' + item.id"
|
||||
>
|
||||
{{ item.oxyUpperOpen ? item.oxyUpperValue + 'Mg/L' : '-' }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 下限行 -->
|
||||
<view class="table-row">
|
||||
<view class="table-cell table-label">下限</view>
|
||||
<view
|
||||
class="table-cell table-value"
|
||||
v-for="item in deviceInfoRes.listLinkedCtr"
|
||||
:key="'low_' + item.id"
|
||||
>
|
||||
{{ item.oxyLowerOpen ? item.oxyLowerValue + 'Mg/L' : '-' }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 开关行 -->
|
||||
<view class="table-row">
|
||||
<view class="table-cell table-label">开关</view>
|
||||
<view
|
||||
class="table-cell table-switch"
|
||||
v-for="item in deviceInfoRes.listLinkedCtr"
|
||||
:key="'sw_' + item.id"
|
||||
>
|
||||
<view class="switch-names">
|
||||
<view
|
||||
class="switch-name"
|
||||
v-for="(sw, idx) in item.listSwitch"
|
||||
:key="sw.id"
|
||||
>
|
||||
{{ sw.switchName }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
<nut-cell title="盐度设置" is-link @click="setSalFunc">
|
||||
<template #desc>
|
||||
<text class="desc"
|
||||
>{{ deviceInfoRes.salinityCompensation }}‰</text
|
||||
>
|
||||
</template>
|
||||
</nut-cell>
|
||||
<nut-cell title="设备校准" is-link @click="toCalibration" />
|
||||
<!-- 联动控制已隐藏 -->
|
||||
</nut-cell-group>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
</nut-col>
|
||||
<!-- <nut-col :span="24" :style="{ marginBottom: '20rpx' }">
|
||||
<nut-button
|
||||
block
|
||||
shape="square"
|
||||
size="large"
|
||||
color="#E22323"
|
||||
plain
|
||||
:style="{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '14px !important',
|
||||
borderRadius: '10px',
|
||||
}"
|
||||
@click="removeDev"
|
||||
>移除设备</nut-button
|
||||
>
|
||||
</nut-col> -->
|
||||
<nut-col :span="24">
|
||||
<nut-button
|
||||
block
|
||||
shape="square"
|
||||
size="large"
|
||||
color="#E22323"
|
||||
:style="{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '14px !important',
|
||||
borderRadius: '10px',
|
||||
}"
|
||||
@click="unbind"
|
||||
v-if="Uid == rootuserid"
|
||||
>解除绑定</nut-button
|
||||
>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</view>
|
||||
</nut-config-provider>
|
||||
@@ -838,6 +755,8 @@ const instance = Taro.getCurrentInstance();
|
||||
const id = instance.router.params.id;
|
||||
const name = instance.router.params.name;
|
||||
const page = instance.router.params.page;
|
||||
const section = instance.router.params.section; // 获取区域参数
|
||||
const hideSwitch = instance.router.params.hideSwitch === '1'; // 是否隐藏开关配置
|
||||
const r_v = `${imgUrl}r_v.png`;
|
||||
// const id = 5
|
||||
// const name = undefined
|
||||
@@ -920,6 +839,17 @@ const vTypeList = [
|
||||
const voltageType = ref<number>(1);
|
||||
const Uid = Taro.getStorageSync("UserId");
|
||||
const rootuserid = ref(store.getRootUserId);
|
||||
// 判断是否为主账号:当前选中的是登录账号,且登录账号是主账号
|
||||
const isMainAccount = computed(() => {
|
||||
// 当前选中的必须是登录账号
|
||||
if (Uid !== rootuserid.value) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否有父账号(如果有父账号,说明是子账号)
|
||||
// 这里需要从 store 或 API 获取父账号列表,但为了简化,我们假设:
|
||||
// 只有当前选中的是登录账号时才有解绑权限
|
||||
return true;
|
||||
});
|
||||
/**--------------method start------------------- */
|
||||
Taro.useDidShow(() => {
|
||||
// 默认
|
||||
@@ -1025,8 +955,16 @@ function confirm({ selectedValue, selectedOptions }) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[绑定塘口] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
})
|
||||
.finally(() => {
|
||||
showPond.value = false;
|
||||
});
|
||||
@@ -1048,7 +986,16 @@ function changeO2(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[溶解氧告警开关] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1064,7 +1011,16 @@ function changeTem(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[温度告警开关] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1090,7 +1046,14 @@ function setOxyEvent() {
|
||||
state.msg = "设置成功";
|
||||
deviceInfoRes.value.oxyWarnLower = oxy.value;
|
||||
openSetOxy.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[溶解氧阈值设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
const setNameEventD = debounce(setNameEvent, 300);
|
||||
@@ -1105,7 +1068,14 @@ function setNameEvent() {
|
||||
state.msg = "设置成功";
|
||||
deviceInfoRes.value.deviceName = deviceName.value;
|
||||
openSetName.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[设备名称设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
function setTemp() {
|
||||
@@ -1127,7 +1097,14 @@ function setTempEvent() {
|
||||
deviceInfoRes.value.tempWarnUpper = tempUp.value;
|
||||
deviceInfoRes.value.tempWarnLower = tempLower.value;
|
||||
openSetTemp.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[温度阈值设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1165,7 +1142,14 @@ function setNameSwitchEvent() {
|
||||
r.switchName = data.newName;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[开关名称设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
function cancelSwitchName() {
|
||||
@@ -1208,7 +1192,14 @@ function setSalinity() {
|
||||
state.msg = "设置成功";
|
||||
deviceInfoRes.value.salinityCompensation = salinity.value;
|
||||
openSalinity.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[盐度设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
//跳转校准页面
|
||||
@@ -1251,7 +1242,16 @@ function changeTemDis(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[温度免打扰] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1271,7 +1271,16 @@ function changeIsOxygenUsed(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[溶解氧机开关] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1287,8 +1296,15 @@ function setTypeEvent() {
|
||||
deviceInfoRes.value.inputVoltage = voltageType.value;
|
||||
openSetType.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
voltageType.value = deviceInfoRes.value.inputVoltage;
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[输入端接线方式] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
voltageType.value = deviceInfoRes.value.inputVoltage;
|
||||
});
|
||||
}
|
||||
function changeV(value, event) {
|
||||
@@ -1301,7 +1317,16 @@ function changeV(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[电压告警开关] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1319,7 +1344,16 @@ function changeOxyDis(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[溶解氧免打扰] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,6 +480,18 @@ const pond404 = `${imgUrl}zanwurenwu.png`;
|
||||
const instance = Taro.getCurrentInstance();
|
||||
const id = instance.router.params.id;
|
||||
const pondId = instance.router.params.pondId;
|
||||
|
||||
// 调试日志:检查参数
|
||||
console.log('[linkControl] 路由参数:', { id, pondId });
|
||||
|
||||
if (!id) {
|
||||
console.error('[linkControl] 警告: 设备ID为空');
|
||||
}
|
||||
|
||||
if (!pondId) {
|
||||
console.error('[linkControl] 警告: 塘口ID为空');
|
||||
}
|
||||
|
||||
// const pondId = 12;
|
||||
const themeVars = ref({
|
||||
cellBorderRadius: "4px",
|
||||
@@ -564,6 +576,15 @@ function getLinksList() {
|
||||
}
|
||||
// 开关列表
|
||||
function getSwitchList(type = undefined,id=undefined) {
|
||||
console.log('[getSwitchList] 查询参数:', { pondId, type, id });
|
||||
|
||||
if (!pondId) {
|
||||
console.error('[getSwitchList] 错误: pondId为空,无法查询开关列表');
|
||||
state.show = true;
|
||||
state.msg = '塑口信息不存在,请返回重试';
|
||||
return;
|
||||
}
|
||||
|
||||
pondSwitchList({ id: pondId }).then((res) => {
|
||||
if (res.code == 200) {
|
||||
if (res.data.length > 0) {
|
||||
@@ -720,8 +741,16 @@ function addHandler() {
|
||||
state.msg = "编辑成功";
|
||||
getLinksList();
|
||||
return;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "编辑失败";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[addHandler] 编辑失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,编辑失败";
|
||||
})
|
||||
.finally(() => {
|
||||
oncancelUp();
|
||||
});
|
||||
@@ -733,8 +762,16 @@ function addHandler() {
|
||||
state.msg = "添加成功";
|
||||
getLinksList();
|
||||
return;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "添加失败";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[addHandler] 添加失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,添加失败";
|
||||
})
|
||||
.finally(() => {
|
||||
oncancel();
|
||||
});
|
||||
@@ -976,8 +1013,16 @@ function upHandler() {
|
||||
state.msg = "编辑成功";
|
||||
getLinksList();
|
||||
return;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "编辑失败";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[upHandler] 编辑失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,编辑失败";
|
||||
})
|
||||
.finally(() => {
|
||||
oncancelUp();
|
||||
openOxyD.value = false;
|
||||
|
||||
1563
src/home/solar.vue
Normal file
1563
src/home/solar.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -126,7 +126,7 @@
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
</nut-col> -->
|
||||
<nut-col :span="24">
|
||||
<!-- <nut-col :span="24">
|
||||
<nut-button
|
||||
block
|
||||
shape="square"
|
||||
@@ -141,7 +141,7 @@
|
||||
@click="toTiming"
|
||||
>定时</nut-button
|
||||
>
|
||||
</nut-col>
|
||||
</nut-col> -->
|
||||
</nut-row>
|
||||
</view>
|
||||
</nut-config-provider>
|
||||
@@ -433,8 +433,16 @@ function confirm({ selectedValue, selectedOptions }) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[绑定塘口] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
})
|
||||
.finally(() => {
|
||||
showPond.value = false;
|
||||
});
|
||||
@@ -460,7 +468,14 @@ function setVEvent() {
|
||||
state.msg = "设置成功";
|
||||
switchInfoRes.value.rateElectricValue = V.value;
|
||||
openSetV.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[额定电流设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
// 接电配置
|
||||
@@ -483,7 +498,14 @@ function setTypeEvent() {
|
||||
state.msg = "设置成功";
|
||||
switchInfoRes.value.connectVoltageType = voltageType.value;
|
||||
openSetType.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[接线方式设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
// 切换图表日期
|
||||
@@ -513,7 +535,18 @@ function changeV(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
// 失败时恢复开关状态
|
||||
getSwitchInfo();
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[电压告警开关] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
// 失败时恢复开关状态
|
||||
getSwitchInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -527,7 +560,18 @@ function changeE(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
// 失败时恢复开关状态
|
||||
getSwitchInfo();
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[电流告警开关] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
// 失败时恢复开关状态
|
||||
getSwitchInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,15 @@
|
||||
<nut-col :span="4">
|
||||
<nut-button type="danger" size="mini" @click="remove(item.id)">删除</nut-button>
|
||||
</nut-col>
|
||||
<nut-col :span="12">
|
||||
<nut-col :span="9">
|
||||
<view class="font_36 c_222"
|
||||
>{{ item.openTime }}~{{ item.closeTime }}</view
|
||||
>
|
||||
</nut-col>
|
||||
<nut-col :span="8" class="view_f font_36 c_222">
|
||||
<view :style="{ marginRight: '10px' }">{{ item.loopType==1 ? "一次" : "每天" }}</view>
|
||||
<nut-col :span="5" class="font_36 c_222">
|
||||
<view>{{ item.loopType==1 ? "一次" : "每天" }}</view>
|
||||
</nut-col>
|
||||
<nut-col :span="6" :style="{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }">
|
||||
<nut-switch
|
||||
v-model="item.isOpen"
|
||||
active-color="#04D98A"
|
||||
@@ -96,13 +98,6 @@ const themeVars = ref({
|
||||
cellBorderRadius: "4px",
|
||||
cellBoxShadow: "0px",
|
||||
cellPadding: "26rpx 0px",
|
||||
SwitchWidth: "112rpx",
|
||||
SwitchHeight: "56rpx",
|
||||
SwitchLineHeight: "56rpx",
|
||||
SwitchInsideHeight: "40rpx",
|
||||
SwitchInsideWidth: "40rpx",
|
||||
SwitchInsideOpenTransform: "translateX(155%)",
|
||||
SwitchInsideCloseTransform: "translateX(20%)",
|
||||
});
|
||||
const themeVars2 = ref({
|
||||
cellBoxShadow: "0px 0px 0px 0px",
|
||||
@@ -131,13 +126,14 @@ Taro.useDidShow(() => {
|
||||
// 查询列表
|
||||
function getTimingList() {
|
||||
timeCtrlList({ id }).then((res) => {
|
||||
if (res.statusCode == 200) {
|
||||
res.data.forEach((item) => {
|
||||
const fmType = "hh:mm";
|
||||
item.openTime = formatDateString(item.openTime, fmType);
|
||||
item.closeTime = formatDateString(item.closeTime, fmType);
|
||||
});
|
||||
timList.value = res.data || [];
|
||||
if (res.code == 200) {
|
||||
// 使用 map 创建新数组,确保 Vue 响应式更新
|
||||
timList.value = res.data.map((item) => ({
|
||||
...item,
|
||||
isOpen: item.isOpen === 1, // 将 0/1 转换为布尔值
|
||||
openTime: item.openTime ? item.openTime.substring(0, 5) : '',
|
||||
closeTime: item.closeTime ? item.closeTime.substring(0, 5) : '',
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -148,15 +144,15 @@ function addTime() {
|
||||
});
|
||||
}
|
||||
/** 删除 */
|
||||
function remove(id) {
|
||||
function remove(timeId) {
|
||||
// 确定提示框
|
||||
Taro.showModal({
|
||||
title: "提示",
|
||||
content: `确认删除该定时信息?`,
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
delTimeCtrl({ id }).then((res) => {
|
||||
if (res.statusCode == 200) {
|
||||
delTimeCtrl({ id: timeId }).then((res) => {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "删除成功";
|
||||
getTimingList();
|
||||
@@ -172,16 +168,23 @@ function setOpen({ value, event }, item: any) {
|
||||
if (event) {
|
||||
const data = {
|
||||
id: item.id,
|
||||
isOpen: item.isOpen,
|
||||
isOpen: item.isOpen ? 1 : 0, // 布尔转数字
|
||||
};
|
||||
setTimeCtrlOpen(data).then(res=>{
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
}else{
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
getTimingList();
|
||||
}
|
||||
})
|
||||
}).catch((error) => {
|
||||
console.error('[定时开关设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
getTimingList();
|
||||
});
|
||||
}
|
||||
}
|
||||
/** method end--------------------- */
|
||||
|
||||
@@ -370,8 +370,19 @@ function save() {
|
||||
url: "/pages/main/home",
|
||||
});
|
||||
}, 1500);
|
||||
} else {
|
||||
// 显示错误提示
|
||||
state.show = true;
|
||||
state.msg = res.msg || "保存失败,请重试";
|
||||
state.type = "fail";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// 处理网络错误等异常情况
|
||||
state.show = true;
|
||||
state.msg = "网络错误,请重试";
|
||||
state.type = "fail";
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
|
||||
251
src/home/wqm.vue
251
src/home/wqm.vue
@@ -5,7 +5,8 @@
|
||||
<nut-config-provider :theme-vars="themeVars">
|
||||
<view class="body">
|
||||
<nut-row>
|
||||
<nut-col :span="24">
|
||||
<!-- 设备信息区域 -->
|
||||
<nut-col :span="24" v-if="!section || section === 'deviceInfo'">
|
||||
<nut-cell class="wqm_body">
|
||||
<nut-row>
|
||||
<nut-col :span="24" class="title"> 设备信息 </nut-col>
|
||||
@@ -63,10 +64,46 @@
|
||||
</nut-cell>
|
||||
</nut-cell-group>
|
||||
</nut-col>
|
||||
<!-- 盐度设置和设备校准 -->
|
||||
<nut-col :span="24">
|
||||
<nut-cell-group>
|
||||
<nut-cell title="盐度设置" is-link @click="setSalFunc">
|
||||
<template #desc>
|
||||
<text class="desc"
|
||||
>{{ deviceInfoRes.salinityCompensation }}‰</text
|
||||
>
|
||||
</template>
|
||||
</nut-cell>
|
||||
<nut-cell
|
||||
title="设备校准"
|
||||
is-link
|
||||
@click="toCalibration"
|
||||
/>
|
||||
</nut-cell-group>
|
||||
</nut-col>
|
||||
<!-- 将解除绑定按钮移到设备信息区域内 -->
|
||||
<nut-col :span="24" :style="{ marginTop: '20rpx' }">
|
||||
<nut-button
|
||||
block
|
||||
shape="square"
|
||||
size="large"
|
||||
color="#E22323"
|
||||
:style="{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '14px !important',
|
||||
borderRadius: '10px',
|
||||
}"
|
||||
@click="unbind"
|
||||
:loading="b_isLoading"
|
||||
v-if="isMainAccount"
|
||||
>解除绑定</nut-button
|
||||
>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<!-- 溶解氧配置区域 -->
|
||||
<nut-col :span="24" v-if="!section || section === 'alarmSettings'">
|
||||
<nut-cell class="wqm_body">
|
||||
<nut-row>
|
||||
<nut-col :span="24" class="title"> 溶解氧配置 </nut-col>
|
||||
@@ -240,136 +277,12 @@
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
<nut-cell>
|
||||
<nut-row>
|
||||
<nut-col
|
||||
:span="24"
|
||||
:style="{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}"
|
||||
>
|
||||
<view class="title">联动控制</view>
|
||||
<view class="ils" @click="openLink"
|
||||
>联动设置</view
|
||||
>
|
||||
</nut-col>
|
||||
<nut-col
|
||||
:span="24"
|
||||
v-if="deviceInfoRes.listLinkedCtr.length > 0"
|
||||
>
|
||||
<!-- 绘制表格 -->
|
||||
<view class="m_t_15">
|
||||
<view class="linked-table">
|
||||
<!-- 表头 -->
|
||||
<view class="table-row table-header">
|
||||
<view class="table-cell"></view>
|
||||
<view
|
||||
class="table-cell"
|
||||
v-for="(item, index) in deviceInfoRes.listLinkedCtr"
|
||||
:key="item.id"
|
||||
>
|
||||
联动{{ index + 1 }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 上限行 -->
|
||||
<view class="table-row">
|
||||
<view class="table-cell table-label">上限</view>
|
||||
<view
|
||||
class="table-cell table-value"
|
||||
v-for="item in deviceInfoRes.listLinkedCtr"
|
||||
:key="'up_' + item.id"
|
||||
>
|
||||
{{ item.oxyUpperOpen ? item.oxyUpperValue + 'Mg/L' : '-' }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 下限行 -->
|
||||
<view class="table-row">
|
||||
<view class="table-cell table-label">下限</view>
|
||||
<view
|
||||
class="table-cell table-value"
|
||||
v-for="item in deviceInfoRes.listLinkedCtr"
|
||||
:key="'low_' + item.id"
|
||||
>
|
||||
{{ item.oxyLowerOpen ? item.oxyLowerValue + 'Mg/L' : '-' }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 开关行 -->
|
||||
<view class="table-row">
|
||||
<view class="table-cell table-label">开关</view>
|
||||
<view
|
||||
class="table-cell table-switch"
|
||||
v-for="item in deviceInfoRes.listLinkedCtr"
|
||||
:key="'sw_' + item.id"
|
||||
>
|
||||
<view class="switch-names">
|
||||
<view
|
||||
class="switch-name"
|
||||
v-for="(sw, idx) in item.listSwitch"
|
||||
:key="sw.id"
|
||||
>
|
||||
{{ sw.switchName }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
<nut-cell title="盐度设置" is-link @click="setSalFunc">
|
||||
<template #desc>
|
||||
<text class="desc"
|
||||
>{{ deviceInfoRes.salinityCompensation }}‰</text
|
||||
>
|
||||
</template>
|
||||
</nut-cell>
|
||||
<nut-cell
|
||||
title="设备校准"
|
||||
is-link
|
||||
@click="toCalibration"
|
||||
/>
|
||||
<!-- 联动控制已隐藏 -->
|
||||
</nut-cell-group>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
</nut-col>
|
||||
<!-- <nut-col :span="24" :style="{ marginBottom: '20rpx' }">
|
||||
<nut-button
|
||||
block
|
||||
shape="square"
|
||||
size="large"
|
||||
color="#E22323"
|
||||
plain
|
||||
:style="{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '14px !important',
|
||||
borderRadius: '10px',
|
||||
}"
|
||||
@click="removeDev"
|
||||
:loading="r_isLoading"
|
||||
>移除设备</nut-button
|
||||
>
|
||||
</nut-col> -->
|
||||
<nut-col :span="24">
|
||||
<nut-button
|
||||
block
|
||||
shape="square"
|
||||
size="large"
|
||||
color="#E22323"
|
||||
:style="{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '14px !important',
|
||||
borderRadius: '10px',
|
||||
}"
|
||||
@click="unbind"
|
||||
:loading="b_isLoading"
|
||||
v-if="Uid==rootuserid"
|
||||
>解除绑定</nut-button
|
||||
>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</view>
|
||||
</nut-config-provider>
|
||||
@@ -687,6 +600,7 @@ const instance = Taro.getCurrentInstance();
|
||||
const id = instance.router.params.id;
|
||||
const name = instance.router.params.name;
|
||||
const page = instance.router.params.page;
|
||||
const section = instance.router.params.section; // 获取区域参数
|
||||
// const name = undefined
|
||||
Taro.setNavigationBarTitle({
|
||||
title: "水质检测仪设置",
|
||||
@@ -760,6 +674,17 @@ const r_isLoading = ref(false)
|
||||
const b_isLoading = ref(false)
|
||||
const Uid = Taro.getStorageSync("UserId")
|
||||
const rootuserid = ref(store.getRootUserId);
|
||||
// 判断是否为主账号:当前选中的是登录账号,且登录账号是主账号
|
||||
const isMainAccount = computed(() => {
|
||||
// 当前选中的必须是登录账号
|
||||
if (Uid !== rootuserid.value) {
|
||||
return false;
|
||||
}
|
||||
// 检查是否有父账号(如果有父账号,说明是子账号)
|
||||
// 这里需要从 store 或 API 获取父账号列表,但为了简化,我们假设:
|
||||
// 只有当前选中的是登录账号时才有解绑权限
|
||||
return true;
|
||||
});
|
||||
/**--------------method start------------------- */
|
||||
Taro.useDidShow(() => {
|
||||
// 默认
|
||||
@@ -871,8 +796,16 @@ console.log(selectedValue)
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[绑定塘口] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
})
|
||||
.finally(() => {
|
||||
showPond.value = false;
|
||||
});
|
||||
@@ -896,7 +829,16 @@ function changeO2(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[溶解氧告警开关] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -914,7 +856,16 @@ function changeTem(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[温度告警开关] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -951,7 +902,14 @@ function setOxyEvent() {
|
||||
state.msg = "设置成功";
|
||||
deviceInfoRes.value.oxyWarnLower = oxy.value;
|
||||
openSetOxy.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[溶解氧阈值设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
const setNameEventD = debounce(setNameEvent, 300);
|
||||
@@ -967,7 +925,14 @@ function setNameEvent() {
|
||||
openSetName.value = false;
|
||||
// 重新加载设备信息
|
||||
getDevInfo();
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[设备名称设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
function setTemp() {
|
||||
@@ -1006,7 +971,14 @@ function setTempEvent() {
|
||||
deviceInfoRes.value.tempWarnUpper = tempUp.value;
|
||||
deviceInfoRes.value.tempWarnLower = tempLower.value;
|
||||
openSetTemp.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[温度阈值设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
// 溶解氧告警
|
||||
@@ -1045,7 +1017,14 @@ function setSalinity() {
|
||||
state.msg = "设置成功";
|
||||
deviceInfoRes.value.salinityCompensation = salinity.value;
|
||||
openSalinity.value = false;
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[盐度设置] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
});
|
||||
}
|
||||
//跳转校准页面
|
||||
@@ -1067,7 +1046,16 @@ function changeOxyDis(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[溶解氧免打扰] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1086,7 +1074,16 @@ function changeTemDis(value, event) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "设置成功";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = res.msg || "设置失败";
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('[温度免打扰] 失败:', error);
|
||||
state.show = true;
|
||||
state.msg = "网络错误,设置失败";
|
||||
}).finally(() => {
|
||||
getDevInfo();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,8 +490,19 @@ function getCheckDevice() {
|
||||
state.show = true;
|
||||
state.msg = "设备异常";
|
||||
}
|
||||
} else {
|
||||
// 显示错误提示
|
||||
state.show = true;
|
||||
state.msg = res.msg || "检查设备失败,请重试";
|
||||
state.type = "fail";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// 处理网络错误等异常情况
|
||||
state.show = true;
|
||||
state.msg = "网络错误,请重试";
|
||||
state.type = "fail";
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
@@ -533,23 +544,34 @@ function next() {
|
||||
state.msg = "请选择放置的设备";
|
||||
return;
|
||||
}
|
||||
console.log('pondId原始值:', params.pondId[0], '类型:', typeof params.pondId[0]);
|
||||
// 发起添加设备请求
|
||||
const data = {
|
||||
serialNum: params.devNum,
|
||||
pondId: params.pondId[0],
|
||||
pondId: String(params.pondId[0]), // 转为字符串保持精度
|
||||
salinityCompensation: waterType.value == 1 ? 0 : Number(salt.value),
|
||||
oxyWarnLower: Number(alarm.value),
|
||||
inputVoltage: Number(inputVoltage.value),
|
||||
listPutPondPartId: listPutPondPartId.value,
|
||||
isOxygenUsed:isHave.value==1?true:false
|
||||
};
|
||||
console.log('添加设备数据', data);
|
||||
console.log('添加设备数据', data, 'pondId类型:', typeof data.pondId);
|
||||
addDeviceController(data).then((res) => {
|
||||
if (res.code == 200) {
|
||||
Taro.redirectTo({
|
||||
url: "/my/addDevSuccess?name=添加测控一体机&page=" + page,
|
||||
});
|
||||
} else {
|
||||
// 显示错误提示
|
||||
state.show = true;
|
||||
state.msg = res.msg || "添加失败,请重试";
|
||||
state.type = "fail";
|
||||
}
|
||||
}).catch((error) => {
|
||||
// 处理网络错误等异常情况
|
||||
state.show = true;
|
||||
state.msg = "网络错误,请重试";
|
||||
state.type = "fail";
|
||||
});
|
||||
} else {
|
||||
if (num != 1 && status.value == 1) {
|
||||
|
||||
@@ -370,8 +370,19 @@ function getCheckDevice() {
|
||||
state.show = true;
|
||||
state.msg = "设备异常";
|
||||
}
|
||||
} else {
|
||||
// 显示错误提示
|
||||
state.show = true;
|
||||
state.msg = res.msg || "检查设备失败,请重试";
|
||||
state.type = "fail";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// 处理网络错误等异常情况
|
||||
state.show = true;
|
||||
state.msg = "网络错误,请重试";
|
||||
state.type = "fail";
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
@@ -412,7 +423,7 @@ function next() {
|
||||
// 发起添加设备请求
|
||||
const data = {
|
||||
serialNum: Number(params.devNum),
|
||||
pondId: Number(params.pondId[0]),
|
||||
pondId: String(params.pondId[0]), // 转为字符串保持精度
|
||||
salinityCompensation: waterType.value == 1 ? 0 : Number(salt.value),
|
||||
oxyWarnLower: Number(alarm.value),
|
||||
};
|
||||
@@ -423,8 +434,19 @@ function next() {
|
||||
Taro.redirectTo({
|
||||
url: "/my/addDevSuccess?name=添加水质检测仪&page=" + page,
|
||||
});
|
||||
} else {
|
||||
// 显示错误提示
|
||||
state.show = true;
|
||||
state.msg = res.msg || "添加失败,请重试";
|
||||
state.type = "fail";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// 处理网络错误等异常情况
|
||||
state.show = true;
|
||||
state.msg = "网络错误,请重试";
|
||||
state.type = "fail";
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
|
||||
@@ -27,6 +27,15 @@
|
||||
<IconFont :name="check_a" />
|
||||
</template>
|
||||
</nut-radio>
|
||||
<nut-radio label="3" icon-size="25">
|
||||
太阳能网控
|
||||
<template #icon>
|
||||
<IconFont :name="check" />
|
||||
</template>
|
||||
<template #checkedIcon>
|
||||
<IconFont :name="check_a" />
|
||||
</template>
|
||||
</nut-radio>
|
||||
</nut-radio-group>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
@@ -108,7 +117,9 @@ const isLoading = ref(false)
|
||||
/**---------------method start-------------------- */
|
||||
Taro.useDidShow(() => {
|
||||
if (pondId) {
|
||||
params.pondId = [pondId];
|
||||
// 将 pondId 转为字符串保持精度
|
||||
params.pondId = [String(pondId)];
|
||||
console.log('addDevice 接收到的 pondId:', pondId, '转换后:', params.pondId);
|
||||
}
|
||||
});
|
||||
// 进入不同设备添加页面
|
||||
@@ -123,16 +134,29 @@ function submit() {
|
||||
state.msg = "请输入设备号";
|
||||
return;
|
||||
}
|
||||
|
||||
// 传参前再次确保 pondId 为字符串
|
||||
const paramsToSend = {
|
||||
...params,
|
||||
pondId: params.pondId.map(id => String(id))
|
||||
};
|
||||
console.log('准备传递的参数:', paramsToSend);
|
||||
|
||||
if (params.devType == 1) {
|
||||
isLoading.value = false
|
||||
Taro.navigateTo({
|
||||
url: "/my/addDetector?params=" + JSON.stringify(params) + "&page=" + page,
|
||||
url: "/my/addDetector?params=" + encodeURIComponent(JSON.stringify(paramsToSend)) + "&page=" + page,
|
||||
});
|
||||
} else if (params.devType == 3) {
|
||||
isLoading.value = false
|
||||
Taro.navigateTo({
|
||||
url: "/my/addSolarDetector?params=" + encodeURIComponent(JSON.stringify(paramsToSend)) + "&page=" + page,
|
||||
});
|
||||
} else {
|
||||
isLoading.value = false
|
||||
Taro.navigateTo({
|
||||
url:
|
||||
"/my/addController?params=" + JSON.stringify(params) + "&page=" + page,
|
||||
"/my/addController?params=" + encodeURIComponent(JSON.stringify(paramsToSend)) + "&page=" + page,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
685
src/my/addSolarDetector.vue
Normal file
685
src/my/addSolarDetector.vue
Normal file
@@ -0,0 +1,685 @@
|
||||
<template>
|
||||
<view class="detector_home">
|
||||
<view class="body">
|
||||
<nut-cell>
|
||||
<nut-row>
|
||||
<nut-col :span="24">
|
||||
<nut-steps :current="current">
|
||||
<nut-step title="第一步" />
|
||||
<nut-step title="第二步" />
|
||||
<nut-step title="第三步" />
|
||||
<nut-step title="第四步" />
|
||||
</nut-steps>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
<nut-cell>
|
||||
<nut-row v-if="current === 1">
|
||||
<nut-col :span="24">
|
||||
<nut-col :span="2"
|
||||
><img
|
||||
:src="dc_1"
|
||||
:style="{
|
||||
width: '48rpx',
|
||||
height: '48rpx',
|
||||
marginRight: '20rpx',
|
||||
}"
|
||||
/></nut-col>
|
||||
<nut-col :span="22" class="font_36 f_weight c_222"
|
||||
>检查设备</nut-col
|
||||
>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-col :span="2"> </nut-col>
|
||||
<nut-col :span="22" class="font_32 c_666"
|
||||
>请检查设备是否上电,网络指示灯处于常亮状态。</nut-col
|
||||
>
|
||||
</nut-col>
|
||||
<nut-col :span="24" class="m_t_20">
|
||||
<nut-col :span="2"
|
||||
><img
|
||||
:src="dc_2"
|
||||
:style="{
|
||||
width: '48rpx',
|
||||
height: '48rpx',
|
||||
marginRight: '20rpx',
|
||||
}"
|
||||
/></nut-col>
|
||||
<nut-col :span="22" class="font_36 f_weight c_222"
|
||||
>检测设备</nut-col
|
||||
>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-col :span="2"> </nut-col>
|
||||
<nut-col :span="22" class="font_32 c_666"
|
||||
>正式使用前,将设备提前上电,并将探头浸泡在水中24小时以上,使用最佳。</nut-col
|
||||
>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
<nut-row v-else-if="current === 2 && status == 1">
|
||||
<nut-col :span="24" class="m_t_10">
|
||||
<nut-radio-group v-model="waterType" direction="horizontal">
|
||||
<nut-radio :label="1" icon-size="25">
|
||||
淡水
|
||||
<template #icon>
|
||||
<IconFont :name="check" />
|
||||
</template>
|
||||
<template #checkedIcon>
|
||||
<IconFont :name="check_a" />
|
||||
</template>
|
||||
</nut-radio>
|
||||
<nut-radio :label="2" icon-size="25">
|
||||
海水
|
||||
<template #icon>
|
||||
<IconFont :name="check" />
|
||||
</template>
|
||||
<template #checkedIcon>
|
||||
<IconFont :name="check_a" />
|
||||
</template>
|
||||
</nut-radio>
|
||||
</nut-radio-group>
|
||||
</nut-col>
|
||||
<nut-col :span="24" v-if="waterType == 2">
|
||||
<nut-config-provider :theme-vars="themeVars">
|
||||
<nut-cell
|
||||
title="请设置您的盐度"
|
||||
is-link
|
||||
:desc="salt + '‰'"
|
||||
@click="setSalt"
|
||||
></nut-cell>
|
||||
</nut-config-provider>
|
||||
</nut-col>
|
||||
<nut-col :span="24" class="c_888 font_28">
|
||||
<view>淡水养殖无需设置,海水根据实际盐度设置。</view>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
<nut-row v-else-if="current === 3 && status == 1">
|
||||
<nut-col :span="24">
|
||||
<nut-config-provider :theme-vars="themeVars">
|
||||
<nut-cell
|
||||
title="溶解氧告警值设置"
|
||||
is-link
|
||||
:desc="String(alarm) + 'Mg/L'"
|
||||
@click="setAlarm"
|
||||
></nut-cell>
|
||||
</nut-config-provider>
|
||||
</nut-col>
|
||||
<nut-col :span="24" class="c_888 font_28">
|
||||
<view>当溶解氧低于设定数值时会电话告警</view>
|
||||
<view>(数值默认为3Mg/L,可设定最低值不能低于1.5Mg/L) </view>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
<nut-row v-else-if="current === 4 && status == 1">
|
||||
<nut-col :span="24">
|
||||
<nut-config-provider :theme-vars="themeVars">
|
||||
<nut-cell title="电量电话告警开关">
|
||||
<template #desc>
|
||||
<nut-switch
|
||||
v-model="batteryWarnCallOpen"
|
||||
active-color="#04D98A"
|
||||
/>
|
||||
</template>
|
||||
</nut-cell>
|
||||
<nut-cell
|
||||
v-if="batteryWarnCallOpen"
|
||||
title="电量电话告警下限"
|
||||
is-link
|
||||
:desc="String(batteryWarnLower) + '%'"
|
||||
@click="setBatteryWarnLower"
|
||||
></nut-cell>
|
||||
<nut-cell title="电量告警免打扰" v-if="batteryWarnCallOpen">
|
||||
<template #desc>
|
||||
<nut-switch
|
||||
v-model="batteryWarnCallNoDis"
|
||||
active-color="#04D98A"
|
||||
/>
|
||||
</template>
|
||||
</nut-cell>
|
||||
</nut-config-provider>
|
||||
</nut-col>
|
||||
<nut-col :span="24" class="c_888 font_28">
|
||||
<view>当电量低于设定数值时会电话告警</view>
|
||||
<view>(数值默认为2,可设定范围1-7)</view>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</nut-cell>
|
||||
<view>
|
||||
<nut-button
|
||||
block
|
||||
shape="square"
|
||||
size="large"
|
||||
:loading="isLoading"
|
||||
:style="{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '14px !important',
|
||||
borderRadius: '10px',
|
||||
marginBottom: '15px',
|
||||
}"
|
||||
@click="prev"
|
||||
v-if="current != 1"
|
||||
>
|
||||
上一步
|
||||
</nut-button>
|
||||
<nut-button
|
||||
block
|
||||
shape="square"
|
||||
type="primary"
|
||||
size="large"
|
||||
:loading="isLoading"
|
||||
:style="{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '14px !important',
|
||||
borderRadius: '10px',
|
||||
}"
|
||||
@click="next"
|
||||
>{{ current == 4 ? "添加" : "下一步" }}</nut-button
|
||||
>
|
||||
</view>
|
||||
<nut-config-provider :theme-vars="themeVars">
|
||||
<nut-dialog v-model:visible="saltShow" text-align="left" no-footer>
|
||||
<view :style="{ height: '100%' }">
|
||||
<view class="d_body">
|
||||
<nut-row>
|
||||
<nut-col :span="24">
|
||||
<view class="d_title">请设置您的盐度</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-divider class="divider" />
|
||||
</nut-col>
|
||||
<nut-col :span="24" class="view_f">
|
||||
<view :style="{ width: '20%' }" class="font_32 c_444"
|
||||
>盐度</view
|
||||
>
|
||||
<view :style="{ width: '80%' }">
|
||||
<nut-input
|
||||
type="digit"
|
||||
@blur="upValue"
|
||||
v-model="salt"
|
||||
placeholder="(盐度输入数值0-40‰)"
|
||||
:border="false"
|
||||
input-align="right"
|
||||
clearable
|
||||
max-length="5"
|
||||
:cursor="String(salt).length"
|
||||
>
|
||||
<template #right>
|
||||
<text class="c_222">‰</text>
|
||||
</template>
|
||||
</nut-input>
|
||||
</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-divider class="divider" />
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</view>
|
||||
<view class="d_btn">
|
||||
<nut-row>
|
||||
<nut-col
|
||||
:span="12"
|
||||
:style="{ border: '1px solid #eee', color: '#222' }"
|
||||
@click="saltShow = false"
|
||||
>
|
||||
取消
|
||||
</nut-col>
|
||||
<nut-col
|
||||
:span="12"
|
||||
:style="{ border: '1px solid #eee', color: '#15BBC5' }"
|
||||
@click="saltShow = false"
|
||||
>
|
||||
确定
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</view>
|
||||
</view>
|
||||
</nut-dialog>
|
||||
<nut-dialog v-model:visible="alarmShow" text-align="left" no-footer>
|
||||
<view :style="{ height: '100%' }">
|
||||
<view class="d_body">
|
||||
<nut-row>
|
||||
<nut-col :span="24">
|
||||
<view class="d_title">溶解氧告警值设置</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-divider class="divider" />
|
||||
</nut-col>
|
||||
<nut-col :span="24" class="view_f">
|
||||
<view :style="{ width: '20%' }" class="font_32 c_444"
|
||||
>告警值</view
|
||||
>
|
||||
<view :style="{ width: '80%' }">
|
||||
<nut-input
|
||||
type="digit"
|
||||
@blur="upAlarmValue"
|
||||
v-model="alarm"
|
||||
placeholder="1.5~20"
|
||||
:border="false"
|
||||
input-align="right"
|
||||
clearable
|
||||
max-length="5"
|
||||
:cursor="String(alarm).length"
|
||||
>
|
||||
<template #right>
|
||||
<text class="c_222">Mg/L</text>
|
||||
</template>
|
||||
</nut-input>
|
||||
</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-divider class="divider" />
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</view>
|
||||
<view class="d_btn">
|
||||
<nut-row>
|
||||
<nut-col
|
||||
:span="12"
|
||||
:style="{ border: '1px solid #eee', color: '#222' }"
|
||||
@click="alarmShow = false"
|
||||
>
|
||||
取消
|
||||
</nut-col>
|
||||
<nut-col
|
||||
:span="12"
|
||||
:style="{ border: '1px solid #eee', color: '#15BBC5' }"
|
||||
@click="alarmShow = false"
|
||||
>
|
||||
确定
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</view>
|
||||
</view>
|
||||
</nut-dialog>
|
||||
<nut-dialog v-model:visible="batteryWarnLowerShow" text-align="left" no-footer>
|
||||
<view :style="{ height: '100%' }">
|
||||
<view class="d_body">
|
||||
<nut-row>
|
||||
<nut-col :span="24">
|
||||
<view class="d_title">电量电话告警下限设置</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-divider class="divider" />
|
||||
</nut-col>
|
||||
<nut-col :span="24" class="view_f">
|
||||
<view :style="{ width: '30%' }" class="font_32 c_444"
|
||||
>告警下限</view
|
||||
>
|
||||
<view :style="{ width: '70%' }">
|
||||
<nut-input
|
||||
type="digit"
|
||||
@blur="upBatteryWarnLowerValue"
|
||||
v-model="batteryWarnLower"
|
||||
placeholder="1~7"
|
||||
:border="false"
|
||||
input-align="right"
|
||||
clearable
|
||||
max-length="5"
|
||||
:cursor="String(batteryWarnLower).length"
|
||||
>
|
||||
<template #right>
|
||||
<text class="c_222">%</text>
|
||||
</template>
|
||||
</nut-input>
|
||||
</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-divider class="divider" />
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</view>
|
||||
<view class="d_btn">
|
||||
<nut-row>
|
||||
<nut-col
|
||||
:span="12"
|
||||
:style="{ border: '1px solid #eee', color: '#222' }"
|
||||
@click="batteryWarnLowerShow = false"
|
||||
>
|
||||
取消
|
||||
</nut-col>
|
||||
<nut-col
|
||||
:span="12"
|
||||
:style="{ border: '1px solid #eee', color: '#15BBC5' }"
|
||||
@click="batteryWarnLowerShow = false"
|
||||
>
|
||||
确定
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
</view>
|
||||
</view>
|
||||
</nut-dialog>
|
||||
</nut-config-provider>
|
||||
</view>
|
||||
<!-- 弹出层提示 -->
|
||||
<nut-toast
|
||||
:msg="state.msg"
|
||||
v-model:visible="state.show"
|
||||
:type="state.type"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import Taro from "@tarojs/taro";
|
||||
import { stateType } from "@/utils/types";
|
||||
import { addDeviceSolarDetector, checkDeviceStatus } from "@/api/device";
|
||||
import { imgUrl } from "@/utils/imgUrl";
|
||||
import { IconFont } from "@nutui/icons-vue-taro";
|
||||
|
||||
definePageConfig({
|
||||
navigationBarTitleText: "添加太阳能网控",
|
||||
});
|
||||
const dc_1 = imgUrl + "dc_1.png";
|
||||
const dc_2 = imgUrl + "dc_2.png";
|
||||
const check = `https://www.yuceyun.cn/wechat/check.png`;
|
||||
const check_a = `https://www.yuceyun.cn/wechat/check_a.png`;
|
||||
const instance = Taro.getCurrentInstance();
|
||||
const r = instance.router.params.params;
|
||||
const page = instance.router.params.page;
|
||||
|
||||
console.log('URL参数原始值', r);
|
||||
let params: any = undefined;
|
||||
try {
|
||||
if (r) {
|
||||
// URL解码后再解析JSON
|
||||
const decodedParams = decodeURIComponent(r);
|
||||
console.log('URL解码后', decodedParams);
|
||||
params = JSON.parse(decodedParams);
|
||||
console.log('解析后的参数', params);
|
||||
} else {
|
||||
console.error('未获取到params参数');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('参数解析失败', e, '原始参数:', r);
|
||||
// 参数解析失败,显示提示后返回
|
||||
Taro.showModal({
|
||||
title: '提示',
|
||||
content: '参数错误,请重新进入',
|
||||
showCancel: false,
|
||||
success: () => {
|
||||
Taro.navigateBack();
|
||||
}
|
||||
});
|
||||
}
|
||||
// 步骤
|
||||
const current = ref<number>(1);
|
||||
const themeVars = ref({
|
||||
cellBoxShadow: "0px 0px 0px 0px",
|
||||
cellPadding: "0",
|
||||
cellColor: "#666666",
|
||||
cellTitleFont: "32rpx",
|
||||
cellTitleDescFont: "30rpx",
|
||||
cellDescFont: "30rpx",
|
||||
cellDescColor: "#222222",
|
||||
popupBorderRadius: "10rpx",
|
||||
});
|
||||
// 盐度
|
||||
const salt = ref<number>(30);
|
||||
const waterType = ref<number>(1);
|
||||
const saltShow = ref<boolean>(false);
|
||||
const alarm = ref<number>(3);
|
||||
const alarmShow = ref<boolean>(false);
|
||||
// 电量相关
|
||||
const batteryWarnCallOpen = ref<boolean>(false);
|
||||
const batteryWarnCallNoDis = ref<boolean>(false);
|
||||
const batteryWarnLower = ref<number>(2);
|
||||
const batteryWarnLowerShow = ref<boolean>(false);
|
||||
|
||||
const state: stateType = reactive({
|
||||
msg: "",
|
||||
type: "text",
|
||||
center: true,
|
||||
show: false,
|
||||
});
|
||||
const status = ref(0);
|
||||
const isLoading = ref<boolean>(false);
|
||||
/** ----------------metod start------------------ */
|
||||
// 监测设备在线状态
|
||||
function getCheckDevice() {
|
||||
if (!params) {
|
||||
console.error('params参数为空');
|
||||
state.show = true;
|
||||
state.msg = '参数错误';
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
devicetype: params.devType,
|
||||
serialnum: params.devNum,
|
||||
};
|
||||
console.log('检查设备状态', data);
|
||||
isLoading.value = true;
|
||||
checkDeviceStatus(data)
|
||||
.then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
status.value = res.data;
|
||||
if (status.value == 0) {
|
||||
state.show = true;
|
||||
state.msg = "设备未激活";
|
||||
} else if (status.value == 1) {
|
||||
current.value = 2;
|
||||
} else if (status.value == 3) {
|
||||
state.show = true;
|
||||
state.msg = "设备离线";
|
||||
} else if (status.value == 8) {
|
||||
state.show = true;
|
||||
state.msg = "设备禁用";
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = "设备异常";
|
||||
}
|
||||
} else {
|
||||
// 显示错误提示
|
||||
state.show = true;
|
||||
state.msg = res.msg || "检查设备失败,请重试";
|
||||
state.type = "fail";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// 处理网络错误等异常情况
|
||||
state.show = true;
|
||||
state.msg = "网络错误,请重试";
|
||||
state.type = "fail";
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
}
|
||||
function next() {
|
||||
if (!params) {
|
||||
state.show = true;
|
||||
state.msg = '参数错误';
|
||||
return;
|
||||
}
|
||||
|
||||
const num = current.value;
|
||||
if (num == 4) {
|
||||
isLoading.value = true;
|
||||
// 验证参数,发起添加设备请求
|
||||
if (salt.value) {
|
||||
if (Number(salt.value) < 0 || Number(salt.value) > 40) {
|
||||
state.show = true;
|
||||
state.msg = "盐度范围为0-40";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = "请录入盐度";
|
||||
return;
|
||||
}
|
||||
if (alarm.value) {
|
||||
if (Number(alarm.value) < 1.5 || Number(alarm.value) > 20) {
|
||||
state.show = true;
|
||||
state.msg = "告警值范围为1.5-20";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = "请录入告警值";
|
||||
return;
|
||||
}
|
||||
// 验证电量告警下限
|
||||
if (batteryWarnCallOpen.value) {
|
||||
if (batteryWarnLower.value) {
|
||||
if (Number(batteryWarnLower.value) < 1 || Number(batteryWarnLower.value) > 7) {
|
||||
state.show = true;
|
||||
state.msg = "电量告警下限范围为1-7";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = "请录入电量告警下限";
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 发起添加设备请求
|
||||
const data = {
|
||||
serialNum: Number(params.devNum),
|
||||
pondId: String(params.pondId[0]), // 转为字符串保持精度
|
||||
salinityCompensation: waterType.value == 1 ? 0 : Number(salt.value),
|
||||
oxyWarnLower: Number(alarm.value),
|
||||
batteryWarnCallOpen: batteryWarnCallOpen.value ? 1 : 0,
|
||||
batteryWarnCallNoDis: batteryWarnCallNoDis.value ? 1 : 0,
|
||||
batteryWarnLower: Number(batteryWarnLower.value),
|
||||
};
|
||||
console.log('添加设备数据', data);
|
||||
addDeviceSolarDetector(data)
|
||||
.then((res) => {
|
||||
if (res.code == 200) {
|
||||
Taro.redirectTo({
|
||||
url: "/my/addDevSuccess?name=添加太阳能网控&page=" + page,
|
||||
});
|
||||
} else {
|
||||
// 显示错误提示
|
||||
state.show = true;
|
||||
state.msg = res.msg || "添加失败,请重试";
|
||||
state.type = "fail";
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// 处理网络错误等异常情况
|
||||
state.show = true;
|
||||
state.msg = "网络错误,请重试";
|
||||
state.type = "fail";
|
||||
})
|
||||
.finally(() => {
|
||||
isLoading.value = false;
|
||||
});
|
||||
} else {
|
||||
if (num != 1 && status.value == 1) {
|
||||
current.value = num + 1;
|
||||
}
|
||||
if (num == 1) {
|
||||
// 检查设备状态
|
||||
getCheckDevice();
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 上一步
|
||||
function prev() {
|
||||
const num = current.value;
|
||||
current.value = num - 1;
|
||||
}
|
||||
// 设置盐度弹框
|
||||
function setSalt() {
|
||||
saltShow.value = true;
|
||||
}
|
||||
// 验证输入框内容
|
||||
function upValue() {
|
||||
const val = salt.value;
|
||||
if (Number(val) < 0 || Number(val) > 40) {
|
||||
salt.value = 40;
|
||||
}
|
||||
}
|
||||
// 设置溶解氧告警弹框
|
||||
function setAlarm() {
|
||||
alarmShow.value = true;
|
||||
}
|
||||
// 验证输入框内容
|
||||
function upAlarmValue() {
|
||||
const val = alarm.value;
|
||||
if (Number(val) < 1.5 || Number(val) > 20) {
|
||||
alarm.value = 20;
|
||||
}
|
||||
}
|
||||
// 设置电量告警下限弹框
|
||||
function setBatteryWarnLower() {
|
||||
batteryWarnLowerShow.value = true;
|
||||
}
|
||||
// 验证电量告警下限输入
|
||||
function upBatteryWarnLowerValue() {
|
||||
const val = batteryWarnLower.value;
|
||||
if (Number(val) < 1 || Number(val) > 7) {
|
||||
batteryWarnLower.value = 2;
|
||||
}
|
||||
}
|
||||
/** ----------------metod end-------------------- */
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.detector_home {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("https://www.yuceyun.cn/wechat/bg.jpg");
|
||||
background-color: #e5ebed;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
position: fixed;
|
||||
margin: 0;
|
||||
|
||||
font-size: 32px;
|
||||
font-family: "PingFang SC";
|
||||
font-weight: 400;
|
||||
|
||||
.body {
|
||||
padding: 15px;
|
||||
|
||||
.title {
|
||||
font-size: 32px;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 24px;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.mt {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 10px;
|
||||
font-size: 28px;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.tag {
|
||||
background: RGB(21, 137, 233, 0.1);
|
||||
border-radius: 4px;
|
||||
color: #1589e9;
|
||||
font-size: 28rpx;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 48px;
|
||||
color: #444444;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.nut-dialog {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nut-dialog__content {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nut-input {
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -149,7 +149,7 @@ Taro.useDidShow(() => {
|
||||
// 获取报警电话列表
|
||||
function getWarnPhoneList() {
|
||||
warnPhoneList().then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
phoneList.value = res.data;
|
||||
phone1.value = res.data[0] ? res.data[0] : "";
|
||||
phone2.value = res.data[1] ? res.data[1] : "";
|
||||
@@ -203,7 +203,7 @@ function save() {
|
||||
};
|
||||
isLoading.value = true
|
||||
updateWarnPhone(params).then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "保存成功";
|
||||
}
|
||||
|
||||
@@ -255,8 +255,9 @@ Taro.useDidShow(() => {
|
||||
});
|
||||
// 设备列表
|
||||
function getDeviceList() {
|
||||
allDeviceList({ type: 1 }).then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
const userId = Taro.getStorageSync("UserId");
|
||||
allDeviceList({ type: 1,rootUserId:userId }).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
deviceList.value = res.data;
|
||||
}
|
||||
});
|
||||
@@ -288,7 +289,7 @@ function removeDev(id: number) {
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
deviceUnbind({ id }).then((res) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "移除成功";
|
||||
getDeviceList();
|
||||
@@ -322,8 +323,8 @@ function goScan() {
|
||||
Taro.scanCode({
|
||||
success: (res) => {
|
||||
const result = res.result;
|
||||
deviceScan({ qrcode: result }).then((v) => {
|
||||
if (v.statusCode == 200) {
|
||||
deviceScan({ qrCode: result }).then((v) => {
|
||||
if (v.code == 200) {
|
||||
params.devType = String(v.data.deviceType);
|
||||
params.devNum = v.data.serialNum;
|
||||
alertShow.value = false;
|
||||
@@ -358,25 +359,35 @@ function submit() {
|
||||
state.msg = "请输入设备号";
|
||||
return;
|
||||
}
|
||||
|
||||
// 传参前确保 pondId 为字符串
|
||||
const paramsToSend = {
|
||||
...params,
|
||||
pondId: params.pondId.map(id => String(id))
|
||||
};
|
||||
console.log('deviceList 准备传递的参数:', paramsToSend);
|
||||
|
||||
if (params.devType == 1) {
|
||||
Taro.navigateTo({
|
||||
url: "/my/addDetector?params=" + JSON.stringify(params) + "&page=" + page,
|
||||
url: "/my/addDetector?params=" + encodeURIComponent(JSON.stringify(paramsToSend)) + "&page=" + page,
|
||||
});
|
||||
} else {
|
||||
Taro.navigateTo({
|
||||
url:
|
||||
"/my/addController?params=" + JSON.stringify(params) + "&page=" + page,
|
||||
"/my/addController?params=" + encodeURIComponent(JSON.stringify(paramsToSend)) + "&page=" + page,
|
||||
});
|
||||
}
|
||||
}
|
||||
// 查询塘口列表
|
||||
function getPondList() {
|
||||
getPond2().then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
pondList.value = res.data;
|
||||
if (pondId) {
|
||||
params.pondName = res.data.find((r) => r.id == pondId)?.["pondName"];
|
||||
params.pondId = [pondId];
|
||||
// 将 pondId 转为字符串保持精度
|
||||
params.pondId = [String(pondId)];
|
||||
console.log('deviceList 接收到的 pondId:', pondId, '转换后:', params.pondId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -389,7 +389,7 @@ Taro.useDidShow(() => {
|
||||
// 支付选项
|
||||
function getPayItem() {
|
||||
payOption().then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
payItem.value = res.data;
|
||||
reType.value = res.data[0]["id"];
|
||||
}
|
||||
@@ -442,7 +442,7 @@ function changeEx(state) {
|
||||
/** 下一步 */
|
||||
function next() {
|
||||
payOption().then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
res.data.forEach((item) => {
|
||||
// 分转元
|
||||
item.amount = item.amount / 100;
|
||||
@@ -471,13 +471,13 @@ function wxpay() {
|
||||
success: function (r) {
|
||||
if (r.code) {
|
||||
const data = {
|
||||
js_code: r.code,
|
||||
jsCode: r.code,
|
||||
payId: reType.value,
|
||||
listDeviceId: rechargeList.value,
|
||||
};
|
||||
// 创建订单
|
||||
createOrder(data).then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
const orderInfo = res.data;
|
||||
// 时间戳
|
||||
const timestamp = String(Math.floor(Date.now() / 1000));
|
||||
@@ -506,14 +506,26 @@ function wxpay() {
|
||||
},
|
||||
fail: function (res) {
|
||||
devOpen.value = false;
|
||||
state.msg = "续费异常,请稍后再试";
|
||||
state.msg = res.errMsg || "续费异常,请稍后再试";
|
||||
state.show = true;
|
||||
loading.value = false;
|
||||
console.error("支付失败:", res);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
loading.value = false;
|
||||
state.msg = res.msg || "创建订单失败";
|
||||
state.show = true;
|
||||
}
|
||||
}).catch((err) => {
|
||||
loading.value = false;
|
||||
state.msg = "网络异常,请稍后再试";
|
||||
state.show = true;
|
||||
});
|
||||
} else {
|
||||
loading.value = false;
|
||||
state.msg = "获取登录信息失败";
|
||||
state.show = true;
|
||||
}
|
||||
},
|
||||
fail: function () {
|
||||
|
||||
@@ -149,7 +149,7 @@ Taro.useDidShow(() => {
|
||||
// 获取子账号列表
|
||||
function getAccountList() {
|
||||
list_user_child().then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
accountList.value = res.data;
|
||||
}
|
||||
});
|
||||
@@ -170,8 +170,8 @@ function del(id) {
|
||||
content: "确认删除该子账号!",
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
delete_user_child({ id }).then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
delete_user_child(id).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "删除成功";
|
||||
getAccountList();
|
||||
@@ -198,7 +198,7 @@ function submit() {
|
||||
return;
|
||||
}
|
||||
add_user_child(Number(account.value)).then((res) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "添加成功";
|
||||
|
||||
|
||||
@@ -162,22 +162,31 @@ function wxLogin(e) {
|
||||
loginWxToPhone(params)
|
||||
.then((res) => {
|
||||
console.log('登录接口返回:', res);
|
||||
if (res.statusCode == 200) {
|
||||
|
||||
if (res.code == 200) {
|
||||
// 存储 token
|
||||
if (res.data.access_token) {
|
||||
Taro.setStorageSync("Access-Token", res.data.access_token);
|
||||
Taro.setStorageSync("X-Access-Token", res.data.access_token);
|
||||
}
|
||||
|
||||
Taro.setStorageSync(
|
||||
"ReTime",
|
||||
res.data.createdTime
|
||||
? formatDate(new Date(res.data.createdTime))
|
||||
: formatDate(new Date())
|
||||
);
|
||||
Taro.setStorageSync("UnLogin", 2);
|
||||
Taro.setStorageSync("UserName", res.data.userName);
|
||||
Taro.setStorageSync("Phone", res.data.mobilePhone);
|
||||
Taro.setStorageSync("UserId", res.data.id);
|
||||
store.updateRootUserId(res.data.id);
|
||||
store.updateUserId(res.data.id);
|
||||
store.updateUnLogin(2);
|
||||
store.updateRootUserName(res.data.userName);
|
||||
store.updateLoginStatus(0);
|
||||
Taro.setStorageSync("UserName", res.data.nickName || res.data.phonenumber || "");
|
||||
Taro.setStorageSync("Phone", res.data.phonenumber || "");
|
||||
Taro.setStorageSync("LoginType", "1");
|
||||
Taro.setStorageSync("UserId", res.data.userId || "");
|
||||
Taro.setStorageSync("UnLogin", 2);
|
||||
store.updateLoginStatus(0);
|
||||
store.updateUnLogin(2);
|
||||
store.updateRootUserId(res.data.userId || "");
|
||||
store.updateUserId(res.data.userId || "");
|
||||
store.updateRootUserName(res.data.nickName || res.data.phonenumber || "");
|
||||
state.msg = "登录成功";
|
||||
state.msg = "登录成功";
|
||||
state.show = true;
|
||||
Taro.switchTab({
|
||||
|
||||
@@ -176,7 +176,7 @@ function login() {
|
||||
? formatDate(new Date(res.data.createdTime))
|
||||
: formatDate(new Date())
|
||||
);
|
||||
Taro.setStorageSync("UserName", res.data.userName || loginForm.phonenumber);
|
||||
Taro.setStorageSync("UserName", res.data.nickName || loginForm.phonenumber);
|
||||
Taro.setStorageSync("Phone", loginForm.phonenumber);
|
||||
Taro.setStorageSync("LoginType", "1");
|
||||
Taro.setStorageSync("UserId", res.data.userId || "");
|
||||
@@ -185,7 +185,7 @@ function login() {
|
||||
store.updateUnLogin(2);
|
||||
store.updateRootUserId(res.data.userId || "");
|
||||
store.updateUserId(res.data.userId || "");
|
||||
store.updateRootUserName(res.data.userName || loginForm.phonenumber);
|
||||
store.updateRootUserName(res.data.nickName || loginForm.phonenumber);
|
||||
state.msg = "登录成功";
|
||||
state.show = true;
|
||||
Taro.switchTab({
|
||||
|
||||
@@ -1,43 +1,61 @@
|
||||
<template>
|
||||
<!-- <nut-row class="home_home" :style="{ marginTop: navBarHeight + 'px' }"> -->
|
||||
<nut-row class="home_home">
|
||||
<CustomNavigationBar @refresh="resUsetInfo" />
|
||||
<!-- 固定区域开始 -->
|
||||
<view class="sticky-header">
|
||||
<CustomNavigationBar @refresh="resUsetInfo" />
|
||||
<!-- 头部操作按钮区 -->
|
||||
<nut-col
|
||||
:span="24"
|
||||
class="view_f_between header-btn-container"
|
||||
>
|
||||
<view>
|
||||
<nut-button type="primary" class="btn header-btn" size="small" @click="changeMode">
|
||||
<template #icon>
|
||||
<IconFont :name="change" size="18" />
|
||||
</template>
|
||||
<text class="font_32 c_fff">切换模式</text>
|
||||
</nut-button>
|
||||
</view>
|
||||
<view>
|
||||
<nut-button
|
||||
type="primary"
|
||||
class="btn header-btn font_28"
|
||||
size="small"
|
||||
open-type="contact"
|
||||
>
|
||||
<template #icon>
|
||||
<IconFont :name="phone" size="18" />
|
||||
</template>
|
||||
<text class="font_32">联系工程师</text>
|
||||
</nut-button>
|
||||
</view>
|
||||
<view>
|
||||
<nut-button
|
||||
type="primary"
|
||||
class="btn header-btn header-btn-warning font_28"
|
||||
size="small"
|
||||
@click="openNotice"
|
||||
>
|
||||
<template #icon>
|
||||
<Tips size="18" />
|
||||
</template>
|
||||
<text class="font_32">系统公告</text>
|
||||
</nut-button>
|
||||
</view>
|
||||
</nut-col>
|
||||
</view>
|
||||
<!-- 固定区域结束 -->
|
||||
<nut-col :span="24" class="container" :class="showChart ? 'ov' : ''">
|
||||
<nut-config-provider :theme-vars="themeVars">
|
||||
<nut-row class="body" :catch-move="false">
|
||||
<view :style="{ height: '120rpx' }">
|
||||
<!-- 头部 -->
|
||||
<nut-col
|
||||
:span="24"
|
||||
class="view_f_between"
|
||||
:style="{ padding: '20rpx 20rpx 0 20rpx' }"
|
||||
>
|
||||
<view class="view_f">
|
||||
<!-- <IconFont :name="location" />
|
||||
<view class="font_28" v-if="store.getUnLogin != 1">{{ city }}</view> -->
|
||||
</view>
|
||||
<view>
|
||||
<nut-button
|
||||
type="warning"
|
||||
class="btn font_28"
|
||||
size="small"
|
||||
@click="openNotice"
|
||||
>
|
||||
<template #icon>
|
||||
<Tips size="18" />
|
||||
</template>
|
||||
<text class="font_32">系统公告</text>
|
||||
</nut-button>
|
||||
</view>
|
||||
</nut-col>
|
||||
<!-- 消息通知 -->
|
||||
<!-- 消息通知 -->
|
||||
<nut-col
|
||||
:span="24"
|
||||
class="pond m_t_15 view_f_between"
|
||||
:style="{ padding: '0 20rpx' }"
|
||||
@click="toPay"
|
||||
>
|
||||
<!-- deadList.length>0 && -->
|
||||
<view :style="{ width: '100%' }">
|
||||
<nut-noticebar
|
||||
background="rgba(255, 255, 255, 0.7)"
|
||||
@@ -48,19 +66,18 @@
|
||||
<template #left-icon>
|
||||
<img :src="noticeImg" style="width: 32rpx; height: 32rpx" />
|
||||
</template>
|
||||
<!-- <text class="content">{{ `${notice}` }}</text> -->
|
||||
<text class="content">{{ `${deadList.length}个设备即将到期` }}</text>
|
||||
</nut-noticebar>
|
||||
</view>
|
||||
</nut-col>
|
||||
<!-- 标题 -->
|
||||
<!-- 塘口列表标题 -->
|
||||
<nut-col
|
||||
:span="24"
|
||||
class="pond m_t_15 view_f_between"
|
||||
:style="{ padding: '0 20rpx' }"
|
||||
>
|
||||
<view class="font_34 f_weight">塘口列表</view>
|
||||
<view id="addPondBtn">
|
||||
<view id="addPondBtn" class="view_f" :style="{ gap: '10rpx' }">
|
||||
<nut-button
|
||||
type="primary"
|
||||
class="btn font_28"
|
||||
@@ -74,17 +91,9 @@
|
||||
</template>
|
||||
<text class="font_32">新建塘口</text>
|
||||
</nut-button>
|
||||
</view>
|
||||
<view>
|
||||
<nut-button type="primary" class="btn" size="small" @click="changeMode">
|
||||
<template #icon>
|
||||
<IconFont :name="change" size="18" />
|
||||
</template>
|
||||
<text class="font_32 c_fff">切换模式</text>
|
||||
</nut-button>
|
||||
|
||||
</view>
|
||||
</nut-col>
|
||||
</view>
|
||||
<!-- 模式一 -->
|
||||
<nut-col
|
||||
:span="24"
|
||||
@@ -280,11 +289,11 @@
|
||||
<nut-row v-if="pondList.length > 0">
|
||||
<!-- 切换选择塘口 -->
|
||||
<nut-col :span="24">
|
||||
<scroll-view :scroll-x="true" style="width: 100%; height: 60rpx">
|
||||
<view :style="{ width: '100%' }">
|
||||
<nut-radio-group
|
||||
v-model="selPond"
|
||||
direction="horizontal"
|
||||
:style="{ whiteSpace: 'nowrap' }"
|
||||
:style="{ flexWrap: 'wrap', gap: '10rpx' }"
|
||||
>
|
||||
<nut-radio
|
||||
:label="item.id"
|
||||
@@ -294,7 +303,7 @@
|
||||
>{{ item.pondName }}</nut-radio
|
||||
>
|
||||
</nut-radio-group>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</nut-col>
|
||||
<nut-col
|
||||
:span="24"
|
||||
@@ -306,7 +315,7 @@
|
||||
@getPondInfo="getPondInfo"
|
||||
@addDevice="addDevice"
|
||||
ref="pondChildInfo"
|
||||
type="1"
|
||||
:type="1"
|
||||
/>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
@@ -487,7 +496,7 @@
|
||||
<nut-row>
|
||||
<nut-col
|
||||
:span="24"
|
||||
:style="{ textAlign: 'right', padding: '20rpx' }"
|
||||
:style="{ textAlign: 'left', padding: '20rpx' }"
|
||||
@click="closeNotice"
|
||||
>
|
||||
<CircleClose />
|
||||
@@ -541,7 +550,7 @@
|
||||
v-model="selPond_2"
|
||||
@addDevice="addDevice"
|
||||
ref="pondChildInfo"
|
||||
type="2"
|
||||
:type="2"
|
||||
/>
|
||||
</nut-col>
|
||||
</nut-row>
|
||||
@@ -571,6 +580,10 @@ definePageConfig({
|
||||
backgroundTextStyle: "dark",
|
||||
});
|
||||
const store: any = useRootUserStore();
|
||||
// 防止重复检查登录状态
|
||||
let isCheckingLogin = false;
|
||||
// 防止重复弹窗
|
||||
let isShowingLoginDialog = false;
|
||||
// 导航拦信息
|
||||
const navBarHeight = ref();
|
||||
const windowInfo = Taro.getWindowInfo();
|
||||
@@ -590,6 +603,8 @@ const c3_n = `${imgUrl}c3_n.png`;
|
||||
const c_def = `${imgUrl}c_def.png`;
|
||||
const location = `${imgUrl}location.png`;
|
||||
const change = `${imgUrl}change.png`;
|
||||
const phone = `${imgUrl}tel.png`;
|
||||
const setting = `${imgUrl}setting.png`;
|
||||
const noticeImg = `${imgUrl}noticeImg.png`;
|
||||
const pond404 = `${imgUrl}zanwurenwu.png`;
|
||||
// const notice = ref("有设备服务快到期,请尽快续费");
|
||||
@@ -632,9 +647,9 @@ let qqmapsdk = new QQMapWX({
|
||||
key: "75RBZ-WQSYB-6KEUB-NCZME-D62T7-YIF4G",
|
||||
});
|
||||
// 选中的塘口id
|
||||
const selPond = ref<number | undefined>(undefined);
|
||||
const selPond = ref<number | string | undefined>(undefined);
|
||||
// 多糖选中塘口id
|
||||
const selPond_2 = ref<number | undefined>(undefined);
|
||||
const selPond_2 = ref<number | string | undefined>(undefined);
|
||||
const selPondName_2 = ref<string | undefined>("塘口详情");
|
||||
const visControl = ref(false);
|
||||
// 展示塘口详情
|
||||
@@ -700,7 +715,7 @@ Taro.usePullDownRefresh(() => {
|
||||
pond2();
|
||||
}
|
||||
// 模式一滚动条高度
|
||||
m1_height.value = Taro.getSystemInfoSync().windowHeight - 200;
|
||||
m1_height.value = Taro.getWindowInfo().windowHeight - 200;
|
||||
nextTick(() => {
|
||||
if (pondChildInfo.value) {
|
||||
if (alertShow.value) {
|
||||
@@ -714,6 +729,9 @@ Taro.usePullDownRefresh(() => {
|
||||
});
|
||||
});
|
||||
Taro.useDidShow(() => {
|
||||
// 检查登录状态
|
||||
checkLoginStatus();
|
||||
|
||||
startPolling();
|
||||
// 默认
|
||||
pond1();
|
||||
@@ -723,6 +741,12 @@ Taro.useDidShow(() => {
|
||||
if (mode.value == 1) {
|
||||
pond2();
|
||||
}
|
||||
// 刷新子组件数据
|
||||
nextTick(() => {
|
||||
if (pondChildInfo.value) {
|
||||
pondChildInfo.value.refresh();
|
||||
}
|
||||
});
|
||||
if (store.getUnLogin != 1 && store.getLoginStatus != 1) {
|
||||
// 位置解析
|
||||
// Taro.getLocation({
|
||||
@@ -743,7 +767,7 @@ Taro.useDidShow(() => {
|
||||
// });
|
||||
}
|
||||
// 模式一滚动条高度
|
||||
m1_height.value = Taro.getSystemInfoSync().windowHeight - 200;
|
||||
m1_height.value = Taro.getWindowInfo().windowHeight - 200;
|
||||
nextTick(() => {
|
||||
if (alertShow.value) {
|
||||
pondChildInfo.value.hideTour(alertShow.value);
|
||||
@@ -793,7 +817,6 @@ function handleSubscriptionStatus(status, tmplId, message) {
|
||||
} else if (status === "reject") {
|
||||
requestUserSubscription([tmplId], "订阅消息", `请授权开通${message}`);
|
||||
} else if (status === "ban") {
|
||||
console.log(`${message}的订阅已被后台封禁`);
|
||||
} else {
|
||||
requestUserSubscription([tmplId], "订阅消息", `请授权开通${message}`);
|
||||
}
|
||||
@@ -817,32 +840,19 @@ function requestUserSubscription(tmplIds, title, content) {
|
||||
Taro.requestSubscribeMessage({
|
||||
...params,
|
||||
success: function (subscribeRes) {
|
||||
console.log("订阅响应:", subscribeRes);
|
||||
tmplIds.forEach((tmplId) => {
|
||||
if (subscribeRes[tmplId] === "accept") {
|
||||
state.show = true;
|
||||
state.msg = "订阅成功";
|
||||
} else if (subscribeRes[tmplId] === "reject") {
|
||||
console.log(tmplId, "用户拒绝订阅");
|
||||
} else if (subscribeRes[tmplId] === "ban") {
|
||||
console.log(tmplId, "订阅被封禁");
|
||||
}
|
||||
});
|
||||
},
|
||||
fail: function (error) {
|
||||
console.log("订阅请求失败:", error);
|
||||
},
|
||||
complete: function (r) {
|
||||
console.log(r);
|
||||
},
|
||||
});
|
||||
// }
|
||||
// });
|
||||
}
|
||||
},
|
||||
fail: function (error) {
|
||||
console.error("弹窗失败:", error);
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -890,6 +900,155 @@ function stopPolling() {
|
||||
timer.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查登录状态
|
||||
function checkLoginStatus() {
|
||||
// 防止重复检查
|
||||
if (isCheckingLogin) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 游客模式直接跳过
|
||||
if (store.getUnLogin == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const token = Taro.getStorageSync('Access-Token');
|
||||
const userId = Taro.getStorageSync('UserId');
|
||||
const loginType = Taro.getStorageSync('LoginType');
|
||||
|
||||
// 方式1:检查本地是否有token和userId
|
||||
if (!token || !userId) {
|
||||
isCheckingLogin = true;
|
||||
// 如果之前是微信登录(LoginType=1),尝试引导重新授权
|
||||
if (loginType === '1') {
|
||||
attemptAutoLogin();
|
||||
} else {
|
||||
// 非微信登录,提示用户重新登录
|
||||
showLoginExpiredDialog();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 方式2:通过接口验证token是否有效
|
||||
// 这里调用一个轻量级接口,如果返回401,request.ts会统一拦截处理
|
||||
verifyTokenValid();
|
||||
}
|
||||
|
||||
// 验证token是否有效
|
||||
function verifyTokenValid() {
|
||||
// 使用塘口列表接口来验证token
|
||||
getPond1().then((res: any) => {
|
||||
console.log('getPond1返回结果:', res);
|
||||
|
||||
if (res && res.code === 200) {
|
||||
// token有效,正常继续
|
||||
console.log('登录状态有效');
|
||||
isCheckingLogin = false;
|
||||
} else if (res && (res.code === 401 || res.statusCode === 401)) {
|
||||
// token无效,主动弹窗提示
|
||||
console.log('检测到401,token已过期,弹出提示');
|
||||
isCheckingLogin = false;
|
||||
showLoginExpiredDialog();
|
||||
} else if (!res || res.code !== 200) {
|
||||
// 其他异常情况,也可能是token问题
|
||||
console.log('接口返回异常,code:', res?.code);
|
||||
isCheckingLogin = false;
|
||||
// 如果返回的不是200,可能也是登录问题
|
||||
if (res && res.msg && res.msg.includes('登录')) {
|
||||
showLoginExpiredDialog();
|
||||
}
|
||||
} else {
|
||||
// 其他错误码
|
||||
isCheckingLogin = false;
|
||||
}
|
||||
}).catch((error) => {
|
||||
// 接口调用失败
|
||||
console.log('登录状态检查失败,error:', error);
|
||||
isCheckingLogin = false;
|
||||
|
||||
// 如果是401错误,也弹出提示
|
||||
if (error && (error.code === 401 || error.statusCode === 401)) {
|
||||
console.log('catch到401错误,弹出提示');
|
||||
showLoginExpiredDialog();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示登录过期提示
|
||||
function showLoginExpiredDialog() {
|
||||
// 防止重复弹窗
|
||||
if (isShowingLoginDialog) {
|
||||
console.log('登录过期弹窗已显示,跳过重复弹窗');
|
||||
return;
|
||||
}
|
||||
|
||||
isShowingLoginDialog = true;
|
||||
console.log('显示登录过期弹窗');
|
||||
|
||||
Taro.showModal({
|
||||
title: '提示',
|
||||
content: '登录信息已过期,请重新登录',
|
||||
showCancel: false,
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
Taro.clearStorageSync();
|
||||
store.updateUnLogin(1);
|
||||
Taro.redirectTo({
|
||||
url: '/pages/login/index',
|
||||
});
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
// 1秒后重置状态,允许再次弹窗
|
||||
setTimeout(() => {
|
||||
isShowingLoginDialog = false;
|
||||
isCheckingLogin = false;
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 尝试自动登录
|
||||
function attemptAutoLogin() {
|
||||
// 防止重复弹窗
|
||||
if (isShowingLoginDialog) {
|
||||
return;
|
||||
}
|
||||
|
||||
isShowingLoginDialog = true;
|
||||
console.log('显示重新授权弹窗');
|
||||
|
||||
// 由于后端需要手机号授权code,无法实现完全静默登录
|
||||
// 直接提示用户重新授权
|
||||
Taro.showModal({
|
||||
title: '登录已过期',
|
||||
content: '需要重新授权获取手机号以继续使用',
|
||||
confirmText: '去授权',
|
||||
cancelText: '稍后再说',
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
// 跳转到登录页,让用户重新授权
|
||||
Taro.clearStorageSync();
|
||||
store.updateUnLogin(1);
|
||||
Taro.redirectTo({
|
||||
url: '/pages/login/index',
|
||||
});
|
||||
} else {
|
||||
// 用户选择稍后,进入游客模式
|
||||
store.updateUnLogin(1);
|
||||
pond1();
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
// 1秒后重置状态
|
||||
setTimeout(() => {
|
||||
isShowingLoginDialog = false;
|
||||
isCheckingLogin = false;
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
/////////////////////
|
||||
function getPondInfo(e) {
|
||||
// Taro.nextTick(() => {
|
||||
@@ -954,26 +1113,31 @@ function pond1() {
|
||||
|
||||
});
|
||||
pondList.value = rows;
|
||||
// 立即设置默认选中的塘口,并强制触发响应式更新
|
||||
if (rows.length > 0) {
|
||||
const firstPondId = rows[0]["id"]; // 保持原始类型
|
||||
if (!selPond.value || !pondIds.includes(selPond.value)) {
|
||||
// 延迟一帧确保 DOM 已渲染
|
||||
setTimeout(() => {
|
||||
selPond.value = firstPondId;
|
||||
console.log('已选中塘口:', selPond.value, '类型:', typeof selPond.value, '所有塘口:', rows.map(r => ({id: r.id, name: r.pondName})));
|
||||
}, 50);
|
||||
}
|
||||
} else {
|
||||
selPond.value = undefined;
|
||||
}
|
||||
setTimeout(() => {
|
||||
showTour.value = rows.length == 0 ? true : false;
|
||||
}, 500);
|
||||
selPond.value = selPond.value
|
||||
? selPond.value
|
||||
: rows.length > 0
|
||||
? Number(rows[0]["id"])
|
||||
: undefined;
|
||||
if (selPond.value) {
|
||||
if (!pondIds.includes(selPond.value)) {
|
||||
selPond.value = rows.length > 0 ? Number(rows[0]["id"]) : undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// 塘口模式2
|
||||
function pond2() {
|
||||
if (selPond.value) {
|
||||
params.pondId = [Number(selPond.value)];
|
||||
// 保持字符串格式避免精度丢失
|
||||
params.pondId = [String(selPond.value)];
|
||||
console.log('pond2 设置 pondId:', params.pondId);
|
||||
}
|
||||
}
|
||||
// 新建塘口
|
||||
@@ -982,6 +1146,18 @@ function addPond() {
|
||||
url: "/home/addPond",
|
||||
});
|
||||
}
|
||||
// 编辑塘口
|
||||
function updatePond() {
|
||||
const pondId = mode.value == 1 ? selPond.value : selPond_2.value;
|
||||
if (pondId) {
|
||||
Taro.navigateTo({
|
||||
url: `/home/updatePond?id=${pondId}`,
|
||||
});
|
||||
} else {
|
||||
state.show = true;
|
||||
state.msg = "请先选择塘口";
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定设备页面
|
||||
function addDevice() {
|
||||
@@ -1099,13 +1275,33 @@ function onconfirm(list) {
|
||||
if (res.code == 200) {
|
||||
state.show = true;
|
||||
state.msg = "操作成功";
|
||||
pond2();
|
||||
pond1();
|
||||
pondChildInfo.value.getDeviceList();
|
||||
// 先关闭弹窗
|
||||
bandDevShow.value = false;
|
||||
// 延迟刷新数据,确保后端数据更新完成
|
||||
setTimeout(() => {
|
||||
// 先刷新塘口列表(会自动选中当前塘口)
|
||||
pond1();
|
||||
// 等待 pond1 完成后再刷新设备详情
|
||||
setTimeout(() => {
|
||||
if (pondChildInfo.value && pondChildInfo.value.getDeviceList) {
|
||||
pondChildInfo.value.getDeviceList();
|
||||
}
|
||||
}, 500);
|
||||
}, 500);
|
||||
} else {
|
||||
// 操作失败也关闭弹窗
|
||||
bandDevShow.value = false;
|
||||
state.show = true;
|
||||
state.msg = res.msg || "绑定失败,请重试";
|
||||
state.type = "fail";
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
.catch((error) => {
|
||||
// 网络错误也关闭弹窗
|
||||
bandDevShow.value = false;
|
||||
state.show = true;
|
||||
state.msg = "网络错误,请重试";
|
||||
state.type = "fail";
|
||||
});
|
||||
} else if (res.cancel) {
|
||||
bandDevShow.value = false;
|
||||
@@ -1131,7 +1327,7 @@ function goScan() {
|
||||
Taro.scanCode({
|
||||
success: (res) => {
|
||||
const result = res.result;
|
||||
deviceScan({ qrcode: result }).then((v) => {
|
||||
deviceScan({ qrCode: result }).then((v) => {
|
||||
if (v.code == 200) {
|
||||
params.devType = String(v.data.deviceType);
|
||||
params.devNum = v.data.serialNum;
|
||||
@@ -1164,13 +1360,21 @@ function submit() {
|
||||
}
|
||||
alertShow.value = false;
|
||||
showTour.value = false;
|
||||
|
||||
// 传参前确保 pondId 为字符串
|
||||
const paramsToSend = {
|
||||
...params,
|
||||
pondId: params.pondId.map(id => String(id))
|
||||
};
|
||||
console.log('home 准备传递的参数:', paramsToSend);
|
||||
|
||||
if (params.devType == 1) {
|
||||
Taro.navigateTo({
|
||||
url: "/my/addDetector?params=" + JSON.stringify(params) + "&page=home",
|
||||
url: "/my/addDetector?params=" + encodeURIComponent(JSON.stringify(paramsToSend)) + "&page=home",
|
||||
});
|
||||
} else {
|
||||
Taro.navigateTo({
|
||||
url: "/my/addController?params=" + JSON.stringify(params) + "&page=home",
|
||||
url: "/my/addController?params=" + encodeURIComponent(JSON.stringify(paramsToSend)) + "&page=home",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1244,6 +1448,56 @@ function toPay() {
|
||||
/** -----------------method end------------------- */
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.sticky-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
background: #fff;
|
||||
padding-bottom: 10rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.header-btn-container {
|
||||
padding: 20rpx !important;
|
||||
gap: 16rpx !important;
|
||||
display: flex !important;
|
||||
align-items: stretch !important;
|
||||
background: #fff !important;
|
||||
|
||||
view {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.header-btn {
|
||||
border-radius: 8rpx !important;
|
||||
width: 100%;
|
||||
height: 72rpx !important;
|
||||
min-height: 72rpx !important;
|
||||
max-height: 72rpx !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
box-sizing: border-box !important;
|
||||
font-size: 28rpx !important;
|
||||
font-weight: 500 !important;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1) !important;
|
||||
transition: all 0.3s ease !important;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 1rpx 4rpx rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.header-btn-warning {
|
||||
background: #ff8800 !important;
|
||||
background-color: #ff8800 !important;
|
||||
}
|
||||
|
||||
.home_home {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -1291,17 +1545,32 @@ function toPay() {
|
||||
// 模式2塘口管理
|
||||
.pond_mode2 {
|
||||
.nut-radio__button--active {
|
||||
background-color: #09b8c2;
|
||||
background: linear-gradient(135deg, #09b8c2 0%, #06a0a9 100%) !important;
|
||||
border-radius: 10px;
|
||||
color: #fff !important;
|
||||
font-weight: bold;
|
||||
font-size: 30rpx !important;
|
||||
box-shadow: 0 6rpx 16rpx rgba(9, 184, 194, 0.6);
|
||||
transform: scale(1.08);
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid #09b8c2;
|
||||
}
|
||||
|
||||
.nut-radio__button--normal {
|
||||
border-radius: 10px;
|
||||
background-color: #f5f6f7;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.06);
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.nut-radio--button {
|
||||
background-color: #fff;
|
||||
background-color: #f5f6f7;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 10rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.nut-tab-pane {
|
||||
@@ -1372,6 +1641,8 @@ function toPay() {
|
||||
.nut-popup--bottom {
|
||||
box-shadow: 0px 1px 7px 0px rgb(20, 20, 20);
|
||||
border-radius: 0px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.nut-popup--center.round {
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
<view class="d_body" :style="{ paddingBottom: '0px' }">
|
||||
<nut-row>
|
||||
<nut-col :span="24">
|
||||
<view class="d_title">请设手机号码</view>
|
||||
<view class="d_title">请设置手机号码</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-divider class="divider" />
|
||||
@@ -136,7 +136,7 @@
|
||||
<nut-col :span="24" class="view_f">
|
||||
<view :style="{ width: '30%' }" class="font_32 c_444">原手机号</view>
|
||||
<view :style="{ width: '70%' }">
|
||||
<nut-input type="number" v-model="phonenumber" :border="false" input-align="right" readonly />
|
||||
<nut-input type="text" v-model="phonenumber" :border="false" input-align="right" readonly />
|
||||
</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
@@ -145,7 +145,7 @@
|
||||
<nut-col :span="24" class="view_f">
|
||||
<view :style="{ width: '30%' }" class="font_32 c_444">新手机号</view>
|
||||
<view :style="{ width: '70%' }">
|
||||
<nut-input type="number" v-model="newPhone" :border="false" input-align="right" placeholder="请输入新手机号" clearable max-length="11" :cursor="String(phnewPhoneone1).length" />
|
||||
<nut-input type="number" v-model="newPhone" :border="false" input-align="right" placeholder="请输入新手机号" clearable max-length="11" :cursor="String(newPhone).length" />
|
||||
</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
@@ -177,7 +177,7 @@
|
||||
<view class="d_body" :style="{ paddingBottom: '0px' }">
|
||||
<nut-row>
|
||||
<nut-col :span="24">
|
||||
<view class="d_title">请设昵称</view>
|
||||
<view class="d_title">请设置昵称</view>
|
||||
</nut-col>
|
||||
<nut-col :span="24">
|
||||
<nut-divider class="divider" />
|
||||
@@ -336,7 +336,7 @@ function getWarnMsg() {
|
||||
pageNum: 1,
|
||||
})
|
||||
msgWarn(warnParams.value).then((res: any) => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
const unReadCount = res.data.unReadCount
|
||||
if (unReadCount) {
|
||||
Taro.setTabBarBadge({
|
||||
@@ -425,6 +425,7 @@ function goContact() {
|
||||
}
|
||||
// 修改手机号码
|
||||
function setPhoneNumber() {
|
||||
phonenumber.value = Taro.getStorageSync("Phone") || "-"
|
||||
setPhoneShow.value = true
|
||||
}
|
||||
/** 验证码读秒 */
|
||||
@@ -445,7 +446,7 @@ function setTime() {
|
||||
}
|
||||
/** 获取验证码 */
|
||||
function getCode() {
|
||||
const v_phone_res = validatePhone(phonenumber.value)
|
||||
const v_phone_res = validatePhone(newPhone.value)
|
||||
if (v_phone_res == 1) {
|
||||
state.msg = "手机号不能为空"
|
||||
state.show = true
|
||||
@@ -453,7 +454,7 @@ function getCode() {
|
||||
state.msg = "手机号格式不正确"
|
||||
state.show = true
|
||||
} else {
|
||||
smsCode(phonenumber.value).then((res: any) => {
|
||||
smsCode(newPhone.value).then((res: any) => {
|
||||
state.msg = "发送成功"
|
||||
state.show = true
|
||||
setTime()
|
||||
@@ -496,13 +497,16 @@ function toSetPhone() {
|
||||
smsCode: code.value,
|
||||
}
|
||||
updatePhone(data).then(res => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
state.msg = "修改成功"
|
||||
state.show = true
|
||||
|
||||
Taro.setStorageSync("Phone", newPhone.value)
|
||||
phonenumber.value = newPhone.value
|
||||
setPhoneShow.value = false
|
||||
} else {
|
||||
state.msg = res.msg || "修改失败"
|
||||
state.show = true
|
||||
}
|
||||
})
|
||||
// verifyCode({ MobilePhone: phonenumber.value, SmsCode: code.value }).then(res => {
|
||||
@@ -548,7 +552,7 @@ function toSetName() {
|
||||
newName: newName.value,
|
||||
}
|
||||
updateNickName(data).then(res => {
|
||||
if (res.statusCode == 200) {
|
||||
if (res.code == 200) {
|
||||
state.msg = "修改成功"
|
||||
state.show = true
|
||||
nextTick(() => {
|
||||
@@ -573,13 +577,23 @@ function logOut() {
|
||||
content: "确认注销当前账号?",
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
logoutFun()
|
||||
Taro.clearStorageSync()
|
||||
Taro.clearStorage()
|
||||
store.updateRootUserId(null)
|
||||
store.updateRootUserName(null)
|
||||
Taro.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
logoutFun().then(() => {
|
||||
Taro.clearStorageSync()
|
||||
Taro.clearStorage()
|
||||
store.updateRootUserId(null)
|
||||
store.updateRootUserName(null)
|
||||
Taro.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
})
|
||||
}).catch(() => {
|
||||
// 即使接口失败也执行本地清理和跳转
|
||||
Taro.clearStorageSync()
|
||||
Taro.clearStorage()
|
||||
store.updateRootUserId(null)
|
||||
store.updateRootUserName(null)
|
||||
Taro.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -728,6 +742,7 @@ function toLogin() {
|
||||
|
||||
.nut-dialog {
|
||||
padding: 0;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.nut-dialog__content {
|
||||
@@ -735,6 +750,11 @@ function toLogin() {
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
scroll-view {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.code {
|
||||
color: #09b8c2;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
refresherThreshold="50"
|
||||
:refresherTriggered="refStatus"
|
||||
@RefresherPulling="onPulling"
|
||||
@scrolltolower="lower"
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<view class="body">
|
||||
<view v-if="selectVal === 0">
|
||||
@@ -246,7 +248,7 @@ const msg_o2 = `${imgUrl}msg_o2.png`;
|
||||
const pond404 = `${imgUrl}zanwurenwu.png`;
|
||||
const selectVal = ref(0);
|
||||
// 告警列表
|
||||
const warnList = ref([]);
|
||||
const warnList = ref<any[]>([]);
|
||||
const warnParams = ref({
|
||||
pageSize: 10,
|
||||
pageNum: 1
|
||||
@@ -254,7 +256,7 @@ const warnParams = ref({
|
||||
const warnTotal = ref(0);
|
||||
const warnTotalPages = ref(1);
|
||||
// 开关列表
|
||||
const switchList = ref([]);
|
||||
const switchList = ref<any[]>([]);
|
||||
const switchParams = ref({
|
||||
pageSize: 10,
|
||||
pageNum: 1
|
||||
@@ -262,7 +264,7 @@ const switchParams = ref({
|
||||
const switchTotal = ref(0);
|
||||
const switchTotalPages = ref(1);
|
||||
// 充值列表
|
||||
const payList = ref([]);
|
||||
const payList = ref<any[]>([]);
|
||||
const payParams = ref({
|
||||
pageSize: 10,
|
||||
pageNum: 1
|
||||
@@ -272,12 +274,25 @@ const payTotalPages = ref(1);
|
||||
const refStatus = ref(false);
|
||||
const unReadCount = ref<number>(0);
|
||||
const msgCount = ref<number>(0);
|
||||
// 使用普通变量而不是 ref,避免响应式延迟
|
||||
let isLoadingMore = false;
|
||||
// 记录当前正在加载的页码,防止重复
|
||||
let currentLoadingPage = 0;
|
||||
|
||||
/** ----------------method start------------------------ */
|
||||
Taro.useDidShow(() => {
|
||||
selectVal.value = 0;
|
||||
// 查询设备列表
|
||||
getWarnMsg();
|
||||
// 每次显示页面时都刷新数据,确保数据一致性
|
||||
// 根据当前选中的标签刷新对应数据,并重置分页
|
||||
if (selectVal.value === 0) {
|
||||
warnParams.value.pageNum = 1;
|
||||
getWarnMsg();
|
||||
} else if (selectVal.value === 1) {
|
||||
switchParams.value.pageNum = 1;
|
||||
getSwitchMsg();
|
||||
} else if (selectVal.value === 2) {
|
||||
payParams.value.pageNum = 1;
|
||||
getPayMsg();
|
||||
}
|
||||
});
|
||||
// 头部组件刷新
|
||||
function resUsetInfo(e){
|
||||
@@ -289,39 +304,51 @@ function changeVal(e) {
|
||||
refStatus.value = false;
|
||||
}, 200);
|
||||
|
||||
// 如果是同一个tab,不做任何操作(保持当前状态)
|
||||
if (selectVal.value === e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先更新选中的值
|
||||
selectVal.value = e;
|
||||
if (e == 0) {
|
||||
|
||||
// 根据选中的值加载对应数据
|
||||
if (e === 0) {
|
||||
warnParams.value.pageNum = 1;
|
||||
getWarnMsg();
|
||||
} else if (e == 1) {
|
||||
} else if (e === 1) {
|
||||
switchParams.value.pageNum = 1;
|
||||
getSwitchMsg();
|
||||
} else if (e == 2) {
|
||||
} else if (e === 2) {
|
||||
payParams.value.pageNum = 1;
|
||||
getPayMsg();
|
||||
}
|
||||
}
|
||||
// 查询告警消息
|
||||
function getWarnMsg() {
|
||||
const userId = Taro.getStorageSync("UserId");
|
||||
function getWarnMsg(isLoadMore = false) {
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
const params = {
|
||||
...warnParams.value,
|
||||
userId
|
||||
};
|
||||
|
||||
msgWarn(params).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
// 数据直接在 res 上,不是 res.data
|
||||
warnList.value = res.rows || [];
|
||||
if (isLoadMore) {
|
||||
const newRows = res.rows || [];
|
||||
warnList.value = [...warnList.value, ...newRows];
|
||||
} else {
|
||||
warnList.value = res.rows || [];
|
||||
}
|
||||
warnTotal.value = res.total || 0;
|
||||
// 计算总页数
|
||||
warnTotalPages.value = Math.ceil(warnTotal.value / warnParams.value.pageSize);
|
||||
// 统计未读数量
|
||||
unReadCount.value = warnList.value.filter(item => !item.isRead).length;
|
||||
msgCount.value = warnTotal.value;
|
||||
|
||||
if (unReadCount.value) {
|
||||
Taro.setTabBarBadge({
|
||||
index: 1, // tabBar的位置,从0开始计数
|
||||
index: 1,
|
||||
text: unReadCount.value > 9 ? "9+" : String(unReadCount.value),
|
||||
});
|
||||
} else {
|
||||
@@ -330,18 +357,30 @@ function getWarnMsg() {
|
||||
});
|
||||
}
|
||||
}
|
||||
}).finally(() => {
|
||||
// 延迟重置锁,防止立即触发下一次滚动
|
||||
setTimeout(() => {
|
||||
isLoadingMore = false;
|
||||
currentLoadingPage = 0;
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
// 查询开关消息
|
||||
function getSwitchMsg() {
|
||||
const userId = Taro.getStorageSync("UserId");
|
||||
function getSwitchMsg(isLoadMore = false) {
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
const params = {
|
||||
...switchParams.value,
|
||||
userId
|
||||
};
|
||||
msgSwitch(params).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
switchList.value = res.rows || [];
|
||||
if (isLoadMore) {
|
||||
const newRows = res.rows || [];
|
||||
switchList.value = [...switchList.value, ...newRows];
|
||||
} else {
|
||||
switchList.value = res.rows || [];
|
||||
}
|
||||
switchTotal.value = res.total || 0;
|
||||
switchTotalPages.value = Math.ceil(switchTotal.value / switchParams.value.pageSize);
|
||||
msgCount.value = switchTotal.value;
|
||||
@@ -349,15 +388,21 @@ function getSwitchMsg() {
|
||||
});
|
||||
}
|
||||
// 查询充值消息
|
||||
function getPayMsg() {
|
||||
const userId = Taro.getStorageSync("UserId");
|
||||
function getPayMsg(isLoadMore = false) {
|
||||
const store = useRootUserStore();
|
||||
const userId = store.getRootUserId || Taro.getStorageSync('UserId');
|
||||
const params = {
|
||||
...payParams.value,
|
||||
userId
|
||||
};
|
||||
msgPay(params).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
payList.value = res.rows || [];
|
||||
if (isLoadMore) {
|
||||
const newRows = res.rows || [];
|
||||
payList.value = [...payList.value, ...newRows];
|
||||
} else {
|
||||
payList.value = res.rows || [];
|
||||
}
|
||||
payTotal.value = res.total || 0;
|
||||
payTotalPages.value = Math.ceil(payTotal.value / payParams.value.pageSize);
|
||||
msgCount.value = payTotal.value;
|
||||
@@ -365,55 +410,46 @@ function getPayMsg() {
|
||||
});
|
||||
}
|
||||
function lower() {
|
||||
// 防止重复加载
|
||||
if (isLoadingMore) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否还有更多数据
|
||||
if (selectVal.value == 0 && warnParams.value.pageNum >= warnTotalPages.value) {
|
||||
return;
|
||||
}
|
||||
if (selectVal.value == 1 && switchParams.value.pageNum >= switchTotalPages.value) {
|
||||
return;
|
||||
}
|
||||
if (selectVal.value == 2 && payParams.value.pageNum >= payTotalPages.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算要加载的页码
|
||||
const nextPage = warnParams.value.pageNum + 1;
|
||||
|
||||
// 检查是否正在加载同一页
|
||||
if (currentLoadingPage === nextPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置加载状态
|
||||
isLoadingMore = true;
|
||||
currentLoadingPage = nextPage;
|
||||
|
||||
// 更新页码
|
||||
warnParams.value.pageNum = nextPage;
|
||||
|
||||
const userId = Taro.getStorageSync("UserId");
|
||||
if (selectVal.value == 0) {
|
||||
if (warnParams.value.pageNum < warnTotalPages.value) {
|
||||
warnParams.value.pageNum = warnParams.value.pageNum + 1;
|
||||
const params = {
|
||||
...warnParams.value,
|
||||
userId
|
||||
};
|
||||
msgWarn(params).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
const newRows = res.rows || [];
|
||||
newRows.forEach((r) => {
|
||||
warnList.value.push(r);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
getWarnMsg(true);
|
||||
} else if (selectVal.value == 1) {
|
||||
if (switchParams.value.pageNum < switchTotalPages.value) {
|
||||
switchParams.value.pageNum = switchParams.value.pageNum + 1;
|
||||
const params = {
|
||||
...switchParams.value,
|
||||
userId
|
||||
};
|
||||
msgSwitch(params).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
const newRows = res.rows || [];
|
||||
newRows.forEach((r) => {
|
||||
switchList.value.push(r);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
switchParams.value.pageNum = switchParams.value.pageNum + 1;
|
||||
getSwitchMsg(true);
|
||||
} else if (selectVal.value == 2) {
|
||||
if (payParams.value.pageNum < payTotalPages.value) {
|
||||
payParams.value.pageNum = payParams.value.pageNum + 1;
|
||||
const params = {
|
||||
...payParams.value,
|
||||
userId
|
||||
};
|
||||
msgPay(params).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
const newRows = res.rows || [];
|
||||
newRows.forEach((r) => {
|
||||
payList.value.push(r);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
payParams.value.pageNum = payParams.value.pageNum + 1;
|
||||
getPayMsg(true);
|
||||
}
|
||||
}
|
||||
/** 上拉触底分页 */
|
||||
@@ -561,6 +597,7 @@ function getWarnCode(warnCode) {
|
||||
}
|
||||
.body {
|
||||
padding: 15px;
|
||||
min-height: 81vh; // 确保内容高度超过容器,支持滚动
|
||||
|
||||
.title {
|
||||
font-size: 32px;
|
||||
|
||||
@@ -8,11 +8,12 @@ const timeOutSeconds = 10000;
|
||||
const getBaseUrl = () => {
|
||||
let BASE_URL = ''
|
||||
if (process.env.TARO_ENV === 'h5') {
|
||||
BASE_URL = 'https://www.qdintc.com/fishery-api' // 线上调试后端
|
||||
// BASE_URL = 'http://127.0.0.1:8080' // 本地调试后端地址
|
||||
// BASE_URL = 'https://www.qdintc.com/fishery-api' // 线上调试后端
|
||||
BASE_URL = 'http://127.0.0.1:8080' // 本地调试后端地址
|
||||
} else {
|
||||
BASE_URL = 'https://api.yuceyun.cn' //填写你的请求域名
|
||||
// BASE_URL = 'https://dev.yuceyun.cn' //测试环境
|
||||
// BASE_URL = 'https://api.yuceyun.cn' //填写你的请求域名
|
||||
BASE_URL = 'https://api.yuceyun.cn/prod-api' // 测试环境
|
||||
// BASE_URL = 'http://127.0.0.1:8080' // 本地调试后端地址
|
||||
// BASE_URL = 'http://47.102.210.182:6678' //测试环境
|
||||
}
|
||||
return BASE_URL
|
||||
@@ -38,10 +39,17 @@ export const BASE_URL = getBaseUrl()
|
||||
const reg = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/;
|
||||
let modalShown = false;
|
||||
let timeModal = false;
|
||||
// 需要loading的url
|
||||
// 需要loading的url(使用v2新版本接口)
|
||||
const urlLoadings = [
|
||||
"/api/device/delete", "/api/device/set_controller_oxy_open", "/api/device/set_oxy_warn_call",
|
||||
"/api/device-switch/turn_switch", "/api/device-switch/turn_pond_switch", "/api/device/voltage_check_open", "/api/device-switch/electric_check_open","/api/device-switch/electric_set"]
|
||||
"/fishery/device", // 删除设备
|
||||
"/fishery/device/set_controller_oxy_open", // 设置溶解氧机开关
|
||||
"/fishery/device/set_oxy_warn_call", // 设置溶解氧告警
|
||||
"/iot/switch/turn_switch", // 单个开关启停
|
||||
"/iot/switch/turn_pond_switch", // 所有开关启停(全开/全关)
|
||||
"/fishery/device/voltage_check_open", // 电压告警检测
|
||||
"/fishery/deviceSwitch/electric_check_open",// 电流告警检测
|
||||
"/iot/switch/electric_set" // 电流设置
|
||||
]
|
||||
let isShow = 0
|
||||
const request = async (method, url, params) => {
|
||||
const pattern = new RegExp(url.split("?rootuserid")[0], 'i');
|
||||
@@ -106,15 +114,23 @@ const request = async (method, url, params) => {
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
Taro.clearStorageSync()
|
||||
store.updateUnLogin(1);
|
||||
Taro.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
} else if (res.cancel) {
|
||||
Taro.clearStorageSync()
|
||||
store.updateUnLogin(1);
|
||||
Taro.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
// 1秒后重置状态,防止永久锁定
|
||||
setTimeout(() => {
|
||||
modalShown = false;
|
||||
}, 1000);
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -133,15 +149,23 @@ const request = async (method, url, params) => {
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
Taro.clearStorageSync()
|
||||
store.updateUnLogin(1);
|
||||
Taro.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
} else if (res.cancel) {
|
||||
Taro.clearStorageSync()
|
||||
store.updateUnLogin(1);
|
||||
Taro.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
// 1秒后重置状态,防止永久锁定
|
||||
setTimeout(() => {
|
||||
modalShown = false;
|
||||
}, 1000);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
104
types/auto-imports.d.ts
vendored
104
types/auto-imports.d.ts
vendored
@@ -58,6 +58,7 @@ declare global {
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
@@ -87,8 +88,11 @@ declare global {
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useId: typeof import('vue')['useId']
|
||||
const useModel: typeof import('vue')['useModel']
|
||||
const useRootUserStore: typeof import('../src/store/index')['useRootUserStore']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const useTemplateRef: typeof import('vue')['useTemplateRef']
|
||||
const validate: typeof import('../src/utils/validate')['default']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
@@ -98,8 +102,11 @@ declare global {
|
||||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
import('vue')
|
||||
// @ts-ignore
|
||||
export type { ResponseAdapter, ParamsBuilder, PathBuilder } from '../src/utils/api-helper'
|
||||
import('../src/utils/api-helper')
|
||||
}
|
||||
// for vue template auto import
|
||||
import { UnwrapRef } from 'vue'
|
||||
@@ -157,6 +164,7 @@ declare module 'vue' {
|
||||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
|
||||
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||
@@ -185,99 +193,11 @@ declare module 'vue' {
|
||||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||
readonly useId: UnwrapRef<typeof import('vue')['useId']>
|
||||
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
|
||||
readonly useRootUserStore: UnwrapRef<typeof import('../src/store/index')['useRootUserStore']>
|
||||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||
readonly validate: UnwrapRef<typeof import('../src/utils/validate')['default']>
|
||||
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
|
||||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||
}
|
||||
}
|
||||
declare module '@vue/runtime-core' {
|
||||
interface GlobalComponents {}
|
||||
interface ComponentCustomProperties {
|
||||
readonly BASE_URL: UnwrapRef<typeof import('../src/utils/request')['BASE_URL']>
|
||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||
readonly ParamsBuilder: UnwrapRef<typeof import('../src/utils/api-helper')['ParamsBuilder']>
|
||||
readonly PathBuilder: UnwrapRef<typeof import('../src/utils/api-helper')['PathBuilder']>
|
||||
readonly ResponseAdapter: UnwrapRef<typeof import('../src/utils/api-helper')['ResponseAdapter']>
|
||||
readonly alarmJudgeCode: UnwrapRef<typeof import('../src/utils/tools')['alarmJudgeCode']>
|
||||
readonly apiHelper: UnwrapRef<typeof import('../src/utils/api-helper')['default']>
|
||||
readonly buildUrl: UnwrapRef<typeof import('../src/utils/api-helper')['buildUrl']>
|
||||
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
|
||||
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
|
||||
readonly daysBeforeToday: UnwrapRef<typeof import('../src/utils/tools')['daysBeforeToday']>
|
||||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||
readonly formatDate: UnwrapRef<typeof import('../src/utils/tools')['formatDate']>
|
||||
readonly formatDateHms: UnwrapRef<typeof import('../src/utils/tools')['formatDateHms']>
|
||||
readonly formatDateMin: UnwrapRef<typeof import('../src/utils/tools')['formatDateMin']>
|
||||
readonly formatDateMin_: UnwrapRef<typeof import('../src/utils/tools')['formatDateMin_']>
|
||||
readonly formatDateString: UnwrapRef<typeof import('../src/utils/tools')['formatDateString']>
|
||||
readonly formatDate_: UnwrapRef<typeof import('../src/utils/tools')['formatDate_']>
|
||||
readonly generateTimeSlotsEndingToday: UnwrapRef<typeof import('../src/utils/tools')['generateTimeSlotsEndingToday']>
|
||||
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
|
||||
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
|
||||
readonly getNowTime: UnwrapRef<typeof import('../src/utils/tools')['getNowTime']>
|
||||
readonly getToken: UnwrapRef<typeof import('../src/utils/auth')['getToken']>
|
||||
readonly getUserId: UnwrapRef<typeof import('../src/utils/auth')['getUserId']>
|
||||
readonly getUsername: UnwrapRef<typeof import('../src/utils/auth')['getUsername']>
|
||||
readonly h: UnwrapRef<typeof import('vue')['h']>
|
||||
readonly imgUrl: UnwrapRef<typeof import('../src/utils/imgUrl')['imgUrl']>
|
||||
readonly inject: UnwrapRef<typeof import('vue')['inject']>
|
||||
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
|
||||
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
|
||||
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
|
||||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||
readonly isRelogin: UnwrapRef<typeof import('../src/utils/request')['isRelogin']>
|
||||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
|
||||
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
|
||||
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
|
||||
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
|
||||
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
|
||||
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
|
||||
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
|
||||
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
|
||||
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
|
||||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||
readonly ref: UnwrapRef<typeof import('vue')['ref']>
|
||||
readonly removeToken: UnwrapRef<typeof import('../src/utils/auth')['removeToken']>
|
||||
readonly removeUserId: UnwrapRef<typeof import('../src/utils/auth')['removeUserId']>
|
||||
readonly removeUsername: UnwrapRef<typeof import('../src/utils/auth')['removeUsername']>
|
||||
readonly request: UnwrapRef<typeof import('../src/utils/request')['default']>
|
||||
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
|
||||
readonly setToken: UnwrapRef<typeof import('../src/utils/auth')['setToken']>
|
||||
readonly setUserId: UnwrapRef<typeof import('../src/utils/auth')['setUserId']>
|
||||
readonly setUsername: UnwrapRef<typeof import('../src/utils/auth')['setUsername']>
|
||||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||
readonly sortByField: UnwrapRef<typeof import('../src/utils/tools')['sortByField']>
|
||||
readonly timeX: UnwrapRef<typeof import('../src/utils/tools')['timeX']>
|
||||
readonly timestampToTime: UnwrapRef<typeof import('../src/utils/tools')['timestampToTime']>
|
||||
readonly toDecimal: UnwrapRef<typeof import('../src/utils/tools')['toDecimal']>
|
||||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||
readonly useRootUserStore: UnwrapRef<typeof import('../src/store/index')['useRootUserStore']>
|
||||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
|
||||
readonly validate: UnwrapRef<typeof import('../src/utils/validate')['default']>
|
||||
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||
|
||||
Reference in New Issue
Block a user