@@ -2,7 +2,15 @@ import { reactive } from 'vue'
22import { constants } from '@opentiny/tiny-engine-utils'
33import { getImportMap as getInitImportMap } from './importMap'
44import { getMetaApi , getMergeMeta , META_SERVICE } from '@opentiny/tiny-engine-meta-register'
5- import { fetchMetaData , fetchAppSchema , fetchBlockSchema , getPageById , getBlockById , fetchPageHistory } from './http'
5+ import {
6+ fetchMetaData ,
7+ fetchAppSchema ,
8+ fetchBlockSchema ,
9+ getPageById ,
10+ getBlockById ,
11+ fetchPageHistory ,
12+ fetchPageList
13+ } from './http'
614import generateMetaFiles , { processAppJsCode } from './generate'
715import srcFiles from './srcFiles'
816
@@ -332,7 +340,7 @@ interface IUsePreviewData {
332340 setImportMap : ( importMap : Record < string , string > ) => void
333341}
334342
335- export const usePreviewData = ( { setFiles, store, setImportMap } : IUsePreviewData ) => {
343+ export const usePreviewData = ( { setFiles, store } : IUsePreviewData ) => {
336344 const basicFiles = setFiles ( srcFiles , 'src/Main.vue' )
337345
338346 const assignFiles = ( { panelName, panelValue, index } : IPanelType , newFiles : Record < string , string > ) => {
@@ -350,58 +358,219 @@ export const usePreviewData = ({ setFiles, store, setImportMap }: IUsePreviewDat
350358 scripts : Record < string , string >
351359 styles : string [ ]
352360 } ) => {
353- const { appData, metaData, importMapData } = await getBasicData ( basicFiles , params . scripts )
361+ const searchParams = new URLSearchParams ( location . search )
362+ const previewType = searchParams . get ( 'previewType' )
363+
364+ if ( previewType === 'page' ) {
365+ const { appData, metaData, importMapData } = await getBasicData ( basicFiles )
366+ previewState . currentPage = params . currentPage
367+ previewState . ancestors = params . ancestors
368+
369+ // importMap 发生变化才更新 importMap
370+ if ( JSON . stringify ( previewState . importMap ) !== JSON . stringify ( importMapData ) ) {
371+ store . setImportMap ( importMapData )
372+ previewState . importMap = importMapData
373+ }
374+ const blockSet = new Set ( )
354375
355- previewState . currentPage = params . currentPage
356- previewState . ancestors = params . ancestors
376+ let blocks = [ ]
377+ const { getAllNestedBlocksSchema , generatePageCode } = getMetaApi ( 'engine.service.generateCode' )
357378
358- // importMap 发生变化才更新 importMap
359- if ( JSON . stringify ( previewState . importMap ) !== JSON . stringify ( importMapData ) ) {
360- setImportMap ( importMapData )
361- previewState . importMap = importMapData
362- }
379+ if ( params . ancestors ?. length ) {
380+ const promises = params . ancestors . map ( ( item ) =>
381+ getAllNestedBlocksSchema ( item . page_content , fetchBlockSchema , blockSet )
382+ )
383+ blocks = ( await Promise . all ( promises ) ) . flat ( )
384+ }
363385
364- const blockSet = new Set ( )
386+ const currentPageBlocks = await getAllNestedBlocksSchema (
387+ params . currentPage ?. page_content || { } ,
388+ fetchBlockSchema ,
389+ blockSet
390+ )
391+ blocks = blocks . concat ( currentPageBlocks )
365392
366- let blocks = [ ]
367- const { getAllNestedBlocksSchema, generatePageCode } = getMetaApi ( 'engine.service.generateCode' )
393+ const pageCode = [
394+ ...getPageAncestryFiles ( appData , params ) ,
395+ ...( blocks || [ ] ) . map ( ( blockSchema ) => {
396+ return {
397+ panelName : `${ blockSchema . fileName } .vue` ,
398+ panelValue : generatePageCode ( blockSchema , appData ?. componentsMap || [ ] , { blockRelativePath : './' } ) || '' ,
399+ panelType : 'vue'
400+ }
401+ } )
402+ ]
403+
404+ const newFiles = store . getFiles ( )
405+ const appJsCode = processAppJsCode ( newFiles [ 'app.js' ] , JSON . parse ( searchParams . get ( 'styles' ) || '[]' ) )
406+
407+ newFiles [ 'app.js' ] = appJsCode
408+
409+ pageCode . map ( fixScriptLang ) . forEach ( ( item ) => assignFiles ( item , newFiles ) )
410+
411+ const metaFiles = generateMetaFiles ( metaData )
412+ Object . assign ( newFiles , metaFiles )
413+
414+ setFiles ( newFiles )
415+ } else if ( previewType === 'app' ) {
416+ const app = searchParams . get ( 'id' )
417+ const { getAllNestedBlocksSchema, generateAppCode } = getMetaApi ( 'engine.service.generateCode' )
418+ const importMap = await getImportMap ( JSON . parse ( searchParams . get ( 'scripts' ) || '{}' ) )
419+ // store.setImportMap(importMap)
420+ let appSchema
421+
422+ const getPreGenerateInfo = async ( ) => {
423+ const promises = [
424+ getMetaApi ( META_SERVICE . Http ) . get ( `/app-center/v1/api/apps/schema/${ app } ` ) ,
425+ fetchPageList ( app )
426+ ]
427+
428+ const [ appData , pageList ] = await Promise . all ( promises )
429+ const pageDetailList = pageList
430+
431+ // 这里需要手动传入 blockSet 的原因是多页面可能会存在重复的区块
432+ const blockSet = new Set ( )
433+ const list = pageDetailList . map ( ( page ) =>
434+ getAllNestedBlocksSchema ( page . page_content , fetchBlockSchema , blockSet )
435+ )
436+ const blocks = await Promise . allSettled ( list )
437+
438+ const blockSchema = [ ]
439+ blocks . forEach ( ( item ) => {
440+ if ( item . status === 'fulfilled' && Array . isArray ( item . value ) ) {
441+ blockSchema . push ( ...item . value )
442+ }
443+ } )
368444
369- if ( params . ancestors ?. length ) {
370- const promises = params . ancestors . map ( ( item ) =>
371- getAllNestedBlocksSchema ( item . page_content , fetchBlockSchema , blockSet )
372- )
373- blocks = ( await Promise . all ( promises ) ) . flat ( )
374- }
445+ appSchema = {
446+ dataSource : appData . dataSource ,
447+ utils : appData . utils ,
448+ i18n : appData . i18n ,
449+ globalState : appData . globalState ,
450+ // 页面 schema
451+ pageSchema : pageDetailList . map ( ( item ) => {
452+ const { page_content, ...meta } = item
453+
454+ return {
455+ ...page_content ,
456+ meta : {
457+ ...meta ,
458+ router : meta . route
459+ }
460+ }
461+ } ) ,
462+ blockSchema,
463+ // 物料数据
464+ componentsMap : [ ...( appData . componentsMap || [ ] ) ] ,
465+ // 物料依赖
466+ packages : [ ...( appData . packages || [ ] ) ] ,
467+ meta : {
468+ ...( appData . meta || { } )
469+ }
470+ }
471+
472+ const res = await generateAppCode ( appSchema )
473+
474+ const { genResult = [ ] } = res || { }
475+ const fileRes = genResult . map ( ( { fileContent, fileName, path, fileType } ) => {
476+ const slash = path . endsWith ( '/' ) || path === '.' ? '' : '/'
477+ let filePath = `${ path } ${ slash } `
478+ if ( filePath . startsWith ( './' ) ) {
479+ filePath = filePath . slice ( 2 )
480+ }
481+ if ( filePath . startsWith ( '.' ) ) {
482+ filePath = filePath . slice ( 1 )
483+ }
375484
376- const currentPageBlocks = await getAllNestedBlocksSchema (
377- params . currentPage ?. page_content || { } ,
378- fetchBlockSchema ,
379- blockSet
380- )
381- blocks = blocks . concat ( currentPageBlocks )
382-
383- const pageCode = [
384- ...getPageAncestryFiles ( appData , params ) ,
385- ...( blocks || [ ] ) . map ( ( blockSchema ) => {
386- return {
387- panelName : `${ blockSchema . fileName } .vue` ,
388- panelValue : generatePageCode ( blockSchema , appData ?. componentsMap || [ ] , { blockRelativePath : './' } ) || '' ,
389- panelType : 'vue'
485+ if ( filePath . startsWith ( '/' ) ) {
486+ filePath = filePath . slice ( 1 )
487+ }
488+
489+ return {
490+ fileContent,
491+ filePath : `${ filePath } ${ fileName } ` ,
492+ fileType
493+ }
494+ } )
495+
496+ return fileRes
497+ }
498+
499+ const getRoutesAndImportSet = ( schema ) => {
500+ const importSet = new Set ( )
501+ const pageSchema = ( schema . pageSchema || [ ] ) . sort ( ( a , b ) => a . meta ?. router ?. length - b . meta ?. router ?. length )
502+ const result = [ ]
503+ const home = {
504+ path : '/'
390505 }
391- } )
392- ]
506+ let isGetHome = false
393507
394- const newFiles = store . getFiles ( )
395- const appJsCode = processAppJsCode ( newFiles [ 'app.js' ] , params . styles )
508+ pageSchema . forEach ( ( item ) => {
509+ if ( ( item . meta ?. isHome || item . meta ?. isDefault ) && ! isGetHome ) {
510+ home . redirect = { name : `${ item . meta . id } ` }
511+ isGetHome = true
512+ }
513+ importSet . add (
514+ `import ${ item . fileName } from './views${ item . path ? `/${ item . path } ` : '' } /${ item . fileName } .vue'`
515+ )
516+ const newNode = {
517+ path : `/${ item . meta . router } ` ,
518+ component : item . fileName ,
519+ name : `${ item . meta . id } `
520+ }
521+ result . push ( newNode )
522+ } )
523+ if ( ! isGetHome ) {
524+ isGetHome = true
525+ home . redirect = { name : result [ 0 ] ?. name }
526+ }
396527
397- newFiles [ 'app.js' ] = appJsCode
528+ return { routes : [ home , ...result ] , importSet }
529+ }
530+
531+ const getRouterFile = ( schema ) => {
532+ const { routes, importSet } = getRoutesAndImportSet ( schema )
533+
534+ const resultStr = JSON . stringify ( routes , null , 2 ) . replace (
535+ / ( " c o m p o n e n t " : \s * ) " ( .* ?) " / g,
536+ ( match , p1 , p2 ) => p1 + p2
537+ )
398538
399- pageCode . forEach ( ( item ) => assignFiles ( item , newFiles ) )
539+ // TODO: 支持 hash 模式、history 模式
540+ const importSnippet = `import { createRouter, createMemoryHistory } from 'vue-router'\n${ [ ...importSet ] . join (
541+ '\n'
542+ ) } `
543+ const exportSnippet = `export default createRouter({history: createMemoryHistory(),routes })`
400544
401- const metaFiles = generateMetaFiles ( metaData )
402- Object . assign ( newFiles , metaFiles )
545+ const routeSnippets = `const routes = ${ resultStr } `
546+
547+ return `${ importSnippet } \n ${ routeSnippets } \n ${ exportSnippet } `
548+ }
403549
404- setFiles ( newFiles , 'App.vue' )
550+ const formatCode = ( fileContent , fileName ) => {
551+ if ( fileName === 'src/router/index.js' ) {
552+ fileContent = getRouterFile ( appSchema )
553+ } else {
554+ fileContent = fileContent . replace ( / ( f r o m \s * ' ) ( @ ) ( \/ .* ' ) / g, '$1.$3' )
555+ }
556+ return fileContent
557+ }
558+
559+ const fileRes = await getPreGenerateInfo ( )
560+ const newFileRes = fileRes . filter ( ( item ) => item . filePath . includes ( 'src/' ) )
561+ const srcFiles = newFileRes . reduce ( ( prev , item ) => {
562+ const fileName = item . filePath
563+ prev [ fileName ] = formatCode ( item . fileContent , fileName )
564+ return prev
565+ } , { } )
566+ srcFiles [ 'import-map.json' ] = JSON . stringify ( importMap )
567+ const newFiles = store . getFiles ( )
568+ const appJsCode = processAppJsCode ( newFiles [ 'app.js' ] , JSON . parse ( searchParams . get ( 'styles' ) || '[]' ) )
569+ srcFiles [ 'app.js' ] = appJsCode
570+ srcFiles [ 'main.js' ] = `import app from './app.js' \n ${ srcFiles [ 'src/main.js' ] } `
571+ srcFiles [ 'main.js' ] = srcFiles [ 'main.js' ] . replace ( "import 'element-plus/dist/index.css'" , '' )
572+ setFiles ( srcFiles , 'src/main.js' )
573+ }
405574 }
406575
407576 const loadInitialData = async ( ) => {
0 commit comments