refactor: events meta app support custom common events and components (#586)
* refactor: events meta app support custom common events and components * refactor: 事件绑定弹窗提取面板左右两部分组件 * fix: remove unnecessary imports * fix: remove empty function * refactor: rename component name * fix: fix theme imports * refactor: import self meta id
This commit is contained in:
parent
38f7ca58e4
commit
3258b26c2b
|
@ -12,8 +12,18 @@
|
|||
|
||||
import entry from './src/Main.vue'
|
||||
import metaData from './meta'
|
||||
import { commonEvents } from './src/commonjs/events.js'
|
||||
import BindEventsDialogContent from './src/components/BindEventsDialogContent.vue'
|
||||
import BindEventsDialogSidebar from './src/components/BindEventsDialogSidebar.vue'
|
||||
|
||||
export default {
|
||||
...metaData,
|
||||
entry
|
||||
entry,
|
||||
options: {
|
||||
commonEvents
|
||||
},
|
||||
components: {
|
||||
BindEventsDialogSidebar,
|
||||
BindEventsDialogContent
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,11 +87,11 @@
|
|||
<script>
|
||||
import { computed, reactive, watchEffect } from 'vue'
|
||||
import { Popover, Button } from '@opentiny/vue'
|
||||
import { useCanvas, useModal, useLayout, useBlock, useResource } from '@opentiny/tiny-engine-controller'
|
||||
import { useModal } from '@opentiny/tiny-engine-controller'
|
||||
import { getMergeMeta, useCanvas, useLayout, useBlock, useResource } from '@opentiny/tiny-engine-entry'
|
||||
import { BlockLinkEvent, SvgButton } from '@opentiny/tiny-engine-common'
|
||||
import { iconHelpQuery, iconChevronDown } from '@opentiny/vue-icon'
|
||||
import BindEventsDialog, { open as openDialog } from './BindEventsDialog.vue'
|
||||
import { commonEvents } from '../commonjs/events.js'
|
||||
import AddEventsDialog from './AddEventsDialog.vue'
|
||||
|
||||
export default {
|
||||
|
@ -115,6 +115,8 @@ export default {
|
|||
|
||||
const { highlightMethod } = getPluginApi(PLUGIN_NAME.PageController)
|
||||
|
||||
const { commonEvents = {} } = getMergeMeta('engine.setting.event').options
|
||||
|
||||
const state = reactive({
|
||||
eventName: '', // 事件名称
|
||||
eventBinding: null, // 事件绑定的处理方法对象
|
||||
|
@ -131,7 +133,7 @@ export default {
|
|||
const componentName = pageState?.currentSchema?.componentName
|
||||
const componentSchema = getMaterial(componentName)
|
||||
state.componentEvent = componentSchema?.content?.schema?.events || componentSchema?.schema?.events || {}
|
||||
Object.assign(state.componentEvents, state.componentEvent)
|
||||
state.componentEvents = { ...commonEvents, ...state.componentEvent }
|
||||
const props = pageState?.currentSchema?.props || {}
|
||||
const keys = Object.keys(props)
|
||||
state.bindActions = {}
|
||||
|
|
|
@ -8,72 +8,8 @@
|
|||
@opened="openedDialog"
|
||||
>
|
||||
<div class="bind-event-dialog-content">
|
||||
<div class="dialog-content-left">
|
||||
<div class="left-title">响应方法</div>
|
||||
<div class="left-list-wrap">
|
||||
<div class="left-action-list">
|
||||
<tiny-search v-model="state.searchValue" placeholder="搜索"></tiny-search>
|
||||
<ul class="action-list-wrap">
|
||||
<li v-for="item in state.filterMethodList" :key="item.name" @click="selectMethod(item)">
|
||||
<div :class="['action-name', { active: item.name === state.bindMethodInfo.name }]">
|
||||
{{ item.title || item.name }}
|
||||
<icon-yes v-if="item.name === state.bindMethodInfo.name" class="action-selected-icon"></icon-yes>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-right">
|
||||
<div :class="['content-right-top', { 'tip-error': state.tipError }]">
|
||||
<div class="content-right-title">方法名称</div>
|
||||
<tiny-input
|
||||
v-model="state.bindMethodInfo.name"
|
||||
:disabled="state.bindMethodInfo.type !== NEW_METHOD_TYPE"
|
||||
:class="[{ 'status-error': state.tipError }]"
|
||||
placeholder="请从左侧选择一个方法进行绑定,或者选择添加新方法,输入自定义方法名称。"
|
||||
@update:modelValue="change"
|
||||
></tiny-input>
|
||||
<div class="new-action-tip">{{ state.tip }}</div>
|
||||
</div>
|
||||
<div :class="['content-right-bottom', { 'tip-error': !state.isValidParams }]">
|
||||
<div class="content-right-title">
|
||||
<span class="set-params-tip">扩展参数设置</span>
|
||||
<tiny-popover placement="top-start" width="350" trigger="hover">
|
||||
<template #reference>
|
||||
<icon-help-query></icon-help-query>
|
||||
</template>
|
||||
<p>
|
||||
扩展参数:调用当前事件传入的真实参数,数组格式,追加在原有事件参数之后<br />
|
||||
如:
|
||||
{{ state.bindMethodInfo.name }}(eventArgs, extParam1, extParam2, ...)
|
||||
</p>
|
||||
</tiny-popover>
|
||||
|
||||
<tiny-switch v-model="state.enableExtraParams" class="set-switch" :show-text="true">
|
||||
<template #open>
|
||||
<span>开启</span>
|
||||
</template>
|
||||
<template #close>
|
||||
<span>关闭</span>
|
||||
</template>
|
||||
</tiny-switch>
|
||||
</div>
|
||||
<div class="content-right-monaco">
|
||||
<monaco-editor
|
||||
v-if="dialogVisible"
|
||||
ref="editor"
|
||||
:value="state.editorContent"
|
||||
:options="editorOptions"
|
||||
class="monaco-editor"
|
||||
/>
|
||||
<div v-if="!state.enableExtraParams" class="mark"></div>
|
||||
</div>
|
||||
<div v-if="!state.isValidParams && state.enableExtraParams" class="params-tip">
|
||||
请输入数组格式的参数,参数可以为表达式。例如:["extParam1", "item.status", 1, "getNames()"]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<component :is="BindEventsDialogSidebar" :eventBinding="eventBinding"></component>
|
||||
<component :is="BindEventsDialogContent" :dialogVisible="dialogVisible"></component>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="bind-dialog-footer">
|
||||
|
@ -85,12 +21,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, watchEffect, nextTick } from 'vue'
|
||||
import { VueMonaco } from '@opentiny/tiny-engine-common'
|
||||
import { Button, DialogBox, Input, Search, Popover, Switch } from '@opentiny/vue'
|
||||
import { useCanvas, useHistory, useLayout } from '@opentiny/tiny-engine-controller'
|
||||
import { string2Ast, ast2String } from '@opentiny/tiny-engine-controller/js/ast'
|
||||
import { iconYes, iconHelpQuery } from '@opentiny/vue-icon'
|
||||
import { ast2String, string2Ast } from '@opentiny/tiny-engine-controller/js/ast'
|
||||
import { getMergeMeta, useCanvas, useHistory, useLayout } from '@opentiny/tiny-engine-entry'
|
||||
import { Button, DialogBox } from '@opentiny/vue'
|
||||
import { nextTick, provide, reactive, ref } from 'vue'
|
||||
import { METHOD_TIPS_MAP } from './constants'
|
||||
import meta from '../../meta'
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
|
||||
|
@ -102,28 +38,10 @@ export const close = () => {
|
|||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
const NEW_METHOD_TYPE = 'newMethod'
|
||||
const invalidVarNameCharRE = /[^0-9a-zA-Z_$]/
|
||||
const validVarNameRE = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/
|
||||
|
||||
const METHOD_TIPS_MAP = {
|
||||
default: '选择已有方法或者添加新方法(点击 确定 之后将在JS面板中创建一个该名称的新方法)',
|
||||
exist: '方法名称已存在',
|
||||
ruleInvalid: '请输入有效的方法名,可以由字母、数字、下划线、$ 符号组成,不能以数字开头',
|
||||
empty: '方法名称不能为空'
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MonacoEditor: VueMonaco,
|
||||
TinyInput: Input,
|
||||
TinyButton: Button,
|
||||
TinySearch: Search,
|
||||
TinyPopover: Popover,
|
||||
TinyDialogBox: DialogBox,
|
||||
IconYes: iconYes(),
|
||||
IconHelpQuery: iconHelpQuery(),
|
||||
TinySwitch: Switch
|
||||
TinyDialogBox: DialogBox
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
|
@ -133,73 +51,22 @@ export default {
|
|||
}
|
||||
},
|
||||
setup(props) {
|
||||
const { BindEventsDialogSidebar, BindEventsDialogContent } = getMergeMeta(meta.id).components
|
||||
|
||||
const { PLUGIN_NAME, getPluginApi, activePlugin } = useLayout()
|
||||
const { pageState } = useCanvas()
|
||||
const { getMethodNameList, getMethods, saveMethod, highlightMethod } = getPluginApi(PLUGIN_NAME.PageController)
|
||||
|
||||
const editor = ref(null)
|
||||
const { getMethods, saveMethod, highlightMethod } = getPluginApi(PLUGIN_NAME.PageController)
|
||||
|
||||
const state = reactive({
|
||||
searchValue: '',
|
||||
editorContent: '',
|
||||
bindMethodInfo: {},
|
||||
filterMethodList: [],
|
||||
tip: METHOD_TIPS_MAP.default,
|
||||
tipError: false,
|
||||
enableExtraParams: false,
|
||||
isValidParams: true
|
||||
})
|
||||
|
||||
const editorOptions = {
|
||||
language: 'json',
|
||||
lineNumbers: false,
|
||||
minimap: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
const generateMethodName = (nameList, eventName) => {
|
||||
const max = nameList
|
||||
.map((name) => Number.parseInt(name.match(/\d+$/)?.[0]) || 0)
|
||||
.sort((a, b) => a - b)
|
||||
.pop()
|
||||
|
||||
const functionName = eventName?.replace(invalidVarNameCharRE, '_') || ''
|
||||
let name = `${functionName}New`
|
||||
|
||||
if (max > -1) {
|
||||
name += `${max + 1}`
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
const eventName = props.eventBinding?.eventName
|
||||
const nameList = getMethodNameList?.().filter((action) => action.indexOf(eventName) > -1) || []
|
||||
const newMethodName = generateMethodName(nameList, eventName)
|
||||
|
||||
const newMethod = {
|
||||
title: '添加新方法',
|
||||
name: newMethodName,
|
||||
type: NEW_METHOD_TYPE
|
||||
}
|
||||
|
||||
if (props.eventBinding?.ref) {
|
||||
state.bindMethodInfo = {
|
||||
name: props.eventBinding.ref
|
||||
}
|
||||
} else {
|
||||
state.bindMethodInfo = newMethod
|
||||
}
|
||||
|
||||
const methodList =
|
||||
getMethodNameList?.()
|
||||
.filter((item) => item.indexOf(state.searchValue) > -1)
|
||||
.map((name) => ({ name })) || []
|
||||
|
||||
state.filterMethodList = [newMethod, ...methodList]
|
||||
})
|
||||
provide('context', state)
|
||||
|
||||
const selectMethod = (data) => {
|
||||
state.bindMethodInfo = data
|
||||
|
@ -243,40 +110,14 @@ export default {
|
|||
const resetTipError = () => {
|
||||
state.tipError = false
|
||||
state.tip = METHOD_TIPS_MAP.default
|
||||
}
|
||||
|
||||
const validMethodNameEmpty = (name) => !name
|
||||
|
||||
const validMethodNameExist = (name) => getMethodNameList?.().includes(name)
|
||||
|
||||
const invalidMethodName = (name) => !validVarNameRE.test(name)
|
||||
|
||||
const change = (value) => {
|
||||
const validRules = [
|
||||
{ validator: validMethodNameEmpty, tip: METHOD_TIPS_MAP.empty },
|
||||
{ validator: validMethodNameExist, tip: METHOD_TIPS_MAP.exist },
|
||||
{ validator: invalidMethodName, tip: METHOD_TIPS_MAP.ruleInvalid }
|
||||
]
|
||||
for (let i = 0; i < validRules.length; i++) {
|
||||
const rule = validRules[i]
|
||||
if (rule.validator(value)) {
|
||||
state.tipError = true
|
||||
state.tip = rule.tip
|
||||
|
||||
// 若存在校验不通过的,则直接返回,不继续走下面的流程
|
||||
return
|
||||
}
|
||||
}
|
||||
state.tipError = false
|
||||
state.tip = METHOD_TIPS_MAP.default
|
||||
state.isValidParams = true
|
||||
}
|
||||
|
||||
const getExtraParams = () => {
|
||||
let extraParams = ''
|
||||
if (state.enableExtraParams) {
|
||||
try {
|
||||
const inputParams = editor.value?.getEditor().getValue()
|
||||
extraParams = JSON.parse(inputParams)
|
||||
extraParams = JSON.parse(state.editorContent)
|
||||
state.isValidParams = Array.isArray(extraParams)
|
||||
} catch (error) {
|
||||
state.isValidParams = false
|
||||
|
@ -365,12 +206,10 @@ export default {
|
|||
}
|
||||
|
||||
return {
|
||||
NEW_METHOD_TYPE,
|
||||
BindEventsDialogSidebar,
|
||||
BindEventsDialogContent,
|
||||
state,
|
||||
editor,
|
||||
editorOptions,
|
||||
dialogVisible,
|
||||
change,
|
||||
confirm,
|
||||
closeDialog,
|
||||
openedDialog,
|
||||
|
@ -384,111 +223,5 @@ export default {
|
|||
.bind-event-dialog-content {
|
||||
display: flex;
|
||||
min-width: 700px;
|
||||
|
||||
.dialog-content-left {
|
||||
margin-right: 30px;
|
||||
width: 30%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.left-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.left-list-wrap {
|
||||
border: 1px solid var(--ti-lowcode-bind-event-dialog-content-left-border-color);
|
||||
border-radius: 4px;
|
||||
height: 300px;
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
.left-action-list {
|
||||
flex: 1;
|
||||
padding: 12px;
|
||||
.action-list-wrap {
|
||||
height: 250px;
|
||||
margin-top: 8px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.action-name {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
background: var(--ti-lowcode-bind-event-dialog-content-left-list-item-active-bg-color);
|
||||
}
|
||||
|
||||
.action-selected-icon {
|
||||
font-size: 14px;
|
||||
color: var(--ti-lowcode-bind-event-dialog-action-selected-icon-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-right {
|
||||
width: 68%;
|
||||
|
||||
.content-right-top {
|
||||
.new-action-tip {
|
||||
margin: 8px 0;
|
||||
color: var(--ti-lowcode-bind-event-dialog-new-action-tip-color);
|
||||
}
|
||||
}
|
||||
.content-right-bottom {
|
||||
.content-right-monaco {
|
||||
border: 1px solid var(--ti-lowcode-bind-event-dialog-content-right-monaco-border-color);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.monaco-editor {
|
||||
width: 100%;
|
||||
height: 216px;
|
||||
padding: 12px 8px;
|
||||
color: var(--ti-lowcode-toolbar-breadcrumb-color);
|
||||
}
|
||||
.mark {
|
||||
width: 100%;
|
||||
height: 216px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
background-color: var(--ti-lowcode-bind-event-dialog-mark-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
.params-tip {
|
||||
margin: 8px 0;
|
||||
color: var(--ti-lowcode-error-tip-color);
|
||||
}
|
||||
}
|
||||
.content-right-top .content-right-title,
|
||||
.content-right-bottom .content-right-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 12px;
|
||||
.set-params-tip {
|
||||
margin-right: 3px;
|
||||
}
|
||||
.set-switch {
|
||||
width: 60px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.tip-error {
|
||||
.content-right-monaco {
|
||||
border: 1px solid var(--ti-lowcode-error-tip-color);
|
||||
}
|
||||
.params-tip,
|
||||
.new-action-tip {
|
||||
color: var(--ti-lowcode-error-tip-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
<template>
|
||||
<div class="content-right">
|
||||
<div :class="['content-right-top', { 'tip-error': context.tipError }]">
|
||||
<div class="content-right-title">方法名称</div>
|
||||
<tiny-input
|
||||
v-model="context.bindMethodInfo.name"
|
||||
:disabled="context.bindMethodInfo.type !== NEW_METHOD_TYPE"
|
||||
:class="[{ 'status-error': context.tipError }]"
|
||||
placeholder="请从左侧选择一个方法进行绑定,或者选择添加新方法,输入自定义方法名称。"
|
||||
@update:modelValue="change"
|
||||
></tiny-input>
|
||||
<div class="new-action-tip">{{ context.tip }}</div>
|
||||
</div>
|
||||
<div :class="['content-right-bottom', { 'tip-error': !context.isValidParams }]">
|
||||
<div class="content-right-title">
|
||||
<span class="set-params-tip">扩展参数设置</span>
|
||||
<tiny-popover placement="top-start" width="350" trigger="hover">
|
||||
<template #reference>
|
||||
<icon-help-query></icon-help-query>
|
||||
</template>
|
||||
<p>
|
||||
扩展参数:调用当前事件传入的真实参数,数组格式,追加在原有事件参数之后<br />
|
||||
如:
|
||||
{{ context.bindMethodInfo.name }}(eventArgs, extParam1, extParam2, ...)
|
||||
</p>
|
||||
</tiny-popover>
|
||||
|
||||
<tiny-switch v-model="context.enableExtraParams" class="set-switch" :show-text="true">
|
||||
<template #open>
|
||||
<span>开启</span>
|
||||
</template>
|
||||
<template #close>
|
||||
<span>关闭</span>
|
||||
</template>
|
||||
</tiny-switch>
|
||||
</div>
|
||||
<div class="content-right-monaco">
|
||||
<monaco-editor
|
||||
v-if="dialogVisible"
|
||||
:value="context.editorContent"
|
||||
:options="editorOptions"
|
||||
@change="editorContentChange"
|
||||
class="monaco-editor"
|
||||
/>
|
||||
<div v-if="!context.enableExtraParams" class="mark"></div>
|
||||
</div>
|
||||
<div v-if="!context.isValidParams && context.enableExtraParams" class="params-tip">
|
||||
请输入数组格式的参数,参数可以为表达式。例如:["extParam1", "item.status", 1, "getNames()"]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { VueMonaco } from '@opentiny/tiny-engine-common'
|
||||
import { theme } from '@opentiny/tiny-engine-controller/js/monaco'
|
||||
import { useLayout } from '@opentiny/tiny-engine-entry'
|
||||
import { Input, Popover, Switch } from '@opentiny/vue'
|
||||
import { iconHelpQuery } from '@opentiny/vue-icon'
|
||||
import { inject } from 'vue'
|
||||
import { METHOD_TIPS_MAP, NEW_METHOD_TYPE, VALID_VARNAME_RE } from './constants'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MonacoEditor: VueMonaco,
|
||||
TinyInput: Input,
|
||||
TinyPopover: Popover,
|
||||
IconHelpQuery: iconHelpQuery(),
|
||||
TinySwitch: Switch
|
||||
},
|
||||
props: {
|
||||
dialogVisible: Boolean
|
||||
},
|
||||
setup() {
|
||||
const { PLUGIN_NAME, getPluginApi } = useLayout()
|
||||
const { getMethodNameList } = getPluginApi(PLUGIN_NAME.PageController)
|
||||
|
||||
const context = inject('context')
|
||||
|
||||
const editorOptions = {
|
||||
roundedSelection: true,
|
||||
automaticLayout: true,
|
||||
autoIndent: true,
|
||||
language: 'json',
|
||||
formatOnPaste: true,
|
||||
tabSize: 2,
|
||||
theme: theme(),
|
||||
lineNumbers: false,
|
||||
minimap: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
|
||||
const editorContentChange = (content) => {
|
||||
context.editorContent = content
|
||||
}
|
||||
|
||||
const validMethodNameEmpty = (name) => !name
|
||||
|
||||
const validMethodNameExist = (name) => getMethodNameList?.().includes(name)
|
||||
|
||||
const invalidMethodName = (name) => !VALID_VARNAME_RE.test(name)
|
||||
|
||||
const change = (value) => {
|
||||
const validRules = [
|
||||
{ validator: validMethodNameEmpty, tip: METHOD_TIPS_MAP.empty },
|
||||
{ validator: validMethodNameExist, tip: METHOD_TIPS_MAP.exist },
|
||||
{ validator: invalidMethodName, tip: METHOD_TIPS_MAP.ruleInvalid }
|
||||
]
|
||||
for (let i = 0; i < validRules.length; i++) {
|
||||
const rule = validRules[i]
|
||||
if (rule.validator(value)) {
|
||||
context.tipError = true
|
||||
context.tip = rule.tip
|
||||
|
||||
// 若存在校验不通过的,则直接返回,不继续走下面的流程
|
||||
return
|
||||
}
|
||||
}
|
||||
context.tipError = false
|
||||
context.tip = METHOD_TIPS_MAP.default
|
||||
}
|
||||
|
||||
return {
|
||||
NEW_METHOD_TYPE,
|
||||
context,
|
||||
editorOptions,
|
||||
change,
|
||||
editorContentChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.content-right {
|
||||
width: 68%;
|
||||
|
||||
.content-right-top {
|
||||
.new-action-tip {
|
||||
margin: 8px 0;
|
||||
color: var(--ti-lowcode-bind-event-dialog-new-action-tip-color);
|
||||
}
|
||||
}
|
||||
.content-right-bottom {
|
||||
.content-right-monaco {
|
||||
border: 1px solid var(--ti-lowcode-bind-event-dialog-content-right-monaco-border-color);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.monaco-editor {
|
||||
width: 100%;
|
||||
height: 216px;
|
||||
padding: 12px 8px;
|
||||
color: var(--ti-lowcode-toolbar-breadcrumb-color);
|
||||
}
|
||||
.mark {
|
||||
width: 100%;
|
||||
height: 216px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
background-color: var(--ti-lowcode-bind-event-dialog-mark-bg-color);
|
||||
}
|
||||
}
|
||||
|
||||
.params-tip {
|
||||
margin: 8px 0;
|
||||
color: var(--ti-lowcode-error-tip-color);
|
||||
}
|
||||
}
|
||||
.content-right-top .content-right-title,
|
||||
.content-right-bottom .content-right-title {
|
||||
font-weight: 600;
|
||||
margin-bottom: 12px;
|
||||
.set-params-tip {
|
||||
margin-right: 3px;
|
||||
}
|
||||
.set-switch {
|
||||
width: 60px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.tip-error {
|
||||
.content-right-monaco {
|
||||
border: 1px solid var(--ti-lowcode-error-tip-color);
|
||||
}
|
||||
.params-tip,
|
||||
.new-action-tip {
|
||||
color: var(--ti-lowcode-error-tip-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,148 @@
|
|||
<template>
|
||||
<div class="dialog-content-left">
|
||||
<div class="left-title">响应方法</div>
|
||||
<div class="left-list-wrap">
|
||||
<div class="left-action-list">
|
||||
<tiny-search v-model="searchValue" placeholder="搜索"></tiny-search>
|
||||
<ul class="action-list-wrap">
|
||||
<li v-for="item in filteredMethodList" :key="item.name" @click="selectMethod(item)">
|
||||
<div :class="['action-name', { active: item.name === context.bindMethodInfo.name }]">
|
||||
{{ item.title || item.name }}
|
||||
<icon-yes v-if="item.name === context.bindMethodInfo.name" class="action-selected-icon"></icon-yes>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useLayout } from '@opentiny/tiny-engine-entry'
|
||||
import { Search } from '@opentiny/vue'
|
||||
import { iconYes } from '@opentiny/vue-icon'
|
||||
import { inject, ref, watchEffect } from 'vue'
|
||||
import { INVALID_VARNAME_CHAR_RE, NEW_METHOD_TYPE } from './constants'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TinySearch: Search,
|
||||
IconYes: iconYes()
|
||||
},
|
||||
props: {
|
||||
eventBinding: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const { PLUGIN_NAME, getPluginApi } = useLayout()
|
||||
const { getMethodNameList } = getPluginApi(PLUGIN_NAME.PageController)
|
||||
|
||||
const searchValue = ref('')
|
||||
const filteredMethodList = ref([])
|
||||
const context = inject('context')
|
||||
|
||||
const generateMethodName = (nameList, eventName) => {
|
||||
const max = nameList
|
||||
.map((name) => Number.parseInt(name.match(/\d+$/)?.[0]) || 0)
|
||||
.sort((a, b) => a - b)
|
||||
.pop()
|
||||
|
||||
const functionName = eventName?.replace(INVALID_VARNAME_CHAR_RE, '_') || ''
|
||||
let name = `${functionName}New`
|
||||
|
||||
if (max > -1) {
|
||||
name += `${max + 1}`
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
const selectMethod = (data) => {
|
||||
context.bindMethodInfo = data
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
const eventName = props.eventBinding?.eventName
|
||||
|
||||
const nameList = getMethodNameList?.().filter((action) => action.includes(eventName)) || []
|
||||
const newMethodName = generateMethodName(nameList, eventName)
|
||||
|
||||
const newMethod = {
|
||||
title: '添加新方法',
|
||||
name: newMethodName,
|
||||
type: NEW_METHOD_TYPE
|
||||
}
|
||||
|
||||
if (props.eventBinding?.ref) {
|
||||
selectMethod({ name: props.eventBinding.ref })
|
||||
} else {
|
||||
selectMethod(newMethod)
|
||||
}
|
||||
|
||||
const methodList =
|
||||
getMethodNameList?.()
|
||||
.filter((item) => item.includes(searchValue.value))
|
||||
.map((name) => ({ name })) || []
|
||||
|
||||
filteredMethodList.value = [newMethod, ...methodList]
|
||||
})
|
||||
|
||||
return {
|
||||
context,
|
||||
searchValue,
|
||||
filteredMethodList,
|
||||
selectMethod
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.dialog-content-left {
|
||||
margin-right: 30px;
|
||||
width: 30%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.left-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.left-list-wrap {
|
||||
border: 1px solid var(--ti-lowcode-bind-event-dialog-content-left-border-color);
|
||||
border-radius: 4px;
|
||||
height: 300px;
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
.left-action-list {
|
||||
flex: 1;
|
||||
padding: 12px;
|
||||
.action-list-wrap {
|
||||
height: 250px;
|
||||
margin-top: 8px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.action-name {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
background: var(--ti-lowcode-bind-event-dialog-content-left-list-item-active-bg-color);
|
||||
}
|
||||
|
||||
.action-selected-icon {
|
||||
font-size: 14px;
|
||||
color: var(--ti-lowcode-bind-event-dialog-action-selected-icon-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,10 @@
|
|||
export const NEW_METHOD_TYPE = 'newMethod'
|
||||
export const INVALID_VARNAME_CHAR_RE = /[^0-9a-zA-Z_$]/
|
||||
export const VALID_VARNAME_RE = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/
|
||||
|
||||
export const METHOD_TIPS_MAP = {
|
||||
default: '选择已有方法或者添加新方法(点击 确定 之后将在JS面板中创建一个该名称的新方法)',
|
||||
exist: '方法名称已存在',
|
||||
ruleInvalid: '请输入有效的方法名,可以由字母、数字、下划线、$ 符号组成,不能以数字开头',
|
||||
empty: '方法名称不能为空'
|
||||
}
|
Loading…
Reference in New Issue