增加继电器管理界面

This commit is contained in:
zy 2025-12-03 18:32:16 +08:00
parent fcdb5c5a49
commit 071832744b
13 changed files with 1401 additions and 45 deletions

View File

@ -150,7 +150,7 @@
const { mode } = unref<Recordable>(getBindValue); const { mode } = unref<Recordable>(getBindValue);
let changeValue:any; let changeValue:any;
// //
//update-begin---author:wangshuai ---date:20230216 for[QQYUN-4290],change------------ //update-begin---author:wangshuai ---date:20230216 for[QQYUN-4290],change------------
//statechange //statechange
if (mode === 'multiple') { if (mode === 'multiple') {
@ -171,7 +171,7 @@
emit('update:value',changeValue) emit('update:value',changeValue)
//update-end---author:wangshuai ---date:20230403 forissues/4507JDictSelectTag使Expected Function, got Array------------ //update-end---author:wangshuai ---date:20230403 forissues/4507JDictSelectTag使Expected Function, got Array------------
//update-end---author:wangshuai ---date:20230216 for[QQYUN-4290],change------------ //update-end---author:wangshuai ---date:20230216 for[QQYUN-4290],change------------
// nextTick(() => formItemContext.onFieldChange()); // nextTick(() => formItemContext.onFieldChange());
} }

View File

