fix: 合并冲突
This commit is contained in:
commit
d9c2da7f4e
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<a-modal :mask-closable="false" visible width="70vw" title="设置属性规则" @cancel="handleCancel" @ok="handleOk">
|
||||
<j-modal :mask-closable="false" visible width="70vw" title="设置属性规则" @cancel="handleCancel" @ok="handleOk">
|
||||
<div class="advance-box">
|
||||
<div class="left">
|
||||
<Editor
|
||||
|
@ -20,7 +20,7 @@
|
|||
<Operator :id="id" @add-operator-value="addOperatorValue"/>
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</j-modal>
|
||||
</template>
|
||||
<script setup lang="ts" name="Advance">
|
||||
import Editor from '../Editor/index.vue'
|
||||
|
|
|
@ -12,28 +12,28 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-table :columns="columns" :data-source="property" :pagination="false" bordered size="small">
|
||||
<j-table :columns="columns" :data-source="property" :pagination="false" bordered size="small">
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.key === 'id'">
|
||||
<j-auto-complete :options="options" v-model:value="record.id" size="small" width="130px"/>
|
||||
</template>
|
||||
<template v-if="column.key === 'current'">
|
||||
<a-input v-model:value="record.current" size="small"></a-input>
|
||||
<j-input v-model:value="record.current" size="small"></j-input>
|
||||
</template>
|
||||
<template v-if="column.key === 'last'">
|
||||
<a-input v-model:value="record.last" size="small"></a-input>
|
||||
<j-input v-model:value="record.last" size="small"></j-input>
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<delete-outlined @click="deleteItem(index)" />
|
||||
<AIcon type="DeleteOutlined" @click="deleteItem(index)" />
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-button type="dashed" block style="margin-top: 5px" @click="addItem">
|
||||
</j-table>
|
||||
<j-button type="dashed" block style="margin-top: 5px" @click="addItem">
|
||||
<template #icon>
|
||||
<plus-outlined />
|
||||
<AIcon type="PlusOutlined" />
|
||||
</template>
|
||||
添加条目
|
||||
</a-button>
|
||||
</j-button>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="header">
|
||||
|
@ -57,15 +57,14 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="log">
|
||||
<a-descriptions>
|
||||
<a-descriptions-item v-for="item in ruleEditorStore.state.log" :label="moment(item.time).format('HH:mm:ss')"
|
||||
<j-descriptions>
|
||||
<j-descriptions-item v-for="item in ruleEditorStore.state.log" :label="moment(item.time).format('HH:mm:ss')"
|
||||
:key="item.time" :span="3">
|
||||
<a-tooltip placement="top" :title="item.content">
|
||||
<j-tooltip placement="top" :title="item.content">
|
||||
{{ item.content }}
|
||||
</a-tooltip>
|
||||
</a-descriptions-item>
|
||||
))}
|
||||
</a-descriptions>
|
||||
</j-tooltip>
|
||||
</j-descriptions-item>
|
||||
</j-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,35 +7,33 @@
|
|||
{{ item.value }}
|
||||
</span>
|
||||
<span>
|
||||
<a-dropdown>
|
||||
<more-outlined />
|
||||
<j-dropdown>
|
||||
<AIcon type="MoreOutlined" />
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item v-for="item in symbolList.filter((t: SymbolType, i: number) => i > 6)" :key="item.key"
|
||||
<j-menu>
|
||||
<j-menu-item v-for="item in symbolList.filter((t: SymbolType, i: number) => i > 6)" :key="item.key"
|
||||
@click="addOperatorValue(item.value)">
|
||||
{{ item.value }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</j-menu-item>
|
||||
</j-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</j-dropdown>
|
||||
</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span v-if="mode !== 'advance'">
|
||||
<a-tooltip :title="!id ? '请先输入标识' : '设置属性规则'">
|
||||
<fullscreen-outlined :class="!id ? 'disabled' : ''" @click="fullscreenClick" />
|
||||
</a-tooltip>
|
||||
<j-tooltip :title="!id ? '请先输入标识' : '设置属性规则'">
|
||||
<AIcon type="FullscreenOutlined" :class="!id ? 'disabled' : ''" @click="fullscreenClick" />
|
||||
</j-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor">
|
||||
<MonacoEditor v-if="loading" v-model:model-value="_value" theme="vs" ref="editor" />
|
||||
<JMonacoEditor v-if="loading" v-model:model-value="_value" theme="vs" ref="editor" lang="javascript"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts" name="Editor">
|
||||
import { FullscreenOutlined, MoreOutlined } from '@ant-design/icons-vue';
|
||||
import MonacoEditor from '@/components/MonacoEditor/index.vue';
|
||||
|
||||
interface Props {
|
||||
mode?: 'advance' | 'simple';
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
<template>
|
||||
<div class="operator-box">
|
||||
<a-input-search @search="search" allow-clear placeholder="搜索关键字" />
|
||||
<j-input-search @search="search" allow-clear placeholder="搜索关键字" />
|
||||
<div class="tree">
|
||||
<a-tree @select="selectTree" :field-names="{ title: 'name', key: 'id', }" auto-expand-parent
|
||||
<j-tree @select="selectTree" :field-names="{ title: 'name', key: 'id', }" auto-expand-parent
|
||||
:tree-data="data">
|
||||
<template #title="node">
|
||||
<div class="node">
|
||||
<div>{{ node.name }}</div>
|
||||
<div :class="node.children?.length > 0 ? 'parent' : 'add'">
|
||||
<a-popover v-if="node.type === 'property'" placement="right" title="请选择使用值">
|
||||
<j-popover v-if="node.type === 'property'" placement="right" title="请选择使用值">
|
||||
<template #content>
|
||||
<a-space direction="vertical">
|
||||
<a-tooltip placement="right" title="实时值为空时获取上一有效值补齐,实时值不为空则使用实时值">
|
||||
<a-button type="text" @click="recentClick(node)">
|
||||
<j-space direction="vertical">
|
||||
<j-tooltip placement="right" title="实时值为空时获取上一有效值补齐,实时值不为空则使用实时值">
|
||||
<j-button type="text" @click="recentClick(node)">
|
||||
$recent实时值
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="right" title="实时值的上一有效值">
|
||||
<a-button @click="lastClick(node)" type="text">
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
<j-tooltip placement="right" title="实时值的上一有效值">
|
||||
<j-button @click="lastClick(node)" type="text">
|
||||
上一值
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</template>
|
||||
<a>添加</a>
|
||||
</a-popover>
|
||||
</j-popover>
|
||||
|
||||
<a v-else @click="addClick(node)">
|
||||
添加
|
||||
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-tree>
|
||||
</j-tree>
|
||||
</div>
|
||||
<div class="explain">
|
||||
<Markdown :source="item?.description || ''"></Markdown>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<a-select v-model:value="_value" mode="tags" :options="options" :size="size" @change="change"></a-select>
|
||||
<a-select v-model:value="_value" mode="tags" :options="options" :size="size" @change="change" placeholder="请选择单位"></a-select>
|
||||
</template>
|
||||
<script setup lang="ts" name="InputSelect">
|
||||
import { SizeType } from 'ant-design-vue/es/config-provider';
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
<template v-if="['int', 'long', 'double', 'float'].includes(type)">
|
||||
<template v-if="value.range">
|
||||
<j-input-number v-model:value="value.value[0]" :max="value.value[1]" size="small"
|
||||
style="width: 100%;"></j-input-number>
|
||||
style="width: 100%;" placeholder="请输入"></j-input-number>
|
||||
~
|
||||
<j-input-number v-model:value="value.value[1]" :min="value.value[0]" size="small"
|
||||
style="width: 100%;"></j-input-number>
|
||||
style="width: 100%;" placeholder="请输入"></j-input-number>
|
||||
</template>
|
||||
<j-input-number v-else v-model:value="value.value" size="small" style="width: 100%;"></j-input-number>
|
||||
<j-input-number v-else v-model:value="value.value" size="small" style="width: 100%;" placeholder="请输入"></j-input-number>
|
||||
</template>
|
||||
<template v-else-if="type === 'date'">
|
||||
<j-range-picker v-if="value.range" show-time v-model:value="value.value" size="small" />
|
||||
<j-date-picker v-else show-time v-model:value="value.value" size="small" />
|
||||
<j-range-picker v-if="value.range" show-time v-model:value="value.value" size="small" placeholder="请输入"/>
|
||||
<j-date-picker v-else show-time v-model:value="value.value" size="small" placeholder="请输入"/>
|
||||
</template>
|
||||
<template v-else-if="type === 'boolean'">
|
||||
<j-select v-model:value="value.value[0]" :options="list" size="small" placeholder="请选择"></j-select>
|
||||
|
@ -57,7 +57,7 @@ const props = defineProps({
|
|||
}
|
||||
})
|
||||
|
||||
Form.useInjectFormItemContext()
|
||||
// Form.useInjectFormItemContext()
|
||||
|
||||
const changeChecked = (e: CheckboxChangeEvent) => {
|
||||
if (e.target.checked) {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<template>
|
||||
<j-button type="dashed" block @click="visible = true">
|
||||
<j-popover :visible="visible" placement="left">
|
||||
<template #title>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="width: 150px;">配置元素</div>
|
||||
<div @click="visible = false"><AIcon type="CloseOutlined" /></div>
|
||||
<div @click="visible = false">
|
||||
<AIcon type="CloseOutlined" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
|
@ -13,16 +16,15 @@
|
|||
<j-form-item label="说明" :name="name.concat(['description'])" :rules="[
|
||||
{ max: 200, message: '最多可输入200个字符' },
|
||||
]">
|
||||
<j-textarea v-model:value="_value.description" size="small"></j-textarea>
|
||||
<j-textarea v-model:value="_value.description" size="small" placeholder="请输入说明"></j-textarea>
|
||||
</j-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<j-button type="dashed" block @click="visible = true">
|
||||
配置元素
|
||||
<AIcon type="EditOutlined" class="item-icon" />
|
||||
</j-button>
|
||||
</j-popover>
|
||||
</j-button>
|
||||
</template>
|
||||
<script setup lang="ts" name="ArrayParam">
|
||||
import ValueTypeForm from '@/views/device/components/Metadata/Base/Edit/ValueTypeForm.vue';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<template>
|
||||
<j-button type="dashed" block>
|
||||
<j-popover placement="left" trigger="click">
|
||||
<template #title>
|
||||
<div class="edit-title" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
|
@ -11,14 +12,14 @@
|
|||
<j-select v-model:value="value[item.property]" :options="item.type?.elements?.map((e: { 'text': string, 'value': string }) => ({
|
||||
label: e.text,
|
||||
value: e.value,
|
||||
}))" size="small"></j-select>
|
||||
}))" size="small" :placeholder="`请输入${item.name}`"></j-select>
|
||||
</j-form-item>
|
||||
</div>
|
||||
</template>
|
||||
<j-button type="dashed" block>
|
||||
存储配置<AIcon type="EditOutlined" class="item-icon"/>
|
||||
</j-button>
|
||||
存储配置
|
||||
<AIcon type="EditOutlined" class="item-icon" />
|
||||
</j-popover>
|
||||
</j-button>
|
||||
</template>
|
||||
<script setup lang="ts" name="ConfigParam">
|
||||
import { PropType } from 'vue';
|
||||
|
@ -57,15 +58,17 @@ const props = defineProps({
|
|||
color: rgb(136, 136, 136);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label) {
|
||||
>label {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-select) {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(input) {
|
||||
height: 22px;
|
||||
}
|
||||
</style>
|
||||
}</style>
|
|
@ -18,13 +18,13 @@
|
|||
{ required: true, message: '请输入Value' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]">
|
||||
<j-input v-model:value="_value[index].value" size="small"></j-input>
|
||||
<j-input v-model:value="_value[index].value" size="small" placeholder="请输入Value"></j-input>
|
||||
</j-form-item>
|
||||
<j-form-item label="Text" :name="name.concat([index, 'text'])" :rules="[
|
||||
{ required: true, message: '请输入Text' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]">
|
||||
<j-input v-model:value="_value[index].text" size="small"></j-input>
|
||||
<j-input v-model:value="_value[index].text" size="small" placeholder="请输入Text"></j-input>
|
||||
</j-form-item>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -22,15 +22,15 @@
|
|||
message: 'ID只能由数字、字母、下划线、中划线组成',
|
||||
},
|
||||
]">
|
||||
<j-input v-model:value="_value[index].id" size="small"></j-input>
|
||||
<j-input v-model:value="_value[index].id" size="small" placeholder="请输入标识"></j-input>
|
||||
</j-form-item>
|
||||
<j-form-item label="名称" :name="name.concat([index, 'name'])" :rules="[
|
||||
{ required: true, message: '请输入名称' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]">
|
||||
<j-input v-model:value="_value[index].name" size="small"></j-input>
|
||||
<j-input v-model:value="_value[index].name" size="small" placeholder="请输入名称"></j-input>
|
||||
</j-form-item>
|
||||
<value-type-form v-model:value="_value[index].valueType" :name="name.concat([index, 'valueType'])" isSub
|
||||
<value-type-form v-model:value="_value[index].valueType" :name="name.concat([index, 'valueType'])" :isSub="isSub"
|
||||
key="json_sub"></value-type-form>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -69,6 +69,10 @@ const props = defineProps({
|
|||
name: {
|
||||
type: Array as PropType<(string | number)[]>,
|
||||
default: () => ([])
|
||||
},
|
||||
isSub: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{{ `#${index + 1}.` }}
|
||||
</div>
|
||||
<div class="item-middle item-editable">
|
||||
<j-popover :visible="editIndex === index" placement="top" @visible-change="change" trigger="click">
|
||||
<j-popover :visible="editIndex === index" placement="left" @visible-change="change" trigger="click">
|
||||
<template #title>
|
||||
<div class="edit-title" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="width: 150px;">配置参数</div>
|
||||
|
@ -24,13 +24,13 @@
|
|||
message: 'ID只能由数字、字母、下划线、中划线组成',
|
||||
},
|
||||
]">
|
||||
<j-input v-model:value="_value[index].id" size="small"></j-input>
|
||||
<j-input v-model:value="_value[index].id" size="small" placeholder="请输入标识"></j-input>
|
||||
</j-form-item>
|
||||
<j-form-item label="名称" :name="name.concat([index, 'name'])" :rules="[
|
||||
{ required: true, message: '请输入名称' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]">
|
||||
<j-input v-model:value="_value[index].name" size="small"></j-input>
|
||||
<j-input v-model:value="_value[index].name" size="small" placeholder="请输入名称"></j-input>
|
||||
</j-form-item>
|
||||
<j-form-item label="指标值" :name="name.concat([index, 'value'])" :rules="[
|
||||
{ required: true, validator: () => validateIndicator(_value[index]), message: '请输入指标值' }
|
||||
|
@ -41,7 +41,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<div class="item-edit" @click="handleEdit(index)">
|
||||
{{ item.name || '配置参数' }}
|
||||
<Ellipsis>{{ item.name || '配置参数' }}</Ellipsis>
|
||||
<AIcon type="EditOutlined" class="item-icon" />
|
||||
</div>
|
||||
</j-popover>
|
||||
|
@ -118,7 +118,7 @@ const validateIndicator = (value: any) => {
|
|||
return Promise.reject(new Error('请输入指标值'));
|
||||
}
|
||||
} else {
|
||||
if (value?.value === '' || value?.value === undefined) {
|
||||
if (!value?.value) {
|
||||
return Promise.reject(new Error('请输入指标值'));
|
||||
}
|
||||
}
|
||||
|
@ -151,6 +151,10 @@ const change = (visible: boolean) => {
|
|||
// }
|
||||
.item-edit {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
max-width: 240px;
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
|
|
|
@ -33,7 +33,10 @@ export const defaultBranches = [
|
|||
terms: [
|
||||
{
|
||||
column: undefined,
|
||||
value: undefined,
|
||||
value: {
|
||||
source: 'fixed',
|
||||
value: undefined
|
||||
},
|
||||
termType: undefined,
|
||||
key: 'params_1',
|
||||
type: 'and',
|
||||
|
@ -89,6 +92,8 @@ export const useSceneStore = defineStore('scene', () => {
|
|||
branches = cloneDeep(defaultBranches)
|
||||
if (triggerType === 'device') {
|
||||
branches.push(null)
|
||||
} else {
|
||||
branches[0].when.length = []
|
||||
}
|
||||
} else {
|
||||
const branchesLength = branches.length;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* @returns {boolean}
|
||||
*/
|
||||
export const phoneRegEx = (value: string) => {
|
||||
const phone = new RegExp('^(((\\+86)|(\\+86-))|((86)|(86\\-))|((0086)|(0086\\-)))?1[3|5|7|8]\\d{9}$')
|
||||
const phone = new RegExp('^(((\\+86)|(\\+86-))|((86)|(86\\-))|((0086)|(0086\\-)))?1[3|5|7|8|9]\\d{9}$')
|
||||
const mobile = /(0[0-9]{2,3})([2-9][0-9]{6,7})+([0-9]{8,11})?$/
|
||||
return phone.test(value) || mobile.test(value)
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
</j-form-item>
|
||||
</j-col>
|
||||
<j-col
|
||||
class="inputs"
|
||||
:span="
|
||||
modelRef.messageType === 'READ_PROPERTY' ||
|
||||
actionType === 'latestData'
|
||||
|
@ -68,6 +69,7 @@
|
|||
</j-col>
|
||||
<j-col
|
||||
:span="12"
|
||||
class="inputs"
|
||||
v-if="
|
||||
modelRef.messageType === 'WRITE_PROPERTY' &&
|
||||
actionType === 'command'
|
||||
|
@ -84,11 +86,11 @@
|
|||
<ValueItem
|
||||
v-model:modelValue="modelRef.message.value"
|
||||
:itemType="
|
||||
property.type || property.valueType?.type || 'int'
|
||||
property.valueType?.type || property.type || 'int'
|
||||
"
|
||||
:options="
|
||||
property.valueType?.type === 'enum'
|
||||
? (property?.dataType?.elements || []).map(
|
||||
? (property?.valueType?.elements || []).map(
|
||||
(item) => {
|
||||
return {
|
||||
label: item?.text,
|
||||
|
@ -190,9 +192,21 @@ const modelRef = reactive({
|
|||
properties: undefined,
|
||||
functionId: undefined,
|
||||
inputs: [],
|
||||
value: undefined
|
||||
},
|
||||
});
|
||||
|
||||
const property = ref<any>({});
|
||||
|
||||
const onPropertyChange = (val: string) => {
|
||||
if (val) {
|
||||
const _item = props.metadata?.properties.find(
|
||||
(item: any) => item.id === val,
|
||||
);
|
||||
property.value = _item || {};
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
|
@ -208,8 +222,6 @@ watch(
|
|||
},
|
||||
);
|
||||
|
||||
const property = ref<any>({});
|
||||
|
||||
const funcChange = (val: string) => {
|
||||
if (val) {
|
||||
const arr =
|
||||
|
@ -227,15 +239,6 @@ const funcChange = (val: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
const onPropertyChange = (val: string) => {
|
||||
if (val) {
|
||||
const _item = props.metadata?.properties.find(
|
||||
(item: any) => item.id === val,
|
||||
);
|
||||
property.value = _item?.[0] || {};
|
||||
}
|
||||
};
|
||||
|
||||
const saveBtn = () =>
|
||||
new Promise((resolve) => {
|
||||
formRef.value
|
||||
|
|
|
@ -571,6 +571,7 @@ const getTypes = async () => {
|
|||
};
|
||||
|
||||
const getDuerOSProperties = (val: string) => {
|
||||
console.log(val)
|
||||
const arr = modelRef.propertyMappings.map((item) => item?.source) || [];
|
||||
const checked = _.cloneDeep(arr);
|
||||
const _index = checked.findIndex((i) => i === val);
|
||||
|
@ -672,6 +673,7 @@ watch(
|
|||
_data.applianceType = _data?.applianceType?.value;
|
||||
}
|
||||
Object.assign(modelRef, _data);
|
||||
console.log(modelRef.propertyMappings)
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
</template>
|
||||
<script setup lang="ts" name="modifyModal">
|
||||
import { PropType } from 'vue';
|
||||
import { Form, message } from 'ant-design-vue';
|
||||
import { Form, message } from 'jetlinks-ui-components';
|
||||
import { queryTree, saveTree, updateTree } from '@/api/device/category';
|
||||
import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
|
||||
import { list } from '@/api/iot-card/home';
|
||||
|
|
|
@ -75,8 +75,7 @@
|
|||
import { queryTree, deleteTree } from '@/api/device/category';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import ModifyModal from './components/modifyModal/index.vue';
|
||||
import type { TableColumnType, TableProps } from 'ant-design-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
const expandedRowKeys = ref<any>([]);
|
||||
const tableRef = ref<Record<string, any>>({});
|
||||
const modifyRef = ref();
|
||||
|
|
|
@ -119,6 +119,7 @@ const Status = defineComponent({
|
|||
<span>网络组件已禁用,请先
|
||||
<PermissionButton
|
||||
type="link"
|
||||
style="padding: 0"
|
||||
hasPermission="link/Type:action"
|
||||
popConfirm={{
|
||||
title: '确认启用',
|
||||
|
@ -288,6 +289,8 @@ const Status = defineComponent({
|
|||
text={<span>设备接入网关已禁用,请先
|
||||
<PermissionButton
|
||||
hasPermission="link/Type:action"
|
||||
type="link"
|
||||
style="padding: 0"
|
||||
popConfirm={{
|
||||
title: '确认启用',
|
||||
onConfirm: async () => {
|
||||
|
@ -416,6 +419,8 @@ const Status = defineComponent({
|
|||
设备接入网关已禁用,请先
|
||||
<PermissionButton
|
||||
hasPermission="link/AccessConfig:action"
|
||||
type="link"
|
||||
style="padding: 0"
|
||||
popConfirm={{
|
||||
title: '确认启用',
|
||||
onConfirm: async () => {
|
||||
|
@ -528,6 +533,8 @@ const Status = defineComponent({
|
|||
网关父设备已禁用,请先
|
||||
<PermissionButton
|
||||
hasPermission="device/Product:action"
|
||||
type="link"
|
||||
style="padding: 0"
|
||||
popConfirm={{
|
||||
title: '确认启用',
|
||||
onConfirm: async () => {
|
||||
|
@ -636,6 +643,8 @@ const Status = defineComponent({
|
|||
产品已禁用,请
|
||||
<PermissionButton
|
||||
hasPermission="device/Product:action"
|
||||
type="link"
|
||||
style="padding: 0"
|
||||
popConfirm={{
|
||||
title: '确认启用',
|
||||
onConfirm: async () => {
|
||||
|
@ -712,6 +721,8 @@ const Status = defineComponent({
|
|||
设备已禁用,请
|
||||
<PermissionButton
|
||||
hasPermission="device/Instance:action"
|
||||
type="link"
|
||||
style="padding: 0"
|
||||
popConfirm={{
|
||||
title: '确认启用',
|
||||
onConfirm: async () => {
|
||||
|
@ -1720,6 +1731,8 @@ const Status = defineComponent({
|
|||
网关父设备已禁用,请先
|
||||
<PermissionButton
|
||||
hasPermission="device/Product:action"
|
||||
type="link"
|
||||
style="padding: 0"
|
||||
popConfirm={{
|
||||
title: '确认启用',
|
||||
onConfirm: async () => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="advance-wrapper">
|
||||
<j-tabs v-model="activeKey" tab-position="left">
|
||||
<j-tab-pane
|
||||
v-for="func in newFunctions"
|
||||
|
@ -129,7 +129,7 @@ const handleClear = (func: any) => {
|
|||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.wrapper {
|
||||
.advance-wrapper {
|
||||
.editor-btn {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="simple-wrapper">
|
||||
<div class="tips">
|
||||
<j-space>
|
||||
<AIcon type="QuestionCircleOutlined" />
|
||||
|
@ -239,7 +239,7 @@ const handleClear = (func: any) => {
|
|||
:deep(.ant-form-item-with-help .ant-form-item-explain) {
|
||||
min-height: 0;
|
||||
}
|
||||
.wrapper {
|
||||
.simple-wrapper {
|
||||
.tips {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
|
|
@ -13,16 +13,16 @@
|
|||
</PermissionButton>
|
||||
</template>
|
||||
<j-descriptions-item label="设备ID">{{
|
||||
instanceStore.current.id
|
||||
instanceStore.current?.id
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="产品名称">{{
|
||||
instanceStore.current.productName
|
||||
instanceStore.current?.productName
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="产品分类">{{
|
||||
instanceStore.current.classifiedName
|
||||
instanceStore.current?.classifiedName
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="设备类型">{{
|
||||
instanceStore.current.deviceType?.text
|
||||
instanceStore.current?.deviceType?.text
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="固件版本">{{
|
||||
instanceStore.current?.firmwareInfo?.version
|
||||
|
@ -31,25 +31,25 @@
|
|||
instanceStore.current?.transport
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="消息协议">{{
|
||||
instanceStore.current.protocolName
|
||||
instanceStore.current?.protocolName
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="创建时间">{{
|
||||
instanceStore.current.createTime
|
||||
? moment(instanceStore.current.createTime).format(
|
||||
instanceStore.current?.createTime
|
||||
? moment(instanceStore.current?.createTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="注册时间">{{
|
||||
instanceStore.current.registerTime
|
||||
? moment(instanceStore.current.registerTime).format(
|
||||
instanceStore.current?.registerTime
|
||||
? moment(instanceStore.current?.registerTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="最后上线时间">{{
|
||||
instanceStore.current.onlineTime
|
||||
? moment(instanceStore.current.onlineTime).format(
|
||||
instanceStore.current?.onlineTime
|
||||
? moment(instanceStore.current?.onlineTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
|
@ -57,12 +57,12 @@
|
|||
<j-descriptions-item
|
||||
label="父设备"
|
||||
v-if="
|
||||
instanceStore.current.deviceType?.value === 'childrenDevice'
|
||||
instanceStore.current?.deviceType?.value === 'childrenDevice'
|
||||
"
|
||||
>{{ instanceStore.current.parentId }}</j-descriptions-item
|
||||
>{{ instanceStore.current?.parentId }}</j-descriptions-item
|
||||
>
|
||||
<j-descriptions-item label="说明">{{
|
||||
instanceStore.current.description
|
||||
instanceStore.current?.description
|
||||
}}</j-descriptions-item>
|
||||
</j-descriptions>
|
||||
<Config />
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
<!-- <j-spin :spinning="loading"> -->
|
||||
<div class="card-container">
|
||||
<div class="header">
|
||||
<div class="title">{{ _props.data.name }}</div>
|
||||
<div class="title">
|
||||
<Ellipsis style="width: 100%;">
|
||||
{{ _props.data.name }}
|
||||
</Ellipsis>
|
||||
</div>
|
||||
<div class="extra">
|
||||
<j-space :size="16">
|
||||
<template v-for="i in actions" :key="i.key">
|
||||
|
@ -97,12 +101,9 @@ const _props = defineProps({
|
|||
.title {
|
||||
width: 60%;
|
||||
margin-right: 10px;
|
||||
overflow: hidden;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
<template>
|
||||
<page-container
|
||||
:tabList="list"
|
||||
@back="onBack"
|
||||
:tabActiveKey="instanceStore.tabActiveKey"
|
||||
@tabChange="onTabChange"
|
||||
>
|
||||
<template #title>
|
||||
<div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<j-button @click="onBack" size="small">返回</j-button>
|
||||
<div style="margin-left: 20px; font-size: 24px">
|
||||
{{ instanceStore.current.name }}
|
||||
<!-- <j-button @click="onBack" size="small">返回</j-button> -->
|
||||
<div style="font-size: 24px">
|
||||
{{ instanceStore.current?.name }}
|
||||
</div>
|
||||
<j-divider type="vertical" />
|
||||
<j-space>
|
||||
|
@ -21,15 +20,15 @@
|
|||
<j-badge
|
||||
:status="
|
||||
statusMap.get(
|
||||
instanceStore.current.state?.value,
|
||||
instanceStore.current?.state?.value,
|
||||
)
|
||||
"
|
||||
/>
|
||||
{{ instanceStore.current.state?.text }}
|
||||
{{ instanceStore.current?.state?.text }}
|
||||
</span>
|
||||
<PermissionButton
|
||||
v-if="
|
||||
instanceStore.current.state?.value ===
|
||||
instanceStore.current?.state?.value ===
|
||||
'notActive'
|
||||
"
|
||||
type="link"
|
||||
|
@ -44,7 +43,7 @@
|
|||
</PermissionButton>
|
||||
<PermissionButton
|
||||
v-if="
|
||||
instanceStore.current.state?.value === 'online'
|
||||
instanceStore.current?.state?.value === 'online'
|
||||
"
|
||||
type="link"
|
||||
style="margin-top: -5px; padding: 0 20px"
|
||||
|
@ -65,7 +64,7 @@
|
|||
"
|
||||
:title="
|
||||
instanceStore.current?.features?.find(
|
||||
(item) => item.id === 'selfManageState',
|
||||
(item) => item?.id === 'selfManageState',
|
||||
)
|
||||
? '该设备的在线状态与父设备(网关设备)保持一致'
|
||||
: '该设备在线状态由设备自身运行状态决定,不继承父设备(网关设备)的在线状态'
|
||||
|
@ -81,7 +80,7 @@
|
|||
<div style="padding-top: 24px">
|
||||
<j-descriptions size="small" :column="4">
|
||||
<j-descriptions-item label="ID">{{
|
||||
instanceStore.current.id
|
||||
instanceStore.current?.id
|
||||
}}</j-descriptions-item>
|
||||
<j-descriptions-item label="所属产品">
|
||||
<PermissionButton
|
||||
|
@ -90,7 +89,7 @@
|
|||
@click="jumpProduct"
|
||||
hasPermission="device/Product:view"
|
||||
>
|
||||
{{ instanceStore.current.productName }}
|
||||
{{ instanceStore.current?.productName }}
|
||||
</PermissionButton>
|
||||
</j-descriptions-item>
|
||||
</j-descriptions>
|
||||
|
@ -193,11 +192,12 @@ const getStatus = (id: string) => {
|
|||
};
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
() => route.params?.id,
|
||||
(newId) => {
|
||||
if (newId) {
|
||||
instanceStore.refresh(String(newId));
|
||||
getStatus(String(newId));
|
||||
instanceStore.tabActiveKey = 'Info'
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
|
@ -207,52 +207,52 @@ onMounted(() => {
|
|||
instanceStore.tabActiveKey = history.state?.params?.tab || 'Info';
|
||||
});
|
||||
|
||||
const onBack = () => {
|
||||
menuStory.jumpPage('device/Instance');
|
||||
};
|
||||
// const onBack = () => {
|
||||
// menuStory.jumpPage('device/Instance');
|
||||
// };
|
||||
|
||||
const onTabChange = (e: string) => {
|
||||
instanceStore.tabActiveKey = e;
|
||||
};
|
||||
|
||||
const handleAction = async () => {
|
||||
if (instanceStore.current.id) {
|
||||
const resp = await _deploy(instanceStore.current.id);
|
||||
if (instanceStore.current?.id) {
|
||||
const resp = await _deploy(instanceStore.current?.id);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
instanceStore.refresh(instanceStore.current.id);
|
||||
instanceStore.refresh(instanceStore.current?.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDisconnect = async () => {
|
||||
if (instanceStore.current.id) {
|
||||
const resp = await _disconnect(instanceStore.current.id);
|
||||
if (instanceStore.current?.id) {
|
||||
const resp = await _disconnect(instanceStore.current?.id);
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
instanceStore.refresh(instanceStore.current.id);
|
||||
instanceStore.refresh(instanceStore.current?.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleRefresh = async () => {
|
||||
if (instanceStore.current.id) {
|
||||
await instanceStore.refresh(instanceStore.current.id);
|
||||
if (instanceStore.current?.id) {
|
||||
await instanceStore.refresh(instanceStore.current?.id);
|
||||
message.success('操作成功');
|
||||
}
|
||||
};
|
||||
|
||||
const jumpProduct = () => {
|
||||
menuStory.jumpPage('device/Product/Detail', {
|
||||
id: instanceStore.current.productId,
|
||||
id: instanceStore.current?.productId,
|
||||
});
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
const keys = list.value.map((i) => i.key);
|
||||
if (
|
||||
instanceStore.current.protocol &&
|
||||
!['modbus-tcp', 'opc-ua'].includes(instanceStore.current.protocol) &&
|
||||
instanceStore.current?.protocol &&
|
||||
!['modbus-tcp', 'opc-ua'].includes(instanceStore.current?.protocol) &&
|
||||
!keys.includes('Diagnose')
|
||||
) {
|
||||
list.value.push({
|
||||
|
@ -261,8 +261,8 @@ watchEffect(() => {
|
|||
});
|
||||
}
|
||||
if (
|
||||
instanceStore.current.features?.find(
|
||||
(item: any) => item.id === 'transparentCodec',
|
||||
instanceStore.current?.features?.find(
|
||||
(item: any) => item?.id === 'transparentCodec',
|
||||
) &&
|
||||
!keys.includes('Parsing')
|
||||
) {
|
||||
|
@ -272,7 +272,7 @@ watchEffect(() => {
|
|||
});
|
||||
}
|
||||
if (
|
||||
instanceStore.current.protocol === 'modbus-tcp' &&
|
||||
instanceStore.current?.protocol === 'modbus-tcp' &&
|
||||
!keys.includes('Modbus')
|
||||
) {
|
||||
list.value.push({
|
||||
|
@ -281,7 +281,7 @@ watchEffect(() => {
|
|||
});
|
||||
}
|
||||
if (
|
||||
instanceStore.current.protocol === 'opc-ua' &&
|
||||
instanceStore.current?.protocol === 'opc-ua' &&
|
||||
!keys.includes('OPCUA')
|
||||
) {
|
||||
list.value.push({
|
||||
|
@ -290,7 +290,7 @@ watchEffect(() => {
|
|||
});
|
||||
}
|
||||
if (
|
||||
instanceStore.current.deviceType?.value === 'gateway' &&
|
||||
instanceStore.current?.deviceType?.value === 'gateway' &&
|
||||
!keys.includes('ChildDevice')
|
||||
) {
|
||||
// 产品类型为网关的情况下才显示此模块
|
||||
|
@ -300,8 +300,8 @@ watchEffect(() => {
|
|||
});
|
||||
}
|
||||
if (
|
||||
instanceStore.current.accessProvider === 'edge-child-device' &&
|
||||
instanceStore.current.parentId &&
|
||||
instanceStore.current?.accessProvider === 'edge-child-device' &&
|
||||
instanceStore.current?.parentId &&
|
||||
!keys.includes('EdgeMap')
|
||||
) {
|
||||
list.value.push({
|
||||
|
|
|
@ -335,6 +335,7 @@ const columns = [
|
|||
key: 'productName',
|
||||
search: {
|
||||
type: 'select',
|
||||
rename: 'productId',
|
||||
options: () =>
|
||||
new Promise((resolve) => {
|
||||
queryNoPagingPost({ paging: false }).then((resp: any) => {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<!-- 勾选 -->
|
||||
<div v-if="active" class="checked-icon">
|
||||
<div>
|
||||
<CheckOutlined />
|
||||
<AIcon type="CheckOutlined"></AIcon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -31,11 +31,6 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
SearchOutlined,
|
||||
CheckOutlined,
|
||||
DeleteOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { StatusColorEnum } from '@/utils/consts.ts';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { PropType } from 'vue';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<div style="display: flex">
|
||||
<h3>配置信息</h3>
|
||||
<div style="margin: 0 0px 0 15px; color: #1d39c4">
|
||||
<edit-outlined @click="editConfig" />
|
||||
<AIcon type="EditOutlined"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -53,11 +53,6 @@ import { useProductStore } from '@/store/product';
|
|||
import Save from '../../Save/index.vue';
|
||||
import moment from 'moment';
|
||||
import { useRoute } from 'vue-router';
|
||||
import {
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
PlusOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
const productStore = useProductStore();
|
||||
const route = useRoute();
|
||||
const saveRef = ref();
|
||||
|
|
|
@ -281,7 +281,7 @@
|
|||
:columns="query.columns"
|
||||
target="deviceModal"
|
||||
@search="search"
|
||||
type='simple'
|
||||
type="simple"
|
||||
/>
|
||||
<JProTable
|
||||
:columns="query.columns"
|
||||
|
@ -370,11 +370,11 @@
|
|||
<script lang="ts" setup>
|
||||
import { useProductStore } from '@/store/product';
|
||||
import { ConfigMetadata } from '@/views/device/Product/typings';
|
||||
import { Empty, FormItem, message } from 'ant-design-vue';
|
||||
import { Empty, message } from 'jetlinks-ui-components';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import Title from '../Title/index.vue';
|
||||
import { usePermissionStore } from '@/store/permission';
|
||||
import { steps, steps1 } from './util'
|
||||
import { steps, steps1 } from './util';
|
||||
import './index.less';
|
||||
import {
|
||||
getProviders,
|
||||
|
@ -396,7 +396,7 @@ const productStore = useProductStore();
|
|||
import Driver from 'driver.js';
|
||||
import 'driver.js/dist/driver.min.css';
|
||||
import { marked } from 'marked';
|
||||
import type { FormInstance, TableColumnType } from 'ant-design-vue';
|
||||
import type { TableColumnType } from 'ant-design-vue';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
const formRef = ref();
|
||||
const menuStore = useMenuStore();
|
||||
|
@ -590,7 +590,7 @@ const search = (e: any) => {
|
|||
};
|
||||
};
|
||||
|
||||
const stepsRef = reactive({current:0})
|
||||
const stepsRef = reactive({ current: 0 });
|
||||
|
||||
/**
|
||||
* 保存引导页数据
|
||||
|
@ -808,8 +808,7 @@ const getConfigDetail = (
|
|||
messageProtocol: string,
|
||||
transportProtocol: string,
|
||||
) => {
|
||||
getConfigView(messageProtocol, transportProtocol).then(
|
||||
(resp) => {
|
||||
getConfigView(messageProtocol, transportProtocol).then((resp) => {
|
||||
if (resp.status === 200) {
|
||||
config.value = resp.result;
|
||||
const Group = {
|
||||
|
@ -844,8 +843,7 @@ const getConfigDetail = (
|
|||
markdownToHtml.value = marked(config.value.document);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -904,7 +902,6 @@ const submitData = async () => {
|
|||
? await updateDevice(obj)
|
||||
: await saveDevice(obj);
|
||||
if (resp.status === 200) {
|
||||
|
||||
detail(productStore.current?.id || '').then((res) => {
|
||||
if (res.status === 200) {
|
||||
productStore.current = { ...res.result };
|
||||
|
@ -913,7 +910,6 @@ const submitData = async () => {
|
|||
}
|
||||
visible.value = false;
|
||||
queryParams.value = {};
|
||||
|
||||
});
|
||||
getData(obj.accessId);
|
||||
}
|
||||
|
@ -947,21 +943,25 @@ const getGuide = async (isDriver1: boolean = false) => {
|
|||
driver.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 查询保存数据信息
|
||||
*/
|
||||
const getData = async (accessId?: string) => {
|
||||
const _accessId = accessId || productStore.current?.accessId
|
||||
const _accessId = accessId || productStore.current?.accessId;
|
||||
if (productStore.current?.id) {
|
||||
getConfigMetadata(productStore.current?.id).then((resp: any) => {
|
||||
metadata.value = resp?.result[0] as ConfigMetadata || { properties: [] };
|
||||
if (accessId) { // 切换接入方式之后获取是否显示引导
|
||||
getGuide(!resp?.result.length) //
|
||||
metadata.value = (resp?.result[0] as ConfigMetadata) || {
|
||||
properties: [],
|
||||
};
|
||||
if (accessId) {
|
||||
// 切换接入方式之后获取是否显示引导
|
||||
getGuide(resp?.result.length); //
|
||||
}
|
||||
});
|
||||
}
|
||||
if (_accessId) { // 有设备接入
|
||||
if (_accessId) {
|
||||
// 有设备接入
|
||||
// const metadataResp = await getConfigMetadata(productStore.current!.id)
|
||||
// if (metadataResp.success) {
|
||||
// metadata.value = (metadataResp.result?.[0] as ConfigMetadata[]) || [];
|
||||
|
@ -1009,7 +1009,7 @@ const submitDevice = async () => {
|
|||
});
|
||||
if (resp.status === 200) {
|
||||
message.success('操作成功!');
|
||||
productStore.current!.storePolicy = storePolicy
|
||||
productStore.current!.storePolicy = storePolicy;
|
||||
if ((window as any).onTabSaveSuccess) {
|
||||
if (resp.result) {
|
||||
(window as any).onTabSaveSuccess(resp);
|
||||
|
@ -1042,13 +1042,13 @@ const add = () => {
|
|||
*/
|
||||
watchEffect(() => {
|
||||
if (productStore.current?.storePolicy) {
|
||||
form.storePolicy = productStore.current!.storePolicy
|
||||
form.storePolicy = productStore.current!.storePolicy;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
nextTick(() => {
|
||||
getData();
|
||||
})
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
:deep(
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//引导页数据
|
||||
export const steps = [
|
||||
{
|
||||
element: '#rc-tabs-0-tab-Metadata',
|
||||
element: '.objectModel',
|
||||
popover: {
|
||||
id: 'driver',
|
||||
className: 'driver',
|
||||
title: `<div id='title'>配置物模型</div><div id='guide'>1/3</div>`,
|
||||
description: `配置产品物模型,实现设备在云端的功能描述。`,
|
||||
position: 'bottom',
|
||||
|
@ -40,7 +40,7 @@ export const steps1 = [
|
|||
},
|
||||
},
|
||||
{
|
||||
element: '#rc-tabs-0-tab-Metadata',
|
||||
element: '.objectModel',
|
||||
popover: {
|
||||
className: 'driver',
|
||||
title: `<div id='title'>配置物模型</div><div id='guide'>2/4</div>`,
|
||||
|
|
|
@ -112,7 +112,7 @@ import {
|
|||
getDeviceNumber,
|
||||
getProtocolDetail,
|
||||
} from '@/api/device/product';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import encodeQuery from '@/utils/encodeQuery';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
|
@ -141,6 +141,7 @@ const list = ref([
|
|||
{
|
||||
key: 'Metadata',
|
||||
tab: '物模型',
|
||||
class:'objectModel'
|
||||
},
|
||||
{
|
||||
key: 'Device',
|
||||
|
|
|
@ -17,13 +17,22 @@
|
|||
<div class="product-tips">
|
||||
<div style="display: flex">
|
||||
<div class="product-icon">
|
||||
<check-circle-outlined class="icon-style" />
|
||||
<AIcon
|
||||
type="CheckCircleOutlined"
|
||||
class="icon-style"
|
||||
></AIcon>
|
||||
</div>
|
||||
<div class="product-title">产品创建成功</div>
|
||||
</div>
|
||||
<div style="display: flex">
|
||||
<div class="product-id">产品ID: {{ idValue }}</div>
|
||||
<div class="product-btn" @click="showDetail" style="cursor: pointer;">查看详情</div>
|
||||
<div
|
||||
class="product-btn"
|
||||
@click="showDetail"
|
||||
style="cursor: pointer"
|
||||
>
|
||||
查看详情
|
||||
</div>
|
||||
</div>
|
||||
<div>接下来推荐操作:</div>
|
||||
<div class="product-main">1、配置产品接入方式</div>
|
||||
|
@ -48,7 +57,6 @@
|
|||
<script lang="ts" setup name="DialogTips">
|
||||
import { getImage } from '@/utils/comm.ts';
|
||||
import { useProductStore } from '@/store/product';
|
||||
import { CheckCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
const visible = ref<boolean>(false);
|
||||
const productStore = useProductStore();
|
||||
|
@ -72,12 +80,11 @@ const show = (id: string) => {
|
|||
* 查看详情
|
||||
*/
|
||||
const showDetail = () => {
|
||||
menuStore.jumpPage('device/Product/Detail',{id:idValue.value})
|
||||
menuStore.jumpPage('device/Product/Detail', { id: idValue.value });
|
||||
};
|
||||
defineExpose({
|
||||
show: show,
|
||||
});
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.product-tips {
|
||||
|
|
|
@ -147,7 +147,7 @@
|
|||
import { category } from '@/api/device/product';
|
||||
import { Form } from 'ant-design-vue';
|
||||
import { getImage } from '@/utils/comm.ts';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import DialogTips from '../DialogTips/index.vue';
|
||||
import { useProductStore } from '@/store/product';
|
||||
import { filterTreeSelectNode, filterSelectNode } from '@/utils/comm';
|
||||
|
|
|
@ -160,12 +160,7 @@
|
|||
import server from '@/utils/request';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import {
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
PlusOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import {
|
||||
getProviders,
|
||||
category,
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
message: 'ID只能由数字、字母、下划线、中划线组成',
|
||||
},
|
||||
]">
|
||||
<j-input v-model:value="value.id" size="small" @change="asyncOtherConfig" :disabled="metadataStore.model.action === 'edit'"></j-input>
|
||||
<j-input v-model:value="value.id" size="small" @change="asyncOtherConfig" :disabled="metadataStore.model.action === 'edit'" placeholder="请输入标识"></j-input>
|
||||
</j-form-item>
|
||||
<j-form-item label="名称" name="name" :rules="[
|
||||
{ required: true, message: '请输入名称' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]">
|
||||
<j-input v-model:value="value.name" size="small"></j-input>
|
||||
<j-input v-model:value="value.name" size="small" placeholder="请输入名称"></j-input>
|
||||
</j-form-item>
|
||||
<template v-if="modelType === 'properties'">
|
||||
<value-type-form :name="['valueType']" v-model:value="value.valueType" key="property" title="数据类型"
|
||||
|
@ -33,7 +33,7 @@
|
|||
<j-form-item label="输入参数" name="inputs" :rules="[
|
||||
{ validator: (_rule: Rule, val: Record<any, any>[]) => validateJson(_rule, val, '输入参数', false) },
|
||||
]">
|
||||
<JsonParam v-model:value="value.inputs" :name="['inputs']"></JsonParam>
|
||||
<JsonParam v-model:value="value.inputs" :name="['inputs']" :is-sub="false"></JsonParam>
|
||||
</j-form-item>
|
||||
<value-type-form :name="['output']" v-model:value="value.output" key="function" title="输出参数" :required="false"></value-type-form>
|
||||
</template>
|
||||
|
@ -41,7 +41,7 @@
|
|||
<j-form-item label="级别" :name="['expands', 'level']" :rules="[
|
||||
{ required: true, message: '请选择级别' },
|
||||
]">
|
||||
<j-select v-model:value="value.expands.level" :options="EventLevel" size="small"></j-select>
|
||||
<j-select v-model:value="value.expands.level" :options="EventLevel" size="small" placeholder="请选择级别"></j-select>
|
||||
</j-form-item>
|
||||
<value-type-form :name="['valueType']" v-model:value="value.valueType" key="function" title="输出参数" only-object></value-type-form>
|
||||
</template>
|
||||
|
@ -50,13 +50,13 @@
|
|||
<j-form-item label="标签类型" :name="['expands', 'type']" :rules="[
|
||||
{ required: true, message: '请选择标签类型' },
|
||||
]">
|
||||
<j-select v-model:value="value.expands.type" :options="ExpandsTypeList" mode="multiple" size="small"></j-select>
|
||||
<j-select v-model:value="value.expands.type" :options="ExpandsTypeList" mode="multiple" size="small" placeholder="请选择标签类型"></j-select>
|
||||
</j-form-item>
|
||||
</template>
|
||||
<j-form-item label="说明" name="description" :rules="[
|
||||
{ max: 200, message: '最多可输入200个字符' },
|
||||
]">
|
||||
<j-textarea v-model:value="value.description" size="small"></j-textarea>
|
||||
<j-textarea v-model:value="value.description" size="small" placeholder="请输入说明"></j-textarea>
|
||||
</j-form-item>
|
||||
</template>
|
||||
<script setup lang="ts" name="BaseForm">
|
||||
|
|
|
@ -19,9 +19,17 @@
|
|||
</j-form-item>
|
||||
<j-form-item
|
||||
v-if="type === 'product' && ['int', 'float', 'double', 'long', 'date', 'string', 'boolean'].includes(valueType.type)"
|
||||
label="指标配置" :name="name.concat(['metrics'])" :rules="[
|
||||
:name="name.concat(['metrics'])" :rules="[
|
||||
{ validator: () => validateMetrics(_value.metrics), message: '请输入指标配置' }
|
||||
]">
|
||||
<template #label>
|
||||
<j-space>
|
||||
指标配置
|
||||
<j-tooltip title="场景联动页面可引用指标配置作为触发条件">
|
||||
<AIcon type="QuestionCircleOutlined" style="color: rgb(136, 136, 136); font-size: 12px;"/>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</template>
|
||||
<metrics-param v-model:value="_value.metrics" :type="valueType.type" :enum="valueType"
|
||||
:name="name.concat(['metrics'])"></metrics-param>
|
||||
</j-form-item>
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
]">
|
||||
<j-select v-model:value="_value.type" :disabled="onlyObject"
|
||||
:options="onlyObject ? eventDataTypeList : _dataTypeList" size="small"
|
||||
@change="changeType"></j-select>
|
||||
@change="changeType" :placeholder="`请选择${title}`"></j-select>
|
||||
</j-form-item>
|
||||
<j-form-item label="单位" :name="name.concat(['unit'])" v-if="['int', 'float', 'long', 'double'].includes(_value.type)">
|
||||
<InputSelect v-model:value="_value.unit" :options="unit.unitOptions" size="small"></InputSelect>
|
||||
</j-form-item>
|
||||
<j-form-item label="精度" :name="name.concat(['scale'])" v-if="['float', 'double'].includes(_value.type)">
|
||||
<j-input-number v-model:value="_value.scale" size="small" :min="0" :max="2147483647" :precision="0"
|
||||
style="width: 100%"></j-input-number>
|
||||
style="width: 100%" placeholder="请输入精度"></j-input-number>
|
||||
</j-form-item>
|
||||
<j-form-item label="布尔值" name="booleanConfig" v-if="['boolean'].includes(_value.type)">
|
||||
<BooleanParam :name="name" v-model:value="_value"></BooleanParam>
|
||||
|
@ -26,12 +26,13 @@
|
|||
<j-space>
|
||||
最大长度
|
||||
<j-tooltip title="字节">
|
||||
<question-circle-outlined style="color: rgb(136, 136, 136); font-size: 12px;" />
|
||||
<AIcon type="QuestionCircleOutlined" style="color: rgb(136, 136, 136); font-size: 12px;" />
|
||||
<!-- <question-circle-outlined style="color: rgb(136, 136, 136); font-size: 12px;" /> -->
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</template>
|
||||
<j-input-number v-model:value="_value.expands.maxLength" size="small" :max="2147483647" :min="1" :precision="0"
|
||||
style="width: 100%;"></j-input-number>
|
||||
style="width: 100%;" placeholder="请输入最大长度"></j-input-number>
|
||||
</j-form-item>
|
||||
<j-form-item label="元素配置" :name="name.concat(['elementType'])" v-if="['array'].includes(_value.type)" :rules="[
|
||||
{ validator: validateArray }
|
||||
|
@ -47,7 +48,7 @@
|
|||
:rules="[
|
||||
{ required: true, message: '请选择文件类型' },
|
||||
]">
|
||||
<j-select v-model:value="_value.fileType" :options="FileTypeList" size="small"></j-select>
|
||||
<j-select v-model:value="_value.fileType" :options="FileTypeList" size="small" placeholder="请选择文件类型"></j-select>
|
||||
</j-form-item>
|
||||
</template>
|
||||
<script lang="ts" setup mame="BaseForm">
|
||||
|
@ -152,6 +153,9 @@ const changeType = (val: SelectValue) => {
|
|||
if (['float', 'double'].includes(_value.value.type) && _value.value.scale === undefined) {
|
||||
_value.value.scale = 2
|
||||
}
|
||||
if (['file'].includes(val as string)) {
|
||||
_value.value.fileType = _value.value.fileType || 'url'
|
||||
}
|
||||
emit('changeType', val as string)
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ const save = reactive({
|
|||
if (props?.type === 'device') {
|
||||
instanceStore.refresh(id as string)
|
||||
} else {
|
||||
productStore.refresh(id as string)
|
||||
productStore.getDetail(id as string)
|
||||
}
|
||||
// Store.set(SystemConst.REFRESH_METADATA_TABLE, true);
|
||||
if (deploy) {
|
||||
|
@ -125,7 +125,7 @@ const save = reactive({
|
|||
}
|
||||
// Store.set('product-deploy', deploy);
|
||||
} else {
|
||||
save.resetMetadata();
|
||||
// save.resetMetadata();
|
||||
message.success({
|
||||
key: 'metadata',
|
||||
content: '操作成功!',
|
||||
|
@ -133,9 +133,9 @@ const save = reactive({
|
|||
}
|
||||
metadataStore.set('edit', false)
|
||||
metadataStore.set('item', {})
|
||||
if (instanceStore.detail) {
|
||||
instanceStore.detail.independentMetadata = true;
|
||||
}
|
||||
// if (props?.type === 'device' && instanceStore.detail) {
|
||||
// instanceStore.detail.independentMetadata = true;
|
||||
// }
|
||||
}
|
||||
} else {
|
||||
message.error('操作失败!');
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { JColumnProps } from "@/components/Table";
|
||||
import { ColumnProps } from "ant-design-vue/es/table";
|
||||
|
||||
const SourceMap = {
|
||||
device: '设备',
|
||||
|
@ -12,7 +12,7 @@ const type = {
|
|||
report: '上报',
|
||||
};
|
||||
|
||||
const BaseColumns: JColumnProps[] = [
|
||||
const BaseColumns: ColumnProps[] = [
|
||||
{
|
||||
title: '标识',
|
||||
dataIndex: 'id',
|
||||
|
@ -30,19 +30,17 @@ const BaseColumns: JColumnProps[] = [
|
|||
},
|
||||
];
|
||||
|
||||
const EventColumns: JColumnProps[] = BaseColumns.concat([
|
||||
const EventColumns: ColumnProps[] = BaseColumns.concat([
|
||||
{
|
||||
title: '事件级别',
|
||||
dataIndex: 'level',
|
||||
scopedSlots: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const FunctionColumns: JColumnProps[] = BaseColumns.concat([
|
||||
const FunctionColumns: ColumnProps[] = BaseColumns.concat([
|
||||
{
|
||||
title: '是否异步',
|
||||
dataIndex: 'async',
|
||||
scopedSlots: true,
|
||||
},
|
||||
// {
|
||||
// title: '读写类型',
|
||||
|
@ -51,38 +49,33 @@ const FunctionColumns: JColumnProps[] = BaseColumns.concat([
|
|||
// },
|
||||
]);
|
||||
|
||||
const PropertyColumns: JColumnProps[] = BaseColumns.concat([
|
||||
const PropertyColumns: ColumnProps[] = BaseColumns.concat([
|
||||
{
|
||||
title: '数据类型',
|
||||
dataIndex: 'valueType',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '属性来源',
|
||||
dataIndex: 'source',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '读写类型',
|
||||
dataIndex: 'type',
|
||||
scopedSlots: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const TagColumns: JColumnProps[] = BaseColumns.concat([
|
||||
const TagColumns: ColumnProps[] = BaseColumns.concat([
|
||||
{
|
||||
title: '数据类型',
|
||||
dataIndex: 'valueType',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '读写类型',
|
||||
dataIndex: 'type',
|
||||
scopedSlots: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const MetadataMapping = new Map<string, JColumnProps[]>();
|
||||
const MetadataMapping = new Map<string, ColumnProps[]>();
|
||||
MetadataMapping.set('properties', PropertyColumns);
|
||||
MetadataMapping.set('events', EventColumns);
|
||||
MetadataMapping.set('tags', TagColumns);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<Edit v-if="metadataStore.model.edit" :type="target" :tabs="type" @refresh="refreshMetadata"></Edit>
|
||||
</div>
|
||||
</div>
|
||||
<a-table :loading="loading" :data-source="data" :columns="columns" row-key="id" model="TABLE" size="small"
|
||||
<j-table :loading="loading" :data-source="data" :columns="columns" row-key="id" model="TABLE" size="small"
|
||||
:pagination="pagination">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'level'">
|
||||
|
@ -44,7 +44,7 @@
|
|||
}">
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
<PermissionButton :has-permission="`${permission}:delete`" type="link" key="delete" style="padding: 0"
|
||||
<PermissionButton :has-permission="`${permission}:delete`" type="link" key="delete" style="padding: 0" danger
|
||||
:pop-confirm="{
|
||||
title: '确认删除?', onConfirm: async () => {
|
||||
await removeItem(record);
|
||||
|
@ -57,7 +57,7 @@
|
|||
</j-space>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</j-table>
|
||||
</template>
|
||||
<script setup lang="ts" name="BaseMetadata">
|
||||
import type { MetadataItem, MetadataType } from '@/views/device/Product/typings'
|
||||
|
@ -69,6 +69,7 @@ import PermissionButton from '@/components/PermissionButton/index.vue'
|
|||
import { TablePaginationConfig, message } from 'ant-design-vue/es'
|
||||
import { asyncUpdateMetadata, removeMetadata } from '../metadata'
|
||||
import Edit from './Edit/index.vue'
|
||||
import { ColumnProps } from 'ant-design-vue/es/table'
|
||||
interface Props {
|
||||
type: MetadataType;
|
||||
target: 'product' | 'device';
|
||||
|
@ -97,13 +98,12 @@ const expandsType = ref({
|
|||
write: '写',
|
||||
report: '上报',
|
||||
});
|
||||
const actions = [
|
||||
const actions: ColumnProps[] = [
|
||||
{
|
||||
title: '操作',
|
||||
align: 'left',
|
||||
width: 200,
|
||||
dataIndex: 'action',
|
||||
scopedSlots: true,
|
||||
},
|
||||
];
|
||||
const pagination = {
|
||||
|
@ -116,14 +116,14 @@ const pagination = {
|
|||
size: 'small',
|
||||
} as TablePaginationConfig
|
||||
const columns = computed(() => MetadataMapping.get(type)!.concat(actions))
|
||||
const items = computed(() => JSON.parse((target === 'product' ? productStore.current?.metadata : instanceStore.current.metadata) || '{}') as MetadataItem[])
|
||||
const items = computed(() => JSON.parse((target === 'product' ? productStore.current?.metadata : instanceStore.current.metadata) || '{}'))
|
||||
const searchValue = ref<string>()
|
||||
const handleSearch = (searchValue: string) => {
|
||||
if (searchValue) {
|
||||
const arr = items.value.filter(item => item.name!.indexOf(searchValue) > -1).sort((a, b) => b?.sortsIndex - a?.sortsIndex)
|
||||
const arr = items.value[type].filter((item: MetadataItem) => item.name!.indexOf(searchValue) > -1).sort((a: MetadataItem, b: MetadataItem) => b?.sortsIndex - a?.sortsIndex)
|
||||
data.value = arr
|
||||
} else {
|
||||
data.value = items.value
|
||||
data.value = items.value[type]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,6 +215,6 @@ const removeItem = async (record: MetadataItem) => {
|
|||
.table-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 16px 0;
|
||||
padding: 16px;
|
||||
}
|
||||
</style>
|
|
@ -18,7 +18,7 @@
|
|||
<j-tabs @change="handleConvertMetadata" destroy-inactive-tab-pane>
|
||||
<j-tab-pane v-for="item in codecs" :key="item.id" :tab="item.name">
|
||||
<div class="cat-panel">
|
||||
<MonacoEditor v-model="value" theme="vs" style="height: 100%"></MonacoEditor>
|
||||
<JMonacoEditor v-model="value" theme="vs" style="height: 100%" lang="javascript"></JMonacoEditor>
|
||||
</div>
|
||||
</j-tab-pane>
|
||||
</j-tabs>
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
<j-form-item label="选择产品" v-bind="validateInfos.copy" v-if="formModel.type === 'copy'">
|
||||
<j-select :options="productList" v-model:value="formModel.copy" option-filter-prop="label"></j-select>
|
||||
</j-form-item>
|
||||
<j-form-item label="物模型类型" v-bind="validateInfos.metadata"
|
||||
v-if="type === 'device' || formModel.type === 'import'">
|
||||
<j-form-item label="物模型类型" v-bind="validateInfos.metadata" v-if="type === 'device' || formModel.type === 'import'">
|
||||
<j-select v-model:value="formModel.metadata">
|
||||
<j-select-option value="jetlinks">Jetlinks物模型</j-select-option>
|
||||
<j-select-option value="alink">阿里云物模型TSL</j-select-option>
|
||||
|
@ -34,16 +33,23 @@
|
|||
<j-form-item label="文件上传" v-bind="validateInfos.upload" v-if="formModel.metadataType === 'file'">
|
||||
<j-input v-model:value="formModel.upload">
|
||||
<template #addonAfter>
|
||||
<j-upload v-model:file-list="fileList" :before-upload="beforeUpload" accept=".json"
|
||||
:show-upload-list="false" :action="FILE_UPLOAD" @change="fileChange"
|
||||
:headers="{ 'X-Access-Token': getToken()}">
|
||||
<j-upload v-model:file-list="fileList" :before-upload="beforeUpload" accept=".json" :show-upload-list="false"
|
||||
:action="FILE_UPLOAD" @change="fileChange" :headers="{ 'X-Access-Token': getToken() }">
|
||||
<AIcon type="UploadOutlined" class="upload-button" />
|
||||
</j-upload>
|
||||
</template>
|
||||
</j-input>
|
||||
</j-form-item>
|
||||
<j-form-item label="物模型" v-bind="validateInfos.import" v-if="formModel.metadataType === 'script'">
|
||||
<MonacoEditor v-model="formModel.import" theme="vs" style="height: 300px"></MonacoEditor>
|
||||
<j-form-item v-bind="validateInfos.import" v-if="(type === 'device' || formModel.type === 'import') && formModel.metadataType === 'script'">
|
||||
<template #label>
|
||||
<j-space>
|
||||
物模型
|
||||
<j-tooltip title="在线编辑器中编写物模型脚本">
|
||||
<AIcon type="QuestionCircleOutlined" style="color: rgb(136, 136, 136);"/>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</template>
|
||||
<JMonacoEditor v-model="formModel.import" theme="vs" style="height: 300px" lang="javascript"></JMonacoEditor>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
</j-modal>
|
||||
|
@ -60,7 +66,6 @@ import { useInstanceStore } from '@/store/instance'
|
|||
import { useProductStore } from '@/store/product';
|
||||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import { getToken } from '@/utils/comm';
|
||||
import MonacoEditor from '@/components/MonacoEditor/index.vue'
|
||||
import { useMetadataStore } from '@/store/metadata';
|
||||
|
||||
const route = useRoute()
|
||||
|
@ -250,7 +255,7 @@ const handleImport = async () => {
|
|||
resp = await modify(id as string, params)
|
||||
}
|
||||
loading.value = false
|
||||
if (resp.status === 200) {
|
||||
if (resp.success) {
|
||||
if (props?.type === 'device') {
|
||||
const detail = instanceStore.current
|
||||
detail.metadata = paramsDevice
|
||||
|
@ -290,6 +295,7 @@ const handleImport = async () => {
|
|||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-button {
|
||||
width: 37px;
|
||||
height: 30px;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<j-card>
|
||||
<div class='device-detail-metadata' style="position: relative;">
|
||||
<div class="tips">
|
||||
<j-tooltip v-if="type === 'device'" :title="instanceStore.detail?.independentMetadata && type === 'device'
|
||||
<j-tooltip :title="instanceStore.detail?.independentMetadata && type === 'device'
|
||||
? '该设备已脱离产品物模型,修改产品物模型对该设备无影响'
|
||||
: '设备会默认继承产品的物模型,修改设备物模型后将脱离产品物模型'">
|
||||
<div class="ellipsis">
|
||||
|
@ -23,8 +23,8 @@
|
|||
:tooltip="{ title: '重置后将使用产品的物模型配置' }" key="reload">
|
||||
重置操作
|
||||
</PermissionButton>
|
||||
<PermissionButton :hasPermission="`${permission}:update`" @click="visible = true">快速导入</PermissionButton>
|
||||
<PermissionButton :hasPermission="`${permission}:update`" @click="cat = true">物模型TSL</PermissionButton>
|
||||
<PermissionButton :hasPermission="`${permission}:update`" @click="visible = true" key="import">快速导入</PermissionButton>
|
||||
<PermissionButton :hasPermission="`${permission}:update`" @click="cat = true" key="tsl">物模型TSL</PermissionButton>
|
||||
</j-space>
|
||||
</template>
|
||||
|
||||
|
@ -54,9 +54,11 @@ import { useInstanceStore } from '@/store/instance'
|
|||
import Import from './Import/index.vue'
|
||||
import Cat from './Cat/index.vue'
|
||||
import BaseMetadata from './Base/index.vue'
|
||||
import { useMetadataStore } from '@/store/metadata'
|
||||
|
||||
const route = useRoute()
|
||||
const instanceStore = useInstanceStore()
|
||||
const metadataStore = useMetadataStore()
|
||||
interface Props {
|
||||
type: 'product' | 'device';
|
||||
independentMetadata?: boolean;
|
||||
|
@ -73,7 +75,9 @@ const resetMetadata = async () => {
|
|||
const resp = await deleteMetadata(id as string)
|
||||
if (resp.status === 200) {
|
||||
message.info('操作成功')
|
||||
instanceStore.refresh(id as string)
|
||||
instanceStore.refresh(id as string).then(() => {
|
||||
metadataStore.set('importMetadata', true)
|
||||
})
|
||||
// Store.set(SystemConst.REFRESH_DEVICE, true)
|
||||
// setTimeout(() => {
|
||||
// Store.set(SystemConst.REFRESH_METADATA_TABLE, true)
|
||||
|
@ -84,11 +88,11 @@ const resetMetadata = async () => {
|
|||
<style scoped lang="less">
|
||||
.device-detail-metadata {
|
||||
.tips {
|
||||
width: calc(100% - 670px);
|
||||
// width: calc(100% - 670px);
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
z-index: 1;
|
||||
margin-left: 380px;
|
||||
margin-left: 420px;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
|
|
|
@ -255,7 +255,7 @@
|
|||
<script setup lang="ts">
|
||||
import { modalState, formState, logoState } from '../data/interface';
|
||||
import { getImage } from '@/utils/comm.ts';
|
||||
import { Form } from 'ant-design-vue';
|
||||
import { Form, message } from 'jetlinks-ui-components';
|
||||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import {
|
||||
getSystemPermission,
|
||||
|
@ -274,8 +274,6 @@ import {
|
|||
deployDevice,
|
||||
saveInit,
|
||||
} from '@/api/initHome';
|
||||
import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { LocalStore } from '@/utils/comm';
|
||||
import { TOKEN_KEY } from '@/utils/variable';
|
||||
import { SystemConst } from '@/utils/consts'
|
||||
|
@ -362,7 +360,7 @@ const saveBasicInfo = () =>{
|
|||
resolve(false);
|
||||
}
|
||||
})
|
||||
.catch((error: ValidateErrorEntity<formState>) => {
|
||||
.catch(() => {
|
||||
resolve(false);
|
||||
});
|
||||
})
|
||||
|
|
|
@ -129,9 +129,8 @@ import {
|
|||
deployDevice,
|
||||
} from '@/api/initHome';
|
||||
import { modalState } from '../data/interface';
|
||||
import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
|
||||
import type { Rule } from 'ant-design-vue/es/form';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
const formRef = ref();
|
||||
/**
|
||||
* 初始化数据状态
|
||||
|
@ -315,7 +314,7 @@ const saveCurrentData = () => {
|
|||
resolve(false);
|
||||
}
|
||||
})
|
||||
.catch((error: ValidateErrorEntity<modalState>) => {
|
||||
.catch(() => {
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -65,33 +65,16 @@ import Basic from './Basic/index.vue';
|
|||
import Role from './Role/index.vue';
|
||||
import Menu from './Menu/index.vue';
|
||||
import InitData from './InitData/index.vue';
|
||||
import {
|
||||
PlusOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
LoadingOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
import type {
|
||||
FormInstance,
|
||||
UploadChangeParam,
|
||||
UploadProps,
|
||||
} from 'ant-design-vue';
|
||||
import { modalState, formState, logoState } from './data/interface';
|
||||
import { saveInit } from '@/api/initHome';
|
||||
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import { LocalStore } from '@/utils/comm';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { Form } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
const basicRef = ref();
|
||||
const roleRef = ref();
|
||||
const initDataRef = ref();
|
||||
const loading = ref(false);
|
||||
// const useForm = Form.useForm;
|
||||
// const { resetFields, validate, validateInfos } = useForm(
|
||||
// modalForm.value,
|
||||
// rulesModle.value,
|
||||
// );
|
||||
/**
|
||||
* 默认打开第一个初始菜单
|
||||
*/
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<pro-search :columns="columns" target="iot-card-management-search" @search="handleSearch" />
|
||||
<j-pro-table ref="cardManageRef" :columns="columns" :request="query"
|
||||
<j-pro-table :scroll="{x: 1366}" ref="cardManageRef" :columns="columns" :request="query"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }" :rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
|
@ -89,7 +89,7 @@
|
|||
<CardBox :value="slotProps" @click="handleClick" :actions="getActions(slotProps, 'card')" v-bind="slotProps"
|
||||
:active="_selectedRowKeys.includes(slotProps.id)" :status="slotProps.cardStateType.value"
|
||||
:statusText="slotProps.cardStateType.text" :statusNames="{
|
||||
using: 'success',
|
||||
using: 'processing',
|
||||
toBeActivated: 'default',
|
||||
deactivate: 'error',
|
||||
}">
|
||||
|
@ -114,11 +114,12 @@
|
|||
<div>{{ slotProps.cardType.text }}</div>
|
||||
</j-col>
|
||||
<j-col :span="6">
|
||||
<div class="card-item-content-text">提醒</div>
|
||||
<!-- <div>{{ slotProps.cardType.text }}</div> -->
|
||||
<div class="card-item-content-text">绑定设备</div>
|
||||
<div>{{ slotProps.deviceName }}</div>
|
||||
</j-col>
|
||||
</j-row>
|
||||
<j-divider style="margin: 12px 0" />
|
||||
<div class="content-bottom">
|
||||
<div v-if="slotProps.usedFlow === 0">
|
||||
<span class="flow-text">
|
||||
{{ slotProps.totalFlow }}
|
||||
|
@ -130,7 +131,7 @@
|
|||
<div class="progress-text">
|
||||
<div>
|
||||
{{
|
||||
slotProps.totalFlow - slotProps.usedFlow
|
||||
(slotProps.usedFlow / slotProps.totalFlow * 100).toFixed(2)
|
||||
}}
|
||||
%
|
||||
</div>
|
||||
|
@ -138,9 +139,8 @@
|
|||
总共 {{ slotProps.totalFlow }} M
|
||||
</div>
|
||||
</div>
|
||||
<j-progress :strokeColor="'#ADC6FF'" :showInfo="false" :percent="
|
||||
slotProps.totalFlow - slotProps.usedFlow
|
||||
" />
|
||||
<j-progress :strokeColor="'#ADC6FF'" :showInfo="false" :percent="slotProps.usedFlow / slotProps.totalFlow * 100" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions="item">
|
||||
|
@ -226,12 +226,20 @@
|
|||
{{ slotProps.cardType.text }}
|
||||
</template>
|
||||
<template #cardStateType="slotProps">
|
||||
{{ slotProps.cardStateType.text }}
|
||||
<BadgeStatus
|
||||
:status="slotProps.cardStateType?.value"
|
||||
:text="slotProps.cardStateType?.text"
|
||||
:statusNames="{
|
||||
using: 'processing',
|
||||
toBeActivated: 'default',
|
||||
deactivate: 'error',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
<template #activationDate="slotProps">
|
||||
{{
|
||||
slotProps.activationDate
|
||||
? moment(slotProps.activationDate).format(
|
||||
? dayjs(slotProps.activationDate).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
|
@ -240,7 +248,7 @@
|
|||
<template #updateTime="slotProps">
|
||||
{{
|
||||
slotProps.updateTime
|
||||
? moment(slotProps.updateTime).format(
|
||||
? dayjs(slotProps.updateTime).format(
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)
|
||||
: ''
|
||||
|
@ -274,7 +282,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import type { ActionsType } from '@/components/Table';
|
||||
import moment from 'moment';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
query,
|
||||
queryPlatformNoPage,
|
||||
|
@ -297,6 +305,8 @@ import Import from './Import.vue';
|
|||
import Export from './Export.vue';
|
||||
import Save from './Save.vue';
|
||||
import { useMenuStore } from 'store/menu'
|
||||
import BadgeStatus from '@/components/BadgeStatus/index.vue';
|
||||
|
||||
const router = useRouter();
|
||||
const menuStory = useMenuStore()
|
||||
const cardManageRef = ref<Record<string, any>>({});
|
||||
|
@ -316,7 +326,7 @@ const columns = [
|
|||
title: '卡号',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
width: 300,
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
fixed: 'left',
|
||||
search: {
|
||||
|
@ -737,6 +747,10 @@ const handelRemove = async () => {
|
|||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
.content-bottom {
|
||||
height: 45px;
|
||||
}
|
||||
.flow-text {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
|
|
|
@ -38,8 +38,7 @@
|
|||
:params="params"
|
||||
:rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onSelect: onSelectChange,
|
||||
onSelectAll: onSelectAllChange,
|
||||
onChange: onSelectChange,
|
||||
}"
|
||||
@cancelSelect="_selectedRowKeys = []"
|
||||
:pagination="{
|
||||
|
@ -165,32 +164,9 @@ const handleSearch = (e: any) => {
|
|||
const listRef = ref();
|
||||
const _selectedRowKeys = ref<string[]>([]);
|
||||
|
||||
const onSelectChange = (
|
||||
record: any[],
|
||||
selected: boolean,
|
||||
selectedRows: any[],
|
||||
) => {
|
||||
_selectedRowKeys.value = selected
|
||||
? [...getSetRowKey(selectedRows)]
|
||||
: _selectedRowKeys.value.filter((item: any) => item !== record?.id);
|
||||
const onSelectChange = (keys: string[]) => {
|
||||
_selectedRowKeys.value = [...keys];
|
||||
};
|
||||
const onSelectAllChange = (
|
||||
selected: boolean,
|
||||
selectedRows: any[],
|
||||
changeRows: any[],
|
||||
) => {
|
||||
const unRowsKeys = getSelectedRowsKey(changeRows);
|
||||
_selectedRowKeys.value = selected
|
||||
? [...getSetRowKey(selectedRows)]
|
||||
: _selectedRowKeys.value
|
||||
.concat(unRowsKeys)
|
||||
.filter((item) => !unRowsKeys.includes(item));
|
||||
};
|
||||
const getSelectedRowsKey = (selectedRows: any[]) =>
|
||||
selectedRows.map((item) => item?.id).filter((i) => !!i);
|
||||
|
||||
const getSetRowKey = (selectedRows: any[]) =>
|
||||
new Set([..._selectedRowKeys.value, ...getSelectedRowsKey(selectedRows)]);
|
||||
|
||||
const loading = ref(false);
|
||||
const handleSave = async () => {
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
:params="params"
|
||||
:rowSelection="{
|
||||
selectedRowKeys: _selectedRowKeys,
|
||||
onSelect: onSelectChange,
|
||||
onSelectAll: onSelectAllChange,
|
||||
onChange: onSelectChange,
|
||||
}"
|
||||
@cancelSelect="_selectedRowKeys = []"
|
||||
:pagination="{
|
||||
|
@ -242,32 +241,9 @@ const listRef = ref();
|
|||
const _selectedRowKeys = ref<string[]>([]);
|
||||
const bindVis = ref(false);
|
||||
|
||||
const onSelectChange = (
|
||||
record: any[],
|
||||
selected: boolean,
|
||||
selectedRows: any[],
|
||||
) => {
|
||||
_selectedRowKeys.value = selected
|
||||
? [...getSetRowKey(selectedRows)]
|
||||
: _selectedRowKeys.value.filter((item: any) => item !== record?.id);
|
||||
const onSelectChange = (keys: string[]) => {
|
||||
_selectedRowKeys.value = [...keys];
|
||||
};
|
||||
const onSelectAllChange = (
|
||||
selected: boolean,
|
||||
selectedRows: any[],
|
||||
changeRows: any[],
|
||||
) => {
|
||||
const unRowsKeys = getSelectedRowsKey(changeRows);
|
||||
_selectedRowKeys.value = selected
|
||||
? [...getSetRowKey(selectedRows)]
|
||||
: _selectedRowKeys.value
|
||||
.concat(unRowsKeys)
|
||||
.filter((item) => !unRowsKeys.includes(item));
|
||||
};
|
||||
const getSelectedRowsKey = (selectedRows: any[]) =>
|
||||
selectedRows.map((item) => item?.id).filter((i) => !!i);
|
||||
|
||||
const getSetRowKey = (selectedRows: any[]) =>
|
||||
new Set([..._selectedRowKeys.value, ...getSelectedRowsKey(selectedRows)]);
|
||||
|
||||
/**
|
||||
* 表格操作按钮
|
||||
|
|
|
@ -121,6 +121,7 @@
|
|||
:key="i.key"
|
||||
>
|
||||
<PermissionButton
|
||||
:danger="i.key === 'delete'"
|
||||
:disabled="i.disabled"
|
||||
:popConfirm="i.popConfirm"
|
||||
:tooltip="{
|
||||
|
|
|
@ -123,7 +123,11 @@
|
|||
</j-form-item>
|
||||
</j-col>
|
||||
<j-col :span="24">
|
||||
<j-form-item name="address" label="安装地址">
|
||||
<j-form-item
|
||||
name="address"
|
||||
label="安装地址"
|
||||
:rules="{ max: 64, message: '最多可输入64个字符' }"
|
||||
>
|
||||
<j-input
|
||||
v-model:value="formData.address"
|
||||
placeholder="请输入安装地址"
|
||||
|
|
|
@ -79,8 +79,10 @@
|
|||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></j-button>
|
||||
:danger="i.key === 'delete'"
|
||||
>
|
||||
<AIcon :type="i.icon" />
|
||||
</j-button>
|
||||
</j-popconfirm>
|
||||
<j-button
|
||||
style="padding: 0"
|
||||
|
@ -92,8 +94,9 @@
|
|||
:disabled="i.disabled"
|
||||
style="padding: 0"
|
||||
type="link"
|
||||
><AIcon :type="i.icon"
|
||||
/></j-button>
|
||||
>
|
||||
<AIcon :type="i.icon" />
|
||||
</j-button>
|
||||
</j-button>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
|
|
|
@ -234,6 +234,8 @@ watch(
|
|||
if (val) {
|
||||
getGatewayList();
|
||||
} else {
|
||||
_selectedRowKeys.value = []
|
||||
extendFormItem.value = []
|
||||
emit('close');
|
||||
}
|
||||
},
|
||||
|
|
|
@ -124,6 +124,7 @@
|
|||
:key="i.key"
|
||||
>
|
||||
<PermissionButton
|
||||
:danger="i.key === 'delete'"
|
||||
:disabled="i.disabled"
|
||||
:popConfirm="i.popConfirm"
|
||||
:tooltip="{
|
||||
|
|
|
@ -69,7 +69,7 @@ const getDeviceList = async () => {
|
|||
const res = await cascadeApi.getMediaTree({ paging: false });
|
||||
if (res.success) {
|
||||
treeData.value = res.result
|
||||
.sort((a: any, b: any) => a.createTime - b.createTime)
|
||||
.sort((a: any, b: any) => b.createTime - a.createTime)
|
||||
.map((m: any) => {
|
||||
const extra: any = {};
|
||||
extra.isLeaf = isLeaf(m);
|
||||
|
|
|
@ -269,7 +269,7 @@
|
|||
v-model:value="
|
||||
formData.configuration.secret
|
||||
"
|
||||
placeholder="Secret"
|
||||
placeholder="请输入Secret"
|
||||
/>
|
||||
</j-form-item>
|
||||
</template>
|
||||
|
@ -493,33 +493,33 @@ const handleSslChange = () => {
|
|||
const resetPublicFiles = () => {
|
||||
switch (formData.value.provider) {
|
||||
case 'dingTalkMessage':
|
||||
formData.value.configuration.appKey = '';
|
||||
formData.value.configuration.appSecret = '';
|
||||
formData.value.configuration.appKey = undefined;
|
||||
formData.value.configuration.appSecret = undefined;
|
||||
break;
|
||||
case 'dingTalkRobotWebHook':
|
||||
formData.value.configuration.url = '';
|
||||
formData.value.configuration.url = undefined;
|
||||
break;
|
||||
case 'corpMessage':
|
||||
formData.value.configuration.corpId = '';
|
||||
formData.value.configuration.corpSecret = '';
|
||||
formData.value.configuration.corpId = undefined;
|
||||
formData.value.configuration.corpSecret = undefined;
|
||||
break;
|
||||
case 'embedded':
|
||||
formData.value.configuration.host = '';
|
||||
formData.value.configuration.host = undefined;
|
||||
formData.value.configuration.port = 25;
|
||||
formData.value.configuration.ssl = false;
|
||||
formData.value.configuration.sender = '';
|
||||
formData.value.configuration.username = '';
|
||||
formData.value.configuration.password = '';
|
||||
formData.value.configuration.sender = undefined;
|
||||
formData.value.configuration.username = undefined;
|
||||
formData.value.configuration.password = undefined;
|
||||
break;
|
||||
case 'aliyun':
|
||||
formData.value.configuration.regionId = '';
|
||||
formData.value.configuration.accessKeyId = '';
|
||||
formData.value.configuration.secret = '';
|
||||
formData.value.configuration.regionId = undefined;
|
||||
formData.value.configuration.accessKeyId = undefined;
|
||||
formData.value.configuration.secret = undefined;
|
||||
break;
|
||||
case 'aliyunSms':
|
||||
formData.value.configuration.regionId = '';
|
||||
formData.value.configuration.accessKeyId = '';
|
||||
formData.value.configuration.secret = '';
|
||||
formData.value.configuration.regionId = undefined;
|
||||
formData.value.configuration.accessKeyId = undefined;
|
||||
formData.value.configuration.secret = undefined;
|
||||
break;
|
||||
case 'http':
|
||||
formData.value.configuration.url = undefined;
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
pageSize: pageSize,
|
||||
pageSizeOptions: ['5', '10', '20', '50', '100'],
|
||||
showSizeChanger: true,
|
||||
hideOnSinglePage: true,
|
||||
hideOnSinglePage: false,
|
||||
showTotal: (total: number, range: number) => `第 ${range[0]} - ${range[1]} 条/总共 ${total} 条`,
|
||||
}"
|
||||
@change="handleTableChange"
|
||||
|
@ -196,11 +196,19 @@ const getDepartment = async () => {
|
|||
deptId.value = _result[0]?.id;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => deptName.value,
|
||||
(val: any) => {
|
||||
if (!val) getDepartment();
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* 部门点击
|
||||
*/
|
||||
const onTreeSelect = (keys: any) => {
|
||||
deptId.value = keys[0];
|
||||
pageSize.value = 5;
|
||||
};
|
||||
|
||||
// 右侧表格
|
||||
|
|
|
@ -168,6 +168,7 @@
|
|||
:key="i.key"
|
||||
>
|
||||
<PermissionButton
|
||||
:danger="i.key === 'delete'"
|
||||
:disabled="i.disabled"
|
||||
:popConfirm="i.popConfirm"
|
||||
:tooltip="{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<j-select
|
||||
:options="options"
|
||||
@change="change"
|
||||
placeholder="请选择标签推送,多个标签用,号分隔"
|
||||
placeholder="请选择标签推送"
|
||||
style="width: 100%"
|
||||
:allowClear="true"
|
||||
v-model:value="_value"
|
||||
|
|
|
@ -598,7 +598,13 @@
|
|||
</j-form-item>
|
||||
</j-col>
|
||||
<j-col :span="12">
|
||||
<j-form-item>
|
||||
<j-form-item
|
||||
v-bind="
|
||||
validateInfos[
|
||||
'template.phoneNumber'
|
||||
]
|
||||
"
|
||||
>
|
||||
<template #label>
|
||||
<span>
|
||||
收信人
|
||||
|
@ -828,7 +834,10 @@ const resetPublicFiles = () => {
|
|||
case 'dingTalkRobotWebHook':
|
||||
formData.value.template.message = undefined;
|
||||
formData.value.template.messageType = 'markdown';
|
||||
formData.value.template.markdown = { text: undefined, title: undefined };
|
||||
formData.value.template.markdown = {
|
||||
text: undefined,
|
||||
title: undefined,
|
||||
};
|
||||
break;
|
||||
case 'corpMessage':
|
||||
formData.value.template.agentId = undefined;
|
||||
|
@ -990,6 +999,17 @@ const formRules = ref({
|
|||
'template.signName': [
|
||||
{ required: true, message: '请输入签名', trigger: 'blur' },
|
||||
],
|
||||
'template.phoneNumber': [
|
||||
{ max: 64, message: '最多可输入64个字符', trigger: 'change' },
|
||||
{
|
||||
trigger: 'change',
|
||||
validator(_rule: Rule, value: string) {
|
||||
if (!value) return Promise.resolve();
|
||||
if (!phoneRegEx(value)) return Promise.reject('该字段不是有效的手机号');
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
],
|
||||
// webhook
|
||||
description: [{ max: 200, message: '最多可输入200个字符' }],
|
||||
'template.message': [
|
||||
|
|
|
@ -131,6 +131,7 @@
|
|||
:key="i.key"
|
||||
>
|
||||
<PermissionButton
|
||||
:danger="i.key === 'delete'"
|
||||
:disabled="i.disabled"
|
||||
:popConfirm="i.popConfirm"
|
||||
:tooltip="{
|
||||
|
|
|
@ -49,9 +49,8 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Form } from 'ant-design-vue';
|
||||
import { saveOutputData } from '@/api/rule-engine/config';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { Form, message } from 'jetlinks-ui-components';
|
||||
const useForm = Form.useForm;
|
||||
const formRef = ref();
|
||||
const Myprops = defineProps({
|
||||
|
|
|
@ -59,9 +59,8 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Form } from 'ant-design-vue';
|
||||
import { saveOutputData } from '@/api/rule-engine/config';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { Form, message } from 'jetlinks-ui-components';
|
||||
const formRef = ref();
|
||||
const useForm = Form.useForm;
|
||||
const Myprops = defineProps({
|
||||
|
|
|
@ -186,11 +186,6 @@
|
|||
<script lang="ts" setup>
|
||||
import InputSave from './Save/input.vue';
|
||||
import OutputSave from './save/output.vue';
|
||||
import {
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
PlusOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { getDataExchange } from '@/api/rule-engine/config';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { marked } from 'marked';
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
import { getImage } from '@/utils/comm';
|
||||
import { queryLevel, saveLevel } from '@/api/rule-engine/config';
|
||||
import { LevelItem } from './typing';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import Io from './Io/index.vue'
|
||||
const list = ref([
|
||||
{
|
||||
|
|
|
@ -56,7 +56,7 @@ import { getTargetTypes, save, detail } from '@/api/rule-engine/configuration';
|
|||
import { queryLevel } from '@/api/rule-engine/config';
|
||||
import { query } from '@/api/rule-engine/scene';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useAlarmConfigurationStore } from '@/store/alarm';
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
import { query } from '@/api/rule-engine/scene';
|
||||
import { bindScene } from '@/api/rule-engine/configuration';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
|
|
|
@ -97,7 +97,7 @@ import { unbindScene } from '@/api/rule-engine/configuration';
|
|||
import { useRoute } from 'vue-router';
|
||||
import type { ActionsType } from '@/components/Table';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import Save from './save/index.vue';
|
||||
import { useAlarmConfigurationStore } from '@/store/alarm';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
|
|
@ -179,7 +179,7 @@ import {
|
|||
import { queryLevel } from '@/api/rule-engine/config';
|
||||
import { Store } from 'jetlinks-store';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
import encodeQuery from '@/utils/encodeQuery';
|
||||
|
|
|
@ -49,7 +49,7 @@ import { detail, queryHistoryList } from '@/api/rule-engine/log';
|
|||
import { useRoute } from 'vue-router';
|
||||
import moment from 'moment';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import { useAlarmStore } from '@/store/alarm';
|
||||
import Info from './info.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Empty } from 'ant-design-vue';
|
||||
import { Empty } from 'jetlinks-ui-components';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { useMenuStore } from '@/store/menu';
|
||||
import moment from 'moment';
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
<script lang="ts" setup>
|
||||
import { saveRule, modify } from '@/api/rule-engine/instance';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
|
||||
const emit = defineEmits(['success', 'closeSave']);
|
||||
const props = defineProps({
|
||||
|
|
|
@ -148,7 +148,7 @@ import {
|
|||
} from '@/api/rule-engine/instance';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { message } from 'jetlinks-ui-components';
|
||||
import Save from './Save/index.vue';
|
||||
import { SystemConst } from '@/utils/consts';
|
||||
const params = ref<Record<string, any>>({});
|
||||
|
|
|
@ -59,10 +59,12 @@ import { detail as deviceDetail } from '@/api/device/instance'
|
|||
import Product from './Product.vue'
|
||||
import DeviceSelect from './DeviceSelect.vue'
|
||||
import Type from './Type.vue'
|
||||
import {continuousValue, handleTimerOptions, timeUnitEnum} from '@/views/rule-engine/Scene/Save/components/Timer/util'
|
||||
import { handleTimerOptions } from '@/views/rule-engine/Scene/Save/components/Timer/util'
|
||||
import { Form } from 'jetlinks-ui-components'
|
||||
|
||||
type Emit = {
|
||||
(e: 'cancel'): void
|
||||
(e: 'change', data: TriggerDevice): void
|
||||
(e: 'save', data: TriggerDevice, options: Record<string, any>): void
|
||||
}
|
||||
|
||||
|
@ -76,6 +78,7 @@ interface AddModelType extends Omit<TriggerDevice, 'selectorValues'> {
|
|||
metadata: metadataType,
|
||||
operator: TriggerDeviceOptions
|
||||
}
|
||||
const formItemContext = Form.useInjectFormItemContext();
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
const typeRef = ref()
|
||||
|
@ -165,26 +168,6 @@ const handleOptions = (data: TriggerDeviceOptions) => {
|
|||
_options.when = when;
|
||||
_options.time = time;
|
||||
_options.extraTime = extraTime;
|
||||
// if (_timer.trigger === 'cron') {
|
||||
// _options.time = _timer.cron;
|
||||
// } else {
|
||||
// // console.log('continuousValue', continuousValue(_timer.when! || [], _timer!.trigger))
|
||||
// let whenStr = '每天';
|
||||
// if (_timer.when!.length) {
|
||||
// whenStr = _timer!.trigger === 'week' ? '每周' : '每月';
|
||||
// const whenStrArr = continuousValue(_timer.when! || [], _timer!.trigger);
|
||||
// const whenStrArr3 = whenStrArr.splice(0, 3);
|
||||
// whenStr += whenStrArr3.join('、');
|
||||
// whenStr += `等${_timer.when!.length}天`;
|
||||
// }
|
||||
// _options.when = whenStr;
|
||||
// if (_timer.once) {
|
||||
// _options.time = _timer.once.time + ' 执行1次';
|
||||
// } else if (_timer.period) {
|
||||
// _options.time = _timer.period.from + '-' + _timer.period.to;
|
||||
// _options.extraTime = `每${_timer.period.every}${timeUnitEnum[_timer.period.unit]}执行1次`;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
if (data.operator === 'online') {
|
||||
|
@ -257,12 +240,13 @@ const save = async (step?: number) => {
|
|||
optionsCache.value.action = typeData.action
|
||||
const _options = handleOptions(typeData.data);
|
||||
const data = {
|
||||
operator: typeData.data,
|
||||
operation: typeData.data,
|
||||
selector: addModel.selector,
|
||||
selectorValues: addModel.selectorValues,
|
||||
productId: addModel.productId
|
||||
}
|
||||
emit('save', data, _options)
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,6 @@ type Emit = {
|
|||
}
|
||||
|
||||
const params = ref({})
|
||||
const context = inject('SceneDeviceAddModel')
|
||||
const props = defineProps({
|
||||
rowKeys: {
|
||||
type: Array as PropType<SelectorValuesItem[]>,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class='device'>
|
||||
<j-form-item
|
||||
:rules='rules'
|
||||
name='device'
|
||||
:name='["trigger", "device"]'
|
||||
>
|
||||
<template #label>
|
||||
<TitleComponent data='触发规则' style='font-size: 14px;' />
|
||||
|
@ -13,9 +13,9 @@
|
|||
>
|
||||
<Title :options='data.options.trigger' />
|
||||
</AddButton>
|
||||
<AddModel v-if='visible' @cancel='visible = false' @save='save' :value='data.trigger.device' :options='data.options.trigger' />
|
||||
</j-form-item>
|
||||
<Terms />
|
||||
<AddModel v-if='visible' @cancel='visible = false' @save='save' :value='data.trigger.device' :options='data.options.trigger' />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -28,6 +28,7 @@ import Title from '../components/Title.vue'
|
|||
import Terms from '../components/Terms'
|
||||
import type { TriggerDevice } from '@/views/rule-engine/Scene/typings'
|
||||
|
||||
|
||||
const sceneStore = useSceneStore()
|
||||
const { data } = storeToRefs(sceneStore)
|
||||
|
||||
|
@ -45,6 +46,7 @@ const rules = [{
|
|||
const save = (device: TriggerDevice, options: Record<string, any>) => {
|
||||
data.value.trigger!.device = device
|
||||
data.value.options!.trigger = options
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<template>
|
||||
<div class='actions-branches-item'>
|
||||
<j-form-item
|
||||
:rules="actionRules"
|
||||
:name="['branches', 0, 'then']"
|
||||
|
@ -8,6 +9,7 @@
|
|||
:name="0"
|
||||
/>
|
||||
</j-form-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name='SceneSaveManual'>
|
||||
|
@ -21,7 +23,6 @@ const { data } = storeToRefs(sceneStore);
|
|||
|
||||
const actionRules = [{
|
||||
validator(_: any, v?: BranchesThen[]) {
|
||||
console.log(_, v)
|
||||
if (!v || (v && !v.length) || (v && v.length && !v[0].actions.length)) {
|
||||
return Promise.reject('至少配置一个执行动作');
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<Title :options='data.options.trigger' />
|
||||
</AddButton>
|
||||
</j-form-item>
|
||||
<div class='actions-branches-item' >
|
||||
<j-form-item
|
||||
:rules="actionRules"
|
||||
:name="['branches', 0, 'then']"
|
||||
|
@ -23,6 +24,7 @@
|
|||
:name="0"
|
||||
/>
|
||||
</j-form-item>
|
||||
</div>
|
||||
<AddModel
|
||||
v-if="visible"
|
||||
@cancel='visible = false'
|
||||
|
@ -79,6 +81,7 @@ const onActionUpdate = (_data: any, type: boolean) => {
|
|||
const save = (_data: OperationTimer, options: Record<string, any>) => {
|
||||
data.value.trigger!.timer = _data
|
||||
data.value.options!.trigger = options
|
||||
visible.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ import { inject } from 'vue'
|
|||
import { useSceneStore } from 'store/scene'
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { flattenDeep, set } from 'lodash-es'
|
||||
import { Form } from 'jetlinks-ui-components'
|
||||
|
||||
const sceneStore = useSceneStore()
|
||||
const { data: formModel } = storeToRefs(sceneStore)
|
||||
|
@ -152,7 +153,7 @@ const paramsValue = reactive<TermsType>({
|
|||
termType: props.value.termType,
|
||||
value: props.value.value
|
||||
})
|
||||
|
||||
const formItemContext = Form.useInjectFormItemContext()
|
||||
const showDelete = ref(false)
|
||||
const columnOptions: any = inject('filter-params') //
|
||||
const termTypeOptions = ref<Array<{ id: string, name: string}>>([]) // 条件值
|
||||
|
@ -187,8 +188,18 @@ const handOptionByColumn = (option: any) => {
|
|||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (!props.value.error && props.value.column) { // 新增不查找option
|
||||
const option = getOption(columnOptions.value, paramsValue.column, 'id')
|
||||
if (option) {
|
||||
handOptionByColumn(option)
|
||||
} else {
|
||||
emit('update:value', {
|
||||
...props.value,
|
||||
error: true
|
||||
})
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const showDouble = computed(() => {
|
||||
|
@ -235,6 +246,7 @@ const columnSelect = (e: any) => {
|
|||
)
|
||||
handleOptionsColumnsValue(termsColumns, _options)
|
||||
emit('update:value', { ...paramsValue })
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
|
||||
const termsTypeSelect = (e: { key: string }) => {
|
||||
|
@ -244,10 +256,12 @@ const termsTypeSelect = (e: { key: string }) => {
|
|||
value: value
|
||||
}
|
||||
emit('update:value', { ...paramsValue })
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
|
||||
const valueSelect = () => {
|
||||
emit('update:value', { ...paramsValue })
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
|
||||
const termAdd = () => {
|
||||
|
|
|
@ -58,7 +58,7 @@ import { storeToRefs } from 'pinia'
|
|||
import { useSceneStore } from 'store/scene'
|
||||
import DropdownButton from '../../components/DropdownButton'
|
||||
import FilterItem from './FilterCondition.vue'
|
||||
import { flattenDeep, isArray, set } from 'lodash-es'
|
||||
import { flattenDeep, isArray } from 'lodash-es'
|
||||
import { provide } from 'vue'
|
||||
import { randomString } from '@/utils/utils'
|
||||
import { useParams } from '@/views/rule-engine/Scene/Save/util'
|
||||
|
@ -172,8 +172,7 @@ const onDelete = () => {
|
|||
const rules = [
|
||||
{
|
||||
validator(_: any, v?: Record<string, any>) {
|
||||
console.log('-----v',v)
|
||||
if (v !== undefined) {
|
||||
if (v !== undefined && !v.error) {
|
||||
if (!Object.keys(v).length) {
|
||||
return Promise.reject(new Error('该数据已发生变更,请重新配置'))
|
||||
}
|
||||
|
|
|
@ -234,7 +234,7 @@
|
|||
@click="onType('device')"
|
||||
>
|
||||
<template v-if="data?.device?.selector === 'fixed'">
|
||||
<div>
|
||||
<div style='display: flex; align-items: center;'>
|
||||
<AIcon
|
||||
:type="
|
||||
typeIconMap[
|
||||
|
@ -248,13 +248,16 @@
|
|||
}}</span>
|
||||
<AIcon
|
||||
type="icon-mubiao"
|
||||
style="padding-right: 2px"
|
||||
style="padding:0 4px"
|
||||
/>
|
||||
<Ellipsis style='max-width: 200px;margin-right: 12px;'>
|
||||
{{data?.options?.name}}
|
||||
</Ellipsis>
|
||||
<Ellipsis style='max-width: 400px;'>
|
||||
{{data?.options?.properties}}
|
||||
</Ellipsis>
|
||||
{{
|
||||
`${data?.options?.name} ${
|
||||
data?.options?.properties
|
||||
}
|
||||
${
|
||||
`${
|
||||
(
|
||||
isBoolean(
|
||||
data?.options?.propertiesValue,
|
||||
|
@ -349,7 +352,7 @@
|
|||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="filter-add-button">
|
||||
<div v-else class="filter-add-button" @click='addFilterParams'>
|
||||
<AIcon type="PlusOutlined" style="padding-right: 4px" />
|
||||
<span>添加过滤条件</span>
|
||||
</div>
|
||||
|
@ -394,6 +397,7 @@ import { useSceneStore } from '@/store/scene';
|
|||
import { storeToRefs } from 'pinia';
|
||||
import { iconMap, itemNotifyIconMap, typeIconMap } from './util';
|
||||
import FilterGroup from './FilterGroup.vue';
|
||||
import { randomString } from '@/utils/utils'
|
||||
|
||||
const sceneStore = useSceneStore();
|
||||
const { data: _data } = storeToRefs(sceneStore);
|
||||
|
@ -471,6 +475,30 @@ const onSave = (data: ActionsType, options: any) => {
|
|||
visible.value = false;
|
||||
};
|
||||
|
||||
const addFilterParams = () => {
|
||||
const item: any = {
|
||||
type: 'and',
|
||||
key: randomString(),
|
||||
terms: [
|
||||
{
|
||||
column: undefined,
|
||||
value: {
|
||||
type: 'fixed',
|
||||
value: undefined
|
||||
},
|
||||
termType: undefined,
|
||||
type: 'and',
|
||||
key: randomString()
|
||||
}
|
||||
]
|
||||
}
|
||||
if (_data.value.branches![props.branchesName].then[props.thenName].actions[props.name].terms) {
|
||||
_data.value.branches![props.branchesName].then[props.thenName].actions[props.name].terms!.push(item)
|
||||
} else {
|
||||
_data.value.branches![props.branchesName].then[props.thenName].actions[props.name].terms = [item]
|
||||
}
|
||||
}
|
||||
|
||||
const onAdd = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
|
|
|
@ -1,57 +1,57 @@
|
|||
<template>
|
||||
<div class="actions">
|
||||
<div class="actions-title">
|
||||
<div class='actions'>
|
||||
<div class='actions-title'>
|
||||
<span>执行</span>
|
||||
<ShakeLimit
|
||||
v-if="props.openShakeLimit"
|
||||
v-model:value="FormModel.branches[name].shakeLimit"
|
||||
v-if='props.openShakeLimit'
|
||||
v-model:value='FormModel.branches[name].shakeLimit'
|
||||
/>
|
||||
</div>
|
||||
<div class="actions-warp">
|
||||
<j-collapse v-model:activeKey="activeKeys">
|
||||
<j-collapse-panel key="1">
|
||||
<div class='actions-warp'>
|
||||
<j-collapse v-model:activeKey='activeKeys'>
|
||||
<j-collapse-panel key='1'>
|
||||
<template #header>
|
||||
<span>
|
||||
串行
|
||||
<span class="panel-tip">
|
||||
<span class='panel-tip'>
|
||||
按顺序依次执行动作,适用于基于动作输出参数,判断是否执行后续动作的场景
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
<div class="actions-list">
|
||||
<div class='actions-list'>
|
||||
<List
|
||||
type="serial"
|
||||
:branchesName="name"
|
||||
:parallel="false"
|
||||
:actions="
|
||||
type='serial'
|
||||
:branchesName='name'
|
||||
:parallel='false'
|
||||
:actions='
|
||||
serialArray.length ? serialArray[0].actions : []
|
||||
"
|
||||
@add="(_item) => onAdd(_item, false)"
|
||||
@delete="(_key) => onDelete(_key, false)"
|
||||
'
|
||||
@add='(_item) => onAdd(_item, false)'
|
||||
@delete='(_key) => onDelete(_key, false)'
|
||||
/>
|
||||
</div>
|
||||
</j-collapse-panel>
|
||||
<j-collapse-panel key="2">
|
||||
<j-collapse-panel key='2'>
|
||||
<template #header>
|
||||
<span>
|
||||
并行
|
||||
<span class="panel-tip">
|
||||
<span class='panel-tip'>
|
||||
同时执行所有动作,适用于不需要关注执行动作先后顺序和结果的场景
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
<div class="actions-list">
|
||||
<div class='actions-list'>
|
||||
<List
|
||||
type="parallel"
|
||||
:branchesName="name"
|
||||
:parallel="true"
|
||||
:actions="
|
||||
type='parallel'
|
||||
:branchesName='name'
|
||||
:parallel='true'
|
||||
:actions='
|
||||
parallelArray.length
|
||||
? parallelArray[0].actions
|
||||
: []
|
||||
"
|
||||
@add="(_item) => onAdd(_item, true)"
|
||||
@delete="(_key) => onDelete(_key, true)"
|
||||
'
|
||||
@add='(_item) => onAdd(_item, true)'
|
||||
@delete='(_key) => onDelete(_key, true)'
|
||||
/>
|
||||
</div>
|
||||
</j-collapse-panel>
|
||||
|
@ -60,18 +60,20 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ShakeLimit from '../components/ShakeLimit/index.vue';
|
||||
import { List } from './ListItem';
|
||||
<script lang='ts' setup>
|
||||
import ShakeLimit from '../components/ShakeLimit/index.vue'
|
||||
import { List } from './ListItem'
|
||||
import { BranchesThen } from '../../typings'
|
||||
import { PropType } from 'vue';
|
||||
import { randomString } from '@/utils/utils';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { PropType } from 'vue'
|
||||
import { randomString } from '@/utils/utils'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useSceneStore } from 'store/scene'
|
||||
import { Form } from 'jetlinks-ui-components'
|
||||
|
||||
const sceneStore = useSceneStore()
|
||||
const { data: FormModel } = storeToRefs(sceneStore)
|
||||
|
||||
const formItemContext = Form.useInjectFormItemContext();
|
||||
const props = defineProps({
|
||||
name: {
|
||||
type: Number,
|
||||
|
@ -79,45 +81,45 @@ const props = defineProps({
|
|||
},
|
||||
thenOptions: {
|
||||
type: Array as PropType<BranchesThen[]>,
|
||||
default: () => [],
|
||||
default: () => []
|
||||
},
|
||||
openShakeLimit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update', 'add']);
|
||||
const emit = defineEmits(['update', 'add'])
|
||||
|
||||
const activeKeys = ref<string[]>(['1']);
|
||||
const parallelArray = ref<BranchesThen[]>([]);
|
||||
const serialArray = ref<BranchesThen[]>([]);
|
||||
const lock = ref<boolean>(false);
|
||||
const activeKeys = ref<string[]>(['1'])
|
||||
const parallelArray = ref<BranchesThen[]>([])
|
||||
const serialArray = ref<BranchesThen[]>([])
|
||||
const lock = ref<boolean>(false)
|
||||
|
||||
watch(
|
||||
() => props.thenOptions,
|
||||
(newVal) => {
|
||||
parallelArray.value = newVal.filter((item) => item.parallel);
|
||||
serialArray.value = newVal.filter((item) => !item.parallel);
|
||||
parallelArray.value = newVal.filter((item) => item.parallel)
|
||||
serialArray.value = newVal.filter((item) => !item.parallel)
|
||||
|
||||
const isSerialActions = serialArray.value.some((item) => {
|
||||
return !!item.actions.length;
|
||||
});
|
||||
return !!item.actions.length
|
||||
})
|
||||
|
||||
if (
|
||||
!lock.value &&
|
||||
parallelArray.value.length &&
|
||||
(!serialArray.value.length || !isSerialActions)
|
||||
) {
|
||||
activeKeys.value = ['2'];
|
||||
lock.value = true;
|
||||
activeKeys.value = ['2']
|
||||
lock.value = true
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
const onDelete = (_key: string, _parallel: boolean) => {
|
||||
const thenName = props.thenOptions.findIndex(item => item.parallel === _parallel)
|
||||
|
@ -125,7 +127,8 @@ const onDelete = (_key: string, _parallel: boolean) => {
|
|||
if (actionIndex !== -1) {
|
||||
FormModel.value.branches?.[props.name].then?.[thenName].actions.splice(actionIndex!, 1)
|
||||
}
|
||||
};
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
|
||||
const onAdd = (actionItem: any, _parallel: boolean) => {
|
||||
const thenName = props.thenOptions.findIndex(item => item.parallel === _parallel)
|
||||
|
@ -146,10 +149,11 @@ const onAdd = (actionItem: any, _parallel: boolean) => {
|
|||
}
|
||||
FormModel.value.branches?.[props.name].then.push(newThenItem)
|
||||
}
|
||||
};
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
<style lang='less' scoped>
|
||||
.actions {
|
||||
.actions-title {
|
||||
display: flex;
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
<slot :label='label'>
|
||||
<div :class='dropdownButtonClass' >
|
||||
<AIcon v-if='!!icon' :type='icon' />
|
||||
<Ellipsis style='max-width: 220px;'>
|
||||
{{ label }}
|
||||
</Ellipsis>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
<slot :label='label'>
|
||||
<div class='dropdown-button value'>
|
||||
<AIcon v-if='!!icon' :type='icon' />
|
||||
<Ellipsis style='max-width: 220px;'>
|
||||
{{ label }}
|
||||
</Ellipsis>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<Action
|
||||
:name='name'
|
||||
:openShakeLimit="true"
|
||||
:thenOptions='FormModel.branches[name].then'
|
||||
:thenOptions='FormModel.branches[name]?.then'
|
||||
/>
|
||||
</j-form-item>
|
||||
</div>
|
||||
|
@ -64,7 +64,7 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup name='Branchs'>
|
||||
<script lang='ts' setup name='Branches'>
|
||||
import type { PropType } from 'vue'
|
||||
import type { ActionBranchesProps } from '@/views/rule-engine/Scene/typings'
|
||||
import TermsItem from './TermsItem.vue'
|
|
@ -44,6 +44,7 @@
|
|||
:tabsOptions='tabsOptions'
|
||||
v-model:value='paramsValue.value.value'
|
||||
v-model:source='paramsValue.value.source'
|
||||
@select='valueSelect'
|
||||
/>
|
||||
<ParamsDropdown
|
||||
v-else
|
||||
|
@ -54,6 +55,7 @@
|
|||
:tabsOptions='tabsOptions'
|
||||
v-model:value='paramsValue.value.value'
|
||||
v-model:source='paramsValue.value.source'
|
||||
@select='valueSelect'
|
||||
/>
|
||||
<j-popconfirm title='确认删除?' @confirm='onDelete'>
|
||||
<div v-show='showDelete' class='button-delete'> <AIcon type='CloseOutlined' /></div>
|
||||
|
@ -77,9 +79,11 @@ import { inject } from 'vue'
|
|||
import { ContextKey } from './util'
|
||||
import { useSceneStore } from 'store/scene'
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { Form } from 'jetlinks-ui-components'
|
||||
|
||||
const sceneStore = useSceneStore()
|
||||
const { data: formModel } = storeToRefs(sceneStore)
|
||||
const formItemContext = Form.useInjectFormItemContext();
|
||||
|
||||
type Emit = {
|
||||
(e: 'update:value', data: TermsType): void
|
||||
|
@ -137,10 +141,10 @@ const props = defineProps({
|
|||
const emit = defineEmits<Emit>()
|
||||
|
||||
const paramsValue = reactive<TermsType>({
|
||||
column: props.value.column,
|
||||
type: props.value.type,
|
||||
termType: props.value.termType,
|
||||
value: props.value.value
|
||||
column: props.value?.column,
|
||||
type: props.value?.type,
|
||||
termType: props.value?.termType,
|
||||
value: props.value?.value
|
||||
})
|
||||
|
||||
const showDelete = ref(false)
|
||||
|
@ -183,8 +187,18 @@ const handOptionByColumn = (option: any) => {
|
|||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (!props.value.error && props.value.column) { // 新增不查找option
|
||||
const option = getOption(columnOptions.value, paramsValue.column, 'column')
|
||||
if (option) {
|
||||
handOptionByColumn(option)
|
||||
} else {
|
||||
emit('update:value', {
|
||||
...props.value,
|
||||
error: true
|
||||
})
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const showDouble = computed(() => {
|
||||
|
@ -216,6 +230,7 @@ const columnSelect = () => {
|
|||
value: undefined
|
||||
}
|
||||
emit('update:value', { ...paramsValue })
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
|
||||
const termsTypeSelect = (e: { key: string }) => {
|
||||
|
@ -225,6 +240,11 @@ const termsTypeSelect = (e: { key: string }) => {
|
|||
value: value
|
||||
}
|
||||
emit('update:value', { ...paramsValue })
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
|
||||
const valueSelect = () => {
|
||||
formItemContext.onFieldChange()
|
||||
}
|
||||
|
||||
const termAdd = () => {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
@deleteAll='branchesDeleteAll'
|
||||
/>
|
||||
<div v-else class='actions-terms-warp' :style='{ marginTop: data.branches.length === 2 ? 0 : 24 }'>
|
||||
<div class='actions-terms-title' style='padding: 0'>
|
||||
<div class='actions-terms-title' style='padding: 0;margin-bottom: 24px;'>
|
||||
否则
|
||||
</div>
|
||||
<div class='actions-terms-options no-when'>
|
||||
|
@ -32,6 +32,18 @@
|
|||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<div v-else class='actions-branches-item'>
|
||||
<j-form-item
|
||||
:name='["branches", 0, "then"]'
|
||||
:rules='thenRules'
|
||||
>
|
||||
<Action
|
||||
:name='0'
|
||||
:openShakeLimit="true"
|
||||
:thenOptions='data.branches[0]?.then'
|
||||
/>
|
||||
</j-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -40,14 +52,14 @@ import { storeToRefs } from 'pinia';
|
|||
import { useSceneStore } from 'store/scene'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { provide } from 'vue'
|
||||
import { ContextKey, handleParamsData } from './util'
|
||||
import { ContextKey, handleParamsData, thenRules } from './util'
|
||||
import { getParseTerm } from '@/api/rule-engine/scene'
|
||||
import type { FormModelType } from '@/views/rule-engine/Scene/typings'
|
||||
import Branches from './Branchs.vue'
|
||||
import Branches from './Branches.vue'
|
||||
import Action from '../../action/index.vue'
|
||||
|
||||
const sceneStore = useSceneStore()
|
||||
const { data } = storeToRefs(sceneStore)
|
||||
|
||||
const open = ref(false)
|
||||
const columnOptions = ref<any>([])
|
||||
|
||||
|
@ -56,6 +68,11 @@ provide(ContextKey, columnOptions)
|
|||
|
||||
const change = (e: boolean) => {
|
||||
open.value = e
|
||||
if (!e) {
|
||||
data.value.branches!.length = 1
|
||||
} else {
|
||||
data.value.branches!.push(null as any)
|
||||
}
|
||||
}
|
||||
|
||||
const queryColumn = (dataModel: FormModelType) => {
|
||||
|
@ -96,9 +113,8 @@ const branchesDeleteAll = () => {
|
|||
}
|
||||
|
||||
watchEffect(() => {
|
||||
console.log(data.value.trigger, data.value.trigger?.device)
|
||||
if (data.value.trigger?.device) {
|
||||
queryColumn(data.value)
|
||||
queryColumn({ trigger: data.value.trigger })
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
v-for='(item, index) in termsData'
|
||||
:key='item.key'
|
||||
:name='["branches", branchName, "when", whenName, "terms", index]'
|
||||
:rules='rules'
|
||||
>
|
||||
<ParamsItem
|
||||
v-model:value='formModel.branches[branchName].when[whenName].terms[index]'
|
||||
|
@ -39,7 +40,6 @@
|
|||
:termsName='name'
|
||||
:whenName='whenName'
|
||||
:branchName='branchName'
|
||||
@change='paramsChange'
|
||||
/>
|
||||
</j-form-item>
|
||||
</div>
|
||||
|
@ -60,6 +60,7 @@ import DropdownButton from '../DropdownButton'
|
|||
import { storeToRefs } from 'pinia';
|
||||
import { useSceneStore } from 'store/scene'
|
||||
import ParamsItem from './ParamsItem.vue'
|
||||
import { isArray } from 'lodash-es'
|
||||
|
||||
const sceneStore = useSceneStore()
|
||||
const { data: formModel } = storeToRefs(sceneStore)
|
||||
|
@ -103,6 +104,41 @@ const props = defineProps({
|
|||
}
|
||||
})
|
||||
|
||||
const rules = [
|
||||
{
|
||||
validator(_: any, v: any) {
|
||||
if (v !== undefined && !v.error) {
|
||||
if (!Object.keys(v).length) {
|
||||
return Promise.reject(new Error('该数据已发生变更,请重新配置'));
|
||||
}
|
||||
if (!v.column) {
|
||||
return Promise.reject(new Error('请选择参数'));
|
||||
}
|
||||
|
||||
if (!v.termType) {
|
||||
return Promise.reject(new Error('请选择操作符'));
|
||||
}
|
||||
|
||||
if (v.value === undefined) {
|
||||
return Promise.reject(new Error('请选择或输入参数值'));
|
||||
} else {
|
||||
if (
|
||||
isArray(v.value.value) &&
|
||||
v.value.value.some((_v: any) => _v === undefined)
|
||||
) {
|
||||
return Promise.reject(new Error('请选择或输入参数值'));
|
||||
} else if (v.value.value === undefined) {
|
||||
return Promise.reject(new Error('请选择或输入参数值'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Promise.reject(new Error('请选择参数'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
const showDelete = ref(false)
|
||||
|
||||
const termsData = computed(() => {
|
||||
|
@ -125,10 +161,6 @@ const onDelete = () => {
|
|||
formModel.value.branches?.[props.branchName]?.when?.splice(props.name, 1)
|
||||
}
|
||||
|
||||
const paramsChange = () => {
|
||||
|
||||
}
|
||||
|
||||
const addTerms = () => {
|
||||
const terms = {
|
||||
type: 'and',
|
||||
|
|
|
@ -106,6 +106,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actions-branches-item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.terms-params {
|
||||
|
@ -131,11 +135,15 @@
|
|||
|
||||
.ant-form-item {
|
||||
margin-bottom: 8px;
|
||||
&:not(:first-child) {
|
||||
&:not(:nth-child(2)) {
|
||||
.ant-form-item-explain-error {
|
||||
padding-left: 80px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.ant-form-item-has-error {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,6 +228,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.actions-branches-item {
|
||||
width: 75%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,3 +10,15 @@ export const handleParamsData = (data: any[], key: string = 'column'): any[] =>
|
|||
}
|
||||
}) || []
|
||||
}
|
||||
|
||||
export const thenRules = [{
|
||||
validator(_: string, value: any) {
|
||||
if (!value || (value && !value.length)) {
|
||||
return Promise.reject('至少配置一个执行动作')
|
||||
} else {
|
||||
const isActions = value.some((item: any) => item.actions && item.actions.length)
|
||||
return isActions ? Promise.resolve() : Promise.reject('至少配置一个执行动作');
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}]
|
|
@ -1,370 +0,0 @@
|
|||
<template>
|
||||
<div class="card">
|
||||
<div
|
||||
class="card-warp"
|
||||
:class="{ active: active ? 'active' : '' }"
|
||||
@click="handleClick"
|
||||
>
|
||||
<div class="card-type">
|
||||
<div class="card-type-text"><slot name="type"></slot></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div style="display: flex">
|
||||
<!-- 图片 -->
|
||||
<div class="card-item-avatar">
|
||||
<slot name="img"> </slot>
|
||||
</div>
|
||||
<!-- 内容 -->
|
||||
<div class="card-item-body">
|
||||
<slot name="title"></slot>
|
||||
<span class="subTitle">
|
||||
<slot name="subTitle"></slot>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 勾选 -->
|
||||
<div v-if="active" class="checked-icon">
|
||||
<div>
|
||||
<AIcon type="CheckOutlined" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 状态 -->
|
||||
<div
|
||||
v-if="showStatus"
|
||||
class="card-state"
|
||||
:class="statusNames ? statusNames[status] : ''"
|
||||
>
|
||||
<div class="card-state-content">
|
||||
<BadgeStatus
|
||||
:status="status"
|
||||
:text="statusText"
|
||||
:statusNames="statusNames"
|
||||
></BadgeStatus>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 按钮 -->
|
||||
<slot name="bottom-tool">
|
||||
<div
|
||||
v-if="showTool && actions && actions.length"
|
||||
class="card-tools"
|
||||
>
|
||||
<div
|
||||
v-for="item in actions"
|
||||
:key="item.key"
|
||||
class="card-button"
|
||||
:class="{
|
||||
delete: item.key === 'delete',
|
||||
}"
|
||||
>
|
||||
<slot name="actions" v-bind="item"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import BadgeStatus from '@/components/BadgeStatus/index.vue';
|
||||
import { StatusColorEnum } from '@/utils/consts.ts';
|
||||
import type { ActionsType } from '@/components/Table/index.vue';
|
||||
import { PropType } from 'vue';
|
||||
|
||||
type EmitProps = {
|
||||
(e: 'click', data: Record<string, any>): void;
|
||||
};
|
||||
|
||||
type TableActionsType = Partial<ActionsType>;
|
||||
|
||||
const emit = defineEmits<EmitProps>();
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: Object as PropType<Record<string, any>>,
|
||||
default: () => {},
|
||||
},
|
||||
showStatus: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showTool: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
statusText: {
|
||||
type: String,
|
||||
default: '正常',
|
||||
},
|
||||
status: {
|
||||
type: [String, Number],
|
||||
default: 'default',
|
||||
},
|
||||
statusNames: {
|
||||
type: Object,
|
||||
},
|
||||
actions: {
|
||||
type: Array as PropType<TableActionsType[]>,
|
||||
default: () => [],
|
||||
},
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const handleClick = () => {
|
||||
emit('click', props.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.card {
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
.checked-icon {
|
||||
position: absolute;
|
||||
right: -22px;
|
||||
bottom: -22px;
|
||||
z-index: 2;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
color: #fff;
|
||||
background-color: red;
|
||||
background-color: #2f54eb;
|
||||
transform: rotate(-45deg);
|
||||
|
||||
> div {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
transform: rotate(45deg);
|
||||
|
||||
> span {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-warp {
|
||||
position: relative;
|
||||
border: 1px solid #e6e6e6;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 24px rgba(#000, 0.1);
|
||||
|
||||
.card-mask {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
position: relative;
|
||||
border: 1px solid #2f54eb;
|
||||
}
|
||||
|
||||
.card-type {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -14px;
|
||||
height: 32px;
|
||||
padding: 0 30px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
line-height: 32px;
|
||||
background-color: rgba(0, 0, 0, 0.06);
|
||||
transform: skewX(-45deg);
|
||||
.card-type-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: skewX(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
position: relative;
|
||||
padding: 43px 12px 19px 30px;
|
||||
overflow: hidden;
|
||||
|
||||
.card-item-avatar {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.card-item-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
width: 0;
|
||||
|
||||
.subTitle {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-state {
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
right: -12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100px;
|
||||
padding: 2px 0;
|
||||
background-color: rgba(#5995f5, 0.15);
|
||||
transform: skewX(45deg);
|
||||
|
||||
&.success {
|
||||
background-color: @success-color-deprecated-bg;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background-color: rgba(#ff9000, 0.1);
|
||||
}
|
||||
|
||||
&.error {
|
||||
background-color: rgba(#e50012, 0.1);
|
||||
}
|
||||
|
||||
.card-state-content {
|
||||
transform: skewX(-45deg);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.card-item-content-title) {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: @primary-color;
|
||||
width: calc(100% - 100px);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
:deep(.card-item-heard-name) {
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
:deep(.card-item-content-text) {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.item-active {
|
||||
position: relative;
|
||||
color: #2f54eb;
|
||||
|
||||
.checked-icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.card-warp {
|
||||
border: 1px solid #2f54eb;
|
||||
}
|
||||
}
|
||||
|
||||
.card-tools {
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
|
||||
.card-button {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
|
||||
& > :deep(span, button) {
|
||||
width: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
:deep(button) {
|
||||
width: 100%;
|
||||
border-radius: 0;
|
||||
background: #f6f6f6;
|
||||
border: 1px solid #e6e6e6;
|
||||
color: #2f54eb;
|
||||
|
||||
&:hover {
|
||||
background-color: @primary-color-hover;
|
||||
border-color: @primary-color-hover;
|
||||
|
||||
span {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: @primary-color-active;
|
||||
border-color: @primary-color-active;
|
||||
|
||||
span {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&.delete {
|
||||
flex-basis: 60px;
|
||||
flex-grow: 0;
|
||||
|
||||
:deep(button) {
|
||||
background: @error-color-deprecated-bg;
|
||||
border: 1px solid @error-color-outline;
|
||||
|
||||
span {
|
||||
color: @error-color !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @error-color-hover;
|
||||
|
||||
span {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: @error-color-active;
|
||||
|
||||
span {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(button[disabled]) {
|
||||
background: @disabled-bg;
|
||||
border-color: @disabled-color;
|
||||
|
||||
span {
|
||||
color: @disabled-color !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: @disabled-active-bg;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: @disabled-active-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -132,7 +132,6 @@ import { query, _delete, _action, _execute } from '@/api/rule-engine/scene';
|
|||
import { message } from 'ant-design-vue';
|
||||
import type { ActionsType } from '@/components/Table';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import SceneCard from './SceneCard.vue';
|
||||
import BadgeStatus from '@/components/BadgeStatus/index.vue';
|
||||
|
||||
const menuStory = useMenuStore();
|
||||
|
|
|
@ -202,6 +202,7 @@ export type TermsType = {
|
|||
options?: any[];
|
||||
terms?: TermsType[];
|
||||
key?: string;
|
||||
error?: boolean
|
||||
};
|
||||
|
||||
export type PlatformRelation = {
|
||||
|
|
|
@ -406,13 +406,16 @@ const uploader: uploaderType = {
|
|||
'image/pjp',
|
||||
'image/pjpeg',
|
||||
],
|
||||
// imageTypes: ['.jpg','.png','.jfif','.pjp','.pjpeg','.jpeg'],
|
||||
iconTypes: ['image/x-icon'],
|
||||
// logo格式校验
|
||||
beforeLogoUpload: ({ size, type }: File) => {
|
||||
// beforeLogoUpload: ({ size, type }: File) => {
|
||||
beforeLogoUpload: (file: File) => {
|
||||
console.log('file: ', file);
|
||||
const typeBool =
|
||||
uploader.imageTypes.filter((typeStr) => type.includes(typeStr))
|
||||
uploader.imageTypes.filter((typeStr) => file.type.includes(typeStr))
|
||||
.length > 0;
|
||||
const sizeBool = size / 1024 / 1024 < 4;
|
||||
const sizeBool = file.size / 1024 / 1024 < 4;
|
||||
if (!typeBool) {
|
||||
message.error(`请上传.jpg.png.jfif.pjp.pjpeg.jpeg格式的图片`);
|
||||
} else if (!sizeBool) {
|
||||
|
|
|
@ -92,11 +92,9 @@ export default defineConfig(({ mode}) => {
|
|||
[env.VITE_APP_BASE_API]: {
|
||||
// target: 'http://192.168.33.22:8800',
|
||||
// target: 'http://192.168.32.244:8881',
|
||||
// target: 'http://47.112.135.104:5096', // opcua
|
||||
target: 'http://120.77.179.54:8844', // 120测试
|
||||
// target: 'http://47.108.63.174:8845', // 测试
|
||||
// target: 'http://120.77.179.54:8844',
|
||||
ws: 'ws://120.77.179.54:8844',
|
||||
// target: 'http://120.77.179.54:8844', // 120测试
|
||||
target: 'http://192.168.33.46:8844', // 本地开发环境
|
||||
ws: 'ws://192.168.33.46:8844',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, '')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue