470 lines
12 KiB
JavaScript
470 lines
12 KiB
JavaScript
/**
|
||
* Admin Framework
|
||
* Version: 1.0.0
|
||
*/
|
||
|
||
// 引入核心依赖
|
||
import Vue from 'vue'
|
||
import VueRouter from 'vue-router'
|
||
import Vuex from 'vuex'
|
||
import ViewUI from 'view-design'
|
||
|
||
// 引入样式
|
||
import 'view-design/dist/styles/iview.css'
|
||
import './assets/css/animate.css'
|
||
import './assets/css/base.less'
|
||
import './assets/css/ivewExpand.less'
|
||
import './assets/icons/iconfont.css'
|
||
|
||
import uiTool from './utils/uiTool'
|
||
import http from './utils/http'
|
||
import * as tools from './utils/tools'
|
||
|
||
// 文件下载工具
|
||
const funTool = {
|
||
downloadFile: (res, fileName) => {
|
||
const blob = new Blob([res.data || res])
|
||
const downloadElement = document.createElement('a')
|
||
const href = window.URL.createObjectURL(blob)
|
||
downloadElement.href = href
|
||
downloadElement.download = fileName || new Date().getTime() + '.csv'
|
||
document.body.appendChild(downloadElement)
|
||
downloadElement.click()
|
||
document.body.removeChild(downloadElement)
|
||
window.URL.revokeObjectURL(href)
|
||
}
|
||
}
|
||
|
||
import storeModules, { userModule, appModule } from './store'
|
||
|
||
import { createBaseRoutes, setupRouterGuards } from './router'
|
||
|
||
import HomePage from './views/home/index.vue'
|
||
|
||
import SysLog from './views/system/sys_log.vue'
|
||
import SysParamSetup from './views/system/sys_param_setup.vue'
|
||
import SysRole from './views/system/sys_role.vue'
|
||
import SysUser from './views/system/sys_user.vue'
|
||
|
||
import SysControl from './views/system_high/sys_control.vue'
|
||
import SysMenu from './views/system_high/sys_menu.vue'
|
||
import SysTitle from './views/system_high/sys_title.vue'
|
||
|
||
import LoginPage from './views/login/login.vue'
|
||
|
||
import Page401 from './views/error-page/401.vue'
|
||
import Page404 from './views/error-page/404.vue'
|
||
import Page500 from './views/error-page/500.vue'
|
||
|
||
import Main from './components/main'
|
||
import ParentView from './components/parent-view'
|
||
|
||
import Tables from './components/tables'
|
||
import UploadSingle from './components/upload/Single.vue'
|
||
import UploadMultiple from './components/upload/Multiple.vue'
|
||
import TreeGrid from './components/treeGrid'
|
||
import AsyncModal from './components/asyncModal'
|
||
import InfoCard from './components/info-card'
|
||
import LoadFlower from './components/load-flower'
|
||
import SplitPane from './components/split-pane'
|
||
import TextArea from './components/text-area'
|
||
import CommonIcon from './components/common-icon'
|
||
import Editor from './components/editor/index.vue'
|
||
import editModal from './components/tables/editModal.vue'
|
||
import fieldItem from './components/tables/fieldItem.vue'
|
||
|
||
import * as systemApi from './api/system'
|
||
import * as systemHighApi from './api/system_high'
|
||
|
||
class AdminFramework {
|
||
constructor() {
|
||
this.version = '1.0.0'
|
||
this.installed = false
|
||
this.config = {}
|
||
this.store = null
|
||
this.router = null
|
||
this.ViewUI = null
|
||
|
||
this.tools = tools
|
||
this.uiTool = uiTool
|
||
this.http = http
|
||
this.funTool = funTool
|
||
|
||
this.storeModules = storeModules
|
||
this.userModule = userModule
|
||
this.appModule = appModule
|
||
|
||
this.createBaseRoutes = createBaseRoutes
|
||
this.setupRouterGuards = setupRouterGuards
|
||
|
||
this.Main = Main
|
||
this.ParentView = ParentView
|
||
this.LoginPage = LoginPage
|
||
this.Page401 = Page401
|
||
this.Page404 = Page404
|
||
this.Page500 = Page500
|
||
|
||
this.HomePage = HomePage
|
||
this.SysLog = SysLog
|
||
this.SysParamSetup = SysParamSetup
|
||
this.SysRole = SysRole
|
||
this.SysUser = SysUser
|
||
this.SysControl = SysControl
|
||
this.SysMenu = SysMenu
|
||
this.SysTitle = SysTitle
|
||
|
||
this.systemApi = systemApi
|
||
this.systemHighApi = systemHighApi
|
||
}
|
||
|
||
/**
|
||
* Vue plugin install method
|
||
* @param {Object} Vue - Vue instance
|
||
* @param {Object} options - config options
|
||
*/
|
||
install(Vue, options = {}) {
|
||
if (this.installed) return
|
||
this.installed = true
|
||
|
||
const { config = {}, ViewUI, VueRouter, Vuex, createPersistedState, componentMap } = options
|
||
this.config = config
|
||
this.ViewUI = ViewUI
|
||
|
||
if (ViewUI) {
|
||
Vue.use(ViewUI)
|
||
}
|
||
|
||
if (VueRouter) {
|
||
Vue.use(VueRouter)
|
||
}
|
||
|
||
if (Vuex) {
|
||
Vue.use(Vuex)
|
||
}
|
||
|
||
Vue.prototype.$config = config
|
||
Vue.prototype.$http = http
|
||
Vue.prototype.$tools = tools
|
||
Vue.prototype.$uiTool = uiTool
|
||
Vue.prototype.$funTool = funTool
|
||
Vue.prototype.$framework = this
|
||
|
||
this.registerGlobalComponents(Vue)
|
||
|
||
this.setupComponentMap(componentMap)
|
||
|
||
if (Vuex && !this.store) {
|
||
this.store = this.createStore(Vuex, {}, createPersistedState)
|
||
http.init(config, this.store)
|
||
}
|
||
|
||
if (VueRouter && !this.router) {
|
||
const mainRoute = this.getRoutes({ Main, ParentView, Page404, HomePage: this.HomePage })
|
||
|
||
this.router = this.createRouter(VueRouter, {
|
||
Main,
|
||
ParentView,
|
||
LoginPage,
|
||
Page401,
|
||
Page404,
|
||
Page500
|
||
}, mainRoute ? [mainRoute] : [], ViewUI)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Register global components
|
||
*/
|
||
registerGlobalComponents(Vue) {
|
||
Vue.component('Main', Main)
|
||
Vue.component('ParentView', ParentView)
|
||
|
||
Vue.component('Page401', Page401)
|
||
Vue.component('Page404', Page404)
|
||
Vue.component('Page500', Page500)
|
||
|
||
Vue.component('LoginPage', LoginPage)
|
||
|
||
Vue.component('Tables', Tables)
|
||
Vue.component('UploadSingle', UploadSingle)
|
||
Vue.component('UploadMultiple', UploadMultiple)
|
||
Vue.component('TreeGrid', TreeGrid)
|
||
Vue.component('AsyncModal', AsyncModal)
|
||
Vue.component('InfoCard', InfoCard)
|
||
Vue.component('LoadFlower', LoadFlower)
|
||
Vue.component('SplitPane', SplitPane)
|
||
Vue.component('TextArea', TextArea)
|
||
Vue.component('CommonIcon', CommonIcon)
|
||
Vue.component('Editor', Editor)
|
||
Vue.component('editModal', editModal)
|
||
Vue.component('fieldItem', fieldItem)
|
||
|
||
|
||
}
|
||
|
||
/**
|
||
* Setup component map
|
||
* @param {Object} customMap - custom component map
|
||
*/
|
||
setupComponentMap(customMap = {}) {
|
||
const components = {
|
||
'home/index': HomePage,
|
||
'system/sys_log': SysLog,
|
||
'system/sys_param_setup': SysParamSetup,
|
||
'system/sys_role': SysRole,
|
||
'system/sys_user': SysUser,
|
||
'system_high/sys_control': SysControl,
|
||
'system_high/sys_menu': SysMenu,
|
||
'system_high/sys_title': SysTitle,
|
||
...customMap
|
||
}
|
||
|
||
const map = {}
|
||
Object.keys(components).forEach(path => {
|
||
const cleanPath = path.replace(/\.vue$/, '')
|
||
map[cleanPath] = components[path]
|
||
map[cleanPath + '.vue'] = components[path]
|
||
})
|
||
|
||
uiTool.setComponentMap(map)
|
||
}
|
||
|
||
/**
|
||
* Add custom component map
|
||
* @param {Object} customMap - custom component map
|
||
* @example
|
||
* AdminFramework.addComponentMap({
|
||
* 'ball/games.vue': GamesComponent,
|
||
* 'order/pay_orders.vue': PayOrdersComponent
|
||
* })
|
||
*/
|
||
addComponentMap(customMap) {
|
||
uiTool.setComponentMap(customMap)
|
||
}
|
||
|
||
/**
|
||
* Init HTTP config
|
||
* @param {Object} config - HTTP config
|
||
* @param {Object} store - Vuex Store instance
|
||
*/
|
||
initHttp(config, store) {
|
||
http.init(config, store)
|
||
this.store = store
|
||
}
|
||
|
||
/**
|
||
* Create router instance
|
||
* @param {Object} Router - VueRouter class
|
||
* @param {Object} components - component object
|
||
* @param {Array} customRoutes - custom routes
|
||
* @param {Object} ViewUI - ViewUI instance
|
||
* @param {String} homeName - home page name
|
||
* @returns {Object} router instance
|
||
*/
|
||
createRouter(Router, components = {}, customRoutes = [], ViewUI, homeName = 'home') {
|
||
const { LoginPage, Page401, Page404, Page500 } = components
|
||
|
||
if (!LoginPage || !Page401 || !Page404 || !Page500) {
|
||
console.error('Missing required page components')
|
||
return null
|
||
}
|
||
|
||
const baseRoutes = createBaseRoutes(LoginPage, Page401, Page404, Page500)
|
||
|
||
const router = new Router({
|
||
routes: [...baseRoutes, ...customRoutes],
|
||
mode: 'hash'
|
||
})
|
||
|
||
if (ViewUI) {
|
||
setupRouterGuards(router, ViewUI, homeName)
|
||
}
|
||
|
||
return router
|
||
}
|
||
|
||
/**
|
||
* Create Store instance
|
||
* @param {Object} Vuex - Vuex class
|
||
* @param {Object} customModules - custom modules
|
||
* @param {Object} createPersistedState - vuex-persistedstate plugin
|
||
* @returns {Object} store instance
|
||
*/
|
||
createStore(Vuex, customModules = {}, createPersistedState) {
|
||
const store = new Vuex.Store({
|
||
modules: {
|
||
user: userModule,
|
||
app: appModule,
|
||
...customModules
|
||
},
|
||
plugins: createPersistedState ? [
|
||
createPersistedState({
|
||
storage: window.localStorage
|
||
})
|
||
] : []
|
||
})
|
||
|
||
this.store = store
|
||
return store
|
||
}
|
||
|
||
/**
|
||
* Get dynamic routes
|
||
* @param {Object} components - component object
|
||
* @returns {Object} main route config
|
||
*/
|
||
getRoutes(components = {}) {
|
||
const { Main, ParentView, Page404, HomePage } = components
|
||
|
||
if (!Main || !ParentView || !Page404) {
|
||
console.error('Missing required layout components')
|
||
return null
|
||
}
|
||
|
||
return uiTool.getRoutes(Main, ParentView, Page404, HomePage || this.HomePage)
|
||
}
|
||
|
||
/**
|
||
* Register global components
|
||
* @param {Object} Vue - Vue instance
|
||
* @param {Object} components - component object
|
||
*/
|
||
registerComponents(Vue, components = {}) {
|
||
Object.keys(components).forEach(name => {
|
||
Vue.component(name, components[name])
|
||
})
|
||
}
|
||
|
||
/**
|
||
* Create app with simplified API (推荐使用)
|
||
* @param {Object} config - application config
|
||
* @param {String} config.title - application title
|
||
* @param {String} config.apiUrl - API base URL
|
||
* @param {String} config.uploadUrl - upload URL (可选,默认为 apiUrl + 'upload')
|
||
* @param {Object} config.componentMap - custom component map (optional)
|
||
* @param {Function} config.onReady - callback when app is ready (optional)
|
||
* @returns {Object} Vue instance
|
||
*/
|
||
createApp(config = {}) {
|
||
// Auto install framework using internal dependencies
|
||
if (!this.installed) {
|
||
const { componentMap, ...appConfig } = config
|
||
|
||
// 如果没有提供 uploadUrl,自动从 apiUrl 推导
|
||
if (!appConfig.uploadUrl && appConfig.apiUrl) {
|
||
appConfig.uploadUrl = appConfig.apiUrl + (appConfig.apiUrl.endsWith('/') ? 'upload' : '/upload')
|
||
}
|
||
|
||
this.install(Vue, {
|
||
config: appConfig,
|
||
ViewUI,
|
||
VueRouter,
|
||
Vuex,
|
||
createPersistedState: null,
|
||
componentMap: componentMap || {}
|
||
})
|
||
}
|
||
|
||
// Create Vue instance with auto menu/title restoration
|
||
const app = new Vue({
|
||
router: this.router,
|
||
store: this.store,
|
||
render: h => h('router-view'),
|
||
async created() {
|
||
console.log('=== Admin Framework App Started ===')
|
||
console.log('Framework Version:', framework.version)
|
||
console.log('Config:', this.$config)
|
||
|
||
// Auto restore menu and title on refresh
|
||
const token = this.$store.state.user.token
|
||
const authorityMenus = localStorage.getItem('authorityMenus')
|
||
|
||
if (token && authorityMenus) {
|
||
console.log('Restoring menu and title...')
|
||
try {
|
||
// Restore menu
|
||
await this.$store.dispatch('user/setAuthorityMenus', {
|
||
Main: framework.Main,
|
||
ParentView: framework.ParentView,
|
||
Page404: framework.Page404,
|
||
authorityMenus: authorityMenus
|
||
})
|
||
console.log('Menu restored')
|
||
|
||
// Get system title
|
||
await this.$store.dispatch('app/getSysTitle', {
|
||
defaultTitle: this.$config.title,
|
||
defaultLogo: ''
|
||
})
|
||
} catch (error) {
|
||
console.error('Restore failed:', error)
|
||
}
|
||
} else {
|
||
// Not logged in, use default title
|
||
console.log('Not logged in, using default title')
|
||
document.title = this.$config.title
|
||
}
|
||
|
||
// Call user callback if provided
|
||
if (config.onReady && typeof config.onReady === 'function') {
|
||
config.onReady.call(this)
|
||
}
|
||
}
|
||
})
|
||
|
||
// Expose to global for debugging
|
||
if (typeof window !== 'undefined') {
|
||
window.app = app
|
||
window.rootVue = app
|
||
window.framework = framework
|
||
}
|
||
|
||
return app
|
||
}
|
||
}
|
||
|
||
const framework = new AdminFramework()
|
||
|
||
// 【关键】框架实例创建后立即暴露到全局,确保在任何地方都能访问
|
||
if (typeof window !== 'undefined') {
|
||
window.framework = framework
|
||
}
|
||
|
||
export default framework
|
||
|
||
export {
|
||
tools,
|
||
uiTool,
|
||
http,
|
||
funTool,
|
||
|
||
storeModules,
|
||
userModule,
|
||
appModule,
|
||
|
||
createBaseRoutes,
|
||
setupRouterGuards,
|
||
|
||
HomePage,
|
||
SysLog,
|
||
SysParamSetup,
|
||
SysRole,
|
||
SysUser,
|
||
SysControl,
|
||
SysMenu,
|
||
SysTitle,
|
||
|
||
LoginPage,
|
||
Page401,
|
||
Page404,
|
||
Page500,
|
||
|
||
Main,
|
||
ParentView,
|
||
|
||
systemApi,
|
||
systemHighApi,
|
||
|
||
AdminFramework
|
||
}
|