assign device

This commit is contained in:
2023-03-31 10:03:07 +08:00
parent 2eeb3bf456
commit 2b7a638c1c
8 changed files with 673 additions and 61 deletions

60
src/api/device/group.js Normal file
View File

@ -0,0 +1,60 @@
import request from "@/utils/request";
// 查询设备分组列表
export function listGroup(query) {
return request({
url: "/device/group/list",
method: "get",
params: query,
});
}
// 查询设备分组详细
export function getGroup(groupId) {
return request({
url: "/device/group/" + groupId,
method: "get",
});
}
// 新增设备分组
export function addGroup(data) {
return request({
url: "/device/group",
method: "post",
data: data,
});
}
// 修改设备分组
export function updateGroup(data) {
return request({
url: "/device/group",
method: "put",
data: data,
});
}
// 删除设备分组
export function delGroup(groupId) {
return request({
url: "/device/group/" + groupId,
method: "delete",
});
}
// 分配设备
export function assignDevice(groupId, deviceIds) {
return request({
url: `/device/group/allot/${groupId}/${deviceIds}`,
method: "post",
});
}
// 分配设备
export function unAssignDevice(deviceIds) {
return request({
url: `/device/group/deleteAllot/${deviceIds}`,
method: "delete",
});
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -1,10 +1,45 @@
<template> <template>
<el-dialog :model-value="modelValue" @close="cancel" @open="handleOpen"> <el-dialog
:model-value="modelValue"
append-to-body
@close="cancel"
@open="handleOpen"
>
<el-row> <el-row>
<el-table ref="tableRef" :data="dataList" @select="handleSelect"> <el-table
<el-table-column align="center" type="selection" width="55" /> ref="tableRef"
<el-table-column prop="deviceId" /> v-loading="loading"
<el-table-column label="设备名称" prop="deviceName" /> :data="dataList"
@select="handleSelect"
@select-all="handleSelectAll"
>
<el-table-column
v-if="!readonly"
align="center"
type="selection"
width="55"
/>
<el-table-column
v-for="item in tableStruct"
:key="item.label || item.prop"
:label="item.label"
:prop="item.prop"
align="center"
>
<template v-if="item.operate" #default="{ row }">
<el-button
v-for="button in item.operate"
:key="button.label"
:icon="button.icon"
:type="button.type"
link
size="small"
@click="button.onClick(row)"
>
{{ button.label }}
</el-button>
</template>
</el-table-column>
</el-table> </el-table>
<pagination <pagination
v-show="total > 0" v-show="total > 0"
@ -14,15 +49,19 @@
@pagination="getList" @pagination="getList"
/> />
</el-row> </el-row>
<el-row>
<el-col> <template #footer>
<el-button type="primary" @click="confirmSelect">确认</el-button> <div class="dialog-footer">
</el-col> <el-button v-if="!readonly" type="primary" @click="confirmSelect"
</el-row> >确认</el-button
>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog> </el-dialog>
</template> </template>
<script setup> <script name="TableSelect" setup>
import { nextTick, reactive, ref, toRefs, watchEffect } from "vue"; import { nextTick, reactive, ref, toRefs, watchEffect } from "vue";
import { cloneDeep } from "lodash-es"; import { cloneDeep } from "lodash-es";
import Pagination from "@/components/Pagination/index.vue"; import Pagination from "@/components/Pagination/index.vue";
@ -30,14 +69,15 @@ import Pagination from "@/components/Pagination/index.vue";
const props = defineProps({ const props = defineProps({
list: { list: {
type: Array, type: Array,
default: [ default: [],
{ },
deviceId: 40, tableStruct: {
}, type: Array,
{ default: [],
deviceId: 38, },
}, readonly: {
], type: Boolean,
default: false,
}, },
requestMethod: { requestMethod: {
type: Function, type: Function,
@ -52,7 +92,7 @@ const props = defineProps({
}); });
const { list } = toRefs(props); const { list } = toRefs(props);
const emit = defineEmits(["select-add", "select-remove", "update:modelValue"]); const emit = defineEmits(["update:modelValue", "confirm-select"]);
const loading = ref(false); const loading = ref(false);
const dataList = ref([]); const dataList = ref([]);
@ -69,8 +109,17 @@ const data = reactive({
const { queryParams } = toRefs(data); const { queryParams } = toRefs(data);
const tableRef = ref(); const tableRef = ref();
watchEffect(() => {
ids.value = selectedProperties.value.map((el) => el[props.selectKey]);
});
const handleOpen = () => { const handleOpen = () => {
selectedProperties.value = cloneDeep(list.value); console.log("open");
if (list.value) {
selectedProperties.value = cloneDeep(list.value);
}
getList();
}; };
function getList() { function getList() {
@ -83,15 +132,13 @@ function getList() {
}); });
} }
watchEffect(() => {
ids.value = selectedProperties.value.map((el) => el[props.selectKey]);
});
const cancel = () => { const cancel = () => {
console.log("cancel");
selectedProperties.value = []; selectedProperties.value = [];
emit("update:modelValue", false); emit("update:modelValue", false);
}; };
/*监听单选事件*/
const handleSelect = (selection, row) => { const handleSelect = (selection, row) => {
const isCheck = const isCheck =
selection.findIndex((el) => el[props.selectKey] === row[props.selectKey]) > selection.findIndex((el) => el[props.selectKey] === row[props.selectKey]) >
@ -99,7 +146,7 @@ const handleSelect = (selection, row) => {
if (isCheck) { if (isCheck) {
/*添加选中*/ /*添加选中*/
const isIdNotExist = const isIdNotExist =
list.value.findIndex( selectedProperties.value.findIndex(
(el) => el[props.selectKey] === row[props.selectKey] (el) => el[props.selectKey] === row[props.selectKey]
) === -1; ) === -1;
if (isIdNotExist) { if (isIdNotExist) {
@ -113,6 +160,31 @@ const handleSelect = (selection, row) => {
} }
}; };
/*监听全选事件*/
const handleSelectAll = (selection) => {
if (selection.length > 0) {
/*全选*/
for (const selectionElement of selection) {
/*添加选中*/
const isIdNotExist =
selectedProperties.value.findIndex(
(el) => el[props.selectKey] === selectionElement[props.selectKey]
) === -1;
if (isIdNotExist) {
selectedProperties.value.push(selectionElement);
}
}
} else {
/*全不选*/
for (const dataElement of dataList.value) {
/*移除选中*/
selectedProperties.value = selectedProperties.value.filter(
(el) => el[props.selectKey] !== dataElement[props.selectKey]
);
}
}
};
/*选择模式下, 将选过的设为选中状态*/ /*选择模式下, 将选过的设为选中状态*/
const setRowSelected = () => { const setRowSelected = () => {
nextTick(() => { nextTick(() => {
@ -129,10 +201,20 @@ const setRowSelected = () => {
}; };
const confirmSelect = () => { const confirmSelect = () => {
console.log(selectedProperties.value); emit("confirm-select", selectedProperties.value);
}; };
getList(); defineExpose({
getList,
});
</script> </script>
<style scoped></style> <style lang="scss" scoped>
:deep(.el-table__header) {
.el-table-column--selection {
.el-checkbox {
//visibility: hidden;
}
}
}
</style>

View File

@ -86,13 +86,11 @@ export const firmwareLatestTypeOptions = [
{ {
label: "否", label: "否",
value: 0, value: 0,
tag: "danger",
elTagType: "danger", elTagType: "danger",
}, },
{ {
label: "是", label: "是",
value: 1, value: 1,
tag: "success",
elTagType: "success", elTagType: "success",
}, },
]; ];
@ -117,25 +115,21 @@ export const deviceStatusMap = [
{ {
label: "未激活", label: "未激活",
value: 1, value: 1,
tag: "info",
elTagType: "info", elTagType: "info",
}, },
{ {
label: "禁用", label: "禁用",
value: 2, value: 2,
tag: "danger",
elTagType: "danger", elTagType: "danger",
}, },
{ {
label: "在线", label: "在线",
value: 3, value: 3,
tag: "success",
elTagType: "success", elTagType: "success",
}, },
{ {
label: "离线", label: "离线",
value: 4, value: 4,
tag: "warning",
elTagType: "warning", elTagType: "warning",
}, },
]; ];
@ -178,17 +172,28 @@ export const isShadowDict = [
elTagType: "success", elTagType: "success",
}, },
]; ];
export const statusOptions = [ export const tenantStatusOptions = [
{
label: "正常",
value: "0",
elTagType: "success",
},
{
label: "禁用",
value: "1",
elTagType: "danger",
},
];
export const deviceGroupStatusDict = [
{ {
label: "正常", label: "正常",
value: "0", value: "0",
tag: "success",
elTagType: "success", elTagType: "success",
}, },
{ {
label: "禁用", label: "禁用",
value: "1", value: "1",
tag: "danger",
elTagType: "danger", elTagType: "danger",
}, },
]; ];

View File

@ -0,0 +1,462 @@
<template>
<div class="app-container">
<el-form
v-show="showSearch"
ref="queryRef"
:inline="true"
:model="queryParams"
label-position="left"
label-width="100px"
>
<el-form-item label="设备分组名称" prop="groupName">
<el-input
v-model="queryParams.groupName"
clearable
placeholder="请输入设备分组名称"
@keyup.enter="handleQuery"
/>
</el-form-item>
<!-- <el-form-item label="排序" prop="sort">-->
<!-- <el-input-->
<!-- v-model="queryParams.sort"-->
<!-- clearable-->
<!-- placeholder="请输入排序"-->
<!-- @keyup.enter="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="租户ID" prop="tenantId">-->
<!-- <el-input-->
<!-- v-model="queryParams.tenantId"-->
<!-- clearable-->
<!-- placeholder="请输入租户ID"-->
<!-- @keyup.enter="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item>
<el-button icon="Search" type="primary" @click="handleQuery"
>搜索
</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
v-hasPermi="['device:group:add']"
icon="Plus"
plain
type="primary"
@click="handleAdd"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['device:group:edit']"
:disabled="single"
icon="Edit"
plain
type="success"
@click="handleUpdate"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['device:group:remove']"
:disabled="multiple"
icon="Delete"
plain
type="danger"
@click="handleDelete"
>删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
v-hasPermi="['device:group:export']"
icon="Download"
plain
type="warning"
@click="handleExport"
>导出
</el-button>
</el-col>
<right-toolbar
v-model:showSearch="showSearch"
@queryTable="getList"
></right-toolbar>
</el-row>
<el-table
v-loading="loading"
:data="groupList"
@selection-change="handleSelectionChange"
>
<el-table-column align="center" type="selection" width="55" />
<el-table-column align="center" label="设备分组ID" prop="groupId" />
<el-table-column align="center" label="设备分组名称" prop="groupName" />
<!-- <el-table-column align="center" label="排序" prop="sort" />-->
<el-table-column align="center" label="备注" prop="remark" />
<el-table-column align="center" label="状态" prop="status">
<template #default="{ row }">
<dict-tag
:options="deviceGroupStatusDict"
:value="[row.status]"
effect="dark"
size="small"
/>
</template>
</el-table-column>
<!-- <el-table-column align="center" label="租户ID" prop="tenantId" />-->
<el-table-column
align="center"
class-name="small-padding fixed-width"
label="操作"
>
<template #default="{ row }">
<el-button
v-hasPermi="['device:group:edit']"
icon="Edit"
link
type="primary"
@click="handleUpdate(row)"
>修改
</el-button>
<el-button
v-hasPermi="['device:group:remove']"
icon="Delete"
link
type="primary"
@click="handleDelete(row)"
>删除
</el-button>
<el-button
icon="pointer"
link
type="primary"
@click="
() => {
activeGroupId = row.groupId;
showSelectDevice = true;
}
"
>分配设备
</el-button>
<el-button
icon="list"
link
type="primary"
@click="
() => {
activeGroupId = row.groupId;
showAssignedDevice = true;
}
"
>
已分配设备
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 已分配设备列表-->
<table-select
ref="assignedDeviceRef"
v-model="showAssignedDevice"
:request-method="listAssignedDevice(activeGroupId)"
:table-struct="[
{
label: 'ID',
prop: 'deviceId',
},
{ label: '设备名称', prop: 'deviceName' },
{
label: '操作',
operate: [
{
label: '取消分配',
type: 'danger',
icon: 'delete',
onClick: async (row) => {
unAssignDevice(row.deviceId).then((resp) => {
ElMessage.success('已取消分配');
assignedDeviceRef.getList();
});
},
},
],
},
]"
select-key="deviceId"
@confirm-select="confirmUnassignedDevice"
/>
<!-- 选择要分配的设备-->
<table-select
v-model="showSelectDevice"
:request-method="listUnassignedDevice(activeGroupId)"
:table-struct="[
{
label: 'ID',
prop: 'deviceId',
},
{
label: '设备名称',
prop: 'deviceName',
},
]"
select-key="deviceId"
@confirm-select="handleAssignDevice"
/>
<pagination
v-show="total > 0"
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNum"
:total="total"
@pagination="getList"
/>
<!-- 添加或修改设备分组对话框 -->
<el-dialog v-model="open" :title="title" append-to-body width="500px">
<el-form
ref="groupRef"
:model="form"
:rules="rules"
label-position="left"
label-width="120px"
>
<el-form-item label="设备分组名称" prop="groupName">
<el-input v-model="form.groupName" placeholder="请输入设备分组名称" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="form.remark"
placeholder="请输入内容"
type="textarea"
/>
</el-form-item>
<!-- <el-form-item label="租户ID" prop="tenantId">-->
<!-- <el-input v-model="form.tenantId" placeholder="请输入租户ID" />-->
<!-- </el-form-item>-->
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script name="Group" setup>
import {
addGroup,
assignDevice,
delGroup,
getGroup,
listGroup,
unAssignDevice,
updateGroup,
} from "@/api/device/group";
import DictTag from "@/components/DictTag/index.vue";
import { deviceGroupStatusDict } from "@/constant/dict";
import { getCurrentInstance, reactive, ref, toRefs } from "vue";
import TableSelect from "@/components/TableSelect/index.vue";
import { listDevice } from "@/api/iot/device";
import { ElMessage } from "element-plus";
const { proxy } = getCurrentInstance();
const groupList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const showAssignedDevice = ref(false); /*显示已分配的设备列表*/
const showSelectDevice = ref(false); /*显示选择设备窗口*/
const assignedDeviceRef = ref();
const activeGroupId = ref();
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
groupName: null,
sort: null,
status: null,
tenantId: null,
},
rules: {
groupName: [
{
required: true,
message: "请输入分组名称",
trigger: "blur",
},
],
},
});
const { queryParams, form, rules } = toRefs(data);
/** 查询设备分组列表 */
function getList() {
loading.value = true;
listGroup(queryParams.value).then((response) => {
groupList.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
// 取消按钮
function cancel() {
open.value = false;
reset();
}
// 表单重置
function reset() {
form.value = {
groupId: null,
groupName: null,
sort: null,
remark: null,
createTime: null,
createBy: null,
status: null,
tenantId: null,
};
proxy.resetForm("groupRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.groupId);
single.value = selection.length !== 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加设备分组";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const _groupId = row.groupId || ids.value;
getGroup(_groupId).then((response) => {
form.value = response.data;
open.value = true;
title.value = "修改设备分组";
});
}
const listUnassignedDevice = (groupId) => (queryParams) =>
listDevice({
...queryParams,
searchValue: 1,
groupId,
});
const listAssignedDevice = (groupId) => (queryParams) =>
listDevice({
...queryParams,
groupId,
});
/*确认取消分配设备*/
const confirmUnassignedDevice = async (data) => {
if (data.length) {
const _ids = data.map((el) => el.deviceId).join(",");
await unAssignDevice(_ids);
showAssignedDevice.value = false;
ElMessage.success("取消分配设备成功");
} else {
ElMessage.error("清选择要取消分配的设备");
}
};
/** 提交按钮 */
function submitForm() {
proxy.$refs["groupRef"].validate((valid) => {
if (valid) {
if (form.value.groupId != null) {
updateGroup(form.value).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addGroup(form.value).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const _groupIds = row.groupId || ids.value;
proxy.$modal
.confirm('是否确认删除设备分组编号为"' + _groupIds + '"的数据项?')
.then(function () {
return delGroup(_groupIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 导出按钮操作 */
function handleExport() {
proxy.download(
"device/group/export",
{
...queryParams.value,
},
`group_${new Date().getTime()}.xlsx`
);
}
const handleAssignDevice = async (data) => {
if (data.length) {
const _ids = data.map((el) => el.deviceId).join(",");
await assignDevice(activeGroupId.value, _ids);
ElMessage.success("成功");
showSelectDevice.value = false;
} else {
ElMessage.error("清选择要分配的设备");
}
};
getList();
</script>

View File

@ -33,13 +33,13 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="设备状态" prop="status"> <!-- <el-form-item label="设备状态" prop="status">-->
<el-switch <!-- <el-switch-->
v-model="queryParams.status" <!-- v-model="queryParams.status"-->
:active-value="1" <!-- :active-value="1"-->
:inactive-value="0" <!-- :inactive-value="0"-->
/> <!-- />-->
</el-form-item> <!-- </el-form-item>-->
<!-- <el-form-item label="用户ID" prop="userId">--> <!-- <el-form-item label="用户ID" prop="userId">-->
<!-- <el-input--> <!-- <el-input-->
<!-- v-model="queryParams.userId"--> <!-- v-model="queryParams.userId"-->
@ -146,8 +146,8 @@
<!-- </el-form-item>--> <!-- </el-form-item>-->
<el-form-item> <el-form-item>
<el-button icon="Search" type="primary" @click="handleQuery" <el-button icon="Search" type="primary" @click="handleQuery"
>搜索</el-button >搜索
> </el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -256,7 +256,14 @@
</el-table-column> </el-table-column>
<!-- <el-table-column align="center" label="设备摘要" prop="summary" />--> <!-- <el-table-column align="center" label="设备摘要" prop="summary" />-->
<!-- <el-table-column align="center" label="图片地址" prop="imgUrl" />--> <!-- <el-table-column align="center" label="图片地址" prop="imgUrl" />-->
<el-table-column align="center" label="描述" prop="remark" /> <el-table-column align="center" label="分组名称" prop="groupName">
<template #default="{ row }">
<el-tag v-if="row.groupName" type="primary">
{{ row.groupName }}
</el-tag>
</template>
</el-table-column>
<el-table-column <el-table-column
align="center" align="center"
class-name="small-padding fixed-width" class-name="small-padding fixed-width"
@ -491,6 +498,7 @@ import { deviceStatusMap, isShadowDict, locationWayMap } from "@/constant/dict";
import UserTreeSelect from "@/components/UserTreeSelect/index.vue"; import UserTreeSelect from "@/components/UserTreeSelect/index.vue";
import { getCurrentInstance, reactive, ref, toRefs } from "vue"; import { getCurrentInstance, reactive, ref, toRefs } from "vue";
import DictTag from "@/components/DictTag/index.vue"; import DictTag from "@/components/DictTag/index.vue";
import { parseTime } from "@/utils/ruoyi";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();

View File

@ -312,8 +312,8 @@
size="small" size="small"
type="danger" type="danger"
@click="removeTriggerItem(index)" @click="removeTriggerItem(index)"
>删除</el-button >删除
> </el-button>
</el-col> </el-col>
</el-row> </el-row>
@ -578,13 +578,7 @@
</el-button> </el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-button <el-button link size="small" type="primary" @click="addActionItem"
icon="
"
link
size="small"
type="primary"
@click="addActionItem"
>添加执行动作 >添加执行动作
</el-button> </el-button>
</el-form-item> </el-form-item>
@ -592,8 +586,8 @@
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button v-if="productId" type="primary" @click="submitForm" <el-button v-if="productId" type="primary" @click="submitForm"
> </el-button >
> </el-button>
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
</div> </div>
</template> </template>

View File

@ -127,7 +127,7 @@
<el-table-column align="center" label="状态" prop="status"> <el-table-column align="center" label="状态" prop="status">
<template #default="{ row }"> <template #default="{ row }">
<dict-tag <dict-tag
:options="statusOptions" :options="tenantStatusOptions"
:value="[row.status]" :value="[row.status]"
size="small" size="small"
/> />
@ -331,7 +331,7 @@ import {
updateTenant, updateTenant,
} from "@/api/system/tenant"; } from "@/api/system/tenant";
import { resetUserPwd } from "@/api/system/user"; import { resetUserPwd } from "@/api/system/user";
import { statusOptions } from "@/constant/dict"; import { tenantStatusOptions } from "@/constant/dict";
import DictTag from "@/components/DictTag/index.vue"; import DictTag from "@/components/DictTag/index.vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();