@ -21,6 +21,8 @@ enum Api {
cameraStopApi = '/appmana/survDeviceDeploy/cameraStop', cameraStopApi = '/appmana/survDeviceDeploy/cameraStop',
getDeviceCateList = '/appmana/fDictDeviceCate/getDeviceCateList', getDeviceCateList = '/appmana/fDictDeviceCate/getDeviceCateList',
getDeviceList='/appmana/survDeviceDeploy/getDeviceList', getDeviceList='/appmana/survDeviceDeploy/getDeviceList',
syncRelays = '/api/farm/fDeviceDeployRelay/syncRelays',
getRelayList = '/appmana/survDeviceDeploy/getRelayList',
} }
/** /**
@ -179,3 +181,33 @@ export const getDeviceCateList = (params) => defHttp.get({ url: Api.getDeviceCat
* @param params * @param params
*/ */
export const getDeviceList = (params) => defHttp.post({ url: Api.getDeviceList, params }); export const getDeviceList = (params) => defHttp.post({ url: Api.getDeviceList, params });
/**
*
* @param params
* @param handleSuccess
*/
export const relaySync = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认同步',
content: '该操作会删除所有当前已绑定继电器,是否继续',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.post({url: Api.syncRelays, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
*
* @param params
* @param isUpdate
*/
export const getRelayList = (params) => {
return defHttp.get({ url: Api.getRelayList,params}, { isTransformResponse: false });
}

View File

@ -99,7 +99,9 @@
<ControlModal ref="qiuFaModal" @success="handleSuccess"></ControlModal> <ControlModal ref="qiuFaModal" @success="handleSuccess"></ControlModal>
<!--字典配置抽屉--> <!--字典配置抽屉-->
<ZhiBiaoList @register="registerDrawer" /> <ZhiBiaoList @register="registerDrawer" />
<SetupList @register="registerSetupDrawer" />
<RelayGroupList @register="registerGroupDrawer" />
</div> </div>
</template> </template>
@ -108,7 +110,7 @@
import { BasicTable, useTable, TableAction } from '/@/components/Table'; import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage'; import { useListPage } from '/@/hooks/system/useListPage';
import { columns } from './SurvDeviceDeploy.data'; import { columns } from './SurvDeviceDeploy.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl,deviceInit,getDeviceCateList} from './SurvDeviceDeploy.api'; import { list, deleteOne, batchDelete, getImportUrl, getExportUrl,deviceInit,getDeviceCateList,relaySync} from './SurvDeviceDeploy.api';
import { downloadFile } from '/@/utils/common/renderUtils'; import { downloadFile } from '/@/utils/common/renderUtils';
import SurvDeviceDeployModal from './components/SurvDeviceDeployModal.vue' import SurvDeviceDeployModal from './components/SurvDeviceDeployModal.vue'
import ControlModal from './components/ControlModal.vue' import ControlModal from './components/ControlModal.vue'
@ -116,7 +118,8 @@
import { getStationList } from '../station/SurvStationInfo.api' import { getStationList } from '../station/SurvStationInfo.api'
import { useDrawer } from '/@/components/Drawer'; import { useDrawer } from '/@/components/Drawer';
import ZhiBiaoList from './components/ZhiBiaoList.vue'; import ZhiBiaoList from './components/ZhiBiaoList.vue';
import SetupList from './components/SetupList.vue';
import RelayGroupList from './components/RelayGroupList.vue';
//drawer //drawer
const [registerDrawer, { openDrawer }] = useDrawer(); const [registerDrawer, { openDrawer }] = useDrawer();
@ -126,6 +129,8 @@
const registerModal = ref(); const registerModal = ref();
const qiuFaModal = ref(); const qiuFaModal = ref();
const open = ref<boolean>(false); const open = ref<boolean>(false);
const [registerSetupDrawer, { openDrawer: openDrawerSetup }] = useDrawer();
const [registerGroupDrawer, { openDrawer: openDrawerGroup }] = useDrawer();
//table //table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({ const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
@ -224,7 +229,7 @@
function handleControl(record) { function handleControl(record) {
qiuFaModal.value.disableSubmit = false; qiuFaModal.value.disableSubmit = false;
qiuFaModal.value.showup({ qiuFaModal.value.showup({
deployCode: record.deployCode, deployId: record.id,
}); });
} }
@ -294,6 +299,56 @@
} }
] ]
} }
else if(record.deployType == 'control_cab' ){
return [
{
label: '继电器同步',
onClick: handleRelay.bind(null, record),
},
{
label: '继电器分组',
onClick: handleRelayGroup.bind(null, record),
},
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
placement: "leftBottom",
confirm: handleDelete.bind(null, record),
}
}
]
}
else if(record.deployType =="water_orient" || record.deployType =="water_live"){
return [
{
label: '控制配置',
onClick: handleRelayDetail.bind(null, record),
},
// {
// label: '',
// onClick: handleRelay.bind(null, record),
// },
{
label: '继电器分组',
onClick: handleRelayGroup.bind(null, record),
},
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
placement: "leftBottom",
confirm: handleDelete.bind(null, record),
}
}
]
}
else{ else{
return [ return [
{ {
@ -311,6 +366,31 @@
} }
/**
* 继电器明细
*/
async function handleRelayDetail(record: Recordable) {
openDrawerSetup(true, {
id: record.id,
});
}
/**
* 继电器分组
*/
async function handleRelayGroup(record: Recordable) {
openDrawerGroup(true, {
id: record.id,
});
}
/**
* 继电器同步
*/
async function handleRelay(record: Recordable) {
await relaySync({ ids: record.id }, handleSuccess);
}
/** /**
* 查询 * 查询
*/ */

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal title="球阀控制" :width="width" :body-style="bodystyle" :visible="visible" @ok="handleOk" <a-modal title="球阀控制" :width="width" :body-style="bodystyle" :visible="visible" @ok="handleOk"
@cancel="handleCancel" footer="" > @cancel="handleCancel" footer="" >
@ -10,11 +10,8 @@
<a-input v-model:value="formState.dataTime" disabled="true"/> <a-input v-model:value="formState.dataTime" disabled="true"/>
</a-form-item> </a-form-item>
<a-form-item label="1#球阀"> <a-form-item :label="item.relayName" v-for="item in formState.relayList" :key="item.id">
<a-switch v-model:checked="formState.delivery1" checked-children="打开" un-checked-children="关闭" @change="on1SwitchChange"/> <a-switch v-model:checked="formState[item.id]" checked-children="打开" un-checked-children="关闭" @change="(checked) => switchChange(checked, item)"/>
</a-form-item>
<a-form-item label="2#球阀">
<a-switch v-model:checked="formState.delivery2" checked-children="打开" un-checked-children="关闭" @change="on2SwitchChange"/>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>
@ -26,26 +23,29 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted,ref, reactive,nextTick, defineExpose } from 'vue'; import { onMounted,ref, reactive,nextTick, defineExpose } from 'vue';
import type { UnwrapRef } from 'vue'; import type { UnwrapRef } from 'vue';
import { getValveStatus,sendDeviceCmd } from '../SurvDeviceDeploy.api'; import { getValveStatus,sendDeviceCmd,getRelayList } from '../SurvDeviceDeploy.api';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
const bodystyle = { const bodystyle = {
height: '200px', height: '250px',
margin: '20px', margin: '20px',
} }
interface FormState { interface FormState {
deployCode:string; deployCode:string;
delivery1: boolean; delivery1: boolean;
delivery2: boolean; delivery2: boolean;
delivery3: boolean;
dataTime:string; dataTime:string;
relayList:[];
} }
const formState: UnwrapRef<FormState> = reactive({ const formState: UnwrapRef<FormState> = reactive({
deployCode:'', deployCode:'',
delivery1: false, delivery1: false,
delivery2: false, delivery2: false,
dataTime:'', dataTime:'',
relayList:[],
}); });
const labelCol = { style: { width: '150px' } }; const labelCol = { style: { width: '150px' } };
@ -65,6 +65,24 @@ const openMessage = () => {
function switchChange(checked,relay) {
openMessage();
let ops = "";
if(checked === true){
ops = "1";
}else if(checked === false){
ops = "0";
}
let parmas = {relayId:relay.id,ops:ops};
sendDeviceCmd(parmas).then((res) => {
if (res.code == 500) {//
formState[relay.id] = false;
message.error({ content: res.message, key, duration: 2 });
}
});
}
function on1SwitchChange(checked) { function on1SwitchChange(checked) {
openMessage(); openMessage();
if(checked === true){ if(checked === true){
@ -72,14 +90,14 @@ const openMessage = () => {
if (res.code == 500) {// if (res.code == 500) {//
formState.delivery1=false; formState.delivery1=false;
message.error({ content: res.message, key, duration: 2 }); message.error({ content: res.message, key, duration: 2 });
} }
}); });
}else if(checked === false){ }else if(checked === false){
sendDeviceCmd({deployCode:formState.deployCode,os:"00",valveCode:"01"}).then((res) => { sendDeviceCmd({deployCode:formState.deployCode,os:"00",valveCode:"01"}).then((res) => {
if (res.code == 500) {// if (res.code == 500) {//
formState.delivery1=true; formState.delivery1=true;
message.error({ content: res.message, key, duration: 2 }); message.error({ content: res.message, key, duration: 2 });
} }
}); });
} }
} }
@ -92,7 +110,7 @@ const openMessage = () => {
if (res.code == 500) { if (res.code == 500) {
formState.delivery2=false; formState.delivery2=false;
message.error({ content: res.message, key, duration: 2 }); message.error({ content: res.message, key, duration: 2 });
} }
}); });
}else if(checked === false){ }else if(checked === false){
sendDeviceCmd({deployCode:formState.deployCode,os:"00",valveCode:"02"}).then((res) => { sendDeviceCmd({deployCode:formState.deployCode,os:"00",valveCode:"02"}).then((res) => {
@ -110,27 +128,38 @@ const openMessage = () => {
function showup(record) { function showup(record) {
title.value = '球阀控制'; title.value = '球阀控制';
visible.value = true; visible.value = true;
getValveStatus({ deployCode: record.deployCode }).then((res) => {
getRelayList({ deployId: record.deployId }).then((res) => {
if (res.code == 200) { if (res.code == 200) {
formState.relayList = res.result.relayList;
formState.dataTime=res.result.dataTime formState.dataTime=res.result.dataTime
formState.deployCode = record.deployCode
if(res.result.firstValveStatus == "01"){
formState.delivery1=true
}else{
formState.delivery1=false
}
if(res.result.secondValveStatus == "01"){
formState.delivery2=true
}else{
formState.delivery2=false
}
} else { } else {
} }
}) })
} }
// getValveStatus({ deployCode: record.deployCode }).then((res) => {
// if (res.code == 200) {
// formState.dataTime=res.result.dataTime
// formState.deployCode = record.deployCode
// if(res.result.firstValveStatus == "01"){
// formState.delivery1=true
// }else{
// formState.delivery1=false
// }
// if(res.result.secondValveStatus == "01"){
// formState.delivery2=true
// }else{
// formState.delivery2=false
// }
// } else {
// }
// })
/** /**
* 编辑 * 编辑
* @param record * @param record
@ -142,7 +171,7 @@ const openMessage = () => {
registerForm.value.edit(record); registerForm.value.edit(record);
}); });
} }
/** /**
* 确定按钮点击事件 * 确定按钮点击事件
*/ */

View File

@ -0,0 +1,121 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/appmana/survDeviceDeployRelaygroup/list',
save='/appmana/survDeviceDeployRelaygroup/add',
edit='/appmana/survDeviceDeployRelaygroup/edit',
deleteOne = '/appmana/survDeviceDeployRelaygroup/delete',
deleteBatch = '/appmana/survDeviceDeployRelaygroup/deleteBatch',
importExcel = '/appmana/survDeviceDeployRelaygroup/importExcel',
exportXls = '/appmana/survDeviceDeployRelaygroup/exportXls',
itemList = '/appmana/survDeviceDeployRelaygroup/list',
deleteItem = '/appmana/survDeviceDeployRelaygroup/delete',
itemSave = '/appmana/survDeviceDeployRelaygroup/add',
itemEdit = '/appmana/survDeviceDeployRelaygroup/edit',
itemCheck ='/appmana/survDeviceDeployRelaygroup/itemCheck',
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
*/
export const getImportUrl = Api.importExcel;
/**
*
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
*
* @param params
* @param handleSuccess
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
*
* @param params
* @param handleSuccess
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
*
* @param params
* @param isUpdate
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params }, { isTransformResponse: false });
}
/**
*
* @param params
*/
export const saveOrUpdateDictItem = (params, isUpdate) => {
let url = isUpdate ? Api.itemEdit : Api.itemSave;
return defHttp.post({ url: url, params });
};
/**
*
* @param params
*/
export const saveOrUpdateDict = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
/**
*
* @param params
*/
export const itemCheck = (params) => defHttp.get({ url: Api.itemCheck, params }, { isTransformResponse: false });
/**
*
* @param params
*/
export const itemList = (params) => defHttp.get({ url: Api.itemList, params });
/**
*
* @param params
*/
export const deleteItem = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteItem, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};

View File

@ -0,0 +1,234 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { itemCheck} from './RelayGroup.api';
//列表数据
export const columns: BasicColumn[] = [
{
title: '创建者',
align: "center",
dataIndex: 'createId'
},
{
title: '更新者',
align: "center",
dataIndex: 'updateId'
},
{
title: '设备主键',
align: "center",
dataIndex: 'equId'
},
{
title: '指标code',
align: "center",
dataIndex: 'code'
},
{
title: '指标名称',
align: "center",
dataIndex: 'name'
},
{
title: '低阈值',
align: "center",
dataIndex: 'valLow'
},
{
title: '高阈值',
align: "center",
dataIndex: 'valHeight'
},
{
title: '计量单位',
align: "center",
dataIndex: 'nuit'
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '创建者',
field: 'createId',
component: 'Input',
},
{
label: '更新者',
field: 'updateId',
component: 'Input',
},
{
label: '设备主键',
field: 'equId',
component: 'Input',
},
{
label: '指标code',
field: 'code',
component: 'Input',
},
{
label: '指标名称',
field: 'name',
component: 'Input',
},
{
label: '低阈值',
field: 'valLow',
component: 'InputNumber',
},
{
label: '高阈值',
field: 'valHeight',
component: 'InputNumber',
},
{
label: '计量单位',
field: 'nuit',
component: 'Input',
},
{
label: '排序',
field: 'sortNo',
component: 'InputNumber',
},
// TODO 主键隐藏字段目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
export const itemFormSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
label: '',
field: 'deployId',
component: 'Input',
show: false,
},
{
label: '分组名称',
field: 'groupName',
component: 'Input',
dynamicRules: ({ values, model }) => {
return [
{
required: true,
validator: (_, value) => {
if (!value) {
return Promise.reject('请输入属性编码');
}
if (new RegExp("[`~!@#$^&*()=|{}'.<>《》/?!¥()—【】‘;:”“。,、?]").test(value)) {
return Promise.reject('数据值不能包含特殊字符!');
}
return new Promise<void>((resolve, reject) => {
console.log('wwwwwww',model)
let params = {
deployId: model.deployId,
groupName: value,
id:model.id
};
itemCheck(params)
.then((res) => {
res.success ? resolve() : reject(res.message || '校验失败');
})
.catch((err) => {
reject(err.message || '验证失败');
});
});
},
},
];
},
},
{
label: '分组种类',
field: 'groupType',
required: true,
component: 'JDictSelectTag',
componentProps: {
dictCode: 'iot_relay_group_type',
placeholder: '请选择继电器种类',
stringToNumber: false,
},
},
{
field: 'isEnable',
label: '是否启用',
defaultValue: 1,
component: 'JDictSelectTag',
componentProps: {
type: 'radioButton',
dictCode: 'yn',
stringToNumber: true,
},
},
{
label: '备注',
field: 'groupNotes',
required: false,
component: 'Input',
},
{
label: '排序',
field: 'sortNo',
required: false,
component: 'InputNumber',
defaultValue: 1
},
];
export const dictItemColumns: BasicColumn[] = [
{
title: '分组名称',
dataIndex: 'groupName',
width: 80,
},
{
title: '分组类别',
dataIndex: 'groupTypeName',
width: 80,
},
{
title: '是否启用',
dataIndex: 'isEnable',
width: 80,
customRender: ({ text }) => {
const color = text == '1' ? 'green' : text == '0' ? 'red' : 'gray';
return render.renderTag(render.renderDict(text, 'dict_item_status'), color);
},
},
{
title: '排序',
dataIndex: 'sortNo',
width: 80,
},
];
export const dictItemSearchFormSchema: FormSchema[] = [
{
label: '名称',
field: 'relayName',
component: 'Input',
},
];

View File

@ -0,0 +1,132 @@
<template>
<BasicDrawer v-bind="$attrs" @register="registerDrawer" title="指标列表" width="800px">
<BasicTable @register="registerTable" :rowClassName="getRowClassName">
<template #tableTitle>
<a-button type="primary" @click="handleCreate"> 新增</a-button>
</template>
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
</BasicDrawer>
<RelayModal @register="registerModal" @success="reload" :deployId="deployId" />
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicDrawer, useDrawerInner } from '/src/components/Drawer';
import { BasicTable, useTable, TableAction } from '/src/components/Table';
import { useModal } from '/src/components/Modal';
import { useDesign } from '/@/hooks/web/useDesign';
import RelayModal from './RelayGroupModal.vue';
import { dictItemColumns, dictItemSearchFormSchema } from './RelayGroup.data';
import { itemList, deleteItem } from './RelayGroup.api';
import { ColEx } from '/@/components/Form/src/types';
const { prefixCls } = useDesign('row-invalid');
const deployId = ref('');
//model
const [registerModal, { openModal }] = useModal();
const [registerDrawer] = useDrawerInner(async (data) => {
deployId.value = data.id;
setProps({ searchInfo: { deployId: unref(deployId) } });
reload();
});
//
const adaptiveColProps: Partial<ColEx> = {
xs: 24, // <576px
sm: 24, // 576px
md: 24, // 768px
lg: 12, // 992px
xl: 12, // 1200px
xxl: 8, // 1600px
};
const [registerTable, { reload, setProps }] = useTable({
api: itemList,
columns: dictItemColumns,
formConfig: {
baseColProps: adaptiveColProps,
labelAlign: 'right',
labelCol: {
offset: 1,
xs: 24,
sm: 24,
md: 24,
lg: 9,
xl: 7,
xxl: 4,
},
wrapperCol: {},
schemas: dictItemSearchFormSchema,
autoSubmitOnEnter: true,
},
striped: true,
useSearchForm: true,
bordered: true,
showIndexColumn: false,
canResize: false,
immediate: false,
actionColumn: {
width: 100,
title: '操作',
dataIndex: 'action',
slots: { customRender: 'action' },
fixed: undefined,
},
});
/**
* 新增
*/
function handleCreate() {
openModal(true, {
isUpdate: false,
});
}
/**
* 编辑
*/
function handleEdit(record) {
openModal(true, {
record,
isUpdate: true,
});
}
/**
* 删除
*/
async function handleDelete(record) {
await deleteItem({ id: record.id }, reload);
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
];
}
function getRowClassName(record) {
return record.status == 0 ? prefixCls : '';
}
</script>
<style scoped lang="less">
@prefix-cls: ~'@{namespace}-row-invalid';
:deep(.@{prefix-cls}) {
background: #f4f4f4;
color: #bababa;
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" width="800px">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { defineProps, ref, computed, unref, reactive } from 'vue';
import { BasicModal, useModalInner } from '/src/components/Modal';
import { BasicForm, useForm } from '/src/components/Form';
import { itemFormSchema } from './RelayGroup.data';
import { saveOrUpdateDictItem } from './RelayGroup.api';
import { stringify } from 'querystring';
// Emits
const emit = defineEmits(['success', 'register']);
const props = defineProps({ deployId: String });
const isUpdate = ref(true);
//
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: itemFormSchema,
showActionButtonGroup: false,
mergeDynamicData: props,
labelCol: {
xs: { span: 24 },
sm: { span: 4 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 18 },
},
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//
await setFieldsValue({
...data.record,
});
}
});
//
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//
async function handleSubmit() {
try {
const values = await validate();
values.deployId = props.deployId;
setModalProps({ confirmLoading: true });
//
await saveOrUpdateDictItem(values, isUpdate.value);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,132 @@
<template>
<BasicDrawer v-bind="$attrs" @register="registerDrawer" title="继电器列表" width="800px">
<BasicTable @register="registerTable" :rowClassName="getRowClassName">
<template #tableTitle>
<a-button type="primary" @click="handleCreate"> 新增</a-button>
</template>
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
</BasicDrawer>
<SetupModal @register="registerModal" @success="reload" :deployId="deployId" />
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicDrawer, useDrawerInner } from '/src/components/Drawer';
import { BasicTable, useTable, TableAction } from '/src/components/Table';
import { useModal } from '/src/components/Modal';
import { useDesign } from '/@/hooks/web/useDesign';
import SetupModal from './SetupModal.vue';
import { dictItemColumns, dictItemSearchFormSchema } from './SetupRelay.data';
import { itemList, deleteItem } from './SetupRelay.api';
import { ColEx } from '/@/components/Form/src/types';
const { prefixCls } = useDesign('row-invalid');
const deployId = ref('');
//model
const [registerModal, { openModal }] = useModal();
const [registerDrawer] = useDrawerInner(async (data) => {
deployId.value = data.id;
setProps({ searchInfo: { deployId: unref(deployId) } });
reload();
});
//
const adaptiveColProps: Partial<ColEx> = {
xs: 24, // <576px
sm: 24, // 576px
md: 24, // 768px
lg: 12, // 992px
xl: 12, // 1200px
xxl: 8, // 1600px
};
const [registerTable, { reload, setProps }] = useTable({
api: itemList,
columns: dictItemColumns,
formConfig: {
baseColProps: adaptiveColProps,
labelAlign: 'right',
labelCol: {
offset: 1,
xs: 24,
sm: 24,
md: 24,
lg: 9,
xl: 7,
xxl: 4,
},
wrapperCol: {},
schemas: dictItemSearchFormSchema,
autoSubmitOnEnter: true,
},
striped: true,
useSearchForm: true,
bordered: true,
showIndexColumn: false,
canResize: false,
immediate: false,
actionColumn: {
width: 100,
title: '操作',
dataIndex: 'action',
slots: { customRender: 'action' },
fixed: undefined,
},
});
/**
* 新增
*/
function handleCreate() {
openModal(true, {
isUpdate: false,
});
}
/**
* 编辑
*/
function handleEdit(record) {
openModal(true, {
record,
isUpdate: true,
});
}
/**
* 删除
*/
async function handleDelete(record) {
await deleteItem({ id: record.id }, reload);
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
];
}
function getRowClassName(record) {
return record.status == 0 ? prefixCls : '';
}
</script>
<style scoped lang="less">
@prefix-cls: ~'@{namespace}-row-invalid';
:deep(.@{prefix-cls}) {
background: #f4f4f4;
color: #bababa;
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" width="800px">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { defineProps, ref, computed, unref, reactive } from 'vue';
import { BasicModal, useModalInner } from '/src/components/Modal';
import { BasicForm, useForm } from '/src/components/Form';
import { itemFormSchema } from './SetupRelay.data';
import { saveOrUpdateDictItem } from './SetupRelay.api';
import { stringify } from 'querystring';
// Emits
const emit = defineEmits(['success', 'register']);
const props = defineProps({ deployId: String });
const isUpdate = ref(true);
//
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: itemFormSchema,
showActionButtonGroup: false,
mergeDynamicData: props,
labelCol: {
xs: { span: 24 },
sm: { span: 4 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 18 },
},
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//
await setFieldsValue({
...data.record,
});
}
});
//
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//
async function handleSubmit() {
try {
const values = await validate();
values.deployId = props.deployId;
setModalProps({ confirmLoading: true });
//
await saveOrUpdateDictItem(values, isUpdate.value);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,127 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/appmana/survDeviceDeployRelay/list',
save='/appmana/survDeviceDeployRelay/add',
edit='/appmana/survDeviceDeployRelay/edit',
deleteOne = '/appmana/survDeviceDeployRelay/delete',
deleteBatch = '/appmana/survDeviceDeployRelay/deleteBatch',
importExcel = '/appmana/survDeviceDeployRelay/importExcel',
exportXls = '/appmana/survDeviceDeployRelay/exportXls',
itemList = '/appmana/survDeviceDeployRelay/list',
deleteItem = '/appmana/survDeviceDeployRelay/delete',
itemSave = '/appmana/survDeviceDeployRelay/add',
itemEdit = '/appmana/survDeviceDeployRelay/edit',
relayItemCheck ='/appmana/survDeviceDeployRelay/relayItemCheck',
allRelay = '/appmana/survDeviceDeployRelay/getRelayType'
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
*/
export const getImportUrl = Api.importExcel;
/**
*
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
*
* @param params
* @param handleSuccess
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
*
* @param params
* @param handleSuccess
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
*
* @param params
* @param isUpdate
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params }, { isTransformResponse: false });
}
/**
*
* @param params
*/
export const saveOrUpdateDictItem = (params, isUpdate) => {
let url = isUpdate ? Api.itemEdit : Api.itemSave;
return defHttp.post({ url: url, params });
};
/**
*
* @param params
*/
export const saveOrUpdateDict = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
/**
*
* @param params
*/
export const relayItemCheck = (params) => defHttp.get({ url: Api.relayItemCheck, params }, { isTransformResponse: false });
/**
*
* @param params
*/
export const itemList = (params) => defHttp.get({ url: Api.itemList, params });
/**
*
* @param params
*/
export const deleteItem = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteItem, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const relayTypeList = (params) => defHttp.get({ url: Api.allRelay, params });

View File

@ -0,0 +1,300 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { relayItemCheck,relayTypeList} from './SetupRelay.api';
//列表数据
export const columns: BasicColumn[] = [
{
title: '创建者',
align: "center",
dataIndex: 'createId'
},
{
title: '更新者',
align: "center",
dataIndex: 'updateId'
},
{
title: '设备主键',
align: "center",
dataIndex: 'equId'
},
{
title: '指标code',
align: "center",
dataIndex: 'code'
},
{
title: '指标名称',
align: "center",
dataIndex: 'name'
},
{
title: '低阈值',
align: "center",
dataIndex: 'valLow'
},
{
title: '高阈值',
align: "center",
dataIndex: 'valHeight'
},
{
title: '计量单位',
align: "center",
dataIndex: 'nuit'
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '创建者',
field: 'createId',
component: 'Input',
},
{
label: '更新者',
field: 'updateId',
component: 'Input',
},
{
label: '设备主键',
field: 'equId',
component: 'Input',
},
{
label: '指标code',
field: 'code',
component: 'Input',
},
{
label: '指标名称',
field: 'name',
component: 'Input',
},
{
label: '低阈值',
field: 'valLow',
component: 'InputNumber',
},
{
label: '高阈值',
field: 'valHeight',
component: 'InputNumber',
},
{
label: '计量单位',
field: 'nuit',
component: 'Input',
},
{
label: '排序',
field: 'sortNo',
component: 'InputNumber',
},
// TODO 主键隐藏字段目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
];
export const itemFormSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
label: '',
field: 'deployId',
component: 'Input',
show: false,
},
{
label: '继电器名称',
field: 'relayName',
required: true,
component: 'Input',
},
{
label: '继电器编码',
field: 'relayKey',
component: 'Input',
dynamicRules: ({ values, model }) => {
return [
{
required: true,
validator: (_, value) => {
if (!value) {
return Promise.reject('请输入属性编码');
}
if (new RegExp("[`~!@#$^&*()=|{}'.<>《》/?!¥()—【】‘;:”“。,、?]").test(value)) {
return Promise.reject('数据值不能包含特殊字符!');
}
return new Promise<void>((resolve, reject) => {
let params = {
deployId: model.deployId,
relayKey: value,
id:model.id
};
relayItemCheck(params)
.then((res) => {
res.success ? resolve() : reject(res.message || '校验失败');
})
.catch((err) => {
reject(err.message || '验证失败');
});
});
},
},
];
},
},
{
label: '继电器种类',
field: 'relayType',
required: true,
component: 'JDictSelectTag',
componentProps: {
dictCode: 'iot_relay_type',
placeholder: '请选择继电器种类',
stringToNumber: true,
},
},
{
label: '继电器类别',
field: 'relayCate',
required: true,
component: 'JDictSelectTag',
componentProps: {
dictCode: 'iot_relay_cate',
placeholder: '请选择继电器类别',
stringToNumber: true,
},
},
{
label: '所属分组',
field: 'groupId',
defaultValue: '',
component: 'JDictSelectTag',
componentProps: ({ schema, formModel }) => {
return {
dictCode: 'surv_device_deploy_relaygroup,GROUP_NAME,ID,IS_ENABLE = 1 and DEPLOY_ID='+formModel.deployId,
dict: 'surv_device_deploy_relaygroup,GROUP_NAME,ID,IS_ENABLE = 1 and DEPLOY_ID='+formModel.deployId
};
}
},
// {
// label: '分组编码',
// field: 'groupCode',
// required: false,
// component: 'Input',
// },
{
label: '开指令',
field: 'registerCmdOn',
required: false,
component: 'Input',
},
{
label: '关指令',
field: 'registerCmdOff',
required: false,
component: 'Input',
},
{
label: '停指令',
field: 'registerCmdStop',
required: false,
component: 'Input',
},
{
field: 'isEnable',
label: '是否启用',
defaultValue: 1,
component: 'JDictSelectTag',
componentProps: {
type: 'radioButton',
dictCode: 'yn',
stringToNumber: true,
},
},
{
field: 'isAbleRemote',
label: '是否可远程控制',
defaultValue: 1,
component: 'JDictSelectTag',
componentProps: {
type: 'radioButton',
dictCode: 'yn',
stringToNumber: true,
},
},
{
label: '排序',
field: 'sortNo',
required: false,
component: 'InputNumber',
defaultValue :1
},
];
export const dictItemColumns: BasicColumn[] = [
{
title: '继电器编号',
dataIndex: 'relayKey',
width: 80,
},
{
title: '继电器名称',
dataIndex: 'relayName',
width: 80,
},
{
title: '分组名称',
dataIndex: 'groupNameStr',
width: 80,
},
{
title: '继电器类别',
dataIndex: 'relayCateName',
width: 80,
},
{
title: '继电器种类',
dataIndex: 'relayTypeName',
width: 80,
},
{
title: '排序',
dataIndex: 'sortNo',
width: 80,
},
];
export const dictItemSearchFormSchema: FormSchema[] = [
{
label: '名称',
field: 'relayName',
component: 'Input',
},
];

