谁被相关

This commit is contained in:
SjS 2025-04-25 20:17:27 +08:00
parent a9dbdc1388
commit 06d03ada25
6 changed files with 574 additions and 87 deletions

21
src/api/bst/deviceIot.js Normal file
View File

@ -0,0 +1,21 @@
import request from '@/utils/request'
// 刷新物联网设备信息
export function refreshIot(deviceId, onlineType) {
return request({
url: `/bst/device/iot/${deviceId}/refreshIot`,
method: 'get',
timeout: 20000,
params: {
onlineType
}
})
}
// 设备开关
export function switchDevice(deviceId, open) {
return request({
url: `/bst/device/iot/${deviceId}/switch?open=${open}`,
method: 'put'
})
}

44
src/api/bst/suit.js Normal file
View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询套餐列表
export function listSuit(query) {
return request({
url: '/bst/suit/list',
method: 'get',
params: query
})
}
// 查询套餐详细
export function getSuit(suitId) {
return request({
url: '/bst/suit/' + suitId,
method: 'get'
})
}
// 新增套餐
export function addSuit(data) {
return request({
url: '/bst/suit',
method: 'post',
data: data
})
}
// 修改套餐
export function updateSuit(data) {
return request({
url: '/bst/suit',
method: 'put',
data: data
})
}
// 删除套餐
export function delSuit(suitId) {
return request({
url: '/bst/suit/' + suitId,
method: 'delete'
})
}

View File

@ -0,0 +1,100 @@
<template>
<div class="dot-status" :class="{ 'is-active': active }">
<el-tooltip :content="active ? activeText : inactiveText" placement="top">
<div class="status-wrapper">
<span class="status-dot"></span>
<span v-if="showText" class="status-text">{{ active ? activeText : inactiveText }}</span>
</div>
</el-tooltip>
</div>
</template>
<script>
export default {
name: 'DotStatus',
props: {
showText: {
type: Boolean,
default: false
},
activeText: {
type: String,
default: '在线'
},
inactiveText: {
type: String,
default: '离线'
},
active: {
type: Boolean,
default: false,
}
},
}
</script>
<style lang="scss" scoped>
.dot-status {
display: inline-flex;
align-items: center;
margin: 0 4px;
.status-wrapper {
display: inline-flex;
align-items: center;
gap: 4px;
}
.status-dot {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
background-color: #f56c6c;
transition: all 0.3s ease;
position: relative;
&::after {
content: '';
position: absolute;
width: 6px;
height: 6px;
border-radius: 50%;
background-color: inherit;
opacity: 0.5;
animation: pulse 2s infinite;
}
}
.status-text {
font-size: 12px;
color: #f56c6c;
line-height: 1;
}
&.is-active {
.status-dot {
background-color: #67c23a;
}
.status-text {
color: #67c23a;
}
}
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 0.5;
}
70% {
transform: scale(2);
opacity: 0;
}
100% {
transform: scale(1);
opacity: 0;
}
}
</style>

View File

@ -126,3 +126,14 @@ export const ModelTag = {
ELE: "5", // 电量
}
// 型号功能
export const OnlineStatus = {
OFFLINE: "0", // 离线
ONLINE: "1", // 在线
}
// 设备获取在线状态类型
export const DeviceOnlineType = {
GET: "1", //OneNet获取
COMMAND: "2", // 命令获取
}

View File

