* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
import { reactive, toRaw } from 'vue'
import { constants } from '@opentiny/tiny-engine-utils'
import { getCanvasStatus } from '@opentiny/tiny-engine-common/js/canvas'
import {
useCanvas,
useTranslate,
useBreadcrumb,
useLayout,
useBlock,
useMaterial,
getMetaApi,
META_APP,
useMessage,
META_SERVICE
} from '@opentiny/tiny-engine-meta-register'
const { COMPONENT_NAME, DEFAULT_INTERCEPTOR } = constants
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: { locales: [], messages: {} },
utils: [],
globalState: [],
materialsDeps: { scripts: [], styles: new Set() }
})
function goPage(pageId: string) {
if (!pageId) {
return
}
getMetaApi(META_SERVICE.GlobalService).updatePageId(pageId)
}
interface PageInfo {
[x: string]: any
meta: any
id: string
fileName: string
componentName: string
props: any
}
const initPage = (pageInfo: PageInfo) => {
try {
if (pageInfo?.id || typeof pageInfo?.id === 'number') {
useLayout().layoutState.pageStatus = getCanvasStatus(pageInfo.occupier)
goPage(pageInfo.id)
} else {
useLayout().layoutState.pageStatus = {
state: 'empty',
data: {}
}
}
} catch (error) {
console.log(error)
}
useCanvas().initData(pageInfo?.page_content || {}, pageInfo)
useBreadcrumb().setBreadcrumbPage([pageInfo?.name || ''])
}
* 根据区块 id 初始化应用
* @param {string} blockId 区块 id
*/
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: { id: string }) => e.id)
}
useLayout().layoutState.pageStatus = getCanvasStatus(blockContent?.occupier)
useBlock().initBlock(blockContent, {}, true)
}
const initPageOrBlock = async () => {
const { pageId, blockId } = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()
const pagePluginApi = getMetaApi(META_APP.AppManage)
const userInfo = getMetaApi(META_SERVICE.GlobalService).getUserInfo()
if (pageId) {
const data = await pagePluginApi.getPageById(pageId)
initPage(data)
return
}
if (blockId) {
await initBlock(blockId)
return
}
const getPageInfo = () => {
const isPageOccupierdByOthers = (page) => {
return page.meta?.occupier && page.meta.occupier.id !== userInfo.id
}
const homePage = appSchemaState.pageTree.find((page) => page?.meta?.isHome)
const firstPage = appSchemaState.pageTree.find(
(page) => page.componentName === COMPONENT_NAME.Page && page?.meta?.group !== 'publicPages'
)
const firstUnoccupiedPage = appSchemaState.pageTree.find(
(page) =>
page.componentName === COMPONENT_NAME.Page &&
page?.meta?.group !== 'publicPages' &&
!isPageOccupierdByOthers(page)
)
const emptyPage = {
page_content: {
componentName: COMPONENT_NAME.Page
}
}
if (homePage && !isPageOccupierdByOthers(homePage)) {
return homePage
}
return firstUnoccupiedPage || homePage || firstPage || emptyPage
}
const pageInfo = getPageInfo()
if (pageInfo.meta?.id) {
const data = await pagePluginApi.getPageById(pageInfo.meta.id)
initPage(data)
} else {
initPage(toRaw(pageInfo))
}
}
const handlePopStateEvent = async () => {
const { id, type } = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()
await initPageOrBlock()
await useTranslate().initI18n({ host: id, hostType: type })
}
const fetchAppState = async () => {
const { id } = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()
const appData = await getMetaApi(META_SERVICE.Http).get(`/app-center/v1/api/apps/schema/${id}`)
appSchemaState.pageTree = appData.componentsTree
appSchemaState.componentsMap = appData.componentsMap
appSchemaState.dataSource = appData.dataSource?.list
appSchemaState.dataHandler = appData.dataSource?.dataHandler || DEFAULT_INTERCEPTOR.dataHandler
appSchemaState.willFetch = appData.dataSource?.willFetch || DEFAULT_INTERCEPTOR.willFetch
appSchemaState.errorHandler = appData.dataSource?.errorHandler || DEFAULT_INTERCEPTOR.errorHandler
appSchemaState.bridge = appData.bridge
appSchemaState.utils = appData.utils
appSchemaState.isDemo = appData?.meta?.isDemo || appData?.meta?.is_demo
appSchemaState.globalState = appData?.meta?.globalState || appData?.meta?.global_state
const defaultLocales = [
{ lang: 'zh_CN', label: 'zh_CN' },
{ lang: 'en_US', label: 'en_US' }
]
const locales = Object.keys(appData.i18n).length
? Object.keys(appData.i18n).map((key) => ({ lang: key, label: key }))
: defaultLocales
appSchemaState.langs = {
locales,
messages: appData.i18n
}
return appData
}
const fetchResource = async ({ isInit = true } = {}) => {
const { id, type } = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()
useMessage().publish({ topic: 'app_id_changed', data: id })
const appData = await fetchAppState()
useMaterial().initMaterial({ isInit, appData })
try {
await useMaterial().fetchMaterial()
if (isInit) {
await initPageOrBlock()
}
await useTranslate().initI18n({ host: id, hostType: type, init: true })
} catch (error) {
console.log(error)
}
}
const getUtilsDeps = () => {
return appSchemaState.utils
.filter((item) => item.type === 'npm')
.map((item) => {
return {
...item,
package: item.content?.package,
script: item.content?.cdnLink
}
})
}
export default function () {
return {
appSchemaState,
getUtilsDeps,
fetchResource,
initPageOrBlock,
handlePopStateEvent,
fetchAppState
}
}