feat: 新增场景联动-触发规则
This commit is contained in:
parent
7d0fbc0e1c
commit
be501e77fe
|
@ -98,7 +98,11 @@ const props = defineProps({
|
||||||
class: {
|
class: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
}
|
},
|
||||||
|
// defaultTerms: {
|
||||||
|
// type: Object,
|
||||||
|
// default: () => ({})
|
||||||
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
const searchRef = ref(null)
|
const searchRef = ref(null)
|
||||||
|
@ -223,6 +227,7 @@ const handleParamsFormat = () => {
|
||||||
*/
|
*/
|
||||||
const searchSubmit = () => {
|
const searchSubmit = () => {
|
||||||
emit('search', handleParamsFormat())
|
emit('search', handleParamsFormat())
|
||||||
|
console.log('searchSubmit')
|
||||||
if (props.type === 'advanced') {
|
if (props.type === 'advanced') {
|
||||||
addUrlParams()
|
addUrlParams()
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,10 @@ const JTable = defineComponent<JTableProps>({
|
||||||
pageSize: 12
|
pageSize: 12
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
scroll: {
|
||||||
|
type: Object,
|
||||||
|
default: () => { x: 1366 }
|
||||||
}
|
}
|
||||||
} as any,
|
} as any,
|
||||||
setup(props: JTableProps, { slots, emit, expose }) {
|
setup(props: JTableProps, { slots, emit, expose }) {
|
||||||
|
@ -331,7 +335,7 @@ const JTable = defineComponent<JTableProps>({
|
||||||
pagination={false}
|
pagination={false}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
rowSelection={props.rowSelection}
|
rowSelection={props.rowSelection}
|
||||||
scroll={{ x: 1366 }}
|
scroll={props.scroll}
|
||||||
v-slots={{
|
v-slots={{
|
||||||
bodyCell: (dt: Record<string, any>) => {
|
bodyCell: (dt: Record<string, any>) => {
|
||||||
const { column, record } = dt;
|
const { column, record } = dt;
|
||||||
|
|
|
@ -68,7 +68,7 @@ const defaultOptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSceneStore = defineStore('scene', () => {
|
export const useSceneStore = defineStore('scene', () => {
|
||||||
const data = reactive<FormModelType | any>({
|
const data = reactive<FormModelType>({
|
||||||
trigger: { type: ''},
|
trigger: { type: ''},
|
||||||
options: defaultOptions,
|
options: defaultOptions,
|
||||||
branches: defaultBranches,
|
branches: defaultBranches,
|
||||||
|
@ -116,67 +116,3 @@ export const useSceneStore = defineStore('scene', () => {
|
||||||
getDetail
|
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: {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// })
|
|
|
@ -7,4 +7,12 @@ export const isUrl = (path: string): boolean => urlReg.test(path)
|
||||||
|
|
||||||
export const inputReg = /^[a-zA-Z0-9_\-]+$/
|
export const inputReg = /^[a-zA-Z0-9_\-]+$/
|
||||||
|
|
||||||
export const isInput = (value: string) => inputReg.test(value)
|
export const isInput = (value: string) => inputReg.test(value)
|
||||||
|
|
||||||
|
// cron 表达式
|
||||||
|
|
||||||
|
export const CronRegEx = new RegExp(
|
||||||
|
'^\\s*($|#|\\w+\\s*=|(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?(?:,(?:[0-5]?\\d)(?:(?:-|\\/|\\,)(?:[0-5]?\\d))?)*)\\s+(\\?|\\*|(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?(?:,(?:[01]?\\d|2[0-3])(?:(?:-|\\/|\\,)(?:[01]?\\d|2[0-3]))?)*)\\s+(\\?|\\*|(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?(?:,(?:0?[1-9]|[12]\\d|3[01])(?:(?:-|\\/|\\,)(?:0?[1-9]|[12]\\d|3[01]))?)*)\\s+(\\?|\\*|(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?(?:,(?:[1-9]|1[012])(?:(?:-|\\/|\\,)(?:[1-9]|1[012]))?(?:L|W)?)*|\\?|\\*|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*)\\s+(\\?|\\*|(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?(?:,(?:[0-6])(?:(?:-|\\/|\\,|#)(?:[0-6]))?(?:L)?)*|\\?|\\*|(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?(?:,(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?)*)(|\\s)+(\\?|\\*|(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?(?:,(?:|\\d{4})(?:(?:-|\\/|\\,)(?:|\\d{4}))?)*))$',
|
||||||
|
);
|
||||||
|
|
||||||
|
export const isCron = (value: string) => CronRegEx.test(value)
|
|
@ -6,7 +6,7 @@
|
||||||
@click='save'
|
@click='save'
|
||||||
@cancel='cancel'
|
@cancel='cancel'
|
||||||
>
|
>
|
||||||
<a-steps :current='addModel.stepNumber'>
|
<a-steps :current='addModel.stepNumber' @change='stepChange'>
|
||||||
<a-step>
|
<a-step>
|
||||||
<template #title>选择产品</template>
|
<template #title>选择产品</template>
|
||||||
</a-step>
|
</a-step>
|
||||||
|
@ -17,19 +17,28 @@
|
||||||
<template #title>触发类型</template>
|
<template #title>触发类型</template>
|
||||||
</a-step>
|
</a-step>
|
||||||
</a-steps>
|
</a-steps>
|
||||||
|
<a-divider style='margin-bottom: 0px' />
|
||||||
<div class='steps-content'>
|
<div class='steps-content'>
|
||||||
<Product :rowKey='addModel.productId' />
|
<Product v-if='addModel.stepNumber === 0' v-model:rowKey='addModel.productId' v-model:detail='addModel.productDetail' />
|
||||||
|
<DeviceSelect
|
||||||
|
v-else-if='addModel.stepNumber === 1'
|
||||||
|
:productId='addModel.productId'
|
||||||
|
v-model:deviceKeys='addModel.deviceKeys'
|
||||||
|
v-model:orgId='addModel.orgId'
|
||||||
|
v-model:selector='addModel.selector'
|
||||||
|
v-model:selectorValues='addModel.selectorValues'
|
||||||
|
/>
|
||||||
|
<Type
|
||||||
|
v-else-if='addModel.stepNumber === 2'
|
||||||
|
:metadata='addModel.metadata'
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class='steps-action'>
|
<div class='steps-action'>
|
||||||
<template>
|
<a-button v-if='addModel.stepNumber === 0' @click='cancel'>取消</a-button>
|
||||||
<a-button v-if='addModel.stepNumber === 0' @click='cancel'>取消</a-button>
|
<a-button v-else @click='prev'>上一步</a-button>
|
||||||
<a-button v-else>上一步</a-button>
|
<a-button type='primary' v-if='addModel.stepNumber < 2' @click='saveClick'>下一步</a-button>
|
||||||
</template>
|
<a-button type='primary' v-else @click='saveClick'>确定</a-button>
|
||||||
<template>
|
|
||||||
<a-button type='primary' v-if='addModel.stepNumber < 2'>下一步</a-button>
|
|
||||||
<a-button type='primary' v-else>确定</a-button>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
@ -37,10 +46,12 @@
|
||||||
|
|
||||||
<script setup lang='ts' name='AddModel'>
|
<script setup lang='ts' name='AddModel'>
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import { TriggerDevice } from '@/views/rule-engine/Scene/typings'
|
import type { metadataType, TriggerDevice } from '@/views/rule-engine/Scene/typings'
|
||||||
import { onlyMessage } from '@/utils/comm'
|
import { onlyMessage } from '@/utils/comm'
|
||||||
import { detail as deviceDetail } from '@/api/device/instance'
|
import { detail as deviceDetail } from '@/api/device/instance'
|
||||||
import Product from './Product.vue'
|
import Product from './Product.vue'
|
||||||
|
import DeviceSelect from './DeviceSelect.vue'
|
||||||
|
import Type from './Type.vue'
|
||||||
|
|
||||||
type Emit = {
|
type Emit = {
|
||||||
(e: 'cancel'): void
|
(e: 'cancel'): void
|
||||||
|
@ -54,11 +65,7 @@ interface AddModelType extends Omit<TriggerDevice, 'selectorValues'> {
|
||||||
orgId: Array<{ label: string, value: string }>
|
orgId: Array<{ label: string, value: string }>
|
||||||
productDetail: any
|
productDetail: any
|
||||||
selectorValues: Array<{ label: string, value: string }>
|
selectorValues: Array<{ label: string, value: string }>
|
||||||
metadata: {
|
metadata: metadataType
|
||||||
properties?: any[]
|
|
||||||
functions?: any[]
|
|
||||||
events?: any[]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits<Emit>()
|
const emit = defineEmits<Emit>()
|
||||||
|
@ -97,39 +104,56 @@ const handleOptions = () => {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const prev = () => {
|
||||||
|
addModel.stepNumber = addModel.stepNumber - 1
|
||||||
|
}
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
emit("cancel")
|
emit("cancel")
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMetadata = (metadata: string) => {
|
const handleMetadata = (metadata?: string) => {
|
||||||
try {
|
try {
|
||||||
addModel.metadata = JSON.parse(metadata)
|
addModel.metadata = JSON.parse(metadata || "{}")
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('handleMetadata: ' + e)
|
console.warn('handleMetadata: ' + e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const save = async () => {
|
const save = async (step?: number) => {
|
||||||
if (addModel.stepNumber === 0) {
|
let _step = step !== undefined ? step : addModel.stepNumber
|
||||||
|
if (_step === 0) {
|
||||||
addModel.productId ? addModel.stepNumber = 1 : onlyMessage('请选择产品', 'error')
|
addModel.productId ? addModel.stepNumber = 1 : onlyMessage('请选择产品', 'error')
|
||||||
} else if (addModel.stepNumber === 1) {
|
} else if (_step === 1) {
|
||||||
const isFixed = addModel.selector === 'fixed' // 是否选择方式为设备
|
const isFixed = addModel.selector === 'fixed' // 是否选择方式为设备
|
||||||
if ((['fixed', 'org'].includes(addModel.selector) ) && addModel.selectorValues?.length) {
|
if ((['fixed', 'org'].includes(addModel.selector) ) && !addModel.selectorValues?.length) {
|
||||||
return onlyMessage(isFixed ? '请选择设备' : '请选择部门', 'error')
|
return onlyMessage(isFixed ? '请选择设备' : '请选择部门', 'error')
|
||||||
}
|
}
|
||||||
// 选择方式为设备且仅选中一个设备时,物模型取该设备
|
// 选择方式为设备且仅选中一个设备时,物模型取该设备
|
||||||
if (isFixed && addModel.selectorValues?.length === 1) {
|
if (isFixed && addModel.selectorValues?.length === 1) {
|
||||||
const resp = await deviceDetail(addModel.selectorValues[0].value)
|
const resp = await deviceDetail(addModel.selectorValues[0].value)
|
||||||
addModel.metadata
|
handleMetadata(resp.result.metadata)
|
||||||
} else {
|
} else {
|
||||||
|
handleMetadata(addModel.productDetail?.metadata)
|
||||||
}
|
}
|
||||||
//
|
addModel.stepNumber = 2
|
||||||
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
// handleOptions()
|
// handleOptions()
|
||||||
// emit('update:value', {})
|
// emit('update:value', {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const saveClick = () => save()
|
||||||
|
|
||||||
|
const stepChange = (step: number) => {
|
||||||
|
if (step !== 0) {
|
||||||
|
save(step - 1)
|
||||||
|
} else {
|
||||||
|
addModel.stepNumber = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
<template>
|
||||||
|
<Search
|
||||||
|
:columns="columns"
|
||||||
|
type='simple'
|
||||||
|
@search="handleSearch"
|
||||||
|
class='search'
|
||||||
|
target="scene-triggrt-device-device"
|
||||||
|
/>
|
||||||
|
<a-divider style='margin: 0' />
|
||||||
|
<j-table
|
||||||
|
ref='actionRef'
|
||||||
|
model='CARD'
|
||||||
|
:columns='columns'
|
||||||
|
:request='deviceQuery'
|
||||||
|
:gridColumn='2'
|
||||||
|
:params='params'
|
||||||
|
:bodyStyle='{
|
||||||
|
paddingRight: 0,
|
||||||
|
paddingLeft: 0
|
||||||
|
}'
|
||||||
|
>
|
||||||
|
<template #card="slotProps">
|
||||||
|
<CardBox
|
||||||
|
:value='slotProps'
|
||||||
|
:active="deviceRowKeys.includes(slotProps.id)"
|
||||||
|
:status="slotProps.state?.value"
|
||||||
|
:statusText="slotProps.state?.text"
|
||||||
|
:statusNames="{
|
||||||
|
online: 'success',
|
||||||
|
offline: 'error',
|
||||||
|
notActive: 'warning',
|
||||||
|
}"
|
||||||
|
@click="handleClick"
|
||||||
|
>
|
||||||
|
<template #img>
|
||||||
|
<slot name="img">
|
||||||
|
<img width='88' height='88' :src="slotProps.photoUrl || getImage('/device/instance/device-card.png')" />
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<Ellipsis style='width: calc(100% - 100px)'>
|
||||||
|
<span style="font-size: 16px;font-weight: 600" >
|
||||||
|
{{ slotProps.name }}
|
||||||
|
</span>
|
||||||
|
</Ellipsis>
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="12">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
设备类型
|
||||||
|
</div>
|
||||||
|
<div>{{ slotProps.deviceType?.text }}</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
产品名称
|
||||||
|
</div>
|
||||||
|
<div>{{ slotProps.productName }}</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
</CardBox>
|
||||||
|
</template>
|
||||||
|
</j-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts' name='DeviceSelectList'>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { getImage } from '@/utils/comm'
|
||||||
|
import { query } from '@/api/device/instance'
|
||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
|
type Emit = {
|
||||||
|
(e: 'update', data: Array<{ name: string, value: string}>): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionRef = ref()
|
||||||
|
const params = ref({})
|
||||||
|
const context = inject('SceneDeviceAddModel')
|
||||||
|
const props = defineProps({
|
||||||
|
rowKeys: {
|
||||||
|
type: Array as PropType<Array<{ name: string, value: string}>>,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
productId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const deviceRowKeys = computed(() => {
|
||||||
|
return props.rowKeys.map(item => item.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
width: 300,
|
||||||
|
ellipsis: true,
|
||||||
|
fixed: 'left',
|
||||||
|
search: {
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '设备名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
width: 200,
|
||||||
|
ellipsis: true,
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
first: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
width: 200,
|
||||||
|
search: {
|
||||||
|
type: 'date'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'state',
|
||||||
|
width: 90,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '禁用', value: 'notActive' },
|
||||||
|
{ label: '离线', value: 'offline' },
|
||||||
|
{ label: '在线', value: 'online' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
const handleSearch = (p: any) => {
|
||||||
|
params.value = p
|
||||||
|
}
|
||||||
|
|
||||||
|
const deviceQuery = (p: any) => {
|
||||||
|
const sorts: any = [];
|
||||||
|
|
||||||
|
if (props.rowKeys) {
|
||||||
|
props.rowKeys.forEach(rowKey => {
|
||||||
|
sorts.push({
|
||||||
|
name: 'id',
|
||||||
|
value: rowKey,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sorts.push({ name: 'createTime', order: 'desc' });
|
||||||
|
const terms = [
|
||||||
|
...p.terms,
|
||||||
|
{ terms: [{ column: "productId", value: props.productId }]}
|
||||||
|
]
|
||||||
|
return query({ ...p, terms, sorts })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = (detail: any) => {
|
||||||
|
const cloneRowKeys = cloneDeep(props.rowKeys)
|
||||||
|
const indexOf = cloneRowKeys.findIndex(item => item.value === detail.id)
|
||||||
|
if (indexOf !== -1) {
|
||||||
|
cloneRowKeys.splice(indexOf, 1)
|
||||||
|
} else {
|
||||||
|
cloneRowKeys.push({
|
||||||
|
name: detail.name,
|
||||||
|
value: detail.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
console.log('cloneRowKeys', cloneRowKeys)
|
||||||
|
emit('update', cloneRowKeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-right: 0px;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,83 @@
|
||||||
|
<template>
|
||||||
|
<div class='device-select'>
|
||||||
|
<TopCard :options='typeList' v-model:value='selectorModel' @select='select' />
|
||||||
|
<DeviceList v-if='selectorModel === "fixed"' :productId='productId' :row-keys='devices' @update='updateDevice' />
|
||||||
|
<OrgList v-else-if='selectorModel === "org"' :productId='productId' :row-keys='orgIds' @update='updateOrg' />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts'>
|
||||||
|
import TopCard from '@/views/rule-engine/Scene/Save/components/TopCard.vue'
|
||||||
|
import DeviceList from './DeviceList.vue'
|
||||||
|
import OrgList from './OrgList.vue'
|
||||||
|
import { getImage } from '@/utils/comm'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
|
||||||
|
type ItemType = {
|
||||||
|
name: string,
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Emit = {
|
||||||
|
(e: 'update:selector', data: string): void
|
||||||
|
(e: 'update:selectorValues', data: ItemType[]): void
|
||||||
|
(e: 'update:deviceKeys', data: ItemType[]): void
|
||||||
|
(e: 'update:orgId', data: ItemType[]): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
productId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
device: {
|
||||||
|
type: Array as PropType<ItemType[]>,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
orgId: {
|
||||||
|
type: Array as PropType<ItemType[]>,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectorModel = ref(props.selector)
|
||||||
|
const devices = ref(props.device)
|
||||||
|
const orgIds = ref(props.orgId)
|
||||||
|
|
||||||
|
const typeList = [
|
||||||
|
{ label: '自定义', value: 'fixed', tip: '自定义选择当前产品下的任意设备', img: getImage('/scene/device-custom.png')},
|
||||||
|
{ label: '全部', value: 'all', tip: '产品下的所有设备', img: getImage('/scene/trigger-device-all.png')},
|
||||||
|
{ label: '按组织', value: 'org', tip: '选择产品下归属于具体组织的设备', img: getImage('/scene/trigger-device-org.png')},
|
||||||
|
]
|
||||||
|
|
||||||
|
const select = (s: string) => {
|
||||||
|
selectorModel.value = s
|
||||||
|
emit('update:selector', s)
|
||||||
|
emit('update:selectorValues', [])
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateDevice = (d: any[]) => {
|
||||||
|
devices.value = d
|
||||||
|
emit('update:deviceKeys', d)
|
||||||
|
emit('update:selectorValues', d)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateOrg = (d: any[]) => {
|
||||||
|
orgIds.value = d
|
||||||
|
emit('update:orgId', d)
|
||||||
|
emit('update:selectorValues', d)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang='less'>
|
||||||
|
.device-select{
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,130 @@
|
||||||
|
<template>
|
||||||
|
<Search
|
||||||
|
:columns="columns"
|
||||||
|
type='simple'
|
||||||
|
@search="handleSearch"
|
||||||
|
class='search'
|
||||||
|
target="scene-triggrt-device-category"
|
||||||
|
/>
|
||||||
|
<a-divider style='margin: 0' />
|
||||||
|
<JTable
|
||||||
|
ref="instanceRef"
|
||||||
|
model='TABLE'
|
||||||
|
type='TREE'
|
||||||
|
:columns="columns"
|
||||||
|
:request="query"
|
||||||
|
:scroll="{
|
||||||
|
y: 350
|
||||||
|
}"
|
||||||
|
:expandable='{
|
||||||
|
expandedRowKeys: openKeys,
|
||||||
|
onExpandedRowsChange: expandedRowChange,
|
||||||
|
}'
|
||||||
|
:rowSelection='{
|
||||||
|
type: "radio",
|
||||||
|
selectedRowKeys: orgRowKeys,
|
||||||
|
onChange: selectedRowChange
|
||||||
|
}'
|
||||||
|
:onChange='tableChange'
|
||||||
|
>
|
||||||
|
|
||||||
|
</JTable>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts' name='OrgList'>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { getExpandedRowById } from './util'
|
||||||
|
import { getTreeData_api } from '@/api/system/department'
|
||||||
|
|
||||||
|
type Emit = {
|
||||||
|
(e: 'update', data: Array<{ name: string, value: string}>): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
rowKeys: {
|
||||||
|
type: Array as PropType<Array<{ name: string, value: string}>>,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
productId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const params = ref()
|
||||||
|
const openKeys = ref<string[]>([])
|
||||||
|
const selectedRowKeys = ref(props.rowKeys.map(item => item.value))
|
||||||
|
const sortParam = ref<{ name:string, order: string }>({ name: 'sortIndex', order: 'asc' })
|
||||||
|
const iniPage = ref(true)
|
||||||
|
|
||||||
|
const orgRowKeys = computed(() => {
|
||||||
|
return props.rowKeys.map(item => item.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
width: 300,
|
||||||
|
ellipsis: true,
|
||||||
|
dataIndex: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '排序',
|
||||||
|
dataIndex: 'sortIndex',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const handleSearch = (p: any) => {
|
||||||
|
params.value = p
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableChange = (_: any, f: any, sorter: any) => {
|
||||||
|
if (sorter.order) {
|
||||||
|
sortParam.value = { name: sorter.columnKey, order: (sorter.order as string).replace('end', ''), }
|
||||||
|
} else {
|
||||||
|
sortParam.value = { name: 'sortIndex', order: 'asc' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = async (p: any) => {
|
||||||
|
const _params: any = {
|
||||||
|
paging: false,
|
||||||
|
sorts: [sortParam.value],
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.terms && p.terms.length) {
|
||||||
|
_params.terms = p.terms
|
||||||
|
}
|
||||||
|
|
||||||
|
const resp = await getTreeData_api(_params)
|
||||||
|
|
||||||
|
if (iniPage.value && props.rowKeys.length) {
|
||||||
|
iniPage.value = false
|
||||||
|
openKeys.value = getExpandedRowById(props.rowKeys[0]?.value, resp.result as any[])
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedRowChange = (_: any, selectedRows: any[]) => {
|
||||||
|
const item = selectedRows[0]
|
||||||
|
console.log(selectedRows)
|
||||||
|
emit('update', item ? [{ name: item.name, value: item.id }] : [])
|
||||||
|
}
|
||||||
|
|
||||||
|
const expandedRowChange = (keys: string[]) => {
|
||||||
|
openKeys.value = keys
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-right: 0px;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -4,18 +4,25 @@
|
||||||
type='simple'
|
type='simple'
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
class='search'
|
class='search'
|
||||||
|
target="scene-triggrt-device-device"
|
||||||
/>
|
/>
|
||||||
|
<a-divider style='margin: 0' />
|
||||||
<j-table
|
<j-table
|
||||||
:columns='columns'
|
|
||||||
ref='actionRef'
|
ref='actionRef'
|
||||||
|
model='CARD'
|
||||||
|
:columns='columns'
|
||||||
|
:params='params'
|
||||||
:request='productQuery'
|
:request='productQuery'
|
||||||
:gridColumn='2'
|
:gridColumn='2'
|
||||||
model='CARD'
|
:bodyStyle='{
|
||||||
|
paddingRight: 0,
|
||||||
|
paddingLeft: 0
|
||||||
|
}'
|
||||||
>
|
>
|
||||||
<template #card="slotProps">
|
<template #card="slotProps">
|
||||||
<CardBox
|
<CardBox
|
||||||
:value='slotProps'
|
:value='slotProps'
|
||||||
:active="selectedRowKeys.includes(slotProps.id)"
|
:active="rowKey === slotProps.id"
|
||||||
:status="slotProps.state"
|
:status="slotProps.state"
|
||||||
:statusText="slotProps.state === 1 ? '正常' : '禁用'"
|
:statusText="slotProps.state === 1 ? '正常' : '禁用'"
|
||||||
:statusNames="{ 1: 'success', 0: 'error', }"
|
:statusNames="{ 1: 'success', 0: 'error', }"
|
||||||
|
@ -23,13 +30,17 @@
|
||||||
>
|
>
|
||||||
<template #img>
|
<template #img>
|
||||||
<slot name="img">
|
<slot name="img">
|
||||||
<img :src="getImage('/device-product.png')" />
|
<img width='88' height='88' :src="slotProps.photoUrl || getImage('/device-product.png')" />
|
||||||
</slot>
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<h3 style="font-weight: 600" >
|
<div style='width: calc(100% - 100px)'>
|
||||||
{{ slotProps.name }}
|
<Ellipsis>
|
||||||
</h3>
|
<span style="font-size: 16px;font-weight: 600" >
|
||||||
|
{{ slotProps.name }}
|
||||||
|
</span>
|
||||||
|
</Ellipsis>
|
||||||
|
</div>
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<div class="card-item-content-text">
|
<div class="card-item-content-text">
|
||||||
|
@ -51,16 +62,25 @@ import { getTreeData_api } from '@/api/system/department'
|
||||||
import { isNoCommunity } from '@/utils/utils'
|
import { isNoCommunity } from '@/utils/utils'
|
||||||
import { getImage } from '@/utils/comm'
|
import { getImage } from '@/utils/comm'
|
||||||
|
|
||||||
|
type Emit = {
|
||||||
|
(e: 'update:rowKey', data: string): void
|
||||||
|
(e: 'update:detail', data: string): void
|
||||||
|
}
|
||||||
|
|
||||||
const actionRef = ref()
|
const actionRef = ref()
|
||||||
const params = ref({})
|
const params = ref({})
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
rowKey: {
|
rowKey: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
|
},
|
||||||
|
detail: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectedRowKeys = ref(props.rowKey)
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
@ -69,12 +89,19 @@ const columns = [
|
||||||
width: 300,
|
width: 300,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
fixed: 'left',
|
fixed: 'left',
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
width: 200,
|
width: 200,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
first: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '网关类型',
|
title: '网关类型',
|
||||||
|
@ -199,7 +226,6 @@ const columns = [
|
||||||
|
|
||||||
const handleSearch = (p: any) => {
|
const handleSearch = (p: any) => {
|
||||||
params.value = p
|
params.value = p
|
||||||
actionRef.value.required()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const productQuery = (p: any) => {
|
const productQuery = (p: any) => {
|
||||||
|
@ -217,12 +243,8 @@ const productQuery = (p: any) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleClick = (detail: any) => {
|
const handleClick = (detail: any) => {
|
||||||
const _selected = new Set(selectedRowKeys.value)
|
emit('update:rowKey', detail.id)
|
||||||
if (_selected.has(detail.id)) {
|
emit('update:detail', detail)
|
||||||
_selected.delete(detail.id)
|
|
||||||
} else {
|
|
||||||
_selected.add(detail.id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -230,5 +252,7 @@ const handleClick = (detail: any) => {
|
||||||
<style scoped lang='less'>
|
<style scoped lang='less'>
|
||||||
.search {
|
.search {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
padding-right: 0px;
|
||||||
|
padding-left: 0px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -0,0 +1,100 @@
|
||||||
|
<template>
|
||||||
|
<div class='type'>
|
||||||
|
<a-form ref='typeForm' :model='formModel' layout='vertical' :colon='false'>
|
||||||
|
<a-form-item
|
||||||
|
required
|
||||||
|
label='触发类型'
|
||||||
|
>
|
||||||
|
<TopCard
|
||||||
|
:label-bottom='true'
|
||||||
|
:options='options'
|
||||||
|
v-model:value='formModel.operator'
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<Timer v-if='showTimer' />
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts'>
|
||||||
|
|
||||||
|
import TopCard from '@/views/rule-engine/Scene/Save/components/TopCard.vue'
|
||||||
|
import { getImage } from '@/utils/comm'
|
||||||
|
import { metadataType } from '@/views/rule-engine/Scene/typings'
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { TypeEnum } from '@/views/rule-engine/Scene/Save/Device/util'
|
||||||
|
import Timer from '../components/Timer.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
metadata: {
|
||||||
|
type: Object as PropType<metadataType>,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const formModel = reactive({
|
||||||
|
operator: 'online',
|
||||||
|
})
|
||||||
|
|
||||||
|
const readProperties = ref<any[]>([])
|
||||||
|
const writeProperties = ref<any[]>([])
|
||||||
|
|
||||||
|
const options = computed(() => {
|
||||||
|
const baseOptions = [
|
||||||
|
{
|
||||||
|
label: '设备上线',
|
||||||
|
value: 'online',
|
||||||
|
img: getImage('/scene/online.png'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '设备离线',
|
||||||
|
value: 'offline',
|
||||||
|
img: getImage('/scene/offline.png'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
if (props.metadata.events?.length) {
|
||||||
|
baseOptions.push(TypeEnum.reportEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.metadata.properties?.length) {
|
||||||
|
const _properties = props.metadata.properties
|
||||||
|
readProperties.value = _properties.filter((item: any) => item.expands.type?.includes('read'))
|
||||||
|
writeProperties.value = _properties.filter((item: any) => item.expands.type?.includes('write'))
|
||||||
|
const reportProperties = _properties.filter((item: any) => item.expands.type?.includes('report'))
|
||||||
|
|
||||||
|
if (readProperties.value.length) {
|
||||||
|
baseOptions.push(TypeEnum.readProperty)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writeProperties.value.length) {
|
||||||
|
baseOptions.push(TypeEnum.writeProperty)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reportProperties.length) {
|
||||||
|
baseOptions.push(TypeEnum.reportProperty)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.metadata.functions?.length) {
|
||||||
|
baseOptions.push(TypeEnum.invokeFunction)
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseOptions
|
||||||
|
})
|
||||||
|
|
||||||
|
const showTimer = computed(() => {
|
||||||
|
return ['readProperty', 'writeProperty', 'invokeFunction'].includes(formModel.operator)
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang='less'>
|
||||||
|
.type {
|
||||||
|
max-height: calc(100vh - 350px);
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -26,7 +26,8 @@ import AddButton from '../components/AddButton.vue'
|
||||||
import Title from '../components/Title.vue'
|
import Title from '../components/Title.vue'
|
||||||
|
|
||||||
const sceneStore = useSceneStore()
|
const sceneStore = useSceneStore()
|
||||||
const { data } = storeToRefs(sceneStore)
|
const { data } = storeToRefs<any>(sceneStore)
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
|
|
||||||
const rules = [{
|
const rules = [{
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
import { getImage } from '@/utils/comm'
|
||||||
|
|
||||||
|
export const TypeName = {
|
||||||
|
online: '设备上线',
|
||||||
|
offline: '设备离线',
|
||||||
|
reportEvent: '事件上报',
|
||||||
|
reportProperty: '属性上报',
|
||||||
|
readProperty: '读取属性',
|
||||||
|
writeProperty: '修改属性',
|
||||||
|
invokeFunction: '功能调用',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TypeEnum = {
|
||||||
|
reportProperty: {
|
||||||
|
label: '属性上报',
|
||||||
|
value: 'reportProperty',
|
||||||
|
img: getImage('/scene/reportProperty.png'),
|
||||||
|
},
|
||||||
|
reportEvent: {
|
||||||
|
label: '事件上报',
|
||||||
|
value: 'reportEvent',
|
||||||
|
img: getImage('/scene/reportProperty.png'),
|
||||||
|
},
|
||||||
|
readProperty: {
|
||||||
|
label: '读取属性',
|
||||||
|
value: 'readProperty',
|
||||||
|
img: getImage('/scene/readProperty.png'),
|
||||||
|
},
|
||||||
|
writeProperty: {
|
||||||
|
label: '修改属性',
|
||||||
|
value: 'writeProperty',
|
||||||
|
img: getImage('/scene/writeProperty.png'),
|
||||||
|
},
|
||||||
|
invokeFunction: {
|
||||||
|
label: '功能调用',
|
||||||
|
value: 'invokeFunction',
|
||||||
|
img: getImage('/scene/invokeFunction.png'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getExpandedRowById = (id: string, data: any[]): string[] => {
|
||||||
|
const expandedKeys:string[] = []
|
||||||
|
const dataMap = new Map()
|
||||||
|
|
||||||
|
const flatMapData = (flatData: any[]) => {
|
||||||
|
flatData.forEach(item => {
|
||||||
|
dataMap.set(item.id, { pid: item.parentId })
|
||||||
|
if (item.children && item.children.length) {
|
||||||
|
flatMapData(item.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getExp = (_id: string) => {
|
||||||
|
const item = dataMap.get(_id)
|
||||||
|
if (item) {
|
||||||
|
expandedKeys.push(_id)
|
||||||
|
if (dataMap.has(dataMap)) {
|
||||||
|
getExp(item.pid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flatMapData(data)
|
||||||
|
|
||||||
|
getExp(id)
|
||||||
|
|
||||||
|
return expandedKeys
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
<template>
|
||||||
|
<a-form
|
||||||
|
ref='timerForm'
|
||||||
|
:model='formModel'
|
||||||
|
layout='vertical'
|
||||||
|
:colon='false'
|
||||||
|
>
|
||||||
|
<a-form-item name='trigger'>
|
||||||
|
<a-radio-group
|
||||||
|
v-model:value='formModel.trigger'
|
||||||
|
:options='[
|
||||||
|
{ label: "按周", value: "week" },
|
||||||
|
{ label: "按月", value: "month" },
|
||||||
|
{ label: "cron表达式", value: "cron" },
|
||||||
|
]'
|
||||||
|
option-type='button'
|
||||||
|
button-style='solid'
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if='showCron' name='cron'>
|
||||||
|
<a-input placeholder='corn表达式' v-model='formModel.cron' />
|
||||||
|
</a-form-item>
|
||||||
|
<template v-else>
|
||||||
|
<a-form-item name='when'>
|
||||||
|
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item name='mod'>
|
||||||
|
<a-radio-group
|
||||||
|
v-model:value='formModel.mod'
|
||||||
|
:options='[
|
||||||
|
{ label: "周期执行", value: "period" },
|
||||||
|
{ label: "执行一次", value: "once" },
|
||||||
|
]'
|
||||||
|
option-type='button'
|
||||||
|
button-style='solid'
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</template>
|
||||||
|
<a-space v-if='showOnce' style='display: flex;gap: 24px'>
|
||||||
|
<a-form-item :name="['once', 'time']">
|
||||||
|
<a-time-picker valueFormat='HH:mm:ss' v-model:value='formModel.once.time' style='width: 100%' format='HH:mm:ss' />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item> 执行一次 </a-form-item>
|
||||||
|
</a-space>
|
||||||
|
<a-space v-if='showPeriod' style='display: flex;gap: 24px'>
|
||||||
|
<a-form-item>
|
||||||
|
<a-time-range-picker
|
||||||
|
valueFormat='HH:mm:ss'
|
||||||
|
:value='[
|
||||||
|
formModel.period.from,
|
||||||
|
formModel.period.to,
|
||||||
|
]'
|
||||||
|
@change='(v) => {
|
||||||
|
formModel.period.from = v[0]
|
||||||
|
formModel.period.to = v[1]
|
||||||
|
}'
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>每</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:name='["period", "every"]'
|
||||||
|
:rules='[{ required: true, message: "请输入时间" }]'
|
||||||
|
>
|
||||||
|
<a-input-number
|
||||||
|
placeholder='请输入时间'
|
||||||
|
style='max-width: 170px'
|
||||||
|
:precision='0'
|
||||||
|
:min='1'
|
||||||
|
:max='59'
|
||||||
|
v-model:value='formModel.period.every'
|
||||||
|
>
|
||||||
|
<template #addonAfter>
|
||||||
|
<a-select
|
||||||
|
v-model:value='formModel.period.unit'
|
||||||
|
:options='[
|
||||||
|
{ label: "秒", value: "seconds" },
|
||||||
|
{ label: "分", value: "minutes" },
|
||||||
|
{ label: "小时", value: "hours" },
|
||||||
|
]'
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</a-input-number>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>执行一次</a-form-item>
|
||||||
|
</a-space>
|
||||||
|
</a-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts' name='Timer'>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
type NameType = string[] | string
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
name: {
|
||||||
|
type: [String, Array] as PropType<NameType>,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const formModel = reactive({
|
||||||
|
trigger: 'week',
|
||||||
|
when: [],
|
||||||
|
mod: 'period',
|
||||||
|
cron: undefined,
|
||||||
|
once: {
|
||||||
|
time: ''
|
||||||
|
},
|
||||||
|
period: {
|
||||||
|
from: moment(new Date()).startOf('day').format('HH:mm:ss'),
|
||||||
|
to: moment(new Date()).endOf('day').format('HH:mm:ss'),
|
||||||
|
every: 1,
|
||||||
|
unit: 'seconds'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const showCron = computed(() => {
|
||||||
|
return formModel.trigger === 'cron'
|
||||||
|
})
|
||||||
|
|
||||||
|
const showOnce = computed(() => {
|
||||||
|
return formModel.trigger !== 'cron' && formModel.mod === 'once'
|
||||||
|
})
|
||||||
|
|
||||||
|
const showPeriod = computed(() => {
|
||||||
|
return formModel.trigger !== 'cron' && formModel.mod === 'period'
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang='less'>
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,167 @@
|
||||||
|
<template>
|
||||||
|
<div :class='classNames'>
|
||||||
|
<div
|
||||||
|
v-for='item in options'
|
||||||
|
:key='item.value'
|
||||||
|
:class='[
|
||||||
|
"trigger-way-item",
|
||||||
|
value === item.value ? "active" : "",
|
||||||
|
labelBottom ? "label-bottom" : ""
|
||||||
|
]'
|
||||||
|
@click='() => click(item.value)'
|
||||||
|
>
|
||||||
|
<div class='way-item-title'>
|
||||||
|
<span class='label'>{{ item.label }}</span>
|
||||||
|
<a-popover v-if='item.tip' :content='item.tip'>
|
||||||
|
<AIcon type='QuestionCircleOutlined' class='icon' />
|
||||||
|
</a-popover>
|
||||||
|
</div>
|
||||||
|
<div class='way-item-image'>
|
||||||
|
<img
|
||||||
|
width='48'
|
||||||
|
v-bind='item.imgProps'
|
||||||
|
:src='item.img'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang='ts' name='TopCard'>
|
||||||
|
|
||||||
|
import type { PropType } from 'vue'
|
||||||
|
|
||||||
|
type optionsType = {
|
||||||
|
label: string
|
||||||
|
value: string
|
||||||
|
img?: string
|
||||||
|
tip?: string
|
||||||
|
imgProps: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
|
type Emit = {
|
||||||
|
(e: 'update:value', data: string): void
|
||||||
|
(e: 'select', data: string): void
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
options: {
|
||||||
|
type: Array as PropType<optionsType[]>,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
labelBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const classNames = computed(() => {
|
||||||
|
return [
|
||||||
|
props.class,
|
||||||
|
'trigger-way-warp',
|
||||||
|
props.disabled ? 'disabled' : ''
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>()
|
||||||
|
|
||||||
|
const click = (value: string) => {
|
||||||
|
emit('update:value', value)
|
||||||
|
emit('select', value)
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang='less'>
|
||||||
|
.trigger-way-warp {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px 24px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.trigger-way-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 237px;
|
||||||
|
//width: 100%;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 1px solid #e0e4e8;
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
.way-item-title {
|
||||||
|
span {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
padding-right: 6px;
|
||||||
|
color: rgba(#000, 0.64);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: rgba(#000, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.way-item-image {
|
||||||
|
margin: 0 !important;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
//color: @primary-color-hover;
|
||||||
|
.way-item-image {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-color: @primary-color-active;
|
||||||
|
.way-item-image {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.label-bottom {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
grid-gap: 16px;
|
||||||
|
gap: 0;
|
||||||
|
align-items: center;
|
||||||
|
width: auto;
|
||||||
|
padding: 8px 16px;
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
.trigger-way-item {
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: initial;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -9,6 +9,11 @@ type State = {
|
||||||
text: string;
|
text: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type optionItem = {
|
||||||
|
label: string
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
type Action = {
|
type Action = {
|
||||||
executor: string;
|
executor: string;
|
||||||
configuration: Record<string, unknown>;
|
configuration: Record<string, unknown>;
|
||||||
|
@ -311,3 +316,9 @@ export interface FormModelType {
|
||||||
options?: Record<string, any>;
|
options?: Record<string, any>;
|
||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type metadataType = {
|
||||||
|
properties?: any[]
|
||||||
|
functions?: any[]
|
||||||
|
events?: any[]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue