Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
8bb756e5e6
|
@ -0,0 +1,8 @@
|
|||
import server from '@/utils/request';
|
||||
|
||||
|
||||
export const modify = (id: string, data: any) => server.put(`/scene/${id}`, data)
|
||||
|
||||
export const save = (data: any) => server.post(`/scene`, data)
|
||||
|
||||
export const detail = (id: string) => server.get(`/scene/${id}`)
|
|
@ -0,0 +1,168 @@
|
|||
<template>
|
||||
<Tooltip ref="tooltipRef" placement="top" v-bind="props.tooltip">
|
||||
<template v-if="props.tooltip" #title>
|
||||
<slot></slot>
|
||||
<slot name="tooltip"></slot>
|
||||
</template>
|
||||
<span
|
||||
ref="triggerRef"
|
||||
v-bind="triggerAttrs()"
|
||||
@click="handleClickRef"
|
||||
@mouseenter="
|
||||
[
|
||||
props.expandTrigger === 'click'
|
||||
? getTooltipDisabled()
|
||||
: undefined,
|
||||
]
|
||||
"
|
||||
>
|
||||
<slot></slot>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Tooltip, TooltipProps } from 'ant-design-vue';
|
||||
|
||||
import { computed, mergeProps, PropType, ref, useAttrs } from 'vue';
|
||||
|
||||
// define class name
|
||||
const jEllipsis = 'j-ellipsis';
|
||||
const jEllipsisCursorClass = 'j-ellipsis-cursor';
|
||||
const jEllipsisLineClampClass = 'j-ellipsis-line-clamp';
|
||||
|
||||
const props = defineProps({
|
||||
/** expand by */
|
||||
expandTrigger: {
|
||||
type: String as PropType<'click'>,
|
||||
default: undefined,
|
||||
},
|
||||
/** multiline ellipsis */
|
||||
lineClamp: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 1,
|
||||
},
|
||||
/** a-tooltip props */
|
||||
tooltip: {
|
||||
type: [Boolean, Object] as PropType<TooltipProps | boolean>,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const attrs = useAttrs();
|
||||
|
||||
function triggerAttrs() {
|
||||
return {
|
||||
...mergeProps(attrs, {
|
||||
class: [
|
||||
jEllipsis,
|
||||
props.lineClamp !== undefined
|
||||
? jEllipsisLineClampClass
|
||||
: undefined,
|
||||
props.expandTrigger === 'click'
|
||||
? jEllipsisCursorClass
|
||||
: undefined,
|
||||
],
|
||||
style: ellipsisStyleRef.value,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
const expandedRef = ref(false);
|
||||
const tooltipRef = ref<HTMLElement | null>(null);
|
||||
const triggerRef = ref<HTMLElement | null>(null);
|
||||
|
||||
const ellipsisStyleRef = computed(() => {
|
||||
const { lineClamp } = props;
|
||||
const { value: expanded } = expandedRef;
|
||||
if (lineClamp !== undefined) {
|
||||
return {
|
||||
textOverflow: '',
|
||||
'-webkit-line-clamp': expanded ? '' : lineClamp,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
textOverflow: expanded ? '' : 'ellipsis',
|
||||
'-webkit-line-clamp': '',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
function syncCursorStyle(trigger: HTMLElement, tooltipDisabled: boolean): void {
|
||||
if (props.expandTrigger === 'click' && !tooltipDisabled) {
|
||||
syncTriggerClass(trigger, jEllipsisCursorClass, 'add');
|
||||
} else {
|
||||
syncTriggerClass(trigger, jEllipsisCursorClass, 'remove');
|
||||
}
|
||||
}
|
||||
|
||||
function getTooltipDisabled(): boolean {
|
||||
let tooltipDisabled = false;
|
||||
const { value: expanded } = expandedRef;
|
||||
if (expanded) return true;
|
||||
const { value: trigger } = triggerRef;
|
||||
if (trigger) {
|
||||
syncEllipsisStyle(trigger);
|
||||
tooltipDisabled = trigger.scrollHeight <= trigger.offsetHeight;
|
||||
|
||||
syncCursorStyle(trigger, tooltipDisabled);
|
||||
}
|
||||
return tooltipDisabled;
|
||||
}
|
||||
|
||||
const handleClickRef = computed(() => {
|
||||
return props.expandTrigger === 'click'
|
||||
? () => {
|
||||
const { value: expanded } = expandedRef;
|
||||
expandedRef.value = !expanded;
|
||||
}
|
||||
: undefined;
|
||||
});
|
||||
|
||||
function syncEllipsisStyle(trigger: HTMLElement): void {
|
||||
if (!trigger) return;
|
||||
const latestStyle = ellipsisStyleRef.value;
|
||||
const lineClampClass = jEllipsisLineClampClass;
|
||||
if (props.lineClamp !== undefined) {
|
||||
syncTriggerClass(trigger, lineClampClass, 'add');
|
||||
} else {
|
||||
syncTriggerClass(trigger, lineClampClass, 'remove');
|
||||
}
|
||||
for (const key in latestStyle) {
|
||||
if ((trigger.style as any)[key] !== (latestStyle as any)[key]) {
|
||||
(trigger.style as any)[key] = (latestStyle as any)[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function syncTriggerClass(
|
||||
trigger: HTMLElement,
|
||||
styleClass: string,
|
||||
action: 'add' | 'remove',
|
||||
): void {
|
||||
if (action === 'add') {
|
||||
if (!trigger.classList.contains(styleClass)) {
|
||||
trigger.classList.add(styleClass);
|
||||
}
|
||||
} else {
|
||||
if (trigger.classList.contains(styleClass)) {
|
||||
trigger.classList.remove(styleClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang='less'>
|
||||
.j-ellipsis {
|
||||
overflow: hidden;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.j-ellipsis-cursor {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.j-ellipsis-line-clamp {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
|
@ -10,6 +10,7 @@ import NormalUpload from './NormalUpload/index.vue'
|
|||
import FileFormat from './FileFormat/index.vue'
|
||||
import JUpload from './JUpload/index.vue'
|
||||
import { BasicLayoutPage, BlankLayoutPage, PageContainer } from './Layout'
|
||||
import Ellipsis from './Ellipsis/index.vue'
|
||||
|
||||
export default {
|
||||
install(app: App) {
|
||||
|
@ -26,5 +27,6 @@ export default {
|
|||
.component('BasicLayoutPage', BasicLayoutPage)
|
||||
.component('BlankLayoutPage', BlankLayoutPage)
|
||||
.component('PageContainer', PageContainer)
|
||||
.component('Ellipsis', Ellipsis)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import { defineStore } from 'pinia'
|
|||
import { queryOwnThree } from '@/api/system/menu'
|
||||
import { filterAsnycRouter, MenuItem } from '@/utils/menu'
|
||||
import { isArray } from 'lodash-es'
|
||||
import { usePermissionStore } from './permission'
|
||||
import router from '@/router'
|
||||
|
||||
const defaultOwnParams = [
|
||||
|
@ -45,26 +46,15 @@ export const useMenuStore = defineStore({
|
|||
}),
|
||||
getters: {
|
||||
hasPermission(state) {
|
||||
return (code: string | string[]) => {
|
||||
if (!code) {
|
||||
return (menuCode: string | string[]) => {
|
||||
if (!menuCode) {
|
||||
return true
|
||||
}
|
||||
if (!!Object.keys(state.menus).length) {
|
||||
let codes: string[] = []
|
||||
|
||||
if (typeof code === 'string') {
|
||||
codes.push(code)
|
||||
} else {
|
||||
codes = code
|
||||
if (typeof menuCode === 'string') {
|
||||
return !!this.menus[menuCode]
|
||||
}
|
||||
|
||||
return codes.some(_c => {
|
||||
const menu_code = _c.split(':')
|
||||
if (menu_code.length > 1) {
|
||||
return !!this.menus[menu_code[0]]?.buttons?.includes(menu_code[1])
|
||||
}
|
||||
return false
|
||||
})
|
||||
return menuCode.some(code => !!this.menus[code])
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -95,6 +85,8 @@ export const useMenuStore = defineStore({
|
|||
//过滤非集成的菜单
|
||||
const resp = await queryOwnThree({ paging: false, terms: defaultOwnParams })
|
||||
if (resp.success) {
|
||||
const permission = usePermissionStore()
|
||||
permission.permissions = {}
|
||||
const { menusData, silderMenus } = filterAsnycRouter(resp.result)
|
||||
this.menus = {}
|
||||
const handleMenuItem = (menu: any) => {
|
||||
|
@ -104,6 +96,7 @@ export const useMenuStore = defineStore({
|
|||
path: menuItem.path,
|
||||
buttons: menuItem.meta.buttons
|
||||
}
|
||||
permission.permissions[menuItem.name] = menuItem.meta.buttons
|
||||
if (menuItem.children && menuItem.children.length) {
|
||||
handleMenuItem(menuItem.children)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import type { BranchesType, FormModelType, SceneItem } from '@/views/rule-engine/Scene/typings'
|
||||
import { detail } from '@/api/rule-engine/scene'
|
||||
import { cloneDeep, isArray } from 'lodash-es'
|
||||
import { randomString } from '@/utils/utils'
|
||||
|
||||
type DataType = {
|
||||
data: FormModelType | any
|
||||
productCache: any
|
||||
}
|
||||
|
||||
const assignmentKey = (data: any[]): any[] => {
|
||||
const onlyKey = ['when', 'then', 'terms', 'actions'];
|
||||
if (!data) return [];
|
||||
|
||||
return data.map((item: any) => {
|
||||
if (item) {
|
||||
item.key = randomString();
|
||||
Object.keys(item).some((key) => {
|
||||
if (onlyKey.includes(key) && isArray(item[key])) {
|
||||
item[key] = assignmentKey(item[key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
|
||||
export const defaultBranches = [
|
||||
{
|
||||
when: [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
column: undefined,
|
||||
value: undefined,
|
||||
termType: undefined,
|
||||
key: 'params_1',
|
||||
type: 'and',
|
||||
},
|
||||
],
|
||||
type: 'and',
|
||||
key: 'terms_1',
|
||||
},
|
||||
],
|
||||
key: 'branches_1',
|
||||
shakeLimit: {
|
||||
enabled: false,
|
||||
time: 1,
|
||||
threshold: 1,
|
||||
alarmFirst: false,
|
||||
},
|
||||
then: [],
|
||||
},
|
||||
];
|
||||
|
||||
const defaultOptions = {
|
||||
trigger: {},
|
||||
when: [
|
||||
{
|
||||
terms: [
|
||||
{
|
||||
terms: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
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: {
|
||||
|
||||
}
|
||||
})
|
|
@ -13,6 +13,7 @@
|
|||
v-model:value="formData.type"
|
||||
placeholder="请选择通知方式"
|
||||
:disabled="!!formData.id"
|
||||
@change="handleTypeChange"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(item, index) in NOTICE_METHOD"
|
||||
|
@ -37,6 +38,7 @@
|
|||
<RadioCard
|
||||
:options="msgType"
|
||||
v-model="formData.provider"
|
||||
@change="handleProviderChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
<!-- 钉钉 -->
|
||||
|
@ -331,22 +333,24 @@ watch(
|
|||
(val) => {
|
||||
msgType.value = MSG_TYPE[val];
|
||||
|
||||
formData.value.provider = msgType.value[0].value;
|
||||
formData.value.provider =
|
||||
formData.value.provider !== ':id'
|
||||
? formData.value.provider
|
||||
: msgType.value[0].value;
|
||||
|
||||
formData.value.configuration =
|
||||
CONFIG_FIELD_MAP[val][formData.value.provider];
|
||||
// formData.value.configuration =
|
||||
// CONFIG_FIELD_MAP[val][formData.value.provider];
|
||||
|
||||
clearValid();
|
||||
// clearValid();
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => formData.value.provider,
|
||||
(val) => {
|
||||
formData.value.configuration =
|
||||
CONFIG_FIELD_MAP[formData.value.type][val];
|
||||
|
||||
clearValid();
|
||||
// formData.value.configuration =
|
||||
// CONFIG_FIELD_MAP[formData.value.type][val];
|
||||
// clearValid();
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -429,10 +433,31 @@ const getDetail = async () => {
|
|||
const res = await configApi.detail(route.params.id as string);
|
||||
// formData.value = res.result;
|
||||
Object.assign(formData.value, res.result);
|
||||
// console.log('res.result: ', res.result);
|
||||
// console.log('formData.value: ', formData.value);
|
||||
};
|
||||
getDetail();
|
||||
|
||||
/**
|
||||
* 通知方式改变
|
||||
*/
|
||||
const handleTypeChange = () => {
|
||||
setTimeout(() => {
|
||||
formData.value.configuration =
|
||||
CONFIG_FIELD_MAP[formData.value.type][formData.value.provider];
|
||||
// resetPublicFiles();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* 通知类型改变
|
||||
*/
|
||||
const handleProviderChange = () => {
|
||||
formData.value.configuration =
|
||||
CONFIG_FIELD_MAP[formData.value.type][formData.value.provider];
|
||||
// resetPublicFiles();
|
||||
};
|
||||
|
||||
/**
|
||||
* 表单提交
|
||||
*/
|
||||
|
|
|
@ -48,10 +48,10 @@
|
|||
<template #img>
|
||||
<slot name="img">
|
||||
<img
|
||||
style="width: 80px; height: 80px"
|
||||
:src="
|
||||
getLogo(slotProps.type, slotProps.provider)
|
||||
"
|
||||
class="logo"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
|
@ -429,3 +429,9 @@ const getActions = (
|
|||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.logo {
|
||||
width: 88px;
|
||||
height: 88px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
:src="
|
||||
getLogo(slotProps.type, slotProps.provider)
|
||||
"
|
||||
class="logo"
|
||||
/>
|
||||
</slot>
|
||||
</template>
|
||||
|
@ -388,3 +389,10 @@ const getActions = (
|
|||
return actions;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.logo {
|
||||
width: 88px;
|
||||
height: 88px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { getImage } from '@/utils/comm'
|
||||
|
||||
export const TriggerHeaderIcon = {
|
||||
time: getImage('/scene/trigger-type-icon/timing.png'),
|
||||
manual: getImage('/scene/trigger-type-icon/manual.png'),
|
||||
device: getImage('/scene/trigger-type-icon/device.png')
|
||||
}
|
||||
|
||||
export const TriggerListIcon = {
|
||||
time: getImage('/scene/scene-timer.png'),
|
||||
manual: getImage('/scene/scene-hand.png'),
|
||||
device: getImage('/scene/scene-device.png')
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<template>
|
||||
<div :class='classNames'>
|
||||
<div
|
||||
v-for='item in options'
|
||||
:key='item.value'
|
||||
:class='["trigger-way-item", modelValue === item.value ? "active" : "" ]'
|
||||
@click='handleClick(item.value)'
|
||||
>
|
||||
<div class='way-item-title'>
|
||||
<p>{{ item.label }}</p>
|
||||
<span>{{ item.tip}}</span>
|
||||
</div>
|
||||
<div class='way-item-image'>
|
||||
<img width='40' :src='item.image' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts' setup name='TriggerWay'>
|
||||
|
||||
import { getImage } from '@/utils/comm'
|
||||
|
||||
type Emit = {
|
||||
(e: 'update:modelValue', data: string): void
|
||||
}
|
||||
|
||||
const options = [
|
||||
{ value: 'device', label: '设备触发', tip: '适用于设备数据或行为满足触发条件时,执行指定的动作', image: getImage('/device-trigger.png') },
|
||||
{ value: 'manual', label: '手动触发', tip: '适用于第三方平台向物联网平台下发指令控制设备', image: getImage('/manual-trigger.png') },
|
||||
{ value: 'timing', label: '定时触发', tip: '适用于定期执行固定任务', image: getImage('/timing-trigger.png') },
|
||||
]
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const classNames = computed(() => {
|
||||
return {
|
||||
[props.className]: true,
|
||||
'scene-trigger-way-warp': true,
|
||||
disabled: props.disabled
|
||||
}
|
||||
})
|
||||
|
||||
const handleClick = (type: string) => {
|
||||
emit('update:modelValue', type)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang='less'>
|
||||
@import 'ant-design-vue/es/style/themes/default.less';
|
||||
|
||||
.scene-trigger-way-warp {display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px 24px;
|
||||
width: 100%;
|
||||
|
||||
.trigger-way-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 16px;
|
||||
border: 1px solid #e0e4e8;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
width: 204px;
|
||||
|
||||
.way-item-title {
|
||||
p {
|
||||
margin-bottom: 8px;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: rgba(#000, 0.35);
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.way-item-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,13 +1,62 @@
|
|||
<template>
|
||||
<page-container>
|
||||
<div class='scene-warp'>
|
||||
<div class='header'>
|
||||
|
||||
<div class='type'>
|
||||
<img :src='TriggerHeaderIcon[data.triggerType]' />
|
||||
{{ keyByLabel[data.triggerType] }}
|
||||
</div>
|
||||
</div>
|
||||
<a-form ref='sceneForm' :model='data'>
|
||||
|
||||
</a-form>
|
||||
<PermissionButton
|
||||
type='primary'
|
||||
hasPermission='rule-engine/Scene:update'
|
||||
>
|
||||
保存
|
||||
</PermissionButton>
|
||||
<!-- <a-button type='primary' :loading='loading'>保存</a-button>-->
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'index'
|
||||
}
|
||||
<script setup lang='ts' name='Scene'>
|
||||
import { useSceneStore } from '@/store/scene'
|
||||
import { TriggerHeaderIcon } from './asstes'
|
||||
import { keyByLabel } from '../typings'
|
||||
|
||||
const { getDetail, data } = useSceneStore()
|
||||
const route = useRoute();
|
||||
const loading = ref(false)
|
||||
|
||||
getDetail(route.query.id as string)
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang='less'>
|
||||
.scene-warp {
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.type {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 100px;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,104 @@
|
|||
<template>
|
||||
<a-modal
|
||||
visible
|
||||
:title='title'
|
||||
:width='750'
|
||||
:confirm-loading='loading'
|
||||
:maskClosable='false'
|
||||
@cancel='emit("close")'
|
||||
@ok='handleOk'
|
||||
>
|
||||
<a-form
|
||||
layout='vertical'
|
||||
name='scene-save'
|
||||
ref="formRef"
|
||||
:model='formModel'
|
||||
>
|
||||
<a-form-item
|
||||
name='name'
|
||||
label='名称'
|
||||
:rules="[
|
||||
{ required: true, message: '请输入名称' },
|
||||
{ max: 64, message: '最多输入64个字符' }
|
||||
]"
|
||||
>
|
||||
<a-input v-model:value='formModel.name' placeholder='请输入名称' />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:name='["trigger", "type"]'
|
||||
label='触发方式'
|
||||
:rules="[{ required: true, message: '请选择触发方式' }]"
|
||||
>
|
||||
<TriggerWay v-model:modelValue='formModel.trigger.type' :disabled='disabled' />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
|
||||
import { SceneItem } from '@/views/rule-engine/Scene/typings'
|
||||
import TriggerWay from './components/TriggerWay.vue'
|
||||
import type { PropType } from 'vue'
|
||||
import type { FormInstance } from 'ant-design-vue';
|
||||
import { save, modify } from '@/api/rule-engine/scene'
|
||||
import { useMenuStore } from 'store/menu'
|
||||
|
||||
type Emit = {
|
||||
(e: 'close'): void
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
const menuStory = useMenuStore()
|
||||
const formModel = reactive({
|
||||
name: '',
|
||||
trigger: {
|
||||
type: 'device'
|
||||
}
|
||||
})
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<Partial<SceneItem>>,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emit>()
|
||||
|
||||
const title = computed(() => {
|
||||
return props.data?.id ? '编辑' : '新增'
|
||||
})
|
||||
|
||||
const disabled = computed(() => {
|
||||
return !!props.data?.id
|
||||
})
|
||||
|
||||
const handleOk = async () => {
|
||||
if (formRef.value) {
|
||||
const values = await formRef.value.validateFields()
|
||||
let modelObj = { ...values }
|
||||
if (props.data.id) {
|
||||
modelObj = {
|
||||
...props.data,
|
||||
name: values.name
|
||||
}
|
||||
}
|
||||
loading.value = true
|
||||
const resp = props.data.id ? await modify(props.data.id, modelObj) : await save(modelObj)
|
||||
loading.value = false
|
||||
if (resp.success) {
|
||||
emit('close')
|
||||
const _id = props.data?.id || (resp.result as any).id
|
||||
menuStory.jumpPage('rule-engine/Scene/Save', {}, { triggerType: values.trigger.type, id: _id })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -5,13 +5,24 @@
|
|||
/>
|
||||
<j-table
|
||||
:columns='columns'
|
||||
/>
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="visible = true">新增</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</j-table>
|
||||
<SaveModal v-if='visible' @close='visible = false'/>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
|
||||
import SaveModal from './Save/save.vue'
|
||||
import type { SceneItem } from './typings'
|
||||
import { useMenuStore } from 'store/menu'
|
||||
|
||||
const menuStory = useMenuStore()
|
||||
const visible = ref<boolean>(false)
|
||||
|
||||
const columns = [
|
||||
{
|
||||
|
@ -52,6 +63,24 @@ const columns = [
|
|||
}
|
||||
}
|
||||
]
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param id
|
||||
* @param triggerType 触发类型
|
||||
*/
|
||||
const handleEdit = (id: string, triggerType: string) => {
|
||||
menuStory.jumpPage('Scene/Save', { }, { triggerType: triggerType, id, type: 'edit' })
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
* @param id
|
||||
* @param triggerType 触发类型
|
||||
*/
|
||||
const handleView = (id: string, triggerType: string) => {
|
||||
menuStory.jumpPage('Scene/Save', { }, { triggerType: triggerType, id, type: 'view' })
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
export const keyByLabel = {
|
||||
manual: '手动触发',
|
||||
timer: '定时触发',
|
||||
device: '设备触发',
|
||||
}
|
||||
|
||||
type State = {
|
||||
value: string;
|
||||
text: string;
|
||||
|
|
Loading…
Reference in New Issue