Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
d36d5356bb
|
@ -59,7 +59,16 @@ export const category = (data: any) => server.post('/device/category/_tree', dat
|
|||
* 获取接入方式
|
||||
* @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
|
||||
}
|
||||
resetNumber.value += 1
|
||||
emit('search', terms)
|
||||
emit('search', { terms: []})
|
||||
}
|
||||
|
||||
watch(width, (value) => {
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
<template>
|
||||
<div class="title">
|
||||
<div class="title" :style='style'>
|
||||
<div class="title-before"></div>
|
||||
<span>{{ data }}</span>
|
||||
<slot name="extra"></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "TitleComponent",
|
||||
props: {
|
||||
data: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
<script setup lang='ts' name='TitleComponent'>
|
||||
import type { CSSProperties, PropType } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
};
|
||||
style: {
|
||||
type: Object as PropType<CSSProperties>,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -67,66 +67,116 @@ const defaultOptions = {
|
|||
],
|
||||
};
|
||||
|
||||
export const useSceneStore = defineStore({
|
||||
id: 'scene',
|
||||
state: (): DataType => {
|
||||
return {
|
||||
data: {
|
||||
trigger: { type: ''},
|
||||
options: defaultOptions,
|
||||
branches: defaultBranches,
|
||||
description: ''
|
||||
},
|
||||
productCache: {}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
initData() {
|
||||
export const useSceneStore = defineStore('scene', () => {
|
||||
const data = reactive<FormModelType | any>({
|
||||
trigger: { type: ''},
|
||||
options: defaultOptions,
|
||||
branches: defaultBranches,
|
||||
description: '',
|
||||
name: '',
|
||||
id: undefined
|
||||
})
|
||||
const productCache = {}
|
||||
|
||||
},
|
||||
/**
|
||||
* 获取详情
|
||||
* @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
|
||||
const getDetail = async (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);
|
||||
}
|
||||
if (!branches) {
|
||||
branches = cloneDeep(defaultBranches)
|
||||
if (triggerType === 'device') {
|
||||
branches.push(null)
|
||||
}
|
||||
|
||||
this.data = {
|
||||
...result,
|
||||
trigger: result.trigger || {},
|
||||
branches: cloneDeep(assignmentKey(branches)),
|
||||
options: {...defaultOptions, ...result.options },
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
},
|
||||
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 { TOKEN_KEY } from '@/utils/variable'
|
||||
import { message } from 'ant-design-vue'
|
||||
|
||||
/**
|
||||
* 静态图片资源处理
|
||||
|
@ -95,4 +96,16 @@ export const modifySearchColumnValue = (e: any, column: object) => {
|
|||
});
|
||||
});
|
||||
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>
|
||||
<div class='scene-warp'>
|
||||
<div class='header'>
|
||||
|
||||
<Ellipsis :tooltip='data.name' style='max-width: 50%'>
|
||||
<span class='title'>{{ data.name }}</span>
|
||||
</Ellipsis>
|
||||
<div class='type'>
|
||||
<img :src='TriggerHeaderIcon[data.triggerType]' />
|
||||
{{ keyByLabel[data.triggerType] }}
|
||||
</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>
|
||||
<PermissionButton
|
||||
type='primary'
|
||||
|
@ -17,19 +21,26 @@
|
|||
>
|
||||
保存
|
||||
</PermissionButton>
|
||||
<!-- <a-button type='primary' :loading='loading'>保存</a-button>-->
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts' name='Scene'>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useSceneStore } from '@/store/scene'
|
||||
import { TriggerHeaderIcon } from './asstes'
|
||||
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 loading = ref(false)
|
||||
console.log('data',data)
|
||||
|
||||
getDetail(route.query.id as string)
|
||||
|
||||
|
@ -45,17 +56,24 @@ getDetail(route.query.id as string)
|
|||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
color: rgba(#000, .8);
|
||||
font-weight: bold;
|
||||
}
|
||||
.type {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 100px;
|
||||
min-width: 80px;
|
||||
margin-left: 16px;
|
||||
padding: 4px 8px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-size: 14px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
border-radius: 2px;
|
||||
img {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue