在线文档

master
toesbieya 6 years ago
parent 5cf96cb347
commit 4c1ecc771f
  1. 22
      docs/.gitignore
  2. 69
      docs/.vuepress/config.js
  3. BIN
      docs/.vuepress/public/abstract-table.png
  4. BIN
      docs/.vuepress/public/puzzle-verify.png
  5. BIN
      docs/.vuepress/public/region-selector_tab.png
  6. BIN
      docs/.vuepress/public/search-form_1.png
  7. BIN
      docs/.vuepress/public/search-form_2.png
  8. BIN
      docs/.vuepress/public/upload-file.png
  9. 9
      docs/README.md
  10. 69
      docs/frontend/README.md
  11. 26
      docs/frontend/components/abstract-table.md
  12. 46
      docs/frontend/components/region-selector.md
  13. 59
      docs/frontend/components/search-form.md
  14. 31
      docs/frontend/components/upload-file.md
  15. 34
      docs/frontend/deploy.md
  16. 6
      docs/frontend/global-methods/bottom-tip.md
  17. 56
      docs/frontend/global-methods/guide.md
  18. 17
      docs/frontend/global-methods/image-viewer.md
  19. 11
      docs/frontend/global-methods/puzzle-verify.md
  20. 21
      docs/frontend/global-methods/signature.md
  21. 52
      docs/frontend/layout.md
  22. 15
      docs/frontend/new.md
  23. 16
      docs/frontend/permission.md
  24. 18
      docs/frontend/plugins.md
  25. 158
      docs/frontend/router.md
  26. 84
      docs/frontend/utils.md
  27. 25
      docs/installation.md
  28. 10573
      docs/package-lock.json
  29. 11
      docs/package.json

22
docs/.gitignore vendored

