This commit is contained in:
磷叶 2024-12-30 14:52:27 +08:00
parent 79cd20467c
commit a14e1841cc
8 changed files with 102 additions and 43 deletions

36
.cursorrules Normal file
View File

@ -0,0 +1,36 @@
# 项目背景
这是一个基于RuoYi-Vue的智能开关项目后台管理系统主要用于管理智能开关设备、用户、订单、支付、设备状态、设备参数等。
# 主要框架
- Vue2
- Element-UI
- Axios
- Vuex
- Vue-Router
# 编码标准
- 变量和函数名使用 camelCase 规范,组件名使用 PascalCase
- 组件的样式使用 scoped 属性,避免样式污染
- 样式使用scss
- props、data、methods、computed、watch 生命周期函数等都使用驼峰命名
- 对于全局能够重复使用的组件,尽量封装成组件,并放在 src/components 目录下
- 对于业务能够重复使用的组件,尽量封装成组件,并放在 src/views/{模块名}/components 目录下
- 所有请求都需要在 src/api/{模块名}.js 文件中定义,并保持统一的命名规范,使用时统一调用
- 业务操作尽量封装成方法或组件
- table中的数据使用columns定义具体可以参考其他组件
- 保持与现有代码风格一致
- 代码需要具有可读性,注释清晰,后续可拓展
- 生成的代码需要自动导入相关依赖,这点很重要
# 项目结构
- src/api 目录下存放接口文件
- src/assets 目录下存放静态资源
- src/components 目录下存放全局组件
- src/views 目录下存放页面
- src/utils 目录下存放工具类
- src/utils/constants.js 目录下存放常量
- src/views/ss 目录下存放业务相关页面
- src/views/system 目录下存放系统相关页面
# 文档规范
- 使用 JSDoc 格式编写函数和组件的注释

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ selenium-debug.log
package-lock.json
yarn.lock
dist.zip

10
jsconfig.json Normal file
View File

@ -0,0 +1,10 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

View File

