改造Ant Design Pro of Vue官网提供的脚手架
Ant Design Pro of Vue
从官网拉下来的脚手架工程,包含了很多不需要的内容,不太喜欢直接作为正式环境使用,所以花了时间对脚手架进行了改造
这次修改过程中忘记记录了,所以只能根据记忆将一些修改过的地方记录一下,可能不准确QAQ
运行脚手架工程
参考官网
git clone --depth=1 https://github.com/vueComponent/ant-design-vue-pro.git my-project
cd my-project
yarn install
yarn run serve
拉取慢,可以使用gitee
git clone --depth=1 https://gitee.com/sendya/ant-design-pro-vue.git
拉取包时如果网络状况不佳,可以使用 cnpm 进行加速,并使用 cnpm
代替 yarn
或者设置 yarn 的 npm 加载源,如 yarn config set registry https://registry.npm.taobao.org
我用的运行环境
插件 | 版本 | 备注 |
---|---|---|
yarn | 1.22.5 | |
node | 14.17.6 |
修改路由为动态路由(根据需要修改)
我觉得直接把路由配置在数据库中后期维护方便一些,所以改成了动态路由,可以根据实际情况修改
修改文件store/index.js
删除不需要的组件和页面
-
删除广告
修改layouts/BasicLayout.vue
-
删除在控制台打印的log
修改文件core/bootstrap.js
-
删除无用文件
删除页面、组件、配置文件等
.github .husky deploy public/avatar2.jpg src/components/ArticleListContent src/components/AvatarList src/components/Charts src/components/Editor src/components/NoticeIcon src/components/NumberInfo src/components/Other src/components/Search src/components/SelectLang src/components/SettingDrawer src/components/StandardFormRow src/components/Table src/components/TagSelect src/components/TextArea src/components/tools src/components/Tree src/components/Trend src/locales(去除国际化) src/mock/services/article.js src/mock/services/manage.js src/mock/services/other.js src/mock/services/tagCloud.js src/store/modules/i18n-mixin.js(去除国际化) src/views/other src/views/dashboard src/views/profile src/views/form src/views/account src/views/result src/views/list .browserslistrc .editorconfig .gitattributes .lintstagedrc.json .travis.yml commitlint.config.js Dockerfile jest.config.js jsconfig.json pnpm-lock.yaml
-
随便找个页面作为测试页面
src\views\test\basicForm\index.vue
-
去除无用代码
修改文件src/components/index.js
import Ellipsis from '@/components/Ellipsis' import FooterToolbar from '@/components/FooterToolbar' import MultiTab from '@/components/MultiTab' import IconSelector from '@/components/IconSelector' import Dialog from '@/components/Dialog' export { Ellipsis, FooterToolbar, MultiTab, IconSelector, Dialog }
修改文件config/router.config.js,我这里改了动态路由,所以很多都不需要在这里定义,如果是静态的根据实际情况修改
import { UserLayout } from '@/layouts' // import { UserLayout, BasicLayout, BlankLayout, RouteView, PageView } from '@/layouts' // import { bxAnaalyse } from '@/core/icons' export const asyncRouterMap = [ ] /** * 基础路由 * @type { *[] } */ export const constantRouterMap = [ { path: '/user', component: UserLayout, redirect: '/user/login', hidden: true, children: [ { path: 'login', name: 'login', component: () => import('@/views/user/Login') }, { path: 'register', name: 'register', component: () => import('@/views/user/Register') }, { path: 'register-result', name: 'registerResult', component: () => import('@/views/user/RegisterResult') }, { path: 'recover', name: 'recover', component: undefined } ] }, { path: '/404', component: () => import('@/views/exception/404') } ]
修改修改layouts/BasicLayout.vue
修改layouts/UserLayout.vue,这里把选择语言也去除了
<template> <div id="userLayout" :class="['user-layout-wrapper', isMobile && 'mobile']"> <div class="container"> <!-- <div class="user-layout-lang">--> <!-- <select-lang class="select-lang-trigger" />--> <!-- </div>--> <div class="user-layout-content"> <div class="top"> <div class="header"> <a href="/"> <img src="~@/assets/logo.svg" class="logo" alt="logo"> <span class="title">网站标题</span> </a> </div> <div class="desc"> 网站标题 </div> </div> <router-view /> <!-- <div class="footer">--> <!-- <div class="links">--> <!-- <a href="_self">帮助</a>--> <!-- <a href="_self">隐私</a>--> <!-- <a href="_self">条款</a>--> <!-- </div>--> <!-- <div class="copyright">--> <!-- Copyright © 2018 vueComponent--> <!-- </div>--> <!-- </div>--> </div> </div> </div> </template> <script> import { deviceMixin } from '@/store/device-mixin' export default { name: 'UserLayout', mixins: [deviceMixin], mounted () { document.body.classList.add('userLayout') }, beforeDestroy () { document.body.classList.remove('userLayout') } } </script> <style lang="less" scoped> #userLayout.user-layout-wrapper { height: 100%; &.mobile { .container { .main { max-width: 368px; width: 98%; } } } .container { width: 100%; min-height: 100%; background: #f0f2f5 url(~@/assets/background.svg) no-repeat 50%; background-size: 100%; //padding: 50px 0 84px; position: relative; .user-layout-lang { width: 100%; height: 40px; line-height: 44px; text-align: right; .select-lang-trigger { cursor: pointer; padding: 12px; margin-right: 24px; display: inline-flex; align-items: center; justify-content: center; font-size: 18px; vertical-align: middle; } } .user-layout-content { padding: 32px 0 24px; .top { text-align: center; .header { height: 44px; line-height: 44px; .badge { position: absolute; display: inline-block; line-height: 1; vertical-align: middle; margin-left: -12px; margin-top: -10px; opacity: 0.8; } .logo { height: 44px; vertical-align: top; margin-right: 16px; border-style: none; } .title { font-size: 33px; color: rgba(0, 0, 0, .85); font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif; font-weight: 600; position: relative; top: 2px; } } .desc { font-size: 14px; color: rgba(0, 0, 0, 0.45); margin-top: 12px; margin-bottom: 40px; } } .main { min-width: 260px; width: 368px; margin: 0 auto; } .footer { // position: absolute; width: 100%; bottom: 0; padding: 0 16px; margin: 48px 0 24px; text-align: center; .links { margin-bottom: 8px; font-size: 14px; a { color: rgba(0, 0, 0, 0.45); transition: all 0.3s; &:not(:last-child) { margin-right: 40px; } } } .copyright { color: rgba(0, 0, 0, 0.45); font-size: 14px; } } } a { text-decoration: none; } } } </style>
修改mock/service/user.js,去除模拟数据中的路由
const userNav = options => { const nav = [ // dashboard { name: 'test', parentId: 0, id: 1, meta: { title: '测试菜单', icon: 'table', show: true }, component: 'RouteView', redirect: '/test/basicForm' }, { name: 'basicForm', parentId: 1, id: 7, meta: { title: '基础表单', show: true }, component: 'BasicForm' }, { name: 'baidu', path: 'https://www.baidu.com/', parentId: 1, id: 3, meta: { title: '百度', target: '_blank', show: true } }, { name: 'basicForm2', parentId: 1, id: 2, meta: { title: '基础表单2', show: true }, componentPath: 'test/basicForm', path: '/test/basicForm2' } ] const json = builder(nav) console.log('json', json) return json }
修改mock/index.js
import { isIE } from '@/utils/util' // 判断环境不是 prod 或者 preview 是 true 时,加载 mock 服务 const useMock = true // if (process.env.NODE_ENV !== 'production' || process.env.VUE_APP_PREVIEW === 'true') { if (useMock) { if (isIE()) { console.error('[antd-pro] ERROR: `mockjs` NOT SUPPORT `IE` PLEASE DO NOT USE IN `production` ENV.') } // 使用同步加载依赖 // 防止 vuex 中的 GetInfo 早于 mock 运行,导致无法 mock 请求返回结果 console.log('[antd-pro] mock mounting') const Mock = require('mockjs2') require('./services/auth') require('./services/user') Mock.setup({ timeout: 800 // setter delay time }) console.log('[antd-pro] mock mounted') }
修改router/generator-routers.js,这里去除了一些路由,也可以将路由定义在这里,这里还改了动态路由的
// eslint-disable-next-line import * as loginService from '@/api/login' // eslint-disable-next-line import { BasicLayout, BlankLayout, PageView, RouteView } from '@/layouts' // 前端路由表 (基于动态) const constantRouterComponents = { // 基础页面 layout 必须引入 BasicLayout: BasicLayout, BlankLayout: BlankLayout, RouteView: RouteView, PageView: PageView, '403': () => import('@/views/exception/403'), '404': () => import('@/views/exception/404'), '500': () => import('@/views/exception/500'), // 你需要动态引入的页面组件,也可以直接指定路径componentPath,就不需要在这里引入 BasicForm: () => import('@/views/test/basicForm') } // 前端未找到页面路由(固定不用改) const notFoundRouter = { path: '*', redirect: '/404', hidden: true } // 根级菜单 const rootRouter = { key: '', name: 'index', path: '', component: 'BasicLayout', redirect: '/test', meta: { title: '首页' }, children: [] } // export const generatorStaticRouter = () => { // } /** * 动态生成菜单 * @param token * @returns {Promise<Router>} */ export const generatorDynamicRouter = token => { return new Promise((resolve, reject) => { loginService .getCurrentUserNav(token) .then(res => { console.log('generatorDynamicRouter response:', res) const { result } = res const menuNav = [] const childrenNav = [] // 后端数据, 根级树数组, 根级 PID listToTree(result, childrenNav, 0) rootRouter.children = childrenNav menuNav.push(rootRouter) console.log('menuNav', menuNav) const routers = generator(menuNav) routers.push(notFoundRouter) console.log('routers', routers) resolve(routers) }) .catch(err => { reject(err) }) }) } /** * 格式化树形结构数据 生成 vue-router 层级路由表 * * @param routerMap * @param parent * @returns {*} */ export const generator = (routerMap, parent) => { return routerMap.map(item => { const { title, show, hideChildren, hiddenHeaderContent, target, icon } = item.meta || {} const currentRouter = { // 如果路由设置了 path,则作为默认 path,否则 路由地址 动态拼接生成如 /dashboard/workplace path: item.path || `${(parent && parent.path) || ''}/${item.key}`, // 路由名称,建议唯一 name: item.name || item.key || '', // 该路由对应页面的 组件 :方案1 // component: constantRouterComponents[item.component || item.key], // 该路由对应页面的 组件 :方案2 (动态加载) component: constantRouterComponents[item.component || item.key] || (() => import(`@/views/${item.componentPath}`)), // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉) meta: { title: title, icon: icon || undefined, hiddenHeaderContent: hiddenHeaderContent, target: target, permission: item.name } } // 是否设置了隐藏菜单 if (show === false) { currentRouter.hidden = true } // 是否设置了隐藏子菜单 if (hideChildren) { currentRouter.hideChildrenInMenu = true } // 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠 if (!currentRouter.path.startsWith('http')) { currentRouter.path = currentRouter.path.replace('//', '/') } // 重定向 item.redirect && (currentRouter.redirect = item.redirect) // 是否有子菜单,并递归处理 if (item.children && item.children.length > 0) { // Recursion currentRouter.children = generator(item.children, currentRouter) } console.log(currentRouter) return currentRouter }) } /** * 数组转树形结构 * @param list 源数组 * @param tree 树 * @param parentId 父ID */ const listToTree = (list, tree, parentId) => { list.forEach(item => { // 判断是否为父级菜单 if (item.parentId === parentId) { const child = { ...item, key: item.key || item.name, children: [] } // 迭代 list, 找到当前菜单相符合的所有子菜单 listToTree(list, child.children, item.id) // 删掉不存在 children 值的属性 if (child.children.length <= 0) { delete child.children } // 加入到树中 tree.push(child) } }) }
修改src/permission.js
// const defaultRoutePath = '/dashboard/workplace' const defaultRoutePath = '/'
去除国际化之后再运行,不然跑不运行起来
去除国际化
-
修改src\views下面所有用到国家化的地方,搜索
$t(..
,替换为中文 -
修改App.vue
<template> <a-config-provider :locale="locale"> <div id="app"> <router-view/> </div> </a-config-provider> </template> <script> import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN' export default { data () { return { locale: zhCN } }, computed: {} } </script>
-
搜索
i18n
删除相关的数据 -
搜索
locales
,修改文件store/modules/app.js,删除方法// import { loadLanguageAsync } from '@/locales' ....... // loadLanguageAsync(lang).then(() => { // resolve() // }).catch((e) => { // reject(e) // }) .....
重新运行
-
运行后根据报错将引入失败的地方,对应修改
-
运行时会报一些格式警告,是因为注释缩进不对,我使用idea,找到对应文件,alt+enter可以校对格式
修改标题
-
修改相关地方
src/config/defaultSettings.js public/index.html src/layouts/UserLayout.vue
-
修改文件public/index.html,去除
<h1>Pro</h1>
停用mock
修改文件src/mock/index.js,根据需要停用
const useMock = false
// if (process.env.NODE_ENV !== 'production' || process.env.VUE_APP_PREVIEW === 'true') {
if (useMock) {
.......
修改logo
- 替换文件public/logo.png
- 替换文件src/assets/logo.svg
修改配置,需要修改样式、菜单位置等
修改文件src/config/defaultSettings.js
新增头部书签
默认是没有头部的书签,需要自己配置,书签组件倒是已经提供了,具体可以参照这篇文章ant design vue pro 支持多页签模式
解决打包有前缀时,静态资源访问不到的问题
参考Ant Design Pro of Vue打包有前缀静态资源访问不到
参考文章
后续就可以开始构建基础页面,主要是登录和用户权限