View File

@ -1,18 +1,26 @@
<template> <template>
<a-row> <a-row>
<a-col :span="24"> <a-col :span="24">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col class="gutter-row" :span="12" v-for="value2 in formData.cams" :key="value2.id" style="text-align: center;"> <a-col class="gutter-row" :span="12" v-for="value2 in formData.cams" :key="value2.id" style="text-align: center;">
<div class="gutter-box" :id="value2.deployCode" style="width: 95%;text-align: center;margin: auto;padding-top: 10px"> <div class="gutter-box" :id="value2.deployCode" style="width: 95%; margin: auto; padding-top: 10px">
<div class="video_head" style=""> <div class="video_head" style="display: flex; justify-content: space-between; align-items: center;">
{{value2.deployDes}} <div class="video_tit">{{value2.deployDes}}</div>
</div> <a-button
<div style="cursor:pointer" @click="handleMonitor(value2)"> type="text"
<img src="/resource/img/cameras.jpg" class="app-loading-logo" alt="Logo" style="width: 100%;text-align: center;"/> v-if="value2.deviceReverseIotUrl"
</div> @click="handleHisMonitor(value2)"
style="color: #64c3a4;"
>
查看回放
</a-button>
</div> </div>
</a-col> <div style="cursor: pointer" @click="handleMonitor(value2)">
</a-row> <img src="/resource/img/cameras.jpg" class="app-loading-logo" alt="Logo" style="width: 100%;"/>
</div>
</div>
</a-col>
</a-row>
</a-col> </a-col>
</a-row> </a-row>
<!--监控--> <!--监控-->
@ -41,6 +49,14 @@
monitorRegisterModal.value.statistic(record); monitorRegisterModal.value.statistic(record);
} }
/**
* 查看历史监控
*/
function handleHisMonitor(record) {
record.deviceIotUrl = record.deviceReverseIotUrl;
monitorRegisterModal.value.statistic(record);
}
/** /**
* 获取设备列表 * 获取设备列表
*/ */
@ -56,6 +72,31 @@
} }
}); });
} }
function historyvideo(item) {
this.lockVideoShow = true
let videohtml =
`<div style="width: 100%;height: 600px;margin:auto;"><div id="videos" style="width: 100%; height: 100%"></div></div>`
this.$nextTick(() => {
let dom = document.querySelector('#parent')
dom.innerHTML = videohtml
this.$forceUpdate()
this.player = new EZUIKit.EZUIKitPlayer({
id: 'videos', // ID
accessToken: item.ysToken,
url: item.deviceIotUrlReserve,
audio: 0,
autoplay: true,
// simple: ; pcLive: pc; pcRec: pc; mobileLive: ; mobileRec: ;security: ; voice: ;
template: 'security',
// themeData: this.themeData,
plugin: ['expend'], // talk-
width: 1160,
height: 600
})
})
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>