Merge branch 'dev' into dev-hub

This commit is contained in:
jackhoo_98 2023-03-17 09:56:09 +08:00
commit 343d88209e
15 changed files with 293 additions and 184 deletions

View File

@ -94,8 +94,8 @@ export const useSceneStore = defineStore('scene', () => {
const branchesLength = branches.length;
if (
triggerType === 'device' &&
((branchesLength === 1 && !!branches[0]?.when?.length) || // 有一组数据并且when有值
(branchesLength > 1 && !branches[branchesLength - 1]?.when?.length)) // 有多组否则数据并且最后一组when有值
((branchesLength === 1 && branches[0]?.when?.length) || // 有一组数据并且when有值
(branchesLength > 1 && branches[branchesLength - 1]?.when?.length)) // 有多组否则数据并且最后一组when有值
) {
branches.push(null);
}

View File

@ -76,6 +76,9 @@
:rules="[
{ required: true, message: '请输入视频地址' },
{ max: 128, message: '最多可输入128个字符' },
{
validator: validateUrl,
},
]"
>
<template #label>
@ -237,7 +240,7 @@ watch(
* @param _rule
* @param value
*/
let validateChannelId = async (_rule: Rule, value: string) => {
const validateChannelId = async (_rule: Rule, value: string) => {
// ID, ID, ID
if (!value) return;
const { result } = await ChannelApi.validateField({
@ -252,6 +255,21 @@ let validateChannelId = async (_rule: Rule, value: string) => {
}
};
/**
* 校验视频地址
* @param _rule
* @param value
*/
const validateUrl = async (_rule: Rule, value: string) => {
console.log('value: ', value);
const reg = /(http|https|rtsp|rtmp):\/\/([\w.]+\/?)\S*/;
return new Promise((resolve, reject) => {
reg.test(value) || !value
? resolve('')
: reject('请输入正确的视频地址');
});
};
/**
* 提交
*/

View File

@ -13,7 +13,13 @@
<j-form-item
label="产品名称"
name="name"
:rules="{ required: true, message: '请输入产品名称' }"
:rules="[
{ required: true, message: '请输入产品名称' },
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<j-input
v-model:value="formData.name"
@ -25,11 +31,17 @@
<j-form-item
:name="item.name"
:label="item.label"
:rules="{
required: item.required,
message: item.message,
trigger: 'change',
}"
:rules="[
{
required: item.required,
message: item.message,
trigger: 'change',
},
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<j-select
v-if="item.type === 'enum'"
@ -260,7 +272,7 @@ const handleOk = () => {
res.result.id,
);
if (deployResp.success) {
emit('save', {...res.result})
emit('save', { ...res.result });
message.success('操作成功');
handleCancel();
}

View File

@ -4,10 +4,14 @@
<j-card>
<j-row :gutter="24">
<j-col :span="12">
<j-form layout="vertical">
<j-form ref="formRef" :model="formData" layout="vertical">
<j-form-item
label="接入方式"
v-bind="validateInfos.channel"
name="channel"
:rules="{
required: true,
message: '请选择接入方式',
}"
>
<RadioCard
layout="horizontal"
@ -15,7 +19,7 @@
:checkStyle="true"
:disabled="!!route.query.id"
v-model="formData.channel"
@change="formData.productId = undefined"
@change="handleChannelChange"
/>
</j-form-item>
<j-row :gutter="24">
@ -28,7 +32,24 @@
<j-col :span="16">
<j-form-item
label="ID"
v-bind="validateInfos.id"
name="id"
:rules="[
{
required:
formData.channel ===
'gb28181-2016',
message: '请输入ID',
},
{
max: 64,
message: '最多输入64个字符',
},
{
pattern: /^[a-zA-Z0-9_\-]+$/,
message:
'请输入英文或者数字或者-或者_',
},
]"
>
<j-input
v-model:value="formData.id"
@ -38,18 +59,32 @@
</j-form-item>
<j-form-item
label="设备名称"
v-bind="validateInfos.name"
name="name"
:rules="[
{
required: true,
message: '请输入设备名称',
},
{
max: 64,
message: '最多可输入64个字符',
},
]"
>
<j-input
v-model:value="formData.name"
placeholder="请输入名称"
placeholder="请输入设备名称"
/>
</j-form-item>
</j-col>
</j-row>
<j-form-item
label="所属产品"
v-bind="validateInfos.productId"
name="productId"
:rules="{
required: true,
message: '请选择所属产品',
}"
>
<j-row :gutter="[0, 10]">
<j-col :span="!!route.query.id ? 24 : 22">
@ -79,7 +114,17 @@
</j-form-item>
<j-form-item
label="接入密码"
v-bind="validateInfos['others.access_pwd']"
:name="['others', 'access_pwd']"
:rules="[
{
required: true,
message: '请输入接入密码',
},
{
max: 64,
message: '最多可输入64个字符',
},
]"
v-if="formData.channel === 'gb28181-2016'"
>
<j-input-password
@ -90,7 +135,11 @@
<template v-if="!!route.query.id">
<j-form-item
label="流传输模式"
v-bind="validateInfos.streamMode"
name="streamMode"
:rules="{
required: true,
message: '请选择流传输模式',
}"
>
<j-radio-group
button-style="solid"
@ -246,18 +295,14 @@
<script setup lang="ts">
import { getImage } from '@/utils/comm';
import { Form } from 'ant-design-vue';
import { message } from 'ant-design-vue';
import DeviceApi from '@/api/media/device';
import { PROVIDER_OPTIONS } from '@/views/media/Device/const';
import type { ProductType } from '@/views/media/Device/typings';
import SaveProduct from './SaveProduct.vue';
const router = useRouter();
const route = useRoute();
const useForm = Form.useForm;
//
const formData = ref({
@ -266,10 +311,10 @@ const formData = ref({
channel: 'gb28181-2016',
photoUrl: getImage('/device-media.png'),
productId: undefined,
description: '',
others: {
access_pwd: '',
},
description: '',
//
streamMode: 'UDP',
manufacturer: '',
@ -277,50 +322,9 @@ const formData = ref({
firmware: '',
});
//
const formRules = ref({
id: [
{
required: true,
message: '请输入ID',
},
{ max: 64, message: '最多输入64个字符' },
{
pattern: /^[j-zA-Z0-9_\-]+$/,
message: '请输入英文或者数字或者-或者_',
},
],
name: [
{ required: true, message: '请输入名称' },
{ max: 64, message: '最多可输入64个字符' },
],
productId: [{ required: true, message: '请选择所属产品' }],
channel: [{ required: true, message: '请选择接入方式' }],
'others.access_pwd': [{ required: true, message: '请输入接入密码' }],
description: [{ max: 200, message: '最多可输入200个字符' }],
streamMode: [{ required: true, message: '请选择流传输模式' }],
});
watch(
() => formData.value.channel,
(val) => {
formRules.value['id'][0].required = val === 'gb28181-2016';
formRules.value['others.access_pwd'][0].required =
val === 'gb28181-2016';
validate();
getProductList();
},
);
const { resetFields, validate, validateInfos, clearValidate } = useForm(
formData.value,
formRules.value,
);
const clearValid = () => {
setTimeout(() => {
clearValidate();
}, 200);
const handleChannelChange = () => {
formData.value.productId = undefined;
getProductList();
};
/**
@ -328,7 +332,6 @@ const clearValid = () => {
*/
const productList = ref<ProductType[]>([]);
const getProductList = async () => {
// console.log('formData.productId: ', formData.value.productId);
const params = {
paging: false,
sorts: [{ name: 'createTime', order: 'desc' }],
@ -352,12 +355,8 @@ const saveProductVis = ref(false);
*/
const getDetail = async () => {
const res = await DeviceApi.detail(route.query.id as string);
// console.log('res: ', res);
// formData.value = res.result;
Object.assign(formData.value, res.result);
formData.value.channel = res.result.provider;
console.log('formData.value: ', formData.value);
};
onMounted(() => {
@ -368,23 +367,51 @@ onMounted(() => {
* 表单提交
*/
const btnLoading = ref<boolean>(false);
const formRef = ref();
const handleSubmit = () => {
// console.log('formData.value: ', formData.value);
validate()
const {
others,
id,
streamMode,
manufacturer,
model,
firmware,
...extraParams
} = formData.value;
let params: any;
if (formData.value.channel === 'fixed-media') {
//
params = !id
? extraParams
: { id, streamMode, manufacturer, model, firmware, ...extraParams };
} else {
//
params = !id
? { others, id, ...extraParams }
: {
others,
id,
streamMode,
manufacturer,
model,
firmware,
...extraParams,
};
}
formRef.value
?.validate()
.then(async () => {
btnLoading.value = true;
let res;
if (!route.query.id) {
res = await DeviceApi.save(formData.value);
} else {
res = await DeviceApi.update(formData.value);
}
const res = !route.query.id
? await DeviceApi.save(params)
: await DeviceApi.update(params);
if (res?.success) {
message.success('保存成功');
router.back();
}
})
.catch((err) => {
.catch((err: any) => {
console.log('err: ', err);
})
.finally(() => {

View File

@ -328,7 +328,7 @@ const getActions = (
? '设备已离线'
: data.state.value === 'notActive'
? '设备已禁用'
: '',
: '更新通道',
},
disabled:
data.state.value === 'offline' ||

View File

@ -82,6 +82,7 @@ import ParamsDropdown, { DoubleParamsDropdown } from '../../components/ParamsDro
import { inject } from 'vue'
import { useSceneStore } from 'store/scene'
import { storeToRefs } from 'pinia';
import { flattenDeep, set } from 'lodash-es'
const sceneStore = useSceneStore()
const { data: formModel } = storeToRefs(sceneStore)
@ -207,12 +208,32 @@ const mouseout = () => {
}
}
const columnSelect = () => {
const handleOptionsColumnsValue = (termsColumns: any[], _options: any) => {
formModel.value.branches![props.branchName].then[props.thenName].actions[props.name].options!.termsColumns = termsColumns
const flatten = new Set(flattenDeep(termsColumns))
let newColumns = [...flatten.values()]
if (_options?.otherColumns) {
newColumns = [..._options?.otherColumns, ...newColumns]
}
formModel.value.branches![props.branchName].then[props.thenName].actions[props.name].options!.columns = newColumns
}
const columnSelect = (e: any) => {
paramsValue.termType = 'eq'
paramsValue.value = {
source: tabsOptions.value[0].key,
value: undefined
}
const columns = e.metadata === true ? [e.column] : []
const _options = formModel.value.branches![props.branchName].then[props.thenName].actions[props.actionName].options
const termsColumns = _options?.termsColumns || []
set(
termsColumns,
[props.termsName, props.name],
columns
)
handleOptionsColumnsValue(termsColumns, _options)
emit('update:value', { ...paramsValue })
}
@ -245,6 +266,14 @@ const termAdd = () => {
const onDelete = () => {
formModel.value.branches?.[props.branchName]?.then?.[props.thenName]?.actions?.[props.actionName].terms?.[props.termsName].terms?.splice(props.name, 1)
const _options = formModel.value.branches![props.branchName].then[props.thenName].actions[props.name].options
const termsColumns = _options?.termsColumns || []
set(
termsColumns,
[props.termsName, props.name],
[]
)
handleOptionsColumnsValue(termsColumns, _options)
}
nextTick(() => {

View File

@ -58,7 +58,7 @@ import { storeToRefs } from 'pinia'
import { useSceneStore } from 'store/scene'
import DropdownButton from '../../components/DropdownButton'
import FilterItem from './FilterCondition.vue'
import { isArray } from 'lodash-es'
import { flattenDeep, isArray, set } from 'lodash-es'
import { provide } from 'vue'
import { randomString } from '@/utils/utils'
import { useParams } from '@/views/rule-engine/Scene/Save/util'
@ -66,8 +66,6 @@ import { useParams } from '@/views/rule-engine/Scene/Save/util'
const sceneStore = useSceneStore()
const { data: formModel } = storeToRefs(sceneStore)
const props = defineProps({
isFirst: {
type: Boolean,
@ -103,9 +101,7 @@ const { columnOptions } = useParams({
branch: props.branchName,
branchGroup: props.thenName,
action: props.actionName
}, [
formModel.value.branches![props.branchName].then[props.thenName].actions[props.actionName]
])
})
provide('filter-params', columnOptions)
@ -123,6 +119,16 @@ const mouseout = () => {
showDelete.value = false
}
const handleOptionsColumnsValue = (termsColumns: any[], _options: any) => {
formModel.value.branches![props.branchName].then[props.thenName].actions[props.name].options!.termsColumns = termsColumns
const flatten = new Set(flattenDeep(termsColumns))
let newColumns = [...flatten.values()]
if (_options?.otherColumns) {
newColumns = [..._options?.otherColumns, ...newColumns]
}
formModel.value.branches![props.branchName].then[props.thenName].actions[props.name].options!.columns = newColumns
}
const addTerms = () => {
const item: any = {
type: 'and',
@ -154,6 +160,13 @@ const onDelete = () => {
.then[props.thenName]
.actions[props.actionName]
.terms?.splice(props.name, 1)
const _options = formModel.value.branches![props.branchName].then[props.thenName].actions[props.actionName].options
const termsColumns = _options?.termsColumns || []
if (_options?.termsColumns) {
termsColumns.splice(props.name, 1)
handleOptionsColumnsValue(termsColumns, _options)
}
}
const rules = [

View File

@ -446,6 +446,11 @@ const termsOptions = computed(() => {
});
const onDelete = () => {
if (props.name !== 0 && !props.parallel) { // options.termsColumnsterms
_data.value.branches![props.branchesName].then[props.thenName].actions[props.name - 1].options!.termsColumns = []
_data.value.branches![props.branchesName].then[props.thenName].actions[props.name - 1].options!.terms = []
_data.value.branches![props.branchesName].then[props.thenName].actions[props.name - 1].terms = []
}
emit('delete');
};
@ -453,11 +458,16 @@ const onClose = () => {
visible.value = false;
};
const onSave = (data: ActionsType, options?: any) => {
emit('update', data, options);
// setTimeout(() => {
// getParams();
// }, 10);
const onSave = (data: ActionsType, options: any) => {
const { key, terms } = _data.value.branches![props.branchesName].then?.[props.thenName].actions?.[props.name]
const actionItem: ActionsType = {
...data,
options,
key,
terms
}
_data.value.branches![props.branchesName].then[props.thenName].actions.splice(props.name, 1, actionItem)
visible.value = false;
};

View File

@ -11,7 +11,6 @@
:isLast="index === actions.length - 1"
:options="item.options"
@delete="_delete(item.key || '')"
@update="(data, options) => _update(data, options, item)"
/>
</template>
<div class="actions-add-list" :class="{ 'border': props.actions.length }">
@ -37,7 +36,6 @@ import { PropType } from 'vue';
import { ActionsType, ParallelType } from '../../../typings';
import Modal from '../Modal/index.vue';
import Item from './Item.vue';
import { pick } from 'lodash';
import { useSceneStore } from '@/store/scene';
import { storeToRefs } from 'pinia';
@ -98,9 +96,7 @@ const _delete = (_key: string) => {
emit('delete', _key)
}
const _update = (data: ActionsType, options: any, item: any) => {
const olData = pick(item, ['terms']);
emit('add', {...olData, ...data, options})
const _update = () => {
visible.value = false
}
</script>

View File

@ -131,7 +131,8 @@ const onOk = () => {
emit(
'save',
{
...props.data,
// ...props.data,
key: props.data.key,
executor: 'alarm',
alarm: { mode: values.type },
},

View File

@ -1,63 +1,63 @@
<template>
<div class="actions">
<div class="actions-title">
<span>执行</span>
<ShakeLimit
v-if="props.openShakeLimit"
v-model:value="FormModel.branches[name].shakeLimit"
/>
</div>
<div class="actions-warp">
<j-collapse v-model:activeKey="activeKeys">
<j-collapse-panel key="1">
<template #header>
<span>
串行
<span class="panel-tip">
按顺序依次执行动作适用于基于动作输出参数判断是否执行后续动作的场景
</span>
</span>
</template>
<div class="actions-list">
<List
type="serial"
:branchesName="name"
:parallel="false"
:actions="
serialArray.length ? serialArray[0].actions : []
"
@add="(_item) => onAdd(_item, false)"
@delete="(_key) => onDelete(_key, false)"
/>
</div>
</j-collapse-panel>
<j-collapse-panel key="2">
<template #header>
<span>
并行
<span class="panel-tip">
同时执行所有动作适用于不需要关注执行动作先后顺序和结果的场景
</span>
</span>
</template>
<div class="actions-list">
<List
type="parallel"
:branchesName="name"
:parallel="true"
:actions="
parallelArray.length
? parallelArray[0].actions
: []
"
@add="(_item) => onAdd(_item, true)"
@delete="(_key) => onDelete(_key, true)"
/>
</div>
</j-collapse-panel>
</j-collapse>
</div>
<div class="actions">
<div class="actions-title">
<span>执行</span>
<ShakeLimit
v-if="props.openShakeLimit"
v-model:value="FormModel.branches[name].shakeLimit"
/>
</div>
<div class="actions-warp">
<j-collapse v-model:activeKey="activeKeys">
<j-collapse-panel key="1">
<template #header>
<span>
串行
<span class="panel-tip">
按顺序依次执行动作适用于基于动作输出参数判断是否执行后续动作的场景
</span>
</span>
</template>
<div class="actions-list">
<List
type="serial"
:branchesName="name"
:parallel="false"
:actions="
serialArray.length ? serialArray[0].actions : []
"
@add="(_item) => onAdd(_item, false)"
@delete="(_key) => onDelete(_key, false)"
/>
</div>
</j-collapse-panel>
<j-collapse-panel key="2">
<template #header>
<span>
并行
<span class="panel-tip">
同时执行所有动作适用于不需要关注执行动作先后顺序和结果的场景
</span>
</span>
</template>
<div class="actions-list">
<List
type="parallel"
:branchesName="name"
:parallel="true"
:actions="
parallelArray.length
? parallelArray[0].actions
: []
"
@add="(_item) => onAdd(_item, true)"
@delete="(_key) => onDelete(_key, true)"
/>
</div>
</j-collapse-panel>
</j-collapse>
</div>
</div>
</template>
<script lang="ts" setup>
@ -130,13 +130,14 @@ const onDelete = (_key: string, _parallel: boolean) => {
const onAdd = (actionItem: any, _parallel: boolean) => {
const thenName = props.thenOptions.findIndex(item => item.parallel === _parallel)
if (thenName !== -1) { //
const cacheAction = props.thenOptions[thenName].actions
const indexOf = cacheAction?.findIndex(item => item.key === actionItem.key) || -1
if (indexOf !== -1) {
FormModel.value.branches?.[props.name].then?.[thenName].actions.splice(indexOf, 1, actionItem)
} else {
FormModel.value.branches?.[props.name].then?.[thenName].actions.push(actionItem)
}
// const cacheAction = props.thenOptions[thenName].actions
// const indexOf = cacheAction?.findIndex(item => item.key === actionItem.key) || -1
// if (indexOf !== -1) {
// FormModel.value.branches?.[props.name].then?.[thenName].actions.splice(indexOf, 1, actionItem)
// } else {
// FormModel.value.branches?.[props.name].then?.[thenName].actions.push(actionItem)
// }
FormModel.value.branches?.[props.name].then?.[thenName].actions.push(actionItem)
} else { //
const newThenItem = {
parallel: _parallel,

View File

@ -1,5 +1,5 @@
<template>
<div :class='["actions-terms-warp", props.class]'>
<div :class='["actions-terms-warp", isFirst ? "first-children" : ""]'>
<div class='actions-terms-title'>
{{ isFirst ? '当' : '否则' }}
</div>

View File

@ -32,13 +32,6 @@
</div>
</template>
</template>
<!-- <j-form-item-->
<!-- v-else-->
<!-- :name='["branches", 0, "then"]'-->
<!-- :rules='rules'-->
<!-- >-->
<!-- -->
<!-- </j-form-item>-->
</div>
</template>

View File

@ -49,16 +49,8 @@
.actions-terms {
.actions-terms-warp {
display: flex;
//width: 66.66%;
margin-bottom: 24px;
&.first-children {
width: 100%;
.actions-branches {
width: 66.66%;
}
}
&.first-children,
&:last-child {
margin-bottom: 0;
@ -212,4 +204,21 @@
}
}
@minWidth: 75%;
@media (min-width: 1600px) {
.actions-terms {
.actions-terms-warp {
width: @minWidth;
&.first-children {
width: 100%;
.actions-branches {
width: calc(@minWidth - 12px);
}
}
}
}
}

View File

@ -27,7 +27,7 @@ export const getParams = (params: Params, sceneModel: FormModelType): Promise<an
/**
* @param params
*/
export const useParams = (params: Params, effect: any[] = []) => {
export const useParams = (params: Params) => {
const sceneStore = useSceneStore()
const { data: formModel } = storeToRefs(sceneStore)
const columnOptions = ref<any[]>([])
@ -38,7 +38,7 @@ export const useParams = (params: Params, effect: any[] = []) => {
}
watchEffect(() => {
if (effect[0]) {
if (formModel.value.branches![params.branch].then[params.branchGroup].actions[params.action]) {
handleParams()
}
})