Compare commits
19 Commits
20b808adc7
...
997cd9426b
| Author | SHA1 | Date |
|---|---|---|
|
|
997cd9426b | |
|
|
d01b66256b | |
|
|
2c224682d2 | |
|
|
0a2bf1ff9a | |
|
|
63d0355c27 | |
|
|
e6dd93498f | |
|
|
991fdc11e7 | |
|
|
b275f706c3 | |
|
|
6a1f44f6ce | |
|
|
9eaf3e7e71 | |
|
|
7f493da241 | |
|
|
4108e58459 | |
|
|
584ada5811 | |
|
|
347082bb30 | |
|
|
610814d178 | |
|
|
e720c37b68 | |
|
|
51fb80c782 | |
|
|
3105c590bb | |
|
|
07ab68aba5 |
5
App.vue
5
App.vue
|
|
@ -2,6 +2,7 @@
|
||||||
import config from './config'
|
import config from './config'
|
||||||
import { getToken } from '@/utils/auth'
|
import { getToken } from '@/utils/auth'
|
||||||
import mqttUtil from '@/utils/mqtt'
|
import mqttUtil from '@/utils/mqtt'
|
||||||
|
import {startMqttOnlinePing, stopMqttOnlinePing} from "./utils/mqtt";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
globalData: {
|
globalData: {
|
||||||
|
|
@ -55,6 +56,9 @@ export default {
|
||||||
console.info("token存在,mqtt重新连接中。。")
|
console.info("token存在,mqtt重新连接中。。")
|
||||||
this.reconnectMqtt()
|
this.reconnectMqtt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 防止 mqtt client 还没连上:可以等 connected 后再 start(见下面提示)
|
||||||
|
startMqttOnlinePing( 20000);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onHide() {
|
onHide() {
|
||||||
|
|
@ -65,6 +69,7 @@ export default {
|
||||||
// ========== 新增:切后台时同步到localStorage ==========
|
// ========== 新增:切后台时同步到localStorage ==========
|
||||||
uni.setStorageSync('mqtt_subscribe_list', this.globalData.mqtt.subscribeList)
|
uni.setStorageSync('mqtt_subscribe_list', this.globalData.mqtt.subscribeList)
|
||||||
mqttUtil.disconnectMqtt()
|
mqttUtil.disconnectMqtt()
|
||||||
|
stopMqttOnlinePing();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询无线传输线管数据列表
|
||||||
|
export function listSpecialData(query) {
|
||||||
|
return request({
|
||||||
|
url: '/data/specialData/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询无线传输线管数据详细
|
||||||
|
export function getSpecialData(id) {
|
||||||
|
return request({
|
||||||
|
url: '/data/specialData/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增无线传输线管数据
|
||||||
|
export function addSpecialData(data) {
|
||||||
|
return request({
|
||||||
|
url: '/data/specialData',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改无线传输线管数据
|
||||||
|
export function updateSpecialData(data) {
|
||||||
|
return request({
|
||||||
|
url: '/data/specialData',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除无线传输线管数据
|
||||||
|
export function delSpecialData(id) {
|
||||||
|
return request({
|
||||||
|
url: '/data/specialData/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取最新一条数据
|
||||||
|
export function getNewSpecialData() {
|
||||||
|
return request({
|
||||||
|
url: '/data/specialData/getNewSpecialData',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询大棚管理列表
|
||||||
|
export function listAgri(query) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/agri/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询大棚管理详细
|
||||||
|
export function getAgri(id) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/agri/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增大棚管理
|
||||||
|
export function addAgri(data) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/agri',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改大棚管理
|
||||||
|
export function updateAgri(data) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/agri',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除大棚管理
|
||||||
|
export function delAgri(id) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/agri/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询告警方式设置列表
|
||||||
|
export function listAlarm(query) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/alarm/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询告警方式设置详细
|
||||||
|
export function getAlarm(id) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/alarm/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增告警方式设置
|
||||||
|
export function addAlarm(data) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/alarm',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改告警方式设置
|
||||||
|
export function updateAlarm(data) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/alarm',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除告警方式设置
|
||||||
|
export function delAlarm(id) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/alarm/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询执行时间限位管理列表
|
||||||
|
export function listLimit(query) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/limit/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询执行时间限位管理详细
|
||||||
|
export function getLimit(id) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/limit/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增执行时间限位管理
|
||||||
|
export function addLimit(data) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/limit',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改执行时间限位管理
|
||||||
|
export function updateLimit(data) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/limit',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除执行时间限位管理
|
||||||
|
export function delLimit(id) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/limit/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 大棚运行时间限位查询
|
||||||
|
export function getAgriByImei(id) {
|
||||||
|
return request({
|
||||||
|
url: '/assets/limit/getAgriByImei/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询需求清单列表
|
||||||
|
export function listRequire(query) {
|
||||||
|
return request({
|
||||||
|
url: '/system/require/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询需求清单详细
|
||||||
|
export function getRequire(id) {
|
||||||
|
return request({
|
||||||
|
url: '/system/require/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增需求清单
|
||||||
|
export function addRequire(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/require',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改需求清单
|
||||||
|
export function updateRequire(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/require',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除需求清单
|
||||||
|
export function delRequire(id) {
|
||||||
|
return request({
|
||||||
|
url: '/system/require/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export function delRequires(ids) {
|
||||||
|
return request({
|
||||||
|
url: '/system/require/remove',
|
||||||
|
method: 'delete',
|
||||||
|
data: ids
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// 应用全局配置
|
// 应用全局配置
|
||||||
module.exports = {
|
module.exports = {
|
||||||
baseUrl: process.env.UNI_PLATFORM === 'mp-weixin'?"http://122.51.109.52:8088":'http://localhost:8088',
|
// baseUrl: process.env.UNI_PLATFORM === 'mp-weixin'?"http://122.51.109.52:8088":(process.env.NODE_ENV === "production" ? "/api" : "http://localhost:8088"),
|
||||||
|
baseUrl: process.env.NODE_ENV === "production"?"https://api.xiaoces.com/api":"http://localhost:8088",
|
||||||
// 应用信息
|
// 应用信息
|
||||||
appInfo: {
|
appInfo: {
|
||||||
// 应用名称
|
// 应用名称
|
||||||
|
|
|
||||||
1
main.js
1
main.js
|
|
@ -13,7 +13,6 @@ Vue.use(plugins)
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
Vue.prototype.$store = store
|
Vue.prototype.$store = store
|
||||||
Vue.prototype.getDicts = getDicts
|
Vue.prototype.getDicts = getDicts
|
||||||
|
|
||||||
App.mpType = 'app'
|
App.mpType = 'app'
|
||||||
|
|
||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
"title" : "Agri-App",
|
"title" : "Agri-App",
|
||||||
"router" : {
|
"router" : {
|
||||||
"mode" : "hash",
|
"mode" : "hash",
|
||||||
"base" : "/m/"
|
"base" : "/"
|
||||||
},
|
},
|
||||||
"optimization" : {
|
"optimization" : {
|
||||||
"minimize" : true,
|
"minimize" : true,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mqtt": "^3.0.0"
|
"mqtt": "^2.18.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
22
pages.json
22
pages.json
|
|
@ -25,12 +25,7 @@
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "我的"
|
"navigationBarTitleText": "我的"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"path": "pages/demo/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "示例"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"path": "pages/control/index",
|
"path": "pages/control/index",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "控制中心"
|
"navigationBarTitleText": "控制中心"
|
||||||
|
|
@ -66,6 +61,16 @@
|
||||||
"navigationBarTitleText": "常见问题"
|
"navigationBarTitleText": "常见问题"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
"path": "pages/mine/mqtt/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "mqtt工具"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"path": "pages/mine/require/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "需求清单"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
"path": "pages/mine/about/index",
|
"path": "pages/mine/about/index",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "关于我们"
|
"navigationBarTitleText": "关于我们"
|
||||||
|
|
@ -100,11 +105,6 @@
|
||||||
"text": "工作台"
|
"text": "工作台"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "pages/demo/index",
|
|
||||||
"iconPath": "static/images/tabbar/work.png",
|
|
||||||
"selectedIconPath": "static/images/tabbar/work_.png",
|
|
||||||
"text": "示例"
|
|
||||||
},{
|
|
||||||
"pagePath": "pages/mine/index",
|
"pagePath": "pages/mine/index",
|
||||||
"iconPath": "static/images/tabbar/mine.png",
|
"iconPath": "static/images/tabbar/mine.png",
|
||||||
"selectedIconPath": "static/images/tabbar/mine_.png",
|
"selectedIconPath": "static/images/tabbar/mine_.png",
|
||||||
|
|
|
||||||
|
|
@ -2,221 +2,160 @@
|
||||||
<view class="container">
|
<view class="container">
|
||||||
<!-- 控制设置标题 -->
|
<!-- 控制设置标题 -->
|
||||||
<view class="control-title">控制设置</view>
|
<view class="control-title">控制设置</view>
|
||||||
<uni-section title="请选择大棚:" titleFontSize="18px" type="line">
|
<uni-section title="请选择大棚:" :subTitle="imei" titleFontSize="18px" type="line">
|
||||||
<view class="uni-px-5 uni-pb-5">
|
<view class="uni-px-5 uni-pb-5">
|
||||||
<uni-data-select v-model="value" :localdata="range" @change="change"></uni-data-select>
|
<uni-data-select v-model="value" :localdata="range" @change="change"></uni-data-select>
|
||||||
</view>
|
</view>
|
||||||
</uni-section>
|
</uni-section>
|
||||||
|
|
||||||
|
<uni-section title="实时温湿度" titleFontSize="16px" type="line" v-if="value!== 1">
|
||||||
<uni-section title="实时温湿度" titleFontSize="16px" type="line" v-if="value!== 1">
|
|
||||||
<template v-slot:right >
|
<template v-slot:right >
|
||||||
{{ temp }}
|
{{ temp }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<view>
|
<view>
|
||||||
|
<!-- 优化:温度卡片循环渲染 -->
|
||||||
<view class="uni-flex_control uni-row" >
|
<view class="uni-flex_control uni-row" >
|
||||||
<view class="text uni-flex_control_one uni-view">
|
<view
|
||||||
<text class="data" :style="fontStyle">{{ liveData.temp1 }}<p v-if=(testNumber(liveData.temp1)) class="tempStyle">℃</p></text>
|
class="text uni-flex_control_one uni-view"
|
||||||
<text class="data">温度1</text>
|
v-for="item in sensorCards.temp"
|
||||||
</view>
|
:key="item.key"
|
||||||
<view class="text uni-flex_control_one uni-view">
|
>
|
||||||
<text class="data" :style="fontStyle">{{ liveData.temp2 }}<p v-if=(testNumber(liveData.temp2)) class="tempStyle">℃</p></text>
|
<text class="data" :style="fontStyle">
|
||||||
<text class="data">温度2</text>
|
{{ liveData[item.key] }}
|
||||||
</view>
|
<text v-if="isEffectiveValue(liveData[item.key])" class="tempStyle">℃</text>
|
||||||
<view class="text uni-flex_control_one uni-view">
|
</text>
|
||||||
<text class="data" :style="fontStyle">{{ liveData.temp3 }}<p v-if=(testNumber(liveData.temp3)) class="tempStyle">℃</p></text>
|
<text class="data">{{ item.label }}</text>
|
||||||
<text class="data">温度3</text>
|
|
||||||
</view>
|
|
||||||
<view class="text uni-flex_control_one uni-view">
|
|
||||||
<text class="data" :style="fontStyle">{{ liveData.temp4 }}<p v-if=(testNumber(liveData.temp4)) class="tempStyle">℃</p></text>
|
|
||||||
<text class="data">温度4</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 优化:湿度卡片循环渲染 -->
|
||||||
<view class="uni-flex_control uni-row" >
|
<view class="uni-flex_control uni-row" >
|
||||||
<view class="text uni-flex_control_two uni-view">
|
<view
|
||||||
<text class="data" :style="fontStyle">{{ liveData.humi1 }}<p v-if=(testNumber(liveData.humi1)) class="humiStyle"> %RH</p></text>
|
class="text uni-flex_control_two uni-view"
|
||||||
<text class="data">湿度1</text>
|
v-for="item in sensorCards.humi"
|
||||||
</view>
|
:key="item.key"
|
||||||
<view class="text uni-flex_control_two uni-view">
|
>
|
||||||
<text class="data" :style="fontStyle">{{ liveData.humi2 }}<p v-if=(testNumber(liveData.humi2)) class="humiStyle"> %RH</p></text>
|
<text class="data" :style="fontStyle">
|
||||||
<text class="data">湿度2</text>
|
{{ liveData[item.key] }}
|
||||||
</view>
|
<text v-if="isEffectiveValue(liveData[item.key])" class="humiStyle"> %RH</text>
|
||||||
<view class="text uni-flex_control_two uni-view">
|
</text>
|
||||||
<text class="data" :style="fontStyle">{{ liveData.humi3 }}<p v-if=(testNumber(liveData.humi3)) class="humiStyle"> %RH</p></text>
|
<text class="data">{{ item.label }}</text>
|
||||||
<text class="data">湿度3</text>
|
|
||||||
</view>
|
|
||||||
<view class="text uni-flex_control_two uni-view">
|
|
||||||
<text class="data" :style="fontStyle">{{ liveData.humi4 }}<p v-if=(testNumber(liveData.humi4)) class="humiStyle"> %RH</p></text>
|
|
||||||
<text class="data">湿度4</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</uni-section>
|
</uni-section>
|
||||||
|
|
||||||
<uni-section title="设备控制" titleFontSize="16px" type="line" v-if="value!== 1">
|
<uni-section title="设备控制" titleFontSize="16px" type="line" v-if="value!== 1 && !['862538065276939','A','B','C'].includes(imei)">
|
||||||
<template v-slot:right >
|
<template v-slot:right >
|
||||||
{{ control }}
|
{{ control }}
|
||||||
</template>
|
</template>
|
||||||
<!-- 卷膜/卷被卡片容器(2列栅格布局) -->
|
<!-- 优化:设备卡片循环渲染 -->
|
||||||
<view class="card-grid">
|
<view class="card-grid">
|
||||||
<!-- 卷被开卡片 -->
|
<view
|
||||||
<view class="control-card" @click="handleCardClick(1-status.jbk, 'jbk')">
|
class="control-card"
|
||||||
|
v-for="card in deviceCards"
|
||||||
|
:key="card.type"
|
||||||
|
@click="openTimeModal(card)"
|
||||||
|
>
|
||||||
<view class="card-text">
|
<view class="card-text">
|
||||||
<text class="card-main">卷被开</text>
|
<text class="card-main">{{ card.name }}</text>
|
||||||
<!-- 核心修改:添加限位时间,与暂停/运行同行靠右 -->
|
|
||||||
<view class="card-sub-wrapper">
|
<view class="card-sub-wrapper">
|
||||||
<text class="card-sub" v-if="hide">{{ show.jbk }}</text>
|
<text class="card-sub" v-if="showStatusText">{{ show[card.type] || '未知' }}</text>
|
||||||
<text class="limit-time">运行时间:{{ limitTimes.jbk }} s</text>
|
<text class="limit-time">
|
||||||
|
运行时间:{{ limitTimes[`${card.type}Limit`] && limitTimes[`${card.type}Limit`]!=='0' ? `${limitTimes[`${card.type}Limit`]} s` : '- -' }}
|
||||||
|
</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-icon" :class="{ active: status.jbk === 1 }">
|
<view class="card-icon" :class="{ active: status[card.type] === 1 }" @click.stop="handleCardClick(1 - status[card.type], card.type)">
|
||||||
<uni-icons :type=" (status.jbk === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
|
<!-- 加@click.stop防止冒泡触发卡片点击的弹窗事件 -->
|
||||||
</view>
|
<uni-icons
|
||||||
</view>
|
:type="status[card.type] === 1 ? 'circle' : 'circle-filled'"
|
||||||
|
size="24"
|
||||||
<!-- 卷被关卡片 -->
|
color="#fff"
|
||||||
<view class="control-card" @click="handleCardClick(1-status.jbg,'jbg')">
|
/>
|
||||||
<view class="card-text">
|
|
||||||
<text class="card-main">卷被关</text>
|
|
||||||
<view class="card-sub-wrapper">
|
|
||||||
<text class="card-sub" v-if="hide">{{ show.jbg }}</text>
|
|
||||||
<text class="limit-time">运行时间:{{ limitTimes.jbg }} s</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-icon" :class="{ active: status.jbg === 1 }">
|
|
||||||
<uni-icons :type=" (status.jbg === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 卷膜1开卡片 -->
|
|
||||||
<view class="control-card" @click="handleCardClick(1-status.jm1k, 'jm1k')">
|
|
||||||
<view class="card-text">
|
|
||||||
<text class="card-main">卷膜1开</text>
|
|
||||||
<view class="card-sub-wrapper">
|
|
||||||
<text class="card-sub" v-if="hide">{{ show.jm1k }}</text>
|
|
||||||
<text class="limit-time">运行时间:{{ limitTimes.jm1k }} s</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-icon" :class="{ active: status.jm1k === 1 }">
|
|
||||||
<uni-icons :type="(status.jm1k === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 卷膜1关卡片 -->
|
|
||||||
<view class="control-card" @click="handleCardClick(1-status.jm1g, 'jm1g')">
|
|
||||||
<view class="card-text">
|
|
||||||
<text class="card-main">卷膜1关</text>
|
|
||||||
<view class="card-sub-wrapper">
|
|
||||||
<text class="card-sub" v-if="hide">{{ show.jm1g }}</text>
|
|
||||||
<text class="limit-time">运行时间:{{ limitTimes.jm1g }} s</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-icon" :class="{ active: status.jm1g === 1 }">
|
|
||||||
<uni-icons :type="(status.jm1g === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 卷膜2卡片 -->
|
|
||||||
<view class="control-card" @click="handleCardClick(1-status.jm2k, 'jm2k')">
|
|
||||||
<view class="card-text">
|
|
||||||
<text class="card-main">卷膜2开</text>
|
|
||||||
<view class="card-sub-wrapper">
|
|
||||||
<text class="card-sub" v-if="hide">{{ show.jm2k }}</text>
|
|
||||||
<text class="limit-time">运行时间:{{ limitTimes.jm2k }} s</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-icon" :class="{ active: status.jm2k === 1 }">
|
|
||||||
<uni-icons :type="(status.jm2k === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 卷膜2关卡片 -->
|
|
||||||
<view class="control-card" @click="handleCardClick(1-status.jm2g, 'jm2g')">
|
|
||||||
<view class="card-text">
|
|
||||||
<text class="card-main">卷膜2关</text>
|
|
||||||
<view class="card-sub-wrapper">
|
|
||||||
<text class="card-sub" v-if="hide">{{ show.jm2g }}</text>
|
|
||||||
<text class="limit-time">运行时间:{{ limitTimes.jm2g }} s</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-icon" :class="{ active: status.jm2g === 1 }">
|
|
||||||
<uni-icons :type="(status.jm2g === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- 卷膜3开卡片 -->
|
|
||||||
<view class="control-card" @click="handleCardClick(1-status.jm3k, 'jm3k')">
|
|
||||||
<view class="card-text">
|
|
||||||
<text class="card-main">卷膜3开</text>
|
|
||||||
<view class="card-sub-wrapper">
|
|
||||||
<text class="card-sub" v-if="hide">{{ show.jm3k }}</text>
|
|
||||||
<text class="limit-time">运行时间:{{ limitTimes.jm3k }} s</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-icon" :class="{ active: status.jm3k === 1 }">
|
|
||||||
<uni-icons :type="(status.jm3k === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 卷膜3关卡片 -->
|
|
||||||
<view class="control-card" @click="handleCardClick(1-status.jm3g, 'jm3g')">
|
|
||||||
<view class="card-text">
|
|
||||||
<text class="card-main">卷膜3关</text>
|
|
||||||
<view class="card-sub-wrapper">
|
|
||||||
<text class="card-sub" v-if="hide">{{ show.jm3g }}</text>
|
|
||||||
<text class="limit-time">运行时间:{{ limitTimes.jm3g }} s</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="card-icon" :class="{ active: status.jm3g === 1 }">
|
|
||||||
<uni-icons :type="(status.jm3g === 1)?'circle':'circle-filled'" size="24" color="#fff"/>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</uni-section>
|
</uni-section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<uni-popup ref="inputDialog" mode="center" >
|
||||||
|
<!-- 新增:修改运行时间的弹窗 -->
|
||||||
|
<view class="modal-container">
|
||||||
|
<view class="modal-title">{{ `【${selectedText} - ${currentCard.name}】运行时间` }}</view>
|
||||||
|
<view class="modal-input-wrap">
|
||||||
|
<text class="modal-label">当前时间:</text>
|
||||||
|
<text class="modal-current">{{ currentCardTime ? `${currentCardTime} 秒` : '未设置' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="modal-input-wrap" >
|
||||||
|
<text class="modal-label">修改后时间:</text>
|
||||||
|
<input
|
||||||
|
class="modal-input"
|
||||||
|
type="number"
|
||||||
|
v-model.number="newLimitTime"
|
||||||
|
/>
|
||||||
|
<!-- <uni-number-box v-model="newLimitTime" />-->
|
||||||
|
<text class="modal-unit">秒</text>
|
||||||
|
</view>
|
||||||
|
<view class="modal-btn-wrap">
|
||||||
|
<button class="modal-btn cancel" @click="close">取消</button>
|
||||||
|
<button class="modal-btn confirm" @click="confirmModifyTime">确定</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</uni-popup>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// ========== 修改:替换原有mqtt引入为全局工具类 ==========
|
// 优化:抽离魔法值常量
|
||||||
// import mqtt from 'mqtt' // 移除原有mqtt直接引入
|
import UniPopupDialog from "../../uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue";
|
||||||
|
|
||||||
|
const SENSOR_MAP = {
|
||||||
|
temp1: "201", temp2: "202", temp3: "203", temp4: "204",
|
||||||
|
humi1: "101", humi2: "102", humi3: "103", humi4: "104"
|
||||||
|
};
|
||||||
|
const MQTT_TOPIC_SUFFIX = { UP: "/up", DOWN: "/down" };
|
||||||
|
|
||||||
import UniDatetimePicker from "../../uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue";
|
import UniDatetimePicker from "../../uni_modules/uni-datetime-picker/components/uni-datetime-picker/uni-datetime-picker.vue";
|
||||||
|
import UniPopup from "../../uni_modules/uni-popup/components/uni-popup/uni-popup.vue"; // 引入弹窗组件
|
||||||
import { findDtuDataByInfo } from "@/api/system/data";
|
import { findDtuDataByInfo } from "@/api/system/data";
|
||||||
import mqttUtil from '@/utils/mqtt'; // 引入全局MQTT工具类
|
import mqttUtil from '@/utils/mqtt';
|
||||||
|
import UniNumberBox from "../../uni_modules/uni-number-box/components/uni-number-box/uni-number-box.vue";
|
||||||
|
import {addLimit, getAgriByImei, updateLimit} from "../../api/system/assets/limit";
|
||||||
|
import {listAgri} from "../../api/system/assets/agri";
|
||||||
|
import {getNewSpecialData} from "../../api/data/specialData";
|
||||||
|
import store from "../../store";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
dicts: ['sys_data_map'],
|
dicts: ['sys_data_map'],
|
||||||
components: {
|
components: {
|
||||||
UniDatetimePicker
|
UniNumberBox,
|
||||||
|
UniPopupDialog,
|
||||||
|
UniDatetimePicker,
|
||||||
|
UniPopup // 注册弹窗组件
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// ========== 修改:移除原有mqttClient相关变量 ==========
|
|
||||||
// mqttClient: null,
|
|
||||||
temp: "",
|
temp: "",
|
||||||
// ========== 修改:简化mqttConfig,仅保留订阅/发布主题(全局配置已移到工具类) ==========
|
|
||||||
mqttConfig: {
|
mqttConfig: {
|
||||||
subscribeTopic:'/up',
|
subscribeTopic:'/up',
|
||||||
},
|
},
|
||||||
value: 1,
|
value: 1,
|
||||||
hide: false,
|
selectedText: '',
|
||||||
|
// 优化:语义化变量名(替换原 hide: false)
|
||||||
|
showStatusText: false,
|
||||||
control: '正在加载中...',
|
control: '正在加载中...',
|
||||||
range: [{
|
range: [],
|
||||||
"value": '864865085016294',
|
agriId:'',
|
||||||
"text": "十方北棚"
|
|
||||||
}, {
|
|
||||||
"value": '864536071808560',
|
|
||||||
"text": "七方北棚",
|
|
||||||
}, {
|
|
||||||
"value": '864865085008135',
|
|
||||||
"text": "八方北棚"
|
|
||||||
}],
|
|
||||||
imei:'',
|
imei:'',
|
||||||
publishTopic: '/down',
|
publishTopic: '/down',
|
||||||
title:'',
|
title:'',
|
||||||
message: {},
|
message: {},
|
||||||
// ========== 修改:从全局工具类获取连接状态 ==========
|
// 优化:声明响应式变量 connected
|
||||||
// connected:false,
|
connected: false,
|
||||||
liveData: {
|
liveData: {
|
||||||
temp1: '数据加载中...',
|
temp1: '数据加载中...',
|
||||||
temp2: '数据加载中...',
|
temp2: '数据加载中...',
|
||||||
|
|
@ -227,7 +166,33 @@ export default {
|
||||||
humi3: '数据加载中...',
|
humi3: '数据加载中...',
|
||||||
humi4: '数据加载中...'
|
humi4: '数据加载中...'
|
||||||
},
|
},
|
||||||
// 卡片状态(模拟后端返回数据)
|
// 优化:温湿度卡片配置(固定顺序:温度1→2→3→4,湿度1→2→3→4)
|
||||||
|
sensorCards: {
|
||||||
|
temp: [
|
||||||
|
{ label: '温度1', key: 'temp1' },
|
||||||
|
{ label: '温度2', key: 'temp2' },
|
||||||
|
{ label: '温度3', key: 'temp3' },
|
||||||
|
{ label: '温度4', key: 'temp4' }
|
||||||
|
],
|
||||||
|
humi: [
|
||||||
|
{ label: '湿度1', key: 'humi1' },
|
||||||
|
{ label: '湿度2', key: 'humi2' },
|
||||||
|
{ label: '湿度3', key: 'humi3' },
|
||||||
|
{ label: '湿度4', key: 'humi4' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// 优化:设备卡片配置(固定顺序)
|
||||||
|
deviceCards: [
|
||||||
|
{ type: 'jbk', name: '卷被开' },
|
||||||
|
{ type: 'jbg', name: '卷被关' },
|
||||||
|
{ type: 'jm1k', name: '卷膜1开' },
|
||||||
|
{ type: 'jm1g', name: '卷膜1关' },
|
||||||
|
{ type: 'jm2k', name: '卷膜2开' },
|
||||||
|
{ type: 'jm2g', name: '卷膜2关' },
|
||||||
|
{ type: 'jm3k', name: '卷膜3开' },
|
||||||
|
{ type: 'jm3g', name: '卷膜3关' }
|
||||||
|
],
|
||||||
|
// 卡片状态
|
||||||
show: {
|
show: {
|
||||||
jbk: "暂停",
|
jbk: "暂停",
|
||||||
jbg: "暂停",
|
jbg: "暂停",
|
||||||
|
|
@ -238,16 +203,16 @@ export default {
|
||||||
jm3k: "暂停",
|
jm3k: "暂停",
|
||||||
jm3g: "暂停"
|
jm3g: "暂停"
|
||||||
},
|
},
|
||||||
// 新增:限位时间配置(你可以根据实际需求修改数值)
|
// 新增:限位时间配置
|
||||||
limitTimes: {
|
limitTimes: {
|
||||||
jbk: 30,
|
jbkLimit: 0,
|
||||||
jbg: 25,
|
jbgLimit: 0,
|
||||||
jm1k: 30,
|
jm1kLimit: 0,
|
||||||
jm1g: 28,
|
jm1gLimit: 0,
|
||||||
jm2k: 30,
|
jm2kLimit: 0,
|
||||||
jm2g: 26,
|
jm2gLimit: 0,
|
||||||
jm3k: 30,
|
jm3kLimit: 0,
|
||||||
jm3g: 29
|
jm3gLimit: 0
|
||||||
},
|
},
|
||||||
deviceType: '',
|
deviceType: '',
|
||||||
status: {
|
status: {
|
||||||
|
|
@ -260,7 +225,11 @@ export default {
|
||||||
jm3k: 0,
|
jm3k: 0,
|
||||||
jm3g: 0
|
jm3g: 0
|
||||||
},
|
},
|
||||||
fontStyle: ''
|
fontStyle: '',
|
||||||
|
// 新增:弹窗相关变量
|
||||||
|
currentCard: {}, // 当前点击的卡片信息
|
||||||
|
currentCardTime: 0, // 当前卡片的运行时间
|
||||||
|
newLimitTime: 0, // 新的运行时间
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
|
@ -280,47 +249,138 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
// ========== 修改:替换原有connectMqtt为注册消息回调 ==========
|
this.getAgriList();
|
||||||
// this.connectMqtt();
|
|
||||||
// 注册MQTT消息回调(接收设备消息)
|
// 注册MQTT消息回调(接收设备消息)
|
||||||
mqttUtil.setOnMessageCallback(this.ackMessage);
|
mqttUtil.setOnMessageCallback(this.ackMessage);
|
||||||
// 更新连接状态
|
// 更新连接状态
|
||||||
this.connected = mqttUtil.getMqttState().isConnected;
|
this.connected = mqttUtil.getMqttState().isConnected;
|
||||||
},
|
},
|
||||||
onUnload() {
|
onUnload() {
|
||||||
// ========== 修改:移除原有disconnectMqtt,改为移除回调 ==========
|
|
||||||
// this.disconnectMqtt()
|
|
||||||
// 移除MQTT消息回调(避免内存泄漏)
|
// 移除MQTT消息回调(避免内存泄漏)
|
||||||
mqttUtil.removeOnMessageCallback();
|
mqttUtil.removeOnMessageCallback();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
getNewSpecialData() {
|
||||||
|
getNewSpecialData().then(response => {
|
||||||
|
if (response.code === 200 && response.data) {
|
||||||
|
this.makeSpecialData(response.data,false);
|
||||||
|
this.temp = "最后更新时间:"+response.data.time;
|
||||||
|
this.fontStyle = 'font-size:16px;'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
change(e) {
|
change(e) {
|
||||||
this.imei = e;
|
this.imei = e;
|
||||||
this.publishTopic = "dtu/"+this.imei+"/down";
|
if ((e === 'A' || e==='B' || e==='C')
|
||||||
this.mqttConfig.subscribeTopic = "dtu/"+this.imei+"/up";
|
&& store.getters && store.getters.name === 'admin' ) {
|
||||||
|
this.getNewSpecialData(e);
|
||||||
|
this.mqttConfig.subscribeTopic = `dtu/862538063921866${MQTT_TOPIC_SUFFIX.UP}`;
|
||||||
|
}
|
||||||
const selectedItem = this.range.find(item => item.value === e);
|
const selectedItem = this.range.find(item => item.value === e);
|
||||||
if (selectedItem) {
|
if (selectedItem) {
|
||||||
this.selectedText = selectedItem.text; // 获取展示文本
|
this.selectedText = selectedItem.text; // 获取展示文本
|
||||||
|
this.agriId = selectedItem.agriId;
|
||||||
this.title= this.selectedText;
|
this.title= this.selectedText;
|
||||||
var queryParams = {
|
if (e !== 'A' && e!=='B' && e!=='C') {
|
||||||
imei: this.imei
|
// 优化:使用常量拼接MQTT主题
|
||||||
|
this.publishTopic = `dtu/${this.imei}${MQTT_TOPIC_SUFFIX.DOWN}`;
|
||||||
|
this.mqttConfig.subscribeTopic = `dtu/${this.imei}${MQTT_TOPIC_SUFFIX.UP}`;
|
||||||
|
var queryParams = {
|
||||||
|
imei: this.imei
|
||||||
|
}
|
||||||
|
findDtuDataByInfo(queryParams).then(response => {
|
||||||
|
Object.keys(response.data).forEach(key => {
|
||||||
|
this.liveData[key] = response.data[key] || '已离线..';
|
||||||
|
});
|
||||||
|
this.temp = "最后更新时间:"+response.data.time;
|
||||||
|
this.fontStyle = 'font-size:16px;'
|
||||||
|
})
|
||||||
|
this.getAgriByImei();
|
||||||
}
|
}
|
||||||
findDtuDataByInfo(queryParams).then(response => {
|
|
||||||
Object.keys(response.data).forEach(key => {
|
|
||||||
this.liveData[key] = response.data[key] || '已离线..';
|
|
||||||
});
|
|
||||||
this.temp = "最后更新时间:"+response.data.time;
|
|
||||||
this.fontStyle = 'font-size:16px;'
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
this.selectedText = ''; // 无匹配项时清空
|
this.selectedText = ''; // 无匹配项时清空
|
||||||
this.title='';
|
this.title='';
|
||||||
this.value=1;
|
this.value=1;
|
||||||
|
this.agriId = '';
|
||||||
}
|
}
|
||||||
this.reset();
|
this.reset();
|
||||||
this.style="";
|
this.style="";
|
||||||
},
|
},
|
||||||
|
getAgriByImei() {
|
||||||
|
getAgriByImei(this.imei).then(response => {
|
||||||
|
if (response.code === 200) {
|
||||||
|
if (!response.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.limitTimes = response.data;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getAgriList() {
|
||||||
|
listAgri().then(response => {
|
||||||
|
if (response.code === 200) {
|
||||||
|
this.range = response.rows.map(item => ({
|
||||||
|
agriId: item.id,
|
||||||
|
text: item.agriName,
|
||||||
|
value: item.imei // 提取并改名
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (store.getters && store.getters.name === 'admin') {
|
||||||
|
this.range.push(
|
||||||
|
{
|
||||||
|
text:"八方南棚",
|
||||||
|
value:"A"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text:"九方春棚",
|
||||||
|
value:"B"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text:"十二方棚",
|
||||||
|
value:"C"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
makeSpecialData(msgData, tag) {
|
||||||
|
const div10 = (v) => (v == null ? null : Math.round((Number(v)/10)*10)/10);
|
||||||
|
|
||||||
|
// 1. 提取B/C的tag对应键名(精简重复三元)
|
||||||
|
const B_KEYS = {
|
||||||
|
true: {temp1:'205',humi1:'105',temp2:'206',humi2:'106',temp3:'207',humi3:'107',temp4:'208',humi4:'108'},
|
||||||
|
false: {temp1:'temp5',humi1:'humi5',temp2:'temp6',humi2:'humi6',temp3:'temp7',humi3:'humi7',temp4:'temp8',humi4:'humi8'}
|
||||||
|
};
|
||||||
|
const C_KEYS = {
|
||||||
|
true: {temp1:'209',humi1:'109',temp2:'210',humi2:'110',temp3:'211',humi3:'111',temp4:'212',humi4:'112'},
|
||||||
|
false: {temp1:'temp9',humi1:'humi9',temp2:'temp10',humi2:'humi10',temp3:'temp11',humi3:'humi11',temp4:'temp12',humi4:'humi12'}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. 简化传感器键名映射表
|
||||||
|
const IMEI_SENSOR_MAP = {
|
||||||
|
A: SENSOR_MAP,
|
||||||
|
B: B_KEYS[tag], // 直接取tag对应的键名,替代三元
|
||||||
|
C: C_KEYS[tag]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 3. 确定传感器键名(精简变量名)
|
||||||
|
const isAdmin = store.getters?.name === 'admin';
|
||||||
|
const sk = (isAdmin && ['A','B','C'].includes(this.imei)) ? IMEI_SENSOR_MAP[this.imei] : IMEI_SENSOR_MAP.A;
|
||||||
|
|
||||||
|
// 4. 简化liveData的嵌套三元(核心优化)
|
||||||
|
this.liveData = Object.fromEntries(
|
||||||
|
Object.entries(sk).map(([k, skVal]) => [
|
||||||
|
k,
|
||||||
|
(tag
|
||||||
|
? div10(msgData[skVal])
|
||||||
|
: (this.imei === 'A' ? msgData[k] : msgData[skVal]))
|
||||||
|
|| "已离线..."
|
||||||
|
])
|
||||||
|
);
|
||||||
|
},
|
||||||
reset() {
|
reset() {
|
||||||
Object.keys(this.show).forEach(key => {
|
Object.keys(this.show).forEach(key => {
|
||||||
this.show[key] = "暂停";
|
this.show[key] = "暂停";
|
||||||
|
|
@ -331,8 +391,17 @@ export default {
|
||||||
Object.keys(this.liveData).forEach(key => {
|
Object.keys(this.liveData).forEach(key => {
|
||||||
this.liveData[key] = '数据加载中...';
|
this.liveData[key] = '数据加载中...';
|
||||||
});
|
});
|
||||||
|
this.limitTimes= {
|
||||||
|
jbkLimit: 0,
|
||||||
|
jbgLimit: 0,
|
||||||
|
jm1kLimit: 0,
|
||||||
|
jm1gLimit: 0,
|
||||||
|
jm2kLimit: 0,
|
||||||
|
jm2gLimit: 0,
|
||||||
|
jm3kLimit: 0,
|
||||||
|
jm3gLimit: 0
|
||||||
|
};
|
||||||
this.deviceType = '';
|
this.deviceType = '';
|
||||||
|
|
||||||
this.control = '正在加载中...';
|
this.control = '正在加载中...';
|
||||||
this.message = {};
|
this.message = {};
|
||||||
this.temp = '';
|
this.temp = '';
|
||||||
|
|
@ -387,21 +456,18 @@ export default {
|
||||||
// 设备回执
|
// 设备回执
|
||||||
this.deviceType = type;
|
this.deviceType = type;
|
||||||
//todo
|
//todo
|
||||||
|
// this.testAuto(type);
|
||||||
// this.status[type] = this.status[type] === 0 ? 1 : 0;
|
|
||||||
// this.show[type] = this.status[type] === 0 ? "暂停" : "运行";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// ========== 删除:原有connectMqtt方法(全局工具类已处理) ==========
|
|
||||||
// connectMqtt() { ... },
|
|
||||||
|
|
||||||
// ========== 删除:原有disconnectMqtt方法(全局工具类已处理) ==========
|
// 测试专用
|
||||||
// disconnectMqtt() { ... },
|
testAuto(type) {
|
||||||
|
this.$set(this.status, type, this.status[type] === 0 ? 1 : 0);
|
||||||
// ========== 修改:替换原有publishMessage为调用全局工具类 ==========
|
this.$set(this.show, type, this.status[type] === 0 ? "暂停" : "运行");
|
||||||
|
},
|
||||||
publishMessage() {
|
publishMessage() {
|
||||||
if (!this.connected || !this.publishTopic || !this.message) {
|
if (!this.connected || !this.publishTopic || !this.message) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
|
|
@ -418,7 +484,6 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.addMessage(`发布失败:设备:[${this.publishTopic}]`)
|
this.addMessage(`发布失败:设备:[${this.publishTopic}]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.message = {};
|
this.message = {};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -426,14 +491,12 @@ export default {
|
||||||
ackMessage(topic, payload) {
|
ackMessage(topic, payload) {
|
||||||
// 1. 先判断是否是目标订阅主题(如dtu/xxx/up)
|
// 1. 先判断是否是目标订阅主题(如dtu/xxx/up)
|
||||||
if (topic !== this.mqttConfig.subscribeTopic) return;
|
if (topic !== this.mqttConfig.subscribeTopic) return;
|
||||||
// console.log(`监听到消息:topic=${topic},message=${payload}`)
|
|
||||||
|
|
||||||
// 2. 解析消息体(注意异常捕获)
|
|
||||||
let msgData = {};
|
let msgData = {};
|
||||||
|
// 优化:捕获JSON解析异常
|
||||||
try {
|
try {
|
||||||
msgData = JSON.parse(payload);
|
msgData = JSON.parse(payload);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("消息解析失败:", e);
|
console.error("MQTT消息解析失败:", e, payload);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -444,32 +507,33 @@ export default {
|
||||||
this.handleOtherContent(msgData,payload)
|
this.handleOtherContent(msgData,payload)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addMessage(content) {
|
addMessage(content) {
|
||||||
console.info("提示消息:" + content)
|
console.info("提示消息:" + content)
|
||||||
},
|
},
|
||||||
|
|
||||||
// 处理指令回执的函数(完全保留)
|
// 处理指令回执的函数(核心修改:添加定时器+快照)
|
||||||
handleCommandAck(ackData, type) {
|
handleCommandAck(ackData, type) {
|
||||||
// 拿到指令字段(如jm2k)和执行状态(suc)
|
// 拿到指令字段(如jm2k)和执行状态(suc)
|
||||||
const commandField = Object.keys(ackData.prop)[0]; // 这里是"jm2k"
|
const commandField = Object.keys(ackData.prop)[0]; // 这里是"jm2k"
|
||||||
const commandValue = ackData.prop[commandField]; // 这里是0
|
const commandValue = ackData.prop[commandField]; // 这里是0/1
|
||||||
const isSuccess = ackData.suc; // 这里是true
|
const isSuccess = ackData.suc; // 这里是true
|
||||||
|
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
this.status[type] = this.status[type] === 0 ? 1 : 0;
|
// 优化:使用$set确保响应式更新
|
||||||
this.show[type] = this.status[type] === 0 ? "暂停" : "运行";
|
this.$set(this.status, type, this.status[type] === 0 ? 1 : 0);
|
||||||
|
this.$set(this.show, type, this.status[type] === 0 ? "暂停" : "运行");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.deviceType = '';
|
this.deviceType = '';
|
||||||
this.$modal.msgSuccess("设备操作成功!")
|
// ========== 修改:自动停止指令不弹窗 ==========
|
||||||
|
this.$modal.msgSuccess("设备操作成功!");
|
||||||
|
|
||||||
console.log(`指令[${commandField}=${commandValue}]执行${isSuccess ? "成功" : "失败"}`);
|
console.log(`指令[${commandField}=${commandValue}]执行${isSuccess ? "成功" : "失败"}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 处理其他内容的函数(完全保留)
|
|
||||||
handleOtherContent(msgData,payload) {
|
handleOtherContent(msgData,payload) {
|
||||||
// 业务逻辑:处理传感器数据、设备状态等
|
// 业务逻辑:处理传感器数据、设备状态等
|
||||||
// console.log("收到其他内容:", msgData);
|
|
||||||
// 例如:更新温湿度显示、设备在线状态等
|
|
||||||
|
|
||||||
// 设备状态展示
|
// 设备状态展示
|
||||||
if (this.value !== 1) {
|
if (this.value !== 1) {
|
||||||
var arr = ['jbk', "jbg", "jm1k", "jm1g", "jm2k", "jm2g", "jm3k", "jm3g"]
|
var arr = ['jbk', "jbg", "jm1k", "jm1g", "jm2k", "jm2g", "jm3k", "jm3g"]
|
||||||
|
|
@ -484,20 +548,10 @@ export default {
|
||||||
}
|
}
|
||||||
const allKeysNumeric2 = Object.keys(msgData).every(key => /^\d+$/.test(key));
|
const allKeysNumeric2 = Object.keys(msgData).every(key => /^\d+$/.test(key));
|
||||||
if (Object.keys(msgData).length > 0 && allKeysNumeric2) {
|
if (Object.keys(msgData).length > 0 && allKeysNumeric2) {
|
||||||
const div10 = (v) => (v == null ? null : Math.round((Number(v)/10)*10)/10)
|
|
||||||
|
|
||||||
this.liveData = {
|
|
||||||
temp1: div10(msgData["201"]) || "已离线...",
|
|
||||||
humi1: div10(msgData["101"]) || "已离线...",
|
|
||||||
temp2: div10(msgData["202"]) || "已离线...",
|
|
||||||
humi2: div10(msgData["102"]) || "已离线...",
|
|
||||||
temp3: div10(msgData["203"]) || "已离线...",
|
|
||||||
humi3: div10(msgData["103"]) || "已离线...",
|
|
||||||
temp4: div10(msgData["204"]) || "已离线...",
|
|
||||||
humi4: div10(msgData["104"]) || "已离线...",
|
|
||||||
}
|
|
||||||
this.temp = "最后更新时间:" + this.getCurrentTime();
|
this.temp = "最后更新时间:" + this.getCurrentTime();
|
||||||
this.fontStyle = 'font-size:16px;'
|
this.fontStyle = 'font-size:16px;'
|
||||||
|
|
||||||
|
this.makeSpecialData(msgData, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -526,19 +580,72 @@ export default {
|
||||||
testNumber(data) {
|
testNumber(data) {
|
||||||
const reg = /^-?\d+(\.\d+)?$/;
|
const reg = /^-?\d+(\.\d+)?$/;
|
||||||
return reg.test(String(data).trim());
|
return reg.test(String(data).trim());
|
||||||
|
},
|
||||||
|
|
||||||
|
// 优化:封装温湿度单位判断函数
|
||||||
|
isEffectiveValue(value) {
|
||||||
|
return this.testNumber(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增:打开修改运行时间的弹窗
|
||||||
|
openTimeModal(card) {
|
||||||
|
this.currentCard = card; // 记录当前卡片信息
|
||||||
|
this.currentCardTime = this.limitTimes[`${card.type}Limit`]; // 记录当前时间
|
||||||
|
this.newLimitTime = this.currentCardTime; // 默认填充当前时间
|
||||||
|
this.$refs.inputDialog.open()
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.$refs.inputDialog.close()
|
||||||
|
},
|
||||||
|
// 新增:确认修改运行时间
|
||||||
|
confirmModifyTime() {
|
||||||
|
// 校验输入:必须是1-60的数字
|
||||||
|
/*if (!this.newLimitTime || this.newLimitTime < 1 || this.newLimitTime > 60) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入1-60的有效数字',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
// 修改limitTimes(用$set确保响应式)
|
||||||
|
if (this.newLimitTime !== this.currentCardTime) {
|
||||||
|
// 提示修改成功
|
||||||
|
uni.showModal({
|
||||||
|
title: '温馨提示:',
|
||||||
|
content: `确定修改${this.selectedText}-${this.currentCard.name}运行时间为:${this.newLimitTime} 秒?`,
|
||||||
|
cancelText: '取消',
|
||||||
|
confirmText: '确定',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
this.$set(this.limitTimes, `${this.currentCard.type}Limit`, this.newLimitTime);
|
||||||
|
if (this.limitTimes.imei) {
|
||||||
|
updateLimit(this.limitTimes).then(response => {
|
||||||
|
response.code === 200 ? this.$modal.msgSuccess("修改成功"):this.$modal.msgSuccess("修改失败")
|
||||||
|
})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$set(this.limitTimes, 'imei', this.imei);
|
||||||
|
this.$set(this.limitTimes, 'agriName', this.selectedText);
|
||||||
|
this.$set(this.limitTimes, 'agriId', this.agriId);
|
||||||
|
addLimit(this.limitTimes).then(response => {
|
||||||
|
response.code === 200 ? this.$modal.msgSuccess("修改成功"):this.$modal.msgSuccess("修改失败")
|
||||||
|
this.getAgriByImei();
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 关闭弹窗
|
||||||
|
this.$refs.inputDialog.close()
|
||||||
|
// (可选)这里可以加接口请求,把新时间同步到后端
|
||||||
|
// this.saveLimitTimeToServer(this.currentCard.type, this.newLimitTime);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onHide() {
|
onHide() {
|
||||||
// ========== 修改:移除页面隐藏时的断开逻辑(全局App.vue已处理) ==========
|
|
||||||
// this.disconnectMqtt();
|
|
||||||
// 仅移除回调,避免后台接收消息导致异常
|
|
||||||
mqttUtil.removeOnMessageCallback();
|
mqttUtil.removeOnMessageCallback();
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
// ========== 修改:移除原有client断开逻辑(全局工具类已处理) ==========
|
|
||||||
// if (this.client) {
|
|
||||||
// this.client.end()
|
|
||||||
// }
|
|
||||||
mqttUtil.removeOnMessageCallback();
|
mqttUtil.removeOnMessageCallback();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -634,7 +741,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.uni-pb-5 {
|
.uni-pb-5 {
|
||||||
padding-bottom: 40rpx;
|
padding-bottom: 15rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
|
@ -681,4 +788,70 @@ export default {
|
||||||
/deep/ .uni-section-header__slot-right {
|
/deep/ .uni-section-header__slot-right {
|
||||||
color: green;
|
color: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 新增:弹窗样式 */
|
||||||
|
.modal-container {
|
||||||
|
width: 600rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
padding: 30rpx 20rpx;
|
||||||
|
}
|
||||||
|
.modal-title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.modal-input-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 25rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
.modal-label {
|
||||||
|
width: 160rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.modal-current {
|
||||||
|
margin-left: 14rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.modal-input {
|
||||||
|
height: 60rpx;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 0 15rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
width: 80rpx;
|
||||||
|
}
|
||||||
|
.modal-unit {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.modal-btn-wrap {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
margin-top: 40rpx;
|
||||||
|
}
|
||||||
|
.modal-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 70rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
.modal-btn.cancel {
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.modal-btn.confirm {
|
||||||
|
background: #007aff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
margin-left: 15rpx
|
||||||
|
}
|
||||||
|
.uni-stat-tooltip {
|
||||||
|
width: 300rpx;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -10,9 +10,19 @@
|
||||||
<view class="iconfont icon-user icon"></view>
|
<view class="iconfont icon-user icon"></view>
|
||||||
<input v-model="loginForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" />
|
<input v-model="loginForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" />
|
||||||
</view>
|
</view>
|
||||||
<view class="input-item flex align-center">
|
<view class="input-item flex align-center" style="position: relative;">
|
||||||
<view class="iconfont icon-password icon"></view>
|
<view class="iconfont icon-password icon"></view>
|
||||||
<input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" />
|
<input v-if="!isShowPwd"
|
||||||
|
v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" />
|
||||||
|
<input v-else v-model="loginForm.password" type="text" class="input" placeholder="请输入密码" maxlength="20" />
|
||||||
|
<!-- 替换为 uni-icons 密码图标 -->
|
||||||
|
<uni-icons
|
||||||
|
class="pwd-icon"
|
||||||
|
:type="isShowPwd ? 'eye-filled' : 'eye'"
|
||||||
|
size="18"
|
||||||
|
color="#666"
|
||||||
|
@click="isShowPwd = !isShowPwd"
|
||||||
|
></uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled">
|
<view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled">
|
||||||
<view class="iconfont icon-code icon"></view>
|
<view class="iconfont icon-code icon"></view>
|
||||||
|
|
@ -41,10 +51,14 @@
|
||||||
<script>
|
<script>
|
||||||
import { getCodeImg } from '@/api/login'
|
import { getCodeImg } from '@/api/login'
|
||||||
import { getToken } from '@/utils/auth'
|
import { getToken } from '@/utils/auth'
|
||||||
|
import UniIcons from "../uni_modules/uni-icons/components/uni-icons/uni-icons.vue";
|
||||||
|
import store from "../store";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {UniIcons},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
isShowPwd: false,
|
||||||
codeUrl: "",
|
codeUrl: "",
|
||||||
captchaEnabled: true,
|
captchaEnabled: true,
|
||||||
// 用户注册开关
|
// 用户注册开关
|
||||||
|
|
@ -131,7 +145,11 @@
|
||||||
// 864865085016294 十方北棚
|
// 864865085016294 十方北棚
|
||||||
// 864536071808560 七方北棚
|
// 864536071808560 七方北棚
|
||||||
// 864865085008135 八方北棚
|
// 864865085008135 八方北棚
|
||||||
const subscribeList = [`dtu/864865085016294/up`, `dtu/864536071808560/up`,`dtu/864865085008135/up`]
|
const subscribeList = [`dtu/864865085016294/up`, `dtu/864536071808560/up`,`dtu/864865085008135/up`,`dtu/862538065276939/up`]
|
||||||
|
|
||||||
|
if (store.getters && store.getters.name === 'admin') {
|
||||||
|
subscribeList.push(`dtu/862538065276061/up`);
|
||||||
|
}
|
||||||
// 4. 调用App.vue的loginSuccess方法,初始化MQTT
|
// 4. 调用App.vue的loginSuccess方法,初始化MQTT
|
||||||
app.loginSuccess(token, subscribeList)
|
app.loginSuccess(token, subscribeList)
|
||||||
|
|
||||||
|
|
@ -147,7 +165,13 @@
|
||||||
page {
|
page {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
|
.pwd-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.normal-login-container {
|
.normal-login-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
|
@ -184,14 +208,19 @@
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input,
|
||||||
width: 100%;
|
.input:focus,
|
||||||
|
.input:active,
|
||||||
|
.input:hover {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
background-color: #f5f6f7; /* 输入框背景色(和页面背景区分) */
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
|
border: none;
|
||||||
|
outline: none !important;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-btn {
|
.login-btn {
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,19 @@
|
||||||
<view>编辑资料</view>
|
<view>编辑资料</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="list-cell list-cell-arrow" @click="handleMqtt" v-if="name === 'admin'">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<view class="iconfont icon-service menu-icon"></view>
|
||||||
|
<view>mqtt工具</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="list-cell list-cell-arrow" @click="handleRequire" v-if="name === 'admin'">
|
||||||
|
<view class="menu-item-box">
|
||||||
|
<uni-icons type="wallet" size="19" color="#007AFF"></uni-icons>
|
||||||
|
<view style="margin-left: 4rpx"> 需求清单</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view class="list-cell list-cell-arrow" @click="handleHelp">
|
<view class="list-cell list-cell-arrow" @click="handleHelp">
|
||||||
<view class="menu-item-box">
|
<view class="menu-item-box">
|
||||||
<view class="iconfont icon-help menu-icon"></view>
|
<view class="iconfont icon-help menu-icon"></view>
|
||||||
|
|
@ -77,7 +90,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import UniIcons from "../../uni_modules/uni-icons/components/uni-icons/uni-icons.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {UniIcons},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
name: this.$store.state.user.name
|
name: this.$store.state.user.name
|
||||||
|
|
@ -91,6 +107,7 @@
|
||||||
return uni.getSystemInfoSync().windowHeight - 50
|
return uni.getSystemInfoSync().windowHeight - 50
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
handleToInfo() {
|
handleToInfo() {
|
||||||
this.$tab.navigateTo('/pages/mine/info/index')
|
this.$tab.navigateTo('/pages/mine/info/index')
|
||||||
|
|
@ -110,6 +127,12 @@
|
||||||
handleHelp() {
|
handleHelp() {
|
||||||
this.$tab.navigateTo('/pages/mine/help/index')
|
this.$tab.navigateTo('/pages/mine/help/index')
|
||||||
},
|
},
|
||||||
|
handleMqtt() {
|
||||||
|
this.$tab.navigateTo('/pages/mine/mqtt/index')
|
||||||
|
},
|
||||||
|
handleRequire() {
|
||||||
|
this.$tab.navigateTo('/pages/mine/require/index')
|
||||||
|
},
|
||||||
handleAbout() {
|
handleAbout() {
|
||||||
this.$tab.navigateTo('/pages/mine/about/index')
|
this.$tab.navigateTo('/pages/mine/about/index')
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -231,14 +231,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import mqtt from 'mqtt/dist/mqtt.min'
|
import mqtt from 'mqtt/dist/mqtt'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// MQTT配置
|
// MQTT配置
|
||||||
mqttConfig: {
|
mqttConfig: {
|
||||||
broker: 'ws://122.51.109.52:9001/mqtt', // 公共测试服务器
|
broker: 'wxs://mq.xiaoces.com:443/mqtt', // 公共测试服务器
|
||||||
clientId: 'uniapp_mqtt_' + Math.random().toString(16).substr(2, 8),
|
clientId: 'uniapp_mqtt_' + Math.random().toString(16).substr(2, 8),
|
||||||
username: 'admin',
|
username: 'admin',
|
||||||
password: 'Admin#12345678',
|
password: 'Admin#12345678',
|
||||||
|
|
@ -0,0 +1,641 @@
|
||||||
|
<template>
|
||||||
|
<view class="container">
|
||||||
|
<view class="form-container">
|
||||||
|
<uni-section title="基础卡片" type="line">
|
||||||
|
<!-- 基础表单校验:缩小字体+一行两列布局 -->
|
||||||
|
<uni-forms
|
||||||
|
ref="valiForm"
|
||||||
|
label-position="left"
|
||||||
|
:modelValue="form"
|
||||||
|
style="font-size: 10px;"
|
||||||
|
>
|
||||||
|
<!-- 一行两列布局容器 -->
|
||||||
|
<view class="form-row">
|
||||||
|
<uni-forms-item label="标题:" name="title" class="form-item">
|
||||||
|
<uni-easyinput
|
||||||
|
v-model="form.title"
|
||||||
|
placeholder="请输入标题搜索"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="详情:" name="detail" class="form-item">
|
||||||
|
<uni-easyinput
|
||||||
|
v-model="form.detail"
|
||||||
|
placeholder="请输入详情搜索"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 第二行两列 -->
|
||||||
|
<view class="form-row">
|
||||||
|
<uni-forms-item label="优先级:" name="priority" class="form-item">
|
||||||
|
<uni-data-select
|
||||||
|
v-model="form.priority"
|
||||||
|
:localdata="priorityList"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
<uni-forms-item label="进度:" name="progress" class="form-item">
|
||||||
|
<uni-data-select
|
||||||
|
v-model="form.progress"
|
||||||
|
:localdata="progressList"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
</view>
|
||||||
|
</uni-forms>
|
||||||
|
|
||||||
|
<view class="btn-group">
|
||||||
|
<view class="btn-left">
|
||||||
|
<!-- 新增按钮:点击打开弹窗 -->
|
||||||
|
<button
|
||||||
|
class="iconfont icon-add mini-btn add-btn"
|
||||||
|
@click="openDialog('add')"
|
||||||
|
hover-class="is-hover"
|
||||||
|
type="default"
|
||||||
|
size="mini"
|
||||||
|
> 新增</button>
|
||||||
|
|
||||||
|
<!-- 删除按钮:未选中数据时禁用 -->
|
||||||
|
<button
|
||||||
|
class="iconfont icon-ashbin mini-btn del-btn"
|
||||||
|
hover-class="is-hover"
|
||||||
|
type="default"
|
||||||
|
size="mini"
|
||||||
|
:disabled="selectedIndexs.length === 0"
|
||||||
|
@click="batchDel"
|
||||||
|
> 删除</button>
|
||||||
|
<!-- 编辑按钮:未选中数据时禁用 -->
|
||||||
|
<button
|
||||||
|
class="iconfont icon-edit mini-btn edit-btn"
|
||||||
|
hover-class="is-hover"
|
||||||
|
type="default"
|
||||||
|
size="mini"
|
||||||
|
:disabled="selectedIndexs.length === 0"
|
||||||
|
@click="openDialog('edit')"
|
||||||
|
> 编辑</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="btn-right">
|
||||||
|
<button
|
||||||
|
class="iconfont icon-search mini-btn"
|
||||||
|
hover-class="is-hover"
|
||||||
|
type="default"
|
||||||
|
size="mini"
|
||||||
|
@click="search"
|
||||||
|
> 查询</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</uni-section>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="uni-container">
|
||||||
|
<!-- 表格区域:保持原有紧凑样式并优化 -->
|
||||||
|
<uni-table
|
||||||
|
ref="table"
|
||||||
|
:loading="loading"
|
||||||
|
border
|
||||||
|
stripe
|
||||||
|
type="selection"
|
||||||
|
emptyText="暂无更多数据"
|
||||||
|
@selection-change="selectionChange"
|
||||||
|
style="width: 100%;"
|
||||||
|
:border-width="1"
|
||||||
|
>
|
||||||
|
<uni-tr>
|
||||||
|
<uni-th align="center" class="ui-th" sortable width="200rpx" @sort-change="idSort">需求单号</uni-th>
|
||||||
|
<uni-th align="center" width="300rpx" class="ui-th">需求标题</uni-th>
|
||||||
|
<uni-th align="center" width="240rpx" class="ui-th">需求详情</uni-th>
|
||||||
|
<uni-th align="center" width="140rpx" @sort-change="prioritySort" sortable class="ui-th">优先级</uni-th>
|
||||||
|
<uni-th align="center" width="140rpx" class="ui-th">进度</uni-th>
|
||||||
|
<uni-th align="center" width="200rpx" class="ui-th">需求类型</uni-th>
|
||||||
|
<uni-th align="center" width="200rpx" class="ui-th">经办人名称</uni-th>
|
||||||
|
<uni-th align="center" width="300rpx" class="ui-th">操作</uni-th>
|
||||||
|
</uni-tr>
|
||||||
|
<uni-tr v-for="(item, index) in tableData" :key="index" style="height: 30px; line-height: 30px;">
|
||||||
|
|
||||||
|
<uni-td style="padding: 1px 0; font-size: 13px;">{{ item.id }}</uni-td>
|
||||||
|
<uni-td style="padding: 1px 0; font-size: 13px;">{{ item.title }}</uni-td>
|
||||||
|
<uni-td style="padding: 1px 0; font-size: 13px;">
|
||||||
|
<view class="name">{{ item.detail }}</view>
|
||||||
|
</uni-td>
|
||||||
|
<uni-td align="center" style=" padding: 1px 0; font-size: 13px;">{{ item.priority }}</uni-td>
|
||||||
|
<uni-td align="center" style=" padding: 1px 0; font-size: 13px;">{{ item.progress }}</uni-td>
|
||||||
|
<uni-td align="center" style=" padding: 1px 0; font-size: 13px;">{{ item.reqType }}</uni-td>
|
||||||
|
<uni-td align="center" style=" padding: 1px 0; font-size: 13px;">{{ item.assigneeName }}</uni-td>
|
||||||
|
<uni-td style="width: auto; padding: 1px 0; font-size: 13px;">
|
||||||
|
<view class="uni-group">
|
||||||
|
<!-- 行内修改按钮:点击打开编辑弹窗 -->
|
||||||
|
<button size="mini" type="primary" style="padding: 1px 6px; font-size: 10px;" @click="openDialog('edit', item)">修改</button>
|
||||||
|
<!-- 行内删除按钮:点击单行删除 -->
|
||||||
|
<button size="mini" type="warn" style="padding: 1px 6px; font-size: 10px;" @click="delSingle(item)">删除</button>
|
||||||
|
</view>
|
||||||
|
</uni-td>
|
||||||
|
</uni-tr>
|
||||||
|
</uni-table>
|
||||||
|
<view class="uni-pagination-box" style="margin-top: 8px;">
|
||||||
|
<uni-pagination
|
||||||
|
show-icon
|
||||||
|
:page-size="form.pageSize"
|
||||||
|
:current="form.pageNum"
|
||||||
|
:total="total"
|
||||||
|
@change="change"
|
||||||
|
style="font-size: 11px;"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 新增/修改弹窗 -->
|
||||||
|
<uni-popup ref="formDialog" type="center" :mask-click="false">
|
||||||
|
<view class="dialog-container">
|
||||||
|
<view class="dialog-title">{{ dialogType === 'add' ? '新增需求' : '编辑需求' }}</view>
|
||||||
|
<!-- 弹窗表单 -->
|
||||||
|
<uni-forms
|
||||||
|
ref="dialogForm"
|
||||||
|
label-width="65px"
|
||||||
|
label-position="left"
|
||||||
|
:modelValue="dialogFormData"
|
||||||
|
:rules="formRules"
|
||||||
|
style="padding: 10rpx;"
|
||||||
|
>
|
||||||
|
<!-- 需求标题(必填) -->
|
||||||
|
<uni-forms-item label="需求标题:" name="title" required>
|
||||||
|
<uni-easyinput
|
||||||
|
v-model="dialogFormData.title"
|
||||||
|
placeholder="请输入需求标题"
|
||||||
|
style="font-size: 12px;"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
<!-- 详情(必填) -->
|
||||||
|
<uni-forms-item label="详情:" name="detail" required>
|
||||||
|
<uni-easyinput
|
||||||
|
v-model="dialogFormData.detail"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请输入需求详情"
|
||||||
|
style="font-size: 12px; height: 100px;"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
<!-- 优先级(下拉框,默认高) -->
|
||||||
|
<uni-forms-item label="优先级:" name="priority">
|
||||||
|
<uni-data-select
|
||||||
|
v-model="dialogFormData.priority"
|
||||||
|
:localdata="priorityList"
|
||||||
|
style="font-size: 12px;"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
<!-- 进度(下拉框) -->
|
||||||
|
<uni-forms-item label="进度:" name="progress">
|
||||||
|
<uni-data-select
|
||||||
|
v-model="dialogFormData.progress"
|
||||||
|
:localdata="progressList"
|
||||||
|
style="font-size: 12px;"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
<!-- 需求类型(下拉框) -->
|
||||||
|
<uni-forms-item label="需求类型:" name="reqType">
|
||||||
|
<uni-data-select
|
||||||
|
v-model="dialogFormData.reqType"
|
||||||
|
:localdata="reqTypeList"
|
||||||
|
style="font-size: 12px;"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
<!-- 经办人(可选输入框) -->
|
||||||
|
<uni-forms-item label="经办人:" name="assigneeName">
|
||||||
|
<uni-easyinput
|
||||||
|
v-model="dialogFormData.assigneeName"
|
||||||
|
placeholder="请输入经办人名称"
|
||||||
|
style="font-size: 12px;"
|
||||||
|
/>
|
||||||
|
</uni-forms-item>
|
||||||
|
</uni-forms>
|
||||||
|
<!-- 弹窗按钮 -->
|
||||||
|
<view class="dialog-btn-group">
|
||||||
|
<button class="cancel-btn" @click="closeDialog">取消</button>
|
||||||
|
<button class="confirm-btn" @click="submitDialog">确定</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</uni-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import UniTh from "../../../uni_modules/uni-table/components/uni-th/uni-th.vue";
|
||||||
|
import UniTr from "../../../uni_modules/uni-table/components/uni-tr/uni-tr.vue";
|
||||||
|
import UniTd from "../../../uni_modules/uni-table/components/uni-td/uni-td.vue";
|
||||||
|
import {addRequire, delRequire, delRequires, listRequire, updateRequire} from "../../../api/system/require";
|
||||||
|
import UniTable from "../../../uni_modules/uni-table/components/uni-table/uni-table.vue";
|
||||||
|
import UniPopup from "../../../uni_modules/uni-popup/components/uni-popup/uni-popup.vue";
|
||||||
|
import UniForms from "../../../uni_modules/uni-forms/components/uni-forms/uni-forms.vue";
|
||||||
|
import UniFormsItem from "../../../uni_modules/uni-forms/components/uni-forms-item/uni-forms-item.vue";
|
||||||
|
import UniEasyinput from "../../../uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue";
|
||||||
|
import UniDataSelect from "../../../uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
UniTable, UniTd, UniTr, UniTh,
|
||||||
|
UniPopup, UniForms, UniFormsItem, UniEasyinput, UniDataSelect
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
searchVal: '',
|
||||||
|
tableData: [],
|
||||||
|
total: 0,
|
||||||
|
// 优先级下拉选项
|
||||||
|
priorityList: [
|
||||||
|
{ value: 0, text: '高' },
|
||||||
|
{ value: 1, text: '中' },
|
||||||
|
{ value: 2, text: '低' }
|
||||||
|
],
|
||||||
|
// 进度下拉选项
|
||||||
|
progressList: [
|
||||||
|
{ value: 0, text: '未完成' },
|
||||||
|
{ value: 1, text: '进行中' },
|
||||||
|
{ value: 2, text: '已完成' }
|
||||||
|
],
|
||||||
|
// 需求类型下拉选项(可根据实际需求补充)
|
||||||
|
reqTypeList: [
|
||||||
|
{ value: 0, text: '功能需求' },
|
||||||
|
{ value: 1, text: '优化需求' },
|
||||||
|
{ value: 2, text: 'BUG修复' }
|
||||||
|
],
|
||||||
|
form: {
|
||||||
|
title: null,
|
||||||
|
detail: null,
|
||||||
|
priority: null,
|
||||||
|
progress: null,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10
|
||||||
|
},
|
||||||
|
loading: false,
|
||||||
|
selectIds:[],
|
||||||
|
selectedIndexs: [], // 已选择的行索引
|
||||||
|
// 弹窗相关
|
||||||
|
dialogType: 'add', // add-新增 edit-编辑
|
||||||
|
dialogFormData: {
|
||||||
|
title: '',
|
||||||
|
detail: '',
|
||||||
|
priority: 0, // 默认高
|
||||||
|
progress: 0,
|
||||||
|
reqType: '',
|
||||||
|
assigneeName: ''
|
||||||
|
},
|
||||||
|
// 表单校验规则
|
||||||
|
formRules: {
|
||||||
|
title: {
|
||||||
|
rules: [{ required: true, errorMessage: '请输入需求标题' }]
|
||||||
|
},
|
||||||
|
detail: {
|
||||||
|
rules: [{ required: true, errorMessage: '请输入需求详情' }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
currentEditItem: null // 当前编辑的行数据
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.getData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 多选处理
|
||||||
|
selectedItems() {
|
||||||
|
this.selectIds = this.selectedIndexs.map(i => this.tableData[i].id);
|
||||||
|
return this.selectedIndexs.map(i => this.tableData[i])
|
||||||
|
},
|
||||||
|
// 补充selection-change事件
|
||||||
|
selectionChange(e) {
|
||||||
|
this.selectedIndexs = e.detail.index
|
||||||
|
console.info(e)
|
||||||
|
},
|
||||||
|
idSort(e) {
|
||||||
|
if (e["order"] === 'descending') {
|
||||||
|
this.tableData.sort((a, b) => b.id - a.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.tableData.sort((a, b) => a.id - b.id);
|
||||||
|
},
|
||||||
|
prioritySort(e) {
|
||||||
|
if (e.order === 'descending') {
|
||||||
|
this.tableData.sort((a, b) => b.priority - a.priority);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.tableData.sort((a, b) => a.priority - b.priority);
|
||||||
|
},
|
||||||
|
// ========== 删除相关方法 ==========
|
||||||
|
// 批量删除
|
||||||
|
batchDel() {
|
||||||
|
const data = this.tableData.filter(item => !this.selectIds.includes(item.id));
|
||||||
|
console.info(`${this.selectIds}选中的数据:${JSON.stringify(data)} `)
|
||||||
|
// todo 多选删除 有bug 第二次删除之前第一次删除还在的索引还在
|
||||||
|
const selectedItems = this.selectedItems()
|
||||||
|
if (selectedItems.length === 0) {
|
||||||
|
uni.showToast({ title: '请选择要删除的数据', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const selectedIds = selectedItems.map(item => Number(item.id))
|
||||||
|
.filter(id => id !== undefined && id !== null && id !== '');
|
||||||
|
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: `确定要删除选中的${selectedItems.length}条数据吗?`,
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
delRequires(selectedIds).then((response) => {
|
||||||
|
if (response.code === 200) {
|
||||||
|
uni.showToast({ title: '批量删除成功', icon: 'success' })
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: '批量删除失败', icon: 'error' })
|
||||||
|
}
|
||||||
|
this.getData()
|
||||||
|
this.selectedIndexs=[]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 分页触发
|
||||||
|
change(e) {
|
||||||
|
this.selectedIndexs = []
|
||||||
|
this.getData(e.current)
|
||||||
|
},
|
||||||
|
// 搜索
|
||||||
|
search() {
|
||||||
|
this.getData()
|
||||||
|
},
|
||||||
|
// 获取数据
|
||||||
|
getData(pageNum) {
|
||||||
|
this.loading = true
|
||||||
|
this.form.pageNum = pageNum || this.form.pageNum
|
||||||
|
listRequire(this.form).then(response => {
|
||||||
|
if (response.code === 200 && response.rows) {
|
||||||
|
this.tableData = response.rows
|
||||||
|
this.total = response.total
|
||||||
|
}
|
||||||
|
this.loading = false
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('获取数据失败:', error)
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// ========== 弹窗相关方法 ==========
|
||||||
|
// 打开弹窗
|
||||||
|
openDialog(type, item = null) {
|
||||||
|
this.dialogType = type
|
||||||
|
// 重置表单
|
||||||
|
this.dialogFormData = {
|
||||||
|
title: '',
|
||||||
|
detail: '',
|
||||||
|
priority: 0,
|
||||||
|
progress: 0,
|
||||||
|
reqType: '',
|
||||||
|
assigneeName: ''
|
||||||
|
}
|
||||||
|
// 编辑模式:回显数据
|
||||||
|
if (type === 'edit') {
|
||||||
|
// 批量编辑取第一个选中项,行内编辑取传入的item
|
||||||
|
const editItem = item || this.selectedItems()[0]
|
||||||
|
if (editItem) {
|
||||||
|
this.currentEditItem = editItem
|
||||||
|
this.dialogFormData = { ...editItem }
|
||||||
|
} else {
|
||||||
|
uni.showToast({ title: '请选择要编辑的数据', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 打开弹窗
|
||||||
|
this.$refs.formDialog.open()
|
||||||
|
},
|
||||||
|
// 关闭弹窗
|
||||||
|
closeDialog() {
|
||||||
|
this.$refs.formDialog.close()
|
||||||
|
// 重置表单校验
|
||||||
|
this.$refs.dialogForm.clearValidate()
|
||||||
|
},
|
||||||
|
// 提交弹窗表单
|
||||||
|
submitDialog() {
|
||||||
|
// 表单校验
|
||||||
|
this.$refs.dialogForm.validate().then(() => {
|
||||||
|
if (this.dialogType === 'add') {
|
||||||
|
addRequire(this.dialogFormData).then(response => {
|
||||||
|
if (response.code===200) {
|
||||||
|
this.$modal.msgSuccess("新增成功")
|
||||||
|
} else {
|
||||||
|
this.$modal.msgError("新增失败")
|
||||||
|
}
|
||||||
|
this.getData()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
updateRequire(this.dialogFormData).then(response => {
|
||||||
|
if (response.code===200) {
|
||||||
|
this.$modal.msgSuccess("修改成功")
|
||||||
|
} else {
|
||||||
|
this.$modal.msgError("修改失败")
|
||||||
|
}
|
||||||
|
this.getData()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 关闭弹窗并刷新数据
|
||||||
|
this.closeDialog()
|
||||||
|
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('表单校验失败:', err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// 单行删除
|
||||||
|
delSingle(item) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '确定要删除这条数据吗?',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
delRequire(item.id).then(response => {
|
||||||
|
if (response.code === 200) {
|
||||||
|
uni.showToast({title: '删除成功', icon: 'success'})
|
||||||
|
} else {
|
||||||
|
uni.showToast({title: '删除失败', icon: 'success'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.getData()
|
||||||
|
this.selectedIndexs=[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 页面基础样式重置 */
|
||||||
|
page {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 整体容器样式 */
|
||||||
|
.container {
|
||||||
|
margin: 20rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
background: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
margin: 20rpx 0 0 0;
|
||||||
|
padding: 15rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单一行两列布局核心样式 - 优化版 */
|
||||||
|
.form-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 0 10rpx 10rpx 10rpx;
|
||||||
|
width: 100%;
|
||||||
|
/* 新增:清除flex布局默认的基线对齐,避免垂直错位 */
|
||||||
|
align-items: flex-start;
|
||||||
|
/* 新增:计算宽度时包含内边距/边框,避免溢出 */
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 48%; /* 保留你的48%宽度,留2%间距 */
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0 !important; /* 保留清除默认间距 */
|
||||||
|
/* 新增适配uni-forms-item的关键样式 */
|
||||||
|
padding: 0; /* 清除组件默认内边距 */
|
||||||
|
min-height: auto; /* 取消组件默认最小高度,避免高度不一致 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 新增:适配uni-data-select组件,防止下拉框溢出 */
|
||||||
|
.form-item .uni-data-select {
|
||||||
|
width: 100%; /* 下拉选择器占满form-item宽度 */
|
||||||
|
flex: 1; /* 让选择器自适应剩余空间 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 新增:统一label标签样式,避免文字错位 */
|
||||||
|
.form-item .uni-forms-item__label {
|
||||||
|
/* 根据你的需求调整label宽度,比如固定120rpx */
|
||||||
|
flex: 0 0 120rpx;
|
||||||
|
padding: 0; /* 清除默认内边距 */
|
||||||
|
margin-right: 10rpx; /* label和选择器之间留间距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 新增:统一表单项内容区域样式 */
|
||||||
|
.form-item .uni-forms-item__content {
|
||||||
|
flex: 1; /* 内容区域占满剩余宽度 */
|
||||||
|
padding: 0; /* 清除默认内边距 */
|
||||||
|
}
|
||||||
|
/* 核心:父容器flex布局,通过justify-content: space-between实现左右分布 */
|
||||||
|
.btn-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between; /* 关键:左右元素分别靠两端 */
|
||||||
|
align-items: center; /* 垂直居中,保证按钮对齐 */
|
||||||
|
width: 100%; /* 占满父容器宽度,确保分布效果 */
|
||||||
|
padding: 20rpx 10rpx 0; /* 左右留间距,避免贴边 */
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 左侧按钮容器:横向排列,靠左 */
|
||||||
|
.btn-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 右侧按钮容器:横向排列,靠右 */
|
||||||
|
.btn-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表格容器样式 */
|
||||||
|
.uni-container {
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uni-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 需求详情文字样式 */
|
||||||
|
.name {
|
||||||
|
line-height: 18px;
|
||||||
|
font-size: 11px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页区域样式 */
|
||||||
|
.uni-pagination-box {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .uni-forms-item__label {
|
||||||
|
font-size: 12px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
/deep/ .uni-select, /deep/.uni-easyinput__content-input {
|
||||||
|
font-size: 12px !important;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 弹窗样式 */
|
||||||
|
.dialog-container {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
padding: 20rpx;
|
||||||
|
width: 600rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10rpx 0;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-btn-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
gap: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 禁用按钮样式 */
|
||||||
|
/deep/ button[disabled] {
|
||||||
|
background-color: #e5e5e5 !important;
|
||||||
|
color: #999 !important;
|
||||||
|
border-color: #ddd !important;
|
||||||
|
}
|
||||||
|
/deep/ .uni-forms-item {
|
||||||
|
margin-bottom: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/deep/ .uni-table-td {
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
.ui-th {
|
||||||
|
width: auto;
|
||||||
|
height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.ui-th:last-child {
|
||||||
|
width: 160rpx;
|
||||||
|
}
|
||||||
|
/deep/ .uni-table-th {
|
||||||
|
padding: 16rpx 5rpx;
|
||||||
|
}
|
||||||
|
.uni-group button:last-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -143,7 +143,7 @@
|
||||||
.uni-margin-wrap {
|
.uni-margin-wrap {
|
||||||
width: 690rpx;
|
width: 690rpx;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.swiper {
|
.swiper {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,539 @@
|
||||||
|
/* Logo 字体 */
|
||||||
|
@font-face {
|
||||||
|
font-family: "iconfont logo";
|
||||||
|
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
|
||||||
|
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
|
||||||
|
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
|
||||||
|
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
|
||||||
|
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
font-family: "iconfont logo";
|
||||||
|
font-size: 160px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tabs */
|
||||||
|
.nav-tabs {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tabs .nav-more {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 42px;
|
||||||
|
line-height: 42px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabs {
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabs li {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#tabs .active {
|
||||||
|
border-bottom-color: #f00;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-container .content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 页面布局 */
|
||||||
|
.main {
|
||||||
|
padding: 30px 100px;
|
||||||
|
width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .logo {
|
||||||
|
color: #333;
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 1;
|
||||||
|
height: 110px;
|
||||||
|
margin-top: -50px;
|
||||||
|
overflow: hidden;
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .logo a {
|
||||||
|
font-size: 160px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helps {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.helps pre {
|
||||||
|
padding: 20px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border: solid 1px #e7e1cd;
|
||||||
|
background-color: #fffdef;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists {
|
||||||
|
width: 100% !important;
|
||||||
|
overflow: hidden;
|
||||||
|
*zoom: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists li {
|
||||||
|
width: 100px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-right: 20px;
|
||||||
|
text-align: center;
|
||||||
|
list-style: none !important;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists li .code-name {
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists .icon {
|
||||||
|
display: block;
|
||||||
|
height: 100px;
|
||||||
|
line-height: 100px;
|
||||||
|
font-size: 42px;
|
||||||
|
margin: 10px auto;
|
||||||
|
color: #333;
|
||||||
|
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
|
||||||
|
-moz-transition: font-size 0.25s linear, width 0.25s linear;
|
||||||
|
transition: font-size 0.25s linear, width 0.25s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists .icon:hover {
|
||||||
|
font-size: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists .svg-icon {
|
||||||
|
/* 通过设置 font-size 来改变图标大小 */
|
||||||
|
width: 1em;
|
||||||
|
/* 图标和文字相邻时,垂直对齐 */
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
/* 通过设置 color 来改变 SVG 的颜色/fill */
|
||||||
|
fill: currentColor;
|
||||||
|
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
|
||||||
|
normalize.css 中也包含这行 */
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_lists li .name,
|
||||||
|
.icon_lists li .code-name {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* markdown 样式 */
|
||||||
|
.markdown {
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown img {
|
||||||
|
vertical-align: middle;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h1 {
|
||||||
|
color: #404040;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 40px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h2,
|
||||||
|
.markdown h3,
|
||||||
|
.markdown h4,
|
||||||
|
.markdown h5,
|
||||||
|
.markdown h6 {
|
||||||
|
color: #404040;
|
||||||
|
margin: 1.6em 0 0.6em 0;
|
||||||
|
font-weight: 500;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h2 {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h4 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h5 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h6 {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown hr {
|
||||||
|
height: 1px;
|
||||||
|
border: 0;
|
||||||
|
background: #e9e9e9;
|
||||||
|
margin: 16px 0;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown p {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>p,
|
||||||
|
.markdown>blockquote,
|
||||||
|
.markdown>.highlight,
|
||||||
|
.markdown>ol,
|
||||||
|
.markdown>ul {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown ul>li {
|
||||||
|
list-style: circle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>ul li,
|
||||||
|
.markdown blockquote ul>li {
|
||||||
|
margin-left: 20px;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>ul li p,
|
||||||
|
.markdown>ol li p {
|
||||||
|
margin: 0.6em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown ol>li {
|
||||||
|
list-style: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>ol li,
|
||||||
|
.markdown blockquote ol>li {
|
||||||
|
margin-left: 20px;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown code {
|
||||||
|
margin: 0 3px;
|
||||||
|
padding: 0 5px;
|
||||||
|
background: #eee;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown strong,
|
||||||
|
.markdown b {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0px;
|
||||||
|
empty-cells: show;
|
||||||
|
border: 1px solid #e9e9e9;
|
||||||
|
width: 95%;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>table th {
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>table th,
|
||||||
|
.markdown>table td {
|
||||||
|
border: 1px solid #e9e9e9;
|
||||||
|
padding: 8px 16px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>table th {
|
||||||
|
background: #F7F7F7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown blockquote {
|
||||||
|
font-size: 90%;
|
||||||
|
color: #999;
|
||||||
|
border-left: 4px solid #e9e9e9;
|
||||||
|
padding-left: 0.8em;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown blockquote p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown .anchor {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown .waiting {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h1:hover .anchor,
|
||||||
|
.markdown h2:hover .anchor,
|
||||||
|
.markdown h3:hover .anchor,
|
||||||
|
.markdown h4:hover .anchor,
|
||||||
|
.markdown h5:hover .anchor,
|
||||||
|
.markdown h6:hover .anchor {
|
||||||
|
opacity: 1;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown>br,
|
||||||
|
.markdown>p>br {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
display: block;
|
||||||
|
background: white;
|
||||||
|
padding: 0.5em;
|
||||||
|
color: #333333;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-comment,
|
||||||
|
.hljs-meta {
|
||||||
|
color: #969896;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-string,
|
||||||
|
.hljs-variable,
|
||||||
|
.hljs-template-variable,
|
||||||
|
.hljs-strong,
|
||||||
|
.hljs-emphasis,
|
||||||
|
.hljs-quote {
|
||||||
|
color: #df5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-keyword,
|
||||||
|
.hljs-selector-tag,
|
||||||
|
.hljs-type {
|
||||||
|
color: #a71d5d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-literal,
|
||||||
|
.hljs-symbol,
|
||||||
|
.hljs-bullet,
|
||||||
|
.hljs-attribute {
|
||||||
|
color: #0086b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-section,
|
||||||
|
.hljs-name {
|
||||||
|
color: #63a35c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-tag {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-title,
|
||||||
|
.hljs-attr,
|
||||||
|
.hljs-selector-id,
|
||||||
|
.hljs-selector-class,
|
||||||
|
.hljs-selector-attr,
|
||||||
|
.hljs-selector-pseudo {
|
||||||
|
color: #795da3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-addition {
|
||||||
|
color: #55a532;
|
||||||
|
background-color: #eaffea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-deletion {
|
||||||
|
color: #bd2c00;
|
||||||
|
background-color: #ffecec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 代码高亮 */
|
||||||
|
/* PrismJS 1.15.0
|
||||||
|
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||||
|
/**
|
||||||
|
* prism.js default theme for JavaScript, CSS and HTML
|
||||||
|
* Based on dabblet (http://dabblet.com)
|
||||||
|
* @author Lea Verou
|
||||||
|
*/
|
||||||
|
code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
color: black;
|
||||||
|
background: none;
|
||||||
|
text-shadow: 0 1px white;
|
||||||
|
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
word-spacing: normal;
|
||||||
|
word-break: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
|
||||||
|
-webkit-hyphens: none;
|
||||||
|
-moz-hyphens: none;
|
||||||
|
-ms-hyphens: none;
|
||||||
|
hyphens: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"]::-moz-selection,
|
||||||
|
pre[class*="language-"] ::-moz-selection,
|
||||||
|
code[class*="language-"]::-moz-selection,
|
||||||
|
code[class*="language-"] ::-moz-selection {
|
||||||
|
text-shadow: none;
|
||||||
|
background: #b3d4fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre[class*="language-"]::selection,
|
||||||
|
pre[class*="language-"] ::selection,
|
||||||
|
code[class*="language-"]::selection,
|
||||||
|
code[class*="language-"] ::selection {
|
||||||
|
text-shadow: none;
|
||||||
|
background: #b3d4fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
|
||||||
|
code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code blocks */
|
||||||
|
pre[class*="language-"] {
|
||||||
|
padding: 1em;
|
||||||
|
margin: .5em 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:not(pre)>code[class*="language-"],
|
||||||
|
pre[class*="language-"] {
|
||||||
|
background: #f5f2f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
:not(pre)>code[class*="language-"] {
|
||||||
|
padding: .1em;
|
||||||
|
border-radius: .3em;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.comment,
|
||||||
|
.token.prolog,
|
||||||
|
.token.doctype,
|
||||||
|
.token.cdata {
|
||||||
|
color: slategray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.punctuation {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.namespace {
|
||||||
|
opacity: .7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.property,
|
||||||
|
.token.tag,
|
||||||
|
.token.boolean,
|
||||||
|
.token.number,
|
||||||
|
.token.constant,
|
||||||
|
.token.symbol,
|
||||||
|
.token.deleted {
|
||||||
|
color: #905;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.selector,
|
||||||
|
.token.attr-name,
|
||||||
|
.token.string,
|
||||||
|
.token.char,
|
||||||
|
.token.builtin,
|
||||||
|
.token.inserted {
|
||||||
|
color: #690;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.operator,
|
||||||
|
.token.entity,
|
||||||
|
.token.url,
|
||||||
|
.language-css .token.string,
|
||||||
|
.style .token.string {
|
||||||
|
color: #9a6e3a;
|
||||||
|
background: hsla(0, 0%, 100%, .5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.atrule,
|
||||||
|
.token.attr-value,
|
||||||
|
.token.keyword {
|
||||||
|
color: #07a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.function,
|
||||||
|
.token.class-name {
|
||||||
|
color: #DD4A68;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.regex,
|
||||||
|
.token.important,
|
||||||
|
.token.variable {
|
||||||
|
color: #e90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.important,
|
||||||
|
.token.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token.entity {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,368 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>iconfont Demo</title>
|
||||||
|
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
|
||||||
|
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
|
||||||
|
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
|
||||||
|
<link rel="stylesheet" href="demo.css">
|
||||||
|
<link rel="stylesheet" href="iconfont.css">
|
||||||
|
<script src="iconfont.js"></script>
|
||||||
|
<!-- jQuery -->
|
||||||
|
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
|
||||||
|
<!-- 代码高亮 -->
|
||||||
|
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
|
||||||
|
<style>
|
||||||
|
.main .logo {
|
||||||
|
margin-top: 0;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .logo a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main .logo .sub-title {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
font-size: 22px;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(-45deg, #3967FF, #B500FE);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="main">
|
||||||
|
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
|
||||||
|
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
|
||||||
|
|
||||||
|
</a></h1>
|
||||||
|
<div class="nav-tabs">
|
||||||
|
<ul id="tabs" class="dib-box">
|
||||||
|
<li class="dib active"><span>Unicode</span></li>
|
||||||
|
<li class="dib"><span>Font class</span></li>
|
||||||
|
<li class="dib"><span>Symbol</span></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="tab-container">
|
||||||
|
<div class="content unicode" style="display: block;">
|
||||||
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">add</div>
|
||||||
|
<div class="code-name">&#xe664;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">ashbin</div>
|
||||||
|
<div class="code-name">&#xe665;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">close</div>
|
||||||
|
<div class="code-name">&#xe668;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">close-bold</div>
|
||||||
|
<div class="code-name">&#xe685;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">edit</div>
|
||||||
|
<div class="code-name">&#xe654;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">search</div>
|
||||||
|
<div class="code-name">&#xea56;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">查询</div>
|
||||||
|
<div class="code-name">&#xe615;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont"></span>
|
||||||
|
<div class="name">蜡烛</div>
|
||||||
|
<div class="code-name">&#xe65b;</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<div class="article markdown">
|
||||||
|
<h2 id="unicode-">Unicode 引用</h2>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
|
||||||
|
<ul>
|
||||||
|
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
|
||||||
|
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
|
||||||
|
</ul>
|
||||||
|
<blockquote>
|
||||||
|
<p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
|
||||||
|
</blockquote>
|
||||||
|
<p>Unicode 使用步骤如下:</p>
|
||||||
|
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
|
||||||
|
<pre><code class="language-css"
|
||||||
|
>@font-face {
|
||||||
|
font-family: 'iconfont';
|
||||||
|
src: url('iconfont.ttf?t=1768306553008') format('truetype');
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||||
|
<pre><code class="language-css"
|
||||||
|
>.iconfont {
|
||||||
|
font-family: "iconfont" !important;
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
|
||||||
|
<pre>
|
||||||
|
<code class="language-html"
|
||||||
|
><span class="iconfont">&#x33;</span>
|
||||||
|
</code></pre>
|
||||||
|
<blockquote>
|
||||||
|
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
|
||||||
|
</blockquote>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content font-class">
|
||||||
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-add"></span>
|
||||||
|
<div class="name">
|
||||||
|
add
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-add
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-ashbin"></span>
|
||||||
|
<div class="name">
|
||||||
|
ashbin
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-ashbin
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-close"></span>
|
||||||
|
<div class="name">
|
||||||
|
close
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-close
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-close-bold"></span>
|
||||||
|
<div class="name">
|
||||||
|
close-bold
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-close-bold
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-edit"></span>
|
||||||
|
<div class="name">
|
||||||
|
edit
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-edit
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-search"></span>
|
||||||
|
<div class="name">
|
||||||
|
search
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-search
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-search1"></span>
|
||||||
|
<div class="name">
|
||||||
|
查询
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-search1
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<span class="icon iconfont icon-lazhu"></span>
|
||||||
|
<div class="name">
|
||||||
|
蜡烛
|
||||||
|
</div>
|
||||||
|
<div class="code-name">.icon-lazhu
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<div class="article markdown">
|
||||||
|
<h2 id="font-class-">font-class 引用</h2>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
|
||||||
|
<p>与 Unicode 使用方式相比,具有如下特点:</p>
|
||||||
|
<ul>
|
||||||
|
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
|
||||||
|
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
|
||||||
|
</ul>
|
||||||
|
<p>使用步骤如下:</p>
|
||||||
|
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
|
||||||
|
<pre><code class="language-html"><link rel="stylesheet" href="./iconfont.css">
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
|
||||||
|
<pre><code class="language-html"><span class="iconfont icon-xxx"></span>
|
||||||
|
</code></pre>
|
||||||
|
<blockquote>
|
||||||
|
<p>"
|
||||||
|
iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
|
||||||
|
</blockquote>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content symbol">
|
||||||
|
<ul class="icon_lists dib-box">
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-add"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">add</div>
|
||||||
|
<div class="code-name">#icon-add</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-ashbin"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">ashbin</div>
|
||||||
|
<div class="code-name">#icon-ashbin</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-close"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">close</div>
|
||||||
|
<div class="code-name">#icon-close</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-close-bold"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">close-bold</div>
|
||||||
|
<div class="code-name">#icon-close-bold</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-edit"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">edit</div>
|
||||||
|
<div class="code-name">#icon-edit</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-search"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">search</div>
|
||||||
|
<div class="code-name">#icon-search</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-search1"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">查询</div>
|
||||||
|
<div class="code-name">#icon-search1</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dib">
|
||||||
|
<svg class="icon svg-icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-lazhu"></use>
|
||||||
|
</svg>
|
||||||
|
<div class="name">蜡烛</div>
|
||||||
|
<div class="code-name">#icon-lazhu</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<div class="article markdown">
|
||||||
|
<h2 id="symbol-">Symbol 引用</h2>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
|
||||||
|
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
|
||||||
|
<ul>
|
||||||
|
<li>支持多色图标了,不再受单色限制。</li>
|
||||||
|
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
|
||||||
|
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
|
||||||
|
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
|
||||||
|
</ul>
|
||||||
|
<p>使用步骤如下:</p>
|
||||||
|
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
|
||||||
|
<pre><code class="language-html"><script src="./iconfont.js"></script>
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
|
||||||
|
<pre><code class="language-html"><style>
|
||||||
|
.icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
fill: currentColor;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</code></pre>
|
||||||
|
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
|
||||||
|
<pre><code class="language-html"><svg class="icon" aria-hidden="true">
|
||||||
|
<use xlink:href="#icon-xxx"></use>
|
||||||
|
</svg>
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('.tab-container .content:first').show()
|
||||||
|
|
||||||
|
$('#tabs li').click(function (e) {
|
||||||
|
var tabContent = $('.tab-container .content')
|
||||||
|
var index = $(this).index()
|
||||||
|
|
||||||
|
if ($(this).hasClass('active')) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
$('#tabs li').removeClass('active')
|
||||||
|
$(this).addClass('active')
|
||||||
|
|
||||||
|
tabContent.hide().eq(index).fadeIn()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: "iconfont"; /* Project id */
|
||||||
|
src: url('@/static/font_ve87r6kfq3/iconfont.ttf?t=1768306553008') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-family: "iconfont" !important;
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-add:before {
|
||||||
|
content: "\e664";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-ashbin:before {
|
||||||
|
content: "\e665";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-close:before {
|
||||||
|
content: "\e668";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-close-bold:before {
|
||||||
|
content: "\e685";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-edit:before {
|
||||||
|
content: "\e654";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-search:before {
|
||||||
|
content: "\ea56";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-search1:before {
|
||||||
|
content: "\e615";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-lazhu:before {
|
||||||
|
content: "\e65b";
|
||||||
|
}
|
||||||
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,65 @@
|
||||||
|
{
|
||||||
|
"id": "",
|
||||||
|
"name": "",
|
||||||
|
"font_family": "iconfont",
|
||||||
|
"css_prefix_text": "icon-",
|
||||||
|
"description": "",
|
||||||
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "15838424",
|
||||||
|
"name": "add",
|
||||||
|
"font_class": "add",
|
||||||
|
"unicode": "e664",
|
||||||
|
"unicode_decimal": 58980
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "15838430",
|
||||||
|
"name": "ashbin",
|
||||||
|
"font_class": "ashbin",
|
||||||
|
"unicode": "e665",
|
||||||
|
"unicode_decimal": 58981
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "15838444",
|
||||||
|
"name": "close",
|
||||||
|
"font_class": "close",
|
||||||
|
"unicode": "e668",
|
||||||
|
"unicode_decimal": 58984
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "15838563",
|
||||||
|
"name": "close-bold",
|
||||||
|
"font_class": "close-bold",
|
||||||
|
"unicode": "e685",
|
||||||
|
"unicode_decimal": 59013
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33215995",
|
||||||
|
"name": "edit",
|
||||||
|
"font_class": "edit",
|
||||||
|
"unicode": "e654",
|
||||||
|
"unicode_decimal": 58964
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "44063702",
|
||||||
|
"name": "search",
|
||||||
|
"font_class": "search",
|
||||||
|
"unicode": "ea56",
|
||||||
|
"unicode_decimal": 59990
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "44849862",
|
||||||
|
"name": "查询",
|
||||||
|
"font_class": "search1",
|
||||||
|
"unicode": "e615",
|
||||||
|
"unicode_decimal": 58901
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "46589632",
|
||||||
|
"name": "蜡烛",
|
||||||
|
"font_class": "lazhu",
|
||||||
|
"unicode": "e65b",
|
||||||
|
"unicode_decimal": 58971
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
|
@ -88,3 +88,39 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 极简版(无CSS变量) */
|
||||||
|
.mini-btn {
|
||||||
|
margin-left: 10rpx !important;
|
||||||
|
font-size: 12px !important;
|
||||||
|
padding: 5rpx 15rpx !important;
|
||||||
|
border-width: 1px !important;
|
||||||
|
border-style: solid !important;
|
||||||
|
}
|
||||||
|
.btn-left .mini-btn:first-child {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 默认按钮 */
|
||||||
|
.mini-btn { color: #fff !important; background: #1890ff !important; border-color: #1890ff !important; }
|
||||||
|
/* 新增按钮 */
|
||||||
|
.add-btn { color: #1890ff !important; background: #e8f4ff !important; border-color: #a3d3ff !important; }
|
||||||
|
/* 删除按钮 */
|
||||||
|
.del-btn { color: #71e2a3 !important; background: #e7faf0 !important; border-color: #d0f5e0 !important; }
|
||||||
|
/* 编辑按钮 */
|
||||||
|
.edit-btn { color: #ff9292 !important; background: #ffeded !important; border-color: #ffdbdb !important; }
|
||||||
|
.cancel-btn { color: #333 !important; background: #f5f5f5 !important; border-color: #f5f5f5 !important; height: 55rpx; line-height: 55rpx; font-size: 14px !important; }
|
||||||
|
.confirm-btn { color: #fff !important; background: #1890ff !important; border-color: #1890ff !important; height: 55rpx; line-height: 55rpx; font-size: 14px !important; }
|
||||||
|
|
||||||
|
/* hover统一样式 */
|
||||||
|
.is-hover {
|
||||||
|
color: #fff !important;
|
||||||
|
/* 按按钮类型匹配背景色 */
|
||||||
|
&.add-btn { background: #1890ff !important; border-color: #1890ff !important; }
|
||||||
|
&.del-btn { background: #71e2a3 !important; border-color: #71e2a3 !important; }
|
||||||
|
&.edit-btn { background: #ff9292 !important; border-color: #ff9292 !important; }
|
||||||
|
&:not(.add-btn):not(.del-btn):not(.edit-btn) { background: #1682e6 !important; border-color: #1682e6 !important; }
|
||||||
|
}
|
||||||
|
|
@ -4,3 +4,4 @@
|
||||||
@import "@/static/scss/colorui.css";
|
@import "@/static/scss/colorui.css";
|
||||||
// iconfont
|
// iconfont
|
||||||
@import "@/static/font/iconfont.css";
|
@import "@/static/font/iconfont.css";
|
||||||
|
@import "@/static/font_ve87r6kfq3/iconfont.css";
|
||||||
103
utils/mqtt.js
103
utils/mqtt.js
|
|
@ -13,11 +13,11 @@ import mqtt from 'mqtt/dist/mqtt'
|
||||||
|
|
||||||
// ===================== MQTT配置(暂时写死,TODO:后续从数据字典获取)=====================
|
// ===================== MQTT配置(暂时写死,TODO:后续从数据字典获取)=====================
|
||||||
const MQTT_CONFIG = {
|
const MQTT_CONFIG = {
|
||||||
server: 'wxs://mq.mj142.cn:443/mqtt', // 替换为你的MQTT服务器地址
|
server: 'wxs://mq.xiaoces.com:443/mqtt', // 替换为你的MQTT服务器地址
|
||||||
username: 'admin', // 替换为通用账号
|
username: 'admin', // 替换为通用账号
|
||||||
password: 'Admin#12345678', // 替换为通用密码
|
password: 'Admin#12345678', // 替换为通用密码
|
||||||
clean: true,
|
clean: true,
|
||||||
host: 'mq.mj142.cn',
|
host: 'mq.xiaoces.com',
|
||||||
port: 443,
|
port: 443,
|
||||||
reconnectPeriod: 5000, // 重连间隔
|
reconnectPeriod: 5000, // 重连间隔
|
||||||
connectTimeout: 10000, // 连接超时
|
connectTimeout: 10000, // 连接超时
|
||||||
|
|
@ -59,7 +59,7 @@ export function initMqttConfig() {
|
||||||
console.log('MQTT配置初始化成功,clientId:', mqttState.options.clientId)
|
console.log('MQTT配置初始化成功,clientId:', mqttState.options.clientId)
|
||||||
return true
|
return true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
uni.showToast({ title: '设备连接异常', icon: 'none', duration: 2000 })
|
uni.showToast({ title: '设备连接异常-设备初始化失败', icon: 'none', duration: 2000 })
|
||||||
console.error('MQTT配置初始化失败:', err)
|
console.error('MQTT配置初始化失败:', err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ export function initMqttConfig() {
|
||||||
export function connectMqtt() {
|
export function connectMqtt() {
|
||||||
// 前置校验:是否已初始化配置
|
// 前置校验:是否已初始化配置
|
||||||
if (!mqttState.options.clientId) {
|
if (!mqttState.options.clientId) {
|
||||||
uni.showToast({ title: '设备连接异常', icon: 'none' })
|
uni.showToast({ title: '设备连接失败', icon: 'none' })
|
||||||
console.error('MQTT连接失败:请先调用initMqttConfig初始化配置')
|
console.error('MQTT连接失败:请先调用initMqttConfig初始化配置')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +86,7 @@ export function connectMqtt() {
|
||||||
try {
|
try {
|
||||||
// 创建客户端实例(同步操作)
|
// 创建客户端实例(同步操作)
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-WEIXIN
|
||||||
MQTT_CONFIG.server = 'wss://mq.mj142.cn:443/mqtt'
|
MQTT_CONFIG.server = 'wxs://mq.xiaoces.com:443/mqtt'
|
||||||
// #endif
|
// #endif
|
||||||
console.info("mqttState.connect",mqttState)
|
console.info("mqttState.connect",mqttState)
|
||||||
mqttState.client = mqtt.connect(MQTT_CONFIG.server, mqttState.options)
|
mqttState.client = mqtt.connect(MQTT_CONFIG.server, mqttState.options)
|
||||||
|
|
@ -156,7 +156,7 @@ export function removeOnMessageCallback() {
|
||||||
*/
|
*/
|
||||||
export function updateSubscribeList(list) {
|
export function updateSubscribeList(list) {
|
||||||
if (!Array.isArray(list)) {
|
if (!Array.isArray(list)) {
|
||||||
uni.showToast({ title: '设备连接异常', icon: 'none' })
|
uni.showToast({ title: '设备订阅更新异常', icon: 'none' })
|
||||||
console.error('订阅列表必须是数组')
|
console.error('订阅列表必须是数组')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +183,7 @@ function subscribeAllTopics() {
|
||||||
|
|
||||||
client.subscribe(subscribeList, { qos: 0 }, (err) => {
|
client.subscribe(subscribeList, { qos: 0 }, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
uni.showToast({ title: '设备连接异常', icon: 'none' })
|
uni.showToast({ title: '设备订阅异常', icon: 'none' })
|
||||||
console.error('MQTT订阅失败:', err)
|
console.error('MQTT订阅失败:', err)
|
||||||
} else {
|
} else {
|
||||||
console.log(`MQTT成功订阅:${subscribeList.join(', ')}`)
|
console.log(`MQTT成功订阅:${subscribeList.join(', ')}`)
|
||||||
|
|
@ -198,33 +198,35 @@ function subscribeAllTopics() {
|
||||||
* @returns {Boolean} - 是否触发发布成功
|
* @returns {Boolean} - 是否触发发布成功
|
||||||
*/
|
*/
|
||||||
export function publishMqtt(topic, message) {
|
export function publishMqtt(topic, message) {
|
||||||
const { isConnected, client } = mqttState
|
if (process.env.NODE_ENV === "production") {
|
||||||
if (!isConnected || !client) {
|
const { isConnected, client } = mqttState
|
||||||
uni.showToast({ title: '控制异常', icon: 'none' })
|
if (!isConnected || !client) {
|
||||||
console.error('MQTT发布失败:未连接')
|
uni.showToast({ title: '控制异常', icon: 'none' })
|
||||||
return false
|
console.error('MQTT发布失败:未连接')
|
||||||
}
|
return false
|
||||||
if (!topic) {
|
}
|
||||||
uni.showToast({ title: '控制异常', icon: 'none' })
|
if (!topic) {
|
||||||
console.error('MQTT发布失败:主题为空')
|
uni.showToast({ title: '控制异常', icon: 'none' })
|
||||||
return false
|
console.error('MQTT发布失败:主题为空')
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const msg = typeof message === 'object' ? JSON.stringify(message) : String(message)
|
const msg = typeof message === 'object' ? JSON.stringify(message) : String(message)
|
||||||
client.publish(topic, msg, (err) => {
|
client.publish(topic, msg, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
uni.showToast({ title: '控制异常', icon: 'none' })
|
uni.showToast({ title: '控制异常', icon: 'none' })
|
||||||
console.error(`MQTT发布失败:topic=${topic},err=${err}`)
|
console.error(`MQTT发布失败:topic=${topic},err=${err}`)
|
||||||
} else {
|
} else {
|
||||||
console.log(`MQTT发布成功:topic=${topic},message=${msg}`)
|
console.log(`MQTT发布成功:topic=${topic},message=${msg}`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
uni.showToast({ title: '控制异常', icon: 'none' })
|
uni.showToast({ title: '控制异常', icon: 'none' })
|
||||||
console.error('MQTT发布异常:', err)
|
console.error('MQTT发布异常:', err)
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,7 +247,7 @@ export function disconnectMqtt() {
|
||||||
console.log('MQTT连接已断开')
|
console.log('MQTT连接已断开')
|
||||||
return true
|
return true
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
uni.showToast({ title: '设备连接异常', icon: 'none' })
|
uni.showToast({ title: '设备通信异常', icon: 'none' })
|
||||||
console.error('MQTT断开失败:', err)
|
console.error('MQTT断开失败:', err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -275,6 +277,39 @@ export function getMqttState() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// utils/mqttOnline.js
|
||||||
|
let timer = null;
|
||||||
|
|
||||||
|
export function startMqttOnlinePing(intervalMs = 20000) {
|
||||||
|
if (!mqttState.client || !mqttState.options.clientId) return;
|
||||||
|
if (timer) return;
|
||||||
|
|
||||||
|
const topic = `frontend/${mqttState.options.clientId}/online`;
|
||||||
|
|
||||||
|
const ping = () => {
|
||||||
|
try {
|
||||||
|
if (!mqttState.client.connected) return;
|
||||||
|
const payload = JSON.stringify({ ts: Date.now() });
|
||||||
|
// qos=0 足够;retain 不要
|
||||||
|
mqttState.client.publish(topic, payload, { qos: 0, retain: false });
|
||||||
|
} catch (e) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ping();
|
||||||
|
// 每 20000ms(20秒)执行一次 ping
|
||||||
|
timer = setInterval(ping, intervalMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopMqttOnlinePing() {
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(timer);
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 导出所有方法(全局调用)
|
// 导出所有方法(全局调用)
|
||||||
export default {
|
export default {
|
||||||
initMqttConfig,
|
initMqttConfig,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue