fix: 运行状态操作
This commit is contained in:
parent
2c6e4173f8
commit
fa00834c95
|
@ -175,3 +175,45 @@ export const delTags = (deviceId: string, id: string) => server.remove(`/device/
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const configurationReset = (deviceId: string) => server.put(`/device-instance/${deviceId}/configuration/_reset`)
|
export const configurationReset = (deviceId: string) => server.put(`/device-instance/${deviceId}/configuration/_reset`)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询事件详情列表
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @param eventId 事件id
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getEventList = (deviceId: string, eventId: string, data: Record<string, any>) => server.post(`/device-instance/${deviceId}/event/${eventId}?format=true`, data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置属性至设备
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const setProperty = (deviceId: string, data: Record<string, any>) => server.put(`/device-instance/${deviceId}/property`, data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最新属性值
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @param type 属性id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getProperty = (deviceId: string, type: string) => server.get(`/device/standard/${deviceId}/property/${type}`)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询设备的物模型指标
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @param propertyId 属性id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const queryMetric = (deviceId: string, propertyId: string) => server.get(`/device-instance/${deviceId}/metric/property/${propertyId}`)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存设备的物模型指标
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @param propertyId 属性id
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const saveMetric = (deviceId: string, propertyId: string, data: Record<string, any>) => server.patch(`/device-instance/${deviceId}/metric/property/${propertyId}`, data)
|
||||||
|
|
|
@ -74,7 +74,8 @@ const JTable = defineComponent<JTableProps>({
|
||||||
slots: [
|
slots: [
|
||||||
'headerTitle', // 顶部左边插槽
|
'headerTitle', // 顶部左边插槽
|
||||||
'card', // 卡片内容
|
'card', // 卡片内容
|
||||||
'rightExtraRender'
|
'rightExtraRender',
|
||||||
|
'paginationRender' // 分页
|
||||||
],
|
],
|
||||||
emits: [
|
emits: [
|
||||||
'modelChange', // 切换卡片和表格
|
'modelChange', // 切换卡片和表格
|
||||||
|
@ -354,6 +355,9 @@ const JTable = defineComponent<JTableProps>({
|
||||||
{
|
{
|
||||||
(!!_dataSource.value.length) && !props.noPagination && props.type === 'PAGE' &&
|
(!!_dataSource.value.length) && !props.noPagination && props.type === 'PAGE' &&
|
||||||
<div class={styles['jtable-pagination']}>
|
<div class={styles['jtable-pagination']}>
|
||||||
|
{
|
||||||
|
slots?.paginationRender ?
|
||||||
|
slots.paginationRender() :
|
||||||
<Pagination
|
<Pagination
|
||||||
size="small"
|
size="small"
|
||||||
total={total.value}
|
total={total.value}
|
||||||
|
@ -375,6 +379,7 @@ const JTable = defineComponent<JTableProps>({
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<JTable
|
<JTable
|
||||||
ref="eventsRef"
|
ref="eventsRef"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:dataSource="dataSource"
|
:request="_getEventList"
|
||||||
model="TABLE"
|
model="TABLE"
|
||||||
:bodyStyle="{padding: '0 24px'}"
|
:bodyStyle="{padding: '0 24px'}"
|
||||||
>
|
>
|
||||||
|
@ -16,16 +16,24 @@
|
||||||
</a-button>
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
</JTable>
|
</JTable>
|
||||||
|
<a-button type="link" @click="detail(slotProps)">
|
||||||
|
<AIcon type="SearchOutlined" />
|
||||||
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
import { getEventList } from '@/api/device/instance'
|
||||||
|
import { useInstanceStore } from '@/store/instance'
|
||||||
|
import { Modal } from 'ant-design-vue'
|
||||||
|
|
||||||
const events = defineProps({
|
const events = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const instanceStore = useInstanceStore()
|
||||||
|
|
||||||
const columns = ref<Record<string, any>>([
|
const columns = ref<Record<string, any>>([
|
||||||
{
|
{
|
||||||
|
@ -41,8 +49,9 @@ const columns = ref<Record<string, any>>([
|
||||||
scopedSlots: true,
|
scopedSlots: true,
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
const params = ref<Record<string, any>>({})
|
||||||
|
|
||||||
const dataSource = ref<Record<string, any>[]>([])
|
const _getEventList = () => getEventList(instanceStore.current.id || '', events.data.id || '', params.value)
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if(events.data?.valueType?.type === 'object'){
|
if(events.data?.valueType?.type === 'object'){
|
||||||
|
@ -50,8 +59,7 @@ watchEffect(() => {
|
||||||
columns.value.splice(0, 0, {
|
columns.value.splice(0, 0, {
|
||||||
key: i.id,
|
key: i.id,
|
||||||
title: i.name,
|
title: i.name,
|
||||||
dataIndex: `${i.id}_format`,
|
dataIndex: `${i.id}_format`
|
||||||
// renderText: (text) => (typeof text === 'object' ? JSON.stringify(text) : text),
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -63,6 +71,13 @@ watchEffect(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const detail = () => {
|
const detail = () => {
|
||||||
|
Modal.info({
|
||||||
|
title: () => '详情',
|
||||||
|
width: 850,
|
||||||
|
content: () => h('div', {}, [
|
||||||
|
h('p', '暂未开发'),
|
||||||
|
]),
|
||||||
|
okText: '关闭'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -0,0 +1,156 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:maskClosable="false"
|
||||||
|
:visible="true"
|
||||||
|
title="编辑指标"
|
||||||
|
@ok="handleSave"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
:confirmLoading="loading"
|
||||||
|
>
|
||||||
|
<a-alert message="场景联动页面可引用指标配置触发条件" type="warning" showIcon />
|
||||||
|
<a-form layout="vertical" ref="formRef" :model="modelRef" style="margin-top: 20px">
|
||||||
|
<template v-for="(item, index) in modelRef.metrics" :key="index">
|
||||||
|
<a-row type="flex" justify="space-between" align="bottom">
|
||||||
|
<a-col :span="11">
|
||||||
|
<a-form-item
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
message: `请${['date', 'boolean'].includes(data?.valueType?.type)? '选择': '输入'}指标值`,
|
||||||
|
}"
|
||||||
|
:name="['metrics', index, 'value', 0]"
|
||||||
|
:label="item?.name || '指标值'"
|
||||||
|
>
|
||||||
|
<ValueItem
|
||||||
|
v-model:modelValue="item.value[0]"
|
||||||
|
:itemType="data.valueType?.type"
|
||||||
|
:options="
|
||||||
|
data.valueType?.type === 'boolean'
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
label: data.valueType?.trueText,
|
||||||
|
value: String(data.valueType?.trueValue),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: data.valueType?.falseText,
|
||||||
|
value: String(data.valueType?.falseValue),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: undefined
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<template v-if="item.range">
|
||||||
|
<a-col><div class="center-icon">~</div></a-col>
|
||||||
|
<a-col :span="11">
|
||||||
|
<a-form-item
|
||||||
|
:name="['metrics', index, 'value', 1]"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
message: `请${['date', 'boolean'].includes(data?.valueType?.type)? '选择': '输入'}指标值`,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<ValueItem
|
||||||
|
v-model:modelValue="item.value[1]"
|
||||||
|
:itemType="data.valueType?.type"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</template>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { queryMetric, saveMetric } from '@/api/device/instance'
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
import { useInstanceStore } from "@/store/instance"
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref<boolean>(false)
|
||||||
|
const instanceStore = useInstanceStore()
|
||||||
|
const formRef = ref();
|
||||||
|
|
||||||
|
const modelRef = reactive({
|
||||||
|
metrics: []
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => props.data.id, (newVal) => {
|
||||||
|
if(newVal && instanceStore.current.id){
|
||||||
|
queryMetric(instanceStore.current.id, props.data.id).then(resp => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
if (Array.isArray(resp?.result) && resp?.result.length) {
|
||||||
|
const list = resp?.result.map((item: any) => {
|
||||||
|
const val = Array.isArray(item?.value) ? [item?.value] : item?.value?.split(',')
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
value: val
|
||||||
|
};
|
||||||
|
});
|
||||||
|
modelRef.metrics = list as any
|
||||||
|
} else {
|
||||||
|
const type = props.data.valueType?.type;
|
||||||
|
if (type === 'boolean') {
|
||||||
|
const list = props.data.expands?.metrics.map((item: any) => {
|
||||||
|
const value = (item?.value || {}).map((i: any) => String(i)) || {};
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
modelRef.metrics = list || []
|
||||||
|
} else {
|
||||||
|
modelRef.metrics = props.data.expands?.metrics || []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, {immediate: true, deep: true})
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
formRef.value
|
||||||
|
.validate()
|
||||||
|
.then(async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const list = (toRaw(modelRef)?.metrics || []).map((item: any) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
value: item.value.join(','),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const resp = await saveMetric(instanceStore.current.id || '', props.data.id || '', list).finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
if (resp.status === 200) {
|
||||||
|
message.success('操作成功!');
|
||||||
|
emit('close')
|
||||||
|
formRef.value.resetFields();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
console.log('error', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.center-icon {
|
||||||
|
height: 86px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -5,33 +5,20 @@
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="title">{{ _props.data.name }}</div>
|
<div class="title">{{ _props.data.name }}</div>
|
||||||
<div class="extra">
|
<div class="extra">
|
||||||
<a-space>
|
<a-space :size="16">
|
||||||
<a-tooltip title="设置属性至设备" v-if="data.expands?.type?.includes('write')">
|
<a-tooltip
|
||||||
<AIcon
|
v-for="i in actions"
|
||||||
type="EditOutlined"
|
:key="i.key"
|
||||||
style="font-size: 12px"
|
v-bind="i.tooltip"
|
||||||
/>
|
>
|
||||||
</a-tooltip>
|
<a-button
|
||||||
<a-tooltip title="指标" v-if="(data.expands?.metrics || []).length > 0 &&
|
style="padding: 0; margin: 0"
|
||||||
['int', 'long', 'float', 'double', 'string', 'boolean', 'date'].includes(
|
type="link"
|
||||||
data.valueType?.type || '',
|
:disabled="i.disabled"
|
||||||
)">
|
@click="i.onClick && i.onClick(data)"
|
||||||
<AIcon
|
>
|
||||||
type="ClockCircleOutlined"
|
<AIcon :type="i.icon" style="color: #323130; font-size: 12px" />
|
||||||
style="font-size: 12px"
|
</a-button>
|
||||||
/>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-tooltip title="获取最新属性值" v-if="data.expands?.type?.includes('read')">
|
|
||||||
<AIcon
|
|
||||||
type="SyncOutlined"
|
|
||||||
style="font-size: 12px"
|
|
||||||
/>
|
|
||||||
</a-tooltip>
|
|
||||||
<a-tooltip title="详情">
|
|
||||||
<AIcon
|
|
||||||
type="BarsOutlined"
|
|
||||||
style="font-size: 12px"
|
|
||||||
/>
|
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,6 +42,10 @@ const _props = defineProps({
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
|
actions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const loading = ref<boolean>(true);
|
const loading = ref<boolean>(true);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:maskClosable="false"
|
||||||
|
:visible="true"
|
||||||
|
title="编辑"
|
||||||
|
@ok="handleSave"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
:confirmLoading="loading"
|
||||||
|
>
|
||||||
|
<a-alert message="当数据来源为设备时,填写的值将下发到设备" type="warning" showIcon />
|
||||||
|
<a-form :rules="rules" layout="vertical" ref="formRef" :model="modelRef" style="margin-top: 20px">
|
||||||
|
<a-form-item name="propertyValue" :label="data?.name || '自定义属性'">
|
||||||
|
<ValueItem
|
||||||
|
v-model:modelValue="modelRef.propertyValue"
|
||||||
|
:itemType="data?.valueType?.type || data?.dataType"
|
||||||
|
:options="
|
||||||
|
(data?.valueType?.type || data?.dataType) === 'enum'
|
||||||
|
? (data?.valueType?.elements || []).map((item) => {
|
||||||
|
return {
|
||||||
|
label: item?.text,
|
||||||
|
value: item?.value
|
||||||
|
};
|
||||||
|
})
|
||||||
|
: undefined
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { setProperty } from '@/api/device/instance'
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
import { useInstanceStore } from "@/store/instance"
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref<boolean>(false)
|
||||||
|
const instanceStore = useInstanceStore()
|
||||||
|
|
||||||
|
const formRef = ref();
|
||||||
|
|
||||||
|
const modelRef = reactive({
|
||||||
|
propertyValue: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
propertyValue: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '该字段是必填字段',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
formRef.value
|
||||||
|
.validate()
|
||||||
|
.then(async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const resp = await setProperty(instanceStore.current?.id || '', {[props.data?.id]: toRaw(modelRef)?.propertyValue}).finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
if (resp.status === 200) {
|
||||||
|
message.success('操作成功!');
|
||||||
|
emit('close')
|
||||||
|
formRef.value.resetFields();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err: any) => {
|
||||||
|
console.log('error', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,14 +1,74 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="value">
|
||||||
{{data.value || '--'}}
|
{{value}}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { getImage } from "@/utils/comm";
|
||||||
|
|
||||||
const _data = defineProps({
|
const _data = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
|
value: {
|
||||||
|
type: [Object, String, Number],
|
||||||
|
default: '--'
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'card'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const imgMap = new Map<any, any>();
|
||||||
|
imgMap.set('txt', getImage('/running/txt.png'));
|
||||||
|
imgMap.set('doc', getImage('/running/doc.png'));
|
||||||
|
imgMap.set('xls', getImage('/running/xls.png'));
|
||||||
|
imgMap.set('ppt', getImage('/running/ppt.png'));
|
||||||
|
imgMap.set('docx', getImage('/running/docx.png'));
|
||||||
|
imgMap.set('xlsx', getImage('/running/xlsx.png'));
|
||||||
|
imgMap.set('pptx', getImage('/running/pptx.png'));
|
||||||
|
imgMap.set('pdf', getImage('/running/pdf.png'));
|
||||||
|
imgMap.set('img', getImage('/running/img.png'));
|
||||||
|
imgMap.set('error', getImage('/running/error.png'));
|
||||||
|
imgMap.set('video', getImage('/running/video.png'));
|
||||||
|
imgMap.set('other', getImage('/running/other.png'));
|
||||||
|
imgMap.set('obj', getImage('/running/obj.png'));
|
||||||
|
|
||||||
|
const imgList = ['.jpg', '.png', '.swf', '.tiff'];
|
||||||
|
const videoList = ['.m3u8', '.flv', '.mp4', '.rmvb', '.mvb'];
|
||||||
|
const fileList = ['.txt', '.doc', '.xls', '.pdf', '.ppt', '.docx', '.xlsx', '.pptx'];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.value {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.cardValue {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #323130;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 24px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.otherValue {
|
||||||
|
img {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,19 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<JTable
|
<JTable
|
||||||
ref="metadataRef"
|
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:dataSource="dataSource"
|
:dataSource="dataSource"
|
||||||
:bodyStyle="{padding: 0}"
|
:bodyStyle="{padding: '0 0 0 20px'}"
|
||||||
>
|
>
|
||||||
<template #headerTitle>
|
<template #headerTitle>
|
||||||
<a-input-search
|
<a-input-search
|
||||||
placeholder="请输入名称"
|
placeholder="请输入名称"
|
||||||
style="width: 300px; margin-bottom: 10px"
|
style="width: 300px; margin-bottom: 10px"
|
||||||
@search="onSearch"
|
@search="onSearch"
|
||||||
|
v-model:value="value"
|
||||||
|
:allowClear="true"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #card="slotProps">
|
<template #card="slotProps">
|
||||||
<PropertyCard :data="slotProps" />
|
<PropertyCard :data="slotProps" :actions="getActions(slotProps)" />
|
||||||
</template>
|
</template>
|
||||||
<template #value="slotProps">
|
<template #value="slotProps">
|
||||||
<ValueRender :data="slotProps" />
|
<ValueRender :data="slotProps" />
|
||||||
|
@ -28,41 +29,45 @@
|
||||||
:key="i.key"
|
:key="i.key"
|
||||||
v-bind="i.tooltip"
|
v-bind="i.tooltip"
|
||||||
>
|
>
|
||||||
<a-popconfirm
|
|
||||||
v-if="i.popConfirm"
|
|
||||||
v-bind="i.popConfirm"
|
|
||||||
:disabled="i.disabled"
|
|
||||||
>
|
|
||||||
<a-button
|
|
||||||
:disabled="i.disabled"
|
|
||||||
style="padding: 0"
|
|
||||||
type="link"
|
|
||||||
><AIcon :type="i.icon"
|
|
||||||
/></a-button>
|
|
||||||
</a-popconfirm>
|
|
||||||
<a-button
|
<a-button
|
||||||
style="padding: 0"
|
style="padding: 0"
|
||||||
type="link"
|
type="link"
|
||||||
v-else
|
:disabled="i.disabled"
|
||||||
@click="i.onClick && i.onClick(slotProps)"
|
@click="i.onClick && i.onClick(slotProps)"
|
||||||
>
|
>
|
||||||
<a-button
|
<AIcon :type="i.icon" />
|
||||||
:disabled="i.disabled"
|
|
||||||
style="padding: 0"
|
|
||||||
type="link"
|
|
||||||
><AIcon :type="i.icon"
|
|
||||||
/></a-button>
|
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
|
<template #paginationRender>
|
||||||
|
<a-pagination
|
||||||
|
size="small"
|
||||||
|
:total="total"
|
||||||
|
:showQuickJumper="false"
|
||||||
|
:showSizeChanger="true"
|
||||||
|
:current="pageIndex + 1"
|
||||||
|
:pageSize="pageSize"
|
||||||
|
:pageSizeOptions="['8', '12', '24', '60', '100']"
|
||||||
|
:show-total="(num) => `第 ${pageIndex * pageSize + 1} - ${(pageIndex + 1) * pageSize > num ? num : (pageIndex + 1) * pageSize} 条/总共 ${num} 条`"
|
||||||
|
@change="pageChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</JTable>
|
</JTable>
|
||||||
|
<Save v-if="editVisible" @close="editVisible = false" :data="currentInfo" />
|
||||||
|
<Indicators v-if="indicatorVisible" @close="indicatorVisible = false" :data="currentInfo" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import _ from "lodash"
|
||||||
import { PropertyData } from "../../../typings"
|
import { PropertyData } from "../../../typings"
|
||||||
import PropertyCard from './PropertyCard.vue'
|
import PropertyCard from './PropertyCard.vue'
|
||||||
import ValueRender from './ValueRender.vue'
|
import ValueRender from './ValueRender.vue'
|
||||||
|
import Save from './Save.vue'
|
||||||
|
import Indicators from './Indicators.vue'
|
||||||
|
import { getProperty } from '@/api/device/instance'
|
||||||
|
import { useInstanceStore } from "@/store/instance"
|
||||||
|
import { message } from "ant-design-vue"
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
@ -96,8 +101,17 @@ const _data = defineProps({
|
||||||
default: () => []
|
default: () => []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const value = ref<string>('')
|
||||||
const dataSource = ref<PropertyData[]>([])
|
const dataSource = ref<PropertyData[]>([])
|
||||||
|
const _dataSource = ref<PropertyData[]>([])
|
||||||
|
const pageIndex = ref<number>(0)
|
||||||
|
const pageSize = ref<number>(8)
|
||||||
|
const total = ref<number>(0)
|
||||||
|
const editVisible = ref<boolean>(false) // 编辑
|
||||||
|
const detailVisible = ref<boolean>(false) // 详情
|
||||||
|
const currentInfo = ref<Record<string, any>>({})
|
||||||
|
const instanceStore = useInstanceStore()
|
||||||
|
const indicatorVisible = ref<boolean>(false) // 指标
|
||||||
|
|
||||||
const getActions = (data: Partial<Record<string, any>>) => {
|
const getActions = (data: Partial<Record<string, any>>) => {
|
||||||
const arr = []
|
const arr = []
|
||||||
|
@ -109,7 +123,8 @@ const getActions = (data: Partial<Record<string, any>>) => {
|
||||||
},
|
},
|
||||||
icon: 'EditOutlined',
|
icon: 'EditOutlined',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
|
editVisible.value = true
|
||||||
|
currentInfo.value = data
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -123,7 +138,8 @@ const getActions = (data: Partial<Record<string, any>>) => {
|
||||||
},
|
},
|
||||||
icon: 'ClockCircleOutlined',
|
icon: 'ClockCircleOutlined',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
|
indicatorVisible.value = true
|
||||||
|
currentInfo.value = data
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -134,8 +150,13 @@ const getActions = (data: Partial<Record<string, any>>) => {
|
||||||
title: '获取最新属性值',
|
title: '获取最新属性值',
|
||||||
},
|
},
|
||||||
icon: 'SyncOutlined',
|
icon: 'SyncOutlined',
|
||||||
onClick: () => {
|
onClick: async () => {
|
||||||
|
if(instanceStore.current.id && data.id){
|
||||||
|
const resp = await getProperty(instanceStore.current.id, data.id)
|
||||||
|
if(resp.status === 200){
|
||||||
|
message.success('操作成功!')
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -147,17 +168,53 @@ const getActions = (data: Partial<Record<string, any>>) => {
|
||||||
},
|
},
|
||||||
icon: 'BarsOutlined',
|
icon: 'BarsOutlined',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
|
detailVisible.value = true
|
||||||
|
currentInfo.value = data
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
watchEffect(() => {
|
const query = (page: number, size: number, value: string) => {
|
||||||
dataSource.value = _data.data as PropertyData[]
|
pageIndex.value = page || 0
|
||||||
|
pageSize.value = size || 8
|
||||||
|
const _from = pageIndex.value * pageSize.value
|
||||||
|
const _to = (pageIndex.value + 1) * pageSize.value
|
||||||
|
const arr = _.cloneDeep(_dataSource.value)
|
||||||
|
if(value){
|
||||||
|
const li = arr.filter((i: any) => {
|
||||||
|
return i?.name.indexOf(value) !== -1;
|
||||||
|
})
|
||||||
|
dataSource.value = li.slice(_from, _to)
|
||||||
|
total.value = li.length
|
||||||
|
} else {
|
||||||
|
dataSource.value = arr.slice(_from, _to)
|
||||||
|
total.value = arr.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageChange = (page: number, size: number) => {
|
||||||
|
if(size === pageSize.value) {
|
||||||
|
query(page - 1, size, value.value)
|
||||||
|
} else {
|
||||||
|
query(0, size, value.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => _data.data,
|
||||||
|
(newVal) => {
|
||||||
|
if(newVal.length) {
|
||||||
|
_dataSource.value = newVal as PropertyData[]
|
||||||
|
query(0, 8, value.value)
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
})
|
})
|
||||||
|
|
||||||
const onSearch = () => {};
|
const onSearch = () => {
|
||||||
|
query(0, 8, value.value)
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,6 @@ const tabChange = (key: string) => {
|
||||||
display: flex;
|
display: flex;
|
||||||
.property-box-left {
|
.property-box-left {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
margin-right: 20px;
|
|
||||||
}
|
}
|
||||||
.property-box-right {
|
.property-box-right {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
Loading…
Reference in New Issue