@ -0,0 +1,22 @@
.DS_Store
node_modules
/dist
/test
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,69 @@
module.exports = {
title: 'jxc-admin',
description: "jxc-admin后台管理系统文档",
host: 'localhost',
// 输出目录
dest: 'dist',
// 主题配置
themeConfig: {
smoothScroll: true,
lastUpdated: '上次更新:',
nav: [
{text: '在线预览', link: 'https://toesbieya.cn'},
{text: 'GitHub', link: 'https://github.com/toesbieya/jxc-admin'}
],
sidebar: [
'installation',
{
title: '前端',
collapsable: false,
children: [
'/frontend/',
'/frontend/layout',
'/frontend/router',
'/frontend/permission',
'/frontend/new',
'/frontend/deploy',
{
title: '组件',
collapsable: false,
children: [
'/frontend/components/abstract-table',
'/frontend/components/region-selector',
'/frontend/components/search-form',
'/frontend/components/upload-file',
]
},
{
title: '全局方法',
collapsable: false,
children: [
'/frontend/global-methods/bottom-tip',
'/frontend/global-methods/guide',
'/frontend/global-methods/image-viewer',
'/frontend/global-methods/puzzle-verify',
'/frontend/global-methods/signature',
]
},
'/frontend/utils',
'/frontend/plugins'
]
},
]
},
plugins: {
'@vuepress/pwa': {
serviceWorker: true,
updatePopup: true
},
'@vuepress/back-to-top': true
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

@ -0,0 +1,9 @@
---
home: true
heroImage: https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png
heroText: jxc-admin
tagline: 前后端分离的简易进销存后台管理系统。
actionText: 快速上手 →
actionLink: ./installation/
footer: MIT Licensed | Copyright © 2020-present toesbieya
---

@ -0,0 +1,69 @@
# 介绍
## 功能
```
- 首屏加载动画
- 登录 \ 注册
- 集成多种canvas背景动画
- 仿极验滑动验证
- 布局功能
- 异步路由组件loading骨架屏
- 动态侧边栏(支持多级路由嵌套)
- 动态面包屑
- 多页签(支持详情页缓存)
- 支持移动端
- 导航栏、侧边栏可隐藏
- 侧边栏折叠时可显示上级
- Excel导出,支持多级表头、合并行
- 错误页面
- 403
- 404
- 组件
- 用户导航
- 行政区划选择器,支持树形和选项卡型
- 封装的上传组件,整合七牛云,支持多种格式的文件预览
- 封装了antd风格的dialog,可拖拽、超出可滚动
- 手写签名
- element-ui增强
- message支持分组、进度条功能
- select重写,分别使用了popperjs的v1和v2版本
```
## 目录结构
```
├── element-ui-personal # element-ui增强
├── mock # 项目mock,需打开devServer.before的注释
├── public # 静态资源文件夹
├── src
│ ├── api # 数据请求集合
│ ├── assets
│ │ │── icons # 项目所有svg icons
│ │ └── styles # 样式集合
│ ├── bizComponents # 公用业务组件
│ ├── components # 公用组件
│ ├── config
│ │ │── index.js # 基础配置项
│ │ └── request.js # axios封装
│ ├── directive # 自定义指令集合
│ ├── filters # 自定义过滤器集合
│ ├── layout # 布局文件夹,包含了导航栏、侧边栏、多页签、全局页脚、页面
│ ├── mixins # 公用混入
│ ├── plugin # 一些插件,均使用import()来动态引入
│ ├── router
│ │ │── authority # 需要鉴权的路由集合
│ │ │── constant # 不需要鉴权的路由集合
│ │ │── index.js
│ │ └── util.js
│ ├── store # vuex配置
│ ├── utils # 工具类
│ ├── views # 路由页面集合
│ ├── App.vue
│ └── main.js
```

@ -0,0 +1,26 @@
# Abstract Table
<img :src="$withBase('/abstract-table.png')">
给`<el-table>`设置了一些默认属性,设置了`empty`插槽。
```html
<el-table
ref="table"
current-row-key="id"
row-key="id"
highlight-current-row
{...data}
>
{children}
<Empty slot="empty"/>
</el-table>
```
### 引入:
`@/components/AbstractTable`
### 使用:
照着官方文档,当成 `<el-table>` 用就行。

@ -0,0 +1,46 @@
# 行政区划选择器
目前分 `树型``选项卡型` 两种,由于 `树型` 不完善,所以这里只介绍 `选项卡型`,有兴趣的可以查看源码`@/components/RegionSelector/Tree`。
<img :src="$withBase('/region-selector_tab.png')">
由于行政区划数据在本项目中是公共数据,所以使用了`vuex`来存放,如果不想用`vuex`但又想拿到别的项目里用,可以自己改造一下。
### 引入:
`@/components/RegionSelector`
### 使用:
```html
<region-selector v-model="value"/>
```
行政区划的数据模型可以查看`public/static/json/region-pcas.json`,这是精确到街道的数据,[由此获取](https://github.com/modood/Administrative-divisions-of-China)。
### RegionSelector Attributes:
| 参数 | 说明 | 类型 | 默认 |
| :-----------------: | :-------------------------------------: | :--------------: | :-----: |
| type | 选择器类型,`tab / tree` | `string` | `'tab'` |
| value / v-model | 绑定值 | `string / array` | - |
| readonly | 是否只读,等同于`el-select`的`disabled` | `boolean` | - |
| size | 大小,等同于`el-select`的`size` | `string` | - |
| getChildrenOnSelect | 在确认选择时是否连同子级一起获取 | `boolean` | - |
| limit | 是否需要剪枝 | `boolean` | - |
| limitApi | 获取剪枝数据的api | `function` | - |
| separation | 分隔号 | `string` | `','` |
### RegionSelector Events:
| 事件名称 | 说明 | 回调参数 |
| :------: | :------------------------: | :--------------: |
| clear | 等同于`el-select`的`clear` | - |
| select | 确定选择时触发 | `(node,idArray)` |
::: tip
`value``string` 时支持被 `separation` 所连接的汉字或者数字,比如可以是 `北京市,东城区` ,也可以是 `北京市,110101`
`array` 时,数组里的每一项除了支持上面的形式外,还支持 `{id:'11',...}、{name:'北京市',...}` 这两种。
使用 `v-model` 时,不管初始传入的数据是什么样的,最终都会返回 `北京市,东城区` 这样的字符串。
:::

@ -0,0 +1,59 @@
# Search Form
一个自适应的表单容器,根据父元素的内宽来确定一行渲染多少个表单控件,同时确定是否需要折叠。
<img :src="$withBase('/search-form_1.png')">
<img :src="$withBase('/search-form_2.png')">
### 引入:
`@/components/SearchForm`,`@/components/SearchFormItem`
### 使用:
```html
<search-form>
<search-form-item label="单 号:">
<el-input/>
</search-form-item>
<search-form-item label="采购订单:">
<el-input/>
</search-form-item>
<search-form-item label="创建人:">
<el-input/>
</search-form-item>
<search-form-item label="创建时间:">
<el-date-picker/>
</search-form-item>
<search-form-item label="审核人:">
<el-input/>
</search-form-item>
<search-form-item label="审核时间:">
<el-date-picker/>
</search-form-item>
<search-form-item label="状 态:">
<el-select/>
</search-form-item>
</search-form>
```
### SearchForm Attributes:
| 参数 | 说明 | 类型 | 默认 |
| :-----------------: | :----------------------------------: | :------: | :-------: |
| label-width | 等同于`el-form`的`label-width` | `string` | `'120px'` |
| xs | 父元素内宽<768px时每行渲染多少空间 | `number` | `1` |
| sm | >=768px | `number` | `2` |
| md | >=998px | `number` | `3` |
| lg | >=1200px | `number` | `4` |
### SearchForm Slots:
| 名称 | 说明 |
| :------: | :---------------------------------------------------------------------: |
| collapse | 折叠按钮,参数为 `{collapse:展开为true否则false,handle:展开折叠的方法}` |
### SearchFormItem Attributes:
| 参数 | 说明 | 类型 | 默认 |
| :---: | :---------------------------: | :------: | :-------: |
| label | 等同于`el-form-item`的`label` | `string` | - |

@ -0,0 +1,31 @@
# Upload File
集成七牛云直传,需要配合后端使用。支持图片、word、pdf、ppt、rar、excel、txt、zip类型的文件预览(使用kkFileView)。
<img :src="$withBase('/upload-file.png')">
### 引入:
`@/components/UploadFile`
### 使用:
```html
<upload-file/>
```
### UploadFile Attributes:
| 参数 | 说明 | 类型 | 默认 |
| :------: | :--------------------: | :---------------: | :------: |
| disabled | 等同于`el-upload` | `boolean` | - |
| multiple | 等同于`el-upload` | `boolean` | `true` |
| fileList | 等同于`el-upload` | `array` | `[]` |
| limit | 等同于`el-upload` | `number` | `10` |
| maxSize | 单次上传文件的最大大小 | `number / string` | `'10MB'` |
### UploadFile Events:
| 事件名称 | 说明 | 回调参数 |
| :------: | :--------------------------: | :---------------: |
| remove | 移出不是本次上传的文件时触发 | `{url}` |
| success | 上传成功后触发 | `(file,response)` |

@ -0,0 +1,34 @@
# 构建和发布
## 构建
当项目开发完毕,只需要运行一行命令就可以打包你的应用:
```shell script
# 默认环境为 production
npm run build
```
构建打包成功之后,会在根目录生成`dist`文件夹,里面就是构建打包好的静态文件。
如果需要指定`dist`目录等,则需要通过`vue.config.js`的`outputDir`进行配置。
## 发布
如果静态文件不是部署在根目录下,比如想部署在 `/app` 下,那么需要将 `@/config/index.js` 中的 `contextPath` 改为 `/app/`
想在 `js`中引入的话,可以直接使用 `process.env.BASE_URL` 拿到`contextPath`。
如果是在 `html` 中引入的话,是 `<%= BASE_URL %>` 的形式,这是 `ejs` 的语法。
::: warning 注意
`contextPath` 应始终以 `/` 开头,以 `/` 结束。
:::
## 路由模式
项目提供了动态修改路由模式的功能,只需要修改 `@/config/index.js` 中的 `routerMode` 即可。
当路由模式为 `'history'` 时,需要服务器提供支持。以 `nginx` 为例,需要在配置中补上:
```shell script
try_files $uri $uri/ /index.html;
```

@ -0,0 +1,6 @@
# 底部警告信息弹框
### 使用:
```js
this.$bottomTip('hello')
```

@ -0,0 +1,56 @@
# 用户导航
这是在driver.js的基础上改造来的。
### 使用:
- 在 `@/mixins/guide/data` 下创建导航步骤,例如 `test.js`
- 在需要导航的路由页面里引入 `@/mixins/guide`,并混入 `mixins: [guide.test]`
```js
//配置导航
this.$guide.config(config)
//开始一个导航
this.$guide(start,steps,[,beforeExist])
//退出导航
this.$guide.exit()
```
### $guide.config(config)
- config,所有可配置项如下:
```js
{
stageBackground: "#ffffff",//弹框背景颜色
doneBtnText: "完成", //完成按钮的文字
closeBtnText: "关闭", //关闭按钮的文字
nextBtnText: "下一步", //下一步按钮的文字
prevBtnText: "上一步", //上一步按钮的文字
}
```
### $guide(start,steps,[,beforeExist])
- `start` : `number / string`,从第几个步骤开始,`number` 型从0开始,`string` 型可以为 `'first'``'last'`
- `step` : `array`,导航步骤数组,所有可配置项如下:
```js
{
...config,
element: string, 用于querySelector,
content: string, 弹框内容,可以使用html,
forceShowPrevBtn: boolean, 是否强制显示上一步按钮
forceShowNextBtn: boolean, 是否强制显示下一步按钮
onPrevious: function, 跳转到上一个导航步骤前触发,返回false或Promise.reject()来阻止跳转
onNext: function, 跳转到下一个导航步骤前触发,返回false或Promise.reject()来阻止跳转
}
```
- `beforeExist` : `function`,退出导航前触发,回调参数是一个 `boolean`,表示当前是否是最后一个步骤,返回 `false``Promise.reject()` 来阻止退出。
### $guide.exit()
退出导航,会触发 `beforeExist` 钩子

@ -0,0 +1,17 @@
# 图片预览
### 使用:
```js
//开始预览
this.$image({index, urlList})
//退出预览
this.$image.close()
```
### $image({index, urlList})
- `index` : `number`,当前图片在图片数组中的下标。
- `urlList` : `array`,需要预览的图片的url数组

@ -0,0 +1,11 @@
# 拼图滑块验证
<img :src="$withBase('/puzzle-verify.png')">
### 使用:
```js
this.$puzzleVerify().then(...).catch(...)
```
返回一个 `promise`,如果验证失败会 `reject`,否则 `resolve`

@ -0,0 +1,21 @@
# 手写签名
### 使用:
```js
//开始签名
this.$signature({image, lineWidth, lineColor, onConfirm)
//退出签名
this.$signature.close()
```
### $signature({image, lineWidth, lineColor, onConfirm)
- `image` : `string`,需要回显的签名图片的src。
- `lineWidth` : `number`,线的宽度,默认 `6`
- `lineColor` : `string`,线的颜色,默认 `'#000000'`
- `onConfirm` : `function`,签名完毕后触发,回调参数为签名图片的base64

@ -0,0 +1,52 @@
# 布局
此布局是在vue-element-admin的基础上改造而来。
实际上这个布局算是二级路由,一级路由是App.vue,这就是为什么经常会看到路由会这么写的原因:
```json
{
"path": "/",
"component": Layout,
"children": [
{
"path": "index",
"name": "index",
"component": Page,
"meta": {"title": "首页"}
}
]
}
```
`Layout` 填充到 `App.vue` 里的 `<router-view>`,而真正的路由页面 `@/views/index` 则填充到 `Layout` 里的 `<router-view>`
项目中没有用到 `Layout` 的页面只有 `@/router/constant/modules/app.js` 里的 `login`、`403`、`404` 这三个。
另外可以发现 `App.vue` 使用了 `<keep-alive>`,这是为了从 `403`、`404` 返回时能保存之前打开的标签页。
## 多页签
增加了平滑滚动功能,增加了快捷键功能:`ctrl + → 下一个页签`、`ctrl + ← 上一个页签`
::: warning 注意
多页签在 启用 / 停用 之间切换时,之前缓存的页签实例会清空,也就是说再次打开时会是新的页面
:::
## 侧边栏
重复点击菜单可刷新路由,折叠时可以选择是否在折叠菜单上显示父级。
侧边栏的滚动分两种情况,一种是整体的滚动,这是用 `<el-scrollbar>` 做的,不过缺点就是移动端体验不好。
另一种是弹出菜单的滚动,这是用 `css` 做的,不用 `<el-scrollbar>` 是因为没办法避免bug,具体原因可以去看element-ui的 `submenu #handleMouseleave`
## 全局页脚
只有使用了 `Layout` 组件的路由页面才会有这个页脚。
这里的实现比较特别,由于路由页面被 `<el-scrollbar>` 包裹,需要将页脚的dom插入到 `<el-scrollbar>` 的dom中,所以使用了这种方法:
```javascript
const FooterConstructor = Vue.extend(Footer)
const footerInstance = new FooterConstructor().$mount()
this.$refs.scrollbar.$refs.wrap.appendChild(footerInstance.$el)
```
至于为什么不用函数式组件,是因为我还不知道怎么样拿到一个函数式组件的dom

@ -0,0 +1,15 @@
# 新增页面
1. 把数据请求api创建出来,建议在 `@/api`下根据模块区分。
2. 创建路由页面,建议在 `@/views` 下根据模块区分。
3. 如果页面过大过复杂,建议按功能拆分,放在当前页面的文件夹里。
4. 独有的样式同样放在当前页面的文件夹里,能公用的提取到 `@/assets/styles` 里。
5. 创建路由,根据是否需要鉴权,在 `@/router/authority/modules``@/router/constant/modules` 下创建,这两个文件夹下的js会被自动导出。
6. 如果需要创建vuex模块,请在 `@/store/modules` 下创建,同样的,该文件夹下的js会被自动导出。
7. 如果页面之间存在公共组件,建议抽取出来,根据业务耦合度拆分至 `@/components``@/bizComponents`

@ -0,0 +1,16 @@
# 权限
项目使用基于资源url的形式来实现权限控制,说白点就是用户的所有操作都可以用一个url来标识。
鉴权方法为 `@/util/auth.js #auth`
鉴权流程:
1. 如果用户的`admin` 字段为1,那么直接放行。
2. 如果访问的 `url` 不在总权限树内,说明该操作无需权限,放行。
3. 如果访问的 `url` 在用户的权限树内,说明有权限,放行。
4. 否则拦截,跳转至403页面。
当然前端的权限控制只是过滤一小部分,真正的工作还是由后端完成。

@ -0,0 +1,18 @@
# 插件
## canvas动画
所有动画位于 `@/plugin/canvasAnimation`下,使用 `new Animation(canvas)`的方式来创建一个动画。
想停止的话调用 `Animation.stop()` 即可。
## 图片压缩
支持 `png`、`jpg` 两种格式的图片,使用方法参考 `@/views/example/developingTest/components/ImageCompressTest.vue`
::: tip
由于是以 `worker` 的形式调用,所以需要准备 `cjpeg.min.js``pngquant.min.js`,这两个文件都放在项目的 `public`下。
:::
## 其他
此外项目中还有 `live2d``webgl` 两个插件,有兴趣的可以自行查看。

@ -0,0 +1,158 @@
# 路由
## 路由配置项
路由配置项不光参与路由的生成,也参与侧边栏、搜索结果的生成。
### Route Attributes:
| 参数 | 说明 | 类型 | 默认 |
| ---------- | ---------------------------------------------------- | ------------------- | ----- |
| hidden | 是否在侧边栏中显示 | `boolean` | - |
| alwaysShow | 是否总是把只有一个子级的菜单以嵌套模式在侧边栏中展示 | `boolean` | - |
| sort | 侧边栏的排序值,值越小越靠前 | `number` | 10000 |
### Route.meta Attributes:
| 参数 | 说明 | 类型 | 默认 |
| ------------ | ------------------------------------------------ | --------- | ----------------------- |
| title | 路由在侧边栏、面包屑、页签、搜索结果中的显示名称 | `string` | - |
| icon | 图标名,支持svg-icon、el-icon | `string` | - |
| affix | 是否在多页签中固定显示 | `boolean` | - |
| noCache | true时缓存页面 | `boolean` | - |
| activeMenu | 侧边栏当前激活菜单的index | `string` | - |
| noAuth | true时路由不需要鉴权 | `boolean` | router/constant下为true |
| iframe | 需要打开的iframe的地址 | `string` | - |
| isDetailPage | 是否是详情页 | `boolean` | - |
::: tip 注意
路由meta上的affix、noAuth、noCache会被子路由继承,优先使用子路由的值
:::
## 页面缓存
先总结一下路由页面被缓存的条件:
- 启用了多页签
- `(route.name || route.meta.isDetailPage) && route.meta.noCache && !route.meta.iframe`
通常情况路由想做缓存都是通过 `<keep-alive>`,但是如果是像 `/edit/1`、`/edit/2` 这样的共用路由页面的详情页的话,
`<keep-alive>` 就满足不了需求,因为它是通过组件的 `name` 来区分组件的。
所以项目中仿照 `<keep-alive>` 写了 `<keep-router-view-alive>`,可以根据当前路由的路径来区分组件。
除此之外还有个问题,在共用了同一个组件的路由之间跳转的话,组件会被复用,假如有以下路由:
```js
const component={template:`<input v-model="data">`, data: ()=> ({data:1})}
const routes = [
{ path: '/foo', component },
{ path: '/bar', component }
]
```
先访问 `/foo`,然后将输入框的值改为100,再访问 `/bar` ,会发现输入框的值还是100。
所以在 `router.beforeEach` 中做了判断,如果跳转前后的路由的 `meta.isDetailPage` 均为 `true` 的话,那么借助 `/redirect` 跳转一次,从而避免组件复用的问题
::: warning 注意
如果不使用meta.isDetailPage的话,需要缓存的页面的 `name` 必须和路由的 `name` 一致
:::
## 路由白名单
`@/router/index.js` 中有这么一句:
```js
const whiteList = transformWhiteList(['/login', '/register', '/404', '/403'])
```
这个 `whiteList` 就是白名单,里面的值会被转为正则表达式,详细请查看[path-to-regexp文档](https://github.com/pillarjs/path-to-regexp)。
被`whiteList` 匹配的路由不需要验证,直接放行。
## 首屏加载效果
想体验的可以把 `network` 设为 `slow 3g` 就可以在在线实例看到效果。
原理很简单,在 `index.html` 里有这么一段:
```html
<div id="app">
<div id="loader-wrapper">
<img>
<p>资源加载中......</p>
</div>
</div>
```
`vuejs` 初始化完成后,`app` 里的内容会被替换,从而实现加载效果。
## 骨架屏
通常情况下,路由组件都是以 `import(...)` 的形式异步引入,
如果想让路由在加载异步组件时显示,可以使用以下方式:
```js
function lazyLoadView(component) {
const AsyncHandler = () => ({component, loading: Skeleton})
return Promise.resolve({
functional: true,
render(h, {data, children}) {
return h(AsyncHandler, data, children)
}
})
}
//将路由配置中的component项改为以下形式
component: () => lazyLoadView(import(...))
```
关于 `AsyncHandler` 的更多选项,可以查看[官方文档](https://cn.vuejs.org/v2/guide/components-dynamic-async.html#%E5%A4%84%E7%90%86%E5%8A%A0%E8%BD%BD%E7%8A%B6%E6%80%81)
## 过渡动画
正常 `<router-view>` 使用过渡动画的方法应该是这样的:
```html
<transition>
<keep-alive>
<router-view>
</keep-alive>
</transition>
```
但是由于项目中使用了自定义的 `<keep-router-view-alive>`,所以就变成这样的:
```html
<keep-router-view-alive :include="cachedViews">
<transition :name="transitionName" mode="out-in">
<router-view>
</transition>
</keep-router-view-alive>
```
具体原因是 `<transition>` 中的代码硬编码了 `<keep-alive>`,导致如果按照往常写法的话,过渡动画不会生效。
项目中是根据页签的前后位置来决定路由动画的,比如从前面的页签跳转到后面的,那么动画是从左滑出,反之是从右滑出。
::: warning 注意
只有在启用了多页签的时候才会有上面的效果,否则默认是 `el-fade-in-linear` 动画。
:::
## iframe
只需要按如下配置即可打开一个iframe:
```json
{
"path":"/baidu",
"meta":{
"iframe":"https://www.baidu.com"
}
}
```
当向上面的路由跳转时,会隐藏路由页面,展示 `<iframe>` 标签,反之则隐藏。
另外,相同地址的iframe不会重复打开,想要刷新需使用 `/redirect` 跳转。
## 外链
也可以在路由中配置一个外链,只要在 path 中填写了合法的 url 路径,当你点击该路由菜单时就会新开这个页面。
例如:
```json
{
"path": "https://www.baidu.com",
"meta": {
"title": "百度"
}
}
```

@ -0,0 +1,84 @@
# 常用工具类
## 日期格式化
```js
import {timeFormat} from '@/utils'
// 以 yyyy-MM-dd HH:mm:ss 格式显示的当前时间
timeFormat()
// 06-29
timeFormat('MM-dd',new Date('2020/06/29'))
```
## 数学运算
基于 `decimal.js` 封装了加减乘除运算方法。
```js
import {plus,sub,mul,div} from '@/utils/math'
//1.05 * 10.8 / 0.6 /0.1 + 0.1 + 0.5 - 0.2 - 0.3
sub(plus(div(mul(1.05,10.8),0.6,0.1),0.1,0.5),0.2,0.3)
```
## 列表转树
```js
import {createTree} from '@/utils/tree'
const arr1 = [{id: 1, pid: 0, name: 'a'}, {id: 2, pid: 1, name: 'b'}, {id: 3, pid:2, name: 'c'}]
const tree1 = createTree(arr1)
const arr2 = [{xid: 1, ypid: 0, name: 'a'}, {xid: 2, ypid: 1, name: 'b'}, {xid: 3, ypid: 2, name:' c'}]
const tree2 = createTree(arr2, 0, 'xid', 'ypid')
```
## 纯前端导出excel
依赖exceljs(实际上项目中还有xlsx-style的实现版本,见 `@/utils/excel/xlsx`,不过存在问题,所以弃用了)。
```js
import {json2workbook, exportExcelByJs} from '@/utils/excel'
const column = [
{header: ['合并表头演示', '序号'], prop: 'no', merge: true},
{header: ['合并表头演示', '名称'], prop: 'name', merge: true},
{header: '日期', prop: 'date'}
]
const arr = [
{no: 1,name: '老王',date: '20190201'}
]
const workbook = json2workbook(arr, column)
exportExcelByJs(workbook, '测试导出.xlsx')
```
### json2workbook(data, columns, merge) : workbook
- `data` : `array`,json数组。
- `columns` : `array`,列配置项数组,列配置详细如下:
```js
{
header : string | array,表头名称,类型为 array 时,将从左往右地解析成一颗树,用于表头的合并
prop : string,表头对应的 json 字段名称,如果为空,则该字段不会写入excel表格
merge : boolean,是否需要合并,true的话会从上至下合并值相同的相邻单元格
width : number,单元格宽度,默认 20
}
```
- `merge` : `object`,合并配置项,详细如下:
```js
{
primaryKey : string,每行json数据的唯一标识字段名称
orderKey : string,每行json数据的序号字段名称
}
```
### exportExcelByJs(workbook, filename)
- `workbook`,json2workbook的返回结果
- `filename` : `string`,导出的文件名称,需要带上.xlsx后缀

@ -0,0 +1,25 @@
# 安装
## 环境准备
- jdk1.8
- mysql8
- redis3.2
- node
- npm
::: warning 注意
后端开发时ide需要安装lombok插件
:::
## 基础信息配置
- 导入位于`java`目录下的sql脚本(初始管理员账号密码:admin/123456)
- 修改`java/src/main/resources/application.yml`中的`datasource`、`redis`、`socket`、`file`、`qiniu`等配置项
- 根据注释修改`vue/src/config/index.js`中的变量,通常只需要修改`socketUrl`、`attachmentPrefix`、`filePreviewPrefix`即可
::: warning 注意
如果后端部署到服务器上,yml中的socket.hostname需要是服务器的局域网ip,否则socket服务端创建不了
:::

10573
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,11 @@
{
"name": "docs",
"version": "1.0.0",
"scripts": {
"dev": "vuepress dev .",
"build": "vuepress build ."
},
"devDependencies": {
"vuepress": "^1.5.2"
}
}
Loading…
Cancel
Save