@ -70,10 +70,14 @@ export function logicDelDevice(deviceId) {
// 刷新物联网设备信息
export function refreshIot(deviceId) {
export function refreshIot(deviceId, onlineType) {
return request({
url: `/system/device/${deviceId}/refreshIot`,
method: 'get'
method: 'get',
timeout: 20000,
params: {
onlineType
}
})
}

View File

@ -289,3 +289,9 @@ export const VipExpireType = {
FOREVER: "1", // 永久有效
TIME: "2", // 有效期
}
// 设备获取在线状态类型
export const DeviceOnlineType = {
GET: "1", //OneNet获取
COMMAND: "2", // 命令获取
}

View File

@ -49,7 +49,7 @@ export default {
default: getVipLevel
},
addApi: {
typ: Function,
type: Function,
default: addVipLevel
},
updateApi: {

View File

@ -58,7 +58,7 @@
</template>
<script>
import { listVipLevel, getVipLevel, delVipLevel, addVipLevel, updateVipLevel } from "@/api/ss/vipLevel";
import { delVipLevel } from "@/api/ss/vipLevel";
import { $showColumns } from '@/utils/mixins';
import UserLink from '@/components/Business/SmUser/UserLink.vue'
import VipLevelEditDialog from '@/views/ss/vipLevel/components/VipLevelEditDialog.vue'

View File

@ -12,7 +12,7 @@
<el-button size="small" plain icon="el-icon-refresh" @click="handleResetEle" v-if="deviceData.modelTags.includes(ModelTag.ELE)">电量归零</el-button>
<el-button size="small" plain type="warning" icon="el-icon-switch-button" v-if="!isOpen" @click="handleSwitch(true)">强制开启</el-button>
<el-button size="small" plain type="warning" icon="el-icon-switch-button" v-if="isOpen" @click="handleSwitch(false)">强制关闭</el-button>
<el-button size="small" plain icon="el-icon-refresh" @click="refreshIot(deviceId, true)" style="margin-right: 1em">刷新设备信息</el-button>
<el-button size="small" plain icon="el-icon-refresh" @click="refreshIot(deviceId, true, DeviceOnlineType.COMMAND)" style="margin-right: 1em">刷新设备信息</el-button>
<el-popover
placement="left"
width="180"
@ -52,6 +52,15 @@
<el-descriptions-item label="限制充值原因">
{{deviceData.limitRechargeReason | defaultValue}}
</el-descriptions-item>
<el-descriptions-item label="用户手动操作时间">
{{deviceData.userOperaTime | defaultValue}}
</el-descriptions-item>
<el-descriptions-item label="用户手动操作电量">
{{deviceData.userOpereEle | defaultValue}}
</el-descriptions-item>
<el-descriptions-item label="用户手动操作类型">
<dict-tag :options="dict.type.device_user_opera_type" :value="deviceData.userOperaType" size="mini"/>
</el-descriptions-item>
</el-descriptions>
</el-card>
@ -110,15 +119,9 @@
<el-descriptions-item label="开关状态">
<el-tag :type="isOpen ? 'success' : 'danger'" size="mini">{{isOpen ? '已开启' : '已关闭'}}</el-tag>
</el-descriptions-item>
<!-- <el-descriptions-item label="电压">{{deviceData.voltage | money | defaultValue }} V</el-descriptions-item>-->
<!-- <el-descriptions-item label="电流">{{deviceData.electricity | money | defaultValue }} A</el-descriptions-item>-->
<!-- <el-descriptions-item label="功率">{{deviceData.realTimePower | money | defaultValue }} W</el-descriptions-item>-->
<el-descriptions-item label="总用电量">
{{deviceData.totalElectriQuantity | money | defaultValue}}
</el-descriptions-item>
<!-- <el-descriptions-item label="电压系数">-->
<!-- {{deviceData.vxs | fix3 | defaultValue}}-->
<!-- </el-descriptions-item>-->
<el-descriptions-item label="电量读数">
{{deviceData.totalElectriQuantity - deviceData.initReading | money | defaultValue}}
<el-link @click="handleInitReading" type="primary" icon="el-icon-refresh" style="margin-left: 0.5em">重置</el-link>
@ -126,15 +129,6 @@
<el-descriptions-item label="最近重置读数时间">
{{deviceData.lastInitReading | defaultValue}}
</el-descriptions-item>
<!-- <el-descriptions-item label="剩余时长">-->
<!-- 数据库{{surplusTimeDesc(surplusTime).text}} / 设备{{surplusTimeDesc(deviceData.remainTime).text}}-->
<!-- </el-descriptions-item>-->
<!-- <el-descriptions-item label="剩余电量">-->
<!-- {{deviceData.surplusEle | defaultValue}} -->
<!-- </el-descriptions-item>-->
<!-- <el-descriptions-item label="最近更新时间">-->
<!-- {{deviceData.lastPullTime | defaultValue }}-->
<!-- </el-descriptions-item>-->
</el-descriptions>
</el-card>
</el-col>
@ -159,29 +153,32 @@
</el-row>
</template>
<el-row>
<el-col :span="8">
<el-col :span="12">
<el-statistic style="margin-bottom: 8px" title="时长(数据库)">
<template #formatter>{{surplusTimeDesc(surplusTime).text}}</template>
</el-statistic>
</el-col>
<el-col :span="8">
<el-col :span="12">
<el-statistic style="margin-bottom: 8px" title="时长(设备)">
<template #formatter>{{surplusTimeDesc(deviceData.remainTime).text}}</template>
</el-statistic>
</el-col>
<el-col :span="8">
<el-statistic style="margin-bottom: 8px" title="电量" :value="deviceData.surplusEle" :precision="2" suffix="度"/>
<el-col :span="12">
<el-statistic style="margin-bottom: 8px" title="电量(数据库)" :value="deviceData.surplusEleDb" :precision="2" suffix="度"/>
</el-col>
<el-col :span="8">
<el-col :span="12">
<el-statistic style="margin-bottom: 8px" title="电量(设备)" :value="deviceData.surplusEle" :precision="2" suffix="度"/>
</el-col>
<el-col :span="12">
<el-statistic style="margin-bottom: 8px" title="电压" :value="deviceData.voltage" :precision="2" suffix="V"/>
</el-col>
<el-col :span="8">
<el-col :span="12">
<el-statistic style="margin-bottom: 8px" title="电流" :value="deviceData.electricity" :precision="2" suffix="A"/>
</el-col>
<el-col :span="8">
<el-col :span="12">
<el-statistic style="margin-bottom: 8px" title="功率" :value="deviceData.realTimePower" :precision="2" suffix="W"/>
</el-col>
<el-col :span="8">
<el-col :span="12">
<el-statistic style="margin-bottom: 8px" title="电压系数">
<template #formatter>{{deviceData.vxs | fix3 | defaultValue}}</template>
</el-statistic>
@ -276,7 +273,7 @@ import UserLink from '@/components/Business/SmUser/UserLink.vue'
import { $serviceType, $view } from '@/utils/mixins'
import Recharge from '@/views/system/recharge/index.vue'
import BooleanTag from '@/components/BooleanTag/index.vue'
import { DeviceOnlineStatus, DeviceServiceMode, ModelTag } from '@/utils/constants'
import { DeviceOnlineStatus, DeviceServiceMode, ModelTag, DeviceOnlineType } from '@/utils/constants'
import { isEmpty } from '@/utils'
import BindMchButton from '@/views/system/device/components/BindMchButton.vue'
import BindAgentButton from '@/views/system/device/components/BindAgentButton.vue'
@ -287,7 +284,7 @@ import CommandLog from "@/views/ss/commandLog/index.vue";
export default {
name: 'Device/:deviceId',
mixins: [$serviceType, $view],
dicts: ['sm_device_status', 'sm_device_outage_way', 'sm_device_notice_way', 'sm_model_tag', 'sm_device_online_status', 'service_type', 'device_service_mode', 'time_unit', 'bonus_arrival_type'],
dicts: ['sm_device_status', 'sm_device_outage_way', 'sm_device_notice_way', 'sm_model_tag', 'sm_device_online_status', 'service_type', 'device_service_mode', 'time_unit', 'bonus_arrival_type', 'device_user_opera_type'],
components: {
CommandLog,
DeviceSetWifiDialog,
@ -324,9 +321,20 @@ export default {
},
// ID
deviceId: null,
DeviceOnlineStatus,
ModelTag,
DeviceServiceMode,
DeviceOnlineType
}
},
computed: {
//
calcDbEle() {
return (device) => {
return device.expireEle - device.totalElectriQuantity;
}
},
// MAC
macList() {
let list = [];
if (!isEmpty(this.deviceData.mac)) {
@ -337,25 +345,19 @@ export default {
}
return list;
},
DeviceOnlineStatus() {
return DeviceOnlineStatus
},
ModelTag() {
return ModelTag
},
DeviceServiceMode() {
return DeviceServiceMode
},
//
qrCodeText() {
return (device) => {
return getWxIndexUrl({ s: device.deviceNo});
}
},
//
surplusTimeDesc() {
return (second) => {
return toDescriptionFromSecond(second);
}
},
//
isOpen() {
return this.deviceData != null && this.deviceData.powerStatus === '1';
},
@ -369,7 +371,7 @@ export default {
},
created() {
this.deviceId = this.$route.params.deviceId;
this.refreshIot(this.deviceId);
this.refreshIot(this.deviceId, false, DeviceOnlineType.GET);
},
beforeDestroy() {
clearInterval(this.timer);
@ -529,9 +531,9 @@ export default {
}
},
//
refreshIot(deviceId, notice = false) {
refreshIot(deviceId, notice = false, onlineType = DeviceOnlineType.GET) {
this.loading = true;
refreshIot(deviceId).then(res => {
refreshIot(deviceId, onlineType).then(res => {
if (res.code !== 200) {
return this.$message.error(res.msg);
}
@ -560,7 +562,7 @@ export default {
}
</script>
<style scoped>
<style scoped lang="scss">
.remark-text {
color: #ccc;
margin-left: 1em;