@ -12,29 +12,23 @@
{{ deviceData.deviceName | dv }}
<el-link type="primary" icon="el-icon-edit" @click="handleEditDevice"></el-link>
</div>
<dot-status :active="deviceData.onlineStatus === DeviceOnlineStatus.ONLINE" show-text/>
<dot-status :active="isOpen" show-text active-text="已开启" inactive-text="已关闭"/>
<dot-status
:active="deviceData.status === DeviceStatus.FREE"
show-text
active-text="空闲"
:inactive-text="deviceData.status === DeviceStatus.USING ? '使用中' : '调试中'"
/>
<span class="last-online-time">
<i class="el-icon-time"></i>
最后在线:
{{ deviceData.lastOnlineTime | dv }}
</span>
<!-- <dot-status :active="deviceData.onlineStatus === onlineStatus.ONLINE" show-text/>-->
<!-- <dot-status :active="isOpen" show-text active-text="已开启" inactive-text="已关闭"/>-->
<!-- <span class="last-online-time">-->
<!-- <i class="el-icon-time"></i>-->
<!-- 最后在线:-->
<!-- {{ deviceData.lastOnlineTime | dv }}-->
<!-- </span>-->
</div>
<!-- 操作按钮组 -->
<el-row class="device-actions">
<el-button size="small" plain icon="el-icon-setting" @click="handleReverse(true)" v-if="!isReverse">
反转开关
</el-button>
<el-button size="small" plain icon="el-icon-setting" @click="handleReverse(false)" v-if="isReverse">
正转开关
</el-button>
<!-- <el-button size="small" plain icon="el-icon-setting" @click="handleReverse(true)" v-if="!isReverse">-->
<!-- 反转开关-->
<!-- </el-button>-->
<!-- <el-button size="small" plain icon="el-icon-setting" @click="handleReverse(false)" v-if="isReverse">-->
<!-- 正转开关-->
<!-- </el-button>-->
<el-button size="small" plain type="warning" icon="el-icon-switch-button" v-if="!isOpen"
@click="handleSwitch(true)">强制开启
</el-button>
@ -44,10 +38,10 @@
<el-button size="small" plain icon="el-icon-refresh"
@click="refreshIot(deviceId, true, DeviceOnlineType.COMMAND)">刷新设备信息
</el-button>
<device-sn :sn="deviceData.deviceNo">
<el-button size="small" type="primary" icon="el-icon-picture" style="margin-left: 0.5em">设备二维码
</el-button>
</device-sn>
<!-- <device-sn :sn="deviceData.deviceNo">-->
<!-- <el-button size="small" type="primary" icon="el-icon-picture" style="margin-left: 0.5em">设备二维码-->
<!-- </el-button>-->
<!-- </device-sn>-->
</el-row>
</div>
@ -62,13 +56,13 @@
<i class="el-icon-connection"></i>
<span class="label">MAC-1:</span>
<span>{{ deviceData.mac | dv }}</span>
<dot-status v-if="deviceData.mac" :active="deviceData.onlineStatus1 === DeviceOnlineStatus.ONLINE"/>
<dot-status v-if="deviceData.mac" :active="deviceData.onlineStatus1 === OnlineStatus.ONLINE"/>
</div>
<div class="info-item" v-if="deviceData.mac2">
<i class="el-icon-connection"></i>
<span class="label">MAC-2:</span>
<span>{{ deviceData.mac2 | dv }}</span>
<dot-status :active="deviceData.onlineStatus2 === DeviceOnlineStatus.ONLINE"/>
<dot-status :active="deviceData.onlineStatus2 === OnlineStatus.ONLINE"/>
</div>
<div class="info-item">
<i class="el-icon-collection-tag"></i>
@ -90,11 +84,6 @@
<span class="label">版本号:</span>
<span>{{ deviceData.version | dv }}</span>
</div>
<div class="info-item" v-if="deviceData.modelTags.includes(ModelTag.WIFI)">
<i class="el-icon-magic-stick"></i>
<span class="label">WIFI:</span>
<span>{{ deviceData.wifi | dv }}</span>
</div>
<div class="info-item">
<i class="el-icon-open"></i>
<span class="label">开关设置:</span>
@ -103,7 +92,7 @@
<div class="info-item">
<i class="el-icon-collection-tag"></i>
<span class="label">功能:</span>
<dict-tag :options="dict.type.sm_model_tag" :value="deviceData.modelTags" size="mini"/>
<dict-tag :options="dict.type.model_type" :value="deviceData.modelTags" size="mini"/>
</div>
</div>
@ -148,31 +137,31 @@
</el-col>
<!-- 电力参数 -->
<el-col :span="12">
<div class="info-section">
<div class="section-title">
<span><i class="el-icon-odometer"></i>电力参数</span>
</div>
<div class="data-grid">
<div class="data-item">
<div class="item-label">电压</div>
<div class="item-value">{{ deviceData.voltage | fix2 | dv }} V</div>
</div>
<div class="data-item">
<div class="item-label">电流</div>
<div class="item-value">{{ deviceData.electricity | fix2 | dv }} A</div>
</div>
<div class="data-item">
<div class="item-label">功率</div>
<div class="item-value">{{ deviceData.realTimePower | fix2 | dv }} W</div>
</div>
<div class="data-item">
<div class="item-label">电压系数</div>
<div class="item-value">{{ deviceData.vxs | fix3 | dv }}</div>
</div>
</div>
</div>
</el-col>
<!-- <el-col :span="12">-->
<!-- <div class="info-section">-->
<!-- <div class="section-title">-->
<!-- <span><i class="el-icon-odometer"></i>电力参数</span>-->
<!-- </div>-->
<!-- <div class="data-grid">-->
<!-- <div class="data-item">-->
<!-- <div class="item-label">电压</div>-->
<!-- <div class="item-value">{{ deviceData.voltage | fix2 | dv }} V</div>-->
<!-- </div>-->
<!-- <div class="data-item">-->
<!-- <div class="item-label">电流</div>-->
<!-- <div class="item-value">{{ deviceData.electricity | fix2 | dv }} A</div>-->
<!-- </div>-->
<!-- <div class="data-item">-->
<!-- <div class="item-label">功率</div>-->
<!-- <div class="item-value">{{ deviceData.realTimePower | fix2 | dv }} W</div>-->
<!-- </div>-->
<!-- <div class="data-item">-->
<!-- <div class="item-label">电压系数</div>-->
<!-- <div class="item-value">{{ deviceData.vxs | fix3 | dv }}</div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </el-col>-->
<!-- 累计用电信息 -->
<el-col :span="12">
@ -233,12 +222,12 @@
<!-- style="margin-left: 0.5em"/>-->
<!-- </el-row>-->
</template>
<el-descriptions-item label="所属商户">
<user-link :name="deviceData.userName" :id="deviceData.userId"/>
</el-descriptions-item>
<el-descriptions-item label="店铺名称">
<store-link :name="deviceData.storeName" :id="deviceData.storeId"/>
</el-descriptions-item>
<!-- <el-descriptions-item label="所属商户">-->
<!-- <user-link :name="deviceData.userName" :id="deviceData.userId"/>-->
<!-- </el-descriptions-item>-->
<!-- <el-descriptions-item label="店铺名称">-->
<!-- <store-link :name="deviceData.storeName" :id="deviceData.storeId"/>-->
<!-- </el-descriptions-item>-->
<el-descriptions-item label="备注">{{ deviceData.remark | dv }}</el-descriptions-item>
</el-descriptions>
</el-card>
@ -256,31 +245,32 @@ import {toDescriptionFromSecond} from '@/utils/date'
import BooleanTag from '@/components/BooleanTag/index.vue'
import {isEmpty} from '@/utils'
import LineField from '@/components/LineField/index.vue'
import {DeviceOnlineType,OnlineStatus} from "@/utils/constants";
import {ModelTag} from "@/utils/constants";
import DotStatus from "@/components/DotStatus/index.vue";
import {refreshIot} from "@/api/bst/deviceIot";
import {getDevice} from "@/api/bst/device";
import {switchDevice} from "@/api/bst/deviceIot";
export default {
name: 'Device/:deviceId',
name: 'DeviceView',
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',
'device_set'
'device_set',
'device_online_status',
'device_status',
'device_power_status',
'device_model_tag',
'model_type',
],
components: {
DotStatus,
LineField,
BooleanTag,
QrCode
QrCode,
OnlineStatus
},
data() {
return {
showSetWifi: false,
loading: false,
deviceData: {
modelTags: [],
@ -300,15 +290,15 @@ export default {
},
// ID
deviceId: null,
DeviceOnlineStatus,
DeviceStatus,
OnlineStatus,
ModelTag,
DeviceServiceMode,
DeviceOnlineType,
editDialogVisible: false
}
},
computed: {
DeviceOnlineType() {
return DeviceOnlineType
},
//
calcDbEle() {
return (device) => {
@ -417,12 +407,6 @@ export default {
})
})
},
onSetWifiSuccess(data) {
this.deviceData.wifi = data.wifiName;
},
handleSetWifi() {
this.showSetWifi = true;
},
isEmpty,
handleUnbind() {
this.$confirm('是否强制解绑该商户?', '警告', {

View File

@ -0,0 +1,327 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="商户ID" prop="userId">
<el-input
v-model="queryParams.userId"
placeholder="请输入商户ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="店铺ID" prop="storeId">
<el-input
v-model="queryParams.storeId"
placeholder="请输入店铺ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="套餐名称" prop="suitName">
<el-input
v-model="queryParams.suitName"
placeholder="请输入套餐名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-has-permi="['bst:suit:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-has-permi="['bst:suit:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-has-permi="['bst:suit:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="suitList" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="onSortChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="套餐名称" align="center" prop="suitName"/>
<el-table-column label="店铺名称" align="center" prop="storeName"/>
<el-table-column label="充值金额" align="center" prop="storeName"/>
<el-table-column label="爆灯次数" align="center" prop="storeName"/>
<template v-for="column of showColumns">
<el-table-column
:key="column.key"
:label="column.label"
:prop="column.key"
:align="column.align"
:min-width="column.minWidth"
:sort-orders="orderSorts"
:sortable="column.sortable"
:show-overflow-tooltip="column.overflow"
:width="column.width"
>
<template slot-scope="d">
<template v-if="column.key === 'suitId'">
{{d.row[column.key]}}
</template>
<template v-else>
{{d.row[column.key]}}
</template>
</template>
</el-table-column>
</template>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-has-permi="['bst:suit:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-has-permi="['bst:suit:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改套餐对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body :close-on-click-modal="false">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row>
<form-col :span="span" label="套餐名称" prop="suitName">
<el-input v-model="form.suitName" placeholder="请输入套餐名称" />
</form-col>
<form-col :span="span" label="充值金额" prop="rechargeAmount">
<el-input v-model="form.rechargeAmount" placeholder="请输入充值金额" />
</form-col>
<form-col :span="span" label="爆灯次数" prop="lightingNums">
<el-input v-model="form.lightingNums" placeholder="请输入爆灯次数" />
</form-col>
<form-col :span="span" label="显示顺序" prop="orderNum">
<el-input v-model="form.orderNum" placeholder="请输入显示顺序" />
</form-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listSuit, getSuit, delSuit, addSuit, updateSuit } from "@/api/bst/suit";
import { $showColumns } from '@/utils/mixins';
import FormCol from "@/components/FormCol/index.vue";
//
const defaultSort = {
prop: "createTime",
order: "descending"
}
export default {
name: "Suit",
mixins: [$showColumns],
components: {FormCol},
data() {
return {
span: 24,
//
orderSorts: ['ascending', 'descending', null],
//
loading: true,
//
ids: [],
//
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
suitList: [],
//
title: "",
//
open: false,
defaultSort,
//
queryParams: {
pageNum: 1,
pageSize: 20,
orderByColumn: defaultSort.prop,
isAsc: defaultSort.order,
userId: null,
storeId: null,
rechargeAmount: null,
lightingNums: null,
suitName: null,
status: null,
deleted: null,
orderNum: null
},
//
form: {},
//
rules: {
}
};
},
created() {
this.getList();
},
methods: {
/** 当排序按钮被点击时触发 **/
onSortChange(column) {
if (column.order == null) {
this.queryParams.orderByColumn = defaultSort.prop;
this.queryParams.isAsc = defaultSort.order;
} else {
this.queryParams.orderByColumn = column.prop;
this.queryParams.isAsc = column.order;
}
this.getList();
},
/** 查询套餐列表 */
getList() {
this.loading = true;
listSuit(this.queryParams).then(response => {
this.suitList = response.rows;
this.total = response.total;
this.loading = false;
});
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
suitId: null,
userId: null,
storeId: null,
rechargeAmount: null,
lightingNums: null,
suitName: null,
status: null,
createTime: null,
deleted: null,
orderNum: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
//
handleSelectionChange(selection) {
this.ids = selection.map(item => item.suitId)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加套餐";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const suitId = row.suitId || this.ids
getSuit(suitId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改套餐";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.suitId != null) {
updateSuit(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addSuit(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const suitIds = row.suitId || this.ids;
this.$modal.confirm('是否确认删除套餐编号为"' + suitIds + '"的数据项?').then(function() {
return delSuit(suitIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('bst/suit/export', {
...this.queryParams
}, `suit_${new Date().getTime()}.xlsx`)
}
}
};
</script>