forked from opentiny/tiny-engine
Merge remote-tracking branch 'origin/develop' into release-v2.4.0-merge
This commit is contained in:
commit
ed7916d641
|
|
@ -1,71 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"jsx": "react",
|
||||
"paths": {
|
||||
"@/*": ["packages/*"],
|
||||
"@opentiny/tiny-engine": ["packages/design-core/index.js"],
|
||||
"@opentiny/tiny-engine-meta-register": ["packages/register/src/index.js"],
|
||||
"@opentiny/tiny-engine-canvas": ["packages/canvas/src/index"],
|
||||
"@opentiny/tiny-engine-plugin-materials": ["packages/plugins/materials/index"],
|
||||
"@opentiny/tiny-engine-plugin-state": ["packages/plugins/state/index"],
|
||||
"@opentiny/tiny-engine-plugin-script": ["packages/plugins/script/index"],
|
||||
"@opentiny/tiny-engine-plugin-tree": ["packages/plugins/tree/index"],
|
||||
"@opentiny/tiny-engine-plugin-help": ["packages/plugins/help/index"],
|
||||
"@opentiny/tiny-engine-plugin-schema": ["packages/plugins/schema/index"],
|
||||
"@opentiny/tiny-engine-plugin-page": ["packages/plugins/page/index"],
|
||||
"@opentiny/tiny-engine-plugin-i18n": ["packages/plugins/i18n/index"],
|
||||
"@opentiny/tiny-engine-plugin-bridge": ["packages/plugins/bridge/index"],
|
||||
"@opentiny/tiny-engine-setting-events": ["packages/settings/events/index"],
|
||||
"@opentiny/tiny-engine-setting-props": ["packages/settings/props/index"],
|
||||
"@opentiny/tiny-engine-common": ["packages/common/index"],
|
||||
"@opentiny/tiny-engine-setting-styles": ["packages/settings/styles/index"],
|
||||
"@opentiny/tiny-engine-toolbar-breadcrumb": ["packages/toolbars/breadcrumb/index"],
|
||||
"@opentiny/tiny-engine-toolbar-fullscreen": ["packages/toolbars/fullscreen/index"],
|
||||
"@opentiny/tiny-engine-toolbar-lang": ["packages/toolbars/lang/index"],
|
||||
"@opentiny/tiny-engine-toolbar-view-setting": ["packages/toolbars/view-setting/index"],
|
||||
"@opentiny/tiny-engine-toolbar-layout": ["packages/toolbars/layout/index"],
|
||||
"@opentiny/tiny-engine-toolbar-lock": ["packages/toolbars/lock/index"],
|
||||
"@opentiny/tiny-engine-toolbar-logo": ["packages/toolbars/logo/index"],
|
||||
"@opentiny/tiny-engine-toolbar-media": ["packages/toolbars/media/index"],
|
||||
"@opentiny/tiny-engine-toolbar-preview": ["packages/toolbars/preview/index"],
|
||||
"@opentiny/tiny-engine-toolbar-generate-code": ["packages/toolbars/generate-code/index"],
|
||||
"@opentiny/tiny-engine-toolbar-clean": ["packages/toolbars/clean/index"],
|
||||
"@opentiny/tiny-engine-toolbar-theme-switch": ["packages/toolbars/themeSwitch/index"],
|
||||
"@opentiny/tiny-engine-toolbar-save": ["packages/toolbars/save/index"],
|
||||
"tiny-engine-canvas": ["packages/canvas/index"],
|
||||
"@opentiny/tiny-engine-svgs": ["packages/svgs/index"],
|
||||
"@opentiny/tiny-engine-plugin-materials/*": ["packages/plugins/materials/*"],
|
||||
"@opentiny/tiny-engine-plugin-state/*": ["packages/plugins/state/*"],
|
||||
"@opentiny/tiny-engine-plugin-script/*": ["packages/plugins/script/*"],
|
||||
"@opentiny/tiny-engine-plugin-tree/*": ["packages/plugins/tree/*"],
|
||||
"@opentiny/tiny-engine-plugin-help/*": ["packages/plugins/help/*"],
|
||||
"@opentiny/tiny-engine-plugin-schema/*": ["packages/plugins/schema/*"],
|
||||
"@opentiny/tiny-engine-plugin-page/*": ["packages/plugins/page/*"],
|
||||
"@opentiny/tiny-engine-plugin-i18n/*": ["packages/plugins/i18n/*"],
|
||||
"@opentiny/tiny-engine-plugin-bridge/*": ["packages/plugins/bridge/*"],
|
||||
"@opentiny/tiny-engine-setting-events/*": ["packages/settings/events/*"],
|
||||
"@opentiny/tiny-engine-setting-props/*": ["packages/settings/props/*"],
|
||||
"@opentiny/tiny-engine-common/*": ["packages/common/*"],
|
||||
"@opentiny/tiny-engine-setting-styles/*": ["packages/settings/styles/*"],
|
||||
"@opentiny/tiny-engine-toolbar-breadcrumb/*": ["packages/toolbars/breadcrumb/*"],
|
||||
"@opentiny/tiny-engine-toolbar-fullscreen/*": ["packages/toolbars/fullscreen/*"],
|
||||
"@opentiny/tiny-engine-toolbar-lang/*": ["packages/toolbars/lang/*"],
|
||||
"@opentiny/tiny-engine-toolbar-view-setting/*": ["packages/toolbars/view-setting/*"],
|
||||
"@opentiny/tiny-engine-toolbar-layout/*": ["packages/toolbars/layout/*"],
|
||||
"@opentiny/tiny-engine-toolbar-lock/*": ["packages/toolbars/lock/*"],
|
||||
"@opentiny/tiny-engine-toolbar-logo/*": ["packages/toolbars/logo/*"],
|
||||
"@opentiny/tiny-engine-toolbar-media/*": ["packages/toolbars/media/*"],
|
||||
"@opentiny/tiny-engine-toolbar-preview/*": ["packages/toolbars/preview/*"],
|
||||
"@opentiny/tiny-engine-toolbar-clean/*": ["packages/toolbars/clean/*"],
|
||||
"@opentiny/tiny-engine-toolbar-theme-switch/*": ["packages/toolbars/themeSwitch/*"],
|
||||
"@opentiny/tiny-engine-toolbar-save/*": ["packages/toolbars/save/*"],
|
||||
"@opentiny/tiny-engine-svgs/*": ["packages/svgs/*"],
|
||||
"@opentiny/tiny-engine-utils": ["packages/utils/src/index"],
|
||||
"@opentiny/tiny-engine-webcomponent-core": ["packages/webcomponent/src/lib"],
|
||||
"@opentiny/tiny-engine-i18n-host": ["packages/i18n/src/lib"]
|
||||
}
|
||||
},
|
||||
"include": ["packages/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import type { Node, RootNode } from '../../../types'
|
||||
|
||||
export type PageSchema = RootNode
|
||||
|
||||
export interface PageState {
|
||||
currentVm?: unknown
|
||||
currentSchema?: unknown
|
||||
currentType?: unknown
|
||||
currentPage?: unknown
|
||||
hoverVm?: unknown
|
||||
pageSchema: RootNode | null
|
||||
properties?: unknown
|
||||
dataSource?: unknown
|
||||
dataSourceMap?: unknown
|
||||
isSaved: boolean
|
||||
isLock: boolean
|
||||
isBlock: boolean
|
||||
nodesStatus: Record<string, any>
|
||||
loading: boolean
|
||||
}
|
||||
|
||||
export interface InsertOperation {
|
||||
parentId: string
|
||||
newNodeData: Node
|
||||
position: string
|
||||
referTargetNodeId?: string
|
||||
}
|
||||
|
||||
export interface DeleteOperation {
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface ChangePropsOperation {
|
||||
id: string
|
||||
value: {
|
||||
props?: any
|
||||
}
|
||||
option?: {
|
||||
overwrite?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface UpdateAttributesOperation {
|
||||
id: string
|
||||
value: any
|
||||
overwrite?: boolean
|
||||
}
|
||||
|
||||
export type NodeOperation =
|
||||
| (InsertOperation & { type: 'insert' })
|
||||
| (DeleteOperation & { type: 'delete' })
|
||||
| (ChangePropsOperation & { type: 'changeProps' })
|
||||
| (UpdateAttributesOperation & { type: 'updateAttributes' })
|
||||
|
|
@ -15,14 +15,26 @@ import * as jsonDiffPatch from 'jsondiffpatch'
|
|||
import DiffMatchPatch from 'diff-match-patch'
|
||||
import { constants, utils } from '@opentiny/tiny-engine-utils'
|
||||
import { useHistory, getMetaApi, useMessage } from '@opentiny/tiny-engine-meta-register'
|
||||
import type { canvasApi as CanvasApi } from '../../../container/src/container'
|
||||
import type { Node, RootNode } from '../../../types'
|
||||
import type {
|
||||
ChangePropsOperation,
|
||||
DeleteOperation,
|
||||
InsertOperation,
|
||||
NodeOperation,
|
||||
PageSchema,
|
||||
PageState,
|
||||
UpdateAttributesOperation
|
||||
} from './types'
|
||||
|
||||
const { COMPONENT_NAME } = constants
|
||||
const { deepClone } = utils
|
||||
|
||||
const defaultPageState = {
|
||||
const defaultPageState: PageState = {
|
||||
currentVm: null,
|
||||
currentSchema: null,
|
||||
currentType: null,
|
||||
currentPage: null,
|
||||
pageSchema: null,
|
||||
properties: null,
|
||||
dataSource: null,
|
||||
|
|
@ -34,7 +46,7 @@ const defaultPageState = {
|
|||
loading: false
|
||||
}
|
||||
|
||||
const defaultSchema = {
|
||||
const defaultSchema: PageSchema = {
|
||||
componentName: 'Page',
|
||||
fileName: '',
|
||||
css: '',
|
||||
|
|
@ -53,11 +65,11 @@ const defaultSchema = {
|
|||
outputs: []
|
||||
}
|
||||
|
||||
const canvasApi = ref({})
|
||||
const canvasApi = ref<Partial<typeof CanvasApi>>({})
|
||||
const isCanvasApiReady = ref(false)
|
||||
const nodesMap = ref(new Map())
|
||||
const nodesMap = ref(new Map<string | number, { node: any; parent: any }>())
|
||||
|
||||
const initCanvasApi = (newCanvasApi) => {
|
||||
const initCanvasApi = (newCanvasApi: typeof CanvasApi) => {
|
||||
canvasApi.value = newCanvasApi
|
||||
isCanvasApiReady.value = true
|
||||
}
|
||||
|
|
@ -72,7 +84,7 @@ const rootSchema = ref([
|
|||
}
|
||||
])
|
||||
|
||||
const handleTinyGridColumnsSlots = (node) => {
|
||||
const handleTinyGridColumnsSlots = (node: Node) => {
|
||||
const columns = Array.isArray(node.props?.columns) ? node.props.columns : []
|
||||
for (const columnItem of columns) {
|
||||
if (!columnItem?.slots) {
|
||||
|
|
@ -81,7 +93,7 @@ const handleTinyGridColumnsSlots = (node) => {
|
|||
|
||||
for (const slotItem of Object.values(columnItem.slots)) {
|
||||
if (Array.isArray(slotItem?.value)) {
|
||||
slotItem.value.forEach((item) => {
|
||||
slotItem.value.forEach((item: Node) => {
|
||||
if (!item.id) {
|
||||
item.id = utils.guid()
|
||||
}
|
||||
|
|
@ -98,13 +110,13 @@ const handleTinyGridColumnsSlots = (node) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleNodesInProps = (node) => {
|
||||
const handleNodesInProps = (node: Node) => {
|
||||
if (node.componentName === 'TinyGrid') {
|
||||
handleTinyGridColumnsSlots(node)
|
||||
}
|
||||
}
|
||||
|
||||
const generateNodesMap = (nodes, parent) => {
|
||||
const generateNodesMap = (nodes: Node[], parent: RootNode | Node) => {
|
||||
nodes.forEach((nodeItem) => {
|
||||
if (!nodeItem.id) {
|
||||
nodeItem.id = utils.guid()
|
||||
|
|
@ -124,7 +136,7 @@ const generateNodesMap = (nodes, parent) => {
|
|||
}
|
||||
|
||||
const jsonDiffPatchInstance = jsonDiffPatch.create({
|
||||
objectHash: function (obj, index) {
|
||||
objectHash: function (obj: { fileName?: string; id?: string }, index) {
|
||||
return obj.fileName || obj.id || `$$index:${index}`
|
||||
},
|
||||
arrays: {
|
||||
|
|
@ -135,8 +147,7 @@ const jsonDiffPatchInstance = jsonDiffPatch.create({
|
|||
diffMatchPatch: DiffMatchPatch,
|
||||
minLength: 60
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
propertyFilter: function (name, context) {
|
||||
propertyFilter: function (name) {
|
||||
return name.slice(0, 1) !== '$'
|
||||
},
|
||||
cloneDiffValues: false
|
||||
|
|
@ -145,7 +156,7 @@ const jsonDiffPatchInstance = jsonDiffPatch.create({
|
|||
const { publish } = useMessage()
|
||||
|
||||
// 重置画布数据
|
||||
const resetCanvasState = async (state = {}) => {
|
||||
const resetCanvasState = async (state: Partial<PageState> = {}) => {
|
||||
const previousSchema = JSON.parse(JSON.stringify(pageState.pageSchema))
|
||||
|
||||
Object.assign(pageState, defaultPageState, state)
|
||||
|
|
@ -178,14 +189,14 @@ const resetCanvasState = async (state = {}) => {
|
|||
}
|
||||
|
||||
// 页面重置画布数据
|
||||
const resetPageCanvasState = (state = {}) => {
|
||||
const resetPageCanvasState = (state: Partial<PageState> = {}) => {
|
||||
state.isBlock = false
|
||||
resetCanvasState(state)
|
||||
useHistory().addHistory(state.pageSchema)
|
||||
}
|
||||
|
||||
// 区块重置画布数据
|
||||
const resetBlockCanvasState = async (state = {}) => {
|
||||
const resetBlockCanvasState = async (state: Partial<PageState> = {}) => {
|
||||
state.isBlock = true
|
||||
await resetCanvasState(state)
|
||||
}
|
||||
|
|
@ -225,7 +236,7 @@ const clearCanvas = () => {
|
|||
const isBlock = () => pageState.isBlock
|
||||
|
||||
// 初始化页面数据
|
||||
const initData = (schema = { ...defaultSchema }, currentPage) => {
|
||||
const initData = (schema: PageSchema = { ...defaultSchema }, currentPage: any) => {
|
||||
if (schema.componentName === COMPONENT_NAME.Block) {
|
||||
resetBlockCanvasState({
|
||||
pageSchema: toRaw(schema),
|
||||
|
|
@ -255,7 +266,7 @@ const getPageSchema = () => {
|
|||
return pageState.pageSchema || {}
|
||||
}
|
||||
|
||||
const setCurrentSchema = (schema) => {
|
||||
const setCurrentSchema = (schema: any) => {
|
||||
pageState.currentSchema = schema
|
||||
}
|
||||
|
||||
|
|
@ -269,15 +280,15 @@ const clearCurrentState = () => {
|
|||
}
|
||||
const getCurrentPage = () => pageState.currentPage
|
||||
|
||||
const getNodeById = (id) => {
|
||||
const getNodeById = (id: string) => {
|
||||
return nodesMap.value.get(id)?.node
|
||||
}
|
||||
|
||||
const getNodeWithParentById = (id) => {
|
||||
const getNodeWithParentById = (id: string) => {
|
||||
return nodesMap.value.get(id)
|
||||
}
|
||||
|
||||
const delNode = (id) => {
|
||||
const delNode = (id: string) => {
|
||||
nodesMap.value.delete(id)
|
||||
}
|
||||
|
||||
|
|
@ -285,18 +296,18 @@ const clearNodes = () => {
|
|||
nodesMap.value.clear()
|
||||
}
|
||||
|
||||
const setNode = (schema, parent) => {
|
||||
const setNode = (schema: Node, parent: Node | RootNode) => {
|
||||
schema.id = schema.id || utils.guid()
|
||||
|
||||
nodesMap.value.set(schema.id, { node: schema, parent })
|
||||
}
|
||||
|
||||
const getNode = (id, parent) => {
|
||||
const getNode = (id: string, parent?: boolean) => {
|
||||
return parent ? nodesMap.value.get(id) : nodesMap.value.get(id)?.node
|
||||
}
|
||||
|
||||
const operationTypeMap = {
|
||||
insert: (operation) => {
|
||||
insert: (operation: InsertOperation) => {
|
||||
const { parentId, newNodeData, position, referTargetNodeId } = operation
|
||||
const parentNode = getNode(parentId) || pageState.pageSchema
|
||||
// 1. 确认是否存在 ParentNode
|
||||
|
|
@ -359,7 +370,7 @@ const operationTypeMap = {
|
|||
previous: undefined
|
||||
}
|
||||
},
|
||||
delete: (operation) => {
|
||||
delete: (operation: DeleteOperation) => {
|
||||
const { id } = operation
|
||||
const targetNode = getNode(id, true)
|
||||
|
||||
|
|
@ -398,7 +409,7 @@ const operationTypeMap = {
|
|||
previous: node
|
||||
}
|
||||
},
|
||||
changeProps: (operation) => {
|
||||
changeProps: (operation: ChangePropsOperation) => {
|
||||
const { id, value, option: changeOption } = operation
|
||||
let { node } = getNode(id, true) || {}
|
||||
const previous = deepClone(node)
|
||||
|
|
@ -423,10 +434,10 @@ const operationTypeMap = {
|
|||
previous
|
||||
}
|
||||
},
|
||||
updateAttributes: (operation) => {
|
||||
updateAttributes: (operation: UpdateAttributesOperation) => {
|
||||
const { id, value, overwrite } = operation
|
||||
const { id: _id, children, ...restAttr } = value
|
||||
const node = getNode(id)
|
||||
const node: Node | RootNode = getNode(id)
|
||||
|
||||
// 其他属性直接浅 merge
|
||||
Object.assign(node, restAttr)
|
||||
|
|
@ -466,7 +477,7 @@ const operationTypeMap = {
|
|||
|
||||
const newChildrenSet = new Set(newChildren.map(({ id }) => id))
|
||||
// 被删除的项
|
||||
const deletedIds = originChildrenIds.filter((id) => !newChildrenSet.has(id))
|
||||
const deletedIds = originChildrenIds.filter((id: any) => !newChildrenSet.has(id))
|
||||
const deletedIdsSet = new Set(deletedIds)
|
||||
|
||||
for (const id of deletedIds) {
|
||||
|
|
@ -526,7 +537,7 @@ const lastUpdateType = ref('')
|
|||
* @param {*} operation
|
||||
* @returns
|
||||
*/
|
||||
const operateNode = async (operation) => {
|
||||
const operateNode = async (operation: NodeOperation) => {
|
||||
if (!operationTypeMap[operation.type]) {
|
||||
return
|
||||
}
|
||||
|
|
@ -546,11 +557,11 @@ const operateNode = async (operation) => {
|
|||
}
|
||||
|
||||
// 获取传入的 schema 与最新 schema 的 diff
|
||||
const getSchemaDiff = (schema) => {
|
||||
const getSchemaDiff = (schema: unknown) => {
|
||||
return jsonDiffPatchInstance.diff(schema, pageState.pageSchema)
|
||||
}
|
||||
|
||||
const patchLatestSchema = (schema) => {
|
||||
const patchLatestSchema = (schema: unknown) => {
|
||||
// 这里 pageSchema 需要 deepClone,不然 patch 的时候,会 patch 成同一个引用,造成画布无法更新
|
||||
const diff = jsonDiffPatchInstance.diff(schema, deepClone(pageState.pageSchema))
|
||||
|
||||
|
|
@ -559,7 +570,7 @@ const patchLatestSchema = (schema) => {
|
|||
}
|
||||
}
|
||||
|
||||
const importSchema = (data) => {
|
||||
const importSchema = (data: any) => {
|
||||
let importData = data
|
||||
|
||||
if (typeof data === 'string') {
|
||||
|
|
@ -581,11 +592,11 @@ const exportSchema = () => {
|
|||
return JSON.stringify(pageState.pageSchema)
|
||||
}
|
||||
|
||||
const getSchema = () => {
|
||||
const getSchema = (): RootNode | object => {
|
||||
return pageState.pageSchema || {}
|
||||
}
|
||||
|
||||
const getNodePath = (id, nodes = []) => {
|
||||
const getNodePath = (id: string, nodes: { name: string; node: string }[] = []) => {
|
||||
const { parent, node } = getNodeWithParentById(id) || {}
|
||||
|
||||
if (node) {
|
||||
|
|
@ -601,7 +612,11 @@ const getNodePath = (id, nodes = []) => {
|
|||
return nodes
|
||||
}
|
||||
|
||||
const updateSchema = (data) => {
|
||||
const updateSchema = (data: Partial<PageSchema>) => {
|
||||
if (!pageState.pageSchema) {
|
||||
return
|
||||
}
|
||||
|
||||
Object.assign(pageState.pageSchema, data)
|
||||
|
||||
publish({ topic: 'schemaChange', data: {} })
|
||||
|
|
|
|||
|
|
@ -1,17 +1,30 @@
|
|||
import { ref } from 'vue'
|
||||
import { getDocument, getRect, querySelectById } from '../container'
|
||||
|
||||
export interface MultiSelectedState {
|
||||
id: string
|
||||
left: number
|
||||
height: number
|
||||
top: number
|
||||
width: number
|
||||
componentName: string
|
||||
doc: Document
|
||||
schema: any
|
||||
parent: any
|
||||
type?: string
|
||||
}
|
||||
|
||||
// 初始化多选节点
|
||||
const multiSelectedStates = ref([])
|
||||
const multiSelectedStates = ref<MultiSelectedState[]>([])
|
||||
|
||||
export const useMultiSelect = () => {
|
||||
/**
|
||||
* 添加state到多选列表
|
||||
* @param {*} selectState
|
||||
* @param {boolean} isMultiple 是否多选
|
||||
* @returns {boolean} 添加成功返回true,否则返回false
|
||||
* @param selectState
|
||||
* @param isMultiple 是否多选
|
||||
* @returns 添加成功返回true,否则返回false
|
||||
*/
|
||||
const toggleMultiSelection = (selectState, isMultiple = false) => {
|
||||
const toggleMultiSelection = (selectState: MultiSelectedState, isMultiple = false) => {
|
||||
if (!selectState || typeof selectState !== 'object') {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,18 @@ import { utils } from '@opentiny/tiny-engine-utils'
|
|||
import { isVsCodeEnv } from '@opentiny/tiny-engine-common/js/environments'
|
||||
import Builtin from '../../render/src/builtin/builtin.json' //TODO 画布内外应该分开
|
||||
import { useMultiSelect } from './composables/useMultiSelect'
|
||||
import type { Node, RootNode } from '../../types'
|
||||
|
||||
export interface DragOffset {
|
||||
offsetX: number
|
||||
offsetY: number
|
||||
horizontal: string
|
||||
vertical: string
|
||||
width: number
|
||||
height: number
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
export const POSITION = Object.freeze({
|
||||
TOP: 'top',
|
||||
|
|
@ -38,31 +50,34 @@ export const POSITION = Object.freeze({
|
|||
const initialDragState = {
|
||||
keydown: false,
|
||||
draging: false,
|
||||
data: null,
|
||||
position: null, // ghost位置
|
||||
mouse: null, // iframe里鼠标位置
|
||||
element: null,
|
||||
offset: {}
|
||||
data: null as Node | null,
|
||||
position: null as { left: number; top: number } | null, // ghost位置
|
||||
mouse: {} as { x: number; y: number }, // iframe里鼠标位置
|
||||
element: null as Element | null,
|
||||
offset: {} as DragOffset,
|
||||
timer: 0
|
||||
}
|
||||
|
||||
export const canvasState = shallowReactive({
|
||||
type: 'normal',
|
||||
schema: null,
|
||||
renderer: null, // 存放画布内的api
|
||||
iframe: null,
|
||||
renderer: null as any, // 存放画布内的api
|
||||
iframe: {} as HTMLIFrameElement,
|
||||
loading: true,
|
||||
current: null,
|
||||
parent: null,
|
||||
loopId: null
|
||||
current: null as any,
|
||||
parent: null as any,
|
||||
loopId: null as string | null,
|
||||
controller: null as any,
|
||||
emit: null as any
|
||||
})
|
||||
|
||||
export const getRenderer = () => canvasState.renderer
|
||||
|
||||
export const getController = () => canvasState.controller
|
||||
|
||||
export const getDocument = () => canvasState.iframe.contentDocument
|
||||
export const getDocument = () => canvasState.iframe.contentDocument!
|
||||
|
||||
export const getWindow = () => canvasState.iframe.contentWindow
|
||||
export const getWindow = () => canvasState.iframe.contentWindow!
|
||||
|
||||
export const getCurrent = () => {
|
||||
return {
|
||||
|
|
@ -74,7 +89,7 @@ export const getCurrent = () => {
|
|||
|
||||
export const getDesignMode = () => getRenderer()?.getDesignMode()
|
||||
|
||||
export const setDesignMode = (mode) => getRenderer()?.setDesignMode(mode)
|
||||
export const setDesignMode = (mode: string) => getRenderer()?.setDesignMode(mode)
|
||||
|
||||
export const getSchema = () => useCanvas().getPageSchema()
|
||||
|
||||
|
|
@ -103,7 +118,8 @@ const initialLineState = {
|
|||
forbidden: false,
|
||||
id: '',
|
||||
config: null,
|
||||
doc: null
|
||||
doc: null,
|
||||
configure: null
|
||||
}
|
||||
|
||||
// 鼠标移入画布中元素时的状态
|
||||
|
|
@ -136,14 +152,14 @@ export const clearSelect = () => {
|
|||
}
|
||||
|
||||
const smoothScroll = {
|
||||
timmer: null,
|
||||
timmer: undefined as ReturnType<typeof setTimeout> | undefined,
|
||||
/**
|
||||
*
|
||||
* @param {*} up 方向
|
||||
* @param {*} step 每次滚动距离
|
||||
* @param {*} time 滚动延时(不得大于系统滚动时长,否则可能出现卡顿效果)
|
||||
* @param {boolean} up 方向
|
||||
* @param {number} step 每次滚动距离
|
||||
* @param {number} time 滚动延时(不得大于系统滚动时长,否则可能出现卡顿效果)
|
||||
*/
|
||||
start(up, step = 40, time = 100) {
|
||||
start(up: boolean, step = 40, time = 100) {
|
||||
const dom = getDocument().documentElement
|
||||
const fn = () => {
|
||||
const top = up ? dom.scrollTop + step : dom.scrollTop - step
|
||||
|
|
@ -158,14 +174,14 @@ const smoothScroll = {
|
|||
},
|
||||
stop() {
|
||||
clearTimeout(this.timmer)
|
||||
this.timmer = null
|
||||
this.timmer = undefined
|
||||
}
|
||||
}
|
||||
|
||||
export const dragStart = (
|
||||
data,
|
||||
element,
|
||||
{ offsetX = 0, offsetY = 0, horizontal, vertical, width, height, x, y } = {}
|
||||
data: Node,
|
||||
element: Element,
|
||||
{ offsetX = 0, offsetY = 0, horizontal, vertical, width, height, x, y } = {} as DragOffset
|
||||
) => {
|
||||
// 表示鼠标按下开始拖拽
|
||||
dragState.keydown = true
|
||||
|
|
@ -188,8 +204,8 @@ export const dragEnd = () => {
|
|||
const { element, data } = dragState
|
||||
|
||||
if (element && canvasState.type === 'absolute') {
|
||||
data.props = data.props || {}
|
||||
data.props.style = element.style.cssText
|
||||
data!.props = data!.props || {}
|
||||
data!.props.style = element.style.cssText
|
||||
|
||||
getController().addHistory()
|
||||
}
|
||||
|
|
@ -202,15 +218,19 @@ export const dragEnd = () => {
|
|||
smoothScroll.stop()
|
||||
}
|
||||
|
||||
export const getOffset = (element) => {
|
||||
export const getOffset = (element: Element) => {
|
||||
if (element.ownerDocument === document) {
|
||||
return { x: 0, y: 0 }
|
||||
return { x: 0, y: 0, bottom: 0, top: 0 }
|
||||
}
|
||||
const { x, y, bottom, top } = canvasState.iframe.getBoundingClientRect()
|
||||
return { x, y, bottom, top }
|
||||
}
|
||||
|
||||
export const getElement = (element) => {
|
||||
export const getElement = (element?: Element): Element | undefined => {
|
||||
if (!element || element.nodeType !== 1) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
// 如果当前元素是body
|
||||
if (element === element.ownerDocument.body) {
|
||||
return element
|
||||
|
|
@ -221,10 +241,6 @@ export const getElement = (element) => {
|
|||
return element.ownerDocument.body
|
||||
}
|
||||
|
||||
if (!element || element.nodeType !== 1) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (element.getAttribute(NODE_UID)) {
|
||||
return element
|
||||
} else if (element.parentElement) {
|
||||
|
|
@ -234,7 +250,7 @@ export const getElement = (element) => {
|
|||
return undefined
|
||||
}
|
||||
|
||||
export const getInactiveElement = (element) => {
|
||||
export const getInactiveElement = (element?: Element): Element | undefined => {
|
||||
if (
|
||||
!element ||
|
||||
element.nodeType !== 1 ||
|
||||
|
|
@ -256,7 +272,7 @@ export const getInactiveElement = (element) => {
|
|||
return undefined
|
||||
}
|
||||
|
||||
export const getRect = (element) => {
|
||||
export const getRect = (element: Element) => {
|
||||
if (element === getDocument().body) {
|
||||
const { innerWidth: width, innerHeight: height } = getWindow()
|
||||
return {
|
||||
|
|
@ -273,48 +289,54 @@ export const getRect = (element) => {
|
|||
return element.getBoundingClientRect()
|
||||
}
|
||||
|
||||
const insertAfter = ({ parent, node, data }) => {
|
||||
interface InsertOptions {
|
||||
parent: Node | RootNode
|
||||
node: Node | RootNode
|
||||
data: Node
|
||||
}
|
||||
|
||||
const insertAfter = ({ parent, node, data }: InsertOptions) => {
|
||||
if (!data.id) {
|
||||
data.id = utils.guid()
|
||||
}
|
||||
|
||||
useCanvas().operateNode({
|
||||
type: 'insert',
|
||||
parentId: parent.id,
|
||||
parentId: parent.id || '',
|
||||
newNodeData: data,
|
||||
position: 'after',
|
||||
referTargetNodeId: node.id
|
||||
})
|
||||
}
|
||||
|
||||
const insertBefore = ({ parent, node, data }) => {
|
||||
const insertBefore = ({ parent, node, data }: InsertOptions) => {
|
||||
if (!data.id) {
|
||||
data.id = utils.guid()
|
||||
}
|
||||
|
||||
useCanvas().operateNode({
|
||||
type: 'insert',
|
||||
parentId: parent.id,
|
||||
parentId: parent.id || '',
|
||||
newNodeData: data,
|
||||
position: 'before',
|
||||
referTargetNodeId: node.id
|
||||
})
|
||||
}
|
||||
|
||||
const insertInner = ({ node, data }, position) => {
|
||||
const insertInner = ({ node, data }: Omit<InsertOptions, 'parent'>, position: string = '') => {
|
||||
if (!data.id) {
|
||||
data.id = utils.guid()
|
||||
}
|
||||
|
||||
useCanvas().operateNode({
|
||||
type: 'insert',
|
||||
parentId: node.id,
|
||||
parentId: node.id || '',
|
||||
newNodeData: data,
|
||||
position: [POSITION.TOP, POSITION.LEFT].includes(position) ? 'before' : 'after'
|
||||
position: ([POSITION.TOP, POSITION.LEFT] as string[]).includes(position) ? 'before' : 'after'
|
||||
})
|
||||
}
|
||||
|
||||
export const removeNode = (id) => {
|
||||
export const removeNode = (id: string) => {
|
||||
useCanvas().operateNode({
|
||||
type: 'delete',
|
||||
id
|
||||
|
|
@ -322,21 +344,21 @@ export const removeNode = (id) => {
|
|||
}
|
||||
|
||||
// 添加外部容器
|
||||
const insertContainer = ({ parent, node, data }) => {
|
||||
const insertContainer = ({ parent, node, data }: InsertOptions) => {
|
||||
if (!data.id) {
|
||||
data.id = utils.guid()
|
||||
}
|
||||
|
||||
useCanvas().operateNode({
|
||||
type: 'insert',
|
||||
parentId: parent.id,
|
||||
parentId: parent.id || '',
|
||||
newNodeData: data,
|
||||
position: POSITION.OUT,
|
||||
referTargetNodeId: node.id
|
||||
})
|
||||
}
|
||||
|
||||
export const removeNodeById = (id) => {
|
||||
export const removeNodeById = (id: string) => {
|
||||
if (!id) {
|
||||
return
|
||||
}
|
||||
|
|
@ -347,9 +369,9 @@ export const removeNodeById = (id) => {
|
|||
canvasState.emit('remove')
|
||||
}
|
||||
|
||||
export const querySelectById = (id) => {
|
||||
export const querySelectById = (id: string) => {
|
||||
let selector = `[${NODE_UID}="${id}"]`
|
||||
const doc = canvasState.iframe.contentDocument
|
||||
const doc = getDocument()
|
||||
let element = doc.querySelector(selector)
|
||||
const loopId = element?.getAttribute('loop-id')
|
||||
if (element && loopId) {
|
||||
|
|
@ -364,12 +386,12 @@ export const getCurrentElement = () => querySelectById(getCurrent().schema?.id)
|
|||
// 滚动页面后,目标元素与页面边界至少保留的边距
|
||||
const SCROLL_MARGIN = 15
|
||||
|
||||
export const scrollToNode = (element) => {
|
||||
export const scrollToNode = (element?: Element | null) => {
|
||||
if (element) {
|
||||
const container = getDocument().documentElement
|
||||
const { clientWidth, clientHeight } = container
|
||||
const { left, right, top, bottom, width, height } = element.getBoundingClientRect()
|
||||
const option = {}
|
||||
const option: { left?: number; top?: number } = {}
|
||||
|
||||
if (right < 0) {
|
||||
option.left = container.scrollLeft + left - SCROLL_MARGIN
|
||||
|
|
@ -391,11 +413,15 @@ export const scrollToNode = (element) => {
|
|||
return nextTick()
|
||||
}
|
||||
|
||||
const setSelectRect = (id, element, options = {}) => {
|
||||
const setSelectRect = (
|
||||
id: string,
|
||||
element?: Element | null,
|
||||
options?: { type?: string; schema: any; isMultiple: boolean }
|
||||
) => {
|
||||
clearHover()
|
||||
|
||||
const { type, isMultiple = false } = options
|
||||
const schema = options.schema || (useCanvas().getNodeWithParentById(id) || {}).node
|
||||
const { type, isMultiple = false } = options || {}
|
||||
const schema = options?.schema || (useCanvas().getNodeWithParentById(id) || {}).node
|
||||
element = element || querySelectById(id) || getDocument().body
|
||||
|
||||
const { left, height, top, width } = getRect(element)
|
||||
|
|
@ -419,7 +445,7 @@ const setSelectRect = (id, element, options = {}) => {
|
|||
)
|
||||
}
|
||||
|
||||
export const updateRect = (id) => {
|
||||
export const updateRect = (id?: string) => {
|
||||
id = (typeof id === 'string' && id) || getCurrent().schema?.id
|
||||
clearHover()
|
||||
|
||||
|
|
@ -440,7 +466,7 @@ export const updateRect = (id) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const getConfigure = (targetName) => {
|
||||
export const getConfigure = (targetName: string) => {
|
||||
const material = getController().getMaterial(targetName)
|
||||
|
||||
// 这里如果是区块插槽,则返回标识为容器的对象
|
||||
|
|
@ -459,7 +485,7 @@ export const getConfigure = (targetName) => {
|
|||
* @param {*} data 当前插入目标的schame数据
|
||||
* @returns
|
||||
*/
|
||||
export const allowInsert = (configure = hoverState.configure || {}, data = dragState.data || {}) => {
|
||||
export const allowInsert = (configure: any = hoverState.configure || {}, data: Node | null = dragState.data) => {
|
||||
const { nestingRule = {} } = configure
|
||||
const { childWhitelist = [], descendantBlacklist = [] } = nestingRule
|
||||
|
||||
|
|
@ -480,7 +506,7 @@ export const allowInsert = (configure = hoverState.configure || {}, data = dragS
|
|||
return flag
|
||||
}
|
||||
|
||||
const isAncestor = (ancestor, descendant) => {
|
||||
const isAncestor = (ancestor: string | Node, descendant: string | Node) => {
|
||||
const ancestorId = typeof ancestor === 'string' ? ancestor : ancestor.id
|
||||
let descendantId = typeof descendant === 'string' ? descendant : descendant.id
|
||||
|
||||
|
|
@ -497,9 +523,13 @@ const isAncestor = (ancestor, descendant) => {
|
|||
return false
|
||||
}
|
||||
|
||||
type Rect =
|
||||
| DOMRect
|
||||
| { left: number; top: number; right: number; bottom: number; width: number; height: number; x: number; y: number }
|
||||
|
||||
// 获取位置信息,返回状态
|
||||
const lineAbs = 20
|
||||
const getPosLine = (rect, configure) => {
|
||||
const getPosLine = (rect: Rect, configure: { isContainer: any }) => {
|
||||
const mousePos = dragState.mouse
|
||||
const yAbs = Math.min(lineAbs, rect.height / 3)
|
||||
const xAbs = Math.min(lineAbs, rect.width / 3)
|
||||
|
|
@ -532,14 +562,14 @@ const getPosLine = (rect, configure) => {
|
|||
return { type, forbidden }
|
||||
}
|
||||
|
||||
const isBodyEl = (element) => element.nodeName === 'BODY'
|
||||
const isBodyEl = (element: Element) => element.nodeName === 'BODY'
|
||||
|
||||
const setHoverRect = (element, data) => {
|
||||
const setHoverRect = (element?: Element, data?: Node | null) => {
|
||||
if (!element) {
|
||||
return clearHover()
|
||||
}
|
||||
const componentName = element.getAttribute(NODE_TAG)
|
||||
const id = element.getAttribute(NODE_UID)
|
||||
const componentName = element.getAttribute(NODE_TAG)!
|
||||
const id = element.getAttribute(NODE_UID)!
|
||||
const configure = getConfigure(componentName)
|
||||
const rect = getRect(element)
|
||||
const { left, height, top, width } = rect
|
||||
|
|
@ -561,7 +591,7 @@ const setHoverRect = (element, data) => {
|
|||
// 如果容器盒子有子节点,则以最后一个子节点为拖拽参照物
|
||||
const lastNode = children[children.length - 1]
|
||||
childEle = querySelectById(lastNode.id)
|
||||
const childComponentName = element.getAttribute(childEle)
|
||||
const childComponentName = childEle!.getAttribute(NODE_TAG)!
|
||||
const Childconfigure = getConfigure(childComponentName)
|
||||
lineState.id = lastNode.id
|
||||
lineState.configure = Childconfigure
|
||||
|
|
@ -572,7 +602,7 @@ const setHoverRect = (element, data) => {
|
|||
if (childEle) {
|
||||
const childRect = getRect(childEle)
|
||||
const { left, height, top, width } = childRect
|
||||
const posLine = getPosLine(childRect, lineState.configure)
|
||||
const posLine = getPosLine(childRect, lineState.configure!)
|
||||
Object.assign(lineState, {
|
||||
width,
|
||||
height,
|
||||
|
|
@ -627,13 +657,13 @@ const updateHoverRect = (id?: string) => {
|
|||
})
|
||||
}
|
||||
|
||||
const setInactiveHoverRect = (element) => {
|
||||
const setInactiveHoverRect = (element?: Element) => {
|
||||
if (!element) {
|
||||
Object.assign(inactiveHoverState, initialRectState, { slot: null })
|
||||
return
|
||||
}
|
||||
|
||||
const componentName = element.getAttribute(NODE_TAG)
|
||||
const componentName = element.getAttribute(NODE_TAG)!
|
||||
const id = element.getAttribute(NODE_INACTIVE_UID)
|
||||
const configure = getConfigure(componentName)
|
||||
const rect = getRect(element)
|
||||
|
|
@ -657,10 +687,10 @@ export const syncNodeScroll = () => {
|
|||
updateHoverRect()
|
||||
}
|
||||
|
||||
let moveUpdateTimer = null
|
||||
let moveUpdateTimer: ReturnType<typeof setTimeout> | undefined = undefined
|
||||
|
||||
// 绝对布局
|
||||
const absoluteMove = (event, element) => {
|
||||
const absoluteMove = (event: DragEvent, element: HTMLElement) => {
|
||||
const { clientX, clientY } = event
|
||||
const { offsetX, offsetY, horizontal, vertical, height, width, x, y } = dragState.offset
|
||||
|
||||
|
|
@ -693,7 +723,7 @@ const absoluteMove = (event, element) => {
|
|||
|
||||
clearTimeout(moveUpdateTimer)
|
||||
|
||||
const { data } = dragState
|
||||
const data = dragState.data!
|
||||
data.props = data.props || {}
|
||||
|
||||
// 防抖更新位置信息到 schema
|
||||
|
|
@ -706,7 +736,16 @@ const absoluteMove = (event, element) => {
|
|||
updateRect()
|
||||
}
|
||||
|
||||
const setDragPosition = ({ clientX, x, clientY, y, offsetBottom, offsetTop }) => {
|
||||
interface SetDragPositionOptions {
|
||||
clientX: number
|
||||
x: number
|
||||
clientY: number
|
||||
y: number
|
||||
offsetBottom: number
|
||||
offsetTop: number
|
||||
}
|
||||
|
||||
const setDragPosition = ({ clientX, x, clientY, y, offsetBottom, offsetTop }: SetDragPositionOptions) => {
|
||||
const left = clientX + x
|
||||
const top = clientY + y
|
||||
if (clientY < 20) {
|
||||
|
|
@ -720,12 +759,14 @@ const setDragPosition = ({ clientX, x, clientY, y, offsetBottom, offsetTop }) =>
|
|||
dragState.position = { left, top }
|
||||
}
|
||||
|
||||
export const dragMove = (event, isHover) => {
|
||||
export const dragMove = (event: DragEvent, isHover: boolean) => {
|
||||
if (!dragState.draging && dragState.keydown && new Date().getTime() - dragState.timer < 200) {
|
||||
return
|
||||
}
|
||||
|
||||
const { x, y, bottom: offsetBottom, top: offsetTop } = getOffset(event.target)
|
||||
const eventTarget = event.target as Element
|
||||
|
||||
const { x, y, bottom: offsetBottom, top: offsetTop } = getOffset(eventTarget)
|
||||
const { clientX, clientY } = event
|
||||
const { element } = dragState
|
||||
const absolute = canvasState.type === 'absolute'
|
||||
|
|
@ -737,24 +778,24 @@ export const dragMove = (event, isHover) => {
|
|||
// 如果仅仅是mouseover事件直接return,并重置拖拽位置状态,优化性能
|
||||
if (isHover) {
|
||||
lineState.position = ''
|
||||
setHoverRect(getElement(event.target), null)
|
||||
setInactiveHoverRect(getInactiveElement(event.target))
|
||||
setHoverRect(getElement(eventTarget), null)
|
||||
setInactiveHoverRect(getInactiveElement(eventTarget))
|
||||
return
|
||||
}
|
||||
|
||||
setHoverRect(getElement(event.target), dragState.data)
|
||||
setHoverRect(getElement(eventTarget), dragState.data)
|
||||
|
||||
if (dragState.draging) {
|
||||
// 绝对布局时走的逻辑
|
||||
if (element && absolute) {
|
||||
absoluteMove(event, element)
|
||||
absoluteMove(event, element as HTMLElement)
|
||||
}
|
||||
setDragPosition({ clientX, x, clientY, y, offsetBottom, offsetTop })
|
||||
}
|
||||
}
|
||||
|
||||
// type == clickTree, 为点击大纲; type == loop-id=xxx ,为点击循环数据
|
||||
export const selectNode = async (id, type, isMultiple = false) => {
|
||||
export const selectNode = async (id: string, type?: string, isMultiple = false) => {
|
||||
const { node } = useCanvas().getNodeWithParentById(id) || {}
|
||||
|
||||
let element = querySelectById(id)
|
||||
|
|
@ -798,16 +839,20 @@ export const selectNode = async (id, type, isMultiple = false) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const hoverNode = (id, data) => {
|
||||
export const hoverNode = (id: string, data: Node) => {
|
||||
const element = querySelectById(id)
|
||||
if (element) {
|
||||
setHoverRect(element, data)
|
||||
}
|
||||
}
|
||||
|
||||
export const insertNode = (node, position = POSITION.IN, select = true) => {
|
||||
export const insertNode = (
|
||||
node: { node: Node; parent: Node; data: Node },
|
||||
position: string = POSITION.IN,
|
||||
select = true
|
||||
) => {
|
||||
if (!node.parent) {
|
||||
insertInner({ node: useCanvas().pageState.pageSchema, data: node.data }, position)
|
||||
insertInner({ node: useCanvas().pageState.pageSchema!, data: node.data }, position)
|
||||
} else {
|
||||
switch (position) {
|
||||
case POSITION.TOP:
|
||||
|
|
@ -837,33 +882,34 @@ export const insertNode = (node, position = POSITION.IN, select = true) => {
|
|||
getController().addHistory()
|
||||
}
|
||||
|
||||
export const addComponent = (data, position) => {
|
||||
export const addComponent = (data: Node, position: string) => {
|
||||
const { schema, parent } = getCurrent()
|
||||
|
||||
insertNode({ node: schema, parent, data }, position)
|
||||
}
|
||||
|
||||
export const copyNode = (id) => {
|
||||
export const copyNode = (id: string) => {
|
||||
if (!id) {
|
||||
return
|
||||
}
|
||||
|
||||
const { node, parent } = useCanvas().getNodeWithParentById(id)
|
||||
const { node, parent } = useCanvas().getNodeWithParentById(id)!
|
||||
|
||||
insertAfter({ parent, node, data: copyObject(node) })
|
||||
getController().addHistory()
|
||||
}
|
||||
|
||||
export const onMouseUp = () => {
|
||||
const { draging, data } = dragState
|
||||
const { draging } = dragState
|
||||
const { position, forbidden } = lineState
|
||||
const absolute = canvasState.type === 'absolute'
|
||||
const sourceId = data?.id
|
||||
const lineId = lineState.id
|
||||
const { getNodeWithParentById, getSchema } = useCanvas()
|
||||
|
||||
if (draging && !forbidden) {
|
||||
const { parent, node } = getNodeWithParentById(lineId) || {} // target
|
||||
const data = dragState.data!
|
||||
const sourceId = data.id
|
||||
|
||||
const insertData = toRaw(data)
|
||||
const targetNode = { parent, node, data: { ...insertData, children: insertData.children || [] } }
|
||||
|
|
@ -890,16 +936,16 @@ export const onMouseUp = () => {
|
|||
dragEnd()
|
||||
}
|
||||
|
||||
export const addStyle = (href) => appendStyle(href, getDocument())
|
||||
export const addStyle = (href: string) => appendStyle(href, getDocument())
|
||||
|
||||
export const addScript = (src) => appendScript(src, getDocument())
|
||||
export const addScript = (src: string) => appendScript(src, getDocument())
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} messages
|
||||
* @param {*} merge 是否合并,默认是重置所有数据
|
||||
*/
|
||||
export const setLocales = (messages, merge) => {
|
||||
export const setLocales = (messages: any, merge?: boolean) => {
|
||||
const i18n = getRenderer().getI18n()
|
||||
|
||||
Object.keys(messages).forEach((lang) => {
|
||||
|
|
@ -908,11 +954,11 @@ export const setLocales = (messages, merge) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const setConfigure = (configure) => {
|
||||
export const setConfigure = (configure: any) => {
|
||||
getRenderer().setConfigure(configure)
|
||||
}
|
||||
|
||||
export const setI18n = (data) => {
|
||||
export const setI18n = (data: any) => {
|
||||
const messages = data || useTranslate().getData()
|
||||
const i18n = getRenderer().getI18n()
|
||||
Object.keys(messages).forEach((lang) => {
|
||||
|
|
@ -920,7 +966,7 @@ export const setI18n = (data) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const setCanvasType = (type) => {
|
||||
export const setCanvasType = (type: string) => {
|
||||
canvasState.type = type || 'normal'
|
||||
getDocument().body.className = type === 'absolute' ? 'canvas-grid-bg' : ''
|
||||
}
|
||||
|
|
@ -932,7 +978,7 @@ export const getCanvasType = () => canvasState.type
|
|||
* @param {string} name 事件名称
|
||||
* @param {any} data 派发的数据
|
||||
*/
|
||||
export const canvasDispatch = (name, data, doc = getDocument()) => {
|
||||
export const canvasDispatch = (name: string, data: any, doc = getDocument()) => {
|
||||
if (!doc) return
|
||||
|
||||
doc.dispatchEvent(new CustomEvent(name, data))
|
||||
|
|
@ -964,15 +1010,15 @@ export const canvasApi = {
|
|||
getConfigure,
|
||||
allowInsert,
|
||||
Builtin,
|
||||
removeBlockCompsCache: (...args) => {
|
||||
removeBlockCompsCache: (...args: any[]) => {
|
||||
return canvasState.renderer.removeBlockCompsCache(...args)
|
||||
},
|
||||
updateCanvas: (...args) => {
|
||||
updateCanvas: (...args: any[]) => {
|
||||
return canvasState.renderer.updateCanvas(...args)
|
||||
}
|
||||
}
|
||||
|
||||
export const initCanvas = ({ renderer, iframe, emit, controller }) => {
|
||||
export const initCanvas = ({ renderer, iframe, emit, controller }: any) => {
|
||||
canvasState.iframe = iframe
|
||||
canvasState.emit = emit
|
||||
// 存放画布外层传进来的插件api
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@opentiny/tiny-engine-vite-plugin-meta-comments": "workspace:*",
|
||||
"@types/diff-match-patch": "^1.0.36",
|
||||
"@vitejs/plugin-vue": "^5.1.2",
|
||||
"@vitejs/plugin-vue-jsx": "^4.0.1",
|
||||
"rollup-plugin-polyfill-node": "^0.13.0",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,6 @@ let designMode = DESIGN_MODE.DESIGN
|
|||
|
||||
export const getDesignMode = () => designMode
|
||||
|
||||
export const setDesignMode = (mode) => {
|
||||
export const setDesignMode = (mode: string) => {
|
||||
designMode = mode
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
export interface Node {
|
||||
id: string
|
||||
componentName: string
|
||||
props: Record<string, any> & { columns?: { slots?: Record<string, any> }[] }
|
||||
children?: Node[]
|
||||
}
|
||||
|
||||
export type RootNode = Omit<Node, 'id'> & {
|
||||
id?: string
|
||||
css?: string
|
||||
fileName?: string
|
||||
methods?: Record<string, any>
|
||||
state?: Record<string, any>
|
||||
lifeCycles?: Record<string, any>
|
||||
dataSource?: any
|
||||
bridge?: any
|
||||
inputs?: any[]
|
||||
outputs?: any[]
|
||||
schema?: any
|
||||
}
|
||||
|
|
@ -1,7 +1,18 @@
|
|||
import { h, render } from 'vue'
|
||||
import { Modal } from '@opentiny/vue'
|
||||
|
||||
const confirm = ({ title, status, message, exec, cancel, showFooter = true }) => {
|
||||
export interface ModalOptions {
|
||||
title: string
|
||||
status?: string
|
||||
message: string | ((...args: any[]) => any)
|
||||
exec?: (...args: any[]) => any
|
||||
cancel?: (...args: any[]) => any
|
||||
showFooter?: boolean
|
||||
}
|
||||
|
||||
export type ConfirmOptions = ModalOptions
|
||||
|
||||
const confirm = ({ title, status, message, exec, cancel, showFooter = true }: ConfirmOptions) => {
|
||||
Modal.confirm({
|
||||
title,
|
||||
status,
|
||||
|
|
@ -13,7 +24,7 @@ const confirm = ({ title, status, message, exec, cancel, showFooter = true }) =>
|
|||
</div>
|
||||
)
|
||||
}
|
||||
}).then((res) => {
|
||||
}).then((res: string) => {
|
||||
if (res === 'confirm' && typeof exec === 'function') {
|
||||
exec()
|
||||
} else if (typeof cancel === 'function') {
|
||||
|
|
@ -22,7 +33,9 @@ const confirm = ({ title, status, message, exec, cancel, showFooter = true }) =>
|
|||
})
|
||||
}
|
||||
|
||||
const message = ({ title, status, message, exec, width = '400' }) => {
|
||||
export type MessageOptions = Pick<ModalOptions, 'title' | 'status' | 'message' | 'exec'> & { width?: string }
|
||||
|
||||
const message = ({ title, status, message, exec, width = '400' }: MessageOptions) => {
|
||||
Modal.alert({
|
||||
title,
|
||||
status,
|
||||
|
|
@ -42,13 +55,13 @@ const message = ({ title, status, message, exec, width = '400' }) => {
|
|||
})
|
||||
}
|
||||
|
||||
const topbox = (options) => {
|
||||
const topbox = (options: ModalOptions) => {
|
||||
const props = { ...options, modelValue: true }
|
||||
let TopBox = h(Modal, props)
|
||||
const modalEl = document.createElement('div')
|
||||
|
||||
const close = () => {
|
||||
TopBox.el.remove()
|
||||
TopBox.el?.remove()
|
||||
TopBox = null
|
||||
}
|
||||
|
||||
|
|
@ -60,6 +73,13 @@ const topbox = (options) => {
|
|||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
topbox?: (options: ModalOptions) => { TopBox: any; close: () => void }
|
||||
message?: (options: MessageOptions) => void
|
||||
}
|
||||
}
|
||||
|
||||
window.topbox = topbox
|
||||
window.message = message
|
||||
|
||||
|
|
@ -7,7 +7,16 @@ const durationMap = {
|
|||
error: 10000
|
||||
}
|
||||
|
||||
const useNotify = (config) => {
|
||||
export interface NotifyOptions {
|
||||
[key: string]: any
|
||||
title?: string
|
||||
message: string
|
||||
type: keyof typeof durationMap
|
||||
customClass?: string
|
||||
position?: string
|
||||
}
|
||||
|
||||
const useNotify = (config: NotifyOptions) => {
|
||||
const { customClass, title, type = 'info', position = 'top-right', ...otherConfig } = config
|
||||
|
||||
Notify({
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import type { App } from 'vue'
|
||||
import ConfigGroup from './ConfigGroup.vue'
|
||||
import ConfigItem from './ConfigItem.vue'
|
||||
export { default as PluginSetting } from './PluginSetting.vue'
|
||||
|
|
@ -54,12 +55,12 @@ export { default as Pane } from './Pane.vue'
|
|||
export { default as I18nInput } from './I18nInput.vue'
|
||||
export { default as CanvasDragItem } from './CanvasDragItem.vue'
|
||||
export { default as ToolbarBase } from './ToolbarBase.vue'
|
||||
export { default as Modal } from './Modal.jsx'
|
||||
export { default as Notify } from './Notify.jsx'
|
||||
export { default as Modal } from './Modal'
|
||||
export { default as Notify } from './Notify'
|
||||
export { ConfigGroup, ConfigItem }
|
||||
|
||||
export const injectGlobalComponents = {
|
||||
install: (app) => {
|
||||
install: (app: App<Element>) => {
|
||||
const globalComponents = {
|
||||
ConfigGroup,
|
||||
ConfigItem
|
||||
|
|
@ -59,7 +59,10 @@ const layoutState = reactive({
|
|||
toolbars: {
|
||||
visiblePopover: false
|
||||
},
|
||||
pageStatus: ''
|
||||
pageStatus: {
|
||||
state: '',
|
||||
data: {}
|
||||
}
|
||||
})
|
||||
const getMoveDragBarState = () => {
|
||||
return layoutState.isMoveDragBar
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
export interface Property {
|
||||
label: {
|
||||
zh_CN?: string
|
||||
}
|
||||
description: {
|
||||
zh_CN?: string
|
||||
}
|
||||
collapse: {
|
||||
number: number
|
||||
text: {
|
||||
zh_CN?: string
|
||||
}
|
||||
}
|
||||
content?: BlockProperty[]
|
||||
}
|
||||
|
||||
export interface BlockContent {
|
||||
componentName: string
|
||||
blockName?: string
|
||||
fileName: string
|
||||
css?: string
|
||||
props: Record<string, any>
|
||||
children: any[]
|
||||
schema: {
|
||||
properties?: Property[]
|
||||
events?: Record<string, any>
|
||||
}
|
||||
state?: Record<string, any>
|
||||
methods: Record<string, any>
|
||||
dataSource?: Record<string, any>
|
||||
i18n?: any
|
||||
}
|
||||
|
||||
export interface BlockOccupier {
|
||||
id: number
|
||||
username: string
|
||||
resetPasswordToken: string
|
||||
}
|
||||
|
||||
export interface Block {
|
||||
id?: string | number
|
||||
name_cn?: string
|
||||
label: string
|
||||
path?: string
|
||||
categories: string[]
|
||||
public: number
|
||||
is_published?: number
|
||||
framework: string
|
||||
content: BlockContent
|
||||
occupier?: BlockOccupier | null
|
||||
created_at?: string | Date
|
||||
updated_at?: string | Date
|
||||
histories?: any[]
|
||||
assets?: any
|
||||
}
|
||||
|
||||
export interface BlockGroup {
|
||||
id: string
|
||||
name: string
|
||||
desc: string
|
||||
app: {
|
||||
id: string | number
|
||||
name: string
|
||||
}
|
||||
blocks: { data: Block }[]
|
||||
groupId: string
|
||||
groupName: string
|
||||
}
|
||||
|
||||
export interface BlockProperty {
|
||||
linked?: { property: any; blockProperty: any } | null
|
||||
property: any
|
||||
defaultValue: any
|
||||
widget?: any
|
||||
}
|
||||
|
||||
export interface SchemaData {
|
||||
langs: Record<string, any>
|
||||
methods: Record<string, any>
|
||||
state: Record<string, any>
|
||||
classNameList: string[]
|
||||
contentList: any[]
|
||||
}
|
||||
|
||||
export type ParsePropToDataOptons = Pick<SchemaData, 'langs' | 'methods' | 'state'> & {
|
||||
prop: {
|
||||
type: string
|
||||
key: string
|
||||
value: any
|
||||
}
|
||||
}
|
||||
|
||||
export type ParseChildPropsOptions = Pick<SchemaData, 'langs' | 'methods' | 'state'> & {
|
||||
child: {
|
||||
props: Record<string, any>
|
||||
[x: string]: any
|
||||
}
|
||||
}
|
||||
|
||||
export interface CreateBlockOptions {
|
||||
name_cn: string
|
||||
label: string
|
||||
path?: string
|
||||
categories: string[]
|
||||
}
|
||||
|
||||
export type CreateEmptyBlockOptions = Pick<Block, 'name_cn' | 'label' | 'path' | 'categories'>
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { ref, reactive, readonly } from 'vue'
|
||||
import { ref, reactive, readonly, type DeepReadonly } from 'vue'
|
||||
import { hyphenate } from '@vue/shared'
|
||||
import { extend, copyArray } from '@opentiny/vue-renderless/common/object'
|
||||
import { format } from '@opentiny/vue-renderless/common/date'
|
||||
|
|
@ -32,12 +32,24 @@ import {
|
|||
META_SERVICE
|
||||
} from '@opentiny/tiny-engine-meta-register'
|
||||
import meta from '../../meta'
|
||||
import type {
|
||||
Block,
|
||||
BlockContent,
|
||||
BlockGroup,
|
||||
BlockProperty,
|
||||
CreateBlockOptions,
|
||||
CreateEmptyBlockOptions,
|
||||
ParseChildPropsOptions,
|
||||
ParsePropToDataOptons,
|
||||
Property,
|
||||
SchemaData
|
||||
} from './types'
|
||||
|
||||
const { SORT_TYPE, SCHEMA_DATA_TYPE, BLOCK_OPENNESS } = constants
|
||||
|
||||
const NODE_TYPE_PAGE = 'Page'
|
||||
const nameCn = 'name_cn'
|
||||
const DEFAULT_PROPERTIES = readonly([
|
||||
const DEFAULT_PROPERTIES = readonly<Property[]>([
|
||||
{
|
||||
label: {
|
||||
zh_CN: '基础信息'
|
||||
|
|
@ -55,7 +67,7 @@ const DEFAULT_PROPERTIES = readonly([
|
|||
}
|
||||
])
|
||||
|
||||
const DEFAULT_BLOCK = readonly({
|
||||
const DEFAULT_BLOCK = readonly<DeepReadonly<BlockContent>>({
|
||||
componentName: 'Block',
|
||||
fileName: '',
|
||||
css: '',
|
||||
|
|
@ -70,63 +82,63 @@ const DEFAULT_BLOCK = readonly({
|
|||
dataSource: {}
|
||||
})
|
||||
|
||||
const blockState = reactive({
|
||||
const blockState = reactive<{ list: Block[]; current: Block | null }>({
|
||||
list: [],
|
||||
current: null // 当前画布中正在渲染的区块数据
|
||||
})
|
||||
|
||||
// 区块分组信息
|
||||
const groupState = reactive({
|
||||
const groupState = reactive<{ list: BlockGroup[]; selected: BlockGroup | object }>({
|
||||
list: [],
|
||||
selected: {}
|
||||
})
|
||||
|
||||
// 区块分类
|
||||
const categoryState = reactive({
|
||||
const categoryState = reactive<{ list: BlockGroup[] }>({
|
||||
list: []
|
||||
})
|
||||
|
||||
const getBlockList = () => blockState.list
|
||||
|
||||
const setBlockList = (list) => {
|
||||
const setBlockList = (list: Block[]) => {
|
||||
blockState.list = list
|
||||
}
|
||||
|
||||
const addBlock = (block) => {
|
||||
const addBlock = (block: Block) => {
|
||||
const blockList = getBlockList()
|
||||
blockList.unshift(block)
|
||||
}
|
||||
|
||||
const delBlock = (block) => {
|
||||
const delBlock = (block: Block) => {
|
||||
remove(getBlockList(), block)
|
||||
}
|
||||
|
||||
// 获取当前画布中的区块信息
|
||||
const getCurrentBlock = () => blockState.current
|
||||
|
||||
const setCurrentBlock = (block) => {
|
||||
const setCurrentBlock = (block: Block) => {
|
||||
blockState.current = block
|
||||
}
|
||||
|
||||
const getGroupList = () => groupState.list
|
||||
|
||||
const setGroupList = (list) => {
|
||||
const setGroupList = (list: BlockGroup[]) => {
|
||||
groupState.list = list
|
||||
}
|
||||
|
||||
const getCategoryList = () => categoryState.list
|
||||
|
||||
const setCategoryList = (list) => {
|
||||
const setCategoryList = (list: BlockGroup[]) => {
|
||||
categoryState.list = list
|
||||
}
|
||||
|
||||
const getSelectedGroup = () => groupState.selected
|
||||
|
||||
const setSelectedGroup = (selected) => {
|
||||
const setSelectedGroup = (selected: BlockGroup) => {
|
||||
groupState.selected = selected
|
||||
}
|
||||
|
||||
const copyCss = (css, classNameList) => {
|
||||
const copyCss = (css: string, classNameList: string[]) => {
|
||||
classNameList = Array.from(new Set(classNameList)).map((item) => '.' + item)
|
||||
const cssObject = getCssObjectFromStyleStr(css)
|
||||
let styleStr = ''
|
||||
|
|
@ -141,10 +153,10 @@ const copyCss = (css, classNameList) => {
|
|||
return styleStr
|
||||
}
|
||||
|
||||
const copySchema = (schema, contentList, methods) => {
|
||||
const copySchema = (schema: Partial<BlockContent['schema']>, contentList: string[], methods: Record<string, any>) => {
|
||||
const content = schema?.properties?.[0]?.content || []
|
||||
let emitList = []
|
||||
const emitListCopies = {}
|
||||
let emitList: string[] = []
|
||||
const emitListCopies: Record<string, any> = {}
|
||||
Object.keys(methods).forEach((key) => {
|
||||
const item = JSON.stringify(methods[key].value).match(/emit..*?\)/g)
|
||||
|
||||
|
|
@ -154,10 +166,16 @@ const copySchema = (schema, contentList, methods) => {
|
|||
})
|
||||
|
||||
emitList.forEach((e) => {
|
||||
let key = e.match(/'.*?'/g)[0].replace(/'/g, '')
|
||||
const matches = e.match(/'.*?'/g)
|
||||
|
||||
if (!matches || !matches.length) {
|
||||
return
|
||||
}
|
||||
|
||||
let key = matches[0].replace(/'/g, '')
|
||||
|
||||
key = `on${key[0].toLocaleUpperCase() + key.slice(1, key.length)}`
|
||||
if (schema?.events[key]) {
|
||||
if (schema?.events?.[key]) {
|
||||
emitListCopies[key] = schema?.events[key]
|
||||
}
|
||||
})
|
||||
|
|
@ -174,12 +192,12 @@ const copySchema = (schema, contentList, methods) => {
|
|||
return schemaCopies
|
||||
}
|
||||
|
||||
const copyMethods = (schema) => {
|
||||
const methodsListCopies = {}
|
||||
const copyMethods = (schema: Record<string, any>) => {
|
||||
const methodsListCopies: Record<string, any> = {}
|
||||
|
||||
// 因为methods方法里面大部分是用户的业务代码(无法复用),所以只需要拷贝一个空方法即可
|
||||
Object.entries(schema).forEach(([key, value]) => {
|
||||
const ast = parseExpression(value.value)
|
||||
const ast: any = parseExpression(value.value)
|
||||
|
||||
// 清空函数体
|
||||
if (ast.body?.body) {
|
||||
|
|
@ -194,8 +212,8 @@ const copyMethods = (schema) => {
|
|||
return methodsListCopies
|
||||
}
|
||||
|
||||
const copyState = (stateObj = {}, methodsObj = {}) => {
|
||||
const stateCopies = {}
|
||||
const copyState = (stateObj: Record<string, any> = {}, methodsObj: Record<string, any> = {}) => {
|
||||
const stateCopies: Record<string, any> = {}
|
||||
const stateKey = Object.keys(stateObj).map((e) => `state.${e} `)
|
||||
|
||||
stateKey.forEach((e) => {
|
||||
|
|
@ -210,7 +228,7 @@ const copyState = (stateObj = {}, methodsObj = {}) => {
|
|||
return stateCopies
|
||||
}
|
||||
|
||||
const parsePropToData = (data, { prop, langs, state, methods }) => {
|
||||
const parsePropToData = (data: SchemaData, { prop, langs, state, methods }: ParsePropToDataOptons) => {
|
||||
if (prop.type === SCHEMA_DATA_TYPE.I18n) {
|
||||
data.langs[prop.key] = langs[prop.key]
|
||||
} else if (prop.type === SCHEMA_DATA_TYPE.JSExpression) {
|
||||
|
|
@ -228,9 +246,9 @@ const parsePropToData = (data, { prop, langs, state, methods }) => {
|
|||
}
|
||||
|
||||
const filterDataFn =
|
||||
(parseChildProps) =>
|
||||
({ children = [], langs = {}, methods = {}, state = {} }) => {
|
||||
const data = {
|
||||
(parseChildProps: (...args: any[]) => any) =>
|
||||
({ children = [] as any[], langs = {}, methods = {}, state = {} }) => {
|
||||
const data: SchemaData = {
|
||||
langs: {},
|
||||
methods: {},
|
||||
state: {},
|
||||
|
|
@ -247,14 +265,14 @@ const filterDataFn =
|
|||
return data
|
||||
}
|
||||
|
||||
const parseChildProps = (data, { child, langs, state, methods }) => {
|
||||
const parseChildProps = (data: SchemaData, { child, langs, state, methods }: ParseChildPropsOptions) => {
|
||||
if (child.props) {
|
||||
Object.entries(child.props).forEach(([propKey, prop]) => {
|
||||
if (typeof prop === 'object') {
|
||||
parsePropToData(data, { prop, langs, state, methods })
|
||||
} else {
|
||||
if (propKey === 'className' && prop) {
|
||||
data.classNameList.push(...prop.split(' ').filter((item) => item))
|
||||
data.classNameList.push(...prop.split(' ').filter((item: string) => item))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -271,14 +289,14 @@ const parseChildProps = (data, { child, langs, state, methods }) => {
|
|||
}
|
||||
}
|
||||
|
||||
const getBlockPageSchema = (block) => {
|
||||
const getBlockPageSchema = (block: Block) => {
|
||||
const content = block?.content || {}
|
||||
content.componentName = content.componentName || content.blockName
|
||||
content.componentName = content.componentName || content.blockName || ''
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
const initBlock = async (block = {}, _langs = {}, isEdit) => {
|
||||
const initBlock = async (block: any = {}, _langs = {}, isEdit?: boolean) => {
|
||||
const { resetBlockCanvasState, setSaved, getSchema } = useCanvas()
|
||||
const { setBreadcrumbBlock } = useBreadcrumb()
|
||||
|
||||
|
|
@ -305,7 +323,7 @@ const initBlock = async (block = {}, _langs = {}, isEdit) => {
|
|||
})
|
||||
}
|
||||
|
||||
const createBlock = ({ name_cn, label, path, categories }) => {
|
||||
const createBlock = ({ name_cn, label, path, categories }: CreateBlockOptions) => {
|
||||
const { pageState } = useCanvas()
|
||||
const schema = extend(true, {}, pageState.currentSchema)
|
||||
// 选中 body 节点创建区块时需传递子节点数据
|
||||
|
|
@ -320,20 +338,20 @@ const createBlock = ({ name_cn, label, path, categories }) => {
|
|||
filterData({
|
||||
children,
|
||||
langs: getLangs(),
|
||||
methods: pageState.pageSchema.methods,
|
||||
state: pageState.pageSchema.state
|
||||
methods: pageState.pageSchema?.methods,
|
||||
state: pageState.pageSchema?.state
|
||||
})
|
||||
)
|
||||
|
||||
const css = copyCss(pageState.pageSchema.css, classNameList)
|
||||
const css = copyCss(pageState.pageSchema?.css || '', classNameList)
|
||||
const methodsCopies = copyMethods(methods)
|
||||
Object.assign(methods, methodsCopies)
|
||||
|
||||
const schemaCopies = copySchema(pageState.pageSchema.schema, contentList, methods)
|
||||
const stateCopies = copyState(pageState.pageSchema.state, methods)
|
||||
const schemaCopies = copySchema(pageState.pageSchema?.schema, contentList, methods)
|
||||
const stateCopies = copyState(pageState.pageSchema?.state, methods)
|
||||
Object.assign(state, stateCopies)
|
||||
|
||||
const block = {
|
||||
const block: Block = {
|
||||
path,
|
||||
[nameCn]: name_cn,
|
||||
label,
|
||||
|
|
@ -355,8 +373,8 @@ const createBlock = ({ name_cn, label, path, categories }) => {
|
|||
initBlock(block, langs)
|
||||
}
|
||||
|
||||
const createEmptyBlock = ({ name_cn, label, path, categories }) => {
|
||||
const block = {
|
||||
const createEmptyBlock = ({ name_cn, label, path, categories }: CreateEmptyBlockOptions) => {
|
||||
const block: Block = {
|
||||
path,
|
||||
[nameCn]: name_cn,
|
||||
label,
|
||||
|
|
@ -372,8 +390,8 @@ const createEmptyBlock = ({ name_cn, label, path, categories }) => {
|
|||
initBlock(block)
|
||||
}
|
||||
|
||||
const setComponentLinkedValue = ({ propertyName, value }) => {
|
||||
const { schema } = useCanvas().canvasApi.value?.getCurrent() || {}
|
||||
const setComponentLinkedValue = ({ propertyName, value }: { propertyName: string; value: any }) => {
|
||||
const { schema } = useCanvas().canvasApi.value?.getCurrent?.() || {}
|
||||
|
||||
if (!propertyName || !schema) {
|
||||
return
|
||||
|
|
@ -383,28 +401,28 @@ const setComponentLinkedValue = ({ propertyName, value }) => {
|
|||
schema.props[propertyName] = value
|
||||
}
|
||||
|
||||
const getBlockI18n = (block) => block?.content?.i18n || {}
|
||||
const getBlockI18n = (block: Block) => block?.content?.i18n || {}
|
||||
|
||||
const getBlockProperties = (block) => block?.content?.schema?.properties?.[0]?.content || []
|
||||
const getBlockProperties = (block: Block) => block?.content?.schema?.properties?.[0]?.content || []
|
||||
|
||||
const addBlockProperty = (property, block) => {
|
||||
const addBlockProperty = (property: BlockProperty, block: Block) => {
|
||||
if (!block) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!block.content) {
|
||||
block.content = {}
|
||||
block.content = {} as BlockContent
|
||||
}
|
||||
|
||||
if (!block.content.schema) {
|
||||
block.content.schema = {}
|
||||
block.content.schema = {} as BlockContent['schema']
|
||||
}
|
||||
|
||||
if (!block.content.schema.properties) {
|
||||
block.content.schema.properties = copyArray(DEFAULT_PROPERTIES)
|
||||
}
|
||||
|
||||
block.content.schema.properties[0].content.push(property)
|
||||
block.content.schema.properties?.[0].content?.push(property)
|
||||
|
||||
if (property.linked) {
|
||||
setComponentLinkedValue({
|
||||
|
|
@ -417,7 +435,7 @@ const addBlockProperty = (property, block) => {
|
|||
}
|
||||
}
|
||||
|
||||
const editBlockProperty = (property, data) => {
|
||||
const editBlockProperty = (property: BlockProperty, data: any) => {
|
||||
if (property.linked) {
|
||||
const value = {
|
||||
type: SCHEMA_DATA_TYPE.JSExpression,
|
||||
|
|
@ -431,13 +449,13 @@ const editBlockProperty = (property, data) => {
|
|||
}
|
||||
}
|
||||
|
||||
const removePropertyLink = ({ componentProperty }) => {
|
||||
const removePropertyLink = ({ componentProperty }: { componentProperty: BlockProperty }) => {
|
||||
const linked = componentProperty.linked
|
||||
componentProperty.linked = null
|
||||
const properties = getBlockProperties(getCurrentBlock())
|
||||
const properties = getBlockProperties(getCurrentBlock()!)
|
||||
|
||||
properties.forEach((property) => {
|
||||
if (property.linked && property.property === linked.blockProperty) {
|
||||
if (property.linked && property.property === linked?.blockProperty) {
|
||||
if (componentProperty.widget?.props?.modelValue) {
|
||||
componentProperty.widget.props.modelValue = property.defaultValue
|
||||
}
|
||||
|
|
@ -452,19 +470,19 @@ const removePropertyLink = ({ componentProperty }) => {
|
|||
})
|
||||
}
|
||||
|
||||
const getBlockEvents = (block = {}) => block?.content?.schema?.events || {}
|
||||
const getBlockEvents = (block = {} as Block) => block?.content?.schema?.events || {}
|
||||
|
||||
const addBlockEvent = ({ name, event }, block) => {
|
||||
const addBlockEvent = ({ name, event }: { name: string; event: any }, block: Block) => {
|
||||
if (!block) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!block.content) {
|
||||
block.content = {}
|
||||
block.content = {} as BlockContent
|
||||
}
|
||||
|
||||
if (!block.content.schema) {
|
||||
block.content.schema = {}
|
||||
block.content.schema = {} as BlockContent['schema']
|
||||
}
|
||||
|
||||
if (!block.content.schema.events) {
|
||||
|
|
@ -474,8 +492,8 @@ const addBlockEvent = ({ name, event }, block) => {
|
|||
block.content.schema.events[name] = event
|
||||
}
|
||||
|
||||
const removeEventLink = (linkedEventName) => {
|
||||
const events = getBlockEvents(getCurrentBlock())
|
||||
const removeEventLink = (linkedEventName: string) => {
|
||||
const events = getBlockEvents(getCurrentBlock()!)
|
||||
|
||||
Object.entries(events).forEach(([name, event]) => {
|
||||
if (linkedEventName === name) {
|
||||
|
|
@ -484,7 +502,7 @@ const removeEventLink = (linkedEventName) => {
|
|||
})
|
||||
}
|
||||
|
||||
const appendEventEmit = ({ eventName, functionName } = {}) => {
|
||||
const appendEventEmit = ({ eventName, functionName }: { eventName?: string; functionName?: string } = {}) => {
|
||||
if (!eventName || !functionName) {
|
||||
return
|
||||
}
|
||||
|
|
@ -495,8 +513,8 @@ const appendEventEmit = ({ eventName, functionName } = {}) => {
|
|||
const method = getMethods()?.[functionName]
|
||||
|
||||
if (method?.type === SCHEMA_DATA_TYPE.JSFunction) {
|
||||
const ast = parseExpression(method.value)
|
||||
const params = ast.params.map((param) => param.name)
|
||||
const ast: any = parseExpression(method.value)
|
||||
const params = ast.params.map((param: { name: string }) => param.name)
|
||||
const emitContent = `this.emit('${hyphenate(eventName.replace(/^on/i, ''))}', ${params.join(',')})`
|
||||
|
||||
// 如果方法里面已经有了相同的emit语句就不添加了
|
||||
|
|
@ -534,13 +552,13 @@ const selectedGroup = ref({ ...DEFAULT_GROUPS[0] })
|
|||
const selectedBlock = ref('')
|
||||
|
||||
// 已选择的区块数组,用于在当前分组里添加区块
|
||||
const selectedBlockArray = ref([])
|
||||
const selectedBlockArray = ref<Block[]>([])
|
||||
|
||||
// 是否刷新区块列表,在当前分组里添加/删除区块后通知刷新区块列表
|
||||
const isRefresh = ref(false)
|
||||
|
||||
// 切换分组时调用
|
||||
const groupChange = (group) => {
|
||||
const groupChange = (group?: BlockGroup) => {
|
||||
if (!group) return
|
||||
|
||||
// 需要改变selectedGroup的引用地址才能触发tiny-select组件的watch事件
|
||||
|
|
@ -551,7 +569,7 @@ const groupChange = (group) => {
|
|||
}
|
||||
|
||||
// 添加设计器默认区块分组
|
||||
const addDefaultGroup = (groups) => {
|
||||
const addDefaultGroup = (groups: BlockGroup[]) => {
|
||||
const result = DEFAULT_GROUPS.map((group) => ({
|
||||
label: group.groupName,
|
||||
value: group
|
||||
|
|
@ -573,15 +591,23 @@ const addDefaultGroup = (groups) => {
|
|||
}
|
||||
|
||||
// 是否是设计器默认区块分组
|
||||
const isDefaultGroupId = (groupId) => groupId === DEFAULT_GROUP_ID
|
||||
const isDefaultGroupId = (groupId: string) => groupId === DEFAULT_GROUP_ID
|
||||
|
||||
const isAllGroupId = (groupId) => groupId === DEFAULT_GROUPS[0].groupId
|
||||
const isAllGroupId = (groupId: string) => groupId === DEFAULT_GROUPS[0].groupId
|
||||
|
||||
// 获取今天的开始时间
|
||||
const getCurrentDate = () => new Date().setHours(0, 0, 0, 0)
|
||||
|
||||
interface DateInfo {
|
||||
nowDayOfWeek: number
|
||||
nowDay: number
|
||||
nowMonth: number
|
||||
nowYear: number
|
||||
lastMonth: number
|
||||
}
|
||||
|
||||
// 获取本周的开始时间
|
||||
const getCurrentWeek = (date) => {
|
||||
const getCurrentWeek = (date: DateInfo) => {
|
||||
const { nowDayOfWeek, nowDay, nowMonth, nowYear } = date
|
||||
const weekStartDate = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek + 1)
|
||||
|
||||
|
|
@ -589,7 +615,7 @@ const getCurrentWeek = (date) => {
|
|||
}
|
||||
|
||||
// 获取本月的开始时间
|
||||
const getCurrentMonth = (date) => {
|
||||
const getCurrentMonth = (date: DateInfo) => {
|
||||
const { nowMonth, nowYear } = date
|
||||
const monthStartDate = new Date(nowYear, nowMonth, 1)
|
||||
|
||||
|
|
@ -597,7 +623,7 @@ const getCurrentMonth = (date) => {
|
|||
}
|
||||
|
||||
// 获取上月的开始时间
|
||||
const getLastMonth = (date) => {
|
||||
const getLastMonth = (date: DateInfo) => {
|
||||
const { nowYear, lastMonth } = date
|
||||
const lastMonthStartDate = new Date(nowYear, lastMonth, 1)
|
||||
|
||||
|
|
@ -605,7 +631,7 @@ const getLastMonth = (date) => {
|
|||
}
|
||||
|
||||
// 判断时间戳属于今天/本周/本月/上月/更久以前
|
||||
const getDateFromNow = (timeStamp) => {
|
||||
const getDateFromNow = (timeStamp: number = 0) => {
|
||||
// 当前日期
|
||||
const now = new Date()
|
||||
const nowDay = now.getDate()
|
||||
|
|
@ -621,7 +647,7 @@ const getDateFromNow = (timeStamp) => {
|
|||
lastMonthDate.setMonth(lastMonthDate.getMonth() - 1)
|
||||
const lastMonth = lastMonthDate.getMonth()
|
||||
|
||||
const date = { nowDayOfWeek, nowDay, nowMonth, nowYear, lastMonth }
|
||||
const date: DateInfo = { nowDayOfWeek, nowDay, nowMonth, nowYear, lastMonth }
|
||||
|
||||
// 存在currentDateStart与currentWeekStart相同的情况,故不可以用currentDateStart作key
|
||||
const dateMap = new Map([
|
||||
|
|
@ -629,7 +655,7 @@ const getDateFromNow = (timeStamp) => {
|
|||
['本周', () => getCurrentWeek(date)],
|
||||
['本月', () => getCurrentMonth(date)],
|
||||
['上月', () => getLastMonth(date)],
|
||||
['更久以前', () => '']
|
||||
['更久以前', () => 0]
|
||||
])
|
||||
|
||||
for (const [key, value] of dateMap) {
|
||||
|
|
@ -642,14 +668,14 @@ const getDateFromNow = (timeStamp) => {
|
|||
}
|
||||
|
||||
// 将历史记录分组
|
||||
const splitBackupGroups = (data) => {
|
||||
const backupList = {}
|
||||
const splitBackupGroups = (data: { updated_at: string | number; message: string; id: string }[]) => {
|
||||
const backupList: Record<string, any> = {}
|
||||
|
||||
if (!data || !data.length) return backupList
|
||||
|
||||
data.sort((backup1, backup2) => new Date(backup2.updated_at) - new Date(backup1.updated_at))
|
||||
data.sort((backup1, backup2) => new Date(backup2.updated_at).getTime() - new Date(backup1.updated_at).getTime())
|
||||
data.forEach((item) => {
|
||||
const updateTime = item.updated_at && new Date(item.updated_at)
|
||||
const updateTime = item.updated_at ? new Date(item.updated_at) : null
|
||||
const title = getDateFromNow(updateTime?.getTime()) || ''
|
||||
backupList[title] = backupList[title] || []
|
||||
backupList[title].push({
|
||||
|
|
@ -663,24 +689,28 @@ const splitBackupGroups = (data) => {
|
|||
}
|
||||
|
||||
const sortTypeHandlerMap = {
|
||||
[SORT_TYPE.timeAsc]: (blockList) => {
|
||||
blockList.sort((block1, block2) => new Date(block1.updated_at) - new Date(block2.updated_at))
|
||||
[SORT_TYPE.timeAsc]: (blockList: Block[]) => {
|
||||
blockList.sort(
|
||||
(block1, block2) => new Date(block1.updated_at || '').getTime() - new Date(block2.updated_at || '').getTime()
|
||||
)
|
||||
},
|
||||
[SORT_TYPE.timeDesc]: (blockList) => {
|
||||
blockList.sort((block1, block2) => new Date(block2.updated_at) - new Date(block1.updated_at))
|
||||
[SORT_TYPE.timeDesc]: (blockList: Block[]) => {
|
||||
blockList.sort(
|
||||
(block1, block2) => new Date(block2.updated_at || '').getTime() - new Date(block1.updated_at || '').getTime()
|
||||
)
|
||||
},
|
||||
[SORT_TYPE.alphabetDesc]: (blockList) => {
|
||||
[SORT_TYPE.alphabetDesc]: (blockList: Block[]) => {
|
||||
// name_cn 包含中文,需要用 localeCompare
|
||||
blockList.sort((block1, block2) => (block2.name_cn || block2.label).localeCompare(block1.name_cn || block1.label))
|
||||
},
|
||||
[SORT_TYPE.alphabetAsc]: (blockList) => {
|
||||
[SORT_TYPE.alphabetAsc]: (blockList: Block[]) => {
|
||||
// name_cn 包含中文,需要用 localeCompare
|
||||
blockList.sort((block1, block2) => (block1.name_cn || block1.label).localeCompare(block2.name_cn || block2.label))
|
||||
}
|
||||
}
|
||||
|
||||
// 排序
|
||||
const sort = (blockList, type) => {
|
||||
const sort = (blockList: Block[], type: string) => {
|
||||
if (blockList.length === 0) return blockList
|
||||
|
||||
if (sortTypeHandlerMap[type]) {
|
||||
|
|
@ -694,7 +724,7 @@ const sort = (blockList, type) => {
|
|||
}
|
||||
|
||||
// 在可选区块列表里选择区块
|
||||
const check = (block) => {
|
||||
const check = (block: Block) => {
|
||||
if (selectedBlockArray.value.some((item) => item.id === block.id)) {
|
||||
return
|
||||
}
|
||||
|
|
@ -703,11 +733,11 @@ const check = (block) => {
|
|||
}
|
||||
|
||||
// 取消选择区块
|
||||
const cancelCheck = (block) => {
|
||||
const cancelCheck = (block: Block) => {
|
||||
selectedBlockArray.value = selectedBlockArray.value.filter((item) => item.id !== block.id)
|
||||
}
|
||||
|
||||
const checkAll = (blockList) => {
|
||||
const checkAll = (blockList: Block[]) => {
|
||||
selectedBlockArray.value = blockList
|
||||
}
|
||||
|
||||
|
|
@ -715,11 +745,11 @@ const cancelCheckAll = () => {
|
|||
selectedBlockArray.value = []
|
||||
}
|
||||
|
||||
const getBlockAssetsByVersion = (block, version) => {
|
||||
const getBlockAssetsByVersion = (block: Block, version?: string) => {
|
||||
let assets = block.assets
|
||||
|
||||
if (version) {
|
||||
const replaceUri = (uri) => uri.replace(/@\d{1,3}(\.\d{1,3}){0,2}\//, `@${version}/`)
|
||||
const replaceUri = (uri: string) => uri.replace(/@\d{1,3}(\.\d{1,3}){0,2}\//, `@${version}/`)
|
||||
|
||||
assets = {
|
||||
...block.assets,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,27 @@ const compareData = () => {
|
|||
return { isRecordSame, isDataSourceSame, isRemoteDataSame }
|
||||
}
|
||||
|
||||
const handleConfirmSave = (dataSourceState, isRecordSame, resolve, isDataSourceSame, callback) => {
|
||||
interface DataSourceState {
|
||||
dataSource: Record<string, any>
|
||||
record: Record<string, any>
|
||||
recordCopies: Record<string, any>
|
||||
dataSourceColumn: Record<string, any>
|
||||
dataSourceColumnCopies: Record<string, any>
|
||||
remoteData: Record<string, any>
|
||||
remoteDataCopies: Record<string, any>
|
||||
currentRecordId: string
|
||||
isRecordValidate: boolean
|
||||
disCard: boolean
|
||||
remoteConfig: Record<string, any>
|
||||
}
|
||||
|
||||
const handleConfirmSave = (
|
||||
dataSourceState: DataSourceState,
|
||||
isRecordSame: boolean,
|
||||
resolve: (value: unknown) => void,
|
||||
isDataSourceSame: boolean,
|
||||
callback: (...args: any[]) => any
|
||||
) => {
|
||||
let {
|
||||
name,
|
||||
data: { data, columns }
|
||||
|
|
@ -63,7 +83,7 @@ const handleConfirmSave = (dataSourceState, isRecordSame, resolve, isDataSourceS
|
|||
// 数据源数据修改,新增,数据源数据做修改
|
||||
if (dataSourceState.currentRecordId) {
|
||||
data = data || []
|
||||
const index = data.findIndex((item) => item.id === dataSourceState.currentRecordId)
|
||||
const index = data.findIndex((item: { id: string }) => item.id === dataSourceState.currentRecordId)
|
||||
|
||||
data[index] = Object.assign(data[index], dataSourceState.record)
|
||||
} else {
|
||||
|
|
@ -85,7 +105,7 @@ const handleConfirmSave = (dataSourceState, isRecordSame, resolve, isDataSourceS
|
|||
|
||||
const requestData = { name, data: { columns, data, type } }
|
||||
|
||||
callback(id, requestData).then((data) => {
|
||||
callback(id, requestData).then((data: any) => {
|
||||
if (data) {
|
||||
dataSourceState.record = {}
|
||||
dataSourceState.recordCopies = {}
|
||||
|
|
@ -100,7 +120,7 @@ const handleConfirmSave = (dataSourceState, isRecordSame, resolve, isDataSourceS
|
|||
return undefined
|
||||
}
|
||||
|
||||
const saveDataSource = (callback) => {
|
||||
const saveDataSource = (callback: (...args: any[]) => any) => {
|
||||
const { isRecordSame, isDataSourceSame } = compareData()
|
||||
const { confirm } = useModal()
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ const helpState = {
|
|||
}
|
||||
}
|
||||
|
||||
const getDocsUrl = (plugin) => {
|
||||
type PluginName = keyof typeof helpState['docsUrl']
|
||||
|
||||
const getDocsUrl = (plugin: PluginName) => {
|
||||
return `${getBaseUrl()}${helpState.docsUrl[plugin]}`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,12 +19,19 @@ import { PROP_DATA_TYPE } from '@opentiny/tiny-engine-common/js/constants'
|
|||
import { useResource, useCanvas, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
|
||||
|
||||
const { HOST_TYPE } = constants
|
||||
const state = reactive({
|
||||
const state = reactive<{ langs: Record<string, any> }>({
|
||||
langs: {}
|
||||
})
|
||||
|
||||
const currentLanguage = ref('zh_CN')
|
||||
const i18nResource = reactive({ messages: {}, locales: [] })
|
||||
const i18nResource = reactive<{
|
||||
messages: Record<string, any>
|
||||
locales: any[]
|
||||
[x: string]: any
|
||||
}>({
|
||||
messages: {},
|
||||
locales: []
|
||||
})
|
||||
const i18nApi = '/app-center/api/i18n/entries'
|
||||
const globalParams = {
|
||||
host: '',
|
||||
|
|
@ -60,7 +67,7 @@ const removeI18n = (key = []) => {
|
|||
* @returns
|
||||
*/
|
||||
|
||||
const ensureI18n = (obj, send) => {
|
||||
const ensureI18n = (obj: { [x: string]: any; key: string }, send?: boolean) => {
|
||||
const { locales } = i18nResource
|
||||
const contents = Object.fromEntries(locales.map(({ lang }) => [lang, obj[lang] || '']))
|
||||
const langs = getLangs()
|
||||
|
|
@ -93,16 +100,16 @@ const ensureI18n = (obj, send) => {
|
|||
}
|
||||
|
||||
try {
|
||||
const messages = {}
|
||||
const messages: Record<string, any> = {}
|
||||
Object.entries(contents).forEach(([locale, message]) => {
|
||||
messages[locale] = {
|
||||
[key]: message
|
||||
}
|
||||
})
|
||||
|
||||
useCanvas().canvasApi.value?.setLocales(messages, true)
|
||||
useCanvas().canvasApi.value?.setLocales?.(messages, true)
|
||||
} catch (e) {
|
||||
throw new Error(e)
|
||||
throw new Error(String(e))
|
||||
// 不需要处理,有报错的词条会在画布初始化的时候统一调setLocales这个方法
|
||||
}
|
||||
|
||||
|
|
@ -117,12 +124,19 @@ const getI18nData = () => {
|
|||
})
|
||||
}
|
||||
|
||||
const getI18n = async ({ init, local }) => {
|
||||
export interface I18nOptions {
|
||||
init?: boolean
|
||||
local?: any
|
||||
host?: string
|
||||
hostType?: string
|
||||
}
|
||||
|
||||
const getI18n = async ({ init, local }: I18nOptions): Promise<typeof appSchemaState.langs> => {
|
||||
const { appSchemaState } = useResource()
|
||||
|
||||
if (local) {
|
||||
const locales = appSchemaState?.langs?.locales || []
|
||||
const messages = {}
|
||||
const messages: Record<string, any> = {}
|
||||
const langs = getLangs()
|
||||
|
||||
if (Array.isArray(locales)) {
|
||||
|
|
@ -143,8 +157,8 @@ const getI18n = async ({ init, local }) => {
|
|||
}
|
||||
}
|
||||
|
||||
const initI18n = async ({ host, hostType, init, local }) => {
|
||||
globalParams.host = host
|
||||
const initI18n = async ({ host, hostType, init, local }: I18nOptions) => {
|
||||
globalParams.host = host || ''
|
||||
const hostTypeVar = 'host_type'
|
||||
globalParams[hostTypeVar] = hostType || HOST_TYPE.App
|
||||
|
||||
|
|
@ -165,23 +179,23 @@ const initI18n = async ({ host, hostType, init, local }) => {
|
|||
})
|
||||
}
|
||||
|
||||
const initAppI18n = async (appId) => {
|
||||
const initAppI18n = async (appId: string) => {
|
||||
if (appId) {
|
||||
await initI18n({
|
||||
host: appId,
|
||||
hostType: HOST_TYPE.App
|
||||
})
|
||||
useCanvas().canvasApi.value?.setLocales(i18nResource.messages)
|
||||
useCanvas().canvasApi.value?.setLocales?.(i18nResource.messages)
|
||||
}
|
||||
}
|
||||
|
||||
const initBlockI18n = async (blockId) => {
|
||||
const initBlockI18n = async (blockId: string) => {
|
||||
if (blockId) {
|
||||
await initI18n({
|
||||
host: blockId,
|
||||
hostType: HOST_TYPE.Block
|
||||
})
|
||||
useCanvas().canvasApi.value?.setLocales(i18nResource.messages)
|
||||
useCanvas().canvasApi.value?.setLocales?.(i18nResource.messages)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -192,12 +206,13 @@ const initBlockLocalI18n = async (langs = {}) => {
|
|||
hostType: HOST_TYPE.Block,
|
||||
local: true
|
||||
})
|
||||
useCanvas().canvasApi.value?.setLocales(i18nResource.messages)
|
||||
useCanvas().canvasApi.value?.setLocales?.(i18nResource.messages)
|
||||
}
|
||||
|
||||
const format = (str = '', params = {}) => str.replace(/\$\{(.+?)\}/g, (substr, key) => params[key] || '')
|
||||
const format = (str = '', params: Record<string, any> = {}) =>
|
||||
str.replace(/\$\{(.+?)\}/g, (_substr, key: string) => params[key] || '')
|
||||
|
||||
const translate = (obj) => {
|
||||
const translate = (obj: { [x: string]: any }) => {
|
||||
const { type, key = utils.guid() } = obj || {}
|
||||
|
||||
if (type === PROP_DATA_TYPE.I18N) {
|
||||
|
|
@ -213,13 +228,13 @@ const translate = (obj) => {
|
|||
|
||||
const getData = () => i18nResource.messages
|
||||
|
||||
const batchCreateI18n = ({ host, hostType }) => {
|
||||
const batchCreateI18n = ({ host, hostType }: Pick<I18nOptions, 'host' | 'hostType'>) => {
|
||||
if (!host) {
|
||||
return
|
||||
}
|
||||
|
||||
globalParams.host = host
|
||||
globalParams.host_type = hostType
|
||||
globalParams.host_type = hostType || ''
|
||||
|
||||
const { locales } = i18nResource
|
||||
const langs = getLangs()
|
||||
|
|
|
|||
|
|
@ -28,16 +28,39 @@ import {
|
|||
|
||||
const { COMPONENT_NAME, DEFAULT_INTERCEPTOR } = constants
|
||||
|
||||
const appSchemaState = reactive({
|
||||
interface AppSchemaState {
|
||||
dataSource: any[]
|
||||
pageTree: any[]
|
||||
langs: {
|
||||
locales: {
|
||||
lang: string
|
||||
}[]
|
||||
messages: any
|
||||
}
|
||||
utils: { [x: string]: any; type: string }[]
|
||||
globalState: any[]
|
||||
materialsDeps: {
|
||||
scripts: any[]
|
||||
styles: Set<unknown>
|
||||
}
|
||||
componentsMap?: any
|
||||
dataHandler?: any
|
||||
willFetch?: any
|
||||
errorHandler?: any
|
||||
bridge?: any
|
||||
isDemo?: boolean
|
||||
}
|
||||
|
||||
const appSchemaState = reactive<AppSchemaState>({
|
||||
dataSource: [],
|
||||
pageTree: [],
|
||||
langs: {},
|
||||
utils: {},
|
||||
langs: { locales: [], messages: {} },
|
||||
utils: [],
|
||||
globalState: [],
|
||||
materialsDeps: { scripts: [], styles: new Set() }
|
||||
})
|
||||
|
||||
function goPage(pageId) {
|
||||
function goPage(pageId: string) {
|
||||
if (!pageId) {
|
||||
return
|
||||
}
|
||||
|
|
@ -45,7 +68,16 @@ function goPage(pageId) {
|
|||
getMetaApi(META_SERVICE.GlobalService).updatePageId(pageId)
|
||||
}
|
||||
|
||||
const initPage = (pageInfo) => {
|
||||
interface PageInfo {
|
||||
[x: string]: any
|
||||
meta: any
|
||||
id: string
|
||||
fileName: string
|
||||
componentName: string
|
||||
props: any
|
||||
}
|
||||
|
||||
const initPage = (pageInfo: PageInfo) => {
|
||||
try {
|
||||
if (pageInfo.meta) {
|
||||
const { occupier } = pageInfo.meta
|
||||
|
|
@ -77,12 +109,12 @@ const initPage = (pageInfo) => {
|
|||
* 根据区块 id 初始化应用
|
||||
* @param {string} blockId 区块 id
|
||||
*/
|
||||
const initBlock = async (blockId) => {
|
||||
const initBlock = async (blockId: string) => {
|
||||
const blockApi = getMetaApi(META_APP.BlockManage)
|
||||
const blockContent = await blockApi.getBlockById(blockId)
|
||||
|
||||
if (blockContent.public_scope_tenants.length) {
|
||||
blockContent.public_scope_tenants = blockContent.public_scope_tenants.map((e) => e.id)
|
||||
blockContent.public_scope_tenants = blockContent.public_scope_tenants.map((e: { id: string }) => e.id)
|
||||
}
|
||||
|
||||
useLayout().layoutState.pageStatus = getCanvasStatus(blockContent?.occupier)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export const metaHashMap: Record<string, any> = {}
|
|||
export const apisMap: Record<string, any> = {}
|
||||
export const optionsMap: Record<string, any> = {}
|
||||
|
||||
export const getMetaApi = (id: string, key: string) => {
|
||||
export const getMetaApi = (id: string, key?: string) => {
|
||||
if (!apisMap[id]) {
|
||||
return
|
||||
}
|
||||
|
|
@ -144,14 +144,14 @@ const handleRegistryProp = (id: string, value: any) => {
|
|||
|
||||
export const preprocessRegistry = (registry: Array<any> | { [s: string]: any }) => {
|
||||
// 元应用支持使用长度为2的数组来配置,第一个参数为元应用,第二个参数是额外的自定义配置。此函数判断数组是否属于这种配置格式
|
||||
const isArrayFormat = (arr) => Array.isArray(arr) && arr.length === 2 && arr[0].id
|
||||
const isArrayFormat = (arr: any) => Array.isArray(arr) && arr.length === 2 && arr[0].id
|
||||
|
||||
Object.values(registry)
|
||||
.filter((metaApps) => Array.isArray(metaApps))
|
||||
.forEach((metaApps) => {
|
||||
// normal: { plugins: [ Page, Block, ... ] }
|
||||
// array format: { plugins: [ [ Page, { options: extraOptions } ], Block, ... ] }
|
||||
metaApps.forEach((metaApp, index) => {
|
||||
metaApps.forEach((metaApp: any, index: number) => {
|
||||
if (isArrayFormat(metaApp)) {
|
||||
metaApps.splice(index, 1, { ...metaApp[0], ...metaApp[1] })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,23 @@
|
|||
import type {
|
||||
NotifyParams,
|
||||
NotifyResult,
|
||||
UseBlockApi,
|
||||
UseBreadcrumbApi,
|
||||
UseCanvasApi,
|
||||
UseDataSourceApi,
|
||||
UseHelpApi,
|
||||
UseHistoryApi,
|
||||
UseLayoutApi,
|
||||
UseMaterialApi,
|
||||
UseModalApi,
|
||||
UsePageApi,
|
||||
UsePropertiesApi,
|
||||
UsePropertyApi,
|
||||
UseResourceApi,
|
||||
UseSaveLocalApi,
|
||||
UseTranslateApi
|
||||
} from './types'
|
||||
|
||||
export const HOOK_NAME = {
|
||||
useLayout: 'layout',
|
||||
useCanvas: 'canvas',
|
||||
|
|
@ -19,7 +39,9 @@ export const HOOK_NAME = {
|
|||
useCustom: 'custom',
|
||||
useMaterial: 'material',
|
||||
useStyle: 'style'
|
||||
}
|
||||
} as const
|
||||
|
||||
type HookName = typeof HOOK_NAME[keyof typeof HOOK_NAME]
|
||||
|
||||
const hooksState = {
|
||||
[HOOK_NAME.useLayout]: {},
|
||||
|
|
@ -44,36 +66,36 @@ const hooksState = {
|
|||
[HOOK_NAME.useCustom]: {} // 自定义
|
||||
}
|
||||
|
||||
const getHook = (hookName: string, args: any[]) => {
|
||||
const getHook = (hookName: HookName, args: any[]) => {
|
||||
if (typeof hooksState[hookName] === 'function') {
|
||||
return hooksState[hookName](...args)
|
||||
}
|
||||
return hooksState[hookName]
|
||||
}
|
||||
|
||||
export const useLayout = (...args: any[]) => getHook(HOOK_NAME.useLayout, args)
|
||||
export const useCanvas = (...args: any[]) => getHook(HOOK_NAME.useCanvas, args)
|
||||
export const useResource = (...args: any[]) => getHook(HOOK_NAME.useResource, args)
|
||||
export const useHistory = (...args: any[]) => getHook(HOOK_NAME.useHistory, args)
|
||||
export const useProperties = (...args: any[]) => getHook(HOOK_NAME.useProperties, args)
|
||||
export const useSaveLocal = (...args: any[]) => getHook(HOOK_NAME.useSaveLocal, args)
|
||||
export const useBlock = (...args: any[]) => getHook(HOOK_NAME.useBlock, args)
|
||||
export const useTranslate = (...args: any[]) => getHook(HOOK_NAME.useTranslate, args)
|
||||
export const usePage = (...args: any[]) => getHook(HOOK_NAME.usePage, args)
|
||||
export const useDataSource = (...args: any[]) => getHook(HOOK_NAME.useDataSource, args)
|
||||
export const useBreadcrumb = (...args: any[]) => getHook(HOOK_NAME.useBreadcrumb, args)
|
||||
export const useProperty = (...args: any[]) => getHook(HOOK_NAME.useProperty, args)
|
||||
export const useHelp = (...args: any[]) => getHook(HOOK_NAME.useHelp, args)
|
||||
export const useLayout = (...args: any[]): UseLayoutApi => getHook(HOOK_NAME.useLayout, args)
|
||||
export const useCanvas = (...args: any[]): UseCanvasApi => getHook(HOOK_NAME.useCanvas, args)
|
||||
export const useResource = (...args: any[]): UseResourceApi => getHook(HOOK_NAME.useResource, args)
|
||||
export const useHistory = (...args: any[]): UseHistoryApi => getHook(HOOK_NAME.useHistory, args)
|
||||
export const useProperties = (...args: any[]): UsePropertiesApi => getHook(HOOK_NAME.useProperties, args)
|
||||
export const useSaveLocal = (...args: any[]): UseSaveLocalApi => getHook(HOOK_NAME.useSaveLocal, args)
|
||||
export const useBlock = (...args: any[]): UseBlockApi => getHook(HOOK_NAME.useBlock, args)
|
||||
export const useTranslate = (...args: any[]): UseTranslateApi => getHook(HOOK_NAME.useTranslate, args)
|
||||
export const usePage = (...args: any[]): UsePageApi => getHook(HOOK_NAME.usePage, args)
|
||||
export const useDataSource = (...args: any[]): UseDataSourceApi => getHook(HOOK_NAME.useDataSource, args)
|
||||
export const useBreadcrumb = (...args: any[]): UseBreadcrumbApi => getHook(HOOK_NAME.useBreadcrumb, args)
|
||||
export const useProperty = (...args: any[]): UsePropertyApi => getHook(HOOK_NAME.useProperty, args)
|
||||
export const useHelp = (...args: any[]): UseHelpApi => getHook(HOOK_NAME.useHelp, args)
|
||||
export const useHttp = (...args: any[]) => getHook(HOOK_NAME.useHttp, args)
|
||||
export const useEnv = (...args: any[]) => getHook(HOOK_NAME.useEnv, args)
|
||||
export const useModal = (...args: any[]) => getHook(HOOK_NAME.useModal, args)
|
||||
export const useNotify = (...args: any[]) => getHook(HOOK_NAME.useNotify, args)
|
||||
export const useMaterial = (...args: any[]) => getHook(HOOK_NAME.useMaterial, args)
|
||||
export const useEnv = (...args: any[]): ImportMetaEnv => getHook(HOOK_NAME.useEnv, args)
|
||||
export const useModal = (...args: any[]): UseModalApi => getHook(HOOK_NAME.useModal, args)
|
||||
export const useNotify = (...args: NotifyParams): NotifyResult => getHook(HOOK_NAME.useNotify, args)
|
||||
export const useMaterial = (...args: any[]): UseMaterialApi => getHook(HOOK_NAME.useMaterial, args)
|
||||
export const useStyle = (...args: any[]) => getHook(HOOK_NAME.useStyle, args)
|
||||
export const useCustom = (...args: any[]) => getHook(HOOK_NAME.useCustom, args)
|
||||
|
||||
export function initHook(
|
||||
hookName: string,
|
||||
hookName: HookName,
|
||||
hookContent: any,
|
||||
{ useDefaultExport } = {} as { useDefaultExport?: boolean }
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
import type { default as useCanvasApi } from '@opentiny/tiny-engine-canvas/DesignCanvas/src/api'
|
||||
import type { LayoutService } from '@opentiny/tiny-engine-layout'
|
||||
import type { BlockService } from '@opentiny/tiny-engine-plugin-block'
|
||||
import type { DataSourceService } from '@opentiny/tiny-engine-plugin-datasource'
|
||||
import type { HelpService } from '@opentiny/tiny-engine-plugin-help'
|
||||
import type { TranslateService } from '@opentiny/tiny-engine-plugin-i18n'
|
||||
import type { MaterialService, ResourceService } from '@opentiny/tiny-engine-plugin-materials'
|
||||
import type { PageService } from '@opentiny/tiny-engine-plugin-page'
|
||||
import type { PropertiesService, PropertyService } from '@opentiny/tiny-engine-setting-props'
|
||||
import type { BreadcrumbService } from '@opentiny/tiny-engine-toolbar-breadcrumb'
|
||||
import type { SaveLocalService } from '@opentiny/tiny-engine-toolbar-generate-code'
|
||||
import type { HistoryService } from '@opentiny/tiny-engine-toolbar-redoundo'
|
||||
import type { Modal, Notify } from '@opentiny/tiny-engine-common'
|
||||
|
||||
export type UseCanvasApi = ReturnType<typeof useCanvasApi>
|
||||
export type UseLayoutApi = typeof LayoutService['apis']
|
||||
|
||||
// plugin
|
||||
export type UseBlockApi = typeof BlockService['apis']
|
||||
export type UseDataSourceApi = typeof DataSourceService['apis']
|
||||
export type UseHelpApi = typeof HelpService['apis']
|
||||
export type UseTranslateApi = typeof TranslateService['apis']
|
||||
export type UseMaterialApi = typeof MaterialService['apis']
|
||||
export type UseResourceApi = typeof ResourceService['apis']
|
||||
export type UsePageApi = typeof PageService['apis']
|
||||
|
||||
// setting
|
||||
export type UsePropertiesApi = typeof PropertiesService['apis']
|
||||
export type UsePropertyApi = typeof PropertyService['apis']
|
||||
|
||||
// toolbar
|
||||
export type UseBreadcrumbApi = typeof BreadcrumbService['apis']
|
||||
export type UseSaveLocalApi = typeof SaveLocalService['apis']
|
||||
export type UseHistoryApi = typeof HistoryService['apis']
|
||||
|
||||
export type UseModalApi = typeof Modal
|
||||
export type NotifyParams = Parameters<typeof Notify>
|
||||
export type NotifyResult = ReturnType<typeof Notify>
|
||||
|
|
@ -18,7 +18,7 @@ const CONSTANTS = {
|
|||
BLOCKTEXT: '区块'
|
||||
}
|
||||
|
||||
const setBreadcrumbPage = (value: string) => {
|
||||
const setBreadcrumbPage = (value: any) => {
|
||||
breadcrumbData.value = [CONSTANTS.PAGETEXT, ...value]
|
||||
sessionStorage.setItem('pageInfo', value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,65 +16,44 @@
|
|||
"paths": {
|
||||
"@/*": ["packages/*"],
|
||||
"@opentiny/tiny-engine": ["packages/design-core/index.js"],
|
||||
"@opentiny/tiny-engine-meta-register": ["packages/register/src/index.js"],
|
||||
"@opentiny/tiny-engine-canvas": ["packages/canvas/src/index"],
|
||||
"@opentiny/tiny-engine-plugin-materials": ["packages/plugins/materials/index"],
|
||||
"@opentiny/tiny-engine-plugin-state": ["packages/plugins/state/index"],
|
||||
"@opentiny/tiny-engine-plugin-script": ["packages/plugins/script/index"],
|
||||
"@opentiny/tiny-engine-plugin-tree": ["packages/plugins/tree/index"],
|
||||
"@opentiny/tiny-engine-plugin-help": ["packages/plugins/help/index"],
|
||||
"@opentiny/tiny-engine-plugin-schema": ["packages/plugins/schema/index"],
|
||||
"@opentiny/tiny-engine-plugin-page": ["packages/plugins/page/index"],
|
||||
"@opentiny/tiny-engine-plugin-i18n": ["packages/plugins/i18n/index"],
|
||||
"@opentiny/tiny-engine-canvas": ["packages/canvas/index"],
|
||||
"@opentiny/tiny-engine-canvas/*": ["packages/canvas/*"],
|
||||
"@opentiny/tiny-engine-common": ["packages/common/index"],
|
||||
"@opentiny/tiny-engine-common/*": ["packages/common/*"],
|
||||
"@opentiny/tiny-engine-i18n-host": ["packages/i18n/src/lib"],
|
||||
"@opentiny/tiny-engine-layout": ["packages/layout/index"],
|
||||
"@opentiny/tiny-engine-meta-register": ["packages/register/src/index"],
|
||||
"@opentiny/tiny-engine-plugin-block": ["packages/plugins/block/index"],
|
||||
"@opentiny/tiny-engine-plugin-bridge": ["packages/plugins/bridge/index"],
|
||||
"@opentiny/tiny-engine-plugin-datasource": ["packages/plugins/datasource/index"],
|
||||
"@opentiny/tiny-engine-plugin-help": ["packages/plugins/help/index"],
|
||||
"@opentiny/tiny-engine-plugin-i18n": ["packages/plugins/i18n/index"],
|
||||
"@opentiny/tiny-engine-plugin-materials": ["packages/plugins/materials/index"],
|
||||
"@opentiny/tiny-engine-plugin-page": ["packages/plugins/page/index"],
|
||||
"@opentiny/tiny-engine-plugin-schema": ["packages/plugins/schema/index"],
|
||||
"@opentiny/tiny-engine-plugin-script": ["packages/plugins/script/index"],
|
||||
"@opentiny/tiny-engine-plugin-state": ["packages/plugins/state/index"],
|
||||
"@opentiny/tiny-engine-plugin-tree": ["packages/plugins/tree/index"],
|
||||
"@opentiny/tiny-engine-setting-events": ["packages/settings/events/index"],
|
||||
"@opentiny/tiny-engine-setting-props": ["packages/settings/props/index"],
|
||||
"@opentiny/tiny-engine-common": ["packages/common/index"],
|
||||
"@opentiny/tiny-engine-setting-styles": ["packages/settings/styles/index"],
|
||||
"@opentiny/tiny-engine-svgs": ["packages/svgs/index"],
|
||||
"@opentiny/tiny-engine-toolbar-breadcrumb": ["packages/toolbars/breadcrumb/index"],
|
||||
"@opentiny/tiny-engine-toolbar-clean": ["packages/toolbars/clean/index"],
|
||||
"@opentiny/tiny-engine-toolbar-fullscreen": ["packages/toolbars/fullscreen/index"],
|
||||
"@opentiny/tiny-engine-toolbar-generate-code": ["packages/toolbars/generate-code/index"],
|
||||
"@opentiny/tiny-engine-toolbar-lang": ["packages/toolbars/lang/index"],
|
||||
"@opentiny/tiny-engine-toolbar-view-setting": ["packages/toolbars/view-setting/index"],
|
||||
"@opentiny/tiny-engine-toolbar-layout": ["packages/toolbars/layout/index"],
|
||||
"@opentiny/tiny-engine-toolbar-lock": ["packages/toolbars/lock/index"],
|
||||
"@opentiny/tiny-engine-toolbar-logo": ["packages/toolbars/logo/index"],
|
||||
"@opentiny/tiny-engine-toolbar-media": ["packages/toolbars/media/index"],
|
||||
"@opentiny/tiny-engine-toolbar-preview": ["packages/toolbars/preview/index"],
|
||||
"@opentiny/tiny-engine-toolbar-generate-code": ["packages/toolbars/generate-code/index"],
|
||||
"@opentiny/tiny-engine-toolbar-clean": ["packages/toolbars/clean/index"],
|
||||
"@opentiny/tiny-engine-toolbar-theme-switch": ["packages/toolbars/themeSwitch/index"],
|
||||
"@opentiny/tiny-engine-toolbar-redoundo": ["packages/toolbars/redoundo/index"],
|
||||
"@opentiny/tiny-engine-toolbar-save": ["packages/toolbars/save/index"],
|
||||
"tiny-engine-canvas": ["packages/canvas/index"],
|
||||
"@opentiny/tiny-engine-svgs": ["packages/svgs/index"],
|
||||
"@opentiny/tiny-engine-plugin-materials/*": ["packages/plugins/materials/*"],
|
||||
"@opentiny/tiny-engine-plugin-state/*": ["packages/plugins/state/*"],
|
||||
"@opentiny/tiny-engine-plugin-script/*": ["packages/plugins/script/*"],
|
||||
"@opentiny/tiny-engine-plugin-tree/*": ["packages/plugins/tree/*"],
|
||||
"@opentiny/tiny-engine-plugin-help/*": ["packages/plugins/help/*"],
|
||||
"@opentiny/tiny-engine-plugin-schema/*": ["packages/plugins/schema/*"],
|
||||
"@opentiny/tiny-engine-plugin-page/*": ["packages/plugins/page/*"],
|
||||
"@opentiny/tiny-engine-plugin-i18n/*": ["packages/plugins/i18n/*"],
|
||||
"@opentiny/tiny-engine-plugin-bridge/*": ["packages/plugins/bridge/*"],
|
||||
"@opentiny/tiny-engine-setting-events/*": ["packages/settings/events/*"],
|
||||
"@opentiny/tiny-engine-setting-props/*": ["packages/settings/props/*"],
|
||||
"@opentiny/tiny-engine-common/*": ["packages/common/*"],
|
||||
"@opentiny/tiny-engine-setting-styles/*": ["packages/settings/styles/*"],
|
||||
"@opentiny/tiny-engine-toolbar-breadcrumb/*": ["packages/toolbars/breadcrumb/*"],
|
||||
"@opentiny/tiny-engine-toolbar-fullscreen/*": ["packages/toolbars/fullscreen/*"],
|
||||
"@opentiny/tiny-engine-toolbar-lang/*": ["packages/toolbars/lang/*"],
|
||||
"@opentiny/tiny-engine-toolbar-view-setting/*": ["packages/toolbars/view-setting/*"],
|
||||
"@opentiny/tiny-engine-toolbar-layout/*": ["packages/toolbars/layout/*"],
|
||||
"@opentiny/tiny-engine-toolbar-lock/*": ["packages/toolbars/lock/*"],
|
||||
"@opentiny/tiny-engine-toolbar-logo/*": ["packages/toolbars/logo/*"],
|
||||
"@opentiny/tiny-engine-toolbar-media/*": ["packages/toolbars/media/*"],
|
||||
"@opentiny/tiny-engine-toolbar-preview/*": ["packages/toolbars/preview/*"],
|
||||
"@opentiny/tiny-engine-toolbar-clean/*": ["packages/toolbars/clean/*"],
|
||||
"@opentiny/tiny-engine-toolbar-theme-switch/*": ["packages/toolbars/themeSwitch/*"],
|
||||
"@opentiny/tiny-engine-toolbar-save/*": ["packages/toolbars/save/*"],
|
||||
"@opentiny/tiny-engine-svgs/*": ["packages/svgs/*"],
|
||||
"@opentiny/tiny-engine-utils": ["packages/utils/src/index.ts"],
|
||||
"@opentiny/tiny-engine-webcomponent-core": ["packages/webcomponent/src/lib"],
|
||||
"@opentiny/tiny-engine-i18n-host": ["packages/i18n/src/lib"]
|
||||
"@opentiny/tiny-engine-toolbar-theme-switch": ["packages/toolbars/themeSwitch/index"],
|
||||
"@opentiny/tiny-engine-toolbar-view-setting": ["packages/toolbars/view-setting/index"],
|
||||
"@opentiny/tiny-engine-utils": ["packages/utils/src/index"],
|
||||
"@opentiny/tiny-engine-webcomponent-core": ["packages/webcomponent/src/lib"]
|
||||
}
|
||||
},
|
||||
"include": ["packages/**/*"],
|
||||
|
|
|
|||
Loading…
Reference in New Issue