feat: 迁移文件

This commit is contained in:
宋建忠 2024-07-02 20:21:15 +08:00
parent fe837d111a
commit 78e58d8ddc
456 changed files with 92765 additions and 1 deletions

3
.eslintignore Normal file
View File

@ -0,0 +1,3 @@
unpackage
node_modules
uview-ui

31
.gitignore vendored Normal file
View File

@ -0,0 +1,31 @@
.DS_Store
/node_modules
/dist
/unpackage
/uniCloud-aliyun
/tests/e2e/videos/
/tests/e2e/screenshots/
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.vs
.idea
.vscode
.hbuilderx
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
*.iml
*.lock
package-lock.json

147
App.vue Normal file
View File

@ -0,0 +1,147 @@
<script>
import request from '@/network/request.js'
// #ifdef APP-PLUS
import update from '@/uni_modules/uni-upgrade-center-app/utils/check-update';
// #endif
export default {
onLaunch: function() {
//
let configList = uni.getStorageSync('configList');
if(!configList || configList.length == 0){
let configList = [{
id:this.$u.guid(32),
protocol:'https://',
address:'cloud.iot-fast.com',
}]
uni.setStorageSync('configList',configList)
uni.setStorageSync('configIndex',0)
}
// #ifdef APP-PLUS
update();
uni.onTabBarMidButtonTap(()=>{
uni.scanCode({
scanType: ['qrCode'],
success: function (res) {
console.log("扫一扫获取内容",res)
// if(res.result){
// let [type,prodKey,devKey] = res.result.split(':')
// if(prodKey&&devKey){
// let opt = {
// url: '/prod-api/iot/device/get/device',
// method: "GET",
// }
// let params={
// devKey,
// pd:prodKey
// }
// // this.$requestonLaunch$requestrequest使
// request.TokenRequest(opt,params).then(res => {
// console.log('res',res)
// if(res.code==200){
// if(res.data){
// let deviceId=res.data.deviceId;
// uni.navigateTo({
// url:'/pages/device/detail?deviceId='+deviceId,
// success: (res) => {
// uni.showToast({
// title: '',
// icon: 'none'
// });
// },
// fail: (err) => {
// uni.showToast({
// title: '',
// icon: 'none'
// });
// }
// })
// }else{
// uni.showToast({
// title: 'id',
// icon: 'none'
// });
// }
// }else{
// uni.showToast({
// title: res.msg,
// icon: 'none'
// });
// }
// }, error => {
// uni.showToast({
// title: '',
// icon: 'none'
// });
// })
// }
// }
}
});
})
// #endif
},
onShow: function() {
console.log('App Show')
// #ifdef MP-WEIXIN
//
this.updateApp()
// #endif
},
onHide: function() {
console.log('App Hide')
},
mounted() {
console.log('App mounted')
// uni.setTabBarItem({
// index: 0,
// text: '',
// })
},
methods:{
//
updateApp(){
const updateManager = uni.getUpdateManager();
updateManager.onCheckForUpdate(function (res) {
//
console.log("请求完新版本信息的回调",res.hasUpdate);
});
updateManager.onUpdateReady(function (res) {
uni.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
// applyUpdate
updateManager.applyUpdate();
}
}
});
});
updateManager.onUpdateFailed(function (res) {
//
});
}
}
}
</script>
<style lang="scss">
/* #ifndef APP-NVUE */
@import "uview-ui/index.scss";
/* #endif */
</style>
<style>
/*#ifndef APP-NVUE || MP-WEIXIN */
@import "static/app-plus/fonts/iconfont.css";
/*#endif*/
/* #ifdef MP-WEIXIN */
@import "static/common/fonts/iconfont.css";
/* #endif */
/* #ifndef APP-NVUE */
@import "static/common/css/base.css";
/* #endif */
</style>

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 www.uviewui.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1 +0,0 @@
#hc-work

View File

@ -0,0 +1,53 @@
<template>
<view class="nav-bar">
<u-navbar :is-back="isBack" :back-text="backText" back-icon-size="40" :title-width="titleWidth" :back-icon-color="color" :title="title" :title-color="color" :border-bottom="borderBottom" :background="{ background: background }"></u-navbar>
</view>
</template>
<script>
export default{
props:{
//
title:{
type:String,
default:''
},
//
isBack:{
type:Boolean,
default:false
},
//
backText:{
type:String,
default:''
},
// (APP)
background:{
type:String,
default:'#1B85E9'
},
//
borderBottom: {
type:Boolean,
default:true
},
// rpx
titleWidth: {
type:Number,
default:250
},
//
color: {
type:String,
default:'#fff'
}
}
}
</script>
<style scoped>
/deep/.uicon-nav-back{
font-weight: bold !important;
}
</style>

View File

@ -0,0 +1,140 @@
/*
该步进器可以设置整数是否最大数最小数步进数支持负数小数
*/
<template>
<view class="number-box">
<view class="minus" :class="{'disabled':selfValue<=min}">
<u-icon name="minus" size="28" @click="minusClick"></u-icon>
</view>
<input class="self-input" type="number" v-model="selfValue" @blur="inputValue"/>
<view class="plus" :class="{'disabled':selfValue>=max}">
<u-icon name="plus" size="28" @click="plusClick"></u-icon>
</view>
</view>
</template>
<script>
// js
import {numAdd,numSub} from '@/static/common/js/js-calculate.js'
export default{
data(){
return{
selfValue: 0
}
},
props:{
//
min:{
type:Number,
default:-99999
},
//
max:{
type:Number,
default:99999
},
//
value:{
type:Number,
default:0
},
//
integer: {
type:Boolean,
default:true
},
//
step: {
type:Number,
default:1
},
},
watch: {
selfValue() {
if (this.value != this.selfValue) {
this.$emit('changeValue', this.selfValue)
}
},
value(){
if (this.value != this.selfValue) {
this.selfValue = this.value
}
}
},
methods:{
//
inputValue(event){
let val = event.detail.value;
if(this.integer){
val = val.replace(/[^0-9]/g, '');
}
if(val <= this.min){
val = this.min;
}
if (val >= this.max) {
val = this.max;
}
this.$nextTick(() => {
this.selfValue = val;
})
},
//
minusClick(){
console.log(this.selfValue)
if (this.selfValue <= this.min) {
this.selfValue = this.min
return
}else if (this.selfValue > this.max) {
this.selfValue = this.max
return
}
this.selfValue = numSub(this.selfValue,this.step);
},
//
plusClick(){
if (this.selfValue < this.min) {
this.selfValue = this.min
return
}else if (this.selfValue >= this.max) {
this.selfValue = this.max
return
}
this.selfValue = numAdd(this.selfValue,this.step);
},
}
}
</script>
<style>
.number-box{
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100%;
}
.minus,.plus{
flex: 1;
height: 100%;
background: #f5f7fa;
border: 1px solid #DCDFE6;
color: #333;
display: flex;
align-items: center;
justify-content: center;
}
.disabled{
background: #f8f8f8;
color: #ccc;
}
.self-input{
width: 120rpx;
height: 100%;
background: #fff;
text-align: center;
line-height: 100%;
color: #333;
}
</style>

31
common/js/tabbarList.js Normal file
View File

@ -0,0 +1,31 @@
module.exports = {
list:[{
iconPath: "home",
selectedIconPath: "home-fill",
text: '首页',
customIcon: false,
pagePath:'/pages/iots/home/index'
},
{
iconPath: "grid",
selectedIconPath: "grid-fill",
text: '设备',
customIcon: false,
pagePath:'/pages/iots/device/device-list'
},
{
iconPath: "map",
selectedIconPath: "map-fill",
text: '地图',
customIcon: false,
pagePath:'/pages/iots/map/device-map'
},
{
iconPath: "bell",
selectedIconPath: "bell-fill",
text: '告警',
customIcon: false,
pagePath:'/pages/iots/notice/index'
},
],
}

105
common/js/util/base64.js Normal file
View File

@ -0,0 +1,105 @@
export default function Base64() {
// 私钥
let _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
// 加密
this.encode = function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
// 解密
this.decode = (input)=> {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
if (input==undefined||input==null){
}else {
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = _utf8_decode(output);
return output;
}
}
// private method for UTF-8 encoding
let _utf8_encode = (string)=> {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
// private method for UTF-8 decoding
let _utf8_decode = (utftext)=> {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
var c1 = 0;
var c2 = 0;
var c3 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}

View File

@ -0,0 +1,39 @@
// 手机号脱敏
export function phoneHide(phone) {
let reg = /^(1[3-9][0-9])\d{4}(\d{4}$)/; // 定义手机号正则表达式
phone = phone.replace(reg, '$1****$2');
return phone; // 185****6696
}
// 邮箱脱敏
export function emailHide(email) {
var avg;
var splitted;
var email1;
var email2;
splitted = email.split('@');
email1 = splitted[0];
avg = email1.length / 2;
email1 = email1.substring(0, email1.length - avg);
email2 = splitted[1];
return email1 + '***@' + email2; // 输出为81226***@qq.com
}
// 身份证脱敏
export function cardHide(card) {
const reg = /^(.{6})(?:\d+)(.{4})$/; // 匹配身份证号前6位和后4位的正则表达式
const maskedIdCard = card.replace(reg, '$1******$2'); // 身份证号脱敏将中间8位替换为“*”
return maskedIdCard; // 输出371782******5896
}
// 姓名脱敏
export function nameHide(name) {
if (name.length == 2) {
name = name.substring(0, 1) + '*'; // 截取name 字符串截取第一个字符,
return name; // 张三显示为张*
} else if (name.length == 3) {
name = name.substring(0, 1) + '*' + name.substring(2, 3); // 截取第一个和第三个字符
return name; // 李思思显示为李*思
} else if (name.length > 3) {
name = name.substring(0, 1) + '*' + '*' + name.substring(3, name.length); // 截取第一个和大于第4个字符
return name; // 王五哈哈显示为王**哈
}
}

22
common/js/util/encrypt.js Normal file
View File

@ -0,0 +1,22 @@
import CryptoJS from 'crypto-js'
const defaultKey = 'f080a463654b2279';
export function encrypt(word, keyStr = defaultKey) {
const key = CryptoJS.enc.Utf8.parse(keyStr);
const src = CryptoJS.enc.Utf8.parse(word);
const encrypted = CryptoJS.AES.encrypt(src, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.toString();
}
export function decrypt(word, keyStr = defaultKey) {
const key = CryptoJS.enc.Utf8.parse(keyStr);
const decrypt = CryptoJS.AES.decrypt(word, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
}

31
common/js/util/filters.js Normal file
View File

@ -0,0 +1,31 @@
import Vue from 'vue'
Vue.filter('hideTel', function(phone){
if(!phone){
return '';
}
return phone.toString().replace(/^(\d{3})\d{4}(\d+)/,"$1****$2");
});
// Vue.filter('hideIDcard', function(cardId){
// if(!cardId){
// return '';
// }
// return cardId.toString().replace(/(?<=\d{3})\d{12}(?=\d{2})/,"************");
// });
Vue.filter('formatBirth', function(birth){
if(!birth){
return '';
}
return birth.split(' ')[0];
});
Vue.filter('formatTime', function(pay_time){
if(!pay_time){
return '';
}
let date = pay_time.split(' ')[0];
let time = pay_time.split(' ')[1];
return date.split('-')[1] + '月' + date.split('-')[2] + '日 ' + time.split(':')[0] + ':' + time.split(':')[1];
});

View File

@ -0,0 +1,267 @@
/**
* 表单验证
* @author dingyong
* @version 1.4.0
**/
const form = {
//当出现错误时返回错误消息,否则返回空即为验证通过
/*
formData:Object 表单对象{key:value,key:value},key==rules.name
rules: Array [{name:name,rule:[],msg:[]},{name:name,rule:[],msg:[]}]
name:name 属性=> 元素的名称
rule:字符串数组 ["required","isMobile","isEmail","isCarNo","isIdCard","isAmount","isNum","isChinese","isEnglish",isEnAndNo","isSpecial","isEmoji",""isDate","isUrl","isSame:key","range:[1,9]","minLength:9","maxLength:Number"]
msg:数组 [] 与数组 rule 长度相同,对应的错误提示信息
*/
validation: function(formData, rules) {
for (let item of rules) {
let key = item.name;
let rule = item.rule;
let msgArr = item.msg;
if (!key || !rule || rule.length === 0 || !msgArr || msgArr.length === 0) {
continue;
}
for (let i = 0, length = rule.length; i < length; i++) {
let ruleItem = rule[i];
let msg = msgArr[i];
if (!ruleItem || !msg) {
continue;
}
//数据处理
let value = null;
if (~ruleItem.indexOf(":")) {
let temp = ruleItem.split(":");
ruleItem = temp[0];
value = temp[1];
}
let isError = false;
switch (ruleItem) {
case "required":
isError = form._isNullOrEmpty(formData[key]);
break;
case "isMobile":
isError = !form._isMobile(formData[key]);
break;
case "isEmail":
isError = !form._isEmail(formData[key]);
break;
case "isCarNo":
isError = !form._isCarNo(formData[key]);
break;
case "isIdCard":
isError = !form._isIdCard(formData[key]);
break;
case "isAmount":
isError = !form._isAmount(formData[key]);
break;
case "isNum":
isError = !form._isNum(formData[key]);
break;
case "isChinese":
isError = !form._isChinese(formData[key]);
break;
case "isEnglish":
isError = !form._isEnglish(formData[key]);
break;
// case "isEnAndNo":
// isError = !form._isEnAndNo(formData[key]);
// break;
case "isEnOrNo":
isError = !form._isEnOrNo(formData[key]);
break;
case "isSpecial":
isError = form._isSpecial(formData[key]);
break;
case "isEmoji":
isError = form._isEmoji(formData[key]);
break;
// case "isDate":
// isError = !form._isDate(formData[key]);
// break;
case "isUrl":
isError = !form._isUrl(formData[key]);
break;
case "isSame":
isError = !form._isSame(formData[key], formData[value]);
break;
case "range":
let range = null;
try {
range = JSON.parse(value);
if (range.length <= 1) {
throw new Error("range值传入有误")
}
} catch (e) {
return "range值传入有误"
}
isError = !form._isRange(formData[key], range[0], range[1])
break;
case "minLength":
isError = !form._minLength(formData[key], value)
break;
case "maxLength":
isError = !form._maxLength(formData[key], value)
break;
default:
break;
}
if (isError) {
return msg;
}
}
}
return "";
},
_isNullOrEmpty: function(value) {
return (value === null || value === '' || value === undefined) ? true : false;
},
_isMobile: function(value) {
return /^(?:13\d|14\d|15\d|16\d|17\d|18\d|19\d)\d{5}(\d{3}|\*{3})$/.test(value);
},
_isEmail: function(value) {
return /^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/.test(value);
},
_isCarNo: function(value) {
// 新能源车牌
const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/;
// 旧车牌
const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
if (value.length === 7) {
return creg.test(value);
} else if (value.length === 8) {
return xreg.test(value);
} else {
return false;
}
},
_isIdCard: function(value) {
let idCard = value;
if (idCard.length == 15) {
return this.__isValidityBrithBy15IdCard;
} else if (idCard.length == 18) {
let arrIdCard = idCard.split("");
if (this.__isValidityBrithBy18IdCard(idCard) && this.__isTrueValidateCodeBy18IdCard(arrIdCard)) {
return true;
} else {
return false;
}
} else {
return false;
}
},
__isTrueValidateCodeBy18IdCard: function(arrIdCard) {
let sum = 0;
let Wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
let ValideCode = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2];
if (arrIdCard[17].toLowerCase() == 'x') {
arrIdCard[17] = 10;
}
for (let i = 0; i < 17; i++) {
sum += Wi[i] * arrIdCard[i];
}
let valCodePosition = sum % 11;
if (arrIdCard[17] == ValideCode[valCodePosition]) {
return true;
} else {
return false;
}
},
__isValidityBrithBy18IdCard: function(idCard18) {
let year = idCard18.substring(6, 10);
let month = idCard18.substring(10, 12);
let day = idCard18.substring(12, 14);
let temp_date = new Date(year, parseFloat(month) - 1, parseFloat(day));
if (temp_date.getFullYear() != parseFloat(year) || temp_date.getMonth() != parseFloat(month) - 1 || temp_date.getDate() !=
parseFloat(day)) {
return false;
} else {
return true;
}
},
__isValidityBrithBy15IdCard: function(idCard15) {
let year = idCard15.substring(6, 8);
let month = idCard15.substring(8, 10);
let day = idCard15.substring(10, 12);
let temp_date = new Date(year, parseFloat(month) - 1, parseFloat(day));
if (temp_date.getYear() != parseFloat(year) || temp_date.getMonth() != parseFloat(month) - 1 || temp_date.getDate() !=
parseFloat(day)) {
return false;
} else {
return true;
}
},
_isAmount: function(value) {
//金额,只允许保留两位小数
return /^([0-9]*[.]?[0-9])[0-9]{0,1}$/.test(value);
},
_isNum: function(value) {
//只能为数字
return /^[0-9]+$/.test(value);
},
_isChinese: function(value) {
let reg = /.*[\u4e00-\u9fa5]+.*$/;
return value !== "" && reg.test(value) && !form._isSpecial(value) && !form._isEmoji(value)
},
_isEnglish: function(value) {
return /^[a-zA-Z]*$/.test(value)
},
// _isEnAndNo: function(value) {
// //8~20位数字和字母组合
// return /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,20}$/.test(value);
// },
_isEnOrNo: function(value) {
//英文或者数字
let reg = /.*[\u4e00-\u9fa5]+.*$/;
let result = true;
if (reg.test(value) || form._isSpecial(value) || form._isEmoji(value)) {
result = false
}
return result
},
_isSpecial: function(value) {
//是否包含特殊字符
let regEn = /[`~!@#$%^&*()_+<>?:"{},.\/;'[\]]/im,
regCn = /[·!#¥(——):;“”‘、,|《。》?、【】[\]]/im;
if (regEn.test(value) || regCn.test(value)) {
return true;
}
return false;
},
_isEmoji: function(value) {
//是否包含表情
return /\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g.test(value);
},
// _isDate: function(value) {
// //2019-10-12
// const reg =
// /^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/;
// return reg.test(value);
// },
_isUrl: function(value) {
return /^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/.test(value);
},
_isSame: function(value1, value2) {
return value1 === value2
},
_isRange: function(value, range1, range2) {
if ((!range1 && range1 != 0) && (!range2 && range2 != 0)) {
return true;
} else if (!range1 && range1 != 0) {
return value <= range2
} else if (!range2 && range2 != 0) {
return value >= range1
} else {
return value >= range1 && value <= range2
}
},
_minLength: function(value, min) {
return value.length >= Number(min)
},
_maxLength: function(value, max) {
return value.length <= Number(max)
}
};
module.exports = {
validation: form.validation
};

View File

@ -0,0 +1,88 @@
/**
* 加法运算避免数据相加小数点后产生多位数和计算精度损失
*
* @param num1加数1 | num2加数2
*/
function numAdd(num1, num2) {
var baseNum, baseNum1, baseNum2;
try {
baseNum1 = num1.toString().split(".")[1].length;
} catch (e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split(".")[1].length;
} catch (e) {
baseNum2 = 0;
}
baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
return (num1 * baseNum + num2 * baseNum) / baseNum;
};
/**
* 加法运算避免数据相减小数点后产生多位数和计算精度损失
*
* @param num1被减数 | num2减数
*/
function numSub(num1, num2) {
var baseNum, baseNum1, baseNum2;
var precision;// 精度
try {
baseNum1 = num1.toString().split(".")[1].length;
} catch (e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split(".")[1].length;
} catch (e) {
baseNum2 = 0;
}
baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
precision = (baseNum1 >= baseNum2) ? baseNum1 : baseNum2;
return ((num1 * baseNum - num2 * baseNum) / baseNum).toFixed(precision);
};
/**
* 乘法运算避免数据相乘小数点后产生多位数和计算精度损失
*
* @param num1被乘数 | num2乘数
*/
function numMulti(num1, num2) {
var baseNum = 0;
try {
baseNum += num1.toString().split(".")[1].length;
} catch (e) {
}
try {
baseNum += num2.toString().split(".")[1].length;
} catch (e) {
}
return Number(num1.toString().replace(".", "")) * Number(num2.toString().replace(".", "")) / Math.pow(10, baseNum);
};
/**
* 除法运算避免数据相除小数点后产生多位数和计算精度损失
*
* @param num1被除数 | num2除数
*/
function numDiv(num1, num2) {
var baseNum1 = 0, baseNum2 = 0;
var baseNum3, baseNum4;
try {
baseNum1 = num1.toString().split(".")[1].length;
} catch (e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split(".")[1].length;
} catch (e) {
baseNum2 = 0;
}
baseNum3 = Number(num1.toString().replace(".", ""));
baseNum4 = Number(num2.toString().replace(".", ""));
return (baseNum3 / baseNum4) * Math.pow(10, baseNum2 - baseNum1);
};
export {
numAdd,
numSub,
numMulti,
numDiv,
}

29
common/js/util/util.js Normal file
View File

@ -0,0 +1,29 @@
export default{
distanceComput: function(distance){
if(distance < 1000){
return distance + "米";
}else if(distance >= 1000){
return (Math.round(distance/100)/10).toFixed(1) + "公里"
}else{
return 0;
}
},
diffSeconds: function (newV) {
const hours = Math.floor(newV / 3600);
const minutes = Math.floor(newV / 60) % 60;
// 拼装数据
return hours? hours + '小时' + minutes + "分钟" : minutes + "分钟";
},
// 计算两个坐标距离
getDistance:function(lat1,lng1,lat2,lng2){
var radLat1 = lat1*Math.PI / 180.0;
var radLat2 = lat2*Math.PI / 180.0;
var a = radLat1 - radLat2;
var b = lng1*Math.PI / 180.0 - lng2*Math.PI / 180.0;
var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
s = s *6378.137 ;// EARTH_RADIUS;
s = Math.round(s * 10000) / 10000;
return s;
}
}

371
common/js/workbench.js Normal file
View File

@ -0,0 +1,371 @@
module.exports = {
teamList:[{
id:1,
name:'海创微联',
imgPath:'../../static/image/workbench/logo.png'
},{
id:2,
name:'智慧物联',
imgPath:''
},{
id:3,
name:'三维数字平台三维数字平台三维数字平台三维数字平台三维数字平台三维数字平台三维数字平台',
imgPath:''
},{
id:4,
name:'海创空天平台',
imgPath:''
}],
bannerlist: [
// 'https://hip.histron.cn/amrept-web/deploy/hcm/ptpz/xtgn/sy/resdir/%E6%BB%9A%E5%8A%A8IAP.png',
// 'https://hip.histron.cn/amrept-web/deploy/hcm/ptpz/xtgn/sy/resdir/%E6%BB%9A%E5%8A%A8EAP.png',
// 'https://hip.histron.cn/amrept-web/deploy/hcm/ptpz/xtgn/sy/resdir/%E6%BB%9A%E5%8A%A8PAAS.png',
'https://www.gkiiot.com/assets/img/images/bannerypt.jpg',
'https://www.gkiiot.com/assets/img/images/bannerzt.jpg'
],
commonList:[
// {
// id:1,
// name:'考勤打卡',
// iconfont:'icon-qiandao-kaoqindaqia',
// iconImg:'',
// bgColor:'#016af9',
// iconBold:false,
// isWebview:false,
// path:'../work/index',
// webviewUrl:''
// },{
// id:2,
// name:'OA审核',
// iconfont:'icon-shenhe',
// iconImg:'',
// bgColor:'#fe9002',
// iconBold:false,
// isWebview:false,
// path:'../work/index',
// webviewUrl:''
// },
// // {
// // id:3,
// // name:'视频会议',
// // iconfont:'',
// // iconImg:'https://hcwl-cdn.cdn.bcebos.com/hcapp/iotos/app/hcworkbench/Videoconferencing.png',
// // bgColor:'#fe9002',
// // iconBold:false,
// // isWebview:true,
// // path:'',
// // webviewUrl:'https://www.baidu.com'
// // },
// {
// id:3,
// name:'视频会议',
// iconfont:'icon-kanban',
// iconImg:'',
// bgColor:'#fe9002',
// iconBold:false,
// isWebview:true,
// path:'',
// webviewUrl:'https://www.baidu.com'
// },
// {
// id:4,
// name:'日志',
// iconfont:'',
// iconImg:'',
// bgColor:'#016af9',
// iconBold:false,
// isWebview:true,
// path:'',
// webviewUrl:'https://element.eleme.cn/#/zh-CN'
// },{
// id:5,
// name:'月报',
// iconfont:'',
// iconImg:'',
// bgColor:'#1ab380',
// iconBold:false,
// isWebview:true,
// path:'',
// webviewUrl:'https://element.eleme.cn/#/zh-CN'
// },{
// id:6,
// name:'设备地图',
// iconfont:'icon-heat-map',
// iconImg:'',
// bgColor:'#ff0000',
// iconBold:false,
// isWebview:false,
// path:'/pages/device/device-map?name=设备位置&isModel=false&type=all&data=[{longitude:119.210333,latitude:26.037021}]',
// webviewUrl:''
// },
{
id:7,
name:'物联网',
iconfont:'icon-hdd',
iconImg:'',
bgColor:'#ff0000',
iconBold:false,
isWebview:false,
path:'/pages/iots/home/index',
webviewUrl:''
},
{
id:8,
name:'可视化',
iconfont:'icon-zutaizu',
iconImg:'',
bgColor:'#ff5500',
iconBold:false,
isWebview:false,
path:'/pages/configuration/configuration-list',
webviewUrl:''
}],
tabsList: [{
name: '海创微联',
},{
name: '海创智家',
},{
name: '智能人事',
}, {
name: '协调效率',
}, {
name: '安全复工'
}, {
name: '未分组'
}],
areaTabsList: [{
name: '全部',
},{
name: '客厅',
},{
name: '未分组'
}],
appList:[
[
{
id:1,
name:'设备',
iconfont:'icon-shebei',
iconImg:'',
bgColor:'#016af9',
iconBold:false,
isWebview:false,
path:'/pages/hcwl/index/device',
webviewUrl:''
},
{
id:2,
name:'组态',
iconfont:'icon-zutaizu',
iconImg:'',
bgColor:'#ff5500',
iconBold:false,
isWebview:false,
path:'/pages/hcwl/configuration/configuration-list',
webviewUrl:''
},
{
id:3,
name:'产品',
iconfont:'icon-chanpin',
iconImg:'',
bgColor:'#ffaa00',
iconBold:false,
isWebview:false,
path:'/pages/hcwl/index/product',
webviewUrl:''
},
{
id:4,
name:'监控',
iconfont:'icon-jiankong',
iconImg:'',
bgColor:'#00aaff',
iconBold:false,
isWebview:false,
path:'/pages/hcwl/video/video-list',
webviewUrl:''
},
{
id:5,
name:'报警信息',
iconfont:'icon-baoxian',
iconImg:'',
bgColor:'#ff0000',
iconBold:false,
isWebview:false,
path:'/pages/hcwl/my/alarm',
webviewUrl:''
}
],
[
{
id:1,
name:'智能',
iconfont:'icon-shouye',
iconImg:'',
bgColor:'#016af9',
iconBold:false,
isWebview:false,
path:'../tabbar/home',
webviewUrl:''
},
{
id:2,
name:'场景',
iconfont:'icon-changjing',
iconImg:'',
bgColor:'#5555ff',
iconBold:false,
isWebview:false,
path:'untapped',
webviewUrl:''
},
{
id:3,
name:'添加设备',
iconfont:'icon-lvzhou_tianjia_shebei',
iconImg:'',
bgColor:'#00aaff',
iconBold:false,
isWebview:false,
path:'untapped',
webviewUrl:''
},
{
id:4,
name:'区域管理',
iconfont:'icon-shezhixitongshezhigongnengshezhishuxing',
iconImg:'',
bgColor:'#ffaa00',
iconBold:false,
isWebview:false,
// path:'/pages/intelligent/region/index',
path:'untapped',
webviewUrl:''
},
{
id:4,
name:'关联音响',
iconfont:'icon-zhinengyouhua',
iconImg:'',
bgColor:'#ff557f',
iconBold:false,
isWebview:false,
path:'untapped',
webviewUrl:''
}
],
[
{
id:1,
name:'考勤打卡',
iconfont:'icon-qiandao-kaoqindaqia',
iconImg:'',
bgColor:'#016af9',
iconBold:false,
isWebview:false,
path:'../work/index',
webviewUrl:''
},{
id:2,
name:'OA审核',
iconfont:'icon-shenhe',
iconImg:'',
bgColor:'#fe9002',
iconBold:false,
isWebview:false,
path:'../work/index',
webviewUrl:''
},
{
id:7,
name:'考勤打卡',
iconfont:'icon-qiandao-kaoqindaqia',
iconImg:'',
bgColor:'#016af9',
iconBold:false,
isWebview:false,
path:'../work/index',
webviewUrl:''
},{
id:8,
name:'OA审核',
iconfont:'icon-shenhe',
iconImg:'',
bgColor:'#fe9002',
iconBold:false,
isWebview:false,
path:'../work/index',
webviewUrl:''
},{
id:3,
name:'视频会议',
iconfont:'',
iconImg:'https://hcwl-cdn.cdn.bcebos.com/hcapp/iotos/app/hcworkbench/Videoconferencing.png',
bgColor:'#fe9002',
iconBold:false,
isWebview:true,
path:'',
webviewUrl:'https://www.baidu.com'
},{
id:4,
name:'日志',
iconfont:'',
iconImg:'',
bgColor:'#016af9',
iconBold:false,
isWebview:true,
path:'',
webviewUrl:'https://element.eleme.cn/#/zh-CN'
},{
id:5,
name:'月报',
iconfont:'',
iconImg:'',
bgColor:'#1ab380',
iconBold:false,
isWebview:true,
path:'',
webviewUrl:'https://element.eleme.cn/#/zh-CN'
}
],
[
{
id:4,
name:'日志',
iconfont:'',
iconImg:'',
bgColor:'#016af9',
iconBold:false,
isWebview:true,
path:'',
webviewUrl:'https://element.eleme.cn/#/zh-CN'
},{
id:5,
name:'月报',
iconfont:'',
iconImg:'',
bgColor:'#1ab380',
iconBold:false,
isWebview:true,
path:'',
webviewUrl:'https://element.eleme.cn/#/zh-CN'
}
],
[
{
id:3,
name:'视频会议',
iconfont:'',
iconImg:'https://hcwl-cdn.cdn.bcebos.com/hcapp/iotos/app/hcworkbench/Videoconferencing.png',
bgColor:'#fe9002',
iconBold:false,
isWebview:true,
path:'',
webviewUrl:'https://www.baidu.com'
}
],
[]
],
}

View File

@ -0,0 +1,273 @@
<!--
* @Description: 生成海报组件
* @Version: 1.0.0
* @Autor: hch
* @Date: 2020-08-07 14:48:41
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-30 09:25:07
* 保存海报按钮和关闭按钮 在html代码中写出来 绑定点击方法然后透明 再用canvas 覆盖
-->
<template>
<view class="content">
<view class="btn" @tap="handleDraw('square1')">正方形</view>
<view class="btn" @tap="handleDraw('square2')">圆角方形</view>
<view class="btn" @tap="handleDraw('square3')">圆形</view>
<view class="btn" @tap="handleDraw('pic1')">图片</view>
<view class="btn" @tap="handleDraw('text1')">左对齐文本</view>
<view class="btn" @tap="handleDraw('text2')">居中对齐文本</view>
<view class="btn" @tap="handleDraw('text3')">右对齐文本</view>
<view
class="canvas-content"
v-show="canvasShow"
:style="'width:' + system.w + 'px; height:' + system.h + 'px;'"
>
<!-- 遮罩层 -->
<view class="canvas-mask"></view>
<!-- :width="system.w" :height="system.h" 支付宝必须要这样设置宽高才有效果 -->
<canvas
class="canvas"
:canvas-id="canvasId"
:id="canvasId"
:style="'width:' + system.w + 'px; height:' + system.h + 'px;'"
:width="system.w"
:height="system.h"
></canvas>
<view class="button-wrapper">
<!-- 保存海报按钮 -->
<!-- #ifndef MP-QQ -->
<!-- cover-view 标签qq小程序有问题 -->
<cover-view class="save-btn cancel-btn" @tap="handleCancel">取消</cover-view>
<!-- #endif -->
<!-- #ifdef MP-QQ -->
<view class="save-btn cancel-btn" @tap="handleCancel">取消</view>
<!-- #endif -->
</view>
</view>
</view>
</template>
<script>
import { drawSquarePic, drawTextReturnH, getSystem } from './utils'
export default {
data() {
return {
canvasId: 'canvas',
system: {},
canvasShow: false,
square1: {
//
x: 40,
y: 40,
r: 0, //
w: 80, //
h: 80 //
},
square2: {
//
x: 40,
y: 40,
r: 10, //
w: 80, //
h: 80 //
},
square3: {
//
x: 40,
y: 40,
r: 40, //
w: 80, //
h: 80 //
},
pic1: {
x: 40,
y: 40,
url: 'https://huangchunhongzz.gitee.io/imgs/poster/product.png',
r: 0, //
w: 250, //
h: 200 //
},
text1: {
x: 0,
y: 40,
text: '今日上新水果,牛奶草莓',
fontSize: 16, //
color: '#000', //
lineHeight: 25, //
mt: 0 //margin-top
},
text2: {
x: 0,
y: 40,
text: '今日上新水果,牛奶草莓',
fontSize: 16, //
color: 'blue', //
lineHeight: 25, //
mt: 0, //margin-top
align: 'center' //
},
text3: {
x: 0,
y: 40,
text: '今日上新水果,牛奶草莓',
fontSize: 16, //
color: 'red', //
lineHeight: 25, //
mt: 0, //margin-top
align: 'right' //
}
}
},
created() {
//
this.system = getSystem()
},
methods: {
/**
* @description: 展示海报
* @param {type}
* @return {type}
* @author: hch
*/
handleDraw(type) {
console.log('handleDraw -> type', type)
this.canvasShow = true
this.draw(type)
},
/**
* @description: 绘制
* @author: hch
*/
draw(type) {
uni.showLoading({
title: '绘制中...'
})
if (this.ctx) {
this.ctx.clearRect(0, 0, this.system.w, this.system.h) //
this.ctx.restore() //canvas
} else {
this.ctx = uni.createCanvasContext(this.canvasId, this)
}
let drawData = this[type]
if (type === 'square1' || type === 'square2' || type === 'square3' || type === 'pic1') {
// /
drawSquarePic(
this.ctx,
drawData.x,
drawData.y,
drawData.w,
drawData.h,
drawData.r,
drawData.url
)
} else {
//
let textY = drawTextReturnH(
this.ctx,
drawData.text,
drawData.x,
drawData.y,
this.system.w,
drawData.fontSize,
drawData.color,
drawData.lineHeight,
drawData.align
)
}
uni.hideLoading()
},
/**
* @description: 取消海报
* @param {type}
* @return {type}
* @author: hch
*/
handleCancel() {
this.canvasShow = false
}
}
}
</script>
<style lang="scss">
.content {
margin-bottom: 80rpx;
overflow: hidden;
border-bottom: 1rpx solid $uni-border-color;
.btn {
float: left;
width: 30%;
margin: 10rpx;
font-size: 30rpx;
line-height: 72rpx;
color: #fff;
text-align: center;
background: $uni-btn-color;
border-radius: 45rpx;
border-radius: 36rpx;
}
}
.canvas-content {
position: absolute;
top: 0;
z-index: 9;
.canvas-mask {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9;
width: 100%;
height: 100%;
background: $uni-btn-color;
}
.canvas {
z-index: 10;
}
.button-wrapper {
position: fixed;
bottom: 20rpx;
z-index: 16;
display: flex;
width: 100%;
height: 72rpx;
justify-content: space-around;
}
.save-btn {
z-index: 16;
width: 40%;
height: 100%;
font-size: 30rpx;
line-height: 72rpx;
color: #fff;
text-align: center;
background: $uni-btn-color;
border-radius: 45rpx;
border-radius: 36rpx;
}
.cancel-btn {
color: $uni-btn-color;
background: #fff;
}
.canvas-close-btn {
position: fixed;
top: 30rpx;
right: 0;
z-index: 12;
width: 60rpx;
height: 60rpx;
padding: 20rpx;
}
}
</style>

View File

@ -0,0 +1,421 @@
<!--
* @Description: 生成海报组件
* @Version: 1.0.0
* @Autor: hch
* @Date: 2020-08-07 14:48:41
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-31 18:11:35
* 保存海报按钮和关闭按钮 在html代码中写出来 绑定点击方法然后透明 再用canvas 覆盖
-->
<template>
<view
class="canvas-content"
v-show="canvasShow"
:style="'width:' + system.w + 'px; height:' + system.h + 'px;'"
>
<!-- 遮罩层 -->
<view class="canvas-mask"></view>
<!-- 海报 -->
<!-- :width="system.w" :height="system.h" 支付宝必须要这样设置宽高才有效果 -->
<canvas
class="canvas"
canvas-id="myCanvas"
id="myCanvas"
:style="'width:' + system.w + 'px; height:' + system.h + 'px;'"
:width="system.w"
:height="system.h"
></canvas>
<view class="button-wrapper">
<!-- 保存海报按钮 -->
<!-- #ifndef MP-QQ -->
<!-- cover-view 标签qq小程序有问题 -->
<view class="save-btn" @tap="handleSaveCanvasImage">保存海报</view>
<view class="save-btn cancel-btn" @tap="handleCanvasCancel">取消</view>
<!-- #endif -->
<!-- #ifdef MP-QQ -->
<view class="save-btn" @tap="handleSaveCanvasImage">保存海报</view>
<view class="save-btn cancel-btn" @tap="handleCanvasCancel">取消</view>
<!-- #endif -->
</view>
</view>
</template>
<script>
import { drawSquarePic, drawTextReturnH, getSystem } from './utils'
export default {
data() {
return {
system: {},
canvasShow: false
}
},
props: {
posterData: {
type: Object,
default: () => {
return {}
}
}
},
computed: {
/**
* @description: 计算海报背景数据
* @param {*}
* @return {*}
* @author: hch
*/
poster() {
let data = this.posterData
let system = this.system
let posterBg = {
url: data.poster.url,
r: data.poster.r * system.scale,
w: data.poster.w * system.scale,
h: data.poster.h * system.scale,
x: (system.w - data.poster.w * system.scale) / 2,
y: (system.h - data.poster.h * system.scale) / 2,
p: data.poster.p * system.scale
}
return posterBg
},
/**
* @description: 计算海报头部主图
* @param {*}
* @return {*}
* @author: hch
*/
mainImg() {
let data = this.posterData
let system = this.system
let posterMain = {
url: data.mainImg.url,
r: data.mainImg.r * system.scale,
w: data.mainImg.w * system.scale,
h: data.mainImg.h * system.scale,
x: (system.w - data.mainImg.w * system.scale) / 2,
y: this.poster.y + data.poster.p * system.scale
}
return posterMain
},
/**
* @description: 计算海报标题
* @param {*}
* @return {*}
* @author: hch
*/
title() {
let data = this.posterData
let system = this.system
let posterTitle = data.title
posterTitle.x = this.mainImg.x
posterTitle.y = this.mainImg.y + this.mainImg.h + data.title.mt * system.scale
return posterTitle
},
/**
* @description: 计算小程序码
* @param {*}
* @return {*}
* @author: hch
*/
codeImg() {
let data = this.posterData
let system = this.system
let posterCode = {
url: data.codeImg.url,
r: data.codeImg.r * system.scale,
w: data.codeImg.w * system.scale,
h: data.codeImg.h * system.scale,
x: this.mainImg.x,
y: data.codeImg.mt * system.scale //yy
}
return posterCode
}
},
created() {
//
this.system = getSystem()
},
methods: {
/**
* @description: 展示海报
* @param {type}
* @return {type}
* @author: hch
*/
posterShow() {
console.log("海报生成软件获取到数据为",this.posterData)
this.canvasShow = true
this.creatPoster()
},
/**
* @description: 生成海报
* @author: hch
*/
async creatPoster() {
uni.showLoading({
title: '生成海报中...'
})
const ctx = uni.createCanvasContext('myCanvas', this)
this.ctx = ctx
ctx.clearRect(0, 0, this.system.w, this.system.h) //
ctx.draw() //
//
let poster = this.poster
let mainImg = this.mainImg
let codeImg = this.codeImg
let title = this.title
console.log("生成海报之前获取的数据为",mainImg)
await drawSquarePic(ctx, poster.x, poster.y, poster.w, poster.h, poster.r, poster.url)
await drawSquarePic(ctx, mainImg.x, mainImg.y, mainImg.w, mainImg.h, mainImg.r, mainImg.url)
// textY y
console.log('creatPoster -> title.x', title.x)
let textY = drawTextReturnH(
ctx,
title.text,
title.x,
title.y,
mainImg.w,
title.fontSize,
title.color,
title.lineHeight,
title.textAlign
)
console.log("绘制小程序码codeImg",codeImg)
//
await drawSquarePic(
ctx,
codeImg.x,
codeImg.y + textY,
codeImg.w,
codeImg.h,
codeImg.r,
codeImg.url
)
//
// /
let y = 0
let x = codeImg.x + codeImg.w + 90
this.posterData.tips.forEach((element, i) => {
if (i == 0) {
y = codeImg.y + textY + codeImg.h/2 - 12
} else {
y += element.mt
}
y = drawTextReturnH(
ctx,
element.text,
x,
y,
mainImg.w,
element.fontSize,
element.color,
element.lineHeight,
element.align
)
})
uni.hideLoading()
},
/**
* @description: 保存到系统相册
* @param {type}
* @return {type}
* @author: hch
*/
handleSaveCanvasImage() {
uni.showLoading({
title: '保存中...'
})
let _this = this
//
// #ifndef MP-ALIPAY
// canvasToTempFilePath
uni.canvasToTempFilePath(
{
x: this.poster.x,
y: this.poster.y,
width: this.poster.w, //
height: this.poster.h, //
destWidth: this.poster.w * 5,
destHeight: this.poster.h * 5,
canvasId: 'myCanvas',
success(res) {
//
// #ifndef H5
// h5
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success(res) {
uni.hideLoading()
uni.showToast({
title: '图片保存成功,可以去分享啦~',
duration: 2000,
icon: 'none'
})
_this.handleCanvasCancel()
},
fail() {
uni.showToast({
title: '保存失败,稍后再试',
duration: 2000,
icon: 'none'
})
uni.hideLoading()
}
})
// #endif
// #ifdef H5
// h5
uni.showToast({
title: '请长按保存',
duration: 3000,
icon: 'none'
})
_this.handleCanvasCancel()
_this.$emit('previewImage', res.tempFilePath)
// #endif
},
fail(res) {
console.log('fail -> res', res)
uni.showToast({
title: '保存失败,稍后再试',
duration: 2000,
icon: 'none'
})
uni.hideLoading()
}
},
this
)
// #endif
// #ifdef MP-ALIPAY
// toTempFilePath
this.ctx.toTempFilePath(
{
x: this.poster.x,
y: this.poster.y,
width: this.poster.w, //
height: this.poster.h, //
destWidth: this.poster.w * 5,
destHeight: this.poster.h * 5,
success(res) {
//
my.saveImage({
url: res.apFilePath,
showActionSheet: true,
success(res) {
uni.hideLoading()
uni.showToast({
title: '图片保存成功,可以去分享啦~',
duration: 2000,
icon: 'none'
})
_this.handleCanvasCancel()
},
fail() {
uni.showToast({
title: '保存失败,稍后再试',
duration: 2000,
icon: 'none'
})
uni.hideLoading()
}
})
},
fail(res) {
console.log('fail -> res', res)
uni.showToast({
title: '保存失败,稍后再试',
duration: 2000,
icon: 'none'
})
uni.hideLoading()
}
},
this
)
// #endif
},
/**
* @description: 取消海报
* @param {type}
* @return {type}
* @author: hch
*/
handleCanvasCancel() {
this.canvasShow = false
this.$emit('cancel', true)
}
}
}
</script>
<style lang="scss">
.content {
height: 100%;
text-align: center;
}
.canvas-content {
position: absolute;
top: 0;
.canvas-mask {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 998;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
}
.canvas {
z-index: 999;
}
.button-wrapper {
position: fixed;
bottom: 20rpx;
z-index: 999;
display: flex;
width: 100%;
height: 72rpx;
justify-content: space-around;
}
.save-btn {
z-index: 1000;
width: 40%;
height: 100%;
font-size: 30rpx;
line-height: 72rpx;
color: #fff;
text-align: center;
background: $uni-btn-color;
border-radius: 45rpx;
border-radius: 36rpx;
}
.cancel-btn {
color: $uni-btn-color;
background: #fff;
}
.canvas-close-btn {
position: fixed;
top: 30rpx;
right: 0;
z-index: 1000;
width: 60rpx;
height: 60rpx;
padding: 20rpx;
}
}
</style>

View File

@ -0,0 +1,148 @@
/*
* @Description: 公共方法
* @Version: 1.0.0
* @Autor: hch
* @Date: 2021-07-22 00:01:09
*/
/**
* @description: 绘制正方形可以定义圆角并且有图片地址的话填充图片
* @param {CanvasContext} ctx canvas上下文
* @param {number} x 圆角矩形选区的左上角 x坐标
* @param {number} y 圆角矩形选区的左上角 y坐标
* @param {number} w 圆角矩形选区的宽度
* @param {number} h 圆角矩形选区的高度
* @param {number} r 圆角的半径
* @param {String} url 图片的url地址
*/
export function drawSquarePic(ctx, x, y, w, h, r, url) {
ctx.save()
ctx.beginPath()
// 绘制左上角圆弧
ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)
// 绘制border-top
// 画一条线 x终点、y终点
ctx.lineTo(x + w - r, y)
// 绘制右上角圆弧
ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)
// 绘制border-right
ctx.lineTo(x + w, y + h - r)
// 绘制右下角圆弧
ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)
// 绘制左下角圆弧
ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)
// 绘制border-left
ctx.lineTo(x, y + r)
// 填充颜色(需要可以自行修改)
ctx.setFillStyle('white')
ctx.fill()
// 剪切剪切之后的绘画绘制剪切区域内进行需要save与restore 这个很重要 不然没办法保存
ctx.clip()
// 绘制图片
return new Promise((resolve, reject) => {
if (url) {
uni.getImageInfo({
src: url,
success(res) {
console.log("图片路径为11",url,res.path)
// #ifdef APP-PLUS
ctx.drawImage(url, x, y, w, h)
// #endif
// #ifdef MP-WEIXIN
ctx.drawImage(res.path, x, y, w, h)
// #endif
ctx.restore() //恢复之前被切割的canvas否则切割之外的就没办法用
ctx.draw(true)
resolve()
},
fail(res) {
console.log('fail -> res', res)
uni.showToast({
title: '图片下载异常',
duration: 2000,
icon: 'none'
})
}
})
} else {
ctx.draw(true)
resolve()
}
})
}
/**
* @description: 获取设备信息
* @param {type}
* @return {type}
* @author: hch
*/
export function getSystem() {
let system = uni.getSystemInfoSync()
let scale = system.windowWidth / 375 //按照苹果留 375*667比例 其他型号手机等比例缩放 显示
return { w: system.windowWidth, h: system.windowHeight, scale: scale }
}
/**
* @description: 绘制文本时文本的总体高度
* @param {Object} ctx canvas上下文
* @param {String} text 需要输入的文本
* @param {Number} x X轴起始位置
* @param {Number} y Y轴起始位置
* @param {Number} maxWidth 单行最大宽度
* @param {Number} fontSize 字体大小
* @param {String} color 字体颜色
* @param {Number} lineHeight 行高
* @param {String} textAlign 字体对齐方式
*/
export function drawTextReturnH(
ctx,
text,
x,
y,
maxWidth = 375,
fontSize = 14,
color = '#000',
lineHeight = 30,
textAlign = 'left'
) {
if (textAlign) {
ctx.setTextAlign(textAlign) //设置文本的水平对齐方式 ctx.setTextAlign这个可以兼容百度小程序 注意ctx.textAlign百度小程序有问题
switch (textAlign) {
case 'center':
x = getSystem().w / 2
break
case 'right':
x = (getSystem().w - maxWidth) / 2 + maxWidth
break
default:
// 左对齐
x = (getSystem().w - maxWidth) / 2
break
}
}
let arrText = text.split('')
let line = ''
for (let n = 0; n < arrText.length; n++) {
let testLine = line + arrText[n]
ctx.font = fontSize + 'px sans-serif' //设置字体大小,注意:百度小程序 用ctx.setFontSize设置字体大小后计算字体宽度会无效
ctx.setFillStyle(color) //设置字体颜色
let metrics = ctx.measureText(testLine) //measureText() 方法返回包含一个对象,该对象包含以像素计的指定字体宽度。
let testWidth = metrics.width
if (testWidth > maxWidth && n > 0) {
ctx.fillText(line, x, y)
line = arrText[n]
y += lineHeight
} else {
line = testLine
}
}
ctx.fillText(line, x, y)
ctx.draw(true) //本次绘制是否接着上一次绘制。即 reserve 参数为 false则在本次调用绘制之前 native 层会先清空画布再继续绘制;若 reserve 参数为 true则保留当前画布上的内容本次调用 drawCanvas 绘制的内容覆盖在上面,默认 false。
return y
}

View File

@ -0,0 +1,189 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
<!-- <view class="select-list">
<uni-data-select
v-model="selectValue"
:localdata="range"
:clear="false"
@change="changeSelect"
></uni-data-select>
</view> -->
</view>
<view class="attr-item-right">
<view class="attr-value item-bar" v-show="charShow">
<qiun-data-charts
type="column"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:reshow="charShow"
:canvasId="canvasId"
/>
</view>
<view class="attr-value item-bar" v-show="!charShow">
<u-empty ></u-empty>
</view>
</view>
</view>
</template>
<script>
import uniDataSelect from "../../uni-data-select/uni-data-select.vue"
export default{
name: 'iots-bar',
props:{
//
value: {
type: [String,Number],
default: false
},
//
dataList:{
type:[String,null],
default:50
},
//
icon: {
type: [String],
default: 'icon-tubiao-zhuzhuangtu'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
}
},
components:{
uniDataSelect
},
data() {
return {
chartData: {},
selectValue:this.value,
charShow: true,
canvasId:this.$u.guid(32),
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [15,15,0,5],
enableScroll: false,
legend: {},
xAxis: {
disableGrid: true
},
yAxis: {
data: [
{
min: 0
}
]
},
extra: {
column: {
type: "group",
width: 30,
activeBgColor: "#000000",
activeBgOpacity: 0.08
}
}
},
range: [
{ value: 0, text: "近1小时" },
{ value: 1, text: "近1天" },
{ value: 2, text: "近1周" },
],
};
},
watch: {
value(newValue) {
this.selectValue = newValue;
}
},
mounted() {
this.getServerData();
this.canvasId=this.$u.guid(32);
},
methods:{
getServerData() {
if(this.dataList){
this.chartData = JSON.parse(this.dataList);
}else{
this.charShow = false;
}
//
// setTimeout(() => {
// //
// let res = {
// categories: ["2018","2019","2020","2021","2022","2023"],
// series: [
// {
// name: "",
// data: [35,36,31,33,13,34]
// },
// {
// name: "",
// data: [18,27,21,24,6,28]
// }
// ]
// };
// this.chartData = JSON.parse(JSON.stringify(res));
// }, 500);
},
//
changeSelect(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
// display: flex;
// align-items: center;
// justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
.select-list{
margin-left: auto;
width: 160rpx;
}
}
.attr-item-right{
// flex: 1;
display: flex;
// flex-wrap: wrap;
align-items: center;
justify-content: center;
.attr-value{
width: 100%;
height: 600rpx;
box-sizing: border-box;
padding-top: 40rpx;
}
}
}
</style>

View File

@ -0,0 +1,234 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
<!-- <view class="select-list">
<uni-data-select
v-model="selectValue"
:localdata="range"
:clear="false"
@change="changeSelect"
></uni-data-select>
</view> -->
</view>
<view class="attr-item-right">
<view class="attr-value item-gauge" v-show="charShow">
<qiun-data-charts
type="gauge"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:reshow="charShow"
:canvasId="canvasId"
/>
</view>
<view class="attr-value item-gauge" v-show="!charShow">
<u-empty></u-empty>
</view>
</view>
</view>
</template>
<script>
import uniDataSelect from "../../uni-data-select/uni-data-select.vue"
export default{
name: 'iots-gauge',
props:{
//
value: {
type: [String,Number],
default: 0
},
//
dataList:{
type:[Object],
default:{series: [{name: '',data: 0}]}
},
//
icon: {
type: [String],
default: 'icon-dashboard2'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
},
//
min:{
type:Number,
default:0
},
//
max:{
type:Number,
default:100
},
unit:{
type: [String],
default: ''
}
},
components:{
uniDataSelect
},
data() {
return {
chartData: {},
selectValue:this.value,
charShow: true,
canvasId:this.$u.guid(32),
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [5,5,5,5],
title: {
name: "60Km/H",
fontSize: 25,
color: "#2fc25b",
offsetY: 50
},
subtitle: {
name: "实时速度",
fontSize: 15,
color: "#666666",
offsetY: -50
},
extra: {
gauge: {
type: "default",
width: 30,
labelColor: "#666666",
startAngle: 0.75,
endAngle: 0.25,
startNumber: 0,
endNumber: 100,
labelFormat: "",
splitLine: {
fixRadius: 0,
splitNumber: 10,
width: 30,
color: "#FFFFFF",
childNumber: 5,
childWidth: 12
},
pointer: {
width: 24,
color: "auto"
},
format:'yAxisDemo2',
// format:function(val, index, opts){return val.toFixed(2)},
}
}
},
range: [
{ value: 0, text: "近1小时" },
{ value: 1, text: "近1天" },
{ value: 2, text: "近1周" },
],
};
},
watch: {
value(newValue) {
if(newValue!==null){
this.getServerData();
}
// // #ifndef H5
// this.getServerData();
// // #endif
}
},
mounted() {
this.canvasId=this.$u.guid(32);
},
methods:{
getServerData() {
if(this.dataList){
console.log("仪表盘数据",this.value)
let list = this.dataList;
this.opts.extra.gauge.startNumber = this.min;
this.opts.extra.gauge.endNumber = this.max.toFixed(2);
this.opts.subtitle.name = list.series[0].name;
this.opts.title.name = this.value + this.unit;
console.log("this.opts",this.opts)
// let obj = {
// categories: [{"value":0.2,"color":"#1890ff"},{"value":0.8,"color":"#2fc25b"},{"value":1,"color":"#f04864"}],
// }
this.chartData = {"categories": [{"value":0.2,"color":"#1890ff"},{"value":0.8,"color":"#2fc25b"},{"value":1,"color":"#f04864"}],"series": this.dataList.series};
// this.chartData = this.dataList;
}else{
this.charShow = false;
}
//
// setTimeout(() => {
// //
// let res = {
// categories: [{"value":0.2,"color":"#1890ff"},{"value":0.8,"color":"#2fc25b"},{"value":1,"color":"#f04864"}],
// series: [
// {
// name: "",
// data: 0.66
// }
// ]
// };
// this.chartData = JSON.parse(JSON.stringify(res));
// }, 500);
},
//
changeSelect(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
// display: flex;
// align-items: center;
// justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
.select-list{
margin-left: auto;
width: 160rpx;
}
}
.attr-item-right{
// flex: 1;
display: flex;
// flex-wrap: wrap;
align-items: center;
justify-content: center;
.attr-value{
width: 100%;
height: 600rpx;
box-sizing: border-box;
padding-top: 40rpx;
}
}
}
</style>

View File

@ -0,0 +1,183 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
<!-- <view class="select-list">
<uni-data-select
v-model="selectValue"
:localdata="range"
:clear="false"
@change="changeSelect"
></uni-data-select>
</view> -->
</view>
<view class="attr-item-right">
<view class="attr-value item-line" v-show="charShow">
<qiun-data-charts
type="line"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:reshow="charShow"
:canvasId="canvasId"
/>
</view>
<view class="attr-value item-line" v-show="!charShow">
<u-empty ></u-empty>
</view>
</view>
</view>
</template>
<script>
import uniDataSelect from "../../uni-data-select/uni-data-select.vue"
export default{
name: 'iots-line',
props:{
//
value: {
type: [String,Number],
default: 0
},
time: {
type: [Number],
default: 0
},
//
icon: {
type: [String],
default: 'icon-tubiao-zhexiantu'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
}
},
components:{
uniDataSelect
},
data() {
return {
chartData: {},
dataList:{
categories:[],
series:[{
name:'',
data:[]
}]
},
selectValue:this.value,
charShow: true,
canvasId:this.$u.guid(32),
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [15,15,0,5],
enableScroll: false,
legend: {show:false},
xAxis: {
disableGrid: true,
// format: "xAxisDemo2"
},
yAxis: {
gridType: "dash",
dashLength: 2,
splitNumber:3,
data:[{tofix:2,min:0}]
},
extra: {
line: {
type: "straight",
width: 2,
activeType: "hollow"
}
},
update:true
},
range: [
{ value: 0, text: "近1小时" },
{ value: 1, text: "近1天" },
{ value: 2, text: "近1周" },
],
};
},
watch: {
value(newValue) {
if(newValue!==null){
// this.selectValue = newValue;
this.getServerData();
}
}
},
mounted() {
// this.getServerData();
this.canvasId=this.$u.guid(32);
},
methods:{
getServerData() {
// this.chartData = JSON.parse(this.dataList);
this.dataList.categories.push(this.$u.timeFormat(this.time,'hh:MM:ss'));
// this.dataList.categories.push(this.time);
this.dataList.series[0].name = this.name;
this.dataList.series[0].data.push(this.value)
this.chartData = this.dataList;
},
//
changeSelect(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
// display: flex;
// align-items: center;
// justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
.select-list{
margin-left: auto;
width: 160rpx;
}
}
.attr-item-right{
// flex: 1;
display: flex;
// flex-wrap: wrap;
align-items: center;
justify-content: center;
.attr-value{
width: 100%;
height: 600rpx;
box-sizing: border-box;
padding-top: 40rpx;
}
}
}
</style>

View File

@ -0,0 +1,174 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
<!-- <view class="select-list">
<uni-data-select
v-model="selectValue"
:localdata="range"
:clear="false"
@change="changeSelect"
></uni-data-select>
</view> -->
</view>
<view class="attr-item-right">
<view class="attr-value item-pie" v-show="charShow">
<qiun-data-charts
type="pie"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:reshow="charShow"
:canvasId="canvasId"
/>
</view>
<view class="attr-value item-pie" v-show="!charShow">
<u-empty></u-empty>
</view>
</view>
</view>
</template>
<script>
import uniDataSelect from "../../uni-data-select/uni-data-select.vue"
export default{
name: 'iots-pie',
props:{
//
value: {
type: [String,Number],
default: false
},
//
dataList:{
type:[String,null],
default:50
},
//
icon: {
type: [String],
default: 'icon-bingtu-xianxing'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
}
},
components:{
uniDataSelect
},
data() {
return {
chartData: {},
selectValue:this.value,
charShow: true,
canvasId:this.$u.guid(32),
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [5,5,5,5],
enableScroll: false,
extra: {
pie: {
activeOpacity: 0.5,
activeRadius: 10,
offsetAngle: 0,
labelWidth: 15,
border: false,
borderWidth: 3,
borderColor: "#FFFFFF"
}
}
},
range: [
{ value: 0, text: "近1小时" },
{ value: 1, text: "近1天" },
{ value: 2, text: "近1周" },
],
};
},
watch: {
value(newValue) {
this.selectValue = newValue;
}
},
mounted() {
this.getServerData();
this.canvasId=this.$u.guid(32);
},
methods:{
getServerData() {
if(this.dataList){
this.chartData = JSON.parse(this.dataList);
}else{
this.charShow = false;
}
// setTimeout(() => {
// //
// let res = {
// series: [
// {
// data: [{"name":"","value":50},{"name":"","value":30},{"name":"","value":20},{"name":"","value":18},{"name":"","value":8}]
// }
// ]
// };
// this.chartData = JSON.parse(JSON.stringify(res));
// }, 500);
},
//
changeSelect(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
// display: flex;
// align-items: center;
// justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
.select-list{
margin-left: auto;
width: 160rpx;
}
}
.attr-item-right{
// flex: 1;
display: flex;
// flex-wrap: wrap;
align-items: center;
justify-content: center;
.attr-value{
width: 100%;
height: 600rpx;
box-sizing: border-box;
padding-top: 40rpx;
}
}
}
</style>

View File

@ -0,0 +1,153 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
</view>
<view class="attr-item-right">
<view class="attr-value item-color-select" @click="changeColor()">
<view class="color-box" :style="{background:value?value:'#f4f5f6'}">
{{value?"":"选择颜色"}}
</view>
<view class="iconfont icon-xiangyou1"></view>
</view>
</view>
<u-popup v-model="colorShow" :closeable="true" mode="bottom" border-radius="10" :safe-area-inset-bottom="true">
<view class="">
<view class="" style="display: flex;justify-content: center;align-items: center;height: 40rpx;margin: 24rpx 0;font-weight: bold;font-size: 34rpx;">
选择颜色
</view>
<zebra-color-picker v-model="colors"></zebra-color-picker>
<!-- <view style="padding: 0 10rpx;">
<u-button type="primary" @click="selectColor">确认颜色</u-button>
</view> -->
<view class="btn-box" @click="selectColor">
<button>确认颜色</button>
</view>
</view>
</u-popup>
</view>
</template>
<script>
/**
* 该组件依赖zebra-color-picker组件https://ext.dcloud.net.cn/plugin?id=9905unimodules
* **/
export default{
name: 'iots-color-select',
props:{
//
value: {
type: [String, Number],
default: ''
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
}
},
data(){
return {
colorShow: false,
colors:{
hex: '#7ED321'
},
}
},
methods:{
changeColor() {
this.colorShow = true;
},
selectColor() {
this.$emit('input', this.colors.hex);
this.$emit('change',this.colors);
this.colorShow = false;
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
// .attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
// }
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
flex: 1;
&.item-color-select {
display: flex;
align-items: center;
justify-content: flex-end;
color: #ccc;
.color-box{
color: #606266;
width: 120rpx;
height: 120rpx;
border-radius: 10rpx;
font-size: 26rpx;
display: flex;
align-items: center;
justify-content: center;
}
.iconfont{
margin-left: 10rpx;
}
}
}
}
}
.btn-box{
position: absolute;
left: 0;
right: 0;
bottom: 0rpx;
padding: 10rpx;
text-align: center;
background: #fff;
z-index: 10076;
button{
height: 100rpx;
line-height: 100rpx;
background-color: $mainColor;
color: #fff;
}
}
</style>

View File

@ -0,0 +1,19 @@
.iots-component-box .attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
}
.iots-component-box .attr-item-left .iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
.iots-component-box .attr-item-left .icon-unordered-list{
margin-left: 16rpx;
margin-right: 0rpx;
font-size: 36rpx;
color: #0b7bff;
}

View File

@ -0,0 +1,115 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
</view>
<view class="attr-item-right">
<view class="attr-value item-border">
<view class="item-img-box">
<image :src="value" @click="lookImg"></image>
</view>
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-switch',
props:{
//
value: {
type: [String],
default: ''
},
//
icon: {
type: [String],
default: 'icon-tupian'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
},
disabled:{
type: [Boolean],
default: true
},
},
data() {
return {
};
},
methods:{
lookImg(){
if(this.value!==''){
uni.previewImage({
urls: [this.value],
});
}
},
//
changeSwitch(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
// .attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
// }
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
.item-img-box{
width: 100rpx;
height:100rpx;
background: #f5f5f5;
image{
width: 100%;
height: 100%;
}
}
}
}
}
</style>

View File

@ -0,0 +1,115 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
</view>
<view class="attr-item-right">
<view class="attr-value item-input">
<input type="text" :placeholder="disabled?'':'请输入'" :disabled="disabled" style="text-align: right;" v-model="inputValue" @input="changeInput"/>
</view>
<text style="margin-left: 6rpx;font-size: 24rpx;">{{unit}}</text>
</view>
</view>
</template>
<script>
export default{
name: 'iots-input',
props:{
//
value: {
type: [String,null],
default: ''
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
},
disabled:{
type: [Boolean],
default: true
},
unit:{
type: [String],
default: ''
},
},
data(){
return {
inputValue:this.vlaue
}
},
created() {
this.inputValue = this.value;
},
watch: {
value(newValue) {
this.inputValue = newValue;
}
},
methods:{
//
changeInput(e) {
this.$emit('input', e.detail.value);
this.$emit('change',e.detail.value);
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
// .attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
// }
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
&.item-input{
input{
flex: 1;
height: 70rpx;
}
}
}
}
}
</style>

View File

@ -0,0 +1,157 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
</view>
<view class="attr-item-right">
<text v-if="disabled">{{value}}</text>
<view v-else class="attr-value item-number">
<number-box :integer="integer"
:min="min"
:max="max"
:step="step"
:value="parseFloat(value)"
@changeValue="changeNumber" style="width: 100%;height: 100%;"></number-box>
</view>
<text style="margin-left: 6rpx;font-size: 24rpx;">&nbsp;&nbsp;{{unit}}</text>
</view>
</view>
</template>
<script>
import NumberBox from '@/components/number-box/NumberBox.vue'
export default{
name: 'iots-number-box',
props:{
//
value: {
type: [ Number,String],
default: 0
},
//
min:{
type:Number,
default:-99999
},
//
max:{
type:Number,
default:99999
},
//
integer: {
type:Boolean,
default:true
},
//
step: {
type:Number,
default:1
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
},
disabled:{
type: [Boolean],
default: true
},
unit:{
type: [String],
default: ''
},
},
components:{
NumberBox
},
data(){
return {
}
},
created() {
console.log("this.vlaue",this.value)
},
methods:{
//
changeNumber(e) {
this.$u.debounce(()=>{
this.$emit('input', e);
this.$emit('change',e);
}, 500)
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
// .attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
// }
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
&.item-number{
flex: 0 1 auto;
width: 250rpx;
display: flex;
align-items: center;
justify-content: flex-end;
color: #ccc;
border: 1px solid #dcdfe6;
border-radius: 8rpx;
/deep/.number-box {
.minus {
border: none;
border-right: 1px solid #dcdfe6;
}
.plus {
border: none;
border-left: 1px solid #dcdfe6;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,133 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
</view>
<view class="attr-item-right">
<view class="attr-value item-select" @click="changeSelect()">
<text
:style="{color:value?'#333':'#ccc'}">{{value!=null?getValue(value):'请选择'}}</text>
<view v-if="!disabled" class="iconfont icon-xiangyou1"></view>
</view>
</view>
<u-picker mode="time" v-model="selectShow" :params="params" :disabled="disabled" @confirm="confirm"></u-picker>
</view>
</template>
<script>
export default{
name: 'iots-select-time',
props:{
//
value: {
type: [String, Number],
default: ''
},
//
icon: {
type: [String],
default: 'icon-xuanze'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
},
disabled:{
type: [Boolean],
default: true
}
},
data(){
return {
selectDefaultValue:[0],
selectShow: false,
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true
},
}
},
methods:{
changeSelect() {
if(!this.disabled){
this.selectShow = true;
}
},
//
getValue(value) {
let time = '';
console.log("uni.getSystemInfoSync().platform",uni.getSystemInfoSync().platform)
if(uni.getSystemInfoSync().platform === 'ios') {
time = this.$u.timeFormat(value, 'yyyy/mm/dd hh:MM:ss');
}else{
time = this.$u.timeFormat(value, 'yyyy-mm-dd hh:MM:ss');
}
return time;
},
confirm(e) {
console.log("当前选择",e)
let time = '';
if(uni.getSystemInfoSync().platform === 'ios') {
time = e.year + '/' + e.month + '/' + e.day + ' ' + e.hour + ':' + e.minute + ':' + e.second;
}else{
time = e.year + '-' + e.month + '-' + e.day + ' ' + e.hour + ':' + e.minute + ':' + e.second;
}
this.$emit('input', time);
this.$emit('change',time);
// this.selectDefaultValue = [this.selectList.findIndex(item => item.value === e[0].value)] || [0];
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
&.item-select {
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: flex-end;
color: #ccc;
.iconfont{
margin-left: 10rpx;
}
}
}
}
}
</style>

View File

@ -0,0 +1,122 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
</view>
<view class="attr-item-right">
<view class="attr-value item-select" @click="changeSelect()">
<text
:style="{color:value?'#333':'#ccc'}">{{value!=null?getVlaue(value):disabled?'--':'请选择'}}</text>
<view v-if="!disabled" class="iconfont icon-xiangyou1"></view>
</view>
</view>
<u-select mode="single-column" :disabled="disabled" :default-value="selectDefaultValue" v-model="selectShow" :list="selectList" @confirm="confirm"></u-select>
</view>
</template>
<script>
export default{
name: 'iots-select',
props:{
//
value: {
type: [String, Number],
default: ''
},
//
selectList:{
type: [Array],
default: [],
},
//
icon: {
type: [String],
default: 'icon-xuanze'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
},
disabled:{
type: [Boolean],
default: true
}
},
data(){
return {
selectDefaultValue:[0],
selectShow: false,
}
},
methods:{
changeSelect() {
if(!this.disabled){
this.selectShow = true;
}
},
//
getVlaue(value) {
console.log("this.selectList[value]",this.selectList,value)
for(let i=0; i<this.selectList.length;i++){
if(this.selectList[i].value == value){
return this.selectList[i].label;
}
}
},
confirm(e) {
console.log("当前选择",e,e[0].value)
this.$emit('input', e[0].value);
this.$emit('change',e[0].value);
this.selectDefaultValue = [this.selectList.findIndex(item => item.value === e[0].value)] || [0];
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
&.item-select {
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: flex-end;
color: #ccc;
.iconfont{
margin-left: 10rpx;
}
}
}
}
}
</style>

View File

@ -0,0 +1,139 @@
<template>
<view class="iots-component-box box-two">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
<view class="attr-item-value">
{{sliderValue}}
<text style="margin-left: 6rpx;font-size: 24rpx;">{{unit}}</text>
</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-slider">
<u-slider
v-model="sliderValue"
:disabled="disabled"
:min="min"
:max="max"
:step="step"
:block-width="BlockWidth"
:height="height"
:block-style="blockStyle"
@end="changeSlider"
></u-slider>
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-slider',
props:{
//
value: {
type: Number,
default: 0
},
//
min:{
type:Number,
default:0
},
//
max:{
type:Number,
default:100
},
//
step: {
type:Number,
default:1
},
// ()rpx
BlockWidth: {
type:Number,
default:40
},
// rpx
height: {
type:Number,
default:12
},
//
icon: {
type: [String],
default: 'icon-redo'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
},
disabled:{
type: [Boolean],
default: true
},
unit:{
type: [String],
default: ''
}
},
data() {
return {
sliderValue: this.value,
blockStyle:{
border:"1px solid #e6e6e6"
}
};
},
watch: {
value(newValue) {
this.sliderValue = newValue;
}
},
methods:{
//
changeSlider() {
console.log("滑动结束")
this.$emit('input', this.sliderValue);
this.$emit('change', this.sliderValue);
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box.box-two{
padding: 20rpx 20rpx;
background: #fff;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
.attr-item-value{
margin-left: auto;
}
}
.attr-item-right{
.attr-value{
padding: 30rpx 20rpx;
}
}
}
</style>

View File

@ -0,0 +1,122 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
</view>
<view class="attr-item-right">
<view class="attr-value item-switch-btn">
<view class="iconfont icon-kaiguan" @click="changeSwitch" :class="switchValue?'active':''"></view>
<!-- <u-button type="primary"><view class="iconfont icon-kaiguan"></view></u-button> -->
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-switch-btn',
props:{
//
value: {
type: Boolean,
default: false
},
//
size:{
type:Number,
default:50
},
//
loading:{
type:Boolean,
default:false
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
}
},
data() {
return {
switchValue: this.value
};
},
watch: {
value(newValue) {
this.switchValue = newValue;
}
},
methods:{
//
changeSwitch() {
let flag = !this.switchValue
console.log("e",flag)
this.$emit('input', flag);
this.$emit('change', flag);
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
// .attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
// }
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
}
}
}
.icon-kaiguan{
padding: 16rpx;
background: #e5e5e5;
color: #7f7f7f;
font-size: 40rpx;
border-radius: 50%;
font-weight: bold;
&.active{
background: #0960ff;
color: #fff;
}
}
</style>

View File

@ -0,0 +1,118 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
</view>
<view class="attr-item-right">
<view class="attr-value item-switch">
<u-switch
v-model="switchValue"
:loading="loading"
:disabled="disabled"
:size="size"
@change="changeSwitch"
></u-switch>
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-switch',
props:{
//
value: {
type: Boolean,
default: false
},
//
size:{
type:Number,
default:50
},
//
loading:{
type:Boolean,
default:false
},
//
icon: {
type: [String],
default: 'icon-m-kaiguan'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
},
disabled:{
type: [Boolean],
default: true
},
},
data() {
return {
switchValue: this.value
};
},
watch: {
value(newValue) {
this.switchValue = newValue;
}
},
methods:{
//
changeSwitch(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
},
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
// .attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
// }
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
}
}
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<view class="iots-component-box" :class="value.length>1?'':'oneFlex'">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view v-if="logShow" class="iconfont icon-unordered-list" @click="clickLog"></view>
</view>
<view class="attr-item-right multi-line" v-if="value.length>1">
<view class="attr-value item-text" v-for="(item,index) in value" :key="index">
<view class="item-value">{{item.value}}<text style="margin-left: 6rpx;font-size: 24rpx;color: #aaa;">{{item.unit}}</text></view>
<view class="item-name">{{item.name}}</view>
</view>
</view>
<view class="attr-item-right" v-else>
<view class="attr-value item-text">
<view>{{value[0].value}}<text style="margin-left: 6rpx;font-size: 24rpx;color: #aaa;">{{value[0].unit}}</text></view>
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-text',
props:{
//
value: {
type:[Array],
default:[{name:'',value:'',unit:''}]
},
//
icon: {
type: [String],
default: 'icon-wenzi'
},
name: {
type: [String],
default: ''
},
logShow:{
type: [Boolean],
default: true
}
},
data() {
return {
};
},
methods:{
clickLog(){
this.$emit('clickLog');
}
}
}
</script>
<style lang="scss" scoped>
@import '../common.css';
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
margin-top: 20rpx;
border-radius: 10rpx;
&.oneFlex{
display: flex;
align-items: center;
justify-content: space-between;
}
// .attr-item-left{
// display: flex;
// align-items: center;
// font-size: 28rpx;
// color: #000;
// .iconfont{
// margin-right: 20rpx;
// font-size: 40rpx;
// }
// }
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
}
&.multi-line{
padding: 20rpx 0;
justify-content: flex-start;
.attr-value{
width: 33%;
height: auto;
flex-direction: column;
flex: 0 1 auto;
.item-value{
font-weight: bold;
font-size: 40rpx;
}
.item-name{
font-size: 24rpx;
color: #aaa;
}
}
}
}
}
</style>

View File

@ -0,0 +1,517 @@
<template>
<view class="uni-stat__select">
<span v-if="label" class="uni-label-text hide-on-phone">{{label + ''}}</span>
<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
<view class="uni-select" :class="{'uni-select--disabled':disabled}">
<view class="uni-select__input-box" @click="toggleSelector">
<view v-if="current" class="uni-select__input-text">{{current}}</view>
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
<view v-if="current && clear && !disabled" @click.stop="clearVal" >
<uni-icons type="clear" color="#c0c4cc" size="24"/>
</view>
<view v-else>
<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
</view>
</view>
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
<view class="uni-select__selector" v-if="showSelector">
<view class="uni-popper__arrow"></view>
<scroll-view scroll-y="true" class="uni-select__selector-scroll">
<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
<text>{{emptyTips}}</text>
</view>
<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" :key="index"
@click="change(item)">
<text :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* DataChecklist 数据选择器
* @description 通过数据渲染的下拉框组件
* @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
* @property {String} value 默认值
* @property {Array} localdata 本地数据 格式 [{text:'',value:''}]
* @property {Boolean} clear 是否可以清空已选项
* @property {Boolean} emptyText 没有数据时显示的文字 本地数据无效
* @property {String} label 左侧标题
* @property {String} placeholder 输入框的提示文字
* @property {Boolean} disabled 是否禁用
* @event {Function} change 选中发生变化触发
*/
export default {
name: "uni-data-select",
mixins: [uniCloud.mixinDatacom || {}],
props: {
localdata: {
type: Array,
default () {
return []
}
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
emptyTips: {
type: String,
default: '无选项'
},
clear: {
type: Boolean,
default: true
},
defItem: {
type: Number,
default: 0
},
disabled: {
type: Boolean,
default: false
},
// field="_id as value, version as text, uni_platform as label" format="{label} - {text}"
format: {
type: String,
default: ''
},
},
data() {
return {
showSelector: false,
current: '',
mixinDatacomResData: [],
apps: [],
channels: [],
cacheKey: "uni-data-select-lastSelectedValue",
};
},
created() {
this.debounceGet = this.debounce(() => {
this.query();
}, 300);
if (this.collection && !this.localdata.length) {
this.debounceGet();
}
},
computed: {
typePlaceholder() {
const text = {
'opendb-stat-app-versions': '版本',
'opendb-app-channels': '渠道',
'opendb-app-list': '应用'
}
const common = this.placeholder
const placeholder = text[this.collection]
return placeholder ?
common + placeholder :
common
},
valueCom(){
// #ifdef VUE3
return this.modelValue;
// #endif
// #ifndef VUE3
return this.value;
// #endif
}
},
watch: {
localdata: {
immediate: true,
handler(val, old) {
if (Array.isArray(val) && old !== val) {
this.mixinDatacomResData = val
}
}
},
valueCom(val, old) {
this.initDefVal()
},
mixinDatacomResData: {
immediate: true,
handler(val) {
if (val.length) {
this.initDefVal()
}
}
}
},
methods: {
debounce(fn, time = 100){
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, time)
}
},
//
query(){
this.mixinDatacomEasyGet();
},
//
onMixinDatacomPropsChange(){
if (this.collection) {
this.debounceGet();
}
},
initDefVal() {
let defValue = ''
if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
defValue = this.valueCom
} else {
let strogeValue
if (this.collection) {
strogeValue = this.getCache()
}
if (strogeValue || strogeValue === 0) {
defValue = strogeValue
} else {
let defItem = ''
if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
defItem = this.mixinDatacomResData[this.defItem - 1].value
}
defValue = defItem
}
if (defValue || defValue === 0) {
this.emit(defValue)
}
}
const def = this.mixinDatacomResData.find(item => item.value === defValue)
this.current = def ? this.formatItemName(def) : ''
},
/**
* @param {[String, Number]} value
* 判断用户给的 value 是否同时为禁用状态
*/
isDisabled(value) {
let isDisabled = false;
this.mixinDatacomResData.forEach(item => {
if (item.value === value) {
isDisabled = item.disable
}
})
return isDisabled;
},
clearVal() {
this.emit('')
if (this.collection) {
this.removeCache()
}
},
change(item) {
if (!item.disable) {
this.showSelector = false
this.current = this.formatItemName(item)
this.emit(item.value)
}
},
emit(val) {
this.$emit('input', val)
this.$emit('update:modelValue', val)
this.$emit('change', val)
if (this.collection) {
this.setCache(val);
}
},
toggleSelector() {
if (this.disabled) {
return
}
this.showSelector = !this.showSelector
},
formatItemName(item) {
let {
label,
value,
channel_code
} = item
channel_code = channel_code ? `(${channel_code})` : ''
if (this.format) {
//
let str = "";
str = this.format;
for (let key in item) {
str = str.replace(new RegExp(`{${key}}`,"g"),item[key]);
}
return str;
} else {
return this.collection.indexOf('app-list') > 0 ?
`${label}(${value})` :
(
label ?
label :
`未命名${channel_code}`
)
}
},
//
getLoadData(){
return this.mixinDatacomResData;
},
// key
getCurrentCacheKey(){
return this.collection;
},
//
getCache(name=this.getCurrentCacheKey()){
let cacheData = uni.getStorageSync(this.cacheKey) || {};
return cacheData[name];
},
//
setCache(value, name=this.getCurrentCacheKey()){
let cacheData = uni.getStorageSync(this.cacheKey) || {};
cacheData[name] = value;
uni.setStorageSync(this.cacheKey, cacheData);
},
//
removeCache(name=this.getCurrentCacheKey()){
let cacheData = uni.getStorageSync(this.cacheKey) || {};
delete cacheData[name];
uni.setStorageSync(this.cacheKey, cacheData);
},
}
}
</script>
<style lang="scss">
$uni-base-color: #6a6a6a !default;
$uni-main-color: #333 !default;
$uni-secondary-color: #909399 !default;
$uni-border-3: #e5e5e5;
/* #ifndef APP-NVUE */
@media screen and (max-width: 500px) {
.hide-on-phone {
display: none;
}
}
/* #endif */
.uni-stat__select {
display: flex;
align-items: center;
// padding: 15px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
width: 100%;
flex: 1;
box-sizing: border-box;
}
.uni-stat-box {
width: 100%;
flex: 1;
}
.uni-stat__actived {
width: 100%;
flex: 1;
// outline: 1px solid #2979ff;
}
.uni-label-text {
font-size: 14px;
font-weight: bold;
color: $uni-base-color;
margin: auto 0;
margin-right: 5px;
}
.uni-select {
font-size: 14px;
border: 1px solid $uni-border-3;
box-sizing: border-box;
border-radius: 4px;
padding: 0 5px;
padding-left: 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
user-select: none;
/* #endif */
flex-direction: row;
align-items: center;
border-bottom: solid 1px $uni-border-3;
width: 100%;
flex: 1;
height: 35px;
&--disabled {
background-color: #f5f7fa;
cursor: not-allowed;
}
}
.uni-select__label {
font-size: 16px;
// line-height: 22px;
height: 35px;
padding-right: 10px;
color: $uni-secondary-color;
}
.uni-select__input-box {
height: 35px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-select__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-select__input-plac {
font-size: 14px;
color: $uni-secondary-color;
}
.uni-select__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
top: calc(100% + 12px);
left: 0;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 3;
padding: 4px 0;
}
.uni-select__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
/* #ifdef H5 */
@media (min-width: 768px) {
.uni-select__selector-scroll {
max-height: 600px;
}
}
/* #endif */
.uni-select__selector-empty,
.uni-select__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 35px;
font-size: 14px;
text-align: center;
/* border-bottom: solid 1px $uni-border-3; */
padding: 0px 10px;
}
.uni-select__selector-item:hover {
background-color: #f9f9f9;
}
.uni-select__selector-empty:last-child,
.uni-select__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.uni-select__selector__disabled {
opacity: 0.4;
cursor: default;
}
/* picker 弹出层通用的指示小三角 */
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-select__input-text {
// width: 280px;
width: 100%;
color: $uni-main-color;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
overflow: hidden;
}
.uni-select__input-placeholder {
color: $uni-base-color;
font-size: 12px;
}
.uni-select--mask {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 2;
}
</style>

View File

@ -0,0 +1,145 @@
/*
该步进器可以设置整数是否最大数最小数步进数支持负数小数
*/
<template>
<view class="number-box">
<view class="minus" :class="{'disabled':selfValue<=min}" @click="minusClick">
<u-icon name="minus" size="28"></u-icon>
</view>
<input class="self-input" type="number" v-model="selfValue" @blur="inputValue"/>
<view class="plus" :class="{'disabled':selfValue>=max}" @click="plusClick">
<u-icon name="plus" size="28" ></u-icon>
</view>
</view>
</template>
<script>
// js
import {numAdd,numSub} from '@/common/js/util/js-calculate.js'
export default{
data(){
return{
selfValue: 0
}
},
props:{
//
min:{
type:Number,
default:-99999
},
//
max:{
type:Number,
default:99999
},
//
value:{
type:Number,
default:0
},
//
integer: {
type:Boolean,
default:true
},
//
step: {
type:Number,
default:1
},
},
created() {
this.selfValue = this.value;
},
watch: {
selfValue(newValue) {
this.$emit('changeValue', newValue)
},
value(){
if (this.value != this.selfValue) {
this.selfValue = this.value
}
}
},
methods:{
//
inputValue(event){
let val = event.detail.value;
val = val.replace(/[^0-9.]/g, '');
if(this.integer){
val = parseInt(val);
}
if(val <= this.min){
val = this.min;
}
if (val >= this.max) {
val = this.max;
}
this.$nextTick(() => {
this.selfValue = val;
})
},
//
minusClick(){
let jvalue = numSub(this.selfValue,this.step);
if (this.selfValue <= this.min || jvalue <= this.min) {
this.selfValue = this.min
return
}else if (this.selfValue > this.max || jvalue > this.max) {
this.selfValue = this.max
return
}
this.selfValue = jvalue;
},
//
plusClick(){
let jvalue = numAdd(this.selfValue,this.step);
if (this.selfValue < this.min || jvalue < this.min) {
this.selfValue = this.min
return
}else if (this.selfValue >= this.max || jvalue >= this.max) {
this.selfValue = this.max
return
}
this.selfValue = jvalue;
},
}
}
</script>
<style>
.number-box{
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100%;
}
.minus,.plus{
flex: 1;
height: 100%;
background: #f5f7fa;
border: 1px solid #DCDFE6;
color: #333;
display: flex;
align-items: center;
justify-content: center;
}
.disabled{
background: #f8f8f8;
color: #ccc;
}
.self-input{
width: 120rpx;
height: 100%;
background: #fff;
text-align: center;
line-height: 100%;
color: #333;
}
</style>

51
main.js Normal file
View File

@ -0,0 +1,51 @@
import Vue from 'vue'
import App from './App'
import request from '@/network/request.js'
import {url,wsUrl,configurationUrl,configurationhtmlUrl} from '@/network/config.js'
import store from '@/store/index.js'
import {Base64} from '@/static/common/js/base64.js'
import api from '@/network/api/index.js'
let staticPath = '';
// #ifdef MP-WEIXIN
staticPath = 'https://file.iot-fast.com/wxapp/static'
// #endif
// #ifndef MP-WEIXIN
staticPath = '@/static'
// #endif
Vue.prototype.$staticPath = staticPath;
Vue.prototype.$store = store;
Vue.prototype.$request = request;
Vue.prototype.$url = url;
Vue.prototype.$wsUrl = wsUrl;
Vue.prototype.$configurationUrl = configurationUrl;
Vue.prototype.$configurationhtmlUrl = configurationhtmlUrl;
Vue.prototype.$urlParameter = '/prod-api';
// 引入全局uView
import uView from 'uview-ui'
Vue.use(uView);
import NavBar from '@/common/components/navbar/NavBar.vue'
Vue.component('NavBar',NavBar)
let mpShare = require('uview-ui/libs/mixin/mpShare.js');
Vue.mixin(mpShare)
Vue.prototype.$api = api;
// Vue.prototype.$htoProtocol = htoProtocol;
// Vue.prototype.$wsProtocol = wsProtocol;
Vue.prototype.$Base64 = new Base64();
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()

237
manifest.json Normal file
View File

@ -0,0 +1,237 @@
{
"name" : "物联网可视化",
"appid" : "__UNI__604B8F1",
"description" : "",
"versionName" : "1.0.22",
"versionCode" : 1022,
"transformPx" : false,
/* 5+App */
"app-plus" : {
"safearea" : {
"bottom" : {
"offset" : "none"
}
},
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {
"Share" : {},
"VideoPlayer" : {},
"Camera" : {},
"Barcode" : {},
"Bluetooth" : {},
"iBeacon" : {},
"Geolocation" : {},
"Maps" : {}
},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a" ]
},
/* ios */
"ios" : {
"idfa" : true,
"dSYMs" : false
},
/* SDK */
"sdkConfigs" : {
"ad" : {},
"share" : {
"weixin" : {
"appid" : "wx46adebdae20b899f",
"UniversalLinks" : ""
}
},
"geolocation" : {
"amap" : {
"__platform__" : [ "ios", "android" ],
"appkey_ios" : "e1b8f62e3438ef2b1101a56a5d64ce18",
"appkey_android" : "e1b8f62e3438ef2b1101a56a5d64ce18"
}
},
"maps" : {
"amap" : {
"appkey_ios" : "e1b8f62e3438ef2b1101a56a5d64ce18",
"appkey_android" : "e1b8f62e3438ef2b1101a56a5d64ce18"
}
}
},
"splashscreen" : {
"iosStyle" : "common",
"androidStyle" : "common",
"useOriginalMsgbox" : false
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
},
"uniStatistics" : {
"enable" : true
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx27c271b0cb420015",
"setting" : {
"urlCheck" : false,
"postcss" : true,
"minified" : true,
"es6" : true
},
"usingComponents" : true,
"uniStatistics" : {
"enable" : true
}
},
"mp-alipay" : {
"usingComponents" : true,
"uniStatistics" : {
"enable" : false
}
},
"mp-baidu" : {
"usingComponents" : true,
"uniStatistics" : {
"enable" : false
}
},
"mp-toutiao" : {
"usingComponents" : true,
"uniStatistics" : {
"enable" : false
}
},
"h5" : {
"template" : "template.h5.html",
"router" : {
"mode" : "history"
},
"devServer" : {
"port" : 8080, //
"disableHostCheck" : true,
"proxy" : {
"/api" : {
"target" : "http://192.168.18.139", //
"changeOrigin" : true, //
"secure" : true, // https
"pathRewrite" : {
"^/api" : "/"
}
}
}
},
"uniStatistics" : {
"enable" : false
}
},
"orientation" : [
//
"portrait-primary",
//
"portrait-secondary",
//
"landscape-primary",
//
"landscape-secondary",
//
"default"
],
"uniStatistics" : {
"enable" : false,
"version" : "2"
},
"mp-jd" : {
"uniStatistics" : {
"enable" : false
}
},
"mp-kuaishou" : {
"uniStatistics" : {
"enable" : false
}
},
"mp-lark" : {
"uniStatistics" : {
"enable" : false
}
},
"mp-qq" : {
"uniStatistics" : {
"enable" : false
}
},
"quickapp-webview-huawei" : {
"uniStatistics" : {
"enable" : false
}
},
"quickapp-webview-union" : {
"uniStatistics" : {
"enable" : false
}
}
}

View File

@ -0,0 +1,60 @@
import request from "../../request.js"
export default {
// 获取组态场景列表
getConfigurationListData(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/console/admin/scene/list',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 获取组态分享列表
getConfigurationShareList(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/console/admin/share/list',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 新增组态
addConfigurationShare(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/console/admin/share/add',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 删除组态
delConfigurationShare(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/console/admin/share/delete',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
}

117
network/api/index.js Normal file
View File

@ -0,0 +1,117 @@
import request from "../request.js"
export default {
// iots物联网模块
iotsApi:require("./iots/index.js").default,
// 组态模块
configurationApi:require("./configuration/index.js").default,
// 消息模块
newApi:require("./new.js").default,
// 获取图片验证码
getImgCode(data){
return new Promise((resolve, reject) => {
request.customRequest({
url: '/user/admin/site/captcha',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 账号密码登录
passwordLogin(data){
return new Promise((resolve, reject) => {
request.customRequest({
url: '/user/admin/site/accountLogin',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 发送短信验证码
sendSms(data){
return new Promise((resolve, reject) => {
request.customRequest({
url: '/admin/admin/sms/send',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 手机号登录
mobileLogin(data){
return new Promise((resolve, reject) => {
request.customRequest({
url: '/user/admin/site/mobileLogin',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 获取用户信息
getUserInfo(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/user/admin/member/info',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 获取用户菜单
getUserMenu(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/user/admin/menu/list',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 修改密码
updatePwd(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/user/admin/member/updatePwd',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
}

184
network/api/iots/index.js Normal file
View File

@ -0,0 +1,184 @@
import request from "../../request.js"
export default {
// 获取设备统计数量
getDeviceCount(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/device/statistics/count',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 获取产品列表
getProductList(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/product/list',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 获取设备列表
getDeviceList(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/device/list',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 获取指定设备信息
getDeviceInfo(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/device/view',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 设备属性下发
downDeviceProp(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/device/data/prop/down',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 属性数据列表
getDeviceDataList(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/device/ts/prop/list',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 设备属性下发
downDeviceAbility(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/device/data/down',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 告警
// 告警记录数量统计
getAlarmReacordCount(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/alarm/record/count',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 告警记录列表
getAlarmReacordList(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/alarm/record/list',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 告警级别列表
getAlarmLevelList(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/alarm/level/list',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 概览页统计(图表)
getAlarmRecordStat(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/alarm/record/stat',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 告警记录审核
applyAlarmRecord(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/iot/admin/alarm/record/apply',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
}

88
network/api/new.js Normal file
View File

@ -0,0 +1,88 @@
import request from "../request.js"
export default {
// 公告消息数量(展示)
getNoticeCount(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/admin/admin/notice/count/all',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 未读消息数量(展示)
getNewsCount(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/admin/admin/notice/count/un/read',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 系统公告列表(展示)
getNoticeList(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/admin/admin/notice/public/messages',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 我的消息列表(展示)
getNewsList(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/admin/admin/notice/my/messages',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 消息全部已读(展示)
getNewReadAll(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/admin/admin/notice/read/all',
method: 'POST',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
// 获取详细(展示)
getNoticeDetail(data){
return new Promise((resolve, reject) => {
request.TokenRequest({
url: '/admin/admin/notice/detail',
method: 'GET',
},data)
.then((res) =>{
resolve(res);
}).catch(err =>{
reject(err);
})
})
},
}

36
network/config.js Normal file
View File

@ -0,0 +1,36 @@
// let url = "http://192.168.21.190"
// let wsUrl = "ws://192.168.21.190"
let htoProtocol = "http://"
let wsProtocol = "ws://"
let url = ""
let wsUrl = ""
// 组态请求地址
let configurationUrl = "";
// 组态页面地址
let configurationhtmlUrl = "";
if(process.env.NODE_ENV === 'development'){
// 开发环境
// url = 'http://iotos-ui-dev.iotos.192.168.10.243.nip.io:32764'
// wsUrl = "ws://iotos-ui-dev.iotos.192.168.10.243.nip.io:32764"
// configurationUrl = "http://192.168.18.139:8855"
// configurationhtmlUrl = "http://hceditor-2d-dev.hceditor.192.168.10.243.nip.io:30405"
url = 'https://miot.gkiiot.com'
wsUrl = 'wss://miot.gkiiot.com'
configurationUrl = 'https://2d.gkiiot.com/prod-api'
configurationhtmlUrl = 'https://2d.gkiiot.com'
}else{
// 生产环境
url = 'https://miot.gkiiot.com'
wsUrl = 'wss://miot.gkiiot.com'
configurationUrl = 'https://2d.gkiiot.com/prod-api'
configurationhtmlUrl = 'https://2d.gkiiot.com'
}
export {
url,
wsUrl,
configurationUrl,
configurationhtmlUrl,
htoProtocol,
wsProtocol
}

183
network/request.js Normal file
View File

@ -0,0 +1,183 @@
import store from '@/store/index.js'
import {url,wsUrl,htoProtocol} from './config.js'
const customRequest = (opts, data) => {
let configList = uni.getStorageSync('configList');
let configIndex = uni.getStorageSync('configIndex');
if(!configList || configIndex==-1){
uni.showToast({
title: '请求域名为空,请先添加',
icon: 'none',
duration: 1500
})
setTimeout(()=>{
uni.navigateTo({
url:'/pages/tabbar/config'
})
},1500)
return null;
}else{
let basicDefaultOpts = {
url: configList[configIndex].protocol + configList[configIndex].address + opts.url,
data: data,
method: opts.method,
header: opts.header,
}
let promise = new Promise(function(resolve, reject) {
uni.request(basicDefaultOpts).then((res) => {
console.log("res",res);
resolve(res[1].data)
if(Object.prototype.toString.call(res[1].data) !== '[object Object]'){
uni.showToast({
title: '请求错误,请检查域名是否错误',
icon: 'none',
duration: 1500
})
}
}).catch(
(response) => {
console.log("response",JSON.stringify(response));
reject(response)
}
)
})
// console.log(JSON.stringify(promise));
return promise
}
};
const basicRequest = (opts, data) => {
let basicDefaultOpts = {
url: url + opts.url,
data: data,
method: opts.method,
header: opts.header,
}
let promise = new Promise(function(resolve, reject) {
uni.request(basicDefaultOpts).then((res) => {
// console.log(JSON.stringify(res));
resolve(res[1].data)
}).catch(
(response) => {
reject(response)
}
)
})
// console.log(JSON.stringify(promise));
return promise
};
//带Token请求
const TokenRequest = (opts, data) => {
let tokenKey = uni.getStorageSync('token');
let configList = uni.getStorageSync('configList');
let configIndex = uni.getStorageSync('configIndex');
if(!configList || configIndex==-1){
uni.showToast({
title: '请求域名为空,请先添加',
icon: 'none',
duration: 1500
})
setTimeout(()=>{
uni.navigateTo({
url:'/pages/tabbar/config'
})
},1500)
return null;
}else{
// tokenKey = store.getters.tokenKey;
//此token是登录成功后后台返回保存在storage中的
let DefaultOpts = {
url: configList[configIndex].protocol + configList[configIndex].address + opts.url,
data: data,
method: opts.method,
header: {
'Authorization': tokenKey,
},
}
let promise = new Promise(function(resolve, reject) {
uni.request(DefaultOpts).then(
(res) => {
// console.log("请求返回",res)
// 令牌过期关闭所有页面跳转登录页
if(res[1].data.code==61){
uni.showToast({
title: '登录已过期,请重新登录',
icon: 'none',
duration: 1500
})
store.commit('setTokenKey', '');
uni.removeStorageSync('token');
setTimeout(()=>{
uni.reLaunch({url:'/pages/tabbar/login'});
},1500)
}else if(res[1].data.code>0){
uni.showToast({
title: res[1].data.message,
icon: 'none',
duration: 1500
})
}
resolve(res[1].data)
}
).catch(
(response) => {
console.log("请求报错",response)
uni.showToast({
title: '服务器开小差了呢,请您稍后再试',
icon: 'none',
duration: 1500
})
reject(response)
}
)
})
// console.log(JSON.stringify(promise));
return promise
}
}
//自带url请求不使用公共域名的Token请求
const TokenURlRequest = (opts, data) => {
let tokenKey = uni.getStorageSync('token');
// tokenKey = store.getters.tokenKey;
//此token是登录成功后后台返回保存在storage中的
let DefaultOpts = {
url: opts.url,
data: data,
method: opts.method,
header: {
'Authorization': 'Bearer '+tokenKey,
},
}
let promise = new Promise(function(resolve, reject) {
uni.request(DefaultOpts).then(
(res) => {
// 令牌过期关闭所有页面跳转登录页
if(res[1].data.error=="invalid_token"){
uni.reLaunch({url:'/pages/index/login'});
}
resolve(res[1].data)
}
).catch(
(response) => {
reject(response)
}
)
})
// console.log(JSON.stringify(promise));
return promise
}
// 将对象导出外部引入使用
export default{
// baseUrl,
customRequest,
basicRequest,
TokenRequest,
TokenURlRequest
}

16
package.json Normal file
View File

@ -0,0 +1,16 @@
{
"id": "hch-poster",
"name": "canvas 生成海报",
"version": "3.2.2",
"description": "分享弹窗,生成海报并支持保存,支持多端H5微信小程序支付宝小程序百度小程序字节跳动小程序QQ小程序",
"keywords": [
"分享",
"海报",
"自定义图片",
"小程序码",
"商城商品分享海报。"
],
"dependencies": {
"crypto-js": "^4.2.0"
}
}

449
pages.json Normal file
View File

@ -0,0 +1,449 @@
{
"easycom": {
// "autoscan": true,
"custom":{
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
}
},
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/tabbar/login",
"style": {
"navigationBarTitleText": "登录页",
"navigationStyle":"custom",
"app-plus": {
"softinputMode": "adjustResize"
}
}
},
{
"path": "pages/tabbar/config",
"style": {
"navigationBarTitleText": "域名配置"
}
},
// {
// "path": "pages/index/forget-password",
// "style": {
// "navigationBarTitleText": "忘记密码",
// "navigationStyle":"custom"
// }
// },
{
"path": "pages/tabbar/new",
"style": {
"navigationBarTitleText": "消息",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "pages/tabbar/workbench",
"style": {
"navigationBarTitleText": "工作台",
"navigationStyle": "custom"
}
},
{
"path": "pages/tabbar/home",
"style": {
"navigationBarTitleText": "首页",
"navigationStyle": "custom"
}
},
{
"path": "pages/tabbar/my",
"style": {
"navigationBarTitleText": "我的",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "pages/tabbar/module/intelligent",
"style": {
"navigationBarTitleText": "智能"
}
},
{
"path": "pages/tabbar/scan",
"style": {
"navigationBarTitleText": "扫一扫"
}
},
{
"path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup",
"style": {
"disableScroll": true,
"app-plus": {
"backgroundColorTop": "transparent",
"background": "transparent",
"titleNView": false,
"scrollIndicator": false,
"popGesture": "none",
"animationType": "fade-in",
"animationDuration": 200
}
}
}
],
"subpackages": [
{
"root": "pages/new/",
"pages": [
{
"path": "detail",
"style": {
"navigationBarTitleText":"消息详情"
}
}
]
},
{
"root": "pages/my/",
"pages": [
{
"path": "reset-password",
"style": {
"navigationBarTitleText":"修改密码"
}
},
{
"path": "replace-phone",
"style": {
"navigationBarTitleText":"换绑手机"
}
}
]
},
{
"root": "pages/intelligent/",
"pages": [
{
"path": "template/public/public1",
"style": {
"navigationBarTitleText":"通用设备"
}
},
{
"path": "template/light/light1",
"style": {
"navigationBarTitleText":"灯类设备"
}
},
{
"path": "region/index",
"style": {
"navigationBarTitleText":"区域管理"
}
}
]
},
{
"root": "pages/webview/",
"pages": [
{
"path": "index",
"style": {
"navigationBarTitleText":"webview"
}
}
]
},
{
"root": "pages/work/",
"pages": [
{
"path": "index",
"style": {
"navigationBarTitleText":"应用内默认页"
}
},
{
"path": "webview",
"style": {
"navigationBarTitleText":"应用内嵌页"
}
}
]
},
{
"root": "pages/iots/",
"pages": [
{
"path": "home/index",
"style": {
"navigationBarTitleText":"物联网"
}
},
{
"path": "device/device-list",
"style": {
"navigationBarTitleText":"设备列表"
}
},
{
"path": "notice/index",
"style": {
"navigationBarTitleText":"告警"
}
},
{
"path": "notice/list",
"style": {
"navigationBarTitleText":"告警列表"
}
},
{
"path": "device/device-detail",
"style": {
"navigationBarTitleText":"设备详情"
// "componentPlaceholder": {
// // "其他分包自定义组件": "占位组件"
// "package-com": "view"
// }
}
},
{
"path": "device/device-control",
"style": {
"navigationBarTitleText":"设备控制"
}
},
{
"path": "device/device-alarm",
"style": {
"navigationBarTitleText":"设备报警"
}
},
{
"path": "device/device-data",
"style": {
"navigationBarTitleText":"历史数据"
}
},
{
"path": "device/device-ability-list",
"style": {
"navigationBarTitleText":"设备功能列表"
}
},
{
"path": "device/device-ability-detail",
"style": {
"navigationBarTitleText":"设备功能详情"
}
},
{
"path": "map/device-map",
"style": {
"navigationBarTitleText":"设备地图"
}
}
]
},
//
{
"root": "pages/configuration/",
"pages": [
{
"path": "configuration-list",
"style": {
"navigationBarTitleText": "组态列表"
// "navigationStyle":"custom"
}
},
{
"path": "configuration-detail",
"style": {
// "navigationStyle": "default",
"navigationBarTitleText": "组态详情",
// "navigationBarBackgroundColor":"#1b85e9",
// "navigationBarTextStyle":"white",
"pageOrientation":"landscape"
// #ifdef APP-PLUS
,
"navigationStyle":"custom"
// #endif
}
},
{
"path": "configuration-transfer",
"style": {
"navigationBarTitleText": "组态跳转"
}
},
{
"path": "configuration-appgo",
"style": {
"navigationBarTitleText": "app跳转"
}
},
{
"path": "configuration-share",
"style": {
"navigationBarTitleText": "组态分享列表"
}
}
]
}
],
"globalStyle": {
// "navigationStyle": "custom",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uView",
"navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#FFFFFF"
},
"tabBar": {
"color": "#666666",
"selectedColor": "#369EFF",
"borderStyle": "black",
"backgroundColor": "#ffffff",
// #ifdef APP-PLUS
"midButton":{
"width": "57px",
"height": "78px",
"iconWidth": "57px",
"iconPath":"static/image/tabbar/app-scan.png",
"text": "扫一扫"
},
// #endif
"list": [{
"pagePath": "pages/tabbar/home",
"iconPath": "static/image/tabbar/home.png",
"selectedIconPath": "static/image/tabbar/home-active.png",
"text": "首页"
},{
"pagePath": "pages/tabbar/workbench",
"iconPath": "static/image/tabbar/workbench.png",
"selectedIconPath": "static/image/tabbar/workbench-active.png",
"text": "工作台"
},
// #ifdef MP-WEIXIN
{
"pagePath": "pages/tabbar/scan",
"iconPath": "static/image/tabbar/scan.png",
"selectedIconPath": "static/image/tabbar/scan-active.png",
"text": "扫一扫"
},
// #endif
{
"pagePath": "pages/tabbar/new",
"iconPath": "static/image/tabbar/new.png",
"selectedIconPath": "static/image/tabbar/new-active.png",
"text": "消息"
},
{
"pagePath": "pages/tabbar/my",
"iconPath": "static/image/tabbar/my.png",
"selectedIconPath": "static/image/tabbar/my-active.png",
"text": "我的"
}]
},
"condition": { //
"current": 0, //(list )
"list": [
// {
// "name": "欢迎", //
// "path": "pages/tabbar/welcome", //
// "query": "" //onLoad
// },
{
"name": "登录", //
"path": "pages/tabbar/login", //
"query": "" //onLoad
},
{
"name": "工作台", //
"path": "pages/tabbar/workbench", //
"query": "" //onLoad
},
{
"name": "我的", //
"path": "pages/tabbar/my", //
"query": "" //onLoad
},
{
"name": "消息", //
"path": "pages/tabbar/new", //
"query": "" //onLoad
},
{
"name": "首页", //
"path": "pages/tabbar/home", //
"query": "" //onLoad
},
{
"name": "公用模板1", //
"path": "pages/intelligent/template/public/public1", //
"query": "" //onLoad
},
{
"name": "区域管理", //
"path": "pages/intelligent/region/index", //
"query": "" //onLoad
},
{
"name": "域名配置", //
"path": "pages/tabbar/config", //
"query": "" //onLoad
},
{
"name": "换绑手机", //
"path": "pages/my/replace-phone", //
"query": "" //onLoad
},
{
"name": "设备地图", //
"path": "pages/iots/map/device-map", //
"query": "name=设备位置&isModel=false&type=all&data=[{longitude:119.210333,latitude:26.037021}]" //onLoad
},
{
"name": "物联网", //
"path": "pages/iots/home/index", //
"query": "" //onLoad
},
{
"name": "设备列表", //
"path": "pages/iots/device/device-list", //
"query": "" //onLoad
},
{
"name": "告警", //
"path": "pages/iots/notice/index", //
"query": "" //onLoad
},
{
"name": "告警列表", //
"path": "pages/iots/notice/list", //
"query": "" //onLoad
},
{
"name": "设备详情", //
"path": "pages/iots/device/device-detail", //
"query": "id=58093&devName=测试设备信息" //onLoad
// "query": "id=58109&devName=手机端测试设备" //onLoad
},
{
"name": "设备数据", //
"path": "pages/iots/device/device-data", //
"query": "" //onLoad
},
{
"name": "设备功能列表", //
"path": "pages/iots/device/device-ability-list", //
"query": "abilityList=%5B%7B%22callType%22%3A%22async%22%2C%22identifier%22%3A%22s1%22%2C%22ioObj%22%3A%7B%22IoDeployForm%22%3A%7B%7D%2C%22in%22%3A%5B%7B%22IoDeployForm%22%3A%7B%22length%22%3A%2220%22%7D%2C%22ioDataType%22%3A%22string%22%2C%22ioDataTypeName%22%3A%22%E5%AD%97%E7%AC%A6%E4%B8%B2%22%2C%22ioFormType%22%3A%22text%22%2C%22ioKey%22%3A%22p1%22%2C%22ioName%22%3A%22%E5%8F%82%E6%95%B01%22%2C%22ioRequired%22%3Atrue%7D%2C%7B%22IoDeployForm%22%3A%7B%22max%22%3A%2250%22%2C%22step%22%3A%221%22%7D%2C%22ioDataType%22%3A%22float%22%2C%22ioDataTypeName%22%3A%22%E6%B5%AE%E7%82%B9%E5%9E%8B%22%2C%22ioFormType%22%3A%22number%22%2C%22ioKey%22%3A%22p2%22%2C%22ioName%22%3A%22canshu2%22%7D%5D%2C%22verification%22%3A%7B%22required%22%3Afalse%7D%7D%2C%22name%22%3A%22%E5%8A%9F%E8%83%BD1%22%7D%2C%7B%22callType%22%3A%22sync%22%2C%22identifier%22%3A%22s2%22%2C%22ioObj%22%3A%7B%22IoDeployForm%22%3A%7B%7D%2C%22in%22%3A%5B%7B%22IoDeployForm%22%3A%7B%7D%2C%22ioDataType%22%3A%22string%22%2C%22ioDataTypeName%22%3A%22%E5%AD%97%E7%AC%A6%E4%B8%B2%22%2C%22ioFormType%22%3A%22text%22%2C%22ioKey%22%3A%22cs1%22%2C%22ioName%22%3A%22%E6%96%87%E6%9C%AC%22%2C%22ioRequired%22%3Atrue%7D%2C%7B%22IoDeployForm%22%3A%7B%22max%22%3A%22100%22%2C%22min%22%3A%220%22%2C%22step%22%3A%221%22%7D%2C%22ioDataType%22%3A%22int%22%2C%22ioDataTypeName%22%3A%22%E6%95%B4%E5%9E%8B%22%2C%22ioFormType%22%3A%22number%22%2C%22ioKey%22%3A%22cs2%22%2C%22ioName%22%3A%22%E6%95%B0%E5%AD%97%22%2C%22ioRequired%22%3Atrue%7D%2C%7B%22IoDeployForm%22%3A%7B%7D%2C%22ioDataType%22%3A%22bool%22%2C%22ioDataTypeName%22%3A%22%E5%B8%83%E5%B0%94%E5%9E%8B%22%2C%22ioFormType%22%3A%22switch%22%2C%22ioKey%22%3A%22cs3%22%2C%22ioName%22%3A%22%E5%BC%80%E5%85%B3%22%2C%22ioRequired%22%3Atrue%7D%2C%7B%22IoDeployForm%22%3A%7B%22max%22%3A%2250%22%2C%22min%22%3A%220%22%2C%22step%22%3A%222%22%7D%2C%22ioDataType%22%3A%22int%22%2C%22ioDataTypeName%22%3A%22%E6%95%B4%E5%9E%8B%22%2C%22ioFormType%22%3A%22slider%22%2C%22ioKey%22%3A%22cs4%22%2C%22ioName%22%3A%22%E8%BF%9B%E5%BA%A6%E6%9D%A1%22%2C%22ioRequired%22%3Atrue%7D%2C%7B%22IoDeployForm%22%3A%7B%7D%2C%22ioDataType%22%3A%22string%22%2C%22ioDataTypeName%22%3A%22%E5%AD%97%E7%AC%A6%E4%B8%B2%22%2C%22ioFormType%22%3A%22time_picker%22%2C%22ioKey%22%3A%22cs6%22%2C%22ioName%22%3A%22%E6%97%B6%E9%97%B4%22%2C%22ioRequired%22%3Atrue%7D%5D%2C%22out%22%3A%5B%7B%22IoDeployForm%22%3A%7B%7D%2C%22ioDataType%22%3A%22string%22%2C%22ioDataTypeName%22%3A%22%E5%AD%97%E7%AC%A6%E4%B8%B2%22%2C%22ioFormType%22%3A%22text%22%2C%22ioKey%22%3A%22scss1%22%2C%22ioName%22%3A%22%E8%BE%93%E5%87%BA%E5%8F%82%E6%95%B01%22%7D%5D%2C%22verification%22%3A%7B%22required%22%3Afalse%7D%7D%2C%22name%22%3A%22%E5%8A%9F%E8%83%BD2%22%7D%5D&deviceName=测试设备信息&devId=55689999sdff&pk=ySJnBomFNhM1TUobuokp" //onLoad
},
{
"name": "组态列表", //
"path": "pages/configuration/configuration-list", //
"query": "" //onLoad
},
{
"name": "组态分享列表", //
"path": "pages/configuration/configuration-share", //
"query": "uuid=m33aczfhwujbvb6uy4mg" //onLoad
}
]
}
}

View File

@ -0,0 +1,17 @@
<template>
</template>
<script>
export default {
onLoad(options) {
console.log("跳转1")
uni.navigateBack({
delta: 2
});
}
}
</script>
<style>
</style>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,566 @@
<template>
<view class="configuration-box">
<view class="device-search">
<u-dropdown active-color="#1b85e9">
<u-dropdown-item v-model="dataType" title="组态类型" :options="typeOptions" @change="searchChange"></u-dropdown-item>
</u-dropdown>
<u-search placeholder="请输入组态名称搜索" margin="0 10rpx" class="uni-search-bar" v-model="searchVal" @custom="searchChange" @clear="searchChange" @search="searchChange"></u-search>
</view>
<mescroll-body ref="mescrollRef" top="160" @init="mescrollInit" @down="downCallback" :up="upOption" @up="upCallback">
<view class="configuration-list">
<view class="configuration-item" v-for="(item,index) in configurationList" :key="index" @click.stop="goDetail(item)">
<view class="item-img-box">
<image :src="item.iconPath" mode="aspectFit"></image>
</view>
<view class="item-content">
<view class="content-left">
<view class="content-top">
<text class="content-name">{{item.sceneName}}</text>
</view>
<view class="content-time">{{item.createdAt}}</view>
<!-- <view class="content-bottom">
<view class="content-btn-box" @click.stop="clickShare(index)">
<u-icon name="zhuanfa" color="#a5a4a5" size="42"></u-icon>
</view>
<text @click.stop="clickShare(index)">分享</text>
</view> -->
<view class="content-btn-box">
<button type="primary">预览</button>
<button type="primary" @click.stop="clickShare(index)">分享</button>
</view>
</view>
<!-- <u-icon name="arrow-right" color="#a5a4a5" size="42"></u-icon> -->
</view>
</view>
</view>
</mescroll-body>
<!-- 分享弹框 -->
<u-popup v-model="shareShow" width="600" border-radius="10" class="share-popup" mode="center">
<view class="title">
请选择分享方式
</view>
<view class="popup-box">
<!-- #ifdef MP-WEIXIN -->
<view class="box-item" @click="shareFriend">
<button type="default" plain="true" open-type="share">
<view class="icon-bg" style="background-color: #44a941;">
<u-icon name="weixin-fill" color="#fff" size="28"></u-icon>
</view>
</button>
<text>分享小程序</text>
</view>
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<!-- #endif -->
<view class="box-item" @click="goShareList">
<button type="default" plain="true">
<view class="icon-bg" style="background-color: #f36038;">
<u-icon name="attach" color="#fff" size="28"></u-icon>
</view>
</button>
<text>分享链接</text>
</view>
</view>
<view class="cancel-share" @click="cancelShare">
取消分享
</view>
</u-popup>
<!-- 生成海报 -->
<hch-poster ref="hchPoster" @cancel="handleCancel" :posterData.sync="posterData" />
</view>
</template>
<script>
let typeOptions=[
{
label: '全部',
value: '',
},
{
label: '2D',
value: '2d',
},
{
label: '3D',
value: '3d',
},
{
label: 'GIS',
value: 'gis',
}
]
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js"
import HchPoster from "@/components/hch-poster/hch-poster.vue"
export default{
mixins: [MescrollMixin],
data(){
return {
expire:0,
token:'',
//
projectName:1,
typeOptions:typeOptions,
configurationList:[],
dataType:'',
searchVal:'',
upOption:{
noMoreSize: 4,
textNoMore: '---- 已经到底啦 ----',
empty:{
tip: '~ 搜索无数据 ~' //
}
},
shareShow:false,
shareIndex:null, //
shareToken:'',
filePrefix:'',
//
posterData: {
poster: {
//
url: "https://am-img.gkiiot.com/iotos/app/img/configuration/white-bg.png",//
r: 10, //
w: 300, //
h: 480, //
p: 20 //padding
},
mainImg: {
//
url: "https://am-img.gkiiot.com/iotos/app/img/configuration/white-bg.png",//
r: 10, //
w: 250, //
h: 200 //
},
title: {
//
text: "标题",//
fontSize: 16, //
color: "#000", //
lineHeight: 25, //
mt: 20 //margin-top
},
codeImg: {
//
url: "https://am-img.gkiiot.com/iotos/app/img/configuration/white-bg.png",//
w: 100, //
h: 100, //
mt: 20, //margin-top
r: 50 //
},
tips: [
//
{
text: "小程序码",//
fontSize: 14,//
color: "#2f1709",//
align: "center",//
lineHeight: 25,//
mt: 20//margin-top
},
{
text: "长按/扫描识别查看",//
fontSize: 12,//
color: "#2f1709",//
align: "center",//
lineHeight: 25,//
mt: 20//margin-top
}
]
}
}
},
components:{
HchPoster
},
onShareAppMessage(res) {
if (res.from === 'button') {//
console.log(res.target)
return this.$u.mpShare
}
},
// #ifdef MP-WEIXIN
onShareTimeline() {
return this.$u.mpShare
},
// #endif
onLoad() {
this.getToken();
this.$u.mpShare = {
title: '', //
path: '', //
imageUrl: '' //
}
this.getFilePrefix();
this.configurationList=[];
this.pageNum=1;
// this.getConfigurationList();
},
methods:{
// token
getToken(){
uni.getStorage({
key:'token',
}).then(res => {
//
if(res.length==2){
this.token = res[1].data;
}
return uni.getStorage({
key:'expire',
})
}).then(res => {
if(res.length==2){
this.expire = res[1].data;
}
})
},
getFilePrefix(){
let configList = uni.getStorageSync('configList');
let configIndex = uni.getStorageSync('configIndex');
if(!configList || configIndex==-1){
uni.showToast({
title: '请求域名为空,请先添加',
icon: 'none',
duration: 1500
})
setTimeout(()=>{
uni.navigateTo({
url:'/pages/tabbar/config'
})
},1500)
}else{
this.filePrefix = configList[configIndex].protocol + configList[configIndex].address;
}
},
searchChange(e) {
this.configurationList = []// ,
this.mescroll.resetUpScroll() //
},
//
upCallback(page){
let params = {
page: page.num,
pageSize: page.size,
dataType:this.dataType,
"Wheres": {
"wheres": [
{"fields": ["sceneName"],"operator": "keyword","value": this.searchVal}
]
},
}
this.$api.configurationApi.getConfigurationListData(params).then(res => {
if(res.code === 0){
let curPageData = res.data && res.data.list;
let curPageLen = curPageData && curPageData.length || 0;
let totalSize = res.data.totalCount;
this.$nextTick(()=>{
// ;
this.mescroll.endBySize(curPageLen, totalSize);
})
//
if(page.num == 1) this.configurationList = []; //
let data = curPageData.map(item=>{
if(!item.iconImage || item.iconImage == ''){
item.iconPath = 'https://am-img.gkiiot.com/iotos/app/img/configuration/default.jpg'
}else{
item.iconPath = this.filePrefix + item.iconImage
}
item.url = this.filePrefix + '/console/' + item.dataType + '/preview?sceneId=' + item.uuid;
return item;
})
this.configurationList = curPageLen > 0 && this.configurationList.concat(data); //
this.total = totalSize;
}else{
this.$u.toast(res.msg);
this.mescroll.endErr();
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
},
//
clickShare(index){
console.log("点击分享",index)
// #ifdef MP-WEIXIN
this.shareShow = true;
this.shareIndex = index;
// #endif
// #ifndef MP-WEIXIN
uni.navigateTo({
url:'./configuration-share?uuid=' + this.configurationList[index].uuid + '&name=' + this.configurationList[index].sceneName + '&imgPath=' + encodeURIComponent(this.configurationList[index].iconPath)
})
// #endif
// this.$u.toast('');
// console.log(this.configurationList[index])
// this.shareShow = true;
// this.shareIndex = index;
},
//
goShareList(){
uni.navigateTo({
url:'./configuration-share?uuid=' + this.configurationList[this.shareIndex].uuid + '&name=' + this.configurationList[this.shareIndex].sceneName + '&imgPath=' + encodeURIComponent(this.configurationList[this.shareIndex].iconPath)
})
},
// ()
shareFriend(){
let obj = this.configurationList[this.shareIndex];
let url = obj.url + '&expires=' + this.expire + '&token=' + this.token;
this.$u.mpShare = {
title: obj.sceneName, //
path: '/pages/configuration/configuration-detail?name=' + encodeURIComponent(obj.sceneName) + '&url=' + encodeURIComponent(url), //
imageUrl: obj.iconPath //
}
},
// (app)
appShareFriend(){
let obj = this.configurationList[this.shareIndex];
uni.share({
provider: 'weixin',
scene: "WXSceneSession",
type: 5,
imageUrl: this.filePrefix+obj.iconPath,
title: obj.name,
miniProgram: {
id: 'gh_74c767462f0a',
path: '/pages/hcwl/configuration/configuration-detail?name=' + encodeURIComponent(obj.name) + '&url=' + encodeURIComponent(obj.url),
type: 0,
webUrl: '/pages/hcwl/configuration/configuration-detail?name=' + encodeURIComponent(obj.name) + '&url=' + encodeURIComponent(obj.url)
},
success: (res) => {
this.$u.toast('分享成功',res);
},
fail: (e) => {
this.$u.toast('分享失败',e);
},
complete:(e) => {
console.log('分享操作结束!')
}
});
},
//
getQrCode(){
let obj = this.configurationList[this.shareIndex];
console.log("当前点击数据",obj)
let id = encodeURIComponent(obj.id);
let opt = {
url: '/prod-api/system/open/wechat/er/image',
method: "POST",
}
let params = {
page:'pages/configuration/configuration-transfer',
// page:'pages/productList/transfer',
scene: id
}
this.$request.TokenRequest(opt,params).then(res => {
console.log("获取二维码成功",res);
if(res.code != 200){
this.$u.toast('生成海报失败!');
return;
}
this.shareShow = false;
this.$set(this.posterData.mainImg,'url',this.filePrefix+obj.iconPath)
this.$set(this.posterData.title,'text',obj.name)
this.$set(this.posterData.codeImg,'url',res.data)
console.log("当前海报信息",this.posterData)
this.$nextTick(()=>{
this.$refs.hchPoster.posterShow()
})
}, error => {
this.$u.toast('获取二维码失败!');
console.log("获取二维码失败",error)
})
},
//
handleCancel(){
console.log("取消海报生成")
},
//
cancelShare(){
this.shareShow = false;
},
//
goDetail(item){
console.log("跳转详情页",item)
let url = item.url + '&expires=' + this.expire + '&token=' + this.token;
uni.navigateTo({
url:'./configuration-detail?name=' + encodeURIComponent(item.sceneName) + '&url=' + encodeURIComponent(url)
})
},
//
reachBottom() {
console.log("这里上拉加载更多")
if(!this.isLoadMore){ //
this.loadStatus = 'loading';
this.isLoadMore=true
this.pageNum+=1
this.getConfigurationList()
}
},
}
}
</script>
<style lang="scss" scoped>
.configuration-box{
background: #f5f5f5;
// height: 100vh;
}
.device-search{
position: fixed;
top: 0;
left: 0;
box-sizing: border-box;
height: 160rpx;
background-color: #fff;
width: 100%;
z-index: 999;
.uni-search-bar{
// padding: 0 10rpx;
}
}
// .scroll-box{
// // height: calc(100% - var(--status-bar-height) - 48px - 120rpx);
// height: calc(100% - var(--status-bar-height) - 48px);
// /* #ifdef APP-PLUS */
// height: calc(100% - var(--status-bar-height) - 44px);
// /* #endif */
// }
.configuration-list{
padding: 10rpx 24rpx;
.configuration-item{
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
// height: 115rpx;
border-bottom: 1px solid #e0dede;
.item-img-box{
width: 192rpx;
height: 150rpx;
margin-right: 20rpx;
background-color: #eee;
image{
width: 100%;
height: 100%;
}
}
.item-content{
flex: 1;
height: 150rpx;
// display: flex;
// justify-content: space-between;
.content-left{
display: flex;
flex-direction: column;
justify-content: space-between;
flex:1;
.content-top{
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
}
.content-time{
font-size: 24rpx;
color: #999;
margin: 4rpx 0 16rpx 0;
}
.content-btn-box{
display: flex;
align-items: center;
// justify-content: space-around;
button{
width: 200rpx;
height: 60rpx;
margin-left: 0;
font-size: 26rpx;
padding: 0;
background: #2979ff;
display: flex;
justify-content: center;
align-items: center;
&:first-child{
margin-right: 30rpx;
}
}
}
.content-bottom{
display: flex;
align-items: center;
// justify-content: space-between;
// margin-top: 10rpx;
.content-bottom-left{
display: flex;
align-items: center;
font-size: 24rpx;
color: #999;
.content-txt{
margin: 0 10rpx;
&:first-of-type{
margin-right: 30rpx;
}
}
}
.content-btn-box{
margin-right: 10rpx;
::v-deep button{
background-color: #1b85e9;
padding: 10rpx 30rpx;
}
}
}
}
}
}
}
//
.share-popup{
.title{
background-color: #eeeff1;
display: flex;
justify-content: center;
align-items: center;
height: 100rpx;
font-size: 30rpx;
}
.popup-box{
display: flex;
justify-content: space-around;
align-items: center;
.box-item{
padding: 20rpx 0;
button{
border: 0px solid #fff;
background: #fff;
padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
.icon-bg{
width: 50rpx;
height: 50rpx;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
}
}
}
.cancel-share{
border-top: 1px solid #f0f0f0;
display: flex;
justify-content: center;
align-items: center;
height: 100rpx;
font-size: 30rpx;
color: #666;
}
}
</style>

View File

@ -0,0 +1,932 @@
<template>
<view class="configuration-share-box">
<view class="search-box">
<u-search placeholder="请输入名称或密码搜索" class="uni-search-bar" v-model="searchVal" @custom="searchChange" @clear="searchChange" @search="searchChange"></u-search>
</view>
<mescroll-body ref="mescrollRef" top="100" bottom="120" @init="mescrollInit" @down="downCallback" :up="upOption" @up="upCallback">
<view class="share-list">
<view class="share-item" v-for="(item,index) in shareList" :key="index">
<view v-if="item.expireType==1 && judgeTime(item.expireAt)" class="share-item-status" :style="{background:'#ccc'}">
{{judgeTime(item.expireAt)?'失效':''}}
</view>
<view class="share-item-box">
<view class="item-label">
标题
</view>
<view class="item-value">
{{item.shareTitle}}
</view>
</view>
<view class="share-item-box">
<view class="item-label">
密码
</view>
<view class="item-value">
{{item.password||'-'}}
</view>
</view>
<view class="share-item-box">
<view class="item-label">
有效期
</view>
<view class="item-value">
<u-tag v-if="item.expireType===1" type="error" text="限期" mode="light" />
<u-tag v-else type="success" text="永久" mode="light" />
</view>
</view>
<view class="share-item-box">
<view class="item-label">
过期时间
</view>
<view class="item-value">
{{item.expireAt||'-'}}
</view>
</view>
<view class="share-item-box">
<view class="item-label">
创建时间
</view>
<view class="item-value">
{{item.createdAt}}
</view>
</view>
<div class="btn-list-box">
<u-button type="primary" :disabled="judgeTime(item.expireAt)" @click="getQrCode(item)">生成海报</u-button>
<u-button type="primary" :disabled="judgeTime(item.expireAt)" @click="lookQr(item)">查看二维码</u-button>
<u-button type="primary" :disabled="judgeTime(item.expireAt)" @click="copyUrl(item.shareUrl)">复制链接</u-button>
<!-- <u-button type="error" @click="delShare(item.id)">删除</u-button> -->
<u-button type="error" shape="square" @click="delShare(item.id)"><u-icon name="trash-fill" color="#fff" size="44"></u-icon></u-button>
</div>
</view>
</view>
</mescroll-body>
<view class="btn-box">
<button type="default" @click="add">新增分享</button>
</view>
<u-toast ref="uToast" />
<uqrcode ref="uqrcode" canvas-id="qrcode" :value="QrUrl" :queue="false" :hide="true"></uqrcode>
<u-modal v-model="QrShow" :show-confirm-button="false" :mask-close-able="true" :title="QrModelTitle">
<view class="qr-content">
<image :src="QrBase64">
<u-button cl type="primary" @click="saveQr">保存到本地</u-button>
</view>
</u-modal>
<!-- 新增分享 -->
<u-popup v-model="addShareShow" mode="bottom" border-radius="10" :closeable="true">
<view class="popup-box">
<view class="popup-box-title">
新增分享
</view>
<view class="popup-box-content">
<view class="content-item" @click="openTitlePopup">
<view class="content-item-label">
标题
</view>
<view class="content-item-value">
<text>{{addShareObj.shareTitle}}</text>
<u-icon name="arrow-right" color="#a5a4a5" style="margin-left:6rpx;" size="24"></u-icon>
</view>
</view>
<view class="content-item" @click="openPasswordPopup">
<view class="content-item-label">
密码
</view>
<view class="content-item-value">
<text>{{addShareObj.hasPw?addShareObj.password:'无'}}</text>
<u-icon name="arrow-right" color="#a5a4a5" style="margin-left:6rpx;" size="24"></u-icon>
</view>
</view>
<view class="content-item" @click="openTimePopup">
<view class="content-item-label">
有效期
</view>
<view class="content-item-value">
<text>{{addShareObj.expireType==1?addShareObj.expireAt:'永久有效'}}</text>
<u-icon name="arrow-right" color="#a5a4a5" style="margin-left:6rpx;" size="24"></u-icon>
</view>
</view>
</view>
<view class="popop-btn">
<button type="default" @click="saveShare">保存</button>
</view>
</view>
</u-popup>
<!-- 编译分享标题 -->
<u-modal v-model="shareTitleShow" title="编辑标题" :mask-close-able="true" @confirm="editTitle">
<view class="popup-title-box">
<input class="popup-title-input" placeholder="请输入标题" v-model="shareTitle" type="text">
</view>
</u-modal>
<!-- 选择密码 -->
<u-popup v-model="addPasswordShow" mode="bottom" border-radius="10" :closeable="true">
<view class="popup-box select-password">
<view class="popup-box-title">
设置密码
</view>
<view class="popup-box-content">
<view class="content-item" :class="index===2?'two':''" @click="selectPassWord(index)" v-for="(item,index) in passwordList" :key="item.id">
<view class="content-item-main">
<text>{{item.name}}</text>
<u-icon v-if="passwordIndex === index" name="checkbox-mark" color="#2979ff" class="content-item-main-icon" size="30"></u-icon>
</view>
<view class="content-item-input-box" v-if="passwordIndex===2 && index==2">
<input class="password-input" placeholder="请输入密码" cursor-spacing="30" v-model="item.value" type="text">
<view class="password-hint">
请不要输入过于简单的密码
</view>
</view>
</view>
</view>
<view class="popop-btn">
<button type="default" @click="editPassword">确认</button>
</view>
</view>
</u-popup>
<!-- 选择有效期 -->
<u-popup v-model="addTimeShow" mode="bottom" border-radius="10" :closeable="true">
<view class="popup-box select-time">
<view class="popup-box-title">
设置有效期
</view>
<view class="popup-box-content">
<view class="content-item" :class="index===4?'two':''" @click="selectTime(index)" v-for="(item,index) in timeList" :key="item.id">
<view class="content-item-main">
<text>{{item.name}}</text>
<u-icon v-if="timeIndex === index" name="checkbox-mark" color="#2979ff" class="content-item-main-icon" size="30"></u-icon>
</view>
<view class="content-item-input-box" v-if="timeIndex===4 && index==4">
<view class="time-hint">
{{item.value||'请不要输入过于简单的密码'}}
</view>
</view>
</view>
</view>
<view class="popop-btn">
<button type="default" @click="editTime">确认</button>
</view>
</view>
</u-popup>
<!-- 加载状态 -->
<u-mask :show="isOnLoadShow" >
<view class="mask-warp">
<view class="mask-box">
<u-loading mode="flower" size="40"></u-loading>
<view class="mask-txt">
加载中
</view>
</view>
</view>
</u-mask>
<!-- 时间选择器 -->
<u-picker mode="time" v-model="timeShow" :params="timeParams" @confirm="timeChange"></u-picker>
<!-- 生成海报 -->
<hch-poster ref="hchPoster" @cancel="handleCancel" :posterData.sync="posterData" />
</view>
</template>
<script>
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js"
import HchPoster from "@/components/hch-poster/hch-poster.vue"
export default {
mixins: [MescrollMixin],
data() {
return {
searchVal:'',
upOption:{
noMoreSize: 4,
textNoMore: '---- 已经到底啦 ----',
empty:{
tip: '~ 暂无分数据 ~' //
}
},
uuid:'',
name:'',
shareList:[],
total:10,
QrModelTitle:'分享二维码',
QrUrl:'1',
QrShow:false,
QrBase64:'',
addShareShow:false,
addShareObj:{
shareTitle:'',
hasPw:false,
password:'',
expireType:0,
expireAt:'',
sceneUuid:''
},
shareTitleShow:false,
shareTitle:'',
addPasswordShow:false,
passwordList:[
{
id:0,
name:'无',
status:false,
value:''
},{
id:1,
name:'系统随机生成',
status:true,
value:''
},{
id:2,
name:'自定义密码',
status:true,
value:''
}
],
passwordIndex:0,
addTimeShow:false,
timeIndex:0,
timeList:[
{
id:0,
name:'永久有效',
status:0,
day:0,
value:''
},{
id:1,
name:'7天',
status:1,
day:7,
value:''
},{
id:2,
name:'14天',
status:1,
day:14,
value:''
},{
id:3,
name:'30天',
status:1,
day:30,
value:''
},{
id:4,
name:'自定义到期时间',
status:1,
day:30,
value:''
}
],
timeShow:false,
timeParams: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true
},
imgPath:null,
//
posterData: {
poster: {
//
url: "",//
r: 5, //
w: 300, //
h: 320, //
p: 20 //padding
},
mainImg: {
//
url: "",//
r: 5, //
w: 250, //
h: 160 //
},
title: {
//
text: "标题",//
fontSize: 16, //
color: "#000", //
lineHeight: 25, //
mt: 30, //margin-top
textAlign:"center"
},
codeImg: {
//
url: "",//
w: 70, //
h: 70, //
mt: 20, //margin-top
r: 0 //
},
tips: [
//
{
text: "Web 组态可视化分享~",//
fontSize: 14,//
color: "#2f1709",//
align: "",//
lineHeight: 25,//
mt: 20//margin-top
},
{
text: "长按/扫描识别查看",//
fontSize: 12,//
color: "#2f1709",//
align: "",//
lineHeight: 25,//
mt: 20//margin-top
}
]
},
isOnLoadShow:true,
}
},
components:{
HchPoster
},
onLoad(option) {
this.getFilePrefix();
//
setTimeout(()=>{
this.isOnLoadShow = false;
},2000)
console.log("option",option);
this.uuid = option.uuid;
this.addShareObj.sceneUuid = option.uuid;
this.name = option.name;
this.imgPath = decodeURIComponent(option.imgPath);
uni.setNavigationBarTitle({
title: option.name + '分享列表'
});
},
methods:{
judgeTime(time){
if(time){
let oldTime = '';
let newTime = new Date().getTime();
if(this.$u.os()=='ios'){
oldTime = new Date(time.replace(/-/g,'/')).getTime();
}else{
oldTime = new Date(time).getTime();
}
if(newTime>oldTime){//
return true;
}else{
return false;
}
}else{
return false;
}
},
getFilePrefix(){
let configList = uni.getStorageSync('configList');
let configIndex = uni.getStorageSync('configIndex');
if(!configList || configIndex==-1){
uni.showToast({
title: '请求域名为空,请先添加',
icon: 'none',
duration: 1500
})
setTimeout(()=>{
uni.navigateTo({
url:'/pages/tabbar/config'
})
},1500)
}else{
console.log("filePrefix",filePrefix)
let filePrefix = configList[configIndex].protocol + configList[configIndex].address;
this.$set(this.posterData.poster,'url',filePrefix+ '/console/web/images/sys/poster.jpg')
}
},
upCallback(page){
let params = {
page: page.num,
pageSize: page.size,
// sceneUuid:this.uuid,
"Wheres": {
"wheres": [
{"field": "sceneUuid","operator": "=","value": this.uuid}
]
},
"Sorters": {
"sorters": [
{"columnKey":"id","order":"descend"}
]
},
}
if(this.searchVal!=''){
params.Wheres.wheres.push({"fields": ["shareTitle","password"],"operator": "keyword","value": this.searchVal})
}
this.$api.configurationApi.getConfigurationShareList(params).then(res => {
if(res.code === 0){
let curPageData = res.data && res.data.list;
let curPageLen = curPageData && curPageData.length || 0;
let totalSize = res.data.totalCount;
this.$nextTick(()=>{
// ;
this.mescroll.endBySize(curPageLen, totalSize);
})
//
if(page.num == 1) this.shareList = []; //
this.shareList = curPageLen > 0 && this.shareList.concat(curPageData); //
this.total = totalSize;
}else{
this.$u.toast(res.msg);
this.mescroll.endErr();
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
},
//
lookQr(item){
uni.showLoading({
mask: true,
title: '生成中...'
})
this.QrModelTitle = item.shareTitle + '分享二维码';
this.QrUrl = item.shareUrl;
// 150
setTimeout(()=>{
this.$refs.uqrcode.toTempFilePath({
success: res => {
uni.hideLoading()
this.QrBase64 = res.tempFilePath;
this.QrShow = true;
},
error:err=>{
uni.hideLoading()
}
});
},150)
},
//
getQrCode(item){
let that = this;
uni.showLoading({
mask: true,
title: '生成中...'
})
this.QrModelTitle = item.shareTitle + '分享二维码';
this.QrUrl = item.shareUrl;
// 150
setTimeout(()=>{
this.$refs.uqrcode.toTempFilePath({
success: res => {
console.log("当前获取图片",res)
uni.hideLoading()
this.QrBase64 = res.tempFilePath;
// this.QrShow = true;
// #ifdef APP-PLUS
this.$set(this.posterData.mainImg,'url',this.imgPath)
this.$set(this.posterData.title,'text',this.name)
this.$set(this.posterData.codeImg,'url',res.tempFilePath)
this.$nextTick(()=>{
this.$refs.hchPoster.posterShow()
})
// #endif
// #ifdef MP-WEIXIN
this.base64ToTempFilePath(res.tempFilePath , function(tempFilePath) {
// that.orderqrpath = tempFilePath // canvas
that.$set(that.posterData.mainImg,'url',that.imgPath)
that.$set(that.posterData.title,'text',that.name)
that.$set(that.posterData.codeImg,'url',tempFilePath)
that.$nextTick(()=>{
that.$set(that.posterData.codeImg,'url',tempFilePath)
setTimeout(()=>{
that.$refs.hchPoster.posterShow()
},500)
})
}, function() {
console.log('转换失败')
})
// #endif
},
error:err=>{
uni.hideLoading()
}
});
},300)
},
// base64
base64ToTempFilePath(base64Data, success, fail) {
const fs = uni.getFileSystemManager()
const fileName = 'temp_image_' + Date.now() + '.png' //
const filePath = wx.env.USER_DATA_PATH + '/' + fileName
const imageData = base64Data.replace(/^data:image\/\w+;base64,/, "");
fs.writeFile({
filePath,
data: imageData,
encoding: 'base64',
success() {
success && success(filePath)
},
fail() {
fail && fail()
}
})
},
//
handleCancel(){
console.log("取消海报生成")
},
searchChange(){
this.mescroll.resetUpScroll();
},
//
add(){
this.addShareObj = {
shareTitle:this.name + this.$u.guid(4,false),
hasPw:false,
password:'',
expireType:0,
expireAt:'',
sceneUuid:this.uuid
};
this.addShareShow = true;
},
saveQr(){
this.$refs.uqrcode.save({
success: () => {
uni.showToast({
icon: 'success',
title: '保存成功'
});
}
});
},
copyUrl(url){
uni.setClipboardData({
data: url,
success: ()=>{
}
});
},
delShare(id){
uni.showModal({
title: '提示',
content: '确认要删除分享吗?',
success: (res)=>{
if (res.confirm) {
this.$api.configurationApi.delConfigurationShare({id}).then(res => {
if(res.code === 0){
this.$refs.uToast.show({
title: '删除成功',
type: 'success',
})
this.mescroll.resetUpScroll();
}else{
this.$refs.uToast.show({
title: res.message,
type: 'error',
})
}
}, error => {
this.$refs.uToast.show({
title: '服务器开小差了呢,请您稍后再试',
type: 'error',
})
})
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
},
openTitlePopup(){
this.shareTitle = this.addShareObj.shareTitle;
this.shareTitleShow = true;
},
editTitle(){
this.addShareObj.shareTitle = this.shareTitle;
},
openPasswordPopup(){
if(this.addShareObj.hasPw){
this.passwordIndex = 2;
this.passwordList[2].value = this.addShareObj.password;
}else{
this.passwordIndex = 0;
}
this.addPasswordShow = true;
},
//
selectPassWord(index){
this.passwordIndex = index;
},
//
editPassword(){
if(this.passwordIndex === 0){
this.addShareObj.hasPw = false;
this.addShareObj.password = '';
}else if(this.passwordIndex === 1){
this.addShareObj.hasPw = true;
this.addShareObj.password = this.$u.guid(6,false);
}else if(!this.passwordList[2].value){
this.$refs.uToast.show({
title: '请输入分享密码',
type: 'error',
})
return '';
}else{
this.addShareObj.hasPw = true;
this.addShareObj.password = this.passwordList[2].value;
}
this.addPasswordShow = false;
},
openTimePopup(){
if(this.addShareObj.expireType == 1){
this.timeIndex = 4;
this.timeList[4].value = this.addShareObj.expireAt;
}else{
this.timeIndex = 0;
}
this.addTimeShow = true;
},
selectTime(index){
this.timeIndex = index;
if(index === 0){
}else if(index === 4){
this.timeShow = true;
}else{
let time = new Date(new Date().getTime() + 60*60*24*1000*this.timeList[index].day);
if(this.$u.os() === 'ios'){
this.timeList[index].value = this.$u.timeFormat(time, 'yyyy/mm/dd hh:MM:ss');
}else{
this.timeList[index].value = this.$u.timeFormat(time, 'yyyy-mm-dd hh:MM:ss');
}
}
},
//
timeChange(e){
this.timeList[4].value = e.year + '-' + e.month + '-' + e.day + ' ' + e.hour + ':' + e.minute + ':' + e.second;
},
//
editTime(){
if(this.timeIndex===0){
this.addShareObj.expireType = 0;
this.addShareObj.expireAt = '';
}else if(this.timeIndex === 4 && !this.timeList[4].value){
this.$refs.uToast.show({
title: '请现在到期时间',
type: 'error',
})
return '';
}else{
this.addShareObj.expireType = 1;
this.addShareObj.expireAt = this.timeList[this.timeIndex].value;
}
this.addTimeShow = false;
},
saveShare(){
this.$api.configurationApi.addConfigurationShare(this.addShareObj).then(res => {
if(res.code === 0){
this.$refs.uToast.show({
title: '新增成功',
type: 'success',
})
this.mescroll.resetUpScroll();
this.addShareShow = false;
}else{
this.$refs.uToast.show({
title: res.message,
type: 'error',
})
}
}, error => {
this.$refs.uToast.show({
title: '服务器开小差了呢,请您稍后再试',
type: 'error',
})
})
}
}
}
</script>
<style lang="less">
.configuration-share-box{
background: #f5f5f5;
.search-box{
position: fixed;
top: 0;
left: 0;
box-sizing: border-box;
height: 100rpx;
padding: 18rpx;
background-color: #fff;
width: 100%;
z-index: 99;
}
.share-list{
padding: 20rpx;
position: relative;
.share-item-status{
position: absolute;
top: 15rpx;
right: 0;
width: 120rpx;
line-height: 50rpx;
height: 50rpx;
border-radius: 25rpx 0 0 25rpx;
text-align: center;
color: #fff;
}
.share-item{
margin-bottom: 20rpx;
background-color: #FFFFFF;
border-radius: 12rpx;
box-shadow: 0px 0px 10px 0px rgba(192,192,192,0.7);
display: flex;
flex-direction: column;
padding: 20rpx;
box-sizing: border-box;
position: relative;
.share-item-box{
display: flex;
align-items: center;
// font-size: 28rpx;
margin-bottom: 6rpx;
}
.btn-list-box{
margin-top: 16rpx;
display: flex;
justify-content: space-between;
align-items: center;
/deep/.u-btn{
padding: 0 20rpx;
}
/deep/.u-btn--error{
width: 80rpx;
// border-radius: 50%;
}
}
}
}
}
.qr-content{
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx;
image{
width: 400rpx;
height: 400rpx;
margin-bottom: 20rpx;
}
}
//
.popup-box{
background: #f8f9fd;
padding: 0 20rpx;
padding-bottom: 36rpx;
.popup-box-title{
height: 100rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 34rpx;
font-weight: bold;
}
.popup-box-content{
background: #FFFFFF;
border-radius: 10rpx;
.content-item{
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
&.two{
display: block;
}
.content-item-label{
font-weight: bold;
}
.content-item-value{
display: flex;
align-items: center;
color: #2979ff;
}
}
}
.popop-btn{
margin-top: 20rpx;
button{
height: 85rpx;
background: #2979ff;
border-radius: 10rpx;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
}
}
}
//
.popup-title-box{
padding: 20rpx 30rpx;
.popup-title-input{
background: #f8f9fd;
padding: 15rpx;
}
}
.select-password{
.content-item-main{
flex: 1;
position: relative;
.content-item-main-icon{
position: absolute;
right: 30rpx;
top:0rpx;
}
}
.content-item-input-box{
padding-top: 30rpx;
.password-input{
background: #f8f9fd;
padding: 15rpx;
}
.password-hint{
color: #999;
font-size: 24rpx;
margin-top: 15rpx;
}
}
}
.select-time{
.content-item-main{
flex: 1;
position: relative;
.content-item-main-icon{
position: absolute;
right: 30rpx;
top:0rpx;
}
}
.content-item-input-box{
// padding-top: 30rpx;
.time-hint{
color: #999;
font-size: 24rpx;
margin-top: 15rpx;
}
}
}
.btn-box{
display: flex;
justify-content: center;
border-top: 1px solid #f5f5f5;
// align-items: center;
padding-top: 10rpx;
height: 120rpx;
z-index: 99;
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #FFFFFF;
button{
width: 700rpx;
height: 85rpx;
background: #2979ff;
border-radius: 10rpx;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
}
}
.color-red{
color: red;
}
.mask-warp{
display: flex;
align-items: center;
justify-content: center;
height: 100%;
.mask-box{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.mask-txt{
margin-top: 20rpx;
font-size: 30rpx;
color: #FFFFFF;
font-weight: bold;
}
}
}
</style>

View File

@ -0,0 +1,60 @@
<template>
<view></view>
</template>
<script>
import {configurationUrl,configurationhtmlUrl} from '@/network/config.js'
export default{
data(){
return {
detailObj:{}
}
},
onLoad(option){
console.log("获取参数为",option)
uni.showLoading({
title: '拼命加载中...'
});
const id = decodeURIComponent(option.scene);
console.log("获取id为",id)
uni.request({
// method: 'POST',
method: 'GET',
url: configurationUrl +'/editor/app/preview/detail/'+id,
// url: 'http://192.168.21.230:8855/editor/app/preview/detail/'+id,
// data: {
// // isTemplate:1,
// pageNum: 1,
// pageSize: 10,
// orderByColumn: 'create_time',
// isAsc: 'desc',
// id:id
// },
success: res =>{
console.log("获取组态详情",res)
if(res.data.data){
uni.hideLoading();
let item = res.data;
// item.url = configurationhtmlUrl + '/client.html?tag=' + item.filePath + '&name=' + item.name;
item.url = configurationhtmlUrl + '/client.html?tag=' + id;
// item.url = 'http://192.168.18.131:8081/client.html?tag=' + id;
this.detailObj = item;
uni.reLaunch({
url: './configuration-detail?name=' + encodeURIComponent(item.name) + '&url=' + encodeURIComponent(item.url)
});
}else{
this.$u.toast("组态列表为空");
}
},
fail: err => {
this.u.toast("未获取到组态数据");
}
})
}
}
</script>
<style>
</style>

162
pages/index/device.vue Normal file
View File

@ -0,0 +1,162 @@
<template>
<view id="device">
<nav-bar :is-back="true" title="设备数据实时监控" :title-width="285" ></nav-bar>
<view class="device-list">
<view class="device-item" @click="goUrl(1)">
<view class="device-bg">
<view class="device-num">
<text>{{productCount}}</text>
</view>
</view>
<view class="device-title">总产品数量</view>
</view>
<view class="device-item" @click="goUrl(2)">
<view class="device-bg">
<view class="device-num">
<text>{{deviceCount}}</text>
</view>
</view>
<view class="device-title">总设备数量</view>
</view>
<view class="device-item" @click="goUrl(3)">
<view class="device-bg">
<view class="device-num">
<text>{{activeCount}}</text>
</view>
</view>
<view class="device-title">激活设备数量</view>
</view>
<view class="device-item" @click="goUrl(4)">
<view class="device-bg">
<view class="device-num">
<text>{{onlineCount}}</text>
</view>
</view>
<view class="device-title">在线设备数量</view>
</view>
</view>
</view>
</template>
<script>
import NavBar from '../../common/components/navbar/NavBar.vue'
export default {
data() {
return {
productCount:0,
deviceCount:0,
activeCount:0,
onlineCount:0,
}
},
components:{
NavBar
},
onLoad() {
this.getDeviceData();
},
onShow() {
},
methods:{
goUrl(type){
if(type == 1){
// uni.switchTab({
// url:'./product'
// })
uni.navigateTo({
url:'./product'
})
}else if(type == 2){
uni.navigateTo({
url:'../device/list'
})
}else if(type == 3){
uni.navigateTo({
url:'../device/list'
})
}else if(type == 4){
uni.navigateTo({
url:'../device/list?deviceStateIndex=0'
})
}
},
//
getDeviceData(){
let opt = {
url: '/prod-api/iot/device/all/count',
method: "GET",
}
this.$request.TokenRequest(opt,{}).then(res => {
console.log("getDeviceData",res);
if(res.code==200){
this.productCount=res.data.productCount;
this.deviceCount=res.data.deviceCount;
this.activeCount=res.data.activeCount;
this.onlineCount=res.data.onlineCount;
}else{
this.$u.toast(res.msg);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
console.log(error);
})
},
}
}
</script>
<style scoped lang="less">
.device-list{
display: flex;
justify-content: space-between;
flex-wrap: wrap;
padding: 0 85rpx;
.device-item{
padding-top: 53rpx;
&:nth-child(1) .device-bg{
background: url(https://am-img.gkiiot.com/iotos/app/img/device/device1.png) no-repeat;
background-size: 100% 100%;
}
&:nth-child(2) .device-bg{
background: url(https://am-img.gkiiot.com/iotos/app/img/device/device2.png) no-repeat;
background-size: 100% 100%;
}
&:nth-child(3) .device-bg{
background: url(https://am-img.gkiiot.com/iotos/app/img/device/device3.png) no-repeat;
background-size: 100% 100%;
}
&:nth-child(4) .device-bg{
background: url(https://am-img.gkiiot.com/iotos/app/img/device/device4.png) no-repeat;
background-size: 100% 100%;
}
.device-bg{
display: flex;
justify-content: center;
align-items: center;
width: 215rpx;
height: 215rpx;
.device-num{
color: #fff;
font-size: 22rpx;
font-weight: bold;
line-height: 38rpx;
text{
font-size: 50rpx;
line-height: 53rpx;
}
}
}
.device-title{
margin-top: 10rpx;
text-align: center;
font-size: 28rpx;
color: #333333;
line-height: 48rpx;
}
}
}
</style>

View File

@ -0,0 +1,236 @@
<template>
<view id="forget-password">
<nav-bar :is-back="true" :background="'#fff'" :color="'#222'" :borderBottom="false" title="忘记密码" style="color: #222;"></nav-bar>
<view class="list-box">
<u-form :model="form" ref="uForm" label-position="top">
<u-form-item :rightIconStyle="{color: '#888', fontSize: '32rpx'}" label="手机号" prop="phone" label-width="150">
<u-input placeholder="请输入手机号" v-model="form.phone" type="number"></u-input>
</u-form-item>
<u-form-item label="验证码" prop="code" label-width="150">
<u-input placeholder="请输入手机验证码" v-model="form.code" type="text"></u-input>
<u-button class="codeBtn" slot="right" @click="getCode">{{codeTips}}</u-button>
</u-form-item>
<u-form-item label="新密码" prop="password">
<u-input :password-icon="false" type="password" v-model="form.password" placeholder="请输入新密码"></u-input>
</u-form-item>
<u-form-item label="确认密码" label-width="150" prop="rePassword">
<u-input :password-icon="false" type="password" v-model="form.rePassword" placeholder="请再次输入密码"></u-input>
</u-form-item>
</u-form>
</view>
<view class="btn">
<button type="default" @click="submit">确认提交</button>
</view>
<u-verification-code seconds="30" ref="uCode" @change="codeChange"></u-verification-code>
</view>
</template>
<script>
import NavBar from '@/common/components/navbar/NavBar.vue'
export default {
data() {
return {
codeTips: '',
form: {
phone: '',
code: '',
password: '',
rePassword: '',
},
rules: {
phone: [
{
required: true,
message: '请输入手机号',
trigger: ['change','blur'],
},
{
validator: (rule, value, callback) => {
// uViewjshttps://www.uviewui.com/js/test.html
return this.$u.test.mobile(value);
},
message: '手机号码不正确',
// blurchange
trigger: ['change','blur'],
}
],
code: [
{
required: true,
message: '请输入验证码',
trigger: ['change','blur'],
},
{
type: 'number',
message: '验证码只能为数字',
trigger: ['change','blur'],
}
],
password: [
{
required: true,
message: '请输入密码',
trigger: ['change','blur'],
},
// {
// //
// pattern: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]+\S{5,12}$/,
// message: '6-12',
// trigger: ['change','blur'],
// }
],
rePassword: [
{
required: true,
message: '请重新输入密码',
trigger: ['change','blur'],
},
{
validator: (rule, value, callback) => {
return value === this.form.password;
},
message: '两次输入的密码不相等',
trigger: ['change','blur'],
}
],
}
}
},
components: {
NavBar
},
// onReadyonLoad
onReady() {
this.$refs.uForm.setRules(this.rules);
},
onLoad() {
},
onShow() {
},
methods: {
codeChange(text) {
this.codeTips = text;
},
//
getCode(){
if(this.$u.test.mobile(this.form.phone)){
if(this.$refs.uCode.canGetCode) {
//
uni.showLoading({
title: '正在获取验证码',
mask: true
})
let opt = {
url: '192.168.18.139'+'/prod-api/system/sms/send-message?phoneNumber=' + this.form.phone+'&sendMessageType='+'CHANGE_PWD_CODE'+'&expirationTime='+'300',
method: "POST",
}
this.$request.basicRequest(opt,{}).then(res => {
// console.log("",res);
if(res.code==200){
uni.hideLoading();
// this.start()
this.$u.toast('验证码已发送');
//
this.$refs.uCode.start();
}else{
this.$u.toast(res.msg);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
} else {
this.$u.toast('倒计时结束后再发送');
}
} else {
this.$u.toast('手机号码不正确');
}
},
submit() {
this.$refs.uForm.validate(valid => {
if (valid) {
// console.log('');
let opt = {
url: '192.168.18.139'+ '/prod-api/system/user/profile/reset-password',
method: "PUT",
}
let params = {
phoneNumber: this.form.phone,
captcha: this.form.code,
newPassword: this.form.password,
}
this.$request.basicRequest(opt,params).then(res => {
// console.log("",res);
if(res.code==200){
this.$u.toast(res.msg);
}else{
this.$u.toast(res.msg);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
} else {
console.log('验证失败');
}
});
}
}
}
</script>
<style scoped lang="less">
#forget-password{
}
.list-box{
padding: 0 60rpx;
/deep/.u-form-item{
font-size: 32rpx;
font-family: Source Han Sans CN;
.u-form-item--left__content__label{
color: #010101;
}
.uni-input-wrapper{
font-size: 32rpx;
}
}
}
.codeBtn{
background: #fff;
padding: 0;
height: 30rpx;
font-size: 32rpx;
font-family: Source Han Sans CN;
color: #0092FF;
line-height: 36rpx;
&::after{ border: none;}
&.u-default-hover{
// font-weight: bold;
background: #fff !important;
color: #666 !important;
border-color: #fff !important;
}
}
.btn{
display: flex;
justify-content: center;
height: 142rpx;
position: fixed;
left: 0;
right: 0;
bottom: 0;
button{
width: 590rpx;
height: 85rpx;
background: #3683FD;
border-radius: 43rpx;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
}
}
</style>

247
pages/index/home.vue Normal file
View File

@ -0,0 +1,247 @@
<template>
<view id="home">
<nav-bar title="海创微联" ></nav-bar>
<!-- #ifdef MP-WEIXIN -->
<official-account></official-account>
<!-- #endif -->
<view class="kanban">
<view class="product-box">
<view class="product-item" @click="goTypeUrl(1)">
<text>总产品数量</text>
<text>{{productCount}}</text>
</view>
<view style="width: 1px;height: 83rpx;background: #FFFFFF;opacity: 0.2;"></view>
<view class="product-item" @click="goTypeUrl(2)">
<text>总设备数量</text>
<text>{{deviceCount}}</text>
</view>
</view>
<view class="device-box">
<view class="device-item" @click="goTypeUrl(2)">
<text>激活设备数量</text>
<text>{{activeCount}}</text>
</view>
<view class="device-item" @click="goTypeUrl(4)">
<text>在线设备数量</text>
<text>{{onlineCount}}</text>
</view>
</view>
</view>
<view class="gray-bars"></view>
<view class="main-list">
<view class="main-item" v-for="(item,index) in dataList" :key="index" @click="goTypeUrl(item.urlType)">
<view class="item-img" :style="{'background':'url('+item.imgPath+') no-repeat','background-size': '100% 100%'}">
<view class="iconfont" :class="item.iconfont"></view>
</view>
<text>{{item.txt}}</text>
</view>
</view>
<!-- 更新组件 force 是否强制更新 tabbar页面是否有原生tabbar组件-->
<!-- <app-update ref="app_update"></app-update> -->
</view>
</template>
<script>
// import appUpdate from "@/common/components/content/update/app-update.vue"
import list from '@/static/common/js/index/home-list.js'
import NavBar from '../../common/components/navbar/NavBar.vue'
export default {
data() {
return {
dataList:list,
productCount:0,
deviceCount:0,
activeCount:0,
onlineCount:0,
}
},
components:{
NavBar,
// appUpdate
},
onLoad() {
this.getInfo();
this.getDeviceData();
},
mounted() {
// this.$refs.app_update.update(); //
},
onShow() {
},
methods:{
//
getInfo(){
let opt = {
url: '/prod-api/system/user/getInfo',
method: "GET",
}
this.$request.TokenRequest(opt,{}).then(res => {
// console.log("info",res);
if(res.code==200){
this.$store.commit('setInfo', res.user);
uni.setStorage({
key: 'info',
data: res.user,
success() {
console.log('用户信息缓存成功')
},
fail() {
console.log('用户信息缓存失败')
}
});
}else{
this.$u.toast(res.msg);
}
}, error => {
console.log(error);
})
},
//
getDeviceData(){
let opt = {
url: '/prod-api/iot/device/all/count',
method: "GET",
}
this.$request.TokenRequest(opt,{}).then(res => {
// console.log("getDeviceData",res);
if(res.code==200){
this.productCount=res.data.productCount;
this.deviceCount=res.data.deviceCount;
this.activeCount=res.data.activeCount;
this.onlineCount=res.data.onlineCount;
}else{
this.$u.toast(res.msg);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
},
goTypeUrl(type){
if(type == 1){
uni.switchTab({
url:'./product'
})
}else if(type == 2){
uni.navigateTo({
url:'../device/list'
})
}else if(type == 3){
uni.navigateTo({
url:'../configuration/configuration-list'
})
}else if(type == 4){
uni.navigateTo({
url:'../video/video-list'
})
}
},
}
}
</script>
<style scoped lang="less">
.kanban{
padding: 27rpx 27rpx 36rpx 23rpx;
color: #fff;
.product-box{
width: 700rpx;
height: 148rpx;
background: #33ABFB;
box-shadow: 0px 0px 10rpx 0px rgba(102, 102, 102, 0.3);
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
.product-item{
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
text{
&:first-of-type{
font-size: 32rpx;
font-weight: 500;
margin-bottom: 16rpx;
}
&:last-of-type{
font-size: 44rpx;
font-weight: 500;
}
}
}
}
.device-box{
display: flex;
justify-content: space-between;
.device-item{
&:first-of-type{
background: url(https://am-img.gkiiot.com/iotos/app/img/home/device-pink.png) no-repeat;
background-size: 100% 100%;
}
&:last-of-type{
background: url(https://am-img.gkiiot.com/iotos/app/img/home/device-orange.png) no-repeat;
background-size: 100% 100%;
}
width: 340rpx;
height: 151rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text{
&:first-of-type{
font-size: 32rpx;
font-weight: 500;
margin-bottom: 8rpx;
}
&:last-of-type{
font-size: 44rpx;
font-weight: 500;
}
}
}
}
}
.gray-bars{
height: 20rpx;
background-color: #EBEEF5;
}
.main-list{
display: flex;
flex-wrap: wrap;
padding-top: 42rpx;
// padding: 42rpx 51rpx 0 43rpx;
.main-item{
display: flex;
flex-direction: column;
align-items: center;
width: 187.5rpx;
margin-bottom: 55rpx;
.item-img{
width: 110rpx;
height: 110rpx;
background-size: 100% 100%;
display: flex;
justify-content: center;
align-items: center;
.iconfont{
font-size: 44rpx;
color: #fff;
}
}
>text{
height: 30rpx;
font-size: 32rpx;
color: #131212;
line-height: 59rpx;
}
}
}
</style>

292
pages/index/login.vue Normal file

File diff suppressed because one or more lines are too long

188
pages/index/my.vue Normal file
View File

@ -0,0 +1,188 @@
<template>
<view id="my">
<nav-bar title="个人中心" :border-bottom="false"></nav-bar>
<view class="header">
<view class="header-avatar">
<!-- 注意请求头部保存在vuex中浏览器调试中直接刷新页面获取不到请求头部 -->
<image :src="imageUrl" mode=""></image>
</view>
<view class="header-info">
<view class="header-name">{{infoData.userName}}</view>
<view class="header-company">{{infoData.nickName}}</view>
</view>
</view>
<view class="my-list">
<view class="my-item" @click="goUrl('../my/alarm')">
<view class="item-left">
<image src="https://am-img.gkiiot.com/iotos/app/img/my/my1.png" mode=""></image>
<view class="item-txt">
<view class="item-name">报警信息</view>
<view class="item-info">消息提醒</view>
</view>
</view>
<u-icon name="arrow-right" color="#A0A0A0" size="32"></u-icon>
</view>
<view class="my-item" @click="goUrl('../my/personal-data')">
<view class="item-left">
<image src="https://am-img.gkiiot.com/iotos/app/img/my/my2.png" mode=""></image>
<view class="item-txt">
<view class="item-name">资料信息</view>
<view class="item-info">用户信息</view>
</view>
</view>
<u-icon name="arrow-right" color="#A0A0A0" size="32"></u-icon>
</view>
<view class="my-item" @click="goUrl('../my/security-setting')">
<view class="item-left">
<image src="https://am-img.gkiiot.com/iotos/app/img/my/my3.png" mode=""></image>
<view class="item-txt">
<view class="item-name">安全设置</view>
<view class="item-info">退出系统及重置密码</view>
</view>
</view>
<u-icon name="arrow-right" color="#A0A0A0" size="32"></u-icon>
</view>
<view class="my-item" @click="goUrl('../my/about')">
<view class="item-left">
<image src="https://am-img.gkiiot.com/iotos/app/img/my/my4.png" mode=""></image>
<view class="item-txt">
<view class="item-name">关于我们</view>
<view class="item-info">公司简介</view>
</view>
</view>
<u-icon name="arrow-right" color="#A0A0A0" size="32"></u-icon>
</view>
<!-- #ifdef MP-WEIXIN -->
<view class="my-item" @click="goUrl('../my/jump-official-account')">
<view class="item-left">
<image src="https://am-img.gkiiot.com/iotos/app/img/my/my5.png" mode=""></image>
<view class="item-txt">
<view class="item-name">关注公众号</view>
<view class="item-info">海创微联</view>
</view>
</view>
<u-icon name="arrow-right" color="#A0A0A0" size="32"></u-icon>
</view>
<!-- #endif -->
</view>
</view>
</template>
<script>
import NavBar from '../../common/components/navbar/NavBar.vue'
import {url } from '../../network/config.js'
export default {
data() {
return {
infoData:{},
defaultImgPath: 'https://am-img.gkiiot.com/iotos/app/img/my/avatar.jpg'
}
},
components:{
NavBar
},
computed:{
/* 有头像返回头像,没有返回默认图片 */
imageUrl(){
if(this.infoData.avatar){
console.log(url + '/prod-api/file/resources/' + this.infoData.avatar)
return url + '/prod-api/file/resources/' + this.infoData.avatar;
}else{
return this.defaultImgPath;
}
}
},
onLoad() {
this.infoData = uni.getStorageSync('info');
console.log(this.infoData)
},
onShow() {
},
methods:{
goUrl(url){
console.log(url)
uni.navigateTo({
url:url
})
}
}
}
</script>
<style scoped lang="less">
.header{
height:230rpx;
display: flex;
padding-top: 14rpx;
padding-left: 45rpx;
background: url(https://am-img.gkiiot.com/iotos/app/img/my/my-header-bg.png) no-repeat;
background-size: 100% 100%;
.header-avatar{
width: 116rpx;
height: 116rpx;
border: 10rpx solid #fff;
border-radius: 50%;
overflow: hidden;
margin-right: 30rpx;
image{
width: 96rpx;
height: 96rpx;
}
}
.header-info{
color: #fff;
padding-top: 14rpx;
.header-name{
font-size: 32rpx;
height: 32rpx;
}
.header-company{
margin-top: 31rpx;
font-size: 32rpx;
line-height: 22rpx;
}
}
}
.my-list{
padding: 13rpx 46rpx 0 41rpx;
.my-item{
display: flex;
align-items: center;
justify-content: space-between;
width: 663rpx;
height: 178rpx;
padding-right: 40rpx;
box-shadow: 0rpx 4rpx 38rpx 0rpx rgba(0, 0, 0, 0.11);
border-radius: 16rpx;
margin-bottom: 17rpx;
overflow: hidden;
.item-left{
display: flex;
image{
width: 181rpx;
height: 163rpx;
margin-left: -27rpx;
margin-right: 23rpx;
}
.item-txt{
padding-top: 46rpx;
.item-name{
font-size: 34rpx;
line-height: 34rpx;
font-weight: 500;
color: #333333;
}
.item-info{
font-size: 24rpx;
line-height: 24rpx;
margin-top: 17rpx;
color: #333333;
opacity: 0.4;
}
}
}
}
}
</style>

194
pages/index/product.vue Normal file
View File

@ -0,0 +1,194 @@
<template>
<view id="product">
<u-navbar :is-back="true" title="产品列表" title-color="#ffffff" :background="{ background: '#1B85E9' }">
<view class="slot-wrap">
<view class="iconfont icon-shaixuan" @click="goUrl(1)"></view>
</view>
</u-navbar>
<view class="search-box">
<u-search placeholder="关键搜索" bg-color="#ffffff" search-icon-color="#DCDCDC" :action-style="{color:'#333333'}" v-model="searchValue" @search="searchClick" @custom="searchClick"></u-search>
</view>
<scroll-view class="scroll-box" scroll-y @scrolltolower="reachBottom">
<view class="product-list">
<view class="product-item" v-for="(item,index) in productList" :key="item.prodId" @click="goUrl(2,index)">
<view class="product-txt">
<view class="product-name">{{item.prodName}}</view>
<view class="product-info">{{item.prodNodeType}}</view>
</view>
<view class="">
<u-icon name="arrow-right" color="#959595" size="23"></u-icon>
</view>
</view>
<u-empty :show="emptyShow" text="没有找到数据" :font-size="40" :icon-size="300" :margin-top="100" mode="list"></u-empty>
<u-loadmore class="loadmore-box" v-if="!emptyShow" :status="loadStatus" />
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
productList:[],
//
loadStatus:'loadmore',//more-loading-nomore-
isLoadMore:false, //
emptyShow:false, //
pageNum:1,
pageSize:15,
orderByColumn:'createTime',
isAsc:'desc',
searchValue:'',
}
},
onLoad(option) {
this.getProductList();
},
onShow() {
},
methods:{
//
getProductList(){
let opt = {
url: '/prod-api/iot/product/list',
method: "GET",
}
let params = {
pageNum: this.pageNum,
pageSize: this.pageSize,
orderByColumn: this.orderByColumn,
isAsc: this.isAsc,
searchValue: this.searchValue
}
this.$request.TokenRequest(opt,params).then(res => {
console.log("getProductList",res);
if(res.code==200){
if(res.rows){
this.productList.push(...res.rows);
//
if(!this.productList.length){
this.emptyShow = true;
}else{
this.emptyShow = false;
}
//
if(res.rows.length<this.pageSize){ //判断接口返回数据量小于请求数据量则表示此为最后一页
this.isLoadMore=true
this.loadStatus='nomore'
}else{
this.isLoadMore=false
this.loadStatus='loadmore'
}
}else{
this.isLoadMore=true
this.loadStatus='nomore'
}
}else{
this.$u.toast(res.msg);
this.isLoadMore=false
if(this.pageNum>1){
this.pageNum=1
}
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
this.isLoadMore=false
if(this.pageNum>1){
this.pageNum=1
}
})
},
goUrl(type,index){
if(type == 1){
uni.navigateTo({
url:'../product/filter'
})
}else if(type == 2){
uni.navigateTo({
url:'../product/detail?prodId='+this.productList[index].prodId
})
}
},
//
reachBottom() {
console.log("这里上拉加载更多")
if(!this.isLoadMore){ //
this.loadStatus = 'loading';
this.isLoadMore=true
this.pageNum+=1
this.getProductList()
}
},
//
searchClick(){
console.log('点击搜索')
this.productList = [];
this.pageNum = 1;
this.getProductList();
}
}
}
</script>
<style scoped lang="less">
#product{
height: 100%;
display: flex;
flex-direction: column;
}
.scroll-box{
height: calc(100% - var(--status-bar-height) - 96rpx - 44px);
/* #ifdef APP-PLUS */
height: calc(100% - var(--status-bar-height) - 96rpx - 48px);
/* #endif */
// box-sizing: border-box;
}
//
.slot-wrap{
display: flex;
align-items: center;
padding-left: 31rpx;
.iconfont{
font-size: 49rpx;
color: #fff;
}
}
.search-box{
height: 96rpx;
background: #EBEEF5;
padding: 18rpx 56rpx 20rpx 72rpx;
}
.product-list{
padding: 10rpx 24rpx;
.product-item{
display: flex;
justify-content: space-between;
align-items: center;
height: 115rpx;
border-bottom: 1px solid #F2F2F2;
.product-txt{
font-size: 28rpx;
color: #444444;
line-height: 28rpx;
text-indent: 2rpx;
}
.product-info{
margin-top: 17rpx;
font-size: 24rpx;
color: #444444;
line-height: 24rpx;
text-indent: 4rpx;
}
}
}
//
.loadmore-box{
padding:10rpx 0 40rpx;
}
</style>

94
pages/index/scan.vue Normal file
View File

@ -0,0 +1,94 @@
<template>
</template>
<script>
import request from '@/network/request.js'
export default {
data() {
return {
on: true
}
},
methods: {
},
onLoad() {
},
onShow() {
// tabshowon
var that = this
if (that.on) {
uni.scanCode({
onlyFromCamera: true,
scanType: ['qrCode'],
success: function (res) {
console.log("获取二维码数据",res)
if(res.result){
let [type,prodKey,devKey] = res.result.split(':')
if(prodKey&&devKey){
let opt = {
url: '/prod-api/iot/device/get/device',
method: "GET",
}
let params={
devKey,
pd:prodKey
}
// this.$requestonLaunch$requestrequest使
request.TokenRequest(opt,params).then(res => {
console.log('res',res)
if(res.code==200){
if(res.data){
let deviceId=res.data.deviceId;
uni.navigateTo({
url:'/pages/device/detail?deviceId='+deviceId,
success: (res) => {
uni.showToast({
title: '跳转成功',
icon: 'none'
});
},
fail: (err) => {
uni.showToast({
title: '跳转失败',
icon: 'none'
});
}
})
}else{
uni.showToast({
title: '未查询到设备id',
icon: 'none'
});
}
}else{
uni.showToast({
title: res.msg,
icon: 'none'
});
}
}, error => {
uni.showToast({
title: '服务器开小差了呢,请您稍后再试',
icon: 'none'
});
})
}
}
}
});
}
},
onHide: function() {
console.log("扫一扫onHide")
this.on = !this.on;
uni.switchTab({
url:'./home'
})
},
}
</script>
<style>
</style>

105
pages/index/welcome.vue Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,178 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view class="select-list">
<uni-data-select
v-model="selectValue"
:localdata="range"
:clear="false"
@change="changeSelect"
></uni-data-select>
</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-bar" v-show="charShow">
<qiun-data-charts
type="column"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:reshow="charShow"
:canvasId="canvasId"
/>
</view>
<view class="attr-value item-bar" v-show="!charShow">
<u-empty ></u-empty>
</view>
</view>
</view>
</template>
<script>
import uniDataSelect from "../../uni-data-select/uni-data-select.vue"
export default{
name: 'iots-bar',
props:{
//
value: {
type: [String,Number],
default: false
},
//
dataList:{
type:[String,null],
default:50
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
components:{
uniDataSelect
},
data() {
return {
chartData: {},
selectValue:this.value,
charShow: true,
canvasId:this.$u.guid(32),
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [15,15,0,5],
enableScroll: false,
legend: {},
xAxis: {
disableGrid: true
},
yAxis: {
data: [
{
min: 0
}
]
},
extra: {
column: {
type: "group",
width: 30,
activeBgColor: "#000000",
activeBgOpacity: 0.08
}
}
},
range: [
{ value: 0, text: "近1小时" },
{ value: 1, text: "近1天" },
{ value: 2, text: "近1周" },
],
};
},
watch: {
value(newValue) {
this.selectValue = newValue;
}
},
mounted() {
this.getServerData();
this.canvasId=this.$u.guid(32);
},
methods:{
getServerData() {
if(this.dataList){
this.chartData = JSON.parse(this.dataList);
}else{
this.charShow = false;
}
//
// setTimeout(() => {
// //
// let res = {
// categories: ["2018","2019","2020","2021","2022","2023"],
// series: [
// {
// name: "",
// data: [35,36,31,33,13,34]
// },
// {
// name: "",
// data: [18,27,21,24,6,28]
// }
// ]
// };
// this.chartData = JSON.parse(JSON.stringify(res));
// }, 500);
},
//
changeSelect(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
}
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
// display: flex;
// align-items: center;
// justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
.select-list{
margin-left: auto;
width: 160rpx;
}
}
.attr-item-right{
// flex: 1;
display: flex;
// flex-wrap: wrap;
align-items: center;
justify-content: center;
.attr-value{
width: 100%;
height: 600rpx;
}
}
}
</style>

View File

@ -0,0 +1,199 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view class="select-list">
<uni-data-select
v-model="selectValue"
:localdata="range"
:clear="false"
@change="changeSelect"
></uni-data-select>
</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-gauge" v-show="charShow">
<qiun-data-charts
type="gauge"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:reshow="charShow"
:canvasId="canvasId"
/>
</view>
<view class="attr-value item-gauge" v-show="!charShow">
<u-empty></u-empty>
</view>
</view>
</view>
</template>
<script>
import uniDataSelect from "../../uni-data-select/uni-data-select.vue"
export default{
name: 'iots-gauge',
props:{
//
value: {
type: [String,Number],
default: false
},
//
dataList:{
type:[String,null],
default:50
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
components:{
uniDataSelect
},
data() {
return {
chartData: {},
selectValue:this.value,
charShow: true,
canvasId:this.$u.guid(32),
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [5,5,5,5],
title: {
name: "60Km/H",
fontSize: 25,
color: "#2fc25b",
offsetY: 50
},
subtitle: {
name: "实时速度",
fontSize: 15,
color: "#666666",
offsetY: -50
},
extra: {
gauge: {
type: "default",
width: 30,
labelColor: "#666666",
startAngle: 0.75,
endAngle: 0.25,
startNumber: 0,
endNumber: 100,
labelFormat: "",
splitLine: {
fixRadius: 0,
splitNumber: 10,
width: 30,
color: "#FFFFFF",
childNumber: 5,
childWidth: 12
},
pointer: {
width: 24,
color: "auto"
}
}
}
},
range: [
{ value: 0, text: "近1小时" },
{ value: 1, text: "近1天" },
{ value: 2, text: "近1周" },
],
};
},
watch: {
value(newValue) {
this.selectValue = newValue;
}
},
mounted() {
this.getServerData();
this.canvasId=this.$u.guid(32);
},
methods:{
getServerData() {
if(this.dataList){
console.log("this.dataList",this.dataList)
let list = JSON.parse(this.dataList);
this.opts.subtitle.name = list.series[0].name;
this.opts.title.name = (list.series[0].data * 100) + '%';
// let obj = {
// categories: [{"value":0.2,"color":"#1890ff"},{"value":0.8,"color":"#2fc25b"},{"value":1,"color":"#f04864"}],
// }
this.chartData = JSON.parse(this.dataList);
}else{
this.charShow = false;
}
//
// setTimeout(() => {
// //
// let res = {
// categories: [{"value":0.2,"color":"#1890ff"},{"value":0.8,"color":"#2fc25b"},{"value":1,"color":"#f04864"}],
// series: [
// {
// name: "",
// data: 0.66
// }
// ]
// };
// this.chartData = JSON.parse(JSON.stringify(res));
// }, 500);
},
//
changeSelect(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
}
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
// display: flex;
// align-items: center;
// justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
.select-list{
margin-left: auto;
width: 160rpx;
}
}
.attr-item-right{
// flex: 1;
display: flex;
// flex-wrap: wrap;
align-items: center;
justify-content: center;
.attr-value{
width: 100%;
height: 600rpx;
}
}
}
</style>

View File

@ -0,0 +1,174 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view class="select-list">
<uni-data-select
v-model="selectValue"
:localdata="range"
:clear="false"
@change="changeSelect"
></uni-data-select>
</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-line" v-show="charShow">
<qiun-data-charts
type="line"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:reshow="charShow"
:canvasId="canvasId"
/>
</view>
<view class="attr-value item-line" v-show="!charShow">
<u-empty ></u-empty>
</view>
</view>
</view>
</template>
<script>
import uniDataSelect from "../../uni-data-select/uni-data-select.vue"
export default{
name: 'iots-line',
props:{
//
value: {
type: [String,Number],
default: false
},
//
dataList:{
type:[String,null],
default:50
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
components:{
uniDataSelect
},
data() {
return {
chartData: {},
selectValue:this.value,
charShow: true,
canvasId:this.$u.guid(32),
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [15,15,0,5],
enableScroll: false,
legend: {},
xAxis: {
disableGrid: true
},
yAxis: {
gridType: "dash",
dashLength: 2
},
extra: {
line: {
type: "straight",
width: 2,
activeType: "hollow"
}
}
},
range: [
{ value: 0, text: "近1小时" },
{ value: 1, text: "近1天" },
{ value: 2, text: "近1周" },
],
};
},
watch: {
value(newValue) {
this.selectValue = newValue;
}
},
mounted() {
this.getServerData();
this.canvasId=this.$u.guid(32);
},
methods:{
getServerData() {
if(this.dataList){
this.chartData = JSON.parse(this.dataList);
}else{
this.charShow = false;
}
//
// setTimeout(() => {
// //
// let res = {
// categories: ["2018","2019","2020","2021","2022","2023"],
// series: [
// {
// name: "",
// data: [35,36,31,33,13,34]
// },
// {
// name: "",
// data: [18,27,21,24,6,28]
// }
// ]
// };
// this.chartData = JSON.parse(JSON.stringify(res));
// }, 500);
},
//
changeSelect(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
}
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
// display: flex;
// align-items: center;
// justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
.select-list{
margin-left: auto;
width: 160rpx;
}
}
.attr-item-right{
// flex: 1;
display: flex;
// flex-wrap: wrap;
align-items: center;
justify-content: center;
.attr-value{
width: 100%;
height: 600rpx;
}
}
}
</style>

View File

@ -0,0 +1,163 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view class="select-list">
<uni-data-select
v-model="selectValue"
:localdata="range"
:clear="false"
@change="changeSelect"
></uni-data-select>
</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-pie" v-show="charShow">
<qiun-data-charts
type="pie"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:reshow="charShow"
:canvasId="canvasId"
/>
</view>
<view class="attr-value item-pie" v-show="!charShow">
<u-empty></u-empty>
</view>
</view>
</view>
</template>
<script>
import uniDataSelect from "../../uni-data-select/uni-data-select.vue"
export default{
name: 'iots-pie',
props:{
//
value: {
type: [String,Number],
default: false
},
//
dataList:{
type:[String,null],
default:50
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
components:{
uniDataSelect
},
data() {
return {
chartData: {},
selectValue:this.value,
charShow: true,
canvasId:this.$u.guid(32),
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [5,5,5,5],
enableScroll: false,
extra: {
pie: {
activeOpacity: 0.5,
activeRadius: 10,
offsetAngle: 0,
labelWidth: 15,
border: false,
borderWidth: 3,
borderColor: "#FFFFFF"
}
}
},
range: [
{ value: 0, text: "近1小时" },
{ value: 1, text: "近1天" },
{ value: 2, text: "近1周" },
],
};
},
watch: {
value(newValue) {
this.selectValue = newValue;
}
},
mounted() {
this.getServerData();
this.canvasId=this.$u.guid(32);
},
methods:{
getServerData() {
if(this.dataList){
this.chartData = JSON.parse(this.dataList);
}else{
this.charShow = false;
}
// setTimeout(() => {
// //
// let res = {
// series: [
// {
// data: [{"name":"","value":50},{"name":"","value":30},{"name":"","value":20},{"name":"","value":18},{"name":"","value":8}]
// }
// ]
// };
// this.chartData = JSON.parse(JSON.stringify(res));
// }, 500);
},
//
changeSelect(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
}
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
// display: flex;
// align-items: center;
// justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
.select-list{
margin-left: auto;
width: 160rpx;
}
}
.attr-item-right{
// flex: 1;
display: flex;
// flex-wrap: wrap;
align-items: center;
justify-content: center;
.attr-value{
width: 100%;
height: 600rpx;
}
}
}
</style>

View File

@ -0,0 +1,143 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-color-select" @click="changeColor()">
<view class="color-box" :style="{background:value?value:'#f4f5f6'}">
{{value?"":"选择颜色"}}
</view>
<view class="iconfont icon-xiangyou1"></view>
</view>
</view>
<u-popup v-model="colorShow" :closeable="true" mode="bottom" border-radius="10" :safe-area-inset-bottom="true">
<view class="">
<view class="" style="display: flex;justify-content: center;align-items: center;height: 40rpx;margin: 24rpx 0;font-weight: bold;font-size: 34rpx;">
选择颜色
</view>
<zebra-color-picker v-model="colors"></zebra-color-picker>
<!-- <view style="padding: 0 10rpx;">
<u-button type="primary" @click="selectColor">确认颜色</u-button>
</view> -->
<view class="btn-box" @click="selectColor">
<button>确认颜色</button>
</view>
</view>
</u-popup>
</view>
</template>
<script>
/**
* 该组件依赖zebra-color-picker组件https://ext.dcloud.net.cn/plugin?id=9905unimodules
* **/
export default{
name: 'iots-color-select',
props:{
//
value: {
type: [String, Number],
default: ''
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
data(){
return {
colorShow: false,
colors:{
hex: '#7ED321'
},
}
},
methods:{
changeColor() {
this.colorShow = true;
},
selectColor() {
this.$emit('input', this.colors.hex);
this.$emit('change',this.colors);
this.colorShow = false;
},
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
}
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
flex: 1;
&.item-color-select {
display: flex;
align-items: center;
justify-content: flex-end;
color: #ccc;
.color-box{
color: #606266;
width: 120rpx;
height: 120rpx;
border-radius: 10rpx;
font-size: 26rpx;
display: flex;
align-items: center;
justify-content: center;
}
.iconfont{
margin-left: 10rpx;
}
}
}
}
}
.btn-box{
position: absolute;
left: 0;
right: 0;
bottom: 0rpx;
padding: 10rpx;
text-align: center;
background: #fff;
z-index: 10076;
button{
height: 100rpx;
line-height: 100rpx;
background-color: $mainColor;
color: #fff;
}
}
</style>

View File

@ -0,0 +1,94 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-input">
<input type="text" placeholder="请输入" style="text-align: right;" v-model="inputValue" @input="changeInput"/>
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-input',
props:{
//
value: {
type: [String,null],
default: ''
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
data(){
return {
inputValue:this.vlaue
}
},
watch: {
value(newValue) {
this.inputValue = newValue;
}
},
methods:{
//
changeInput(e) {
this.$emit('input', e);
this.$emit('change',e);
}
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
}
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
&.item-input{
input{
flex: 1;
height: 70rpx;
}
}
}
}
}
</style>

View File

@ -0,0 +1,131 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-number">
<number-box :integer="integer"
:min="min?min:-99999"
:max="max?max:99999"
:step="step"
@changeValue="changeNumber()" style="width: 100%;height: 100%;"></number-box>
</view>
</view>
</view>
</template>
<script>
import NumberBox from '@/components/number-box/NumberBox.vue'
export default{
name: 'iots-number-box',
props:{
//
value: {
type: [String, Number],
default: ''
},
//
min:{
type:Number,
default:-99999
},
//
max:{
type:Number,
default:99999
},
//
integer: {
type:Boolean,
default:true
},
//
step: {
type:Number,
default:1
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
components:{
NumberBox
},
data(){
return {
}
},
methods:{
//
changeNumber(e, index) {
this.$emit('input', e);
this.$emit('change',e);
}
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
}
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
&.item-number{
flex: 0 1 auto;
width: 250rpx;
display: flex;
align-items: center;
justify-content: flex-end;
color: #ccc;
border: 1px solid #dcdfe6;
border-radius: 8rpx;
/deep/.number-box {
.minus {
border: none;
border-right: 1px solid #dcdfe6;
}
.plus {
border: none;
border-left: 1px solid #dcdfe6;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,115 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-select" @click="changeSelect()">
<text
:style="{color:value?'#333':'#ccc'}">{{value!=null?getVlaue(value):'请选择'}}</text>
<view class="iconfont icon-xiangyou1"></view>
</view>
</view>
<u-select mode="single-column" :default-value="selectDefaultValue" v-model="selectShow" :list="selectList" @confirm="confirm"></u-select>
</view>
</template>
<script>
export default{
name: 'iots-select',
props:{
//
value: {
type: [String, Number],
default: ''
},
//
selectList:{
type: [Array],
default: [],
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
data(){
return {
selectDefaultValue:[0],
selectShow: false,
}
},
methods:{
changeSelect() {
this.selectShow = true;
},
//
getVlaue(value) {
console.log("this.selectList[value]",this.selectList,value)
for(let i=0; i<this.selectList.length;i++){
if(this.selectList[i].value == value){
return this.selectList[i].label;
}
}
},
confirm(e) {
console.log("当前选择",e,e[0].value)
this.$emit('input', e[0].value);
this.$emit('change',e[0]);
this.selectDefaultValue = [this.selectList.findIndex(item => item.value === e[0].value)] || [0];
},
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
}
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
&.item-select {
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: flex-end;
color: #ccc;
.iconfont{
margin-left: 10rpx;
}
}
}
}
}
</style>

View File

@ -0,0 +1,120 @@
<template>
<view class="iots-component-box box-two">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
<view class="attr-item-value">
{{sliderValue}}
</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-slider">
<u-slider
v-model="sliderValue"
:min="min?min:0"
:max="max?max:100"
:step="step"
:block-width="BlockWidth"
:height="height"
:block-style="blockStyle"
@end="changeSlider"
></u-slider>
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-slider',
props:{
//
value: {
type: Number,
default: 0
},
//
min:{
type:Number,
default:0
},
//
max:{
type:Number,
default:100
},
//
step: {
type:Number,
default:1
},
// ()rpx
BlockWidth: {
type:Number,
default:40
},
// rpx
height: {
type:Number,
default:12
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
data() {
return {
sliderValue: this.value,
blockStyle:{
border:"1px solid #e6e6e6"
}
};
},
watch: {
value(newValue) {
this.sliderValue = newValue;
}
},
methods:{
//
changeSlider() {
console.log("滑动结束")
this.$emit('input', this.sliderValue);
this.$emit('change', this.sliderValue);
}
}
}
</script>
<style lang="scss" scoped>
.iots-component-box.box-two{
padding: 20rpx 20rpx;
background: #fff;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
.attr-item-value{
margin-left: auto;
}
}
.attr-item-right{
.attr-value{
padding: 30rpx 20rpx;
}
}
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-switch-btn">
<view class="iconfont icon-kaiguan" @click="changeSwitch" :class="switchValue?'active':''"></view>
<!-- <u-button type="primary"><view class="iconfont icon-kaiguan"></view></u-button> -->
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-switch-btn',
props:{
//
value: {
type: Boolean,
default: false
},
//
size:{
type:Number,
default:50
},
//
loading:{
type:Boolean,
default:false
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
data() {
return {
switchValue: this.value
};
},
watch: {
value(newValue) {
this.switchValue = newValue;
}
},
methods:{
//
changeSwitch() {
let flag = !this.switchValue
console.log("e",flag)
this.$emit('input', flag);
this.$emit('change', flag);
}
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
}
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
}
}
}
.icon-kaiguan{
padding: 16rpx;
background: #e5e5e5;
color: #7f7f7f;
font-size: 40rpx;
border-radius: 50%;
font-weight: bold;
&.active{
background: #0960ff;
color: #fff;
}
}
</style>

View File

@ -0,0 +1,104 @@
<template>
<view class="iots-component-box">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
</view>
<view class="attr-item-right">
<view class="attr-value item-switch">
<u-switch
v-model="switchValue"
:loading="loading"
:size="size"
@change="changeSwitch()"
></u-switch>
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-switch',
props:{
//
value: {
type: Boolean,
default: false
},
//
size:{
type:Number,
default:50
},
//
loading:{
type:Boolean,
default:false
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
data() {
return {
switchValue: this.value
};
},
watch: {
value(newValue) {
this.switchValue = newValue;
}
},
methods:{
//
changeSwitch(e) {
console.log("e",e)
this.$emit('input', e);
this.$emit('change',e);
}
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
border-radius: 10rpx;
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
}
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
}
}
}
</style>

View File

@ -0,0 +1,104 @@
<template>
<view class="iots-component-box" :class="value.length>1?'':'oneFlex'">
<view class="attr-item-left">
<view class="iconfont" :class="icon"></view>
<view class="attr-name">{{name}}</view>
</view>
<view class="attr-item-right multi-line" v-if="value.length>1">
<view class="attr-value item-text" v-for="(item,index) in value" :key="index">
<view class="item-value">{{item.value}}<text style="margin-left: 6rpx;font-size: 24rpx;color: #aaa;">{{item.unit}}</text></view>
<view class="item-name">{{item.name}}</view>
</view>
</view>
<view class="attr-item-right" v-else>
<view class="attr-value item-text">
<view>{{value[0].value}}<text style="margin-left: 6rpx;font-size: 24rpx;color: #aaa;">{{value[0].unit}}</text></view>
</view>
</view>
</view>
</template>
<script>
export default{
name: 'iots-text',
props:{
//
value: {
type:[Array],
default:[{name:'',value:'',unit:''}]
},
//
icon: {
type: [String],
default: 'icon-gongnengdingyi'
},
name: {
type: [String],
default: ''
}
},
data() {
return {
};
},
methods:{
}
}
</script>
<style lang="scss" scoped>
.iots-component-box{
padding: 20rpx 20rpx;
background: #fff;
margin-top: 20rpx;
border-radius: 10rpx;
&.oneFlex{
display: flex;
align-items: center;
justify-content: space-between;
}
.attr-item-left{
display: flex;
align-items: center;
font-size: 28rpx;
color: #000;
.iconfont{
margin-right: 20rpx;
font-size: 40rpx;
}
}
.attr-item-right{
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
.attr-value{
display: flex;
align-items: center;
justify-content: flex-end;
height: 70rpx;
flex: 1;
}
&.multi-line{
padding: 20rpx 0;
justify-content: flex-start;
.attr-value{
width: 33%;
height: auto;
flex-direction: column;
flex: 0 1 auto;
.item-value{
font-weight: bold;
font-size: 40rpx;
}
.item-name{
font-size: 24rpx;
color: #aaa;
}
}
}
}
}
</style>

View File

@ -0,0 +1,517 @@
<template>
<view class="uni-stat__select">
<span v-if="label" class="uni-label-text hide-on-phone">{{label + ''}}</span>
<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
<view class="uni-select" :class="{'uni-select--disabled':disabled}">
<view class="uni-select__input-box" @click="toggleSelector">
<view v-if="current" class="uni-select__input-text">{{current}}</view>
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
<view v-if="current && clear && !disabled" @click.stop="clearVal" >
<uni-icons type="clear" color="#c0c4cc" size="24"/>
</view>
<view v-else>
<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
</view>
</view>
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
<view class="uni-select__selector" v-if="showSelector">
<view class="uni-popper__arrow"></view>
<scroll-view scroll-y="true" class="uni-select__selector-scroll">
<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
<text>{{emptyTips}}</text>
</view>
<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" :key="index"
@click="change(item)">
<text :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* DataChecklist 数据选择器
* @description 通过数据渲染的下拉框组件
* @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
* @property {String} value 默认值
* @property {Array} localdata 本地数据 格式 [{text:'',value:''}]
* @property {Boolean} clear 是否可以清空已选项
* @property {Boolean} emptyText 没有数据时显示的文字 本地数据无效
* @property {String} label 左侧标题
* @property {String} placeholder 输入框的提示文字
* @property {Boolean} disabled 是否禁用
* @event {Function} change 选中发生变化触发
*/
export default {
name: "uni-data-select",
mixins: [uniCloud.mixinDatacom || {}],
props: {
localdata: {
type: Array,
default () {
return []
}
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
emptyTips: {
type: String,
default: '无选项'
},
clear: {
type: Boolean,
default: true
},
defItem: {
type: Number,
default: 0
},
disabled: {
type: Boolean,
default: false
},
// field="_id as value, version as text, uni_platform as label" format="{label} - {text}"
format: {
type: String,
default: ''
},
},
data() {
return {
showSelector: false,
current: '',
mixinDatacomResData: [],
apps: [],
channels: [],
cacheKey: "uni-data-select-lastSelectedValue",
};
},
created() {
this.debounceGet = this.debounce(() => {
this.query();
}, 300);
if (this.collection && !this.localdata.length) {
this.debounceGet();
}
},
computed: {
typePlaceholder() {
const text = {
'opendb-stat-app-versions': '版本',
'opendb-app-channels': '渠道',
'opendb-app-list': '应用'
}
const common = this.placeholder
const placeholder = text[this.collection]
return placeholder ?
common + placeholder :
common
},
valueCom(){
// #ifdef VUE3
return this.modelValue;
// #endif
// #ifndef VUE3
return this.value;
// #endif
}
},
watch: {
localdata: {
immediate: true,
handler(val, old) {
if (Array.isArray(val) && old !== val) {
this.mixinDatacomResData = val
}
}
},
valueCom(val, old) {
this.initDefVal()
},
mixinDatacomResData: {
immediate: true,
handler(val) {
if (val.length) {
this.initDefVal()
}
}
}
},
methods: {
debounce(fn, time = 100){
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, time)
}
},
//
query(){
this.mixinDatacomEasyGet();
},
//
onMixinDatacomPropsChange(){
if (this.collection) {
this.debounceGet();
}
},
initDefVal() {
let defValue = ''
if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
defValue = this.valueCom
} else {
let strogeValue
if (this.collection) {
strogeValue = this.getCache()
}
if (strogeValue || strogeValue === 0) {
defValue = strogeValue
} else {
let defItem = ''
if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
defItem = this.mixinDatacomResData[this.defItem - 1].value
}
defValue = defItem
}
if (defValue || defValue === 0) {
this.emit(defValue)
}
}
const def = this.mixinDatacomResData.find(item => item.value === defValue)
this.current = def ? this.formatItemName(def) : ''
},
/**
* @param {[String, Number]} value
* 判断用户给的 value 是否同时为禁用状态
*/
isDisabled(value) {
let isDisabled = false;
this.mixinDatacomResData.forEach(item => {
if (item.value === value) {
isDisabled = item.disable
}
})
return isDisabled;
},
clearVal() {
this.emit('')
if (this.collection) {
this.removeCache()
}
},
change(item) {
if (!item.disable) {
this.showSelector = false
this.current = this.formatItemName(item)
this.emit(item.value)
}
},
emit(val) {
this.$emit('input', val)
this.$emit('update:modelValue', val)
this.$emit('change', val)
if (this.collection) {
this.setCache(val);
}
},
toggleSelector() {
if (this.disabled) {
return
}
this.showSelector = !this.showSelector
},
formatItemName(item) {
let {
text,
value,
channel_code
} = item
channel_code = channel_code ? `(${channel_code})` : ''
if (this.format) {
//
let str = "";
str = this.format;
for (let key in item) {
str = str.replace(new RegExp(`{${key}}`,"g"),item[key]);
}
return str;
} else {
return this.collection.indexOf('app-list') > 0 ?
`${text}(${value})` :
(
text ?
text :
`未命名${channel_code}`
)
}
},
//
getLoadData(){
return this.mixinDatacomResData;
},
// key
getCurrentCacheKey(){
return this.collection;
},
//
getCache(name=this.getCurrentCacheKey()){
let cacheData = uni.getStorageSync(this.cacheKey) || {};
return cacheData[name];
},
//
setCache(value, name=this.getCurrentCacheKey()){
let cacheData = uni.getStorageSync(this.cacheKey) || {};
cacheData[name] = value;
uni.setStorageSync(this.cacheKey, cacheData);
},
//
removeCache(name=this.getCurrentCacheKey()){
let cacheData = uni.getStorageSync(this.cacheKey) || {};
delete cacheData[name];
uni.setStorageSync(this.cacheKey, cacheData);
},
}
}
</script>
<style lang="scss">
$uni-base-color: #6a6a6a !default;
$uni-main-color: #333 !default;
$uni-secondary-color: #909399 !default;
$uni-border-3: #e5e5e5;
/* #ifndef APP-NVUE */
@media screen and (max-width: 500px) {
.hide-on-phone {
display: none;
}
}
/* #endif */
.uni-stat__select {
display: flex;
align-items: center;
// padding: 15px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
width: 100%;
flex: 1;
box-sizing: border-box;
}
.uni-stat-box {
width: 100%;
flex: 1;
}
.uni-stat__actived {
width: 100%;
flex: 1;
// outline: 1px solid #2979ff;
}
.uni-label-text {
font-size: 14px;
font-weight: bold;
color: $uni-base-color;
margin: auto 0;
margin-right: 5px;
}
.uni-select {
font-size: 14px;
border: 1px solid $uni-border-3;
box-sizing: border-box;
border-radius: 4px;
padding: 0 5px;
padding-left: 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
user-select: none;
/* #endif */
flex-direction: row;
align-items: center;
border-bottom: solid 1px $uni-border-3;
width: 100%;
flex: 1;
height: 35px;
&--disabled {
background-color: #f5f7fa;
cursor: not-allowed;
}
}
.uni-select__label {
font-size: 16px;
// line-height: 22px;
height: 35px;
padding-right: 10px;
color: $uni-secondary-color;
}
.uni-select__input-box {
height: 35px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-select__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-select__input-plac {
font-size: 14px;
color: $uni-secondary-color;
}
.uni-select__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
top: calc(100% + 12px);
left: 0;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 3;
padding: 4px 0;
}
.uni-select__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
/* #ifdef H5 */
@media (min-width: 768px) {
.uni-select__selector-scroll {
max-height: 600px;
}
}
/* #endif */
.uni-select__selector-empty,
.uni-select__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 35px;
font-size: 14px;
text-align: center;
/* border-bottom: solid 1px $uni-border-3; */
padding: 0px 10px;
}
.uni-select__selector-item:hover {
background-color: #f9f9f9;
}
.uni-select__selector-empty:last-child,
.uni-select__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.uni-select__selector__disabled {
opacity: 0.4;
cursor: default;
}
/* picker 弹出层通用的指示小三角 */
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-select__input-text {
// width: 280px;
width: 100%;
color: $uni-main-color;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
overflow: hidden;
}
.uni-select__input-placeholder {
color: $uni-base-color;
font-size: 12px;
}
.uni-select--mask {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 2;
}
</style>

View File

@ -0,0 +1,243 @@
<template>
<view class="region-box">
<mescroll-body class="new-mescroll" ref="mescrollRef" bottom="130" @init="mescrollInit" @down="downCallback" @up="upCallback" :up="upOption" >
<view class="region-list" v-if="dataList && dataList.length > 0">
<view class="region-item">
<view class="item-left">
<view class="item-name">
全部
</view>
</view>
<view class="item-right">
<view class="iconfont icon-xiangyou1"></view>
</view>
</view>
<view class="region-item" v-for="(item,index) in dataList" :key="item.id">
<view class="item-left">
<view class="item-name">
{{item.name}}
</view>
<view class="item-info">
{{item.deviceNum?item.deviceNum:0}}个设备
</view>
</view>
<view class="item-right">
<view class="sort-box" v-if="sortStatus">
<view class="iconfont icon-help"></view>
<view class="iconfont icon-help"></view>
</view>
<view class="iconfont icon-xiangyou1"></view>
</view>
</view>
</view>
</mescroll-body>
<view class="btn-box">
<button type="primary" @tap="refundBatteryFn">新增</button>
<button type="primary" @tap="toggleSortStatus">{{sortStatus?'取消排序':'排序'}}</button>
</view>
</view>
</template>
<script>
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
export default{
data(){
return{
dataList:[
{
id:0,
name:'客厅',
deviceNum:10,
sort:1,
},
{
id:1,
name:'主卧',
deviceNum:4,
sort:2,
},
{
id:2,
name:'次卧',
deviceNum:3,
sort:3,
},
{
id:0,
name:'客厅',
deviceNum:10,
sort:1,
},
{
id:1,
name:'主卧',
deviceNum:4,
sort:2,
},
{
id:2,
name:'次卧',
deviceNum:3,
sort:3,
},
{
id:0,
name:'客厅',
deviceNum:10,
sort:1,
},
{
id:1,
name:'主卧',
deviceNum:4,
sort:2,
},
{
id:2,
name:'次卧',
deviceNum:3,
sort:3,
}
],
sortStatus:false,
upOption:{
page:{
num : 0 ,
size : 10 ,
time : null
},
noMoreSize: 4,
empty:{
// icon:'https://hcwl-cdn.cdn.bcebos.com/hcapp/iotos/app/iconImg/new.png',
use : true ,
tip: '~ 区域列表为空 ~',
fixed: true,
top: "200rpx",
},
bgColor:"#fff"
},
}
},
mixins:[MescrollMixin],
methods:{
/*上拉加载的回调*/
upCallback(page) {
console.log("查询数据",page)
// this.dataList = list; //
this.mescroll.endBySize(8, 10); //
this.loading = false;
// let pageNum = page.num; // , 1
// let pageSize = page.size; // , 10
// let obj = {
// page:pageNum,
// limit:pageSize,
// msgType:this.tabIndex==0?'private':'public'
// }
// if (this.isToken) {
// this.$api.getNewList(obj).then((res)=>{
// console.log("",res)
// if (res.data.rows && res.data.rows.length>0) {
// // ()
// let curPageData = res.data.rows;
// // (26,8,curPageLen=8)
// let curPageLen = curPageData && curPageData.length;
// //
// console.log(curPageLen,res.data.total);
// if(pageNum == 1){
// this.newsList = []; //
// // this.getUnreadNewIdList(); //
// this.getUnreadNewNum();
// }
// this.newsList = this.newsList.concat(curPageData); //
// this.mescroll.endBySize(curPageLen, res.data.total); //
// this.loading = false;
// console.log("newsList",this.newsList)
// } else{
// this.newsList = [];
// this.mescroll.endErr();
// this.mescroll.showEmpty();
// this.loading = false;
// // this.mescroll.endUpScroll(true)
// }
// }).catch(()=>{
// this.$u.toast('')
// this.newsList = [];
// //,
// this.mescroll.endErr();
// this.mescroll.showEmpty();
// this.loading = false;
// })
// }else{
// this.newsList = [];
// this.mescroll.endErr();
// this.mescroll.showEmpty();
// this.loading = false;
// }
},
toggleSortStatus(){
this.sortStatus = !this.sortStatus;
}
}
}
</script>
<style lang="scss" scoped>
.region-box{
height: 100%;
.region-list{
.region-item{
padding: 20rpx 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
.item-left{
.item-name{
font-weight: bold;
}
.item-info{
margin-top: 5rpx;
font-size: 22rpx;
color: #666;
}
}
.item-right{
display: flex;
align-items: center;
.sort-box{
display: flex;
.iconfont{
margin-right: 42rpx;
font-size: 48rpx;
color: $mainColor;
}
}
.icon-xiangyou1{
font-size: 32rpx;
}
}
}
}
}
.btn-box{
position: fixed;
width: 100%;
height: 130rpx;
padding: 10rpx;
padding-bottom: 20rpx;
box-sizing: border-box;
bottom: 0;
display: flex;
align-items: center;
justify-content: space-around;
background-color: #fff;
button{
width: 45%;
background-color: $mainColor;
color: #fff;
}
.bg-grey{
background: #e7e7e7;
color: #8a8c90;
}
}
</style>

View File

@ -0,0 +1,215 @@
<template>
<view class="light-box" :style="{backgroundColor:bgcolor}">
<view class="header-box">
</view>
<view class="attr-box">
</view>
</view>
</template>
<script>
let attrList = [
{
"tenantId": 10151,
"createId": 10340,
"createBy": "hcwl",
"icon":"icon-gx-mingcheng",
"createTime": "2022-09-02 09:49:32",
"updateBy": "",
"updateTime": "2022-09-02 09:48:00",
"funId": 2694,
"sourceId": "adE134a38026GBDa",
"mainId": null,
"funName": "开关",
"funKey": "switch",
"funDataType": "BOOL",
"funDataTypeName": "布尔型",
"funRwType": "READWRITE",
"funRwTypeName": "可上报可下发",
"funValidType": "RANGE",
"funValidTypeName": "枚举校验",
"funValMin": null,
"funValMax": null,
"funObj": null,
"unitName": null,
"funValAcc": null,
"lastValue": false,
"lastTime": null
},
{
"tenantId": 10152,
"createId": 10341,
"createBy": "hcwl",
"icon":"icon-gx-mingcheng",
"createTime": "2022-09-02 09:49:32",
"updateBy": "",
"updateTime": "2022-09-02 09:48:00",
"funId": 2694,
"sourceId": "adE134a38026GBDa",
"mainId": null,
"funName": "亮度",
"funKey": "brightness",
"funDataType": "int",
"funDataTypeName": "整数型",
"funRwType": "READWRITE",
"funRwTypeName": "可上报可下发",
"funValidType": "RANGE",
"funValidTypeName": "范围校验",
"funValMin": 0,
"funValMax": 100,
"funObj": null,
"unitName": null,
"funValAcc": null,
"lastValue": 100,
"lastTime": null
},
{
"tenantId": 10153,
"createId": 10342,
"createBy": "hcwl",
"icon":"icon-gx-mingcheng",
"createTime": "2022-09-02 09:49:32",
"updateBy": "",
"updateTime": "2022-09-02 09:48:00",
"funId": 2694,
"sourceId": "adE134a38026GBDa",
"mainId": null,
"funName": "颜色",
"funKey": "color",
"funDataType": "TEXT",
"funDataTypeName": "字符串",
"funRwType": "READWRITE",
"funRwTypeName": "可上报可下发",
"funValidType": "RANGE",
"funValidTypeName": "范围校验",
"funValMin": null,
"funValMax": null,
"funObj": null,
"unitName": null,
"funValAcc": null,
"lastValue": '#ffffff',
"lastTime": null
},
{
"tenantId": 10154,
"createId": 10343,
"createBy": "hcwl",
"icon":"icon-gx-kaiguan",
"createTime": "2022-09-02 09:49:32",
"updateBy": "",
"updateTime": "2022-09-02 09:48:00",
"funId": 2694,
"sourceId": "adE134a38026GBDa",
"mainId": null,
"funName": "我的模式",
"funKey": "mode",
"funDataType": "OBJ",
"funDataTypeName": "对象型",
"funRwType": "READWRITE",
"funRwTypeName": "可上报可下发",
"funValidType": "ENUM",
"funValidTypeName": "枚举校验",
"funValMin": null,
"funValMax": null,
"funObj": "[{\"name\":\"睡眠模式\",\"color\":\"#ffff00\",\"brightness\":30},{\"name\":\"观影模式\",\"color\":\"#ffff00\",\"brightness\":50},{\"name\":\"阅读模式\",\"color\":\"#ffffff\",\"brightness\":50},{\"name\":\"办公模式\",\"color\":\"#ffffff\",\"brightness\":100}]",
"unitName": null,
"funValAcc": null,
"lastValue": {
"name":"睡眠模式",
"color":"#ffff00",
"brightness":30
},
"lastTime": null
},
{
"tenantId": 10152,
"createId": 10341,
"createBy": "hcwl",
"icon":"icon-gx-mingcheng",
"createTime": "2022-09-02 09:49:32",
"updateBy": "",
"updateTime": "2022-09-02 09:48:00",
"funId": 2694,
"sourceId": "adE134a38026GBDa",
"mainId": null,
"funName": "定时",
"funKey": "calmTime",
"funDataType": "int",
"funDataTypeName": "整数型",
"funRwType": "READWRITE",
"funRwTypeName": "可上报可下发",
"funValidType": "RANGE",
"funValidTypeName": "范围校验",
"funValMin": 0,
"funValMax": 100,
"funObj": null,
"unitName": null,
"funValAcc": null,
"lastValue": null,
"lastTime": null
},
]
// [
// {
// "name":"",
// "color":"#ffff00",
// "brightness":30
// },{
// "name":"",
// "color":"#ffff00",
// "brightness":50
// },{
// "name":"",
// "color":"#ffffff",
// "brightness":50
// },{
// "name":"",
// "color":"#ffffff",
// "brightness":100
// }
// ]
export default{
data(){
return {
color:"#ffff00",
brightness:100,
}
},
onLoad(option) {
if(option.name){
//
uni.setNavigationBarTitle({
title: option.name
});
}
},
computed:{
bgcolor(){
let bgcolor = this.hexToRgba(this.color,this.brightness*0.01);
return bgcolor;
}
},
methods:{
hexToRgba(hex, opacity) {
return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ',' + parseInt('0x' + hex.slice(5, 7)) + ',' + opacity + ')'
}
}
}
</script>
<style>
page{
height: 100%;
}
</style>
<style lang="scss" scoped>
.light-box{
height: 100%;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,292 @@
<template>
<view class="ability-box">
<view class="attr-list">
<view class="attr-list-item" v-for="(item,index) in dataList" :key="index">
<view class="checkbox-box">
<u-checkbox
size="40"
v-model="item.checked"
@change="changeCheck($event,index)"
></u-checkbox>
</view>
<view class="attr-list-item-content" :class="item.ioRequired?'required':''">
<!-- 选择器 -->
<iots-select
v-if="item.ioFormType == 'select'"
:name="item.ioName"
:disabled="false"
v-model="item.value"
:selectList="item.ioObj.enums"
@change="changeData($event,index)"
:logShow="false"
></iots-select>
<!-- 步进器 -->
<iots-number-box
v-else-if="item.ioFormType == 'number'"
:name="item.ioName"
:disabled="false"
:min="parseFloat(item.IoDeployForm.min || 0)"
:max="parseFloat(item.IoDeployForm.max || 100)"
:step="parseFloat(item.IoDeployForm.step || 1)"
:logShow="false"
@change="changeData($event,index)"
v-model="item.value"
></iots-number-box>
<!-- 输入框 -->
<iots-input
v-else-if="item.ioFormType == 'text'"
:name="item.ioName"
:disabled="false"
v-model="item.value"
@change="changeData($event,index)"
:logShow="false"
></iots-input>
<!-- 开关 -->
<iots-switch
v-else-if="item.ioFormType == 'switch'"
:name="item.ioName"
:disabled="false"
v-model="item.value"
@change="changeData($event,index)"
:logShow="false"
></iots-switch>
<!-- 滑块 -->
<iots-slider
v-else-if="item.ioFormType == 'slider'"
:name="item.ioName"
:disabled="false"
:min="parseFloat(item.IoDeployForm.min || 0)"
:max="parseFloat(item.IoDeployForm.max || 100)"
:step="parseFloat(item.IoDeployForm.step || 1)"
v-model="item.value"
@change="changeData($event,index)"
:logShow="false"
></iots-slider>
<!-- 时间选择器 -->
<iots-select-time
v-else-if="item.ioFormType == 'time_picker'"
:name="item.ioName"
:disabled="false"
v-model="item.value"
@change="changeData($event,index)"
:logShow="false"
></iots-select-time>
</view>
</view>
</view>
<view class="btn-box">
<u-checkbox
size="40"
v-model="isSelectAll"
@change="changeCheckAll"
>全选</u-checkbox>
<button @click="execute">执行</button>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import IotsSelect from '@/components/iot-components/select/iots-select.vue'
import IotsNumberBox from "@/components/iot-components/number-box/iots-number-box.vue"
import IotsSwitch from '@/components/iot-components/switch/iots-switch.vue'
import IotsSlider from '@/components/iot-components/slider/iots-slider.vue'
import IotsInput from '@/components/iot-components/input/iots-input.vue'
import IotsSelectTime from '@/components/iot-components/select-time/iots-select-time.vue'
export default{
data(){
return {
abilityObj:{},
dataList:[],
devId:'',
pk:'',
isSelectAll:true,
}
},
components: {
IotsSelect,
IotsSelectTime,
IotsNumberBox,
IotsSwitch,
IotsSlider,
IotsInput,
},
onLoad(option) {
let ability = JSON.parse(decodeURIComponent(option.ability))
console.log("当前参数",ability);
this.abilityObj = ability;
this.devId = option.devId;
this.pk = option.pk;
// this.dataList = ability.ioObj.in;
this.formatData(ability.ioObj.in);
uni.setNavigationBarTitle({
title:ability.name
})
},
methods:{
formatData(list){
let datalist = list.map(item=>{
if(item.ioFormType == 'number' || item.ioFormType == 'slider'){
if(item.IoDeployForm.min == undefined){
item.IoDeployForm.min = 0;
item.value = 0;
}else{
item.value = parseFloat(item.IoDeployForm.min);
}
}else if(item.ioFormType == 'switch'){
item.value = false;
}else{
item.value = null;
}
item.checked = true;
return item;
})
this.dataList = datalist;
},
changeCheck(e,index){
console.log("单选",e,index)
this.$forceUpdate()
let dataList = JSON.parse(JSON.stringify(this.dataList));
dataList[index].checked = e.value;
let isSelectAll = true;
dataList.forEach((item)=>{
if(!item.checked){
isSelectAll = false;
}
})
this.isSelectAll = isSelectAll;
},
changeCheckAll(e){
console.log("全选",e)
let dataList = JSON.parse(JSON.stringify(this.dataList));
dataList = dataList.map((item)=>{
item.checked = e.value;
return item;
})
this.$nextTick(()=>{
this.$set(this,'dataList',dataList)
this.$forceUpdate()
})
},
changeData(){
this.$forceUpdate()
},
execute(){
if(this.verification()){
let obj = {};
this.dataList.forEach((item)=>{
obj[item.ioKey]=item.value
})
let params = {
ac:'write',
d:this.devId,
pk:this.pk,
p:obj
}
this.$api.iotsApi.downDeviceAbility(params).then(res => {
console.log("下发数据成功",res)
if(res.code == 0){
// this.$u.toast('')
this.$refs.uToast.show({
title: '执行成功',
type: 'success',
})
}else{
this.$refs.uToast.show({
title: res.message,
type: 'error',
})
}
}, error => {
})
}else{
console.log("校验未通过")
}
},
//
verification(){
let flag = true;
this.dataList.forEach((item)=>{
if(flag && item.checked && item.ioRequired && !item.value && !['number', 'slider', 'switch'].includes(item.ioFormType)){
this.$refs.uToast.show({
title: item.ioName + '不能为空!',
type: 'error',
})
flag = false;
}
})
return flag;
}
}
}
</script>
<style>
page{
background: #f5f5f5;
}
</style>
<style lang="scss" scoped>
/deep/.iots-component-box{
margin-top: 0 !important;
}
.ability-box{
padding-bottom: 140rpx;
}
.attr-list-item{
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20rpx;
background: #FFFFFF;
border-radius: 10rpx;
margin-top: 20rpx;
.checkbox-box{
padding: 0 20rpx;
width: 80rpx;
display: flex;
justify-content: center;
// margin-right: 20rpx;
}
.attr-list-item-content{
flex: 1;
position: relative;
&.required::after{
content: '';
width: 16rpx;
height: 16rpx;
border-radius: 50%;
position: absolute;
top: 12rpx;
left: 6rpx;
background: red;
}
}
}
.btn-box{
display: flex;
align-items: center;
justify-content: space-between;
background: #fff;
height: 140rpx;
padding: 0 30rpx;
padding-bottom: 10rpx;
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 99;
button{
width: 300rpx;
height: 90rpx;
background: #3683FD;
border-radius: 43rpx;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
}
}
</style>

View File

@ -0,0 +1,95 @@
<template>
<view class="ability-list-box">
<view class="ability-list">
<view class="ability-item" v-for="item in abilityList" :key="item.identifier" @click="goDetail(item)">
<view class="item-left">
<view class="iconfont icon-appstore"></view>
<view class="item-left-content">
<view class="item-name">
{{item.name}}
</view>
<view class="item-status">
<u-tag v-if="item.callType == 'async'" text="同步" type="success" />
<u-tag v-else-if="item.callType == 'sync'" text="异步" type="warning" />
</view>
</view>
</view>
<view class="iconfont icon-xiangyou1"></view>
</view>
<u-empty v-if="abilityList.length == 0" margin-top="250" text="设备功能为空,请添加功能" src="grid"></u-empty>
</view>
</view>
</template>
<script>
export default{
data(){
return {
abilityList:[],
devId:'',
pk:'',
}
},
onLoad(option) {
let abilityList = JSON.parse(decodeURIComponent(option.abilityList))
console.log("当前参数",abilityList);
this.abilityList = abilityList;
this.devId = option.devId;
this.pk = option.pk;
uni.setNavigationBarTitle({
title:option.deviceName + '功能列表'
})
},
methods:{
goDetail(obj){
console.log("当前点击功能",obj)
let ability = encodeURIComponent(JSON.stringify(obj))
uni.navigateTo({
url:'./device-ability-detail?ability=' + ability + '&devId=' + this.devId + '&pk=' + this.pk
})
}
}
}
</script>
<style>
page{
background-color: #f5f5f5;
}
</style>
<style lang="scss" scoped>
.ability-list-box{
.ability-list{
.ability-item{
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx;
background: #fff;
border-bottom: 1px solid #f5f5f5;
.item-left{
display: flex;
align-items: center;
.iconfont{
font-size: 90rpx;
}
.item-left-content{
margin-left: 20rpx;
.item-name{
font-size: 30rpx;
font-weight: bold;
}
.item-status{
margin-top: 10rpx;
}
}
}
.iconfont{
color: #818181;
}
}
}
}
</style>

View File

@ -0,0 +1,430 @@
<template>
<view class="notice-box">
<view class="notice-top" @click="openSelect">
{{noticeTimeObj.beginTime!==''?noticeTimeObj.beginTime+' ~ '+noticeTimeObj.endTime:'全部时间'}}<view class="iconfont icon-xiangyou1"></view>
</view>
<mescroll-body ref="mescrollRef" top="80" @init="mescrollInit" @down="downCallback" @up="upCallback" :up="upOption" >
<view class="notice-list">
<view class="notice-item" v-for="(item,index) in dataList" :key="index">
<view class="item-header">
<view class="item-header-left">
<view class="header-title">
设备报警通知
</view>
<view class="header-time">
{{$u.timeFormat(item.alarmTime, 'mm月dd日')}}
</view>
</view>
<view class="item-header-right" :style="{color:index%3==2?'#10CC70':index%3==1?'#FF2B38':'#999999'}">
{{index%3==2?'已处理':index%3==1?'未处理':'待处理'}}
</view>
</view>
<view class="item-body">
<view class="item-body-left">
<view class="body-txt">设备报警</view>
<view class="body-txt"><text>时间</text>{{$u.timeFormat(item.alarmTime, 'yyyy年mm月dd日 hh时MM分ss秒')}}</view>
<view class="body-txt"><text>设备</text>{{item.deviceName}}</view>
<view class="body-txt"><text>等级</text>{{item.alarmLevel | numberfilter}}</view>
<view class="body-txt"><text>内容</text>{{item.alarmContent}}</view>
<view class="body-txt">当前值{{item.currentValue}}</view>
</view>
<view class="item-body-right" v-if="index%3!==2">
<u-button type="primary">处理</u-button>
</view>
</view>
</view>
</view>
</mescroll-body>
<u-calendar v-model="timeshow" :mode="mode" :min-date="minDate" :max-date="maxDate" @change="selectTime"></u-calendar>
</view>
</template>
<script>
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js"
import {numberfilter} from "@/static/common/js/util/number-to-chinese.js"
export default {
mixins: [MescrollMixin],
filters: {
numberfilter
},
data() {
return {
upOption:{
noMoreSize: 4,
textNoMore: '---- 已经到底啦 ----',
empty:{
tip: '~ 搜索无数据 ~' //
}
},
dataList:[],
timeshow: false,
mode: 'range',
minDate:'1950-01-01',
maxDate:'2023-12-28',
timeObj:{
beginTime:'',
endTime:''
},
loadStatus:'loadmore',//more-loading-nomore-
isLoadMore:false, //
emptyShow:false, //
pageNum:1,
pageSize:10,
orderByColumn:'alarmTime',
isAsc:'desc',
noticeTimeObj:{
beginTime:'',
endTime:''
}
}
},
components: {
},
onLoad() {
// this.getAlarmList();
},
onShow() {
},
methods: {
openSelect(){
this.maxDate=this.$u.timeFormat(new Date(), 'yyyy-mm-dd');
this.timeshow = true;
},
selectTime(e){
console.log("当前选择日期",e)
this.noticeTimeObj.beginTime = e.startDate;
this.noticeTimeObj.endTime = e.endDate;
//
this.mescroll.resetUpScroll();
},
upCallback(page) {
let opt = {
url: '/iot/admin/device/list',
method: 'POST',
};
let params = {
page: page.num,
pageSize: page.size,
search: this.searchVal
}
this.$request.TokenRequest(opt, params).then(res => {
console.log("获取设备列表",res)
//
res = {
"totalCount": 12,
"data": [
{
"tenantId": 10213,
"createId": 10403,
"createBy": "",
"createTime": "2023-12-02 23:25:06",
"updateBy": "",
"updateTime": "2023-12-02 23:25:06",
"recordId": 12738,
"sourceId": null,
"triggerId": 29,
"triggerName": "xt",
"deviceId": "322",
"deviceKey": "3JcEibiaC4baH1ie",
"alarmLevel": "1",
"alarmLevelName": null,
"currentValue": "(一号主机通道1:987)",
"alarmContent": "设备 报警",
"alarmTime": "2023-12-02T23:25:06",
"processState": "UNPROCESS",
"sendState": "SEND",
"sendCount": 1,
"sendWay": null,
"typeId": 20,
"typeCode": "4a7215I6DEBaH1aH",
"typeName": "低报报警",
"alarmDivide": "ALARM",
"alarmSource": "CLOUD",
"deviceName": "一号主机",
"processStateName": "未处理",
"alarmProcessList": [
],
"sendStateName": "已发送"
},
{
"tenantId": 10213,
"createId": 10403,
"createBy": "",
"createTime": "2023-12-02 23:24:05",
"updateBy": "",
"updateTime": "2023-12-02 23:24:05",
"recordId": 12733,
"sourceId": null,
"triggerId": 29,
"triggerName": "xt",
"deviceId": "322",
"deviceKey": "3JcEibiaC4baH1ie",
"alarmLevel": "1",
"alarmLevelName": null,
"currentValue": "(一号主机通道1:987)",
"alarmContent": "设备 报警",
"alarmTime": "2023-12-02T23:24:06",
"processState": "UNPROCESS",
"sendState": "SEND",
"sendCount": 1,
"sendWay": null,
"typeId": 20,
"typeCode": "4a7215I6DEBaH1aH",
"typeName": "低报报警",
"alarmDivide": "ALARM",
"alarmSource": "CLOUD",
"deviceName": "一号主机",
"processStateName": "未处理",
"alarmProcessList": [
],
"sendStateName": "已发送"
},
{
"tenantId": 10213,
"createId": 10403,
"createBy": "",
"createTime": "2023-12-02 23:24:05",
"updateBy": "",
"updateTime": "2023-12-02 23:24:05",
"recordId": 12734,
"sourceId": null,
"triggerId": 29,
"triggerName": "xt",
"deviceId": "322",
"deviceKey": "3JcEibiaC4baH1ie",
"alarmLevel": "1",
"alarmLevelName": null,
"currentValue": "(一号主机通道1:987)",
"alarmContent": "设备 报警",
"alarmTime": "2023-12-02T23:24:06",
"processState": "UNPROCESS",
"sendState": "SEND",
"sendCount": 1,
"sendWay": null,
"typeId": 20,
"typeCode": "4a7215I6DEBaH1aH",
"typeName": "低报报警",
"alarmDivide": "ALARM",
"alarmSource": "CLOUD",
"deviceName": "一号主机",
"processStateName": "未处理",
"alarmProcessList": [
],
"sendStateName": "已发送"
},
{
"tenantId": 10213,
"createId": 10403,
"createBy": "",
"createTime": "2023-12-02 23:24:05",
"updateBy": "",
"updateTime": "2023-12-02 23:24:05",
"recordId": 12735,
"sourceId": null,
"triggerId": 29,
"triggerName": "xt",
"deviceId": "322",
"deviceKey": "3JcEibiaC4baH1ie",
"alarmLevel": "1",
"alarmLevelName": null,
"currentValue": "(一号主机通道1:987)",
"alarmContent": "设备 报警",
"alarmTime": "2023-12-02T23:24:06",
"processState": "UNPROCESS",
"sendState": "SEND",
"sendCount": 1,
"sendWay": null,
"typeId": 20,
"typeCode": "4a7215I6DEBaH1aH",
"typeName": "低报报警",
"alarmDivide": "ALARM",
"alarmSource": "CLOUD",
"deviceName": "一号主机",
"processStateName": "未处理",
"alarmProcessList": [
],
"sendStateName": "已发送"
}
],
"code": 0,
"msg": "查询成功"
}
if(res.code === 0){
let curPageData = res.data && res.data;
let curPageLen = curPageData && curPageData.length || 0;
let totalSize = res.totalCount;
this.$nextTick(()=>{
// ;
this.mescroll.endBySize(curPageLen, totalSize);
})
//
if(page.num == 1) this.dataList = []; //
this.dataList = curPageLen > 0 && this.dataList.concat(curPageData); //
}else{
this.$u.toast(res.msg);
this.mescroll.endErr();
}
}, error => {
})
},
//
getAlarmList(){
let opt = {
url: '/prod-api/iot/alarm/record/list',
method: "GET",
}
let params = {
pageNum: this.pageNum,
pageSize: this.pageSize,
orderByColumn: this.orderByColumn,
isAsc: this.isAsc,
}
this.$request.TokenRequest(opt,params).then(res => {
console.log("getAlarmList",res);
if(res.code==200){
if(res.rows){
this.dataList.push(...res.rows);
//
if(!this.dataList.length){
this.emptyShow = true;
}else{
this.emptyShow = false;
}
//
if(res.rows.length<this.pageSize){ //判断接口返回数据量小于请求数据量则表示此为最后一页
this.isLoadMore=true
this.loadStatus='nomore'
}else{
this.isLoadMore=false
this.loadStatus='loadmore'
}
}else{
this.isLoadMore=true
this.loadStatus='nomore'
}
}else{
this.$u.toast(res.msg);
this.isLoadMore=false
if(this.pageNum>1){
this.pageNum=1
}
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
this.isLoadMore=false
if(this.pageNum>1){
this.pageNum=1
}
})
},
//
reachBottom() {
console.log("这里上拉加载更多")
if(!this.isLoadMore){ //
this.loadStatus = 'loading';
this.isLoadMore=true
this.pageNum+=1
this.getAlarmList()
}
},
}
}
</script>
<style>
page,.notice-box{
background: #f5f5f5;
}
</style>
<style scoped lang="scss">
.notice-box{
// background: #ebeef5;
// height: 100%;
// display: flex;
// flex-direction: column;
}
.notice-top{
position: fixed;
top: 0;
left: 0;
right: 0;
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
background: #FFFFFF;
border-bottom: 1px solid #f4f6f8;
z-index: 999;
.iconfont{
transform: rotate(90deg);
margin-left: 10rpx;
}
}
.notice-list{
padding: 24rpx 24rpx 0;
.notice-item{
width: 702rpx;
min-height: 381rpx;
background: #FFFFFF;
border-radius: 10rpx;
margin-bottom: 24rpx;
.item-header{
// height: 104rpx;
// padding-left: 28rpx;
// padding-top: 23rpx;
padding: 20rpx 25rpx;
box-sizing: border-box;
border-bottom: 1px solid #e8e8f2;
display: flex;
justify-content: space-between;
align-items: center;
.item-header-left{
.header-title{
font-size: 28rpx;
line-height: 28rpx;
color: #444444;
}
.header-time{
font-size: 26rpx;
line-height: 26rpx;
color: #999;
margin-top: 15rpx;
}
}
.item-header-right{
}
}
.item-body{
padding: 18rpx 26rpx;
display: flex;
justify-content: space-between;
align-items: flex-end;
.item-body-left{
.body-txt{
font-size: 26rpx;
line-height: 42rpx;
color: #0053A2;
text{
color: #444;
}
}
}
.item-body-right{
}
}
}
}
</style>

View File

@ -0,0 +1,287 @@
<template>
<view class="ability-box">
<view class="attr-list">
<view class="attr-list-item" :class="item.ioRequired?'required':''" v-for="(item,index) in dataList" :key="index" v-if="item.accessMode !=='r'">
<view class="checkbox-box">
<u-checkbox
size="40"
v-model="item.checked"
@change="changeCheck($event,index)"
></u-checkbox>
</view>
<view class="attr-list-item-content">
<!-- 选择器 -->
<iots-select
v-if="item.formType == 'select'"
:name="item.name"
:disabled="false"
v-model="item.value"
:selectList="item.ioObj.enums"
@change="changeData($event,index)"
:logShow="false"
></iots-select>
<!-- 步进器 -->
<iots-number-box
v-else-if="item.formType == 'number'"
:name="item.name"
:disabled="false"
:min="parseFloat(item.ioObj.IoDeployForm.min || 0)"
:max="parseFloat(item.ioObj.IoDeployForm.max || 100)"
:step="parseFloat(item.ioObj.IoDeployForm.step || 1)"
:integer="item.integer=='int'"
:unit="item.ioObj.unit"
:logShow="false"
@change="changeData($event,index)"
:value="item.value"
></iots-number-box>
<!-- 开关 -->
<iots-switch
v-else-if="item.formType == 'switch'"
:name="item.name"
:disabled="false"
v-model="item.value"
@change="changeData($event,index)"
:logShow="false"
></iots-switch>
<!-- 滑块 -->
<iots-slider
v-else-if="item.formType == 'slider'"
:name="item.name"
:disabled="false"
:min="parseFloat(item.ioObj.IoDeployForm.min || 0)"
:max="parseFloat(item.ioObj.IoDeployForm.max || 100)"
:step="parseFloat(item.ioObj.IoDeployForm.step || 1)"
:unit="item.ioObj.unit"
v-model="item.value"
@change="changeData($event,index)"
:logShow="false"
></iots-slider>
<!-- 时间选择器 -->
<iots-select-time
v-else-if="item.formType == 'time_picker'"
:name="item.name"
:disabled="false"
v-model="item.value"
@change="changeData($event,index)"
:logShow="false"
></iots-select-time>
<!-- 输入框 -->
<iots-input
v-else
:name="item.name"
:disabled="false"
v-model="item.value"
:unit="item.ioObj.unit"
@change="changeData($event,index)"
:logShow="false"
></iots-input>
</view>
</view>
</view>
<view class="btn-box">
<u-checkbox
size="40"
v-model="isSelectAll"
@change="changeCheckAll"
>全选</u-checkbox>
<button @click="execute">执行</button>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import IotsSelect from '@/components/iot-components/select/iots-select.vue'
import IotsNumberBox from "@/components/iot-components/number-box/iots-number-box.vue"
import IotsSwitch from '@/components/iot-components/switch/iots-switch.vue'
import IotsSlider from '@/components/iot-components/slider/iots-slider.vue'
import IotsInput from '@/components/iot-components/input/iots-input.vue'
import IotsSelectTime from '@/components/iot-components/select-time/iots-select-time.vue'
export default{
data(){
return {
abilityObj:{},
dataList:[],
devId:'',
pk:'',
isSelectAll:true,
}
},
components: {
IotsSelect,
IotsSelectTime,
IotsNumberBox,
IotsSwitch,
IotsSlider,
IotsInput,
},
onLoad(option) {
console.log("option",option)
let dataList = JSON.parse(decodeURIComponent(option.dataList).replace(/%25/g, '%'))
console.log("当前参数",dataList);
// this.abilityObj = ability;
this.devId = option.devId;
this.pk = option.pk;
// this.dataList = ability.ioObj.in;
this.formatData(dataList);
uni.setNavigationBarTitle({
title:option.devName+'设备控制'
})
},
methods:{
formatData(list){
let datalist = list.map(item=>{
item.checked = true;
return item;
})
this.dataList = datalist;
},
changeCheck(e,index){
let dataList = JSON.parse(JSON.stringify(this.dataList));
dataList[index].checked = e.value;
let isSelectAll = true;
dataList.forEach((item)=>{
if(!item.checked){
isSelectAll = false;
}
})
this.isSelectAll = isSelectAll;
},
changeCheckAll(e){
console.log("全选",e)
let dataList = JSON.parse(JSON.stringify(this.dataList));
dataList = dataList.map((item)=>{
item.checked = e.value;
return item;
})
this.$nextTick(()=>{
this.$set(this,'dataList',dataList)
this.$forceUpdate()
})
},
changeData(){
this.$forceUpdate()
},
execute(){
if(this.verification()){
let obj = {};
console.log("dataList",this.dataList)
this.dataList.forEach((item)=>{
if(item.checked){
obj[item.identifier]=item.value
}
})
let params = {
ac:'write',
d:this.devId,
pk:this.pk,
p:obj
}
this.$api.iotsApi.downDeviceAbility(params).then(res => {
console.log("下发数据成功",res)
if(res.code == 0){
// this.$u.toast('')
this.$refs.uToast.show({
title: '执行成功',
type: 'success',
})
}else{
this.$refs.uToast.show({
title: res.message,
type: 'error',
})
}
}, error => {
})
}else{
console.log("校验未通过")
}
},
//
verification(){
let flag = true;
this.dataList.forEach((item)=>{
if(flag && item.checked && !item.value && !['number', 'slider', 'switch'].includes(item.formType)){
this.$refs.uToast.show({
title: item.name + '不能为空!',
type: 'error',
})
flag = false;
}
})
return flag;
}
}
}
</script>
<style>
page{
background: #f5f5f5;
}
</style>
<style lang="scss" scoped>
/deep/.iots-component-box{
margin-top: 0 !important;
}
.ability-box{
padding-bottom: 140rpx;
}
.attr-list-item{
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20rpx;
background: #FFFFFF;
border-radius: 10rpx;
margin-top: 20rpx;
.checkbox-box{
padding: 0 20rpx;
width: 80rpx;
display: flex;
justify-content: center;
// margin-right: 20rpx;
}
.attr-list-item-content{
flex: 1;
position: relative;
&.required::after{
content: '';
width: 16rpx;
height: 16rpx;
border-radius: 50%;
position: absolute;
top: 12rpx;
left: 26rpx;
background: red;
}
}
}
.btn-box{
display: flex;
align-items: center;
justify-content: space-between;
background: #fff;
height: 140rpx;
padding: 0 30rpx;
padding-bottom: 10rpx;
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 99;
button{
width: 300rpx;
height: 90rpx;
background: #3683FD;
border-radius: 43rpx;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
}
}
</style>

View File

@ -0,0 +1,502 @@
<template>
<view id="data-list-box">
<view class="header">
<view class="header-item">
<text>设备名称</text>
<text>{{deviceName}}</text>
</view>
<view class="header-item">
<text>运行状态</text>
<text>{{deviceStateName}}</text>
</view>
</view>
<u-tabs :list="tabList" :is-scroll="false" :current="tabCurrent" :bar-width="138" :bold="false" :duration="0.1"
@change="tabChange"></u-tabs>
<!-- 自定义时间 -->
<view class="time-selcet-box" v-if="tabCurrent==3">
<view class="time-selcet">
<text @click="selectTime(0,startTime)">{{startTime?startTime:'开始时间'}}</text>
<view class="iconfont icon-shijian"></view>
<text @click="selectTime(1,endTime)">{{endTime?endTime:'结束时间'}}</text>
</view>
</view>
<view class="menu-list">
<view class="menu-left">
<view class="menu-btn" :class="btnActive==0?'active':''" @click="changeBtn(0)">列表模式</view>
<view class="menu-btn" :class="btnActive==1?'active':''" @click="changeBtn(1)">图表模式</view>
</view>
<view class="iconfont icon-reload" @click="getDataList"></view>
</view>
<!-- 列表 -->
<view class="data-list" v-if="btnActive==0">
<view class="data-list-header">
<text>时间</text>
<text></text>
</view>
<view class="data-item" v-for="(item,index) in dataList" :key="index">
<text>{{$u.timeFormat(item.fg_device_ts, 'yyyy-mm-dd hh:MM:ss')}}</text>
<text>{{item[fields]}}</text>
</view>
<u-empty :show="emptyShow" text="没有找到数据" :font-size="40" :icon-size="300" :margin-top="20" mode="list"
style="background: #fff;"></u-empty>
</view>
<!-- 图表 -->
<view class="data-chart" v-else>
<qiun-data-charts
type="line"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:canvasId="canvasId"
:enableScroll="true"
:ontouch="true"
/>
</view>
<!-- 分页 -->
<view class="list-pagination">
<uni-pagination :current="pageNum" :pageSize="pageSize" :total="total"
@change="changePagination"></uni-pagination>
</view>
<!-- 时间选择器 -->
<u-picker mode="time" v-model="timeShow" :default-time="defaultTime" :params="timeParams"
@confirm="confirmTime"></u-picker>
</view>
</template>
<script>
export default {
data() {
return {
btnActive:0,
tabList: [{
name: '近一天'
}, {
name: '近一周'
}, {
name: '近一月'
}, {
name: '自定义'
}],
tabCurrent: 0,
emptyShow: false, //
dataList: [],
//
timeShow: false,
//
timeParams: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true
},
defaultTime: '',
startTime: '',
endTime: '',
selectIndex: 0,
pageNum: 1,
pageSize: 10,
total: 10,
devId:null,
fields:null,
cmdId: null,
deviceKey: null,
field: null,
prodId: null,
deviceStateName: null,
//
listWhere: [{ // xx
field: "time",
operator: "gt",
val: 0,
valType: "time",
},
{ // xx
field: "time",
operator: "lt",
val: 0,
valType: "time",
},
],
deviceName: null,
chartData: {},
selectValue:this.value,
charShow: true,
canvasId:this.$u.guid(32),
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
enableScroll: true,
legend: {
show:false,
},
xAxis: {
disableGrid: true,
scrollShow: true,
itemCount: 6,
fontSize:10,
rotateAngle:60,
rotateLabel:true,
// boundaryGap:"justify",
},
yAxis: {
gridType: "dash",
dashLength: 1,
type:'value',
splitNumber:3,
data:[{tofix:2,min:0}]
},
extra: {
area: {
type: "straight",
width: 2,
activeType: "hollow"
}
}
},
}
},
components: {
},
onLoad(option) {
this.defaultTime = this.$u.date(new Date(), 'yyyy-mm-dd hh:MM:ss')
if (option) {
console.log("获取到的参数", option)
this.devId = option.devId;
this.fields = option.fields;
this.deviceName = option.devName;
this.deviceStateName = option.devState;
this.getDataList();
}
// this.getChartData();
},
onShow() {
},
methods: {
changeBtn(index){
this.btnActive = index;
this.getDataList();
},
//
getDataList() {
this.timeFormat();
let params = {
page: this.pageNum,
pageSize: this.pageSize,
devId: this.devId,
startTs: this.listWhere[0].val,
endTs: this.listWhere[1].val,
fields: this.fields + ',fg_device_ts'
}
console.log("params", params)
this.dataList = [];
this.$api.iotsApi.getDeviceDataList(params).then(res => {
console.log("getDataList", res);
if (res.code == 0) {
if (res.data) {
this.dataList = res.data.list?res.data.list:[];
this.pageNum = res.data.page;
this.total = res.data.totalCount;
//
if (!this.dataList.length) {
this.emptyShow = true;
} else {
this.emptyShow = false;
}
if(this.btnActive==1){
this.getChartData(res.data.list?res.data.list:[]);
}
console.log('this.emptyShow', this.emptyShow)
} else {}
} else {
this.$u.toast(res.msg);
if (this.pageNum > 1) {
this.pageNum = 1
}
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
if (this.pageNum > 1) {
this.pageNum = 1
}
})
},
getChartData(data) {
let resData = {
categories: [],
series: [{
name: "值",
data: []
}]
};
data.map((item,index)=>{
resData.categories.push(this.$u.timeFormat(item.fg_device_ts, 'yyyy-mm-dd hh:MM:ss'));
resData.series[0].data.push(item[this.fields]);
})
console.log("resData",resData)
this.chartData = JSON.parse(JSON.stringify(resData));
},
//
timeFormat() {
//
let date = new Date();
switch (this.tabCurrent) {
case 0:
this.listWhere[0].val = date.getTime() - 24 * 60 * 60 * 1000;
this.listWhere[1].val = date.getTime();
break;
case 1:
this.listWhere[0].val = date.getTime() - 24 * 7 * 60 * 60 * 1000;
this.listWhere[1].val = date.getTime();
break;
case 2:
this.listWhere[0].val = date.getTime() - 24 * 30 * 60 * 60 * 1000;
this.listWhere[1].val = date.getTime();
break;
default:
this.listWhere[0].val = 0
this.listWhere[1].val = 0
if (this.startTime) {
console.log("this.startTime", this.startTime)
let time1 = new Date(this.startTime);
this.listWhere[0].val = time1.getTime();
if (this.endTime) {
let time2 = new Date(this.endTime);
console.log("this.endTime", this.endTime)
this.listWhere[1].val = time2.getTime();
}
}
}
},
tabChange(index) {
this.tabCurrent = index;
this.pageNum = 1;
this.total = 10;
this.dataList = [];
this.getDataList();
},
//
changePagination(e) {
console.log("点击页面", e);
this.pageNum = e.current;
this.getDataList()
},
//
selectTime(index, defaultTime) {
this.selectIndex = index;
this.timeShow = true;
if (defaultTime) {
this.defaultTime = defaultTime;
}
},
//
confirmTime(obj) {
console.log(obj)
let time = obj.year + '-' + obj.month + '-' + obj.day + ' ' + obj.hour + ':' + obj.minute + ':' + obj
.second;
if (this.selectIndex == 0) {
this.startTime = time;
} else {
this.endTime = time;
}
if (this.startTime && this.endTime) {
this.getDataList();
}
}
}
}
</script>
<style>
page,.data-list-box{
background-color: #e9ecf3;
}
</style>
<style scoped lang="scss">
.header {
padding: 10rpx 24rpx 0;
background: #fff;
margin-bottom: 20rpx;
.header-item {
height: 98rpx;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 23rpx 0 17rpx;
font-size: 28rpx;
color: #444444;
line-height: 55px;
&:first-of-type {
border-bottom: 1px solid #E8EBF2;
}
text {
&:first-of-type {
color: #666;
}
}
}
}
//
.time-selcet-box {
padding: 18rpx 24rpx 0;
.time-selcet {
width: 702rpx;
height: 84rpx;
background: #FFFFFF;
// box-shadow: 0px 6rpx 29rpx 0px rgba(174, 185, 190, 0.7);
border-radius: 10rpx;
display: flex;
justify-content: space-around;
align-items: center;
text {
font-size: 26rpx;
color: #B4B4B4;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.iconfont {
font-size: 34rpx;
color: #444;
}
}
}
.menu-list{
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx;
padding-bottom: 0;
.menu-left{
display: flex;
align-items: center;
.menu-btn{
border: 1px solid #009CFF;
color: #009CFF;
border-radius: 10rpx;
background-color: #fff;
// height: 100rpx;
padding: 10rpx 20rpx;
display: flex;
justify-content: center;
align-items: center;
&.active{
color: #fff;
background: #009CFF;
}
&:first-child{
margin-right: 10rpx;
}
}
}
.iconfont{
font-size: 40rpx;
color: #009CFF;
font-weight: bold;
padding: 10rpx;
}
}
.data-list {
padding: 20rpx 20rpx 0;
.data-list-header {
height: 80rpx;
background: #FFFFFF;
// box-shadow: 0px 6rpx 18rpx 0px rgba(174, 185, 190, 0.7);
border-bottom: 1px solid #f5f5f5;
border-radius: 10rpx 10rpx 0 0;
z-index: 10;
position: relative;
display: flex;
text {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
font-size: 26rpx;
font-weight: bold;
color: #444444;
}
}
.data-item {
background: #FFFFFF;
height: 80rpx;
border-bottom: 1px solid #f5f5f5;
display: flex;
&:last-of-type {
border: none;
}
text {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
font-size: 24rpx;
color: #444444;
}
}
}
.data-chart{
margin: 20rpx 20rpx 0;
padding-bottom: 5rpx;
height: 800rpx;
background: #fff;
}
.list-pagination {
// width: 100%;
margin: 0 20rpx;
background: #FFFFFF;
border-top: 1px solid #f5f5f5;
border-radius: 0 0 10rpx 10rpx;
padding: 20rpx 40rpx;
/deep/ .uni-pagination__btn.uni-pagination__btn {
width: 140rpx;
height: 60rpx;
background: #FFFFFF;
border: 1px solid #DCDCDC;
border-radius: 5rpx;
font-size: 24rpx;
line-height: 60rpx;
text {
color: #727272;
}
}
/deep/ .uni-pagination--enabled.uni-pagination--enabled {
border: 1px solid #009CFF;
text {
color: #009CFF;
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,391 @@
<template>
<view class="device-list-box">
<!-- 菜单 -->
<view class="device-search">
<u-dropdown class="sl-filter" border-bottom >
<u-dropdown-item v-model="productId" title="所属产品" height="750" :options="productList" @change="searchChange"></u-dropdown-item>
<u-dropdown-item v-model="deviceType" title="设备类型" :options="deviceTypeList" @change="searchChange"></u-dropdown-item>
</u-dropdown>
<u-search placeholder="请输入设备名称/编号搜索" class="uni-search-bar" v-model="searchVal" @custom="searchChange" @clear="searchChange" @search="searchChange"></u-search>
<u-tabs :list="tabsList" bar-width="187" :is-scroll="false" :current="tabIndex" @change="tabChange"></u-tabs>
</view>
<mescroll-body ref="mescrollRef" top="260" @init="mescrollInit" @down="downCallback" :up="upOption" @up="upCallback">
<view class="device-box">
<view class="device-info">
<view class="name">设备总数: <text style="font-size: 24rpx;">{{total}}</text></view>
</view>
<!-- 设备列表 -->
<view class="device-list">
<view class="device-item" v-for="(item, index) in dataList" :key="index" @click="goDetail(item)">
<view class="device-name">
{{item.devName}}
</view>
<view class="device-status">
<view class="device-status-item">
<u-icon name="wifi" :color="item.devState==1?'#10CC70':item.devState==2?'#FF2B38':'#999999'"
size="26"></u-icon>
<text
:style="{marginLeft:'10rpx',color:item.devState==1?'#10CC70':item.devState==2?'#FF2B38':'#999999'}">{{item.devState==1?'在线':item.devState==2?'离线':'未激活'}}</text>
</view>
<!-- <view class="device-status-item notice-tag">
<u-icon name="warning" color="#F6A582" size="26"></u-icon>
<text
:style="{marginLeft:'10rpx',color:'#F6A582'}">告警未处理</text>
</view> -->
</view>
<view class="device-img-box">
<image v-if="item.devImage" :src="imgPath + item.devImage" mode=""></image>
<!-- #ifdef MP-WEIXIN -->
<image v-else src="https://file.iot-fast.com/wxapp/static/image/device/device-default.png" mode=""></image>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<image v-else src="/static/app-plus/image/device/device-default.png" mode=""></image>
<!-- #endif -->
</view>
</view>
</view>
</view>
</mescroll-body>
<u-tabbar class="tabbar-box" v-model="tabbarIndex" active-color="#1890ff" :list="tabbarList" @change="tabbarChange"></u-tabbar>
</view>
</template>
<script>
import IotsTabbarMixin from "../iotsTabbarMixins.js"
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js"
export default {
mixins: [IotsTabbarMixin,MescrollMixin],
components: {
},
data() {
return {
upOption:{
noMoreSize: 4,
textNoMore: '---- 已经到底啦 ----',
empty:{
tip: '~ 搜索无数据 ~' //
}
},
tabbarIndex:1,
productId:null,
deviceType:null,
searchVal: '',
tabIndex: 0, // tab
productList:[],
deviceTypeList:[
{
label: '全部设备',
value: null,
},
{
label: '直连设备',
value: 'dev',
},
{
label: '网关子设备',
value: 'childrenDevice',
},
{
label: '网关设备',
value: 'gateway',
}
],
tabsList:[{
name: '全部',
value: null
}, {
name: '未激活',
value: 0
}, {
name: '在线',
value: 1
}, {
name: '离线',
value: 2
}],
dataList: [],
total: 0,
imgPath:'',
}
},
onLoad() {
this.getConfigPath();
this.getProductList();
},
methods: {
goDetail(obj){
// console.log("",obj)
uni.navigateTo({
url:'./device-detail?id=' + obj.id + '&devName=' + obj.devName
})
},
getConfigPath(){
let configList = uni.getStorageSync('configList');
let configIndex = uni.getStorageSync('configIndex');
this.imgPath = configList[configIndex].protocol + configList[configIndex].address;
},
getDeviveTypeName(e){
if(e == 'dev'){
return '直连设备'
}else if(e == 'childrenDevice'){
return '网关子设备'
}else if(e == 'gateway'){
return '网关设备'
}else{
return '-'
}
},
//
tabChange(e) {
this.tabIndex = e;
this.mescroll.resetUpScroll() //
},
searchChange(e) {
// this.searchVal = res.value
this.dataList = []// ,
this.mescroll.resetUpScroll() //
},
getProductList(){
this.$api.iotsApi.getProductList({page:1,pageSize:999}).then(res => {
if(res.code == 0 && res.data.list.length>0){
let productList = res.data.list.map((item)=>{
return {
label:item.prodName,
value:item.pk
}
})
this.productList = [{
label: '全部产品',
value: null,
},...productList];
}else{
this.productList = [{
label: '全部产品',
value: null,
}];
}
}, error => {
})
},
upCallback(page) {
let params = {
"pk": this.productId,
"page": page.num,
"pageSize": page.size,
"Wheres": {
"wheres": [
{"field": "prodType","operator": "=","value": this.deviceType},
{"field":"devState","operator":"=","value":this.tabsList[this.tabIndex].value},
{"fields": ["devId","devName"],"operator": "keyword","value": this.searchVal}
]
},
}
this.$api.iotsApi.getDeviceList(params).then(res => {
if(res.code === 0){
let curPageData = res.data && res.data.list;
let curPageLen = curPageData && curPageData.length || 0;
let totalSize = res.data.totalCount;
this.$nextTick(()=>{
// ;
this.mescroll.endBySize(curPageLen, totalSize);
})
//
if(page.num == 1) this.dataList = []; //
this.dataList = curPageLen > 0 && this.dataList.concat(curPageData); //
this.total = totalSize;
}else{
this.$u.toast(res.msg);
this.mescroll.endErr();
}
}, error => {
})
}
}
}
</script>
<style>
page{
background-color: #f5f5f5;
}
</style>
<style lang="scss" scoped>
/deep/.u-search{
padding: 19rpx 20rpx;
border-bottom: 1px solid #f4f6f8;
}
.device-list-box{
width: 100%;
height: 100%;
background-color: #f5f5f5;
.device-search{
position: fixed;
top: 0;
left: 0;
box-sizing: border-box;
height: 260rpx;
background-color: #fff;
width: 100%;
z-index: 999;
}
.device-box{
.device-info{
padding: 20rpx 20rpx;
padding-bottom: 0;
.name{
font-size: 28rpx;
font-weight: bold;
color: #333333;
}
}
.device-list {
display: flex;
flex-wrap: wrap;
padding: 20rpx;
// background-color: #f5f5f5;
.device-item {
width: 345rpx;
// height: 300rpx;
background: #fff;
border-radius: 20rpx;
margin-bottom: 20rpx;
font-weight: bold;
padding: 20rpx;
box-sizing: border-box;
// overflow: hidden;
&:nth-child(2n-1) {
margin-right: 20rpx;
}
.device-name {
font-size: 28rpx;
line-height: 28rpx;
display: inline-block;
width: 310rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.device-status{
display: flex;
align-items: center;
margin-bottom: 10rpx;
font-size: 22rpx;
line-height: 22rpx;
.device-status-item{
display: flex;
align-items: center;
&.notice-tag{
margin-left:auto;
}
}
}
.device-img-box {
margin-left: 10rpx;
width: 120rpx;
height: 120rpx;
// background: #f5f5f5;
// display: flex;
// justify-content: center;
// align-items: center;
image{
width: 100%;
height: 100%;
}
}
}
}
// .device-list{
// padding: 0 20rpx;
// box-sizing: border-box;
// .device-item{
// width: 100%;
// background-color: #fff;
// box-shadow: 0px 0px 10px 0px rgba(192,192,192,0.5);
// border-radius: 12rpx;
// // padding: 20rpx 40rpx;
// box-sizing: border-box;
// margin-top: 20rpx;
// .device-item-top{
// display: flex;
// align-items: center;
// justify-content: space-between;
// font-size: 28rpx;
// color: #333333;
// padding: 20rpx 30rpx;
// // padding-bottom: 20rpx;
// box-sizing: border-box;
// border-bottom: 1rpx solid #f1f1f1;
// .device-id{
// flex: 1;
// overflow: hidden;
// text-overflow: ellipsis;
// word-break: break-all;
// }
// }
// .device-content{
// display: flex;
// justify-content: space-between;
// align-items: center;
// padding:20rpx 30rpx;
// .device-content-left{
// .device-centent-center{
// display: flex;
// align-items: center;
// .device-img-box{
// // padding: 20rpx;
// margin-right: 20rpx;
// width: 120rpx;
// height: 120rpx;
// // background: #f5f5f5;
// display: flex;
// justify-content: center;
// align-items: center;
// image{
// width: 100%;
// height: 100%;
// }
// }
// .device-name{
// font-size: 30rpx;
// font-weight: bold;
// }
// }
// .detail-centent-bottom{
// .device-item-row{
// display: flex;
// // align-items: center;
// line-height: 50rpx;
// font-size: 28rpx;
// color: #333333;
// margin-top: 10rpx;
// .name{
// width: 140rpx;
// }
// .val{
// flex: 1;
// overflow: hidden;
// text-overflow: ellipsis;
// word-break: break-all;
// }
// }
// }
// }
// .device-content-right{
// font-size: 28rpx;
// font-weight: bold;
// }
// }
// }
// }
}
}
</style>

622
pages/iots/home/index.vue Normal file
View File

@ -0,0 +1,622 @@
<template>
<view class="iots-home">
<view class="iots-header">
<view class="main-item alarm-item" @click="goNoticeList">
<view class="main-header alarm-header">
<view class="main-title alarm-title">
<view class="title-box alarm-title-box">
<view class="iconfont icon-baojingguanli"></view>
</view>
<text>报警统计</text>
</view>
<view class="iconfont icon-xiangyou1"></view>
</view>
<view class="alarm-content">
<view class="content-left">
<view class="item-num">{{deviceInfo.alarmCount}}</view>
<view class="item-name">报警总数</view>
</view>
<view class="content-right">
<view class="content-right-item">
<view class="item-num">{{deviceInfo.applyCount}}</view>
<view class="item-name">已处理</view>
</view>
<view class="content-right-item">
<view class="item-num">{{deviceInfo.notApplyCount}}</view>
<view class="item-name">未处理</view>
</view>
</view>
</view>
</view>
<view class="main-item device-item" @click="goDeviceList">
<view class="main-header device-header">
<view class="main-title device-title">
<view class="title-box device-title-box">
<view class="iconfont icon-shebei1"></view>
</view>
<text>设备统计</text>
</view>
<view class="iconfont icon-xiangyou1"></view>
</view>
<view class="main-content device-content">
<view class="content-item">
<view class="content-item-left">
<view class="iconfont icon-shebeizongshu"></view>
</view>
<view class="content-item-right">
<text class="item-num">{{deviceInfo.deviceCount}}</text>
<text class="item-name">设备总数</text>
</view>
</view>
<view class="content-item">
<view class="content-item-left">
<view class="iconfont icon-shebeizaixian"></view>
</view>
<view class="content-item-right">
<text class="item-num">{{deviceInfo.onlineCount}}</text>
<text class="item-name">在线数</text>
</view>
</view>
<view class="content-item">
<view class="content-item-left">
<view class="iconfont icon-shebeilixian"></view>
</view>
<view class="content-item-right">
<text class="item-num">{{deviceInfo.offlineCount}}</text>
<text class="item-name">离线数</text>
</view>
</view>
</view>
</view>
<u-tabs :list="productList" name="label" :current="tabIndex" @change="tabChange"></u-tabs>
</view>
<mescroll-uni ref="mescrollRef" :top="top" :height="mescrollHeight" :bottom="bottom" @init="mescrollInit" @down="downCallback"
:up="upOption" @up="upCallback">
<view class="device-box">
<!-- 设备列表 -->
<view class="device-list">
<view class="device-item" v-for="(item, index) in dataList" :key="index" @click="goDetail(item)">
<view class="device-name">
{{item.devName}}
</view>
<view class="device-status">
<view class="device-status-item">
<u-icon name="wifi" :color="item.devState==1?'#10CC70':item.devState==2?'#FF2B38':'#999999'"
size="26"></u-icon>
<text
:style="{marginLeft:'10rpx',color:item.devState==1?'#10CC70':item.devState==2?'#FF2B38':'#999999'}">{{item.devState==1?'在线':item.devState==2?'离线':'未激活'}}</text>
</view>
<!-- <view class="device-status-item notice-tag">
<u-icon name="warning" color="#F6A582" size="26"></u-icon>
<text
:style="{marginLeft:'10rpx',color:'#F6A582'}">告警未处理</text>
</view> -->
</view>
<view class="device-img-box">
<image v-if="item.devImage" :src="imgPath + item.devImage" mode=""></image>
<!-- #ifdef MP-WEIXIN -->
<image v-else src="https://file.iot-fast.com/wxapp/static/image/device/device-default.png" mode=""></image>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<image v-else src="/static/app-plus/image/device/device-default.png" mode=""></image>
<!-- #endif -->
</view>
</view>
</view>
</view>
</mescroll-uni>
<u-tabbar class="tabbar-box" v-model="tabbarIndex" active-color="#1890ff" :list="tabbarList" @change="tabbarChange"></u-tabbar>
</view>
</template>
<script>
let that = null;
import IotsTabbarMixin from "../iotsTabbarMixins.js"
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js"
export default {
mixins: [IotsTabbarMixin,MescrollMixin],
data() {
return {
upOption: {
noMoreSize: 4,
textNoMore: '---- 已经到底啦 ----',
empty: {
tip: '~ 设备为空 ~' //
},
onScroll: true
},
tabbarIndex:0,
top: 738,
bottom: '50px',
mescrollHeight: 0,
dataList: [],
total: 0,
productList: [{
label: '全部产品',
value: null
}],
tabIndex: 0,
productPk: null,
deviceInfo: {
deviceCount: 0,
onlineCount: 0,
productCount: 0,
offlineCount: 0,
activeCount: 0,
notActiveCount: 0,
alarmCount: 0,
applyCount: 0,
notApplyCount: 0,
},
timer: null,
imgPath:'',
};
},
props: {
showToggle: {
type: Boolean,
default: () => {
return false
}
},
hideToggle: {
type: Boolean,
default: () => {
return false
}
}
},
watch: {
// showToggle() {
// console.log("show")
// clearInterval(this.timer);
// this.timer = setInterval(() => {
// this.mescroll.resetUpScroll();
// console.log("Index", this.showStartIndex, this.showEndIndex);
// }, 5000)
// },
// hideToggle() {
// console.log("hide")
// clearInterval(this.timer);
// },
},
onLoad() {
that = this;
this.getConfigPath();
this.getDeviceInfo();
this.getProductList();
const query = uni.createSelectorQuery().in(this);
const sys = uni.getSystemInfoSync();
setTimeout(() => {
query
.select(".iots-header")
.boundingClientRect((data) => {
console.log("当前值为",data)
this.top = data.height + 'px';
// #ifdef APP-PLUS
this.top = data.height + 'px';
// #endif
this.height = (sys.windowHeight - data.height) * 2 - 50;
})
.exec();
}, 0)
},
methods: {
getConfigPath(){
let configList = uni.getStorageSync('configList');
let configIndex = uni.getStorageSync('configIndex');
this.imgPath = configList[configIndex].protocol + configList[configIndex].address;
},
getDeviceInfo() {
this.$api.iotsApi.getDeviceCount({}).then(res => {
console.log("获取数据为", res)
if (res.code == 0) {
this.deviceInfo = res.data;
}
}, error => {})
},
goDeviceList() {
uni.redirectTo({
url: '/pages/iots/device/device-list'
})
},
goDetail(obj){
uni.navigateTo({
url:'/pages/iots/device/device-detail?id=' + obj.id + '&devName=' + obj.devName
})
},
goNoticeList() {
// this.$u.toast('')
uni.redirectTo({
url:'/pages/iots/notice/index'
})
},
getProductList() {
this.$api.iotsApi.getProductList({
page: 1,
pageSize: 999
}).then(res => {
if (res.code == 0 && res.data.list.length > 0) {
let productList = res.data.list.map((item) => {
return {
label: item.prodName,
value: item.pk
}
})
this.productList = [{
label: '全部产品',
value: null,
}, ...productList];
} else {
this.productList = [{
label: '全部产品',
value: null,
}];
}
}, error => {})
},
tabChange(e) {
// id
console.log("当前点击tab", e)
this.tabIndex = e;
this.productPk = this.productList[e].value;
this.mescroll.resetUpScroll();
},
changeSwitch(e, index) {
console.log("当前点击开关", e, index)
},
changeSelect(e, index) {
console.log("选择", e, index)
},
upCallback(page) {
let params = {
"pk": this.productPk,
"page": page.num,
"pageSize": page.size,
// "Wheres": {
// "wheres": [
// {"field": "prodType","operator": "=","value": null},
// {"field":"devState","operator":"=","value":'null'},
// {"fields": ["devId","devName"],"operator": "keyword","value": ''}
// ]
// },
}
this.$api.iotsApi.getDeviceList(params).then(res => {
if (res.code === 0) {
let curPageData = res.data && res.data.list;
// let curPageData = res.data && deviceData;
let curPageLen = curPageData && curPageData.length || 0;
let totalSize = res.data.totalCount;
this.$nextTick(() => {
// ;
this.mescroll.endBySize(curPageLen, totalSize);
})
//
if (page.num == 1) {
this.dataList = []; //
}
this.dataList = curPageLen > 0 && this.dataList.concat(curPageData); //
this.total = totalSize;
} else {
this.$u.toast(res.msg);
this.mescroll.endErr();
}
}, error => {})
}
}
}
</script>
<style>
page{
background-color: #f5f5f5;
}
</style>
<style lang="scss" scoped>
.iots-home {
height: 100%;
background-color: #f5f5f5;
// padding: 10rpx;
font-family: Georgia, 'Times New Roman', Times, serif;
}
.iots-header {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 99;
background-color: #f5f5f5;
}
.device-list {
display: flex;
flex-wrap: wrap;
padding: 20rpx;
// background-color: #f5f5f5;
.device-item {
width: 345rpx;
// height: 300rpx;
background: #fff;
border-radius: 20rpx;
margin-bottom: 20rpx;
font-weight: bold;
padding: 20rpx;
box-sizing: border-box;
// overflow: hidden;
&:nth-child(2n-1) {
margin-right: 20rpx;
}
.device-name {
font-size: 28rpx;
line-height: 28rpx;
display: inline-block;
width: 310rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.device-status{
display: flex;
align-items: center;
margin-bottom: 10rpx;
font-size: 22rpx;
line-height: 22rpx;
.device-status-item{
display: flex;
align-items: center;
&.notice-tag{
margin-left:auto;
}
}
}
.device-img-box {
margin-left: 10rpx;
width: 120rpx;
height: 120rpx;
// background: #f5f5f5;
// display: flex;
// justify-content: center;
// align-items: center;
image{
width: 100%;
height: 100%;
}
}
}
}
.menu-list {
display: flex;
.menu-item {
flex: 1;
margin: 20rpx;
background-color: #fff;
border-radius: 20rpx;
height: 130rpx;
display: flex;
align-items: center;
justify-content: space-around;
padding: 0 50rpx;
box-shadow: 0px 0px 15rpx 0px rgba(201, 201, 201, 0.4);
.iconfont {
font-size: 80rpx;
background-image: -webkit-linear-gradient(90deg, #3BBCFF, #006CFF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.menu-txt {
font-size: 50rpx;
font-family: Georgia, 'Times New Roman', Times, serif;
font-weight: bold;
}
}
&.menu-list-three {
.menu-item {
padding: 0 15rpx;
}
}
}
.main-item {
margin: 20rpx;
background-color: #fff;
border-radius: 20rpx;
// height: 200rpx;
box-shadow: 0px 0px 15rpx 0px rgba(201, 201, 201, 0.4);
.main-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 70rpx;
padding: 0 20rpx;
.main-title {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 500;
.title-box{
width: 40rpx;
height: 40rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
border-radius: 50%;
.iconfont{
font-size: 26rpx;
line-height: 26rpx;
color: #fff;
}
}
>text{
font-weight: 600;
}
}
.icon-xiangyou1{
color: #939393;
}
}
}
.alarm-item{
.alarm-title{
.alarm-title-box{
background: linear-gradient(180deg, #FFE99E, #FA9930);
box-shadow: 0px 6rpx 10rpx 0px rgba(255,206,142,0.81);
}
}
.alarm-content{
padding: 20rpx;
display: flex;
font-weight: 500;
.content-left{
flex: 1;
margin-right: 10rpx;
height: 250rpx;
/* #ifdef MP-WEIXIN */
background: url('https://file.iot-fast.com/wxapp/static/image/device/alarm1.png') no-repeat right bottom,#FFF8E8;
/* #endif */
/* #ifndef MP-WEIXIN */
background: url('@/static/app-plus/image/device/alarm1.png') no-repeat right bottom,#FFF8E8;
/* #endif */
background-size: auto 75%;
// padding: 25rpx 30rpx;
box-sizing: border-box;
border-radius: 10rpx;
>view{
margin-left: 30rpx;
margin-top: 25rpx;
width: 115rpx;
text-align: center;
color: #F6A582;
font-size: 28rpx;
line-height: 28rpx;
&:first-child{
margin-bottom: 24rpx;
}
}
}
.content-right{
flex: 1;
display: flex;
flex-direction: column;
font-size: 28rpx;
line-height: 28rpx;
.content-right-item{
flex: 1;
width: 100%;
height: 80rpx;
padding: 25rpx 30rpx 15rpx;
border-radius: 10rpx;
box-sizing: border-box;
&:first-child{
margin-bottom: 10rpx;
/* #ifdef MP-WEIXIN */
background: url('https://file.iot-fast.com/wxapp/static/image/device/alarm2.png') no-repeat right bottom,#ECF2FE;
/* #endif */
/* #ifndef MP-WEIXIN */
background: url('@/static/app-plus/image/device/alarm2.png') no-repeat right bottom,#ECF2FE;
/* #endif */
background-size: auto 85%;
>view{
width: 110rpx;
text-align: center;
color: #616FE7;
&:first-child{
margin-bottom: 16rpx;
}
}
}
&:last-child{
/* #ifdef MP-WEIXIN */
background: url('https://file.iot-fast.com/wxapp/static/image/device/alarm3.png') no-repeat right bottom,#E9F9FF;
/* #endif */
/* #ifndef MP-WEIXIN */
background: url('@/static/app-plus/image/device/alarm3.png') no-repeat right bottom,#E9F9FF;
/* #endif */
background-size: auto 85%;
>view{
width: 110rpx;
text-align: center;
color: #319DC6;
&:first-child{
margin-bottom: 12rpx;
}
}
}
}
}
}
}
.device-item{
.device-title{
.device-title-box{
background: linear-gradient(180deg, #9EDAFF, #5D96FF);
box-shadow: 0px 6px 10px 0px rgba(142,181,255,0.81);
}
}
.device-content{
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
padding: 30rpx;
.content-item{
width: 50%;
display: flex;
align-items: center;
padding-left: 30rpx;
&:nth-child(3){
margin-top: 30rpx;
}
.content-item-left{
width: 62rpx;
height: 62rpx;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(0deg, #9EDAFF, #FFFFFF);
border-radius: 50%;
color:#0a73ee;
margin-right: 20rpx;
.iconfont{
font-size: 38rpx;
font-weight: 550;
// margin-bottom: 4rpx;
background-image: -webkit-linear-gradient(0deg, #3BBCFF, #006CFF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.content-item-right{
.item-num{
font-size: 36rpx;
font-weight: 550;
}
.item-name{
color: #777;
}
>text{
display: block;
}
}
}
}
}
</style>

View File

@ -0,0 +1,51 @@
let _this ;
import tabbarList from '@/common/js/tabbarList.js'
export default {
data() {
return {
tabbarList:tabbarList.list,
bottom:100,
}
},
onLoad(opt) {
const query = uni.createSelectorQuery().in(this);
setTimeout(() => {
query
.select(".tabbar-box")
.boundingClientRect((data) => {
this.bottom = data.height * 2;
})
.exec();
}, 0)
},
onReady() {
},
methods: {
tabbarChange(e){
// console.log("当前点击tabbar",this.tabbarList[e])
if(e!==this.tabbarIndex){
if(e === 2){
uni.navigateTo({
url:this.tabbarList[e].pagePath
})
}
// else if(e === 3){
// uni.navigateTo({
// url:this.tabbarList[e].pagePath
// })
// // this.$u.toast('功能未完成')
// }
else{
uni.redirectTo({
url:this.tabbarList[e].pagePath
})
}
}
}
},
computed: {},
components: {}
}

View File

@ -0,0 +1,558 @@
<template>
<view class="map-box">
<map
id="maps"
ref="maps"
:style="{'width': width,'height': height}"
:longitude="mapLocation.longitude"
:latitude="mapLocation.latitude"
show-location="false"
:include-points="includePoints"
:markers="mapMarkers"
:polyline="mapPolyline"
:polygons="mapPolygons"
:scale="scale"
:enable-scroll="true"
@markertap="pointClick"
@tap="mapClick"
@regionchange="getRegion"
>
</map>
<view class="search-box">
<view class="search-content">
<input class="search-content-input" type="text" placeholder="搜索设备名称/ID" v-model="searchVal" @input="getDeviceDataList(true)">
<button class="search-content-btn" @click="getDeviceDataList(true)"><text class="search-content-btn-txt">搜索</text></button>
</view>
<scroll-view class="search-list" scroll-y="true" v-if="isShowSearchList">
<view class="search-item" :class="activeId==item.id?'active':''" v-for="(item,index) in deviceList" :key="item.id" @click="selectDevice(item,index)">
<!-- <view class="item-img"> -->
<image class="item-img" :src="item.devImage ? imgPath + item.devImage : deviceDefaultPath"></image>
<!-- </view> -->
<view class="item-content">
<text class="item-title">
{{item.devName}}
</text>
<text class="item-info">
{{item.devId}}
</text>
</view>
</view>
<view class="empty-box" v-if="deviceList.length == 0 && showEmpy">
<image class="empty-box-img" :src="deviceDefaultPath"></image>
<text class="empty-box-txt">暂无设备</text>
</view>
</scroll-view>
</view>
<scroll-view class="info-box" v-if="isModel" scroll-y="true" :style="{height:deviceInfoList.length>7?'600rpx':'auto'}">
<view class="info-box-header">
<!-- <view class="iconfont icon-plus" @click="isModel=false"></view> -->
<text class="icon-close" @click="isModel=false">×</text>
</view>
<view class="info-box-content">
<!-- <view class="info-img"> -->
<image class="info-img" :src="deviceInfo.devImage ? imgPath + deviceInfo.devImage : deviceDefaultPath" mode=""></image>
<!-- </view> -->
<view class="info-list">
<view class="info-item">
<text class="item-label">
设备名:
</text>
<text class="item-value">
{{deviceInfo.devName}}
</text>
</view>
<view class="info-item">
<text class="item-label">
在线状态:
</text>
<text class="item-value" :style="{color:deviceInfo.devState==1?'#10CC70':deviceInfo.devState==2?'#FF2B38':'#999999'}">
{{deviceInfo.devState==1?'在线':deviceInfo.devState==2?'离线':'未激活'}}
</text>
</view>
<view class="info-item">
<text class="item-label">
设备ID
</text>
<text class="item-value">
{{deviceInfo.devId}}
</text>
</view>
<view class="info-item">
<text class="item-label">
上线时间:
</text>
<text class="item-value">
{{deviceInfo.lastOnlineTime}}
</text>
</view>
<view class="info-item">
<text class="item-label">
PK
</text>
<text class="item-value">
{{deviceInfo.pk}}
</text>
</view>
</view>
</view>
<button class="info-box-btn" @click="goDeviceDetail"><text class="info-box-btn-txt">查看设备详情</text></button>
</scroll-view>
</view>
</template>
<script>
import { numAdd,numSub } from '@/common/js/util/js-calculate.js'
import request from '@/network/request.js'
export default {
data() {
return {
mapCtx:null,
mapLocation:{
longitude:119.216327,
latitude:26.028788
},
scale:12,
includePoints:[],
height:'500px',
width:'100%',
mapMarkers:[],
mapPolyline:[],
mapPolygons:[],
isModel:false,
deviceInfoList:[
{
label:'设备id',
value:'00000000000001'
},
{
label:'设备名称',
value:'换电柜001'
},
{
label:'设备状态',
value:'在线'
},
{
label:'仓门数量',
value:'5'
},
{
label:'电池数量',
value:'4'
}
],
pointData:[],
isShowSearchList:false,
showEmpy:false,
searchVal:'',
imgPath:'',
activeIndex:-1,
activeId:0,
deviceList:[],
deviceInfo:{
devImage:null,
devName:null,
devState:0,
devId:null,
lastOnlineTime:null,
pk:null,
},
mapRange:{
latMax:0,
latMin:0,
lngMax:0,
lngMin:0,
},
deviceDefaultPath:'/static/app-plus/image/device/device-default.png'
};
},
onReady() {
if (!this.mapCtx) {
this.mapCtx = uni.createMapContext("maps",this); // map 组件绑定,操作对应的 map 组件
}
// this.deviceDefaultPath = this.$staticPath+'/image/device/device-default.png';
this.getRegion();
},
onLoad(option) {
this.getConfigPath();
this.getSystemInfo();
// this.getDeviceDataList();
},
methods:{
// 获取系统信息
getSystemInfo() {
uni.getSystemInfo({
success: (res) => {
console.log("获取到系统信息", res)
let height = (res.windowHeight ) + 'px'
this.$set(this, "height", height)
this.$set(this, "width", res.windowWidth)
}
})
},
selectDevice(data,index){
this.activeIndex = index;
this.activeId = data.id;
this.deviceInfo = data;
this.mapLocation.longitude = data.lng;
this.mapLocation.latitude = data.lat;
this.isShowSearchList = false;
this.isModel = true;
},
getConfigPath(){
let configList = uni.getStorageSync('configList');
let configIndex = uni.getStorageSync('configIndex');
this.imgPath = configList[configIndex].protocol + configList[configIndex].address;
},
getDeviceDataList(flag){
let params = {
"page": 1,
"pageSize": 99999,
"Wheres": {
"wheres": [
{"field": "locateState","operator": "=","value": 1},
{"field": "lng","operator": ">=","value": this.mapRange.lngMin},
{"field": "lng","operator": "<=","value": this.mapRange.lngMax},
{"field": "lat","operator": ">=","value": this.mapRange.latMin},
{"field": "lat","operator": "<=","value": this.mapRange.latMax},
// {"field": "prodType","operator": "=","value": this.deviceType},
// {"field":"devState","operator":"=","value":this.tabsList[this.tabIndex].value},
{"fields": ["devId","devName"],"operator": "keyword","value": this.searchVal}
]
},
}
request.TokenRequest({
url: '/iot/admin/device/list',
method: 'POST',
},params)
.then((res) =>{
console.log("获取设备列表",res)
// res.data.list = null;
if(res.code === 0){
this.deviceList = res.data.list ? res.data.list : [];
if(res.data.list){
this.getPointData()
}
if(flag){
this.isShowSearchList = true;
this.showEmpy = res.data.list ? false : true;
}
}else{
this.deviceList = [];
if(flag){
this.isShowSearchList = true;
this.showEmpy = true;
}
}
}).catch(err =>{
})
},
getRegion() {
this.mapCtx.getRegion({
success: res => {
let obj = {
"latMax": res.northeast.latitude.toString(),
"latMin": res.southwest.latitude.toString(),
"lngMax": res.northeast.longitude.toString(),
"lngMin": res.southwest.longitude.toString(),
}
this.mapRange = obj;
this.getDeviceDataList(false);
},
fail: (data, code) => {
console.log('fail' + JSON.stringify(data));
}
})
},
getPointData(){
let includePoints = [];
let points = this.deviceList.map((item,index)=>{
includePoints.push({
longitude:item.lng,
latitude:item.lat,
})
// this.pointData.push({
// index:index,
// id:item.id,
// infoData:item.infoData,
// longitude:item.lng,
// latitude:item.lat,
// })
let x = 0;
if(uni.getSystemInfoSync().platform=='android'){
x = - item.devName.length*5;
}else{
x = - item.devName.length*8;
}
return {
// id:item.id,
id:index,
longitude:item.lng,
latitude:item.lat,
title:item.devName,
label:{
content:item.devName,
textAlign:'center',
color:'#2e66e7',
anchorX:x,
textAlign:'left'
},
// iconPath: '/static/image/device/location-blue.png',
iconPath: item.devImage ? this.imgPath + item.devImage : this.deviceDefaultPath,
width:24,
height:24,
}
});
this.$nextTick(()=>{
this.$set(this,'mapMarkers',points);
this.$forceUpdate()//手动刷新页面数据
})
// this.includePoints = this.getPaddingPoints(includePoints);
// this.mapCtx.includePoints({
// padding: [20,20,20,20],
// points: this.getPaddingPoints(includePoints)
// })
},
// 经纬度向四周移动0.0001约为10米防止边缘点位被覆盖
getPaddingPoints(points){
points = JSON.parse(JSON.stringify(points))
let minLatIndex = 0;
let maxLatIndex = 0;
let minLngIndex = 0;
let maxLngIndex = 0;
points.forEach((item,index)=>{
if(index !== 0){
if(points[minLatIndex].latitude > item.latitude){
minLatIndex = index;
}
if(points[maxLatIndex].latitude < item.latitude){
maxLatIndex = index;
}
if(points[minLngIndex].longitude > item.longitude){
minLngIndex = index;
}
if(points[maxLngIndex].longitude < item.longitude){
maxLngIndex = index;
}
}
})
points[minLatIndex].latitude = numSub(points[minLatIndex].latitude,0.0050);
points[maxLatIndex].latitude = numAdd(points[maxLatIndex].latitude,0.0050);
points[minLngIndex].longitude = numSub(points[minLngIndex].longitude,0.0050);
points[maxLngIndex].longitude = numAdd(points[maxLngIndex].longitude,0.0050);
return points;
},
pointClick(e){
console.log("当前点击点",e)
this.activeIndex = e.detail.markerId;
this.deviceInfo = this.deviceList[e.detail.markerId];
this.activeId = this.deviceList[e.detail.markerId].id;
this.mapLocation.longitude = this.deviceList[e.detail.markerId].lng;
this.mapLocation.latitude = this.deviceList[e.detail.markerId].lat;
this.isModel = true;
},
mapClick(e){
console.log("当前点击地图",e)
this.isModel = false;
},
goDeviceDetail(){
uni.navigateTo({
url:'/pages/iots/device/device-detail?id=' + this.deviceInfo.id + '&devName=' + this.deviceInfo.devName
})
}
}
}
</script>
<style lang="scss" scoped>
// .map-box,#maps{
// width: 100%;
// height: 100%;
// }
.search-box {
position: fixed;
top: 20rpx;
left: 20rpx;
right: 20rpx;
z-index: 999;
}
.search-content {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
background: #fff;
border-radius: 10rpx;
}
.search-content-input{
flex: 1;
padding-left: 20rpx;
height: 80rpx;
line-height: 80rpx;
}
.search-content-btn{
height: 80rpx;
line-height: 80rpx;
margin: 0;
background: #0960ff;
border: 1px solid #0960ff;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.search-content-btn-txt{
color: #fff;
}
.search-list {
margin-top: 10rpx;
// max-height: 450rpx;
height: 450rpx;
background: #fff;
border-radius: 10rpx;
overflow: hidden;
}
.search-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 10rpx 20rpx;
border-bottom: 1px solid #f0f0f0;
}
.search-item:last-child {
border-bottom: 1px solid transparent;
}
.active {
background: #e2edff;
}
.item-img {
width: 80rpx;
height: 80rpx;
margin-right: 20rpx;
}
.item-title {
font-weight: bold;
}
.item-info {
margin-top: 5rpx;
font-size: 24rpx;
color: #666;
}
.empty-box {
padding: 50rpx 30rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.empty-box-img {
width: 80rpx;
height: 80rpx;
}
.empty-box-txt {
margin-top: 10rpx;
color: #666;
}
.info-box {
position: fixed;
bottom: 20rpx;
left: 20rpx;
right: 20rpx;
z-index: 999;
background: #fff;
border-radius: 10rpx;
padding: 20rpx;
padding-top: 0;
box-shadow: 0px 0px 10px 0px rgba(192, 192, 192, 0.5);
// max-height: 750rpx;
height: 750rpx;
overflow: hidden;
}
.info-box-header {
position: relative;
height: 60rpx;
}
// .icon-plus {
// position: absolute;
// top: -10rpx;
// right: -10rpx;
// font-size: 40rpx;
// transform: rotate(45deg);
// font-weight: bold;
// }
.icon-close{
position: absolute;
top: 0rpx;
right: 0rpx;
font-size: 50rpx;
line-height: 60rpx;
// transform: rotate(45deg);
font-weight: bold;
}
.info-box-content {
display: flex;
flex-direction: row;
align-items: center;
}
.info-img {
width: 170rpx;
height: 170rpx;
margin-right: 20rpx;
}
.info-list {
flex: 1;
}
.info-item {
display: flex;
align-items: center;
flex-direction: row;
justify-content: space-between;
}
.item-label{
font-size: 28rpx;
}
.item-value {
font-size: 28rpx;
font-weight: bold;
}
.info-box-btn {
margin-top: 10rpx;
background: #0960ff;
border-radius: 8rpx;
height: 80rpx;
line-height: 80rpx;
}
.info-box-btn-txt{
color: #fff;
font-size: 36rpx;
}
</style>

View File

@ -0,0 +1,465 @@
<template>
<view class="map-box">
<map
id="maps"
:longitude="mapLocation.longitude"
:latitude="mapLocation.latitude"
show-location="true"
:markers="mapMarkers"
:polyline="mapPolyline"
:polygons="mapPolygons"
:scale="scale"
:enable-scroll="true"
@markertap="pointClick"
@tap="mapClick"
@regionchange="getRegion"
>
</map>
<view class="search-box">
<view class="search-content">
<input type="text" placeholder="搜索设备名称/ID" v-model="searchVal" @input="getDeviceList(true)">
<button @click="getDeviceList(true)">搜索</button>
</view>
<view class="search-list" v-if="isShowSearchList">
<view class="search-item" :class="activeId==item.id?'active':''" v-for="(item,index) in deviceList" :key="item.id" @click="selectDevice(item,index)">
<view class="item-img">
<image :src="item.devImage ? imgPath + item.devImage : deviceDefaultPath"></image>
</view>
<view class="item-content">
<view class="item-title">
{{item.devName}}
</view>
<view class="item-info">
{{item.devId}}
</view>
</view>
</view>
<view class="empty-box" v-if="deviceList.length == 0 && showEmpy">
<image :src="deviceDefaultPath"></image>
<text>暂无设备</text>
</view>
</view>
</view>
<view class="info-box" v-if="isModel">
<view class="info-box-header">
<view class="iconfont icon-plus" @click="isModel=false"></view>
</view>
<view class="info-box-content">
<view class="info-img">
<image :src="deviceInfo.devImage ? imgPath + deviceInfo.devImage : deviceDefaultPath" mode=""></image>
</view>
<view class="info-list">
<view class="info-item">
<view class="item-label">
设备名
</view>
<view class="item-value">
{{deviceInfo.devName}}
</view>
</view>
<view class="info-item">
<view class="item-label">
在线状态
</view>
<view class="item-value" :style="{color:deviceInfo.devState==1?'#10CC70':deviceInfo.devState==2?'#FF2B38':'#999999'}">
{{deviceInfo.devState==1?'在线':deviceInfo.devState==2?'离线':'未激活'}}
</view>
</view>
<view class="info-item">
<view class="item-label">
设备ID
</view>
<view class="item-value">
{{deviceInfo.devId}}
</view>
</view>
<view class="info-item">
<view class="item-label">
上线时间
</view>
<view class="item-value">
{{deviceInfo.lastOnlineTime}}
</view>
</view>
<view class="info-item">
<view class="item-label">
PK
</view>
<view class="item-value">
{{deviceInfo.pk}}
</view>
</view>
</view>
</view>
<button @click="goDeviceDetail">查看设备详情</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
mapCtx:null,
mapLocation:{
longitude:119.216327,
latitude:26.028788
},
scale:12,
// includePoints:[],
mapMarkers:[],
mapPolyline:[],
mapPolygons:[],
isModel:false,
deviceInfoList:[
{
label:'设备id',
value:'00000000000001'
},
{
label:'设备名称',
value:'换电柜001'
},
{
label:'设备状态',
value:'在线'
},
{
label:'仓门数量',
value:'5'
},
{
label:'电池数量',
value:'4'
}
],
pointData:[],
isShowSearchList:false,
showEmpy:false,
searchVal:'',
imgPath:'',
activeIndex:-1,
activeId:0,
deviceList:[],
deviceInfo:{
devImage:null,
devName:null,
devState:0,
devId:null,
lastOnlineTime:null,
pk:null,
},
mapRange:{
latMax:0,
latMin:0,
lngMax:0,
lngMin:0,
},
deviceDefaultPath:'https://file.iot-fast.com/wxapp/static/image/device/device-default.png'
};
},
onLoad(option) {
// this.deviceDefaultPath = 'https://file.iot-fast.com/wxapp/static/image/device/device-default.png';
this.getConfigPath();
if (!this.mapCtx) {
this.mapCtx = uni.createMapContext("maps"); // map map
}
// this.getDeviceList(false);
this.getRegion();
// this.getDeviceList(true);
},
methods:{
selectDevice(data,index){
this.activeIndex = index;
this.activeId = data.id;
this.deviceInfo = data;
this.mapLocation.longitude = data.lng;
this.mapLocation.latitude = data.lat;
this.isShowSearchList = false;
this.isModel = true;
},
getConfigPath(){
let configList = uni.getStorageSync('configList');
let configIndex = uni.getStorageSync('configIndex');
this.imgPath = configList[configIndex].protocol + configList[configIndex].address;
},
getDeviceList(flag){
let params = {
"page": 1,
"pageSize": 99999,
"Wheres": {
"wheres": [
{"field": "locateState","operator": "=","value": 1},
{"field": "lng","operator": ">=","value": this.mapRange.lngMin},
{"field": "lng","operator": "<=","value": this.mapRange.lngMax},
{"field": "lat","operator": ">=","value": this.mapRange.latMin},
{"field": "lat","operator": "<=","value": this.mapRange.latMax},
// {"field": "prodType","operator": "=","value": this.deviceType},
// {"field":"devState","operator":"=","value":this.tabsList[this.tabIndex].value},
{"fields": ["devId","devName"],"operator": "keyword","value": this.searchVal}
]
},
}
this.$api.iotsApi.getDeviceList(params).then(res => {
if(res.code === 0){
this.deviceList = res.data.list ? res.data.list : [];
if(res.data.list){
this.getPointData()
}
if(flag){
this.isShowSearchList = true;
this.showEmpy = res.data.list ? false : true;
}
}else{
this.deviceList = [];
if(flag){
this.isShowSearchList = true;
this.showEmpy = true;
}
}
}, error => {
})
},
getRegion() {
this.mapCtx.getRegion({
success: res => {
let obj = {
"latMax": res.northeast.latitude.toString(),
"latMin": res.southwest.latitude.toString(),
"lngMax": res.northeast.longitude.toString(),
"lngMin": res.southwest.longitude.toString(),
}
this.mapRange = obj;
this.getDeviceList(false);
},
fail: (data, code) => {
console.log('fail' + JSON.stringify(data));
}
})
},
getPointData(){
let includePoints = [];
let points = this.deviceList.map((item,index)=>{
includePoints.push({
longitude:item.lng,
latitude:item.lat,
})
// this.pointData.push({
// index:index,
// id:item.id,
// infoData:item.infoData,
// longitude:item.lng,
// latitude:item.lat,
// })
let x = - item.devName.length*6;
return {
// id:item.id,
id:index,
longitude:item.lng,
latitude:item.lat,
title:item.devName,
label:{
content:item.devName,
textAlign:'center',
color:'#2e66e7',
anchorX:x,
textAlign:'left'
},
// iconPath: '/static/image/device/location-blue.png',
iconPath: item.devImage ? this.imgPath + item.devImage : this.deviceDefaultPath,
width:24,
height:24,
}
});
this.$nextTick(()=>{
this.$set(this,'mapMarkers',points);
this.$forceUpdate()//
})
// this.mapCtx.includePoints({
// padding: [20,20,20,20],
// points: includePoints
// })
},
pointClick(e){
console.log("当前点击点",e)
this.$nextTick(()=>{
this.activeIndex = e.markerId;
this.deviceInfo = this.deviceList[e.markerId];
this.activeId = this.deviceList[e.markerId].id;
this.mapLocation.longitude = this.deviceList[e.markerId].lng;
this.mapLocation.latitude = this.deviceList[e.markerId].lat;
this.isModel = true;
})
},
mapClick(e){
console.log("当前点击地图",e)
this.isModel = false;
},
goDeviceDetail(){
uni.navigateTo({
url:'/pages/iots/device/device-detail?id=' + this.deviceInfo.id + '&devName=' + this.deviceInfo.devName
})
}
}
}
</script>
<style lang="scss" scoped>
.map-box,#maps{
width: 100%;
height: 100%;
}
.search-box{
position: fixed;
top: 20rpx;
left: 20rpx;
right: 20rpx;
z-index: 999;
// background: #fff;
// border-radius: 10rpx;
// padding: 20rpx;
/* box-shadow: 0px 0px 10px 0px rgba(192,192,192,0.5); */
// max-height: 750rpx;
// overflow-y: auto;
.search-content{
display: flex;
align-items: center;
justify-content: space-between;
background: #fff;
border-radius: 10rpx;
input{
flex: 1;
// text-indent: 20rpx;
padding-left: 20rpx;
height: 80rpx;
line-height: 80rpx;
}
>button{
height: 80rpx;
line-height: 80rpx;
margin: 0;
background: #0960ff;
color: #fff;
border: 1px solid #0960ff;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
.search-list{
margin-top: 10rpx;
max-height: 450rpx;
background: #fff;
border-radius: 10rpx;
overflow-y: auto;
.search-item{
display: flex;
align-items: center;
padding: 10rpx 20rpx;
border-bottom: 1px solid #f0f0f0;
&:last-child{
border-bottom: none;
}
&.active{
background: #e2edff;
}
.item-img{
width: 80rpx;
height:80rpx;
margin-right: 20rpx;
image{
width: 100%;
height:100%;
}
}
.item-content{
.item-title{
font-weight: bold;
}
.item-info{
margin-top: 5rpx;
font-size: 24rpx;
color: #666;
}
}
}
.empty-box{
padding: 50rpx 30rpx;
display: flex;
flex-direction: column;
align-items: center;
image{
width: 80rpx;
height: 80rpx;
}
text{
margin-top: 10rpx;
color: #666;
}
}
}
}
.info-box{
position: fixed;
bottom: 20rpx;
left: 20rpx;
right: 20rpx;
z-index: 999;
background: #fff;
border-radius: 10rpx;
padding: 20rpx;
box-shadow: 0px 0px 10px 0px rgba(192,192,192,0.5);
max-height: 750rpx;
overflow-y: auto;
.info-box-header{
position: relative;
height: 30rpx;
.iconfont{
position: absolute;
top: -10rpx;
right: -10rpx;
font-size: 40rpx;
transform: rotate(45deg);
font-weight: bold;
}
}
.info-box-content{
display: flex;
align-items: center;
.info-img{
width: 170rpx;
height: 170rpx;
margin-right: 20rpx;
image{
width:100%;
height:100%;
}
}
.info-list{
flex: 1;
.info-item{
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.item-value{
font-weight: bold;
}
}
}
}
button{
margin-top: 10rpx;
background: #0960ff;
color: #fff;
font-size: 36rpx;
border-radius: 8rpx;
height: 80rpx;
line-height: 80rpx;
}
}
</style>

697
pages/iots/notice/index.vue Normal file
View File

@ -0,0 +1,697 @@
<template>
<view class="notice-box">
<view class="notice-box-main">
<view class="notice-item">
<view class="item-header">
<view class="item-header-title">
未处理
</view>
<view class="item-header-txt">{{alarmCount.alarmUnCount}}</view>
</view>
<view class="item-bottom">
<view class="bottom-item">
<view class="bottom-item-left">
<view class="item-bg bg-green"></view>
<view class="bottom-item-name">当日</view>
</view>
<view class="bottom-item-right">
{{alarmCount.alarmToday}}
</view>
</view>
<view class="bottom-item">
<view class="bottom-item-left">
<view class="item-bg bg-red"></view>
<view class="bottom-item-name">当月</view>
</view>
<view class="bottom-item-right">
{{alarmCount.alarmMonth}}
</view>
</view>
</view>
</view>
<view class="notice-item">
<view class="item-header">
<view class="item-header-title">
告警配置
</view>
<view class="item-header-txt">{{alarmCount.ruleCount}}</view>
</view>
<view class="item-bottom">
<view class="bottom-item">
<view class="bottom-item-left">
<view class="item-bg bg-green"></view>
<view class="bottom-item-name">正常</view>
</view>
<view class="bottom-item-right">
{{alarmCount.ruleEnabled}}
</view>
</view>
<view class="bottom-item">
<view class="bottom-item-left">
<view class="item-bg bg-red"></view>
<view class="bottom-item-name">禁用</view>
</view>
<view class="bottom-item-right">
{{alarmCount.ruleDisable}}
</view>
</view>
</view>
</view>
</view>
<view class="main-item">
<view class="main-header device-header" @click="goAlarmList">
<view class="main-title device-title">
<view class="title-box device-title-box">
<view class="iconfont icon-baojingguanli"></view>
</view>
<text>最新告警</text>
</view>
<view class="main-header-right">
<view class="header-other">
更多
</view>
<view class="iconfont icon-xiangyou1"></view>
</view>
</view>
<view class="main-content">
<view class="content-item" v-if="nowAlarmList.length>0" v-for="item in nowAlarmList" :key="item.id">
<view class="content-item-header">
{{item.alarmName}}<u-tag :text="item.applyState === 2?'已忽略':item.applyState === 1?'已处理':'未处理'" :type="item.applyState === 2?'info':item.applyState === 1?'success':'error'" mode="light" size="mini" style="margin-left: 10rpx;" />
</view>
<view class="content-body-item">
<view class="content-body-label">
告警内容
</view>
<view class="content-body-value">
{{item.alarmContent}}
</view>
</view>
<view class="content-body-item">
<view class="content-body-label">
告警等级
</view>
<view class="content-body-value">
{{item.alarmLevel}}
</view>
</view>
<view class="content-body-item">
<view class="content-body-label">
告警设备
</view>
<view class="content-body-value">
{{item.devName}}
</view>
</view>
<view class="content-body-item">
<view class="content-body-label">
告警时间
</view>
<view class="content-body-value">
{{item.createdAt}}
</view>
</view>
</view>
<u-empty v-else margin-top="50" text="告警为空" mode="list"></u-empty>
</view>
</view>
<view class="chart-box">
<view class="chart-header">
<view class="main-title device-title">
<view class="title-box device-title-box">
<view class="iconfont icon-line-chart"></view>
</view>
<text>告警统计</text>
</view>
<view class="chart-right">
<uni-data-select
v-model="statisticsParams.alarmLevel"
:localdata="alarmLevelList"
placeholder="选择告警等级"
@change="changeLevel"
></uni-data-select>
<uni-data-select
style="margin-left: 10rpx;"
v-model="statisticsParams.dateType"
:localdata="dateTypeList"
:clear="false"
placeholder="选择类型"
@change="changeType"
></uni-data-select>
<view class="select-item" @click="openTimeModel">
<text v-if="statisticsParams.dateType==='date'" class="select-item-left">{{timeNum.year + '-' + timeNum.month + '-' + timeNum.day}}</text>
<text v-if="statisticsParams.dateType==='month'" class="select-item-left">{{timeNum.year + '-' + timeNum.month}}</text>
<text v-if="statisticsParams.dateType==='year'" class="select-item-left">{{timeNum.year}}</text>
<text class="iconfont icon-calendar11"></text>
</view>
</view>
</view>
<view class="chart-main">
<qiun-data-charts
type="line"
:opts="opts"
:chartData="chartData"
:canvas2d="true"
:reshow="charShow"
/>
</view>
</view>
<u-picker mode="time" v-model="timeShow" :params="timeParams" @confirm="changeTime"></u-picker>
<u-tabbar class="tabbar-box" v-model="tabbarIndex" active-color="#1890ff" :list="tabbarList" @change="tabbarChange"></u-tabbar>
</view>
</template>
<script>
import IotsTabbarMixin from "../iotsTabbarMixins.js"
import {numberfilter} from "@/static/common/js/util/number-to-chinese.js"
export default {
mixins: [IotsTabbarMixin],
filters: {
numberfilter
},
data() {
return {
tabbarIndex:3,
opts: {
color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [15,15,15,5],
enableScroll: false,
legend: {show:false},
xAxis: {
disableGrid: true,
// format: "xAxisDemo2"
scrollShow: true,
// itemCount: 6,
fontSize:10,
// rotateAngle:60,
// rotateLabel:true,
labelCount: 6, //
// itemCount:24 //x
},
yAxis: {
gridType: "dash",
dashLength: 2,
splitNumber:5,
data:[{tofix:2,min:0}]
},
extra: {
line: {
type: "straight",
width: 2,
activeType: "hollow"
}
},
update:true
},
//
alarmCount:{
alarmUnCount: 0,
alarmToday: 0,
alarmMonth: 0,
ruleCount: 0,
ruleEnabled: 0,
ruleDisable: 0
},
//
nowAlarmList:[],
//
levelShow:false,
alarmLevelList:[],
statisticsParams:{
alarmLevel:null,
dateType:null,
dateValue:null,
},
dateTypeList:[
{
text:'天',
value:'date'
},
{
text:'月',
value:'month'
},
{
text:'年',
value:'year'
}
],
timeParams: {
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false
},
timeShow: false,
timeNum:{
year: null,
month: null,
day: null,
},
chartData: {},
charShow: true,
}
},
onLoad() {
this.statisticsParams.dateType = 'date';
let newTime = new Date().getTime();
let today = new Date();
this.timeNum.year = today.getFullYear();
this.timeNum.month = today.getMonth() + 1; // 0 1
this.timeNum.day = today.getDate();
if(this.$u.os()=='ios'){
this.statisticsParams.dateValue = this.$u.timeFormat(new Date(), 'yyyy/mm/dd');
}else{
this.statisticsParams.dateValue = this.$u.timeFormat(new Date(), 'yyyy-mm-dd');
}
},
onShow() {
this.getAlarmReacordCount();
this.getAlarmReacordList();
this.getAlarmLevelList();
this.getAlarmRecordStat();
},
methods: {
getAlarmReacordCount(){
this.$api.iotsApi.getAlarmReacordCount({}).then(res => {
console.log("获取告警数量为", res)
if (res.code == 0) {
this.alarmCount = res.data;
}else{
this.alarmCount = {
alarmUnCount: 0,
alarmToday: 0,
alarmMonth: 0,
ruleCount: 0,
ruleEnabled: 0,
ruleDisable: 0
}
}
}, error => {})
},
//
getAlarmReacordList(){
let params = {
page: 1,
pageSize: 2,
"Sorters": {
"sorters": [
{"columnKey":"id","order":"descend"}
]
},
}
this.$api.iotsApi.getAlarmReacordList(params).then(res => {
console.log("获取最新告警为", res)
if (res.code == 0) {
this.nowAlarmList = res.data.list ? res.data.list : [];
}else{
this.nowAlarmList = [];
}
}, error => {})
},
//
getAlarmLevelList(){
this.$api.iotsApi.getAlarmLevelList({page:1,pageSize:999}).then(res => {
console.log("获取告警等级为", res)
if (res.code == 0 && res.data.list) {
this.alarmLevelList = res.data.list.map(item=>{
return {
text:item.name,
value:item.level,
}
});
console.log("alarmLevelList",this.alarmLevelList)
}else{
this.alarmLevelList = [];
}
}, error => {})
},
changeLevel(e){
console.log("e",e)
// this.statisticsParams.alarmLevel = e;
this.getAlarmRecordStat()
},
changeType(e){
// this.statisticsParams.dateType = e;
if(e === 'date'){
this.timeParams={
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false
}
}else if(e === 'month'){
this.timeParams={
year: true,
month: true,
day: false,
hour: false,
minute: false,
second: false
}
}else if(e === 'year'){
this.timeParams={
year: true,
month: false,
day: false,
hour: false,
minute: false,
second: false
}
}
this.getAlarmRecordStat()
},
openTimeModel(){
this.timeShow = true;
},
changeTime(e){
console.log("选择时间",e)
this.timeNum.year = e.year;
if(e.month){
this.timeNum.month = e.month;
}
if(e.day){
this.timeNum.day = e.day;
}
this.getAlarmRecordStat()
},
// ()
getAlarmRecordStat(){
let params = {
alarmLevel: this.statisticsParams.alarmLevel,
dateType: this.statisticsParams.dateType,
dateValue: this.timeNum.year + '-' + this.timeNum.month + '-' + this.timeNum.day,
}
this.$api.iotsApi.getAlarmRecordStat(params).then(res => {
console.log("获取概览页统计", res)
if (res.code == 0) {
this.chartData = {
categories:res.data.xdata,
series:[{
name:'告警数量',
data:res.data.ydata
}]
}
}else{
// this.alarmLevelList = [];
}
}, error => {})
},
goAlarmList(){
uni.navigateTo({
url:'/pages/iots/notice/list'
})
}
}
}
</script>
<style>
page,.notice-box{
background: #f5f5f5;
}
</style>
<style scoped lang="scss">
.notice-box{
// background: #ebeef5;
// height: 100%;
// display: flex;
// flex-direction: column;
padding: 20rpx;
padding-bottom: 50px;
}
.notice-box-main{
display: flex;
align-items: center;
.notice-item{
flex: 1;
border: 1px solid #f0f0f0;
background: #FFFFFF;
border-radius: 20rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0px 0px 15rpx 0px rgba(201, 201, 201, 0.4);
&:first-child{
margin-right: 20rpx;
}
.item-header{
border-bottom: 1px solid #e8e8f2;
.item-header-txt{
line-height: 80rpx;
font-size: 40rpx;
font-weight: bold;
}
}
.item-bottom{
margin-top: 20rpx;
// line-height: 40rpx;
display: flex;
align-items: center;
.bottom-item{
flex: 1;
display: flex;
// justify-content: center;
align-items: center;
.bottom-item-left{
display: flex;
align-items: center;
margin-right: 20rpx;
.item-bg{
width: 20rpx;
height: 20rpx;
border-radius: 50%;
margin-right: 10rpx;
}
}
}
}
}
}
.bg-green{
background-color: #52c41a;
}
.bg-red{
background-color: red;
}
.main-item{
background-color: #fff;
border-radius: 20rpx;
// height: 200rpx;
box-shadow: 0px 0px 15rpx 0px rgba(201, 201, 201, 0.4);
margin-bottom: 20rpx;
.main-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 70rpx;
padding: 0 20rpx;
border-bottom: 1px solid #e8e8f2;
.main-title {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 500;
.title-box{
width: 40rpx;
height: 40rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
border-radius: 50%;
background: linear-gradient(180deg, #FFE99E, #FA9930);
box-shadow: 0px 6rpx 10rpx 0px rgba(255,206,142,0.81);
.iconfont{
font-size: 26rpx;
line-height: 26rpx;
color: #fff;
}
}
>text{
font-weight: 600;
}
}
.main-header-right{
display: flex;
align-items: center;
color: #939393;
.header-other{
font-size: 26rpx;
}
}
}
.main-content{
padding:20rpx;
.content-item{
&:not(:first-child){
border-top: 1px solid #e8e8f2;
padding-top: 20rpx;
margin-top: 20rpx;
}
.content-item-header{
font-weight: 600;
font-size: 30rpx;
display: flex;
align-items: center;
}
.content-body-item{
display: flex;
margin-top: 5rpx;
.content-body-label{
color: #888888;
}
}
}
}
}
.chart-box{
background-color: #fff;
border-radius: 20rpx;
box-shadow: 0px 0px 15rpx 0px rgba(201, 201, 201, 0.4);
.chart-header{
height: 80rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20rpx;
border-bottom: 1px solid #e8e8f2;
.main-title {
display: flex;
align-items: center;
font-size: 30rpx;
font-weight: 500;
.title-box{
width: 40rpx;
height: 40rpx;
display: flex;
justify-content: center;
align-items: center;
margin-right: 20rpx;
border-radius: 50%;
background: linear-gradient(180deg, #9EDAFF, #5D96FF);
box-shadow: 0px 6px 10px 0px rgba(142,181,255,0.81);
.iconfont{
font-size: 26rpx;
line-height: 26rpx;
color: #fff;
}
}
>text{
font-weight: 600;
}
}
.chart-right{
display: flex;
.select-item{
margin-left: 10rpx;
border: 1px solid #e5e5e5;
border-radius: 10rpx;
padding: 0 10rpx;
width: 190rpx;
display: flex;
align-items: center;
justify-content: space-between;
color: #666;
font-size: 24rpx;
height: 60rpx;
}
}
}
.chart-main{
height: 600rpx;
}
}
/deep/.uni-select{
padding: 0 10rpx;
height: 60rpx;
}
.notice-top{
position: fixed;
top: 0;
left: 0;
right: 0;
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
background: #FFFFFF;
border-bottom: 1px solid #f4f6f8;
z-index: 999;
.iconfont{
transform: rotate(90deg);
margin-left: 10rpx;
}
}
.notice-list{
padding: 24rpx 24rpx 0;
.notice-item{
width: 702rpx;
min-height: 381rpx;
background: #FFFFFF;
border-radius: 10rpx;
margin-bottom: 24rpx;
.item-header{
// height: 104rpx;
// padding-left: 28rpx;
// padding-top: 23rpx;
padding: 20rpx 25rpx;
box-sizing: border-box;
border-bottom: 1px solid #e8e8f2;
display: flex;
justify-content: space-between;
align-items: center;
.item-header-left{
.header-title{
font-size: 28rpx;
line-height: 28rpx;
color: #444444;
}
.header-time{
font-size: 26rpx;
line-height: 26rpx;
color: #999;
margin-top: 15rpx;
}
}
.item-header-right{
}
}
.item-body{
padding: 18rpx 26rpx;
display: flex;
justify-content: space-between;
align-items: flex-end;
.item-body-left{
.body-txt{
font-size: 26rpx;
line-height: 42rpx;
color: #0053A2;
text{
color: #444;
}
}
}
.item-body-right{
}
}
}
}
</style>

363
pages/iots/notice/list.vue Normal file
View File

@ -0,0 +1,363 @@
<template>
<view class="notice-box">
<u-dropdown class="notice-top">
<u-dropdown-item v-model="paramsObj.status" title="状态" :options="statusOptions" @change="searchList"></u-dropdown-item>
<u-dropdown-item v-model="paramsObj.applyStatus" title="审核状态" :options="applyStatusOptions" @change="searchList"></u-dropdown-item>
</u-dropdown>
<mescroll-body ref="mescrollRef" top="80" @init="mescrollInit" @down="downCallback" @up="upCallback" :up="upOption" >
<view class="notice-list">
<view class="notice-item" v-for="(item,index) in dataList" :key="index">
<view class="item-header">
<view class="item-header-left">
<view class="header-title">
{{item.alarmName}}
</view>
<!-- <view class="header-time">
{{$u.timeFormat(item.alarmTime, 'mm月dd日')}}
</view> -->
</view>
<view class="item-header-right" :style="{color:item.applyState===1?'#10CC70':item.applyState===0?'#FF2B38':'#999999'}">
{{item.applyState===1?'已处理':item.applyState===0?'未处理':'已忽略'}}
</view>
</view>
<view class="item-body">
<view class="item-body-left">
<view class="body-txt"><text>时间</text>{{item.createdAt}}</view>
<view class="body-txt"><text>设备</text>{{item.devName}}</view>
<view class="body-txt"><text>状态</text>{{item.status}}</view>
<view class="body-txt"><text>等级</text>{{item.alarmLevel | numberfilter}}</view>
<view class="body-txt"><text>内容</text>{{item.alarmContent}}</view>
</view>
<view class="item-body-right" v-if="item.applyState!==1">
<u-button type="primary" @click="openApply(item)">处理</u-button>
</view>
</view>
</view>
</view>
</mescroll-body>
<u-calendar v-model="timeshow" :mode="mode" :min-date="minDate" :max-date="maxDate" @change="selectTime"></u-calendar>
<u-modal v-model="applyShow" title="告警审核" :mask-close-able="true" @confirm="applyItem" ref="applyModal" :async-close="true">
<view class="slot-content">
<view class="content-item">
<view class="content-label">审核类型:</view>
<view class="content-value">
<uni-data-select
v-model="applyObj.applyState"
:localdata="applyTypeList"
placeholder="选择审核类型"
></uni-data-select>
</view>
</view>
<view class="content-item">
<view class="content-label">审核类型:</view>
<view class="content-value">
<u-input v-model="applyObj.applyRemark" type="textarea" border height="200" :auto-height="true" />
</view>
</view>
</view>
</u-modal>
<u-toast ref="uToast" />
</view>
</template>
<script>
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js"
import {numberfilter} from "@/static/common/js/util/number-to-chinese.js"
export default {
mixins: [MescrollMixin],
filters: {
numberfilter
},
data() {
return {
upOption:{
noMoreSize: 4,
textNoMore: '---- 已经到底啦 ----',
empty:{
tip: '~ 暂无告警数据 ~' //
}
},
tabbarIndex:3,
dataList:[],
timeshow: false,
mode: 'range',
minDate:'1950-01-01',
maxDate:'2023-12-28',
timeObj:{
beginTime:'',
endTime:''
},
loadStatus:'loadmore',//more-loading-nomore-
isLoadMore:false, //
emptyShow:false, //
pageNum:1,
pageSize:10,
orderByColumn:'alarmTime',
isAsc:'desc',
noticeTimeObj:{
beginTime:'',
endTime:''
},
paramsObj:{
status:null,
applyStatus:null,
devId:null,
},
statusOptions: [{
label: '全部',
value: null,
},{
label: '启用',
value: 1,
},
{
label: '禁用',
value: 2,
}
],
applyStatusOptions: [{
label: '全部',
value: null,
},{
label: '未处理',
value: 0,
},
{
label: '已处理',
value: 1,
},
{
label: '已忽略',
value: 2,
}
],
//
applyShow:false,
applyId:null,
applyObj:{
applyState:null,
applyRemark:null,
},
applyTypeList: [{
text: '未处理',
value: 0,
},
{
text: '已处理',
value: 1,
},
{
text: '已忽略',
value: 2,
}
]
}
},
components: {
},
onLoad(option) {
//
if(option.devId){
this.paramsObj.devId = option.devId;
uni.setNavigationBarTitle({
title: option.devName+'告警列表'
});
}
},
onShow() {
},
methods: {
openSelect(){
this.maxDate=this.$u.timeFormat(new Date(), 'yyyy-mm-dd');
this.timeshow = true;
},
selectTime(e){
console.log("当前选择日期",e)
this.noticeTimeObj.beginTime = e.startDate;
this.noticeTimeObj.endTime = e.endDate;
//
this.mescroll.resetUpScroll();
},
searchList(){
this.mescroll.resetUpScroll();
},
upCallback(page) {
let params = {
page: page.num,
pageSize: page.size,
status: this.paramsObj.status,
"Wheres": {
"wheres": [
{"field": "applyState","operator": "=","value": this.paramsObj.applyStatus},
]
},
// devId: this.paramsObj.devId
}
if(this.paramsObj.devId){
params.devId = this.paramsObj.devId;
}
this.$api.iotsApi.getAlarmReacordList(params).then(res => {
console.log("获取设备列表",res)
if(res.code === 0){
let curPageData = res.data && res.data.list;
let curPageLen = curPageData && curPageData.length || 0;
let totalSize = res.totalCount;
this.$nextTick(()=>{
// ;
this.mescroll.endBySize(curPageLen, totalSize);
})
//
if(page.num == 1) this.dataList = []; //
this.dataList = curPageLen > 0 && this.dataList.concat(curPageData); //
}else{
this.$u.toast(res.msg);
this.mescroll.endErr();
}
}, error => {
})
},
//
openApply(data){
// console.log("",data)
this.applyId = data.id;
this.applyObj.applyState = data.applyState;
this.applyObj.applyRemark = "";
this.applyShow = true;
},
applyItem(){
console.log("审核告警",this.applyObj)
if(this.applyObj.applyState!==""){
let params = {
ids:[this.applyId],
...this.applyObj
}
console.log("params", params)
this.$api.iotsApi.applyAlarmRecord(params).then(res => {
console.log("审核告警",res)
if(res.code === 0){
this.applyShow = false;
this.$refs.uToast.show({
title: res.message,
type: 'success',
})
this.mescroll.resetUpScroll();
}else{
this.$refs.uToast.show({
title: res.message,
type: 'error',
})
}
}, error => {
})
}else{
this.$refs.uToast.show({
title: '请选择审核状态',
type: 'error',
})
this.$refs.applyModal.clearLoading();
}
}
}
}
</script>
<style>
page,.notice-box{
background: #f5f5f5;
}
</style>
<style scoped lang="scss">
.notice-box{
// background: #ebeef5;
// height: 100%;
// display: flex;
// flex-direction: column;
}
.notice-top{
position: fixed;
top: 0;
left: 0;
right: 0;
height: 80rpx;
z-index: 999;
background-color: #FFFFFF;
}
.notice-list{
padding: 24rpx 24rpx 0;
.notice-item{
width: 702rpx;
// min-height: 381rpx;
background: #FFFFFF;
border-radius: 10rpx;
margin-bottom: 24rpx;
.item-header{
// height: 104rpx;
// padding-left: 28rpx;
// padding-top: 23rpx;
padding: 20rpx 25rpx;
box-sizing: border-box;
border-bottom: 1px solid #e8e8f2;
display: flex;
justify-content: space-between;
align-items: center;
.item-header-left{
.header-title{
font-size: 28rpx;
line-height: 28rpx;
color: #444444;
font-weight: bold;
}
.header-time{
font-size: 26rpx;
line-height: 26rpx;
color: #999;
margin-top: 15rpx;
}
}
.item-header-right{
}
}
.item-body{
padding: 18rpx 26rpx;
display: flex;
justify-content: space-between;
align-items: flex-end;
.item-body-left{
.body-txt{
font-size: 26rpx;
line-height: 42rpx;
color: #0053A2;
text{
color: #444;
}
}
}
.item-body-right{
}
}
}
}
.slot-content{
padding: 20rpx;
.content-item{
&:first-child{
margin-bottom: 20rpx;
}
.content-label{
margin-bottom: 20rpx;
font-size: 30rpx;
}
}
}
::v-deep .u-model__title.u-model__title{
padding-top: 30rpx;
font-weight: 500;
}
</style>

146
pages/my/about.vue Normal file
View File

@ -0,0 +1,146 @@
<template>
<view id="about">
<nav-bar :is-back="true" title="关于我们"></nav-bar>
<view class="header-box">
<image src="https://am-img.gkiiot.com/iotos/app/img/login/logo.png" mode="logo"></image>
<view>
海创微联
</view>
<text>{{version}}</text>
</view>
<view class="list-box">
<view class="item" @click="goUrl('./company-profile')">
<view class="item-left">
<text>公司简介</text>
</view>
<u-icon name="arrow-right" color="#666" size="28" style="font-weight: bold;"></u-icon>
</view>
<view class="item">
<view class="item-left">
<text>公司邮箱</text>
</view>
<view class="item-right">
<text user-select="true" selectable="true">gkiiot@163.com</text>
</view>
</view>
<view class="item">
<view class="item-left">
<text>咨询热线</text>
</view>
<view class="item-right">
<text user-select="true" selectable="true">13055292364</text>
</view>
</view>
<view class="item">
<view class="item-left">
<text>公司地址</text>
</view>
<view class="item-right">
<text user-select="true" selectable="true">福建省福州市闽侯县上街镇乌龙江大道7#创新园二期18号楼(总办)</text>
</view>
</view>
</view>
</view>
</template>
<script>
import NavBar from '@/common/components/navbar/NavBar.vue'
export default {
data() {
return {
infoData:{},
version:'1.0.0'
}
},
components: {
NavBar
},
onLoad() {
this.infoData = uni.getStorageSync('info');
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid,(wgtinfo)=>{
// console.log(JSON.stringify(wgtinfo));
// console.log(wgtinfo.version);//
this.version = wgtinfo.version;
})
// #endif
// #ifdef MP-WEIXIN
const accountInfo = wx.getAccountInfoSync();
if(accountInfo.miniProgram.envVersion=='release'){
this.version = accountInfo.miniProgram.version;
}
console.log(accountInfo.miniProgram.version) // 'a.b.c'
// #endif
},
onShow() {
},
methods: {
goUrl(url){
console.log(url)
uni.navigateTo({
url:url
})
}
}
}
</script>
<style scoped lang="less">
#about{
height: 100%;
background: #eaeff5;
padding: 0 20rpx;
.header-box{
display: flex;
flex-direction: column;
align-items: center;
padding: 100rpx 0 50rpx 0;
image{
width: 128rpx;
height: 128rpx;
}
>view{
color: #222;
margin-top: 42rpx;
font-size: 28rpx;
line-height: 28rpx;
}
>text{
color: #666;
font-size: 22rpx;
line-height: 22rpx;
margin-top: 24rpx;
}
}
.list-box{
background: #fff;
padding: 0 20rpx;
border-radius: 20rpx;
.item{
padding: 20rpx 12rpx;
min-height: 100rpx;
border-bottom: 1px solid #E5E5E5;
display: flex;
align-items: center;
font-size: 26rpx;
line-height: 48rpx;
.item-left{
box-sizing: border-box;
// width: 294rpx;
display: flex;
align-items: center;
color: #666;
flex: 1;
}
.item-right{
flex: 2;
color: #444;
}
}
}
}
</style>

178
pages/my/alarm.vue Normal file
View File

@ -0,0 +1,178 @@
<template>
<view id="alarm">
<nav-bar :is-back="true" title="报警通知"></nav-bar>
<scroll-view class="scroll-box" scroll-y @scrolltolower="reachBottom">
<view class="alarm-list">
<view class="alarm-item" v-for="(item,index) in alarmList" :key="index">
<view class="item-header">
<view class="header-title">
设备报警通知
</view>
<view class="header-time">
{{$u.timeFormat(item.alarmTime, 'mm月dd日')}}
</view>
</view>
<view class="item-body">
<view class="body-txt">设备报警</view>
<view class="body-txt"><text>时间</text>{{$u.timeFormat(item.alarmTime, 'yyyy年mm月dd日 hh时MM分ss秒')}}</view>
<view class="body-txt"><text>设备</text>{{item.deviceName}}</view>
<view class="body-txt"><text>等级</text>{{item.alarmLevel | numberfilter}}</view>
<view class="body-txt"><text>内容</text>{{item.alarmContent}}</view>
<view class="body-txt">当前值{{item.currentValue}}</view>
</view>
</view>
<u-empty :show="emptyShow" text="没有找到数据" :font-size="40" :icon-size="300" :margin-top="100" mode="list"></u-empty>
<u-loadmore v-if="!emptyShow" :status="loadStatus" />
</view>
</scroll-view>
</view>
</template>
<script>
import {numberfilter} from "@/static/common/js/util/number-to-chinese.js"
import NavBar from '@/common/components/navbar/NavBar.vue'
export default {
filters: {
numberfilter
},
data() {
return {
alarmList:[],
loadStatus:'loadmore',//more-loading-nomore-
isLoadMore:false, //
emptyShow:false, //
pageNum:1,
pageSize:10,
orderByColumn:'alarmTime',
isAsc:'desc',
}
},
components: {
NavBar
},
onLoad() {
this.getAlarmList();
},
onShow() {
},
methods: {
//
getAlarmList(){
let opt = {
url: '/prod-api/iot/alarm/record/list',
method: "GET",
}
let params = {
pageNum: this.pageNum,
pageSize: this.pageSize,
orderByColumn: this.orderByColumn,
isAsc: this.isAsc,
}
this.$request.TokenRequest(opt,params).then(res => {
console.log("getAlarmList",res);
if(res.code==200){
if(res.rows){
this.alarmList.push(...res.rows);
//
if(!this.alarmList.length){
this.emptyShow = true;
}else{
this.emptyShow = false;
}
//
if(res.rows.length<this.pageSize){ //判断接口返回数据量小于请求数据量则表示此为最后一页
this.isLoadMore=true
this.loadStatus='nomore'
}else{
this.isLoadMore=false
this.loadStatus='loadmore'
}
}else{
this.isLoadMore=true
this.loadStatus='nomore'
}
}else{
this.$u.toast(res.msg);
this.isLoadMore=false
if(this.pageNum>1){
this.pageNum=1
}
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
this.isLoadMore=false
if(this.pageNum>1){
this.pageNum=1
}
})
},
//
reachBottom() {
console.log("这里上拉加载更多")
if(!this.isLoadMore){ //
this.loadStatus = 'loading';
this.isLoadMore=true
this.pageNum+=1
this.getAlarmList()
}
},
}
}
</script>
<style scoped lang="less">
#alarm{
background: #ebeef5;
height: 100%;
display: flex;
flex-direction: column;
}
.scroll-box{
height: calc(100% - var(--status-bar-height) - 44px);
/* #ifdef APP-PLUS */
height: calc(100% - var(--status-bar-height) - 48px);
/* #endif */
}
.alarm-list{
padding: 24rpx 24rpx 0;
.alarm-item{
width: 702rpx;
min-height: 381rpx;
background: #FFFFFF;
border-radius: 10rpx;
margin-bottom: 24rpx;
.item-header{
height: 104rpx;
padding-left: 28rpx;
padding-top: 23rpx;
box-sizing: border-box;
border-bottom: 1px solid #e8e8f2;
.header-title{
font-size: 28rpx;
line-height: 28rpx;
color: #444444;
}
.header-time{
font-size: 26rpx;
line-height: 26rpx;
color: #999;
margin-top: 15rpx;
}
}
.item-body{
padding: 18rpx 26rpx;
.body-txt{
font-size: 26rpx;
line-height: 42rpx;
color: #0053A2;
text{
color: #444;
}
}
}
}
}
</style>

View File

@ -0,0 +1,79 @@
<template>
<view id="company-profile">
<nav-bar :is-back="true" :borderBottom="false" :background="'#1d85e8'"></nav-bar>
<image class="header-img" src="https://am-img.gkiiot.com/iotos/app/img/my/about/about-logo.png" mode=""></image>
<scroll-view class="scroll-box" scroll-y >
<view class="profile-txt">
<text>
基于多年打造的工业+核心技术商业模式与产业链体系全速执行工业互联网+的发展战略全面涉及智慧工厂智慧城市智慧交通智慧环保智慧物流等领域提供世界领先的智能化产品和解决方案进一步推动工业互联网与各行业的深度融合用创新重塑传统工业与广大行业龙头企业携手开启工业互联网新时代
</text>
<text>
我们建设统一的物联网平台底座于感知设备AI智能识别边缘计算泛在网络融合应用孵化N个产品实现工业互联网可观可监可控可追溯可复制提升生产效率生产质量
</text>
<!-- <text>
基于多年打造的工业+核心技术商业模式与产业链体系全速执行工业互联网+的发展战略全面涉及智慧工厂智慧城市智慧交通智慧环保智慧物流等领域提供世界领先的智能化产品和解决方案进一步推动工业互联网与各行业的深度融合用创新重塑传统工业与广大行业龙头企业携手开启工业互联网新时代"
</text>
<text>
我们建设统一的物联网平台底座于感知设备AI智能识别边缘计算泛在网络融合应用孵化N个产品实现工业互联网可观可监可控可追溯可复制提升生产效率生产质量
</text> -->
</view>
</scroll-view>
</view>
</template>
<script>
import NavBar from '@/common/components/navbar/NavBar.vue'
export default {
data() {
return {
infoData:{},
}
},
components: {
NavBar
},
onLoad() {
this.infoData = uni.getStorageSync('info');
},
onShow() {
},
methods: {
}
}
</script>
<style scoped lang="less">
#company-profile{
height: 100%;
display: flex;
flex-direction: column;
background-color: #eaeff5;
}
.scroll-box{
height: calc(100% - var(--status-bar-height) - 442rpx);
/* #ifdef APP-PLUS */
height: calc(100% - var(--status-bar-height) - 442rpx);
/* #endif */
}
.header-img{
width: 100%;
height: 442rpx;
margin-top: -44px;
/* #ifdef APP-PLUS */
margin-top: -48px;
/* #endif */
}
.profile-txt{
font-size: 30rpx;
line-height: 54rpx;
padding: 40rpx;
color: #000;
text{
display: block;
text-indent: 2em;
}
}
</style>

View File

@ -0,0 +1,20 @@
<template>
<web-view :src="url"></web-view>
</template>
<script>
export default{
data(){
return {
url:''
}
},
onLoad() {
// this.url="https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzI2NDM2MjUzOQ==#wechat_redirect";
this.url="https://mp.weixin.qq.com/s/u1oYXuODFvu6vs8D_i8uDA";
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,81 @@
<template>
<view id="personal-data">
<nav-bar :is-back="true" title="个人资料"></nav-bar>
<view class="list-box">
<view class="item">
<view class="item-left">
<text>用户账号</text>
</view>
<text>{{infoData.userName}}</text>
</view>
<view class="item">
<view class="item-left">
<text>手机号码</text>
</view>
<text>{{infoData.phonenumber}}</text>
</view>
<view class="item">
<view class="item-left">
<text>公司名称</text>
</view>
<text>中海创科技福建集团有限公司</text>
</view>
<view class="item">
<view class="item-left">
<text>邮箱</text>
</view>
<text>{{infoData.email}}</text>
</view>
</view>
</view>
</template>
<script>
import NavBar from '@/common/components/navbar/NavBar.vue'
export default {
data() {
return {
infoData:{},
}
},
components: {
NavBar
},
onLoad() {
this.infoData = uni.getStorageSync('info');
},
onShow() {
},
methods: {
}
}
</script>
<style scoped lang="less">
#personal-data{
.list-box{
padding: 0 20rpx;
.item{
padding: 0 12rpx;
height: 100rpx;
border-bottom: 1px solid #E5E5E5;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
.item-left{
box-sizing: border-box;
// width: 294rpx;
display: flex;
align-items: center;
color: #666;
}
>text{
color: #444;
}
}
}
}
</style>

266
pages/my/replace-phone.vue Normal file
View File

@ -0,0 +1,266 @@
<template>
<view id="replace-password">
<view class="form-box phone-box">
<view class="form-item login-name">
<view class="iconfont icon-shoujihao"></view>
<view class="phone-num">
{{oldPhone}}
</view>
</view>
<view class="form-item login-phone">
<view class="iconfont icon-yanzhengma"></view>
<input v-model.trim="oldCode" type="text" placeholder="请输入旧手机验证码" />
<button type="primary" class="login-phone-btn" @click="verifygetImgCode('old')">获取验证码</button>
</view>
<view class="form-item login-name">
<view class="iconfont icon-shoujihao"></view>
<input v-model.trim="newPhone" type="text" placeholder="请输入新手机号" />
</view>
<view class="form-item login-phone">
<view class="iconfont icon-yanzhengma"></view>
<input v-model.trim="newCode" type="text" placeholder="请输入新手机验证码" />
<button type="primary" class="login-phone-btn" @click="verifygetImgCode('new')">获取验证码</button>
</view>
</view>
<view class="btn">
<button type="default" @click="submit">确认提交</button>
</view>
<u-modal v-model="codeShow" ref="codeModal" async-close title="图片验证码" :mask-close-able="true" @confirm="verifySenCode">
<view class="slot-content imgCodeModel-content" >
<view class="imgCodeModel-content-title">
<image slot="right" style="width: 500rpx;height:150rpx" @click="getImgCodeTxt" :src="imgCodePath" mode=""></image>
</view>
<view class="imgCodeModel-content-input">
<u-input border class="login-input" type="text" v-model="imgCodeTxt" c
laceholder-style="font-size:36rpx" placeholder="请输入图片验证码" />
</view>
</view>
</u-modal>
<u-toast ref="uToast" />
</view>
</template>
<script>
import NavBar from '@/common/components/navbar/NavBar.vue'
export default {
data() {
return {
infoData:{},
//
oldPhone:'',
oldCode:'',
newPhone:'',
newCode:'',
//
codeShow:false,
imgPhone:'',
imgCodePath:'',
imgCodeKey:'',
imgCodeTxt:'',
}
},
components: {
NavBar
},
onLoad() {
this.infoData = uni.getStorageSync('userInfo');
// this.oldPhone = this.infoData.mobile;
this.oldPhone = '17859911022';
},
onShow() {
},
methods: {
verifygetImgCode(type){
console.log("获取验证码1")
if(type == 'old'){
this.imgPhone = this.oldPhone;
}else{
this.imgPhone = this.newPhone;
}
if(!this.imgPhone){
this.$refs.uToast.show({
title: '请先输入手机号',
type: 'error',
})
}else if(!this.$u.test.mobile(this.imgPhone)){
this.$refs.uToast.show({
title: '请先输入正确的手机号',
type: 'error',
})
}else{
this.getImgCodeTxt();
}
},
getImgCodeTxt(){
let opt = {
url: '/user/admin/site/captcha',
method: 'GET',
header: {
},
};
this.$request.TokenRequest(opt, {}).then(res => {
if(res.code == 0){
this.imgCodeKey = res.data.cid;
this.imgCodePath = res.data.base64;
this.imgCodeTxt = '';
//
this.codeShow = true;
}else{
this.$u.toast(res.message);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
},
submit(){
if(this.verification()){
let opt = {
url: '/user/admin/member/updatePwd',
method: "POST",
}
let params={
id:this.infoData.id,
newPassword:this.newPassword,
oldPassword:this.oldPassword,
}
this.$request.TokenRequest(opt,params).then(res => {
console.log("submit",res);
if(res.code==0){
this.$u.toast(res.message);
this.$store.commit('setTokenKey', '');
uni.$u.toast('退出登录成功');
uni.removeStorageSync('token')
uni.removeStorageSync('password')
setTimeout(()=>{
uni.reLaunch({
url:"../tabbar/login"
})
return;
},200)
}else{
this.$u.toast(res.message);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
}
},
//
verification(){
if(!this.oldPhone){
this.$refs.uToast.show({
title: '没有获取到旧手机号!',
type: 'error',
})
return false;
}else if(!this.$u.test.mobile(this.oldPhone)){
this.$refs.uToast.show({
title: '旧手机号错误!',
type: 'error',
})
return false;
}else if(!this.oldCode){
this.$refs.uToast.show({
title: '请输入旧手机验证码!',
type: 'error',
})
return false;
}else if(!this.newPhone){
this.$refs.uToast.show({
title: '请输入新手机号!',
type: 'error',
})
return false;
}else if(!this.$u.test.mobile(this.newPhone)){
this.$refs.uToast.show({
title: '请输入正确的新手机号!',
type: 'error',
})
return false;
}else if(!this.newCode){
this.$refs.uToast.show({
title: '请输入新手机验证码!',
type: 'error',
})
return false;
}else if(this.oldPhone==this.newPhone){
this.$refs.uToast.show({
title: '换绑手机号和旧手机号相同!',
type: 'error',
})
return false;
}else{
console.log('true',true)
return true;
}
}
}
}
</script>
<style scoped lang="scss">
#replace-password{
.form-box{
padding: 0 30rpx;
.form-item {
height: 126rpx;
border-bottom: 1px solid #ddd;
display: flex;
align-items: center;
padding: 0 21rpx;
.iconfont {
&:first-of-type {
font-size: 50rpx;
color: #45a5ff;
font-weight: 550;
}
}
input {
width: 500rpx;
padding-left: 20rpx;
}
&.login-phone{
input {
width: 350rpx;
padding-left: 20rpx;
}
.login-phone-btn{
font-size: 30rpx;
background: #2F7EFD;
margin-right: 0;
}
}
.phone-num{
padding-left: 20rpx;
}
}
}
}
.btn{
display: flex;
justify-content: center;
height: 142rpx;
position: fixed;
left: 0;
right: 0;
bottom: 0;
button{
width: 690rpx;
height: 90rpx;
background: #3683FD;
border-radius: 43rpx;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
}
}
.imgCodeModel-content{
padding: 10rpx 50rpx;
}
</style>

173
pages/my/reset-password.vue Normal file
View File

@ -0,0 +1,173 @@
<template>
<view id="reset-password">
<view class="list-box">
<view class="item">
<view class="item-left">
<image src="https://am-img.gkiiot.com/iotos/app/img/my/reset-password/account.png" mode="账号"></image>
<text>账号</text>
</view>
<input type="text" disabled v-model="infoData.username" />
</view>
<view class="item">
<view class="item-left">
<image src="https://am-img.gkiiot.com/iotos/app/img/my/reset-password/old-password.png" mode="旧密码"></image>
<text>旧密码</text>
</view>
<input type="password" v-model="oldPassword" placeholder="请输入旧的密码" />
</view>
<view class="item">
<view class="item-left">
<image src="https://am-img.gkiiot.com/iotos/app/img/my/reset-password/password.png" mode="新密码"></image>
<text>新密码</text>
</view>
<input type="password" v-model="newPassword" placeholder="请输入新的密码" />
</view>
<view class="item">
<view class="item-left">
<image src="https://am-img.gkiiot.com/iotos/app/img/my/reset-password/password.png" mode="确认密码"></image>
<text>确认密码</text>
</view>
<input type="password" v-model="confirmPassword" placeholder="请再次输入新密码"/>
</view>
</view>
<view class="btn">
<button type="default" @click="submit">确认提交</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
infoData:{},
oldPassword:'',
newPassword:'',
confirmPassword:'',
}
},
onLoad() {
this.infoData = uni.getStorageSync('userInfo');
},
onShow() {
},
methods: {
submit(){
if(this.verification()){
let params={
id:this.infoData.id,
newPassword:this.newPassword,
oldPassword:this.oldPassword,
}
this.$api.updatePwd(params).then(res => {
console.log("submit",res);
if(res.code==0){
this.$u.toast(res.message);
this.$store.commit('setTokenKey', '');
uni.$u.toast('退出登录成功');
uni.removeStorageSync('token')
uni.removeStorageSync('password')
setTimeout(()=>{
uni.reLaunch({
url:"../tabbar/login"
})
return;
},200)
}else{
this.$u.toast(res.message);
}
}, error => {
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
}
},
//
verification(){
console.log(this.oldPassword)
if(!this.oldPassword){
this.$refs.uToast.show({
title: '请输入旧密码!',
type: 'error',
})
return false;
}else if(!this.newPassword){
this.$refs.uToast.show({
title: '请输入新密码!',
type: 'error',
})
return false;
}else if(!this.confirmPassword){
this.$refs.uToast.show({
title: '请输入确认密码!',
type: 'error',
})
return false;
}else if(this.newPassword!=this.confirmPassword){
this.$refs.uToast.show({
title: '两次输入密码不同!',
type: 'error',
})
return false;
}else{
return true;
}
}
}
}
</script>
<style scoped lang="less">
#reset-password{
.list-box{
padding: 0 36rpx 0 45rpx;
.item{
height: 120rpx;
border-bottom: 1px solid #E5E5E5;
display: flex;
align-items: center;
font-size: 28rpx;
color: #222;
.item-left{
box-sizing: border-box;
padding-left: 28rpx;
width: 294rpx;
display: flex;
align-items: center;
image{
width: 33rpx;
height: 33rpx;
margin-right: 23rpx;
}
}
input{
flex: 1;
font-size: 28rpx;
}
&:first-of-type{
color: #666;
}
}
}
}
.btn{
display: flex;
justify-content: center;
height: 142rpx;
position: fixed;
left: 0;
right: 0;
bottom: 0;
button{
width: 690rpx;
height: 90rpx;
background: #3683FD;
border-radius: 43rpx;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
}
}
</style>

View File

@ -0,0 +1,92 @@
<template>
<view id="security-setting">
<nav-bar :is-back="true" title="安全设置"></nav-bar>
<view class="list-box">
<view class="item-box" @click="goUrl('./reset-password')">
<text>修改密码</text>
<u-icon name="arrow-right" color="#A8A8A8" size="25" style="font-weight: bold;"></u-icon>
</view>
<view class="item-box" style="padding-right: 49rpx;">
<text>版本信息</text>
<text>V{{version}}</text>
</view>
<view class="item-box btn" @click="quit()">
退出
</view>
</view>
</view>
</template>
<script>
import NavBar from '@/common/components/navbar/NavBar.vue'
export default {
data() {
return {
version:'1.0.0'
}
},
components: {
NavBar
},
onLoad() {
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid,(wgtinfo)=>{
// console.log(JSON.stringify(wgtinfo));
// console.log(wgtinfo.version);//
this.version = wgtinfo.version;
})
// #endif
// #ifdef MP-WEIXIN
const accountInfo = wx.getAccountInfoSync();
if(accountInfo.miniProgram.envVersion=='release'){
this.version = accountInfo.miniProgram.version;
}
console.log(accountInfo.miniProgram.version) // 'a.b.c'
// #endif
},
onShow() {
},
methods: {
// 退
quit(){
uni.reLaunch({
url: '../index/login'
})
},
goUrl(url){
console.log(url)
uni.navigateTo({
url:url
})
}
}
}
</script>
<style scoped lang="less">
#security-setting{
background: #ebeef5;
height: 100%;
.list-box{
padding: 20rpx 24rpx 0;
.item-box{
// width: 703px;
height: 75rpx;
background: #FFFFFF;
border-radius: 10rpx;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 46rpx 0 40rpx;
font-size: 28rpx;
color: #666666;
margin-bottom: 20rpx;
&.btn{
justify-content: center;
color: #222222;
}
}
}
}
</style>

81
pages/new/detail.vue Normal file
View File

@ -0,0 +1,81 @@
<template>
<view class="new-detail">
<view class="title">
{{title}}
</view>
<view class="info-box">
<text>{{time}}</text>
</view>
<view class="content">
<u-parse :html="content"></u-parse>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title:'',
time:'',
clicks:'',
content:'',
}
},
onLoad(option){
if (option?.obj) {
let data = JSON.parse(decodeURIComponent(option.obj));
this.id = data.id;
this.time = data.createdAt;
this.title = data.title;
// this.content = data.message;
this.readNew(data.id);
}
},
methods:{
readNew(id){
this.$api.newApi.getNoticeDetail({id:id}).then((res)=>{
console.log("当前获取消息详情",res)
if(res.code == 0){
this.clicks = res.data.clicks;
this.content = res.data.content
}else{
uni.showToast({
title: res.msg,
icon:"none",
duration: 2000
});
}
}).catch(()=>{
this.$u.toast('服务器开小差了呢,请您稍后再试')
})
}
}
}
</script>
<style lang="scss" scoped>
.new-detail{
padding: 20rpx;
.title{
font-weight: bold;
font-size: 38rpx;
}
.info-box{
margin: 20rpx 0;
display: flex;
justify-content: space-between;
align-items: center;
text{
color: #999;
font-size: 24rpx;
}
}
.content{
text-indent: 56rpx;
font-size: 30rpx;
color: #666;
}
}
</style>

389
pages/tabbar/config.vue Normal file
View File

@ -0,0 +1,389 @@
<template>
<view class="config-box">
<view class="config-list" v-if="configList.length">
<view class="config-item" v-for="(item,index) in configList" :key="item.id" @click="changeConfig(index)">
<!-- <u-icon v-if="configIndex==index" class="icon-checkbox-mark" name="checkbox-mark" color="#ff0000" size="50"></u-icon> -->
<view class="acitve-box" v-if="configIndex==index">
已选择
</view>
<view class="congfig-txt">
{{item.protocol+item.address}}
</view>
<view class="operate-box">
<view class="iconfont icon-bianji1 color-blue" @click.stop="openEdit(index)"></view>
<view class="iconfont icon-shanchu color-red" @click.stop="delConfig(index)"></view>
</view>
</view>
</view>
<u-empty margin-top="200" v-else text="没有域名,请添加" mode="list"></u-empty>
<view class="btn-box">
<button type="primary" @tap="openAdd">添加域名</button>
</view>
<u-modal v-model="show" width="700" title="新增/修改域名" ref="uModal" :show-cancel-button="true" :mask-close-able="true" @confirm="addConfig">
<view class="slot-content">
<view class="form-item">
<view class="form-label">
网络协议
</view>
<view class="form-value" @click="protocolShow=true">
{{form.protocol?form.protocol:'请选择'}}
<view class="iconfont icon-xiangyou1"></view>
</view>
</view>
<view class="form-item">
<view class="form-label">
域名或ip
</view>
<view class="form-value">
<input type="text" v-model="form.address" placeholder="请输入地址如:192.168.0.1">
</view>
</view>
</view>
</u-modal>
<u-select v-model="protocolShow" :list="protocolList" @confirm="confirmProtocol"></u-select>
<u-toast ref="uToast" />
</view>
</template>
<script>
export default {
data() {
return {
configIndex:0,
configList:[],
form:{
id:'',
protocol:'',
address:'',
},
protocolShow:false,
protocolList:[
{
value: 'http://',
label: 'http://'
},
{
value: 'https://',
label: 'https://'
}
],
show:false,
};
},
onLoad() {
// 使https
// #ifdef MP-WEIXIN
this.protocolList = [
{
value: 'https://',
label: 'https://'
}
]
// #endif
this.getConfigList();
},
methods:{
getConfigList(){
uni.getStorage({
key:'configList',
}).then(res => {
//
if(res.length==2){
this.configList = res[1].data;
}
return uni.getStorage({
key:'configIndex',
})
}).then(res => {
console.log("configIndex",res)
if(res.length==2){
this.configIndex = res[1].data;
}
})
},
changeConfig(i){
console.log("index",i)
if(i !== this.configIndex){
this.configIndex = i;
uni.setStorage({
key:'configIndex',
data: i,
}).then(res => {
console.log("修改索引")
})
}
},
verification(){
if(!this.form.protocol){
this.$refs.uToast.show({
title: '请先选择协议!',
type: 'error'
})
return false;
}else if(!this.form.address){
this.$refs.uToast.show({
title: '请先输入地址',
type: 'error',
})
return false;
}else if(!this.$u.test.url(this.form.protocol+this.form.address)){
this.$refs.uToast.show({
title: '请确认输入地址正确',
type: 'error',
})
return false;
}else{
return true;
}
},
openAdd(){
if(this.configList.length == 0){
this.form = {
id:'',
protocol:'https://',
address:'cloud.iot-fast.com',
}
}else{
this.form = {
id:'',
protocol:'',
address:'',
}
}
this.show = true;
},
addConfig(){
console.log("添加页面",this.form)
if(this.verification()){
if(this.form.id===''){
//
this.configList.push({
id:this.$u.guid(32),
protocol:this.form.protocol,
address:this.form.address,
})
uni.setStorage({
key:'configList',
data: this.configList,
}).then(res => {
this.$refs.uToast.show({
title: '新增成功',
type: 'success',
})
})
if(this.configList.length==1){
uni.setStorage({
key:'configIndex',
data: 0,
}).then(res => {
console.log("添加第一个域名索引为0")
})
}
this.show = false;
this.getConfigList()
console.log("configList",this.configList)
}else{
//
this.configList.map(item=>{
if(item.id == this.form.id){
item.protocol=this.form.protocol;
item.address=this.form.address;
}
return item;
})
uni.setStorage({
key:'configList',
data: this.configList,
}).then(res => {
this.$refs.uToast.show({
title: '编辑成功',
type: 'success',
})
})
this.show = false;
this.getConfigList()
}
}else{
this.$refs.uModal.clearLoading();
}
},
confirmProtocol(e){
this.form.protocol = e[0].value;
},
openEdit(index){
this.form = this.configList[index];
this.show = true;
},
delConfig(index){
uni.showModal({
title: '提示',
content: '确认要删除域名吗?',
success: (res)=>{
if (res.confirm) {
console.log('用户点击确定');
this.configList.splice(index, 1);
uni.setStorage({
key:'configList',
data: this.configList,
}).then(res => {
this.$refs.uToast.show({
title: '删除成功',
type: 'success',
})
})
if(this.configIndex<index){
}else{
if(this.configIndex>index){
this.configIndex = this.configIndex - 1;
}else if(this.configIndex==index){
if(this.configList.length==0){
this.configIndex = -1;
}else{
this.configIndex = 0;
}
}
uni.setStorage({
key:'configIndex',
data: this.configIndex,
}).then(res => {
console.log("修改索引")
})
}
this.getConfigList();
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
}
}
}
</script>
<style>
page{
background: #f5f5f5;
}
</style>
<style lang="scss" scoped>
.color-blue{
color: $mainColor;
}
.color-red{
color: red;
}
.config-box{
.config-list{
.config-item{
background: #fff;
// border-radius: 10rpx;
padding: 30rpx 20rpx;
padding-left: 70rpx;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
border-bottom: 1px solid #f5f5f5;
overflow: hidden;
.acitve-box{
z-index: 888;
position: absolute;
top: -16rpx;
left: -76rpx;
width: 200rpx;
height: 80rpx;
display: flex;
justify-content: center;
align-items: center;
transform: rotate(-40deg) ;
padding-top: 30rpx;
color: #fff;
background: $mainColor;
font-size: 26rpx;
}
.icon-checkbox-mark{
position: absolute;
top:20rpx;
left:10rpx;
}
.operate-box{
display: flex;
align-items: center;
.iconfont{
font-weight: bold;
margin-left: 20rpx;
font-size: 40rpx;
}
}
}
}
}
.slot-content{
padding: 20rpx 30rpx;
.form-item{
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10rpx;
.form-label{
width: 170rpx;
}
.form-value{
flex: 1;
background: #f0f0f0;
border-radius: 8rpx;
height: 70rpx;
display: flex;
align-items: center;
padding-right: 20rpx;
input{
width: 100%;
padding-left: 20rpx;
}
}
&:first-child{
.form-value{
// justify-content: flex-end;
padding-left: 20rpx;
position: relative;
padding-right: 40rpx;
.iconfont{
position: absolute;
right: 6rpx;
top: 19rpx;
font-size: 37rpx;
color: #8a8c90;
}
}
}
}
}
.btn-box{
position: fixed;
width: 100%;
height: 130rpx;
padding: 10rpx;
padding-bottom: 20rpx;
box-sizing: border-box;
bottom: 0;
display: flex;
align-items: center;
justify-content: space-around;
background-color: #fff;
button{
width: 95%;
background-color: $mainColor;
color: #fff;
}
.bg-grey{
background: #e7e7e7;
color: #8a8c90;
}
}
</style>

43
pages/tabbar/home.vue Normal file
View File

@ -0,0 +1,43 @@
<template>
<view class="content">
<intelligent v-if="homeType == 'intelligent'" style="width: 100%;height: 100%;" ref="intelligentRef"></intelligent>
<iots v-if="homeType == 'iots'" :showToggle="showToggle" :hideToggle="hideToggle" style="width: 100%;height: 100%;" ref="iotsRef"></iots>
</view>
</template>
<script>
// navbar
import intelligent from "@/pages/tabbar/module/intelligent.vue"
// import iots from "@/pages/tabbar/module/iots.vue"
import iots from "@/pages/tabbar/module/iots2.vue"
export default {
data() {
return {
homeType:'iots',
showToggle:false,
hideToggle:false,
}
},
components:{
intelligent,
iots,
},
onUnload() {
console.log("离开页面")
},
onShow() {
console.log("show")
this.showToggle = !this.showToggle;
},
onHide(){
console.log("hide")
this.hideToggle = !this.hideToggle;
}
}
</script>
<style lang="scss" scoped>
page,.content {
height: 100%;
}
</style>

511
pages/tabbar/login.vue Normal file

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More