diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index 4d414d9aa..000000000 --- a/jsconfig.json +++ /dev/null @@ -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"] -} diff --git a/packages/canvas/DesignCanvas/src/api/types.ts b/packages/canvas/DesignCanvas/src/api/types.ts new file mode 100644 index 000000000..a00d11b2b --- /dev/null +++ b/packages/canvas/DesignCanvas/src/api/types.ts @@ -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 + 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' }) diff --git a/packages/canvas/DesignCanvas/src/api/useCanvas.ts b/packages/canvas/DesignCanvas/src/api/useCanvas.ts index f494a54a7..e247bf99f 100644 --- a/packages/canvas/DesignCanvas/src/api/useCanvas.ts +++ b/packages/canvas/DesignCanvas/src/api/useCanvas.ts @@ -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>({}) const isCanvasApiReady = ref(false) -const nodesMap = ref(new Map()) +const nodesMap = ref(new Map()) -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 = {}) => { 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 = {}) => { state.isBlock = false resetCanvasState(state) useHistory().addHistory(state.pageSchema) } // 区块重置画布数据 -const resetBlockCanvasState = async (state = {}) => { +const resetBlockCanvasState = async (state: Partial = {}) => { 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) => { + if (!pageState.pageSchema) { + return + } + Object.assign(pageState.pageSchema, data) publish({ topic: 'schemaChange', data: {} }) diff --git a/packages/canvas/container/src/composables/useMultiSelect.ts b/packages/canvas/container/src/composables/useMultiSelect.ts index abb78e39a..3d645806b 100644 --- a/packages/canvas/container/src/composables/useMultiSelect.ts +++ b/packages/canvas/container/src/composables/useMultiSelect.ts @@ -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([]) 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 } diff --git a/packages/canvas/container/src/container.ts b/packages/canvas/container/src/container.ts index 7e728a25c..e86fa26fc 100644 --- a/packages/canvas/container/src/container.ts +++ b/packages/canvas/container/src/container.ts @@ -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 | 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, 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 | 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 diff --git a/packages/canvas/package.json b/packages/canvas/package.json index f811e4e6d..30dbf84e9 100644 --- a/packages/canvas/package.json +++ b/packages/canvas/package.json @@ -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", diff --git a/packages/canvas/render/src/canvas-function/design-mode.ts b/packages/canvas/render/src/canvas-function/design-mode.ts index 977bc05e7..6affae934 100644 --- a/packages/canvas/render/src/canvas-function/design-mode.ts +++ b/packages/canvas/render/src/canvas-function/design-mode.ts @@ -8,6 +8,6 @@ let designMode = DESIGN_MODE.DESIGN export const getDesignMode = () => designMode -export const setDesignMode = (mode) => { +export const setDesignMode = (mode: string) => { designMode = mode } diff --git a/packages/canvas/types.ts b/packages/canvas/types.ts new file mode 100644 index 000000000..31a691b9e --- /dev/null +++ b/packages/canvas/types.ts @@ -0,0 +1,20 @@ +export interface Node { + id: string + componentName: string + props: Record & { columns?: { slots?: Record }[] } + children?: Node[] +} + +export type RootNode = Omit & { + id?: string + css?: string + fileName?: string + methods?: Record + state?: Record + lifeCycles?: Record + dataSource?: any + bridge?: any + inputs?: any[] + outputs?: any[] + schema?: any +} diff --git a/packages/common/component/Modal.jsx b/packages/common/component/Modal.tsx similarity index 65% rename from packages/common/component/Modal.jsx rename to packages/common/component/Modal.tsx index 8e350e416..189255bfd 100644 --- a/packages/common/component/Modal.jsx +++ b/packages/common/component/Modal.tsx @@ -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 }) => ) } - }).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 & { 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 diff --git a/packages/common/component/Notify.jsx b/packages/common/component/Notify.tsx similarity index 65% rename from packages/common/component/Notify.jsx rename to packages/common/component/Notify.tsx index 4ec4661e0..5846337dd 100644 --- a/packages/common/component/Notify.jsx +++ b/packages/common/component/Notify.tsx @@ -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({ diff --git a/packages/common/component/index.js b/packages/common/component/index.ts similarity index 95% rename from packages/common/component/index.js rename to packages/common/component/index.ts index 98da34cce..5143f0160 100644 --- a/packages/common/component/index.js +++ b/packages/common/component/index.ts @@ -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) => { const globalComponents = { ConfigGroup, ConfigItem diff --git a/packages/layout/src/composable/useLayout.js b/packages/layout/src/composable/useLayout.js index 8595eb2ff..0d54dc4c6 100644 --- a/packages/layout/src/composable/useLayout.js +++ b/packages/layout/src/composable/useLayout.js @@ -59,7 +59,10 @@ const layoutState = reactive({ toolbars: { visiblePopover: false }, - pageStatus: '' + pageStatus: { + state: '', + data: {} + } }) const getMoveDragBarState = () => { return layoutState.isMoveDragBar diff --git a/packages/plugins/block/src/composable/types.ts b/packages/plugins/block/src/composable/types.ts new file mode 100644 index 000000000..5c2132a8a --- /dev/null +++ b/packages/plugins/block/src/composable/types.ts @@ -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 + children: any[] + schema: { + properties?: Property[] + events?: Record + } + state?: Record + methods: Record + dataSource?: Record + 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 + methods: Record + state: Record + classNameList: string[] + contentList: any[] +} + +export type ParsePropToDataOptons = Pick & { + prop: { + type: string + key: string + value: any + } +} + +export type ParseChildPropsOptions = Pick & { + child: { + props: Record + [x: string]: any + } +} + +export interface CreateBlockOptions { + name_cn: string + label: string + path?: string + categories: string[] +} + +export type CreateEmptyBlockOptions = Pick diff --git a/packages/plugins/block/src/composable/useBlock.ts b/packages/plugins/block/src/composable/useBlock.ts index 750e8523e..a6a93460c 100644 --- a/packages/plugins/block/src/composable/useBlock.ts +++ b/packages/plugins/block/src/composable/useBlock.ts @@ -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([ { label: { zh_CN: '基础信息' @@ -55,7 +67,7 @@ const DEFAULT_PROPERTIES = readonly([ } ]) -const DEFAULT_BLOCK = readonly({ +const DEFAULT_BLOCK = readonly>({ 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, contentList: string[], methods: Record) => { const content = schema?.properties?.[0]?.content || [] - let emitList = [] - const emitListCopies = {} + let emitList: string[] = [] + const emitListCopies: Record = {} 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) => { + const methodsListCopies: Record = {} // 因为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 = {}, methodsObj: Record = {}) => { + const stateCopies: Record = {} 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([]) // 是否刷新区块列表,在当前分组里添加/删除区块后通知刷新区块列表 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 = {} 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, diff --git a/packages/plugins/datasource/src/composable/useDataSource.ts b/packages/plugins/datasource/src/composable/useDataSource.ts index 70fefc62f..4b61c8cc1 100644 --- a/packages/plugins/datasource/src/composable/useDataSource.ts +++ b/packages/plugins/datasource/src/composable/useDataSource.ts @@ -45,7 +45,27 @@ const compareData = () => { return { isRecordSame, isDataSourceSame, isRemoteDataSame } } -const handleConfirmSave = (dataSourceState, isRecordSame, resolve, isDataSourceSame, callback) => { +interface DataSourceState { + dataSource: Record + record: Record + recordCopies: Record + dataSourceColumn: Record + dataSourceColumnCopies: Record + remoteData: Record + remoteDataCopies: Record + currentRecordId: string + isRecordValidate: boolean + disCard: boolean + remoteConfig: Record +} + +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() diff --git a/packages/plugins/help/src/composable/useHelp.ts b/packages/plugins/help/src/composable/useHelp.ts index 8240c3ccc..c2b19428c 100644 --- a/packages/plugins/help/src/composable/useHelp.ts +++ b/packages/plugins/help/src/composable/useHelp.ts @@ -25,7 +25,9 @@ const helpState = { } } -const getDocsUrl = (plugin) => { +type PluginName = keyof typeof helpState['docsUrl'] + +const getDocsUrl = (plugin: PluginName) => { return `${getBaseUrl()}${helpState.docsUrl[plugin]}` } diff --git a/packages/plugins/i18n/src/composable/useTranslate.ts b/packages/plugins/i18n/src/composable/useTranslate.ts index 377794f40..f93421690 100644 --- a/packages/plugins/i18n/src/composable/useTranslate.ts +++ b/packages/plugins/i18n/src/composable/useTranslate.ts @@ -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 }>({ langs: {} }) const currentLanguage = ref('zh_CN') -const i18nResource = reactive({ messages: {}, locales: [] }) +const i18nResource = reactive<{ + messages: Record + 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 = {} 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 => { const { appSchemaState } = useResource() if (local) { const locales = appSchemaState?.langs?.locales || [] - const messages = {} + const messages: Record = {} 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 = {}) => + 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) => { if (!host) { return } globalParams.host = host - globalParams.host_type = hostType + globalParams.host_type = hostType || '' const { locales } = i18nResource const langs = getLangs() diff --git a/packages/plugins/materials/src/composable/useResource.ts b/packages/plugins/materials/src/composable/useResource.ts index 225d9198f..052da714a 100644 --- a/packages/plugins/materials/src/composable/useResource.ts +++ b/packages/plugins/materials/src/composable/useResource.ts @@ -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 + } + componentsMap?: any + dataHandler?: any + willFetch?: any + errorHandler?: any + bridge?: any + isDemo?: boolean +} + +const appSchemaState = reactive({ 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) diff --git a/packages/register/src/common.ts b/packages/register/src/common.ts index 1016abbee..75c806db1 100644 --- a/packages/register/src/common.ts +++ b/packages/register/src/common.ts @@ -51,7 +51,7 @@ export const metaHashMap: Record = {} export const apisMap: Record = {} export const optionsMap: Record = {} -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 | { [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] }) } diff --git a/packages/register/src/hooks.ts b/packages/register/src/hooks.ts index 60eb82f47..837c9ce00 100644 --- a/packages/register/src/hooks.ts +++ b/packages/register/src/hooks.ts @@ -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 } ) { diff --git a/packages/register/src/types.ts b/packages/register/src/types.ts new file mode 100644 index 000000000..e47b3dc65 --- /dev/null +++ b/packages/register/src/types.ts @@ -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 +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 +export type NotifyResult = ReturnType diff --git a/packages/toolbars/breadcrumb/src/composable/useBreadcrumb.ts b/packages/toolbars/breadcrumb/src/composable/useBreadcrumb.ts index 02096da86..4bf778747 100644 --- a/packages/toolbars/breadcrumb/src/composable/useBreadcrumb.ts +++ b/packages/toolbars/breadcrumb/src/composable/useBreadcrumb.ts @@ -18,7 +18,7 @@ const CONSTANTS = { BLOCKTEXT: '区块' } -const setBreadcrumbPage = (value: string) => { +const setBreadcrumbPage = (value: any) => { breadcrumbData.value = [CONSTANTS.PAGETEXT, ...value] sessionStorage.setItem('pageInfo', value) } diff --git a/tsconfig.app.json b/tsconfig.app.json index 6c00d32a9..fd1e71b1d 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -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/**/*"],