feat: 新增场景联动设备规则新增Modal
This commit is contained in:
parent
dd3013ee04
commit
8ddd2562f1
|
|
@ -59,7 +59,16 @@ export const category = (data: any) => server.post('/device/category/_tree', dat
|
||||||
* 获取接入方式
|
* 获取接入方式
|
||||||
* @param data 查询条件
|
* @param data 查询条件
|
||||||
*/
|
*/
|
||||||
export const queryGatewayList = (data: any) => server.post('/gateway/device/_query/no-paging', data)
|
const defaultGatewayData = {
|
||||||
|
paging: false,
|
||||||
|
sorts: [
|
||||||
|
{
|
||||||
|
name: 'createTime',
|
||||||
|
order: 'desc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
export const queryGatewayList = (data: any = defaultGatewayData) => server.post('/gateway/device/_query/no-paging', data)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询产品列表(分页)
|
* 查询产品列表(分页)
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@ const reset = () => {
|
||||||
urlParams.target = null
|
urlParams.target = null
|
||||||
}
|
}
|
||||||
resetNumber.value += 1
|
resetNumber.value += 1
|
||||||
emit('search', terms)
|
emit('search', { terms: []})
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(width, (value) => {
|
watch(width, (value) => {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="title">
|
<div class="title" :style='style'>
|
||||||
<div class="title-before"></div>
|
<div class="title-before"></div>
|
||||||
<span>{{ data }}</span>
|
<span>{{ data }}</span>
|
||||||
<slot name="extra"></slot>
|
<slot name="extra"></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup lang='ts' name='TitleComponent'>
|
||||||
export default {
|
import type { CSSProperties, PropType } from 'vue'
|
||||||
name: "TitleComponent",
|
|
||||||
props: {
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ""
|
default: ""
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
style: {
|
||||||
|
type: Object as PropType<CSSProperties>,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
||||||
|
|
@ -67,66 +67,116 @@ const defaultOptions = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSceneStore = defineStore({
|
export const useSceneStore = defineStore('scene', () => {
|
||||||
id: 'scene',
|
const data = reactive<FormModelType | any>({
|
||||||
state: (): DataType => {
|
trigger: { type: ''},
|
||||||
return {
|
options: defaultOptions,
|
||||||
data: {
|
branches: defaultBranches,
|
||||||
trigger: { type: ''},
|
description: '',
|
||||||
options: defaultOptions,
|
name: '',
|
||||||
branches: defaultBranches,
|
id: undefined
|
||||||
description: ''
|
})
|
||||||
},
|
const productCache = {}
|
||||||
productCache: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
/**
|
|
||||||
* 初始化数据
|
|
||||||
*/
|
|
||||||
initData() {
|
|
||||||
|
|
||||||
},
|
const getDetail = async (id: string) => {
|
||||||
/**
|
const resp = await detail(id)
|
||||||
* 获取详情
|
if (resp.success) {
|
||||||
* @param id
|
const result = resp.result as SceneItem
|
||||||
*/
|
const triggerType = result.triggerType
|
||||||
async getDetail(id: string) {
|
let branches: any[] = result.branches
|
||||||
const resp = await detail(id)
|
|
||||||
if (resp.success) {
|
|
||||||
const result = resp.result as SceneItem
|
|
||||||
const triggerType = result.triggerType
|
|
||||||
let branches: any[] = result.branches
|
|
||||||
|
|
||||||
if (!branches) {
|
if (!branches) {
|
||||||
branches = cloneDeep(defaultBranches)
|
branches = cloneDeep(defaultBranches)
|
||||||
if (triggerType === 'device') {
|
if (triggerType === 'device') {
|
||||||
branches.push(null)
|
branches.push(null)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const branchesLength = branches.length;
|
|
||||||
if (
|
|
||||||
triggerType === 'device' &&
|
|
||||||
((branchesLength === 1 && !!branches[0]?.when?.length) || // 有一组数据并且when有值
|
|
||||||
(branchesLength > 1 && !branches[branchesLength - 1]?.when?.length)) // 有多组否则数据,并且最后一组when有值
|
|
||||||
) {
|
|
||||||
branches.push(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
this.data = {
|
const branchesLength = branches.length;
|
||||||
...result,
|
if (
|
||||||
trigger: result.trigger || {},
|
triggerType === 'device' &&
|
||||||
branches: cloneDeep(assignmentKey(branches)),
|
((branchesLength === 1 && !!branches[0]?.when?.length) || // 有一组数据并且when有值
|
||||||
options: {...defaultOptions, ...result.options },
|
(branchesLength > 1 && !branches[branchesLength - 1]?.when?.length)) // 有多组否则数据,并且最后一组when有值
|
||||||
|
) {
|
||||||
|
branches.push(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
getProduct() {
|
|
||||||
|
|
||||||
|
Object.assign(data, {
|
||||||
|
...result,
|
||||||
|
trigger: result.trigger || {},
|
||||||
|
branches: cloneDeep(assignmentKey(branches)),
|
||||||
|
options: result.options ? {...defaultOptions, ...result.options } : defaultOptions,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
productCache,
|
||||||
|
getDetail
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//
|
||||||
|
// export const useSceneStore = defineStore({
|
||||||
|
// id: 'scene',
|
||||||
|
// state: (): DataType => {
|
||||||
|
// return {
|
||||||
|
// data: {
|
||||||
|
// trigger: { type: ''},
|
||||||
|
// options: defaultOptions,
|
||||||
|
// branches: defaultBranches,
|
||||||
|
// description: ''
|
||||||
|
// },
|
||||||
|
// productCache: {}
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// actions: {
|
||||||
|
// /**
|
||||||
|
// * 初始化数据
|
||||||
|
// */
|
||||||
|
// initData() {
|
||||||
|
//
|
||||||
|
// },
|
||||||
|
// /**
|
||||||
|
// * 获取详情
|
||||||
|
// * @param id
|
||||||
|
// */
|
||||||
|
// async getDetail(id: string) {
|
||||||
|
// const resp = await detail(id)
|
||||||
|
// if (resp.success) {
|
||||||
|
// const result = resp.result as SceneItem
|
||||||
|
// const triggerType = result.triggerType
|
||||||
|
// let branches: any[] = result.branches
|
||||||
|
//
|
||||||
|
// if (!branches) {
|
||||||
|
// branches = cloneDeep(defaultBranches)
|
||||||
|
// if (triggerType === 'device') {
|
||||||
|
// branches.push(null)
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// const branchesLength = branches.length;
|
||||||
|
// if (
|
||||||
|
// triggerType === 'device' &&
|
||||||
|
// ((branchesLength === 1 && !!branches[0]?.when?.length) || // 有一组数据并且when有值
|
||||||
|
// (branchesLength > 1 && !branches[branchesLength - 1]?.when?.length)) // 有多组否则数据,并且最后一组when有值
|
||||||
|
// ) {
|
||||||
|
// branches.push(null);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// this.data = {
|
||||||
|
// ...result,
|
||||||
|
// trigger: result.trigger || {},
|
||||||
|
// branches: cloneDeep(assignmentKey(branches)),
|
||||||
|
// options: {...defaultOptions, ...result.options },
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// getProduct() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// getters: {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import type { Slots } from 'vue'
|
import type { Slots } from 'vue'
|
||||||
import { TOKEN_KEY } from '@/utils/variable'
|
import { TOKEN_KEY } from '@/utils/variable'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 静态图片资源处理
|
* 静态图片资源处理
|
||||||
|
|
@ -95,4 +96,16 @@ export const modifySearchColumnValue = (e: any, column: object) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return e;
|
return e;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅提示一次的message
|
||||||
|
* @param msg 消息内容
|
||||||
|
* @param type 消息类型
|
||||||
|
*/
|
||||||
|
export const onlyMessage = (msg: string, type: 'success' | 'error' | 'warning' = 'success') => {
|
||||||
|
message[type]({
|
||||||
|
content: msg,
|
||||||
|
key: type
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
title='触发规则'
|
||||||
|
visible
|
||||||
|
:width='820'
|
||||||
|
@click='save'
|
||||||
|
@cancel='cancel'
|
||||||
|
>
|
||||||
|
<a-steps :current='addModel.stepNumber'>
|
||||||
|
<a-step>
|
||||||
|
<template #title>选择产品</template>
|
||||||
|
</a-step>
|
||||||
|
<a-step>
|
||||||
|
<template #title>选择设备</template>
|
||||||
|
</a-step>
|
||||||
|
<a-step>
|
||||||
|
<template #title>触发类型</template>
|
||||||
|
</a-step>
|
||||||
|
</a-steps>
|
||||||
|
<div class='steps-content'>
|
||||||
|
<Product :rowKey='addModel.productId' />
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class='steps-action'>
|
||||||
|
<template>
|
||||||
|
<a-button v-if='addModel.stepNumber === 0' @click='cancel'>取消</a-button>
|
||||||
|
<a-button v-else>上一步</a-button>
|
||||||
|
</template>
|
||||||
|
<template>
|
||||||
|
<a-button type='primary' v-if='addModel.stepNumber < 2'>下一步</a-button>
|
||||||
|
<a-button type='primary' v-else>确定</a-button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts' name='AddModel'>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { TriggerDevice } from '@/views/rule-engine/Scene/typings'
|
||||||
|
import { onlyMessage } from '@/utils/comm'
|
||||||
|
import { detail as deviceDetail } from '@/api/device/instance'
|
||||||
|
import Product from './Product.vue'
|
||||||
|
|
||||||
|
type Emit = {
|
||||||
|
(e: 'cancel'): void
|
||||||
|
(e: 'update:value', data: TriggerDevice): void
|
||||||
|
(e: 'update:options', data: any): void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddModelType extends Omit<TriggerDevice, 'selectorValues'> {
|
||||||
|
stepNumber: number
|
||||||
|
deviceKeys: Array<{ label: string, value: string }>
|
||||||
|
orgId: Array<{ label: string, value: string }>
|
||||||
|
productDetail: any
|
||||||
|
selectorValues: Array<{ label: string, value: string }>
|
||||||
|
metadata: {
|
||||||
|
properties?: any[]
|
||||||
|
functions?: any[]
|
||||||
|
events?: any[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: Object as PropType<TriggerDevice>,
|
||||||
|
default: () => ({
|
||||||
|
productId: '',
|
||||||
|
selector: 'fixed',
|
||||||
|
selectorValues: [],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const addModel = reactive<AddModelType>({
|
||||||
|
productId: '',
|
||||||
|
selector: 'fixed',
|
||||||
|
selectorValues: [],
|
||||||
|
stepNumber: 0,
|
||||||
|
deviceKeys: [],
|
||||||
|
orgId: [],
|
||||||
|
productDetail: {},
|
||||||
|
metadata: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.assign(addModel, props.value)
|
||||||
|
|
||||||
|
const handleOptions = () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancel = () => {
|
||||||
|
emit("cancel")
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMetadata = (metadata: string) => {
|
||||||
|
try {
|
||||||
|
addModel.metadata = JSON.parse(metadata)
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('handleMetadata: ' + e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const save = async () => {
|
||||||
|
if (addModel.stepNumber === 0) {
|
||||||
|
addModel.productId ? addModel.stepNumber = 1 : onlyMessage('请选择产品', 'error')
|
||||||
|
} else if (addModel.stepNumber === 1) {
|
||||||
|
const isFixed = addModel.selector === 'fixed' // 是否选择方式为设备
|
||||||
|
if ((['fixed', 'org'].includes(addModel.selector) ) && addModel.selectorValues?.length) {
|
||||||
|
return onlyMessage(isFixed ? '请选择设备' : '请选择部门', 'error')
|
||||||
|
}
|
||||||
|
// 选择方式为设备且仅选中一个设备时,物模型取该设备
|
||||||
|
if (isFixed && addModel.selectorValues?.length === 1) {
|
||||||
|
const resp = await deviceDetail(addModel.selectorValues[0].value)
|
||||||
|
addModel.metadata
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
//
|
||||||
|
}
|
||||||
|
// handleOptions()
|
||||||
|
// emit('update:value', {})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
<template>
|
||||||
|
<Search
|
||||||
|
:columns="columns"
|
||||||
|
type='simple'
|
||||||
|
@search="handleSearch"
|
||||||
|
/>
|
||||||
|
<j-table
|
||||||
|
:columns='columns'
|
||||||
|
ref='actionRef'
|
||||||
|
:request='productQuery'
|
||||||
|
:gridColumn='2'
|
||||||
|
model='CARD'
|
||||||
|
>
|
||||||
|
<template #card="slotProps">
|
||||||
|
<CardBox
|
||||||
|
:value='slotProps'
|
||||||
|
:active="selectedRowKeys.includes(slotProps.id)"
|
||||||
|
:status="slotProps.state"
|
||||||
|
:statusText="slotProps.state === 1 ? '正常' : '禁用'"
|
||||||
|
:statusNames="{ 1: 'success', 0: 'error', }"
|
||||||
|
@click="handleClick"
|
||||||
|
>
|
||||||
|
<template #img>
|
||||||
|
<slot name="img">
|
||||||
|
<img :src="getImage('/device-product.png')" />
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<h3 style="font-weight: 600" >
|
||||||
|
{{ slotProps.name }}
|
||||||
|
</h3>
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="12">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
设备类型
|
||||||
|
</div>
|
||||||
|
<div>直连设备</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
</CardBox>
|
||||||
|
</template>
|
||||||
|
</j-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts' name='Product'>
|
||||||
|
import { getProviders, queryGatewayList, queryProductList } from '@/api/device/product'
|
||||||
|
import { queryTree } from '@/api/device/category'
|
||||||
|
import { getTreeData_api } from '@/api/system/department'
|
||||||
|
import { isNoCommunity } from '@/utils/utils'
|
||||||
|
import { getImage } from '@/utils/comm'
|
||||||
|
|
||||||
|
const actionRef = ref()
|
||||||
|
const params = ref({})
|
||||||
|
const props = defineProps({
|
||||||
|
rowKey: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectedRowKeys = ref(props.rowKey)
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
width: 300,
|
||||||
|
ellipsis: true,
|
||||||
|
fixed: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
width: 200,
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '网关类型',
|
||||||
|
dataIndex: 'accessProvider',
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true,
|
||||||
|
hideInTable: true,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: () => getProviders().then((resp: any) => {
|
||||||
|
if (isNoCommunity) {
|
||||||
|
return (resp?.result || []).map((item: any) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
return (resp?.result || []).filter((item: any) => [
|
||||||
|
'mqtt-server-gateway',
|
||||||
|
'http-server-gateway',
|
||||||
|
'mqtt-client-gateway',
|
||||||
|
'tcp-server-gateway',
|
||||||
|
].includes(item.id))
|
||||||
|
.map((item: any) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '接入方式',
|
||||||
|
dataIndex: 'accessName',
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: () => queryGatewayList().then((resp: any) =>
|
||||||
|
resp.result.map((item: any) => ({
|
||||||
|
label: item.name, value: item.id
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '设备类型',
|
||||||
|
dataIndex: 'deviceType',
|
||||||
|
width: 150,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '直连设备', value: 'device' },
|
||||||
|
{ label: '网关子设备', value: 'childrenDevice' },
|
||||||
|
{ label: '网关设备', value: 'gateway' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'state',
|
||||||
|
width: '90px',
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '禁用', value: 0 },
|
||||||
|
{ label: '正常', value: 1 },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '说明',
|
||||||
|
dataIndex: 'describe',
|
||||||
|
ellipsis: true,
|
||||||
|
width: 300,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'classifiedId',
|
||||||
|
title: '分类',
|
||||||
|
hideInTable: true,
|
||||||
|
search: {
|
||||||
|
type: 'treeSelect',
|
||||||
|
options: queryTree({ paging: false }).then(resp => resp.result),
|
||||||
|
componentProps: {
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'id$dim-assets',
|
||||||
|
title: '所属组织',
|
||||||
|
hideInTable: true,
|
||||||
|
search: {
|
||||||
|
type: 'treeSelect',
|
||||||
|
options: getTreeData_api({ paging: false }).then((resp: any) => {
|
||||||
|
const formatValue = (list: any[]) => {
|
||||||
|
return list.map((item: any) => {
|
||||||
|
if (item.children) {
|
||||||
|
item.children = formatValue(item.children);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
value: JSON.stringify({
|
||||||
|
assetType: 'product',
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
type: 'org',
|
||||||
|
id: item.id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return formatValue(resp.result)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const handleSearch = (p: any) => {
|
||||||
|
params.value = p
|
||||||
|
actionRef.value.required()
|
||||||
|
}
|
||||||
|
|
||||||
|
const productQuery = (p: any) => {
|
||||||
|
const sorts: any = [];
|
||||||
|
|
||||||
|
if (props.rowKey) {
|
||||||
|
sorts.push({
|
||||||
|
name: 'id',
|
||||||
|
value: props.rowKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
sorts.push({ name: 'createTime', order: 'desc' });
|
||||||
|
p.sorts = sorts
|
||||||
|
return queryProductList(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = (detail: any) => {
|
||||||
|
const _selected = new Set(selectedRowKeys.value)
|
||||||
|
if (_selected.has(detail.id)) {
|
||||||
|
_selected.delete(detail.id)
|
||||||
|
} else {
|
||||||
|
_selected.add(detail.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<template>
|
||||||
|
<div class='device'>
|
||||||
|
<a-form-item
|
||||||
|
:rules='rules'
|
||||||
|
name='device'
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<TitleComponent data='触发规则' style='font-size: 14px;' />
|
||||||
|
</template>
|
||||||
|
<AddButton
|
||||||
|
style='width: 100%'
|
||||||
|
@click='visible = true'
|
||||||
|
>
|
||||||
|
<Title :options='data.options.trigger' />
|
||||||
|
</AddButton>
|
||||||
|
</a-form-item>
|
||||||
|
<AddModel v-if='visible' @cancel='visible = false' v-model='data.device' v-model:options='data.options.trigger' />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts' name='SceneSaveDevice'>
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useSceneStore } from '@/store/scene'
|
||||||
|
import AddModel from './AddModal.vue'
|
||||||
|
import AddButton from '../components/AddButton.vue'
|
||||||
|
import Title from '../components/Title.vue'
|
||||||
|
|
||||||
|
const sceneStore = useSceneStore()
|
||||||
|
const { data } = storeToRefs(sceneStore)
|
||||||
|
const visible = ref(false)
|
||||||
|
|
||||||
|
const rules = [{
|
||||||
|
validator(_: any, v: any) {
|
||||||
|
if (!v) {
|
||||||
|
return Promise.reject(new Error('请配置设备触发规则'));
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang='less'>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'index'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'inex'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
<template>
|
||||||
|
<div class='rule-button-warp' :style='style'>
|
||||||
|
<div class='rule-button add-button' @click='click'>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts' name='AddButton'>
|
||||||
|
import type { PropType, CSSProperties} from 'vue'
|
||||||
|
|
||||||
|
type Emit = {
|
||||||
|
(e: 'click'): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
style: {
|
||||||
|
type: Object as PropType<CSSProperties>,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const click = () => {
|
||||||
|
emit('click')
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang='less'>
|
||||||
|
.rule-button-warp {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 14px 16px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.rule-button {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
border-radius: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-button {
|
||||||
|
color: #bdbdbd;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
border-color: #d0d0d0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
<template>
|
||||||
|
<div :class='["trigger-options-content", isAdd ? "is-add" : ""]'>
|
||||||
|
<span v-if='!isAdd'> 点击配置设备触发 </span>
|
||||||
|
<template v-else>
|
||||||
|
<div class='center-item'>
|
||||||
|
<AIcon v-if='options.selectorIcon' :type='options.selectorIcon' class='icon-padding-right' />
|
||||||
|
<span class='trigger-options-name'>
|
||||||
|
<Ellipsis style='width: 310px'>
|
||||||
|
{{ options.name }}
|
||||||
|
</Ellipsis>
|
||||||
|
</span>
|
||||||
|
<span v-if='options.extraName'>{{ options.extraName }}</span>
|
||||||
|
</div>
|
||||||
|
<template v-if='options.onlyName'>
|
||||||
|
<div v-if='options.productName' class='center-item'>
|
||||||
|
<AIcon type='icon-chanpin1' class='icon-padding-right' />
|
||||||
|
<span className='trigger-options-type'>{{ options.productName }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if='options.when'>
|
||||||
|
<span className='trigger-options-when'>{{ options.when }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if='options.time'>
|
||||||
|
<span className='trigger-options-time'>{{ options.time }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if='options.extraTime'>
|
||||||
|
<span className='trigger-options-extraTime'>{{ options.extraTime }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if='options.action' class='center-item'>
|
||||||
|
<AIcon :type='options.typeIcon' class='icon-padding-right' />
|
||||||
|
<span className='trigger-options-action'>{{ options.productName }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if='options.type' class='center-item'>
|
||||||
|
<AIcon :type='options.typeIcon' class='icon-padding-right' />
|
||||||
|
<span className='trigger-options-type'>{{ options.type }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts' name='DeviceTitle'>
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const isAdd = computed(() => {
|
||||||
|
console.log(props.options, Object.keys(props.options).length)
|
||||||
|
return !!Object.keys(props.options).length
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang='less'>
|
||||||
|
.trigger-options-content {
|
||||||
|
|
||||||
|
.center-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-padding-right {
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -2,14 +2,18 @@
|
||||||
<page-container>
|
<page-container>
|
||||||
<div class='scene-warp'>
|
<div class='scene-warp'>
|
||||||
<div class='header'>
|
<div class='header'>
|
||||||
|
<Ellipsis :tooltip='data.name' style='max-width: 50%'>
|
||||||
|
<span class='title'>{{ data.name }}</span>
|
||||||
|
</Ellipsis>
|
||||||
<div class='type'>
|
<div class='type'>
|
||||||
<img :src='TriggerHeaderIcon[data.triggerType]' />
|
<img :src='TriggerHeaderIcon[data.triggerType]' />
|
||||||
{{ keyByLabel[data.triggerType] }}
|
{{ keyByLabel[data.triggerType] }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a-form ref='sceneForm' :model='data'>
|
<a-form ref='sceneForm' :model='data' :colon='false' layout='vertical'>
|
||||||
|
<Device v-if='data.triggerType === "device"' />
|
||||||
|
<Manual v-else-if='data.triggerType === "manual"' />
|
||||||
|
<Timer v-else-if='data.triggerType === "timer"' />
|
||||||
</a-form>
|
</a-form>
|
||||||
<PermissionButton
|
<PermissionButton
|
||||||
type='primary'
|
type='primary'
|
||||||
|
|
@ -17,19 +21,26 @@
|
||||||
>
|
>
|
||||||
保存
|
保存
|
||||||
</PermissionButton>
|
</PermissionButton>
|
||||||
<!-- <a-button type='primary' :loading='loading'>保存</a-button>-->
|
|
||||||
</div>
|
</div>
|
||||||
</page-container>
|
</page-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang='ts' name='Scene'>
|
<script setup lang='ts' name='Scene'>
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
import { useSceneStore } from '@/store/scene'
|
import { useSceneStore } from '@/store/scene'
|
||||||
import { TriggerHeaderIcon } from './asstes'
|
import { TriggerHeaderIcon } from './asstes'
|
||||||
import { keyByLabel } from '../typings'
|
import { keyByLabel } from '../typings'
|
||||||
|
import Device from './Device/index.vue'
|
||||||
|
import Manual from './Manual/index.vue'
|
||||||
|
import Timer from './Timer/index.vue'
|
||||||
|
|
||||||
|
const sceneStore = useSceneStore()
|
||||||
|
const { data } = storeToRefs(sceneStore)
|
||||||
|
const { getDetail } = sceneStore
|
||||||
|
|
||||||
const { getDetail, data } = useSceneStore()
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
console.log('data',data)
|
||||||
|
|
||||||
getDetail(route.query.id as string)
|
getDetail(route.query.id as string)
|
||||||
|
|
||||||
|
|
@ -45,17 +56,24 @@ getDetail(route.query.id as string)
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
.title {
|
||||||
|
font-size: 20px;
|
||||||
|
color: rgba(#000, .8);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
.type {
|
.type {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 100px;
|
min-width: 80px;
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
color: rgba(0, 0, 0, 0.65);
|
color: rgba(0, 0, 0, 0.65);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
|
img {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,8 @@ export default defineConfig(({ mode}) => {
|
||||||
// target: 'http://192.168.32.244:8881',
|
// target: 'http://192.168.32.244:8881',
|
||||||
// target: 'http://47.112.135.104:5096', // opcua
|
// target: 'http://47.112.135.104:5096', // opcua
|
||||||
// target: 'http://120.77.179.54:8844', // 120测试
|
// target: 'http://120.77.179.54:8844', // 120测试
|
||||||
target: 'http://47.108.63.174:8845', // 测试
|
// target: 'http://47.108.63.174:8845', // 测试
|
||||||
// target: 'http://120.77.179.54:8844',
|
target: 'http://120.77.179.54:8844',
|
||||||
ws: 'ws://120.77.179.54:8844',
|
ws: 'ws://120.77.179.54:8844',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/api/, '')
|
rewrite: (path) => path.replace(/^\/api/, '')
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue