Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
a5d7c228c2
|
@ -100,7 +100,7 @@ const matchComponents: IMatcher[] = [
|
|||
},
|
||||
{
|
||||
pattern: /^TimePicker|^TimeRangePicker/,
|
||||
styleDir: 'TimeTicker'
|
||||
styleDir: 'TimePicker'
|
||||
},
|
||||
{
|
||||
pattern: /^Radio/,
|
||||
|
|
|
@ -85,7 +85,7 @@ export const batchDeleteDevice = (data: string[]) => server.put(`/device-instanc
|
|||
*/
|
||||
export const deviceTemplateDownload = (productId: string, type: string) => `${BASE_API_PATH}/device-instance/${productId}/template.${type}`
|
||||
|
||||
export const templateDownload = (productId: string, type: string) => server.get(`/device-instance/${productId}/template.${type}`,{},{responseType: 'blob'})
|
||||
export const templateDownload = (productId: string, type: string) => server.get(`/device-instance/${productId}/template.${type}`, {}, { responseType: 'blob' })
|
||||
/**
|
||||
* 设备导入
|
||||
* @param productId 产品id
|
||||
|
@ -245,6 +245,22 @@ export const unbindBatchDevice = (deviceId: string, data: Record<string, any>) =
|
|||
*/
|
||||
export const bindDevice = (deviceId: string, data: Record<string, any>) => server.post(`/device/gateway/${deviceId}/bind`, data)
|
||||
|
||||
/**
|
||||
* 获取产品列表
|
||||
* @param data
|
||||
*/
|
||||
export const getProductListNoPage = (data: any) => server.post('/device/product/_query/no-paging?paging=false', data)
|
||||
|
||||
/**
|
||||
* 修改设备
|
||||
*/
|
||||
export const editDevice = (parmas: any) => server.patch('/device-instance', parmas)
|
||||
|
||||
/**
|
||||
* 新增设备
|
||||
*/
|
||||
export const addDevice = (params: any) => server.post("/device-instance", params)
|
||||
|
||||
/**
|
||||
* 设备接入网关状态
|
||||
* @param id 设备接入网关id
|
||||
|
@ -504,14 +520,14 @@ export const productCode = (productId: string) => server.get(`/device/transparen
|
|||
* @param productId
|
||||
* @returns
|
||||
*/
|
||||
export const saveProductCode = (productId: string,data: Record<string, unknown>) => server.post(`/device/transparent-codec/${productId}`,data)
|
||||
export const saveProductCode = (productId: string, data: Record<string, unknown>) => server.post(`/device/transparent-codec/${productId}`, data)
|
||||
/**
|
||||
* 获取设备解析规则
|
||||
* @param productId
|
||||
* @param deviceId
|
||||
* @returns
|
||||
*/
|
||||
export const deviceCode = (productId: string,deviceId:string) => server.get(`device/transparent-codec/${productId}/${deviceId}`)
|
||||
export const deviceCode = (productId: string, deviceId: string) => server.get(`device/transparent-codec/${productId}/${deviceId}`)
|
||||
/**
|
||||
* 保存设备解析规则
|
||||
* @param productId
|
||||
|
@ -520,13 +536,13 @@ export const deviceCode = (productId: string,deviceId:string) => server.get(`dev
|
|||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
export const saveDeviceCode = (productId: string,deviceId:string,data: Record<string, unknown>) => server.post(`/device/transparent-codec/${productId}/${deviceId}`,data)
|
||||
export const saveDeviceCode = (productId: string, deviceId: string, data: Record<string, unknown>) => server.post(`/device/transparent-codec/${productId}/${deviceId}`, data)
|
||||
/**
|
||||
* 编码测试
|
||||
* @param data
|
||||
* @returns
|
||||
*/
|
||||
export const testCode = (data: Record<string, unknown>) => server.post(`/device/transparent-codec/decode-test`,data)
|
||||
export const testCode = (data: Record<string, unknown>) => server.post(`/device/transparent-codec/decode-test`, data)
|
||||
/**
|
||||
* 删除设备解析规则
|
||||
* @param productId
|
||||
|
|
|
@ -7,6 +7,15 @@
|
|||
:options="options"
|
||||
allowClear
|
||||
style="width: 100%"
|
||||
@change='selectChange'
|
||||
/>
|
||||
<j-time-picker
|
||||
v-else-if="typeMap.get(itemType) === 'time'"
|
||||
v-model:value="myValue"
|
||||
allowClear
|
||||
format="HH:mm:ss"
|
||||
style="width: 100%"
|
||||
@change='timeChange'
|
||||
/>
|
||||
<j-date-picker
|
||||
v-else-if="typeMap.get(itemType) === 'date'"
|
||||
|
@ -16,17 +25,20 @@
|
|||
lang="cn"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
style="width: 100%"
|
||||
@change='dateChange'
|
||||
/>
|
||||
<j-input-number
|
||||
v-else-if="typeMap.get(itemType) === 'inputNumber'"
|
||||
v-model:value="myValue"
|
||||
allowClear
|
||||
style="width: 100%"
|
||||
@change='inputChange'
|
||||
/>
|
||||
<j-input
|
||||
allowClear
|
||||
v-else-if="typeMap.get(itemType) === 'object'"
|
||||
v-model:value="myValue"
|
||||
@change='inputChange'
|
||||
>
|
||||
<template #addonAfter>
|
||||
<AIcon type="FormOutlined" @click="modalVis = true" />
|
||||
|
@ -60,6 +72,7 @@
|
|||
type="text"
|
||||
v-model:value="myValue"
|
||||
style="width: 100%"
|
||||
@change='inputChange'
|
||||
/>
|
||||
|
||||
<!-- 代码编辑器弹窗 -->
|
||||
|
@ -92,6 +105,7 @@ import { FILE_UPLOAD } from '@/api/comm';
|
|||
|
||||
type Emits = {
|
||||
(e: 'update:modelValue', data: string | number | boolean): void;
|
||||
(e: 'change', data: any, item?: any): void;
|
||||
};
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
|
@ -169,6 +183,23 @@ const handleFileChange = (info: UploadChangeParam<UploadFile<any>>) => {
|
|||
emit('update:modelValue', url);
|
||||
}
|
||||
};
|
||||
|
||||
const selectChange = (e: string, option: any) => {
|
||||
emit('change', e, option)
|
||||
}
|
||||
|
||||
const timeChange = (e: any) => {
|
||||
emit('change', e)
|
||||
}
|
||||
|
||||
const inputChange = (e: any) => {
|
||||
emit('change', e.target.value)
|
||||
}
|
||||
|
||||
const dateChange = (e: any) => {
|
||||
emit('change', e)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { App } from 'vue'
|
||||
import AIcon from './AIcon'
|
||||
// import AIcon from './AIcon'
|
||||
import PermissionButton from './PermissionButton/index.vue'
|
||||
import JTable from './Table/index'
|
||||
import TitleComponent from "./TitleComponent/index.vue";
|
||||
|
@ -10,7 +10,7 @@ import NormalUpload from './NormalUpload/index.vue'
|
|||
import FileFormat from './FileFormat/index.vue'
|
||||
import JProUpload from './JUpload/index.vue'
|
||||
import { BasicLayoutPage, BlankLayoutPage } from './Layout'
|
||||
import { PageContainer } from 'jetlinks-ui-components'
|
||||
import { PageContainer, AIcon } from 'jetlinks-ui-components'
|
||||
import Ellipsis from './Ellipsis/index.vue'
|
||||
import JEmpty from './Empty/index.vue'
|
||||
import AMapComponent from './AMapComponent/index.vue'
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
@search="handleSearch"
|
||||
type="simple"
|
||||
/>
|
||||
<JTable
|
||||
<JProTable
|
||||
ref="bindDeviceRef"
|
||||
:columns="columns"
|
||||
:request="query"
|
||||
|
@ -78,7 +78,7 @@
|
|||
:status="statusMap.get(slotProps.state.value)"
|
||||
/>
|
||||
</template>
|
||||
</JTable>
|
||||
</JProTable>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
<template>
|
||||
<a-select allowClear v-model:value="_value" @change="onChange" placeholder="请选择" style="width: 100%">
|
||||
<a-select-option
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
:value="item.id"
|
||||
:label="item.name"
|
||||
:filter-option="filterOption"
|
||||
>{{ item.name }}</a-select-option
|
||||
>
|
||||
</a-select>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
edgeCollector,
|
||||
edgePoint,
|
||||
} from '@/api/device/instance';
|
||||
|
||||
const _props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'POINT',
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
edgeId: {
|
||||
type: String,
|
||||
default: '',
|
||||
}
|
||||
});
|
||||
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
};
|
||||
|
||||
type Emits = {
|
||||
(e: 'update:modelValue', data: string | undefined): void;
|
||||
};
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const list = ref<any[]>([]);
|
||||
const _value = ref<string | undefined>(undefined);
|
||||
|
||||
watchEffect(() => {
|
||||
_value.value = _props.modelValue;
|
||||
});
|
||||
|
||||
const onChange = (_val: string) => {
|
||||
emit('update:modelValue', _val);
|
||||
};
|
||||
|
||||
const getCollector = async (_val: string) => {
|
||||
if (!_val) {
|
||||
return [];
|
||||
} else {
|
||||
const resp = await edgeCollector(_props.edgeId, {
|
||||
terms: [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
column: 'channelId',
|
||||
value: _val,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
if (resp.status === 200) {
|
||||
list.value = (resp.result as any[])?.[0] || []
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getPoint = async (_val: string) => {
|
||||
if (!_val) {
|
||||
return [];
|
||||
} else {
|
||||
const resp = await edgePoint(_props.edgeId, {
|
||||
terms: [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
column: 'collectorId',
|
||||
value: _val,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
if (resp.status === 200) {
|
||||
list.value = (resp.result as any[])?.[0] || []
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
if (_props.id) {
|
||||
if (_props.type === 'POINT') {
|
||||
getPoint(_props.id);
|
||||
} else {
|
||||
getCollector(_props.id);
|
||||
}
|
||||
} else {
|
||||
list.value = [];
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
|
@ -0,0 +1,212 @@
|
|||
<template>
|
||||
<a-modal
|
||||
width="900px"
|
||||
title="批量映射"
|
||||
visible
|
||||
@ok="handleClick"
|
||||
@cancel="handleClose"
|
||||
>
|
||||
<div class="map-tree">
|
||||
<div class="map-tree-top">
|
||||
采集器的点位名称与属性名称一致时将自动映射绑定;有多个采集器点位名称与属性名称一致时以第1个采集器的点位数据进行绑定
|
||||
</div>
|
||||
<a-spin :spinning="loading">
|
||||
<div class="map-tree-content">
|
||||
<a-card class="map-tree-content-card" title="源数据">
|
||||
<a-tree
|
||||
checkable
|
||||
:height="300"
|
||||
:tree-data="dataSource"
|
||||
:checkedKeys="checkedKeys"
|
||||
@check="onCheck"
|
||||
/>
|
||||
</a-card>
|
||||
<div style="width: 100px">
|
||||
<a-button
|
||||
:disabled="rightList.length >= leftList.length"
|
||||
@click="onRight"
|
||||
>加入右侧</a-button
|
||||
>
|
||||
</div>
|
||||
<a-card class="map-tree-content-card" title="采集器">
|
||||
<a-list
|
||||
size="small"
|
||||
:data-source="rightList"
|
||||
class="map-tree-content-card-list"
|
||||
>
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item>
|
||||
{{ item.title }}
|
||||
<template #actions>
|
||||
<a-popconfirm
|
||||
title="确定删除?"
|
||||
@confirm="_delete(item.key)"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { treeEdgeMap, saveEdgeMap, addDevice } from '@/api/device/instance';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
const _props = defineProps({
|
||||
metaData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
edgeId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
deviceData: {
|
||||
type: Object,
|
||||
},
|
||||
});
|
||||
const _emits = defineEmits(['close', 'save']);
|
||||
|
||||
const checkedKeys = ref<string[]>([]);
|
||||
|
||||
const leftList = ref<any[]>([]);
|
||||
const rightList = ref<any[]>([]);
|
||||
|
||||
const dataSource = ref<any[]>([]);
|
||||
const loading = ref<boolean>(false);
|
||||
|
||||
const handleData = (data: any[], type: string) => {
|
||||
data.forEach((item) => {
|
||||
item.key = item.id;
|
||||
item.title = item.name;
|
||||
item.checkable = type === 'collectors';
|
||||
if (
|
||||
item.collectors &&
|
||||
Array.isArray(item.collectors) &&
|
||||
item.collectors.length
|
||||
) {
|
||||
item.children = handleData(item.collectors, 'collectors');
|
||||
}
|
||||
if (item.points && Array.isArray(item.points) && item.points.length) {
|
||||
item.children = handleData(item.points, 'points');
|
||||
}
|
||||
});
|
||||
return data as any[];
|
||||
};
|
||||
|
||||
const handleSearch = async () => {
|
||||
loading.value = true;
|
||||
const resp = await treeEdgeMap(_props.edgeId);
|
||||
loading.value = false;
|
||||
if (resp.status === 200) {
|
||||
dataSource.value = handleData((resp.result as any[])?.[0], 'channel');
|
||||
}
|
||||
};
|
||||
|
||||
const onCheck = (keys: string[], e: any) => {
|
||||
checkedKeys.value = [...keys];
|
||||
leftList.value = e?.checkedNodes || [];
|
||||
};
|
||||
|
||||
const onRight = () => {
|
||||
rightList.value = leftList.value;
|
||||
};
|
||||
|
||||
const _delete = (_key: string) => {
|
||||
const _index = rightList.value.findIndex((i) => i.key === _key);
|
||||
rightList.value.splice(_index, 1);
|
||||
checkedKeys.value = rightList.value.map((i) => i.key);
|
||||
leftList.value = rightList.value;
|
||||
};
|
||||
|
||||
const handleClick = async () => {
|
||||
if (!rightList.value.length) {
|
||||
message.warning('请选择采集器');
|
||||
} else {
|
||||
const params: any[] = [];
|
||||
rightList.value.map((item: any) => {
|
||||
const array = (item.children || []).map((element: any) => ({
|
||||
channelId: item.parentId,
|
||||
collectorId: element.collectorId,
|
||||
pointId: element.id,
|
||||
metadataType: 'property',
|
||||
metadataId: (_props.metaData as any[]).find(
|
||||
(i: any) => i.name === element.name,
|
||||
)?.metadataId,
|
||||
provider: dataSource.value.find(
|
||||
(it: any) => it.id === item.parentId,
|
||||
).provider,
|
||||
}));
|
||||
params.push(...array);
|
||||
});
|
||||
const filterParms = params.filter((item) => !!item.metadataId);
|
||||
if (_props.deviceId) {
|
||||
if (filterParms && filterParms.length !== 0) {
|
||||
const res = await saveEdgeMap(_props.edgeId, {
|
||||
deviceId: _props.deviceId,
|
||||
provider: filterParms[0]?.provider,
|
||||
requestList: filterParms,
|
||||
});
|
||||
if (res.status === 200) {
|
||||
message.success('操作成功');
|
||||
_emits('save');
|
||||
}
|
||||
} else {
|
||||
message.error('暂无对应属性的映射');
|
||||
}
|
||||
} else {
|
||||
if (filterParms && filterParms.length !== 0) {
|
||||
const res = await addDevice(_props.deviceData);
|
||||
if (res.status === 200) {
|
||||
const resq = await saveEdgeMap(_props.edgeId, {
|
||||
deviceId: res.result?.id,
|
||||
provider: filterParms[0]?.provider,
|
||||
requestList: filterParms,
|
||||
});
|
||||
if (res.status === 200) {
|
||||
message.success('操作成功');
|
||||
_emits('save');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleClose = () => {
|
||||
_emits('close');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (_props.edgeId) {
|
||||
handleSearch();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.map-tree-content {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.map-tree-content-card {
|
||||
width: 350px;
|
||||
height: 400px;
|
||||
|
||||
.map-tree-content-card-list {
|
||||
overflow-y: auto;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,337 @@
|
|||
<template>
|
||||
<a-spin :spinning="loading" v-if="_metadata">
|
||||
<a-card :bordered="false">
|
||||
<template #title>
|
||||
<TitleComponent data="点位映射"></TitleComponent>
|
||||
</template>
|
||||
<template #extra>
|
||||
<a-space>
|
||||
<a-button @click="showModal">批量映射</a-button>
|
||||
<a-button type="primary" @click="onSave">保存</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-form ref="formRef" :model="modelRef">
|
||||
<a-table :dataSource="modelRef.dataSource" :columns="columns">
|
||||
<template #headerCell="{ column }">
|
||||
<template v-if="column.key === 'collectorId'">
|
||||
采集器
|
||||
<a-tooltip title="边缘网关代理的真实物理设备">
|
||||
<AIcon type="QuestionCircleOutlined" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.dataIndex === 'channelId'">
|
||||
<a-form-item
|
||||
:name="['dataSource', index, 'channelId']"
|
||||
>
|
||||
<a-select
|
||||
style="width: 100%"
|
||||
v-model:value="record[column.dataIndex]"
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
:filter-option="filterOption"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in channelList"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
>{{ item.label }}</a-select-option
|
||||
>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'collectorId'">
|
||||
<a-form-item
|
||||
:name="['dataSource', index, 'collectorId']"
|
||||
:rules="[
|
||||
{
|
||||
required: !!record.channelId,
|
||||
message: '请选择采集器',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<MSelect
|
||||
v-model="record[column.dataIndex]"
|
||||
:id="record.channelId"
|
||||
type="COLLECTOR"
|
||||
:edgeId="instanceStore.current.id"
|
||||
/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'pointId'">
|
||||
<a-form-item
|
||||
:name="['dataSource', index, 'pointId']"
|
||||
:rules="[
|
||||
{
|
||||
required: !!record.channelId,
|
||||
message: '请选择点位',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<MSelect
|
||||
v-model="record[column.dataIndex]"
|
||||
:id="record.collectorId"
|
||||
type="POINT"
|
||||
:edgeId="instanceStore.current.id"
|
||||
/>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'id'">
|
||||
<a-badge
|
||||
v-if="record[column.dataIndex]"
|
||||
status="success"
|
||||
text="已绑定"
|
||||
/>
|
||||
<a-badge v-else status="error" text="未绑定" />
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<a-tooltip title="解绑">
|
||||
<a-popconfirm
|
||||
title="确认解绑"
|
||||
:disabled="!record.id"
|
||||
@confirm="unbind(record.id)"
|
||||
>
|
||||
<a-button type="link" :disabled="!record.id"
|
||||
><AIcon type="icon-jiebang"
|
||||
/></a-button>
|
||||
</a-popconfirm>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-form>
|
||||
</a-card>
|
||||
<PatchMapping
|
||||
:deviceId="instanceStore.current.parentId"
|
||||
v-if="visible"
|
||||
@close="visible = false"
|
||||
@save="onPatchBind"
|
||||
:metaData="modelRef.dataSource"
|
||||
:edgeId="instanceStore.current.id"
|
||||
:deviceData="deviceData"
|
||||
/>
|
||||
</a-spin>
|
||||
<a-card v-else>
|
||||
<JEmpty description="暂无数据,请配置物模型" style="margin: 10% 0" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useInstanceStore } from '@/store/instance';
|
||||
import {
|
||||
getEdgeMap,
|
||||
saveEdgeMap,
|
||||
removeEdgeMap,
|
||||
edgeChannel,
|
||||
addDevice,
|
||||
editDevice,
|
||||
} from '@/api/device/instance';
|
||||
import MSelect from './MSelect.vue';
|
||||
import PatchMapping from './PatchMapping.vue';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { inject } from 'vue';
|
||||
const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'metadataName',
|
||||
key: 'metadataName',
|
||||
width: '20%',
|
||||
},
|
||||
{
|
||||
title: '通道',
|
||||
dataIndex: 'channelId',
|
||||
key: 'channelId',
|
||||
width: '20%',
|
||||
},
|
||||
{
|
||||
title: '采集器',
|
||||
dataIndex: 'collectorId',
|
||||
key: 'collectorId',
|
||||
width: '20%',
|
||||
},
|
||||
{
|
||||
title: '点位',
|
||||
key: 'pointId',
|
||||
dataIndex: 'pointId',
|
||||
width: '20%',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'id',
|
||||
dataIndex: 'id',
|
||||
width: '10%',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: '10%',
|
||||
},
|
||||
];
|
||||
const validate = inject('validate');
|
||||
const form = ref();
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
};
|
||||
const { productList } = defineProps(['productList']);
|
||||
const _emit = defineEmits(['close']);
|
||||
const instanceStore = useInstanceStore();
|
||||
let _metadata = ref();
|
||||
const loading = ref<boolean>(false);
|
||||
const channelList = ref([]);
|
||||
|
||||
const modelRef = reactive({
|
||||
dataSource: [],
|
||||
});
|
||||
const deviceData = ref();
|
||||
const formRef = ref();
|
||||
const visible = ref<boolean>(false);
|
||||
|
||||
const getChannel = async () => {
|
||||
if (instanceStore.current?.id) {
|
||||
const resp: any = await edgeChannel(instanceStore.current.id);
|
||||
if (resp.status === 200) {
|
||||
channelList.value = resp.result?.[0]?.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
provider: item.provider,
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleSearch = async () => {
|
||||
loading.value = true;
|
||||
modelRef.dataSource = _metadata;
|
||||
getChannel();
|
||||
if (_metadata && _metadata.length) {
|
||||
const resp: any = await getEdgeMap(instanceStore.current?.orgId || '', {
|
||||
deviceId: instanceStore.current.id,
|
||||
query: {},
|
||||
}).catch(() => {
|
||||
modelRef.dataSource = _metadata;
|
||||
loading.value = false;
|
||||
});
|
||||
if (resp.status === 200) {
|
||||
const array = resp.result?.[0].reduce((x: any, y: any) => {
|
||||
const metadataId = _metadata.find(
|
||||
(item: any) => item.metadataId === y.metadataId,
|
||||
);
|
||||
if (metadataId) {
|
||||
Object.assign(metadataId, y);
|
||||
} else {
|
||||
x.push(y);
|
||||
}
|
||||
return x;
|
||||
}, _metadata);
|
||||
modelRef.dataSource = array;
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const unbind = async (id: string) => {
|
||||
if (id) {
|
||||
const resp = await removeEdgeMap(
|
||||
instanceStore.current?.parentId || '',
|
||||
{
|
||||
deviceId: instanceStore.current.id,
|
||||
idList: [id],
|
||||
},
|
||||
);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
handleSearch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onPatchBind = () => {
|
||||
visible.value = false;
|
||||
_emit('close');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleSearch();
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
if (instanceStore.current?.metadata) {
|
||||
_metadata.value = instanceStore.current?.metadata;
|
||||
} else {
|
||||
_metadata.value = {};
|
||||
}
|
||||
});
|
||||
const onSave = async () => {
|
||||
form.value = await validate();
|
||||
if (form.value) {
|
||||
formRef.value.validateFields().then(async () => {
|
||||
if (modelRef.dataSource.length === 0) {
|
||||
message.error('请配置物模型');
|
||||
} else {
|
||||
channelList.value.forEach((item: any) => {
|
||||
modelRef.dataSource.forEach((i: any) => {
|
||||
if (item.value === i.channelId) {
|
||||
i.provider = item.provider;
|
||||
}
|
||||
});
|
||||
});
|
||||
const formData = {
|
||||
...form.value,
|
||||
productName: productList.find(
|
||||
(item: any) => item.id === form.value?.productId,
|
||||
).name,
|
||||
parentId: instanceStore.current.id,
|
||||
id: instanceStore.current.parentId
|
||||
? instanceStore.current.parentId
|
||||
: undefined,
|
||||
};
|
||||
const resq = instanceStore.current.parentId
|
||||
? await editDevice(formData)
|
||||
: await addDevice(formData);
|
||||
if (resq.status === 200) {
|
||||
const array = modelRef.dataSource.filter(
|
||||
(item: any) => item.channelId,
|
||||
);
|
||||
const submitData = {
|
||||
deviceId: instanceStore.current.parentId
|
||||
? instanceStore.current.parentId
|
||||
: resq.result?.id,
|
||||
provider: array?.[0]?.provider,
|
||||
requestList: array,
|
||||
};
|
||||
save(submitData);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
const save = async (item: any) => {
|
||||
const res = await saveEdgeMap(instanceStore.current.id, item);
|
||||
if (res.status === 200) {
|
||||
message.success('保存成功');
|
||||
_emit('close');
|
||||
}
|
||||
};
|
||||
const showModal = async () => {
|
||||
form.value = await validate();
|
||||
if (form.value) {
|
||||
const formData = {
|
||||
...form.value,
|
||||
productName: productList.find(
|
||||
(item: any) => item.id === form.value?.productId,
|
||||
).name,
|
||||
parentId: instanceStore.current.id,
|
||||
};
|
||||
deviceData.value = formData;
|
||||
}
|
||||
visible.value = true;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ant-form-item) {
|
||||
margin: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,106 @@
|
|||
<template>
|
||||
<div>
|
||||
<TitleComponent data="基本信息">
|
||||
<template #extra>
|
||||
<j-button @click="comeBack">返回</j-button>
|
||||
</template>
|
||||
</TitleComponent>
|
||||
<j-form layout="vertical" :model="form" ref="formRef">
|
||||
<j-row :gutter="24">
|
||||
<j-col :span="12">
|
||||
<j-form-item
|
||||
label="设备名称"
|
||||
name="name"
|
||||
:rules="{ required: true, message: '请输入设备名称' }"
|
||||
>
|
||||
<j-input v-model:value="form.name"></j-input>
|
||||
</j-form-item>
|
||||
</j-col>
|
||||
<j-col :span="12">
|
||||
<j-form-item
|
||||
label="产品名称"
|
||||
name="productId"
|
||||
:rules="{ required: true, message: '请选择产品名称' }"
|
||||
>
|
||||
<j-select
|
||||
:disabled="props.childData?.id"
|
||||
@change="selectChange"
|
||||
v-model:value="form.productId"
|
||||
>
|
||||
<j-select-option
|
||||
v-for="i in productList"
|
||||
:key="i.id"
|
||||
:value="i.id"
|
||||
>{{ i.name }}</j-select-option
|
||||
>
|
||||
</j-select>
|
||||
</j-form-item>
|
||||
</j-col>
|
||||
</j-row>
|
||||
<j-row :gutter="24" v-if="visible">
|
||||
<j-col :span="24"
|
||||
><EdgeMap :productList="productList" @close="comeBack"
|
||||
/></j-col>
|
||||
</j-row>
|
||||
</j-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getProductListNoPage } from '@/api/device/instance';
|
||||
import EdgeMap from '../EdgeMap/index.vue';
|
||||
import { useInstanceStore } from '@/store/instance';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { provide } from 'vue';
|
||||
const instanceStore = useInstanceStore();
|
||||
const { current } = storeToRefs(instanceStore);
|
||||
const props = defineProps(['childData']);
|
||||
const form = reactive({
|
||||
name: '',
|
||||
productId: '',
|
||||
});
|
||||
const formRef = ref();
|
||||
const emit = defineEmits(['closeChildSave']);
|
||||
const productList = ref();
|
||||
const visible = ref(false);
|
||||
const getProductList = async () => {
|
||||
const res = await getProductListNoPage({
|
||||
terms: [{ column: 'accessProvider', value: 'edge-child-device' }],
|
||||
});
|
||||
if (res.status === 200) {
|
||||
productList.value = res.result;
|
||||
}
|
||||
};
|
||||
getProductList();
|
||||
const selectChange = (e: any) => {
|
||||
if (e) {
|
||||
visible.value = true;
|
||||
}
|
||||
const item = productList.value.filter((i: any) => i.id === e)[0];
|
||||
const array = JSON.parse(item.metadata || [])?.properties?.map(
|
||||
(i: any) => ({
|
||||
metadataType: 'property',
|
||||
metadataName: `${i.name}(${i.id})`,
|
||||
metadataId: i.id,
|
||||
name: i.name,
|
||||
}),
|
||||
);
|
||||
current.value.metadata = array;
|
||||
};
|
||||
watchEffect(() => {
|
||||
if (props.childData?.id) {
|
||||
visible.value = true;
|
||||
}
|
||||
});
|
||||
watchEffect(() => {});
|
||||
|
||||
const validate = async () => {
|
||||
return formRef.value.validateFields();
|
||||
};
|
||||
provide('validate',validate);
|
||||
const comeBack = () =>{
|
||||
emit('closeChildSave');
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
</style>
|
|
@ -1,12 +1,18 @@
|
|||
<template>
|
||||
<a-card>
|
||||
<SaveChild
|
||||
v-if="childVisible"
|
||||
@close-child-save="closeChildSave"
|
||||
:childData="current"
|
||||
/>
|
||||
<div v-else>
|
||||
<Search
|
||||
:columns="columns"
|
||||
target="child-device"
|
||||
@search="handleSearch"
|
||||
class="child-device-search"
|
||||
/>
|
||||
<JTable
|
||||
<JProTable
|
||||
ref="childDeviceRef"
|
||||
:columns="columns"
|
||||
:request="query"
|
||||
|
@ -28,15 +34,37 @@
|
|||
:model="'TABLE'"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-space>
|
||||
<a-button type="primary"> 新增并绑定 </a-button>
|
||||
<a-button type="primary" @click="visible = true">
|
||||
绑定
|
||||
</a-button>
|
||||
<a-popconfirm title="确认解绑吗?" @confirm="handleUnBind">
|
||||
<a-button type="primary"> 批量解绑 </a-button>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
<j-space>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
v-if="
|
||||
detail?.accessProvider ===
|
||||
'official-edge-gateway'
|
||||
"
|
||||
hasPermission="device/Instance:update"
|
||||
@click="
|
||||
current = {};
|
||||
childVisible = true;
|
||||
"
|
||||
>新增并绑定</PermissionButton
|
||||
>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
@click="visible = true"
|
||||
hasPermission="device/Instance:update"
|
||||
>
|
||||
绑定</PermissionButton
|
||||
>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
hasPermission="device/Instance:update"
|
||||
:popConfirm="{
|
||||
title: '确定解绑吗?',
|
||||
onConfirm: handleUnBind,
|
||||
}"
|
||||
>批量解除</PermissionButton
|
||||
>
|
||||
</j-space>
|
||||
</template>
|
||||
<template #registryTime="slotProps">
|
||||
{{
|
||||
|
@ -54,38 +82,32 @@
|
|||
/>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<a-tooltip
|
||||
v-for="i in getActions(slotProps)"
|
||||
<j-space :size="16">
|
||||
<template
|
||||
v-for="i in getActions(slotProps, 'table')"
|
||||
:key="i.key"
|
||||
v-bind="i.tooltip"
|
||||
>
|
||||
<a-popconfirm v-if="i.popConfirm" v-bind="i.popConfirm">
|
||||
<a-button
|
||||
<PermissionButton
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
:popConfirm="i.popConfirm"
|
||||
:tooltip="{
|
||||
...i.tooltip,
|
||||
}"
|
||||
@click="i.onClick"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-popconfirm>
|
||||
<a-button
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
v-else
|
||||
@click="i.onClick && i.onClick(slotProps)"
|
||||
style="padding: 0px"
|
||||
:hasPermission="'device/Instance:' + i.key"
|
||||
>
|
||||
<a-button
|
||||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
<template #icon
|
||||
><AIcon :type="i.icon"
|
||||
/></a-button>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
/></template>
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</JTable>
|
||||
</j-space>
|
||||
</template>
|
||||
</JProTable>
|
||||
<BindChildDevice v-if="visible" @change="closeBindDevice" />
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
|
@ -97,11 +119,17 @@ import { useInstanceStore } from '@/store/instance';
|
|||
import { storeToRefs } from 'pinia';
|
||||
import { message } from 'ant-design-vue';
|
||||
import BindChildDevice from './BindChildDevice/index.vue';
|
||||
import { usePermissionStore } from '@/store/permission';
|
||||
import SaveChild from './SaveChild/index.vue';
|
||||
|
||||
const instanceStore = useInstanceStore();
|
||||
const { detail } = storeToRefs(instanceStore);
|
||||
const router = useRouter();
|
||||
|
||||
const childVisible = ref(false);
|
||||
const permissionStore = usePermissionStore();
|
||||
// watchEffect(() => {
|
||||
// console.log(detail.value);
|
||||
// });
|
||||
const statusMap = new Map();
|
||||
statusMap.set('online', 'success');
|
||||
statusMap.set('offline', 'error');
|
||||
|
@ -111,6 +139,7 @@ const childDeviceRef = ref<Record<string, any>>({});
|
|||
const params = ref<Record<string, any>>({});
|
||||
const _selectedRowKeys = ref<string[]>([]);
|
||||
const visible = ref<boolean>(false);
|
||||
const current = ref({});
|
||||
|
||||
const columns = [
|
||||
{
|
||||
|
@ -192,7 +221,7 @@ const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
|
|||
},
|
||||
},
|
||||
{
|
||||
key: 'unbind',
|
||||
key: 'action',
|
||||
text: '解绑',
|
||||
tooltip: {
|
||||
title: '解绑',
|
||||
|
@ -215,6 +244,18 @@ const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'update',
|
||||
text: '编辑',
|
||||
tooltip: {
|
||||
title: '编辑',
|
||||
},
|
||||
icon: 'EditOutlined',
|
||||
onClick: () => {
|
||||
current.value = data;
|
||||
childVisible.value = true;
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
|
@ -252,6 +293,10 @@ const closeBindDevice = (val: boolean) => {
|
|||
childDeviceRef.value?.reload();
|
||||
}
|
||||
};
|
||||
|
||||
const closeChildSave = () => {
|
||||
childVisible.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -306,23 +306,6 @@ const columns = [
|
|||
const _selectedRowKeys = ref<string[]>([]);
|
||||
const currentForm = ref({});
|
||||
|
||||
const onSelectChange = (keys: string[]) => {
|
||||
_selectedRowKeys.value = [...keys];
|
||||
};
|
||||
|
||||
const cancelSelect = () => {
|
||||
_selectedRowKeys.value = [];
|
||||
};
|
||||
|
||||
// const handleClick = (dt: any) => {
|
||||
// if (_selectedRowKeys.value.includes(dt.id)) {
|
||||
// const _index = _selectedRowKeys.value.findIndex((i) => i === dt.id);
|
||||
// _selectedRowKeys.value.splice(_index, 1);
|
||||
// } else {
|
||||
// _selectedRowKeys.value = [..._selectedRowKeys.value, dt.id];
|
||||
// }
|
||||
// };
|
||||
|
||||
const getActions = (
|
||||
data: Partial<Record<string, any>>,
|
||||
type: 'card' | 'table',
|
||||
|
|
|
@ -116,6 +116,9 @@
|
|||
@click="i.onClick"
|
||||
type="link"
|
||||
style="padding: 0px"
|
||||
:hasPermission="
|
||||
'rule-engine/Instance:' + i.key
|
||||
"
|
||||
>
|
||||
<template #icon
|
||||
><AIcon :type="i.icon"
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
<template>
|
||||
<j-dropdown class='scene-select' trigger='click'>
|
||||
<div :class='dropdownButtonClass'>
|
||||
<span :style='LabelStyle'>
|
||||
{{ label }}
|
||||
</span>
|
||||
</div>
|
||||
<template #overlay>
|
||||
<template v-if='options.length'>
|
||||
<j-menu v-if='component === "select"' @click='menuSelect'>
|
||||
<j-menu-item v-for='item in options' :key='item.value'>{{ item.label }}</j-menu-item>
|
||||
</j-menu>
|
||||
<j-tree
|
||||
:selectedKeys='selectValue ? [selectValue] : []'
|
||||
:treeData='options'
|
||||
@select='treeSelect'
|
||||
/>
|
||||
</template>
|
||||
<div class='scene-select-empty' v-else>
|
||||
<j-empty />
|
||||
</div>
|
||||
</template>
|
||||
</j-dropdown>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup name='DropdownButton'>
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
type LabelType = string | number | undefined
|
||||
|
||||
type DropdownButtonOptions = {
|
||||
label: string;
|
||||
value: string;
|
||||
children?: DropdownButtonOptions[];
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
type Emit = {
|
||||
(e: 'update:value', data: string | number): void
|
||||
(e: 'select', data: DropdownButtonOptions | undefined ): void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: undefined
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<Array<DropdownButtonOptions>>,
|
||||
default: () => []
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'column' // 'column' | 'termType' | 'value' | 'type'
|
||||
},
|
||||
component: {
|
||||
type: String,
|
||||
default: 'select' // 'select' | 'treeSelect'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const label = ref<LabelType>(props.placeholder)
|
||||
const selectValue = ref(props.value)
|
||||
const flatMapTree = new Map()
|
||||
|
||||
const LabelStyle = computed(() => {
|
||||
return {
|
||||
color: selectValue.value ? '#' : '#'
|
||||
}
|
||||
})
|
||||
|
||||
const dropdownButtonClass = computed(() => ({
|
||||
'dropdown-button': true,
|
||||
'column': props.type === 'column',
|
||||
'termType': props.type === 'termType',
|
||||
'value': props.type === 'value',
|
||||
'type': props.type === 'type',
|
||||
}))
|
||||
|
||||
const getOption = (key?: string | number): DropdownButtonOptions | undefined => {
|
||||
let option
|
||||
for(let i = props.options.length - 1; i >= 0; i --) {
|
||||
const cacheOption = props.options[i]
|
||||
if (cacheOption.value === key) {
|
||||
option = {
|
||||
...cacheOption
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return option
|
||||
}
|
||||
|
||||
const treeSelect = () => {
|
||||
|
||||
}
|
||||
|
||||
const menuSelect = (v: any) => {
|
||||
const option = getOption(props.value)
|
||||
emit('update:value', v.key)
|
||||
emit('select', option)
|
||||
}
|
||||
|
||||
watch([props.options, props.value], () => {
|
||||
const option = getOption(props.value)
|
||||
console.log(props.value)
|
||||
if (option) {
|
||||
label.value = option.label
|
||||
} else {
|
||||
label.value = props.value || props.placeholder
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.dropdown-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.column {
|
||||
color: #00a4fe;
|
||||
background-color: rgba(154, 219, 255, 0.3);
|
||||
border-color: rgba(0, 164, 254, 0.3);
|
||||
}
|
||||
|
||||
.termType {
|
||||
color: #2f54eb;
|
||||
background-color: rgba(163, 202, 255, 0.3);
|
||||
border-color: rgba(47, 84, 235, 0.3);
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #692ca7;
|
||||
background-color: rgba(188, 125, 238, 0.1);
|
||||
border-color: rgba(188, 125, 238, 0.5);
|
||||
}
|
||||
|
||||
.type {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<j-dropdown class='scene-select' trigger='click'>
|
||||
<div :class='dropdownButtonClass'>
|
||||
<AIcon v-if='!!icon' :type='icon' />
|
||||
{{ label }}
|
||||
</div>
|
||||
<template #overlay>
|
||||
<div class='scene-select-content'>
|
||||
<template v-if='options.length'>
|
||||
<drop-menus
|
||||
v-if='component === "select"'
|
||||
:value='selectValue'
|
||||
:options='options'
|
||||
@click='menuSelect'
|
||||
/>
|
||||
<DropdownTimePicker
|
||||
v-else-if='["date","time"].includes(component)'
|
||||
:type='component'
|
||||
@change='timeSelect'
|
||||
/>
|
||||
<div v-else>
|
||||
<j-tree
|
||||
:selectedKeys='selectValue ? [selectValue] : []'
|
||||
:treeData='options'
|
||||
@select='treeSelect'
|
||||
:height='450'
|
||||
:virtual='true'
|
||||
>
|
||||
<template #title="{ name, description }">
|
||||
<j-space>
|
||||
{{ name }}
|
||||
<span v-if='description' class='tree-title-description'>{{ description }}</span>
|
||||
</j-space>
|
||||
</template>
|
||||
</j-tree>
|
||||
</div>
|
||||
</template>
|
||||
<div class='scene-select-empty' v-else>
|
||||
<j-empty />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</j-dropdown>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup name='DropdownButton'>
|
||||
import type { PropType } from 'vue'
|
||||
import DropMenus from './Menus.vue'
|
||||
import DropdownTimePicker from './Time.vue'
|
||||
import { getOption } from './util'
|
||||
import type { DropdownButtonOptions } from './util'
|
||||
|
||||
type LabelType = string | number | boolean | undefined
|
||||
|
||||
type Emit = {
|
||||
(e: 'update:value', data: string | number): void
|
||||
(e: 'select', data: DropdownButtonOptions | string | undefined ): void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
value: {
|
||||
type: [String, Number, Boolean],
|
||||
default: undefined
|
||||
},
|
||||
valueName: {
|
||||
type: String,
|
||||
default: 'value'
|
||||
},
|
||||
labelName: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<Array<DropdownButtonOptions>>,
|
||||
default: () => []
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'column' // 'column' | 'termType' | 'value' | 'type'
|
||||
},
|
||||
component: {
|
||||
type: String,
|
||||
default: 'select' // 'select' | 'treeSelect'
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const label = ref<LabelType>(props.placeholder)
|
||||
const selectValue = ref(props.value)
|
||||
const flatMapTree = new Map()
|
||||
|
||||
const LabelStyle = computed(() => {
|
||||
return {
|
||||
color: selectValue.value ? '#' : '#'
|
||||
}
|
||||
})
|
||||
|
||||
const dropdownButtonClass = computed(() => ({
|
||||
'dropdown-button': true,
|
||||
'column': props.type === 'column',
|
||||
'termType': props.type === 'termType',
|
||||
'value': props.type === 'value',
|
||||
'type': props.type === 'type',
|
||||
}))
|
||||
|
||||
const treeSelect = (v: any) => {
|
||||
|
||||
}
|
||||
|
||||
const timeSelect = (v: string) => {
|
||||
emit('update:value', v)
|
||||
emit('select', v)
|
||||
}
|
||||
|
||||
const menuSelect = (v: any) => {
|
||||
const option = getOption(props.options, props.value, props.valueName)
|
||||
emit('update:value', v.key)
|
||||
emit('select', option)
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
const option = getOption(props.options, props.value, props.valueName)
|
||||
if (option && Object.keys(option).length) {
|
||||
label.value = option[props.labelName] || option.name
|
||||
} else {
|
||||
label.value = props.value || props.placeholder
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
@import './index.less';
|
||||
</style>
|
|
@ -0,0 +1,81 @@
|
|||
<template>
|
||||
<j-menu class='scene-dropdown-menus' @click='click' :selectedKeys='[myValue]'>
|
||||
<j-menu-item v-for='item in myOptions' :key='item.value' :title='item.label'>
|
||||
{{ item.label }}
|
||||
</j-menu-item>
|
||||
</j-menu>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup name='DropdownMenus'>
|
||||
import { isBoolean } from 'lodash-es'
|
||||
import { getOption } from '../DropdownButton/util'
|
||||
|
||||
type ValueType = string| number | boolean
|
||||
type Emits = {
|
||||
(e: 'update:value', value: ValueType): void
|
||||
(e: 'click', data: any): void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: [String, Number, Boolean],
|
||||
default: undefined
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const myOptions = computed(() => {
|
||||
return props.options.map((item: any) => {
|
||||
let _label = item.label || item.name
|
||||
if (isBoolean(item.value)) {
|
||||
_label = item.value === true ? '是' : '否'
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
label: _label,
|
||||
value: item.value || item.id,
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const myValue = ref(props.value)
|
||||
|
||||
const click = (e: any) => {
|
||||
const option = getOption(myOptions.value, e.key)
|
||||
myValue.value = e.key
|
||||
emit('update:value', e.key)
|
||||
emit('click', {
|
||||
key: e.key,
|
||||
...option
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
.scene-dropdown-menus {
|
||||
border: 0px;
|
||||
|
||||
:deep(.ant-menu-item){
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
padding: 0 4px;
|
||||
margin: 0;
|
||||
|
||||
&:hover {
|
||||
background-color: @item-hover-bg;
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
&.ant-menu-item-selected {
|
||||
background-color: @primary-1;
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<div class='dropdown-time-picker'>
|
||||
<j-time-picker
|
||||
v-if='type === "time"'
|
||||
open
|
||||
class='manual-time-picker'
|
||||
v-model:value='myValue'
|
||||
:format='myFormat'
|
||||
:valueFormat='myFormat'
|
||||
:getPopupContainer='getPopupContainer'
|
||||
popupClassName='manual-time-picker-popup'
|
||||
@change='change'
|
||||
/>
|
||||
<j-date-picker
|
||||
v-else
|
||||
open
|
||||
class='manual-time-picker'
|
||||
v-model:value='myValue'
|
||||
:format='myFormat'
|
||||
:valueFormat='myFormat'
|
||||
:getPopupContainer='getPopupContainer'
|
||||
@change='change'
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='DropdownTime'>
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
type Emit = {
|
||||
(e: 'update:value', value: string) : void
|
||||
(e: 'change', value: string) : void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
type: String,
|
||||
default: 'time' // time | date
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
const myFormat = props.format || ( props.type === 'time' ? 'HH:mm:ss' : 'YYYY-MM-DD HH:mm:ss')
|
||||
const myValue = ref(props.value || dayjs(new Date()).format(myFormat))
|
||||
|
||||
const getPopupContainer = (trigger: HTMLElement) => {
|
||||
return trigger?.parentNode || document.body
|
||||
}
|
||||
|
||||
const change = (e: string) => {
|
||||
myValue.value = e
|
||||
emit('update:value', e)
|
||||
emit('change', e)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='less'>
|
||||
.dropdown-time-picker {
|
||||
>div{
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.manual-time-picker{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-picker-dropdown {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
.ant-picker-panel {
|
||||
width: 100%
|
||||
}
|
||||
}
|
||||
|
||||
.ant-picker-panel-container {
|
||||
box-shadow: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,44 @@
|
|||
.dropdown-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.scene-select-content {
|
||||
position: relative;
|
||||
min-width: 220px;
|
||||
padding: 4px;
|
||||
background: #fff;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d;
|
||||
}
|
||||
|
||||
.column {
|
||||
color: #00a4fe;
|
||||
background-color: rgba(154, 219, 255, 0.3);
|
||||
border-color: rgba(0, 164, 254, 0.3);
|
||||
}
|
||||
|
||||
.termType {
|
||||
color: #2f54eb;
|
||||
background-color: rgba(163, 202, 255, 0.3);
|
||||
border-color: rgba(47, 84, 235, 0.3);
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #692ca7;
|
||||
background-color: rgba(188, 125, 238, 0.1);
|
||||
border-color: rgba(188, 125, 238, 0.5);
|
||||
}
|
||||
|
||||
.type {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.tree-title-description {
|
||||
padding-left: 5px;
|
||||
color: grey;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import Dropdown from './DropdownButton.vue'
|
||||
import DropdownMenus from './Menus.vue'
|
||||
import DropdownTimePicker from './Time.vue'
|
||||
|
||||
export default Dropdown
|
||||
|
||||
export {
|
||||
DropdownMenus, DropdownTimePicker
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
export type DropdownButtonOptions = {
|
||||
label: string;
|
||||
value: string;
|
||||
children?: DropdownButtonOptions[];
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export const getComponent = (type: string): string => {
|
||||
switch (type) {
|
||||
case 'int':
|
||||
case 'long':
|
||||
case 'float':
|
||||
case 'double':
|
||||
return 'number'
|
||||
case 'metric':
|
||||
case 'enum':
|
||||
case 'boolean':
|
||||
return 'menu'
|
||||
case 'date':
|
||||
return 'date'
|
||||
case 'tree':
|
||||
return 'tree'
|
||||
default:
|
||||
return 'input'
|
||||
}
|
||||
}
|
||||
|
||||
export const getOption = (data: any[], value?: string | number | boolean, key: string = 'name'): DropdownButtonOptions | any => {
|
||||
let option = {}
|
||||
if (!value) return option
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const item = data[i]
|
||||
if (item[key] === value) {
|
||||
option = data[i]
|
||||
break
|
||||
} else if (item.children && item.children.length){
|
||||
option = getOption(item.children, value, key)
|
||||
if (option) break
|
||||
}
|
||||
}
|
||||
return option
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ParamsDropdown'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,49 @@
|
|||
<template>
|
||||
<ParamsDropdown
|
||||
v-model:value='myValue[0]'
|
||||
v-model:source='mySource'
|
||||
:options='options'
|
||||
:icon='icon'
|
||||
:placeholder='placeholder'
|
||||
:tabs-options='tabsOptions'
|
||||
@select='onSelect'
|
||||
/>
|
||||
<ParamsDropdown
|
||||
v-model:value='myValue[1]'
|
||||
v-model:source='mySource'
|
||||
:icon='icon'
|
||||
:placeholder='placeholder'
|
||||
:tabs-options='tabsOptions'
|
||||
:options='options'
|
||||
@select='onSelect'
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup name='DoubleParamsDropdown'>
|
||||
import ParamsDropdown from './index.vue'
|
||||
import { defaultSetting, ValueType } from './typings'
|
||||
|
||||
type Emit = {
|
||||
(e: 'update:value', data: ValueType): void
|
||||
(e: 'update:source', data: string): void
|
||||
(e: 'select', data: any): void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
...defaultSetting
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const myValue = ref<ValueType>(props.value)
|
||||
const mySource = ref<string>(props.source)
|
||||
|
||||
const onSelect = () => {
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,8 @@
|
|||
import ParamsDropdown from './index.vue'
|
||||
import DoubleParamsDropdown from './Double.vue'
|
||||
|
||||
export default ParamsDropdown
|
||||
|
||||
export {
|
||||
DoubleParamsDropdown
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
<template>
|
||||
<j-dropdown
|
||||
class='scene-select-value'
|
||||
trigger='click'
|
||||
v-model:visible='visible'
|
||||
@visibleChange='visibleChange'
|
||||
>
|
||||
<div class='dropdown-button value' @click.prevent='visible = true'>
|
||||
<AIcon v-if='!!icon' :type='icon' />
|
||||
{{ label }}
|
||||
</div>
|
||||
<template #overlay>
|
||||
<div class='scene-select-content'>
|
||||
<j-tabs
|
||||
@change='tabsChange'
|
||||
v-model:activeKey='mySource'
|
||||
>
|
||||
<j-tab-pane v-for='item in tabsOptions' :tab='item.label' :key='item.key'>
|
||||
<div class='select-box-content'>
|
||||
<DropdownTimePicker
|
||||
v-if='["time","date"].includes(item.component)'
|
||||
:type='item.component'
|
||||
v-model:value='myValue'
|
||||
@change='timeChange'
|
||||
/>
|
||||
<DropdownMenus
|
||||
v-if='["metric","enum", "boolean"].includes(item.component)'
|
||||
:options='options'
|
||||
@change='onSelect'
|
||||
/>
|
||||
<ValueItem
|
||||
v-else-if='valueItemKey.includes(item.component)'
|
||||
v-model:modelValue='myValue'
|
||||
:itemType='getComponent(item.component)'
|
||||
:options='options'
|
||||
@change='valueItemChange'
|
||||
/>
|
||||
<j-tree
|
||||
v-else
|
||||
:selectedKeys='myValue ? [myValue] : []'
|
||||
:treeData='options'
|
||||
@select='treeSelect'
|
||||
:height='450'
|
||||
:virtual='true'
|
||||
>
|
||||
<template #title="{ name, description }">
|
||||
<j-space>
|
||||
{{ name }}
|
||||
<span v-if='description' class='tree-title-description'>{{ description }}</span>
|
||||
</j-space>
|
||||
</template>
|
||||
</j-tree>
|
||||
</div>
|
||||
</j-tab-pane>
|
||||
</j-tabs>
|
||||
</div>
|
||||
</template>
|
||||
</j-dropdown>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup name='ParamsDropdown'>
|
||||
import ValueItem from '@/components/ValueItem/index.vue'
|
||||
import type { ValueType } from './typings'
|
||||
import { defaultSetting } from './typings'
|
||||
import { DropdownMenus, DropdownTimePicker} from '../DropdownButton'
|
||||
import { getComponent, getOption } from '../DropdownButton/util'
|
||||
|
||||
const valueItemKey = ['int', 'int','long','float','double','string', 'password']
|
||||
|
||||
type Emit = {
|
||||
(e: 'update:value', data: ValueType): void
|
||||
(e: 'update:source', data: string): void
|
||||
(e: 'select', data: any): void
|
||||
(e: 'tabChange', data: any): void
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
...defaultSetting
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const myValue = ref<ValueType>(props.value)
|
||||
const mySource = ref<string>(props.source)
|
||||
const label = ref<any>(props.placeholder)
|
||||
const visible = ref(false)
|
||||
|
||||
nextTick(() => {
|
||||
mySource.value = props.source
|
||||
myValue.value = props.value
|
||||
})
|
||||
|
||||
const tabsChange = (e: string) => {
|
||||
mySource.value = e
|
||||
myValue.value = undefined
|
||||
}
|
||||
|
||||
const updateValue = () => {
|
||||
emit('update:source', mySource.value)
|
||||
emit('update:value', myValue.value)
|
||||
}
|
||||
|
||||
const treeSelect = (e: any) => {
|
||||
console.log('treeSelect', e)
|
||||
visible.value = false
|
||||
label.value = e.fullname || e.name
|
||||
emit('update:value', e.id)
|
||||
emit('select', e)
|
||||
}
|
||||
|
||||
const valueItemChange = (e: string) => {
|
||||
console.log('valueItemSelect', e)
|
||||
label.value = e
|
||||
emit('update:value', e)
|
||||
emit('select', e)
|
||||
}
|
||||
|
||||
const sonSelect = (e: string, option: any) => {
|
||||
visible.value = false
|
||||
label.value = option.label
|
||||
emit('update:value', e)
|
||||
emit('select', e)
|
||||
}
|
||||
|
||||
const timeChange = (e: any) => {
|
||||
label.value = e
|
||||
visible.value = false
|
||||
emit('update:value', e)
|
||||
emit('select', e)
|
||||
}
|
||||
|
||||
const visibleChange = (v: boolean) => {
|
||||
visible.value = v
|
||||
}
|
||||
|
||||
watch([props.options, props.value], () => {
|
||||
const option = getOption(props.options, props.value as string, props.valueName) // 回显label值
|
||||
if (option && Object.keys(option).length) {
|
||||
label.value = option[props.labelName] || option.name
|
||||
} else {
|
||||
label.value = props.value || props.placeholder
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
@import '../DropdownButton/index.less';
|
||||
.manual-time-picker {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: 0;
|
||||
border: none;
|
||||
visibility: hidden;
|
||||
:deep(.ant-picker-input) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,58 @@
|
|||
import type { PropType } from 'vue'
|
||||
|
||||
export type LabelType = string | number | undefined
|
||||
|
||||
export type DropdownButtonOptions = {
|
||||
label: string;
|
||||
value: string;
|
||||
children?: DropdownButtonOptions[];
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export type TabsOption = {
|
||||
label: string;
|
||||
key: string;
|
||||
component: string,
|
||||
options: DropdownButtonOptions[]
|
||||
}
|
||||
type ValueArrayType = [string, number]
|
||||
export type ValueType = string | number | undefined | ValueArrayType
|
||||
|
||||
export const defaultSetting = {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
value: {
|
||||
type: [String, Number, Array] as PropType<ValueType>,
|
||||
default: undefined
|
||||
},
|
||||
valueName: {
|
||||
type: String,
|
||||
default: 'value'
|
||||
},
|
||||
labelName: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
default: 'fixed'
|
||||
},
|
||||
options: {
|
||||
type: Array as PropType<Array<DropdownButtonOptions>>,
|
||||
default: () => []
|
||||
},
|
||||
metricOptions: { // 指标值
|
||||
type: Array as PropType<Array<DropdownButtonOptions>>,
|
||||
default: () => []
|
||||
},
|
||||
tabsOptions: {
|
||||
type: Array as PropType<Array<TabsOption>>,
|
||||
default: () => []
|
||||
}
|
||||
}
|
|
@ -16,8 +16,11 @@
|
|||
@mouseout='mouseout'
|
||||
>
|
||||
<DropdownButton
|
||||
:options='options'
|
||||
:options='columnOptions'
|
||||
icon='icon-zhihangdongzuoxie-1'
|
||||
type='column'
|
||||
value-name='column'
|
||||
label-name='fullName'
|
||||
placeholder='请选择参数'
|
||||
v-model:value='paramsValue.column'
|
||||
component='treeSelect'
|
||||
|
@ -26,18 +29,41 @@
|
|||
<DropdownButton
|
||||
:options='termTypeOptions'
|
||||
type="termType"
|
||||
value-name='id'
|
||||
label-name='name'
|
||||
placeholder="操作符"
|
||||
v-model:value='paramsValue.termsType'
|
||||
v-model:value='paramsValue.termType'
|
||||
@select='termsTypeSelect'
|
||||
/>
|
||||
<termplate v-if='showDouble'>
|
||||
|
||||
</termplate>
|
||||
<DoubleParamsDropdown
|
||||
v-if='showDouble'
|
||||
icon='icon-canshu'
|
||||
placeholder='参数值'
|
||||
:options='valueOptions'
|
||||
:tabsOptions='[
|
||||
{ label: "手动输入", component: "input", key: "fixed" },
|
||||
{ label: "指标值", component: "time", key: "manual" }
|
||||
]'
|
||||
v-model:value='paramsValue.value.value'
|
||||
v-model:source='paramsValue.value.source'
|
||||
/>
|
||||
<ParamsDropdown
|
||||
v-else
|
||||
icon='icon-canshu'
|
||||
placeholder='参数值'
|
||||
:options='valueOptions'
|
||||
:tabsOptions='[
|
||||
{ label: "手动输入", component: "time", key: "fixed" },
|
||||
{ label: "指标值", component: "input", key: "manual" },
|
||||
]'
|
||||
v-model:value='paramsValue.value.value'
|
||||
v-model:source='paramsValue.value.source'
|
||||
/>
|
||||
<j-popconfirm title='确认删除?' @confirm='onDelete'>
|
||||
<div v-show='showDelete' class='button-delete'> <AIcon type='CloseOutlined' /></div>
|
||||
</j-popconfirm>
|
||||
</div>
|
||||
<div class='term-add' @click.stop='termAdd'>
|
||||
<div class='term-add' @click.stop='termAdd' v-if='isLast'>
|
||||
<div class='terms-content'>
|
||||
<AIcon type='PlusOutlined' style='font-size: 12px' />
|
||||
</div>
|
||||
|
@ -48,7 +74,9 @@
|
|||
<script setup lang='ts' name='ParamsItem'>
|
||||
import type { PropType } from 'vue'
|
||||
import type { TermsType } from '@/views/rule-engine/Scene/typings'
|
||||
import DropdownButton from '../DropdownButton.vue'
|
||||
import DropdownButton from '../DropdownButton'
|
||||
import { getOption } from '../DropdownButton/util'
|
||||
import ParamsDropdown, { DoubleParamsDropdown } from '../ParamsDropdown'
|
||||
import { inject } from 'vue'
|
||||
import { ContextKey } from './util'
|
||||
|
||||
|
@ -70,32 +98,33 @@ const props = defineProps({
|
|||
default: () => ({
|
||||
column: '',
|
||||
type: '',
|
||||
termsType: undefined,
|
||||
termType: undefined,
|
||||
value: {
|
||||
source: 'fixed',
|
||||
value: undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const paramsValue = reactive<TermsType>({
|
||||
column: '',
|
||||
type: '',
|
||||
termType: undefined,
|
||||
value: undefined
|
||||
column: props.value.column,
|
||||
type: props.value.type,
|
||||
termType: props.value.termType,
|
||||
value: props.value.value
|
||||
})
|
||||
|
||||
const showDelete = ref(false)
|
||||
const columnOptions = inject(ContextKey)
|
||||
|
||||
const options = computed(() => {
|
||||
function handleOptions() {
|
||||
|
||||
}
|
||||
|
||||
return []
|
||||
})
|
||||
const columnOptions: any = inject(ContextKey)
|
||||
const options = ref<any>([])
|
||||
|
||||
const termTypeOptions = computed(() => {
|
||||
const option = getOption(columnOptions.value, paramsValue.column, 'column')
|
||||
return option && Object.keys(option).length ? option.termTypes : []
|
||||
})
|
||||
|
||||
const tabsOptions = computed(() => {
|
||||
// 获取当前value对应的option
|
||||
return []
|
||||
})
|
||||
|
||||
|
@ -131,7 +160,11 @@ const onDelete = () => {
|
|||
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const valueOptions = computed(() => {
|
||||
return []
|
||||
})
|
||||
|
||||
nextTick(() => {
|
||||
Object.assign(paramsValue, props.value)
|
||||
})
|
||||
|
||||
|
|
|
@ -56,7 +56,8 @@ const sceneStore = useSceneStore()
|
|||
const { data } = storeToRefs(sceneStore)
|
||||
|
||||
const open = ref(false)
|
||||
const columnOptions = ref<any[]>([])
|
||||
const columnOptions = ref<any>([])
|
||||
|
||||
|
||||
provide(ContextKey, columnOptions)
|
||||
|
||||
|
@ -80,7 +81,7 @@ const queryColumn = (dataModel: FormModelType) => {
|
|||
const cloneDevice = cloneDeep(dataModel)
|
||||
cloneDevice.branches = cloneDevice.branches?.filter(item => !!item)
|
||||
getParseTerm(cloneDevice).then(res => {
|
||||
columnOptions.value = res as any
|
||||
columnOptions.value = res.result
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -89,12 +90,12 @@ const addBranches = () => {
|
|||
}
|
||||
|
||||
const branchesDelete = (index: number) => {
|
||||
if ((data as FormModelType).branches?.length === 2) {
|
||||
(data as FormModelType).branches?.splice(index, 1, null as any)
|
||||
if (data.value.branches?.length === 2) {
|
||||
data.value.branches?.splice(index, 1, null as any)
|
||||
} else {
|
||||
(data as FormModelType).branches?.splice(index, 1)
|
||||
data.value.branches?.splice(index, 1)
|
||||
}
|
||||
(data as FormModelType).options?.when?.splice(index, 1)
|
||||
data.value.options?.when?.splice(index, 1)
|
||||
}
|
||||
|
||||
const branchesDeleteAll = () => {
|
||||
|
@ -102,15 +103,16 @@ const branchesDeleteAll = () => {
|
|||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if ((data as FormModelType).trigger?.device) {
|
||||
queryColumn((data as FormModelType))
|
||||
console.log(data.value.trigger, data.value.trigger?.device)
|
||||
if (data.value.trigger?.device) {
|
||||
queryColumn(data.value)
|
||||
}
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
open.value = !(
|
||||
(data as FormModelType).branches &&
|
||||
(data as FormModelType).branches?.length === 1
|
||||
data.value.branches &&
|
||||
data.value.branches?.length === 1
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<script setup lang='ts' name='TermsItem'>
|
||||
import type { PropType } from 'vue'
|
||||
import type { TermsType } from '@/views/rule-engine/Scene/typings'
|
||||
import DropdownButton from '../DropdownButton.vue'
|
||||
import DropdownButton from '../DropdownButton'
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useSceneStore } from 'store/scene'
|
||||
import ParamsItem from './ParamsItem.vue'
|
||||
|
@ -86,14 +86,12 @@ const props = defineProps({
|
|||
const showDelete = ref(false)
|
||||
|
||||
const mouseover = () => {
|
||||
console.log(props.whenName)
|
||||
if (props.whenName !== 0){
|
||||
showDelete.value = true
|
||||
}
|
||||
}
|
||||
|
||||
const mouseout = () => {
|
||||
console.log(props.whenName)
|
||||
if (props.whenName !== 0){
|
||||
showDelete.value = false
|
||||
}
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
export const ContextKey = 'columnOptions'
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ export default defineConfig(({ mode}) => {
|
|||
},
|
||||
},
|
||||
plugins: [
|
||||
|
||||
vue(),
|
||||
monacoEditorPlugin({}),
|
||||
vueJsx(),
|
||||
|
|
Loading…
Reference in New Issue