Compare commits
142 Commits
v2.0.0-bet
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
4f5d88d83b | |
|
|
c8a051da23 | |
|
|
ade4e82369 | |
|
|
d5193dc265 | |
|
|
5a866808b3 | |
|
|
1fc57cf030 | |
|
|
43af3929aa | |
|
|
a76a3b65c9 | |
|
|
cc302124a3 | |
|
|
32722d4382 | |
|
|
722fc36b7f | |
|
|
35aca729f0 | |
|
|
24c58b9d7a | |
|
|
e1e0dc0b3e | |
|
|
b904d7f497 | |
|
|
456acef2d6 | |
|
|
1b5c9a49c8 | |
|
|
3c5880a201 | |
|
|
bfb8f3543a | |
|
|
f1737683df | |
|
|
6a24b17c6b | |
|
|
2592e3b43a | |
|
|
91f2362629 | |
|
|
65da8286d7 | |
|
|
362f0827e0 | |
|
|
07726d1ec8 | |
|
|
9257201a83 | |
|
|
8165cbd697 | |
|
|
16a44053c8 | |
|
|
8f48604956 | |
|
|
1124878133 | |
|
|
0ee24af85e | |
|
|
0b58996a4d | |
|
|
c336aef320 | |
|
|
dde4576bf2 | |
|
|
666639083d | |
|
|
7a75e24849 | |
|
|
11209b0ada | |
|
|
96d4982c94 | |
|
|
e78f77fc76 | |
|
|
aa52d9559b | |
|
|
c2d3e0be50 | |
|
|
1c5d33bdcd | |
|
|
ec949dace3 | |
|
|
5e345e02f5 | |
|
|
fc8cf99e59 | |
|
|
7c7fb7e73e | |
|
|
c85574b795 | |
|
|
42c153ff74 | |
|
|
17b9ef22aa | |
|
|
3ec36b6b8e | |
|
|
0f6f038d49 | |
|
|
037c8e820d | |
|
|
6106e500f4 | |
|
|
2c08ea160f | |
|
|
8552ce1267 | |
|
|
37e29bc4f7 | |
|
|
228cd68748 | |
|
|
a1803b0995 | |
|
|
e15918c532 | |
|
|
a30a6e55a6 | |
|
|
853f3d3fb8 | |
|
|
590aa7677c | |
|
|
39e8fa75f6 | |
|
|
c9fb7f42ea | |
|
|
387b0b354d | |
|
|
22ceb98ab4 | |
|
|
bd4ffc49c8 | |
|
|
e33acdc8d2 | |
|
|
cb88361a0d | |
|
|
855d0fe02a | |
|
|
12f29b7d16 | |
|
|
f4f4a82dcf | |
|
|
56742b707e | |
|
|
59a72ae1c0 | |
|
|
21b2c15577 | |
|
|
ac71d28739 | |
|
|
a72be82a9b | |
|
|
585c4028f5 | |
|
|
e82724c16f | |
|
|
ae5edc07c5 | |
|
|
afdbeacac2 | |
|
|
f1feef19ed | |
|
|
70fe4ee16a | |
|
|
a7b7a20d33 | |
|
|
b5b0b0c123 | |
|
|
612abab7df | |
|
|
5b085204f3 | |
|
|
dc302d0f12 | |
|
|
6ac6bf5644 | |
|
|
9c6f2ee1f2 | |
|
|
80d132d13f | |
|
|
e2c0b12f3e | |
|
|
454ab6fec6 | |
|
|
36a0462012 | |
|
|
9bbc3705c9 | |
|
|
d86bdb3cc5 | |
|
|
8f3a2386e6 | |
|
|
1da243719c | |
|
|
39db4e473e | |
|
|
9c7726d4bc | |
|
|
46ce4cf26c | |
|
|
84e10d6154 | |
|
|
c45d437d3d | |
|
|
096c1db65f | |
|
|
614c0bf4cb | |
|
|
e23bafc75a | |
|
|
c2d3969ac7 | |
|
|
8c2548fff0 | |
|
|
7f4f6ec8e2 | |
|
|
4f0b548e38 | |
|
|
c2ff64d973 | |
|
|
75f8c59d9c | |
|
|
35cfa08879 | |
|
|
0a7dc1a273 | |
|
|
3bae2e7207 | |
|
|
bbc5eef5e1 | |
|
|
6e9eb65ec0 | |
|
|
6d225a9118 | |
|
|
aa46211e2d | |
|
|
4d5c66cbbd | |
|
|
a35a8743fe | |
|
|
c75381a13a | |
|
|
d6e47baaad | |
|
|
b7dd9dfd52 | |
|
|
70daf10ece | |
|
|
9ddc50078d | |
|
|
73394b1c8c | |
|
|
70dffc7767 | |
|
|
8302a6ad34 | |
|
|
3bcb620f66 | |
|
|
8b0676462c | |
|
|
58d08a5ece | |
|
|
57901336e3 | |
|
|
7b89fca7fe | |
|
|
fb23651312 | |
|
|
65a4d4b2a3 | |
|
|
a72c89a73b | |
|
|
0425a692b8 | |
|
|
5223e771a5 | |
|
|
e885e77a54 | |
|
|
c21cf1bb01 |
3
.babelrc
|
|
@ -1,8 +1,5 @@
|
|||
{
|
||||
"presets": [
|
||||
"@vue/app"
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-syntax-dynamic-import"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
routers.js
|
||||
10
.eslintrc.js
|
|
@ -9,7 +9,13 @@ module.exports = {
|
|||
'generator-star-spacing': 'off',
|
||||
// allow debugger during development
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }],
|
||||
'no-undef': 'off'
|
||||
'vue/no-parsing-error': [2, {
|
||||
'x-invalid-end-tag': false
|
||||
}],
|
||||
'no-undef': 'off',
|
||||
'camelcase': 'off'
|
||||
},
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
node_modules
|
||||
/dist
|
||||
|
||||
package-lock.json
|
||||
|
||||
/tests/e2e/videos/
|
||||
/tests/e2e/screenshots/
|
||||
|
||||
|
|
|
|||
244
README.md
|
|
@ -4,183 +4,111 @@
|
|||
</a>
|
||||
</p>
|
||||
|
||||
# iView Admin
|
||||
<h1>
|
||||
iView Admin
|
||||
<h3>Vue.js 2.0 admin management system template based on iView.</h3>
|
||||
</h1>
|
||||
|
||||
[](https://github.com/iview/iview-admin/releases)
|
||||
[](https://travis-ci.org/iview/iview-admin)
|
||||
[](https://github.com/vuejs/vue)
|
||||
[](https://github.com/iview/iview)
|
||||
[](https://github.com/vuejs/vue)
|
||||
[](https://github.com/iview/iview)
|
||||
[]()
|
||||
|
||||
<h2 align="center">Special Sponsors</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://segmentfault.com/ls/1650000016424063" target="_blank">
|
||||
<img width="300" src="https://file.iviewui.com/asd/asd-i-2.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://e.coding.net/?utm_source=iview" target="_blank">
|
||||
<img width="300" src="https://file.iviewui.com/asd/asd-coding4.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://cn.udacity.com/fend/?utm_source=iviewui&utm_medium=banner&utm_campaign=fend" target="_blank">
|
||||
<img width="300" src="https://file.iviewui.com/asd/asd-u-new-2.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## 当前版本:v2.0-beta.6
|
||||
[更新日志](https://github.com/iview/iview-admin/releases)
|
||||
> If you'd like be a sponsor, to show your ads in GitHub and iView doc, please email admin@aresn.com to get more infomation.
|
||||
|
||||
[使用文档](https://lison16.github.io/iview-admin-doc/#/)
|
||||
## Introduction
|
||||
|
||||
[在线访问](https://admin.iviewui.com/)
|
||||
iView Admin is a front-end management background integration solution. It based on [Vue.js](https://github.com/vuejs/vue) and use the UI Toolkit [iView](https://github.com/iview/iview).
|
||||
|
||||
[简化版模板](https://github.com/iview/iview-admin/tree/template)
|
||||
- [Document](https://lison16.github.io/iview-admin-doc/)
|
||||
- [Preview](https://admin.iviewui.com/)
|
||||
- [Base template recommends using](https://github.com/iview/iview-admin/tree/template)
|
||||
|
||||
[教学视频(26课时)](https://segmentfault.com/ls/1650000016221751?utm_source=banner)
|
||||

|
||||
|
||||
`注:在线版本会在开发版本新小版本发布后更新到相应版本,所以如果想体验最新版本iview-admin,请clone完整项目代码到本地运行。`
|
||||
## Features
|
||||
|
||||
## Install
|
||||
- Login / Logout
|
||||
- Permission Authentication
|
||||
- A list of filters
|
||||
- Permission to switch
|
||||
- i18n
|
||||
- Components
|
||||
- Rich Text Editor
|
||||
- Markdown Editor
|
||||
- City Cascader
|
||||
- Photos preview and edit
|
||||
- Draggable list
|
||||
- File upload
|
||||
- Digital gradient
|
||||
- split-pane
|
||||
- Form
|
||||
- The article published
|
||||
- Workflow
|
||||
- Table
|
||||
- Drag-and-drop sort
|
||||
- Searchable form
|
||||
- Table export data
|
||||
- Export to Csv file
|
||||
- Export to Xls file
|
||||
- Table to picture
|
||||
- Error Page
|
||||
- 403
|
||||
- 404
|
||||
- 500
|
||||
- Router
|
||||
- Dynamic routing
|
||||
- With reference page
|
||||
- Theme
|
||||
- Shrink the sidebar
|
||||
- Tag navigation
|
||||
- Breadcrumb navigation
|
||||
- Full screen / exit full screen
|
||||
- Lock screen
|
||||
- The message center
|
||||
- Personal center
|
||||
|
||||
## Getting started
|
||||
```bush
|
||||
# clone the project
|
||||
git clone https://github.com/iview/iview-admin.git
|
||||
|
||||
// install dependencies
|
||||
npm install
|
||||
```
|
||||
## Run
|
||||
### Development
|
||||
```bush
|
||||
|
||||
// develop
|
||||
npm run dev
|
||||
```
|
||||
### Production(Build)
|
||||
|
||||
## Build
|
||||
```bush
|
||||
npm run build
|
||||
```
|
||||
|
||||
## 简介
|
||||
  iView admin是基于Vue.js,搭配使用[iView](https://www.iviewui.com) UI组件库形成的一套后台集成解决方案,由TalkingData前端可视化团队部分成员开发维护。iView admin遵守iView设计和开发约定,风格统一,设计考究,并且更多功能在不停开发中。
|
||||
如果您想查看iview-admin的更新动态,您可以到[更新日志](https://github.com/iview/iview-admin/releases)查看了解最新更新;如果您是新手,想快速入手iview-admin,您可以到[使用教程](https://github.com/iview/iview-admin/wiki)查看讲解;如果您想在线体验iview-admin,您可以到[在线访问](https://admin.iviewui.com/)体验。如果你只是想要一个清醒爽朗的界面,那你可以下载[简化版模板](https://github.com/iview/iview-admin/tree/template)来做开发。
|
||||
|
||||
## 功能
|
||||
|
||||
- 登录/登出
|
||||
- 权限管理
|
||||
- 列表过滤
|
||||
- 权限切换
|
||||
- 多语言切换
|
||||
- 组件
|
||||
- 富文本编辑器
|
||||
- Markdown编辑器
|
||||
- 城市级联
|
||||
- 图片预览编辑
|
||||
- 可拖拽列表
|
||||
- 文件上传
|
||||
- 数字渐变
|
||||
- split-pane
|
||||
- 表单编辑
|
||||
- 文章发布
|
||||
- 工作流
|
||||
- 表格
|
||||
- 可拖拽排序
|
||||
- 可编辑表格
|
||||
- 行内编辑
|
||||
- 单元格编辑
|
||||
- 可搜索表格
|
||||
- 表格导出数据
|
||||
- 导出为Csv文件
|
||||
- 导出为Xls文件
|
||||
- 表格转图片
|
||||
- 错误页面
|
||||
- 403页面
|
||||
- 404页面
|
||||
- 500页面
|
||||
- 高级路由
|
||||
- 动态路由
|
||||
- 带参页面
|
||||
- 换肤
|
||||
- 收缩侧边栏
|
||||
- tag标签导航
|
||||
- 面包屑导航
|
||||
- 全屏/退出全屏
|
||||
- 锁屏
|
||||
- 消息中心
|
||||
- 个人中心
|
||||
|
||||
## 文件结构
|
||||
```shell
|
||||
.
|
||||
├── build 项目构建配置
|
||||
├── config 开发相关配置
|
||||
├── public 打包所需静态资源
|
||||
└── src
|
||||
├── api AJAX请求
|
||||
└── assets 项目静态资源
|
||||
├── icons 自定义图标资源
|
||||
└── images 图片资源
|
||||
├── components 业务组件
|
||||
├── config 项目运行配置
|
||||
├── directive 自定义指令
|
||||
├── libs 封装工具函数
|
||||
├── locale 多语言文件
|
||||
├── mock mock模拟数据
|
||||
├── router 路由配置
|
||||
├── store Vuex配置
|
||||
├── view 页面文件
|
||||
└── tests 测试相关
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- [TalkingData](https://github.com/TalkingData)
|
||||
- [iView](https://github.com/iview/iview)
|
||||
- [Vue](https://github.com/vuejs/vue)
|
||||
- [Webpack](https://github.com/webpack/webpack)
|
||||
|
||||
## 效果展示
|
||||
|
||||
- 响应式布局首页
|
||||

|
||||
|
||||
- 标签导航
|
||||

|
||||
|
||||
- 权限管理
|
||||

|
||||
|
||||
- 可拖拽列表
|
||||

|
||||
|
||||
- 图片预览编辑
|
||||

|
||||
|
||||
- 文件上传
|
||||

|
||||
|
||||
- 数字渐变
|
||||

|
||||
|
||||
- split-pane
|
||||

|
||||
|
||||
- 文章发布
|
||||

|
||||
|
||||
- 工作流
|
||||

|
||||
|
||||
- 可拖拽表格
|
||||

|
||||
|
||||
- 可编辑表格
|
||||

|
||||
|
||||
- 表格导出数据
|
||||

|
||||
|
||||
- 表格转图片
|
||||

|
||||
|
||||
- 错误页面
|
||||

|
||||
|
||||
- 锁屏
|
||||

|
||||
|
||||
- 可收缩侧边栏
|
||||

|
||||
|
||||
- 主题切换
|
||||

|
||||
|
||||
- 消息中心
|
||||

|
||||
|
||||
### 💖💖 If you find this project helpful, maybe you can buy me a coffee. 💖💖
|
||||

|
||||
|
||||
|
||||
## License
|
||||
[MIT](http://opensource.org/licenses/MIT)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "iview-admin",
|
||||
"version": "2.0.0",
|
||||
"author": "Lison<lison.modern@gmail.com>",
|
||||
"author": "Lison<lison16new@163.com>",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve --open",
|
||||
|
|
@ -16,13 +16,16 @@
|
|||
"codemirror": "^5.38.0",
|
||||
"countup": "^1.8.2",
|
||||
"cropperjs": "^1.2.2",
|
||||
"dayjs": "^1.7.7",
|
||||
"echarts": "^4.0.4",
|
||||
"html2canvas": "^1.0.0-alpha.12",
|
||||
"iview": "^3.1.3",
|
||||
"iview": "^3.2.2",
|
||||
"iview-area": "^1.5.17",
|
||||
"js-cookie": "^2.2.0",
|
||||
"simplemde": "^1.11.2",
|
||||
"sortablejs": "^1.7.0",
|
||||
"tree-table-vue": "^1.1.0",
|
||||
"v-org-tree": "^1.0.6",
|
||||
"vue": "^2.5.10",
|
||||
"vue-i18n": "^7.8.0",
|
||||
"vue-router": "^3.0.1",
|
||||
|
|
@ -32,7 +35,6 @@
|
|||
"xlsx": "^0.13.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.0.0-rc.1",
|
||||
"@vue/cli-plugin-babel": "^3.0.1",
|
||||
"@vue/cli-plugin-eslint": "^3.0.1",
|
||||
"@vue/cli-plugin-unit-mocha": "^3.0.1",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>iview-admin</title>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
|
|
|
|||
|
|
@ -13,3 +13,39 @@ export const getDragList = () => {
|
|||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export const errorReq = () => {
|
||||
return axios.request({
|
||||
url: 'error_url',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export const saveErrorLogger = info => {
|
||||
return axios.request({
|
||||
url: 'save_error_logger',
|
||||
data: info,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export const uploadImg = formData => {
|
||||
return axios.request({
|
||||
url: 'image/upload',
|
||||
data: formData
|
||||
})
|
||||
}
|
||||
|
||||
export const getOrgData = () => {
|
||||
return axios.request({
|
||||
url: 'get_org_data',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export const getTreeSelectData = () => {
|
||||
return axios.request({
|
||||
url: 'get_tree_select_data',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,3 +28,57 @@ export const logout = (token) => {
|
|||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export const getUnreadCount = () => {
|
||||
return axios.request({
|
||||
url: 'message/count',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export const getMessage = () => {
|
||||
return axios.request({
|
||||
url: 'message/init',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export const getContentByMsgId = msg_id => {
|
||||
return axios.request({
|
||||
url: 'message/content',
|
||||
method: 'get',
|
||||
params: {
|
||||
msg_id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const hasRead = msg_id => {
|
||||
return axios.request({
|
||||
url: 'message/has_read',
|
||||
method: 'post',
|
||||
data: {
|
||||
msg_id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const removeReaded = msg_id => {
|
||||
return axios.request({
|
||||
url: 'message/remove_readed',
|
||||
method: 'post',
|
||||
data: {
|
||||
msg_id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const restoreTrash = msg_id => {
|
||||
return axios.request({
|
||||
url: 'message/restore',
|
||||
method: 'post',
|
||||
data: {
|
||||
msg_id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
@font-face {font-family: "iconfont";
|
||||
src: url('iconfont.eot?t=1530874958372'); /* IE9*/
|
||||
src: url('iconfont.eot?t=1530874958372#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),
|
||||
url('iconfont.ttf?t=1530874958372') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
||||
url('iconfont.svg?t=1530874958372#iconfont') format('svg'); /* iOS 4.1- */
|
||||
src: url('iconfont.eot?t=1541579316141'); /* IE9*/
|
||||
src: url('iconfont.eot?t=1541579316141#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'),
|
||||
url('iconfont.ttf?t=1541579316141') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
||||
url('iconfont.svg?t=1541579316141#iconfont') format('svg'); /* iOS 4.1- */
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
.icon-resize-vertical:before { content: "\e7c3"; }
|
||||
|
||||
.icon-chuizhifanzhuan:before { content: "\e661"; }
|
||||
|
||||
.icon-shuipingfanzhuan:before { content: "\e662"; }
|
||||
|
||||
.icon-qq:before { content: "\e609"; }
|
||||
|
||||
.icon-frown:before { content: "\e77e"; }
|
||||
|
|
|
|||
|
|
@ -20,19 +20,18 @@ Created by iconfont
|
|||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="x" unicode="x" horiz-adv-x="1001"
|
||||
d="M281 543q-27 -1 -53 -1h-83q-18 0 -36.5 -6t-32.5 -18.5t-23 -32t-9 -45.5v-76h912v41q0 16 -0.5 30t-0.5 18q0 13 -5 29t-17 29.5t-31.5 22.5t-49.5 9h-133v-97h-438v97zM955 310v-52q0 -23 0.5 -52t0.5 -58t-10.5 -47.5t-26 -30t-33 -16t-31.5 -4.5q-14 -1 -29.5 -0.5
|
||||
t-29.5 0.5h-32l-45 128h-439l-44 -128h-29h-34q-20 0 -45 1q-25 0 -41 9.5t-25.5 23t-13.5 29.5t-4 30v167h911zM163 247q-12 0 -21 -8.5t-9 -21.5t9 -21.5t21 -8.5q13 0 22 8.5t9 21.5t-9 21.5t-22 8.5zM316 123q-8 -26 -14 -48q-5 -19 -10.5 -37t-7.5 -25t-3 -15t1 -14.5
|
||||
t9.5 -10.5t21.5 -4h37h67h81h80h64h36q23 0 34 12t2 38q-5 13 -9.5 30.5t-9.5 34.5q-5 19 -11 39h-368zM336 498v228q0 11 2.5 23t10 21.5t20.5 15.5t34 6h188q31 0 51.5 -14.5t20.5 -52.5v-227h-327z" />
|
||||
|
||||
|
||||
|
||||
<glyph glyph-name="bear" unicode="" d="M1024 683.008q0-70.656-46.08-121.856 46.08-89.088 46.08-193.536 0-96.256-39.936-181.248t-109.568-147.968-162.816-99.328-199.68-36.352-199.68 36.352-162.304 99.328-109.568 147.968-40.448 181.248q0 104.448 46.08 193.536-46.08 51.2-46.08 121.856 0 37.888 13.824 71.168t37.376 58.368 55.808 39.424 68.096 14.336q43.008 0 78.848-18.432t59.392-50.176q46.08 17.408 96.256 26.624t102.4 9.216 102.4-9.216 96.256-26.624q24.576 31.744 59.904 50.176t78.336 18.432q36.864 0 68.608-14.336t55.296-39.424 37.376-58.368 13.824-71.168zM205.824 268.288q10.24 0 18.944 10.24t15.36 28.672 10.24 42.496 3.584 51.712-3.584 51.712-10.24 41.984-15.36 28.16-18.944 10.24q-9.216 0-17.92-10.24t-15.36-28.16-10.752-41.984-4.096-51.712 4.096-51.712 10.752-42.496 15.36-28.672 17.92-10.24zM512-31.744000000000028q53.248 0 99.84 13.312t81.408 35.84 54.784 52.736 19.968 65.024q0 33.792-19.968 64t-54.784 52.736-81.408 35.84-99.84 13.312-99.84-13.312-81.408-35.84-54.784-52.736-19.968-64q0-34.816 19.968-65.024t54.784-52.736 81.408-35.84 99.84-13.312zM818.176 268.288q10.24 0 18.944 10.24t15.36 28.672 10.24 42.496 3.584 51.712-3.584 51.712-10.24 41.984-15.36 28.16-18.944 10.24q-9.216 0-17.92-10.24t-15.36-28.16-10.752-41.984-4.096-51.712 4.096-51.712 10.752-42.496 15.36-28.672 17.92-10.24zM512 235.51999999999998q39.936 0 68.096-9.728t28.16-24.064-28.16-24.064-68.096-9.728-68.096 9.728-28.16 24.064 28.16 24.064 68.096 9.728z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="resize-vertical" unicode="" d="M512 896C229.248 896 0 666.752 0 384s229.248-512 512-512 512 229.248 512 512S794.752 896 512 896zM576 192l64 0-128-128-128 128 64 0L448 576l-64 0 128 128 128-128-64 0L576 192z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="chuizhifanzhuan" unicode="" d="M286.01856 645.08416l472.4224 0 0-146.2784-472.4224 0 0 146.2784ZM87.19872 420.37248l885.80096 0 0-70.87104-885.80096 0 0 70.87104ZM773.55008 268.05248l0-31.0016L270.6688 237.05088l0 31.0016L773.55008 268.05248zM773.55008 121.4208l0-31.0016L270.6688 90.4192l0 31.0016L773.55008 121.4208zM742.54848 240.75776l31.0016 0 0-123.04896-31.0016 0L742.54848 240.75776zM270.70464 240.57856l31.0016 0 0-123.04896-31.0016 0L270.70464 240.57856z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="shuipingfanzhuan" unicode="" d="M252.76928 596.096l146.2784 0 0-472.42752-146.2784 0 0 472.42752ZM477.48096 810.65472l70.87104 0 0-885.80608-70.87104 0 0 885.80608ZM629.80096 611.2l31.0016 0 0-502.88128-31.0016 0L629.80096 611.2zM776.42752 611.2l31.0016 0 0-502.88128-31.0016 0L776.42752 611.2zM657.09056 580.1984l0 31.0016 123.04896 0 0-31.0016L657.09056 580.1984zM657.27488 108.35456l0 31.0016 123.04896 0 0-31.0016L657.27488 108.35456z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="qq" unicode="" d="M147.372058 491.394284c-5.28997-13.909921 2.431986-22.698872 0-75.732573-0.682996-14.25092-62.165649-78.762555-86.569511-145.791177-24.192863-66.517625-27.519845-135.978232 9.811944-163.285078 37.419789-27.305846 72.191593 90.879487 76.757567 73.685584 1.961989-7.509958 4.436975-15.317914 7.423958-23.338868a331.945126 331.945126 0 0 1 61.140655-101.162429c5.929967-6.783962-36.009797-19.199892-61.140655-61.99365-25.173858-42.751759 7.209959-120.49032 132.223254-120.49032 161.27909 0 197.288886 56.70368 200.574868 56.447681 12.031932-0.895995 12.841928 0 25.599855 0 15.572912 0 9.129948-1.279993 23.593867 0 7.807956 0.682996 86.186514-67.839617 194.686901-56.447681 184.873956 19.45589 156.586116 81.40754 142.079198 120.48932-15.103915 40.83277-68.692612 59.946662-66.303626 62.549647 44.28775 48.938724 51.285711 79.018554 66.346626 123.9463 6.143965 18.473896 49.066723-101.674426 82.089537-73.685584 13.781922 11.690934 41.301767 60.24566 13.781922 163.285078-27.519845 102.996419-80.767544 126.505286-79.615551 145.791177 2.389987 40.191773 1.023994 68.436614-1.023994 75.732573-9.812945 35.4128-30.378829 27.604844-30.378829 35.4128C858.450044 730.752933 705.10691 896 515.966978 896s-342.398067-165.289067-342.398068-369.192916c0-16.169909-14.378919-4.223976-26.154852-35.4128z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1547543883733" class="icon" style="" viewBox="0 0 1272 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16831" xmlns:xlink="http://www.w3.org/1999/xlink" width="496.875" height="400"><defs><style type="text/css"></style></defs><path d="M729.64116345 165.27693991L634.32650881 90.125l-99.5625 78.52693991-5.17887981 4.16056009 104.74137981 83.50215546 105.09051682-83.50215546-9.77586218-7.53556009z m361.21228445 291.47198236l-456.78879245 360.19396555-456.49784537-359.99030128L110.125 511.12715547l523.93965546 413.11745671 524.23060335-413.35021555-67.44181091-54.14547436z m-456.78879245 29.21120673L385.4784479 290.00646554 318.06573237 344.12284454l315.96982771 249.16810336 316.28987101-249.40086136-67.41271555-54.14547436-248.84806008 196.21551682z" fill="#006cff" p-id="16832"></path></svg>
|
||||
|
After Width: | Height: | Size: 955 B |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1547543874130" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16498" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400"><defs><style type="text/css"></style></defs><path d="M511.8 0.6C229.2 0.6 0.1 229.7 0.1 512.3S229.2 1024 511.8 1024s511.7-229.1 511.7-511.7S794.4 0.6 511.8 0.6z m264.9 375.3c-0.1 0.1-0.1 0.2-0.2 0.3h0.2c-9 14.3-21.2 28.8-34.2 39.2-5.2 4.2-10.5 8.3-15.7 12.5v0.5c0.3 22.9-0.3 44.9-4.7 64.2-25.2 113.1-91.9 189.9-197.4 222.8-37.9 11.8-99.1 16.7-142.6 5.9-21.5-5.4-41-11.4-59.3-19.3-10.2-4.5-19.6-9.3-28.5-14.7l-8.8-5.3h0.5l-0.5-0.3c9.8 0.2 21.3 2.9 32.2 1.2 9.8-1.6 19.6-1.2 28.7-3.2 22.7-5 43-11.6 60.4-21.8 8.3-4.8 20.9-10.6 27-17.6-11.2 0.2-21.4-2.4-29.7-5.4-32.6-11.5-51.6-32.7-63.9-64.4h0.1c0-0.1-0.1-0.2-0.1-0.3 9.7 1.1 37.3 3.5 44.6-1.7-12.3-0.8-24.1-7.9-32.5-13.2-26.2-16.4-47.6-43.9-47.4-86.2v-0.3c3.5 1.7 6.9 3.3 10.4 4.9 6.6 2.8 13.3 4.3 21.1 5.9 3.1 0.7 9.3 2.4 13.2 1.4-5.1-5.8-13.2-9.7-18.4-16-14.7-18.3-28.7-45.3-25.2-77.4 0.5-4.7 1.3-9.4 2.6-14.3 2.5-9.7 6.5-18.3 10.8-26.2 0.2 0.1 0.4 0.2 0.5 0.3 2 4.2 6.4 7.2 9.1 10.6 8.6 10.7 19.2 20.3 30 28.7 36.7 28.7 69.9 46.4 123.1 59.5 13.5 3.3 29 5.9 45.1 5.9-1.9-5.8-2.7-13-2.7-20.5 0-9.7 1.3-19.6 3.3-26.8 9-32.1 28.5-55.2 57-67.6 6.9-3 14.4-5.2 22.4-6.9 4.1-0.6 8.2-1.1 12.3-1.6 39-0.7 59.8 13.5 79.6 31.6 16.8-1.4 38.7-10.8 51.6-17.4l12.6-6.9c0 0.1-0.1 0.3-0.1 0.4l0.1-0.1c-7.3 19.9-17.4 35.5-32.7 47.3-3.1 2.4-6.3 5.6-10 7.4 21.5-0.4 39.3-10 56.1-15.4v0.3z" fill="#2EB1EB" p-id="16499"></path><path d="M719.7 391.1s0.1 0 0.1-0.1c0 0-0.1 0-0.1 0.1zM726.8 428.4v-0.5 0.5zM336.4 479.9c3.3 0.7 9.9 2.7 13.8 1.2h-0.5l-0.1-0.1c-3.9 1-10.1-0.7-13.2-1.4-7.8-1.6-14.5-3.1-21.1-5.9-3.5-1.6-6.9-3.2-10.4-4.9v0.3c3.4 1.6 6.9 3.2 10.4 4.9 6.6 2.8 13.3 4.3 21.1 5.9zM719.6 391.4v0.2c21.9-0.2 39.8-10.1 56.9-15.4 0.1-0.1 0.1-0.2 0.2-0.3v-0.3c-16.9 5.3-34.6 14.9-56.1 15.4-0.4 0.1-0.7 0.3-1 0.4zM584.8 337.5c6.9-3 14.4-5.1 22.4-6.9 4.1-0.6 8.2-1 12.3-1.6 39-0.7 59.8 13.5 79.6 31.6 16.8-1.4 38.7-10.8 51.6-17.4 4.2-2.3 8.3-4.5 12.5-6.8 0-0.1 0.1-0.3 0.1-0.4l-12.6 6.9c-12.9 6.6-34.8 16-51.6 17.4-19.8-18.1-40.6-32.3-79.6-31.6-4.1 0.5-8.2 1-12.3 1.6-8 1.7-15.5 3.9-22.4 6.9-28.5 12.4-48 35.5-57 67.6-2 7.2-3.4 17.2-3.3 26.8 0-9.6 1.3-19.4 3.3-26.5 9-32.1 28.5-55.2 57-67.6zM385.2 568.5h-0.4c-7.3 5.2-34.9 2.8-44.6 1.7 0 0.1 0.1 0.2 0.1 0.3 10 1.1 38.2 3.6 44.9-2zM319.4 347.4c0.1 0.1 0.3 0.1 0.5 0.3 2 4.1 6.3 7.1 9.1 10.6 8.6 10.6 19.2 20.2 30 28.7 36.8 28.7 69.9 46.4 123.1 59.5 13.5 3.3 29.1 5.9 45.2 5.9 0-0.1-0.1-0.2-0.1-0.3-16.1 0-31.6-2.6-45.1-5.9-53.2-13.1-86.4-30.8-123.1-59.5-10.8-8.4-21.4-18-30-28.7-2.7-3.4-7.1-6.4-9.1-10.6-0.1-0.1-0.3-0.2-0.5-0.3-4.3 7.9-8.3 16.5-10.8 26.2-1.3 4.9-2.1 9.6-2.6 14.3 0.5-4.6 1.3-9.2 2.6-14 2.5-9.7 6.5-18.3 10.8-26.2zM317.7 683.2c9.9-1.6 19.6-1.2 28.7-3.2 22.8-5 43-11.6 60.4-21.8 8.4-4.9 21.3-10.8 27.3-17.9h-0.3c-6.1 7-18.7 12.8-27 17.6-17.4 10.2-37.7 16.8-60.4 21.8-9.1 2-18.9 1.6-28.7 3.2-10.9 1.7-22.4-1-32.2-1.2l0.5 0.3c9.7 0.4 21 2.9 31.7 1.2z" fill="#FFFFFF" p-id="16500"></path></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1547543863835" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16165" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400"><defs><style type="text/css"></style></defs><path d="M512 1024C229.236364 1024 0 794.763636 0 512S229.236364 0 512 0s512 229.236364 512 512-229.236364 512-512 512z m-129.861818-756.48s-36.212364 2.094545-48.989091 24.482909c-12.8 22.365091-54.318545 137.378909-54.318546 137.378909s13.847273 6.376727 37.28291-10.658909c23.435636-17.035636 30.882909-46.848 30.882909-46.848l42.589091-2.117818 1.070545 121.390545s-73.495273-1.070545-88.413091 0c-14.894545 1.047273-23.412364 40.448-23.412364 40.448h111.825455s-9.588364 67.095273-38.353455 116.084364c-28.741818 48.989091-83.060364 87.319273-83.060363 87.319273s39.424 15.965091 77.730909-6.4c38.353455-22.341818 66.629818-120.692364 66.629818-120.692364l89.925818 110.056727s8.192-52.386909-1.466182-67.188363c-9.658182-14.778182-62.208-74.286545-62.208-74.286546l-22.946909 20.247273 16.337455-65.117091h97.954909s0-38.353455-19.153455-40.494545c-19.176727-2.094545-78.801455 0-78.801454 0V371.898182h88.389818s-1.070545-39.400727-18.106182-39.400727h-143.755636l22.341818-64.954182z m169.984 61.184v358.562909h36.002909l13.102545 45.009455 63.348364-45.009455h89.064727V328.704h-201.518545z" fill="#0f84fd" p-id="16166"></path><path d="M594.781091 368.64h117.899636v277.876364h-41.890909l-53.364363 40.261818-11.636364-40.261818h-11.008V368.64z" fill="#0f84fd" p-id="16167"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
|
@ -5,6 +5,7 @@
|
|||
<script>
|
||||
import echarts from 'echarts'
|
||||
import tdTheme from './theme.json'
|
||||
import { on, off } from '@/libs/tools'
|
||||
echarts.registerTheme('tdTheme', tdTheme)
|
||||
export default {
|
||||
name: 'ChartBar',
|
||||
|
|
@ -13,6 +14,16 @@ export default {
|
|||
text: String,
|
||||
subtext: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dom: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resize () {
|
||||
this.dom.resize()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
let xAxisData = Object.keys(this.value)
|
||||
|
|
@ -35,15 +46,13 @@ export default {
|
|||
type: 'bar'
|
||||
}]
|
||||
}
|
||||
let dom = echarts.init(this.$refs.dom, 'tdTheme')
|
||||
dom.setOption(option)
|
||||
this.dom = echarts.init(this.$refs.dom, 'tdTheme')
|
||||
this.dom.setOption(option)
|
||||
on(window, 'resize', this.resize)
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
off(window, 'resize', this.resize)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.charts{
|
||||
//
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
<script>
|
||||
import echarts from 'echarts'
|
||||
import tdTheme from './theme.json'
|
||||
import { on, off } from '@/libs/tools'
|
||||
echarts.registerTheme('tdTheme', tdTheme)
|
||||
export default {
|
||||
name: 'ChartPie',
|
||||
|
|
@ -13,6 +14,16 @@ export default {
|
|||
text: String,
|
||||
subtext: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dom: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resize () {
|
||||
this.dom.resize()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
let legend = this.value.map(_ => _.name)
|
||||
|
|
@ -47,15 +58,13 @@ export default {
|
|||
}
|
||||
]
|
||||
}
|
||||
let dom = echarts.init(this.$refs.dom, 'tdTheme')
|
||||
dom.setOption(option)
|
||||
this.dom = echarts.init(this.$refs.dom, 'tdTheme')
|
||||
this.dom.setOption(option)
|
||||
on(window, 'resize', this.resize)
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
off(window, 'resize', this.resize)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.charts{
|
||||
//
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import Icons from '_c/icons'
|
||||
export default {
|
||||
name: 'CommonIcon',
|
||||
components: {Icons},
|
||||
components: { Icons },
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
import Cropper from './index.vue'
|
||||
export default Cropper
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
.bg{
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")
|
||||
}
|
||||
.cropper-wrapper{
|
||||
width: 600px;
|
||||
height: 340px;
|
||||
.img-box{
|
||||
height: 340px;
|
||||
width: 430px;
|
||||
border: 1px solid #ebebeb;
|
||||
display: inline-block;
|
||||
.bg;
|
||||
img{
|
||||
max-width: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.right-con{
|
||||
display: inline-block;
|
||||
width: 170px;
|
||||
vertical-align: top;
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px;
|
||||
.preview-box{
|
||||
height: 150px !important;
|
||||
width: 100% !important;
|
||||
overflow: hidden;
|
||||
border: 1px solid #ebebeb;
|
||||
.bg;
|
||||
}
|
||||
.button-box{
|
||||
padding: 10px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
<template>
|
||||
<div class="cropper-wrapper">
|
||||
<div class="img-box">
|
||||
<img class="cropper-image" :id="imgId" alt="">
|
||||
</div>
|
||||
<div class="right-con">
|
||||
<div v-if="preview" class="preview-box" :id="previewId"></div>
|
||||
<div class="button-box">
|
||||
<slot>
|
||||
<Upload action="image/upload" :before-upload="beforeUpload">
|
||||
<Button style="width: 150px;" type="primary">上传图片</Button>
|
||||
</Upload>
|
||||
</slot>
|
||||
<div v-show="insideSrc">
|
||||
<Button type="primary" @click="rotate">
|
||||
<Icon type="md-refresh" :size="18"/>
|
||||
</Button>
|
||||
<Button type="primary" @click="shrink">
|
||||
<Icon type="md-remove" :size="18"/>
|
||||
</Button>
|
||||
<Button type="primary" @click="magnify">
|
||||
<Icon type="md-add" :size="18"/>
|
||||
</Button>
|
||||
<Button type="primary" @click="scale('X')">
|
||||
<Icon custom="iconfont icon-shuipingfanzhuan" :size="18"/>
|
||||
</Button>
|
||||
<Button type="primary" @click="scale('Y')">
|
||||
<Icon custom="iconfont icon-chuizhifanzhuan" :size="18"/>
|
||||
</Button>
|
||||
<Button type="primary" @click="move(0, -moveStep)">
|
||||
<Icon type="md-arrow-round-up" :size="18"/>
|
||||
</Button>
|
||||
<Button type="primary" @click="move(-moveStep, 0)">
|
||||
<Icon type="md-arrow-round-back" :size="18"/>
|
||||
</Button>
|
||||
<Button type="primary" @click="move(0, moveStep)">
|
||||
<Icon type="md-arrow-round-down" :size="18"/>
|
||||
</Button>
|
||||
<Button type="primary" @click="move(moveStep, 0)">
|
||||
<Icon type="md-arrow-round-forward" :size="18"/>
|
||||
</Button>
|
||||
<Button style="width: 150px;margin-top: 10px;" type="primary" @click="crop">{{ cropButtonText }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Cropper from 'cropperjs'
|
||||
import './index.less'
|
||||
import 'cropperjs/dist/cropper.min.css'
|
||||
export default {
|
||||
name: 'Cropper',
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
preview: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
moveStep: {
|
||||
type: Number,
|
||||
default: 4
|
||||
},
|
||||
cropButtonText: {
|
||||
type: String,
|
||||
default: '裁剪'
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
cropper: null,
|
||||
insideSrc: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
imgId () {
|
||||
return `cropper${this._uid}`
|
||||
},
|
||||
previewId () {
|
||||
return `cropper_preview${this._uid}`
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
src (src) {
|
||||
this.replace(src)
|
||||
},
|
||||
insideSrc (src) {
|
||||
this.replace(src)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
beforeUpload (file) {
|
||||
const reader = new FileReader()
|
||||
reader.readAsDataURL(file)
|
||||
reader.onload = (event) => {
|
||||
this.insideSrc = event.srcElement.result
|
||||
}
|
||||
return false
|
||||
},
|
||||
replace (src) {
|
||||
this.cropper.replace(src)
|
||||
this.insideSrc = src
|
||||
},
|
||||
rotate () {
|
||||
this.cropper.rotate(90)
|
||||
},
|
||||
shrink () {
|
||||
this.cropper.zoom(-0.1)
|
||||
},
|
||||
magnify () {
|
||||
this.cropper.zoom(0.1)
|
||||
},
|
||||
scale (d) {
|
||||
this.cropper[`scale${d}`](-this.cropper.getData()[`scale${d}`])
|
||||
},
|
||||
move (...argu) {
|
||||
this.cropper.move(...argu)
|
||||
},
|
||||
crop () {
|
||||
this.cropper.getCroppedCanvas().toBlob(blob => {
|
||||
this.$emit('on-crop', blob)
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
let dom = document.getElementById(this.imgId)
|
||||
this.cropper = new Cropper(dom, {
|
||||
preview: `#${this.previewId}`,
|
||||
checkCrossOrigin: true
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<template>
|
||||
<div :class="`${prefix}-move-trigger`">
|
||||
<div :class="`${prefix}-move-trigger-point`">
|
||||
<i></i><i></i><i></i><i></i><i></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Mixin from './mixin'
|
||||
export default {
|
||||
name: 'DragDrawerTrigger',
|
||||
mixins: [Mixin]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<Drawer ref="drawerWrapper"
|
||||
:value="value"
|
||||
@input="handleInput"
|
||||
:width="width"
|
||||
:class-name="outerClasses"
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners">
|
||||
<!-- 所有插槽内容显示在这里 ↓ -->
|
||||
|
||||
<template v-for="(slots, slotsName) in $slots">
|
||||
<template v-if="slotsName !== 'default'">
|
||||
<render-dom v-for="(render, index) in slots"
|
||||
:key="`b_drawer_${slotsName}_${index}`"
|
||||
:render="() => render"
|
||||
:slot="slotsName">
|
||||
</render-dom>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div :class="`${prefix}-body-wrapper`"
|
||||
:key="`b_drawer_${slotsName}`">
|
||||
<render-dom v-for="(render, index) in slots"
|
||||
:key="`b_drawer_${slotsName}_${index}`"
|
||||
:render="() => render"
|
||||
:slot="slotsName">
|
||||
</render-dom>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<!-- 所有插槽内容显示在这里 ↑ -->
|
||||
<div v-if="draggable"
|
||||
:style="triggerStyle"
|
||||
:class="`${prefix}-trigger-wrapper`"
|
||||
@mousedown="handleTriggerMousedown">
|
||||
<slot name="trigger">
|
||||
<drag-drawer-trigger></drag-drawer-trigger>
|
||||
</slot>
|
||||
</div>
|
||||
<div v-if="$slots.footer"
|
||||
:class="`${prefix}-footer`">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</Drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RenderDom from '@/libs/render-dom'
|
||||
import DragDrawerTrigger from './drag-drawer-trigger.vue'
|
||||
import Mixin from './mixin'
|
||||
import { on, off } from '@/libs/tools'
|
||||
import './index.less'
|
||||
export default {
|
||||
name: 'BDrawer',
|
||||
components: {
|
||||
RenderDom,
|
||||
DragDrawerTrigger
|
||||
},
|
||||
mixins: [Mixin],
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: 256
|
||||
},
|
||||
// 是否可拖动修改宽度
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 最小拖动宽度
|
||||
minWidth: {
|
||||
type: [String, Number],
|
||||
default: 256
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
canMove: false,
|
||||
wrapperWidth: 0,
|
||||
wrapperLeft: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
outerClasses () {
|
||||
const classesArray = [
|
||||
`${this.prefix}-wrapper`,
|
||||
this.canMove ? 'no-select pointer-events-none' : ''
|
||||
]
|
||||
return classesArray.join(' ')
|
||||
},
|
||||
placement () {
|
||||
return this.$attrs.placement
|
||||
},
|
||||
innerWidth () {
|
||||
const width = this.width
|
||||
return width <= 100 ? (this.wrapperWidth * width) / 100 : width
|
||||
},
|
||||
triggerStyle () {
|
||||
return {
|
||||
[this.placement]: `${this.innerWidth}px`,
|
||||
position: this.$attrs.inner ? 'absolute' : 'fixed'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleInput (status) {
|
||||
this.$emit('input', status)
|
||||
},
|
||||
handleTriggerMousedown (event) {
|
||||
this.canMove = true
|
||||
this.$emit('on-resize-start')
|
||||
// 防止鼠标选中抽屉中文字,造成拖动trigger触发浏览器原生拖动行为
|
||||
window.getSelection().removeAllRanges()
|
||||
},
|
||||
handleMousemove (event) {
|
||||
if (!this.canMove) return
|
||||
// 更新容器宽度和距离左侧页面距离,如果是window则距左侧距离为0
|
||||
this.setWrapperWidth()
|
||||
const left = event.pageX - this.wrapperLeft
|
||||
// 如果抽屉方向为右边,宽度计算需用容器宽度减去left
|
||||
let width = this.placement === 'right' ? this.wrapperWidth - left : left
|
||||
// 限定做小宽度
|
||||
width = Math.max(width, parseFloat(this.minWidth))
|
||||
event.atMin = width === parseFloat(this.minWidth)
|
||||
// 如果当前width不大于100,视为百分比
|
||||
if (width <= 100) width = (width / this.wrapperWidth) * 100
|
||||
this.$emit('update:width', parseInt(width))
|
||||
this.$emit('on-resize', event)
|
||||
},
|
||||
handleMouseup (event) {
|
||||
this.canMove = false
|
||||
this.$emit('on-resize-end')
|
||||
},
|
||||
setWrapperWidth () {
|
||||
const {
|
||||
width,
|
||||
left
|
||||
} = this.$refs.drawerWrapper.$el.getBoundingClientRect()
|
||||
this.wrapperWidth = width
|
||||
this.wrapperLeft = left
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
on(document, 'mousemove', this.handleMousemove)
|
||||
on(document, 'mouseup', this.handleMouseup)
|
||||
this.setWrapperWidth()
|
||||
},
|
||||
beforeDestroy () {
|
||||
off(document, 'mousemove', this.handleMousemove)
|
||||
off(document, 'mouseup', this.handleMouseup)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import DragDrawer from './drag-drawer.vue'
|
||||
export default DragDrawer
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
@prefix: ~"drag-drawer";
|
||||
@drag-drawer-trigger-height: 100px;
|
||||
@drag-drawer-trigger-width: 8px;
|
||||
|
||||
.@{prefix}-wrapper{
|
||||
&.no-select{
|
||||
user-select: none;
|
||||
}
|
||||
&.pointer-events-none{
|
||||
pointer-events: none;
|
||||
& .@{prefix}-trigger-wrapper{
|
||||
pointer-events: all;
|
||||
}
|
||||
}
|
||||
.ivu-drawer{
|
||||
&-header{
|
||||
overflow: hidden !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
&-body{
|
||||
padding: 0;
|
||||
overflow: visible;
|
||||
position: static;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
.@{prefix}-body-wrapper{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
}
|
||||
.@{prefix}-trigger-wrapper{
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
.@{prefix}-move-trigger{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
height: @drag-drawer-trigger-height;
|
||||
width: @drag-drawer-trigger-width;
|
||||
background: rgb(243, 243, 243);
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: ~"4px / 6px";
|
||||
box-shadow: 0 0 1px 1px rgba(0, 0, 0, .2);
|
||||
line-height: @drag-drawer-trigger-height;
|
||||
cursor: col-resize;
|
||||
&-point{
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
transform: translateX(50%);
|
||||
i{
|
||||
display: block;
|
||||
border-bottom: 1px solid rgb(192, 192, 192);
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.@{prefix}-footer{
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
padding: 10px 16px;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
export default {
|
||||
data () {
|
||||
return {
|
||||
prefix: 'drag-drawer'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -68,6 +68,8 @@ export default {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
<style lang="less">
|
||||
.editor-wrapper *{
|
||||
z-index: 100 !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -55,8 +55,7 @@ export default {
|
|||
|
||||
<style lang="less">
|
||||
.common{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
float: left;
|
||||
height: 100%;
|
||||
display: table;
|
||||
text-align: center;
|
||||
|
|
@ -80,14 +79,12 @@ export default {
|
|||
position: relative;
|
||||
.left-area{
|
||||
.common;
|
||||
left: 0px;
|
||||
& > .icon{
|
||||
.middle-center;
|
||||
}
|
||||
}
|
||||
.right-area{
|
||||
.common;
|
||||
right: 0px;
|
||||
& > div{
|
||||
.middle-center;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
import ABackTop from './index.vue'
|
||||
export default ABackTop
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<div :class="classes" :style="styles" @click="back">
|
||||
<slot>
|
||||
<div :class="innerClasses">
|
||||
<i class="ivu-icon ivu-icon-ios-arrow-up"></i>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { scrollTop } from '@/libs/util'
|
||||
import { on, off } from '@/libs/tools'
|
||||
const prefixCls = 'ivu-back-top'
|
||||
|
||||
export default {
|
||||
name: 'ABackTop',
|
||||
props: {
|
||||
height: {
|
||||
type: Number,
|
||||
default: 400
|
||||
},
|
||||
bottom: {
|
||||
type: Number,
|
||||
default: 30
|
||||
},
|
||||
right: {
|
||||
type: Number,
|
||||
default: 30
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 1000
|
||||
},
|
||||
container: {
|
||||
type: null,
|
||||
default: window
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
backTop: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// window.addEventListener('scroll', this.handleScroll, false)
|
||||
// window.addEventListener('resize', this.handleScroll, false)
|
||||
on(this.containerEle, 'scroll', this.handleScroll)
|
||||
on(this.containerEle, 'resize', this.handleScroll)
|
||||
},
|
||||
beforeDestroy () {
|
||||
// window.removeEventListener('scroll', this.handleScroll, false)
|
||||
// window.removeEventListener('resize', this.handleScroll, false)
|
||||
off(this.containerEle, 'scroll', this.handleScroll)
|
||||
off(this.containerEle, 'resize', this.handleScroll)
|
||||
},
|
||||
computed: {
|
||||
classes () {
|
||||
return [
|
||||
`${prefixCls}`,
|
||||
{
|
||||
[`${prefixCls}-show`]: this.backTop
|
||||
}
|
||||
]
|
||||
},
|
||||
styles () {
|
||||
return {
|
||||
bottom: `${this.bottom}px`,
|
||||
right: `${this.right}px`
|
||||
}
|
||||
},
|
||||
innerClasses () {
|
||||
return `${prefixCls}-inner`
|
||||
},
|
||||
containerEle () {
|
||||
return this.container === window ? window : document.querySelector(this.container)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleScroll () {
|
||||
this.backTop = this.containerEle.scrollTop >= this.height
|
||||
},
|
||||
back () {
|
||||
let target = typeof this.container === 'string' ? this.containerEle : (document.documentElement || document.body)
|
||||
const sTop = target.scrollTop
|
||||
scrollTop(this.containerEle, sTop, 0, this.duration)
|
||||
this.$emit('on-click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<template>
|
||||
<div class="error-store">
|
||||
<Badge dot :count="countComputed">
|
||||
<Button type="text" @click="openErrorLoggerPage">
|
||||
<Icon :size="20" type="ios-bug"/>
|
||||
</Button>
|
||||
</Badge>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ErrorStore',
|
||||
props: {
|
||||
count: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
hasRead: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
countComputed () {
|
||||
return this.hasRead ? 0 : this.count
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openErrorLoggerPage () {
|
||||
this.$router.push({
|
||||
name: 'error_logger_page'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.error-store{
|
||||
margin-right: 12px;
|
||||
.ivu-badge-dot{
|
||||
top: 20px;
|
||||
}
|
||||
.ivu-btn.ivu-btn-text{
|
||||
padding: 5px 1px 6px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
import ErrorStore from './error-store.vue'
|
||||
export default ErrorStore
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { showTitle } from '_c/common/util'
|
||||
import { showTitle } from '@/libs/util'
|
||||
import CommonIcon from '_c/common-icon'
|
||||
import './custom-bread-crumb.less'
|
||||
export default {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import CommonIcon from '_c/common-icon'
|
||||
import { showTitle } from '@/libs/util'
|
||||
export default {
|
||||
components: {
|
||||
CommonIcon
|
||||
},
|
||||
methods: {
|
||||
showTitle (item) {
|
||||
return this.$config.useI18n ? this.$t(item.name) : ((item.meta && item.meta.title) || item.name)
|
||||
return showTitle(item, this)
|
||||
},
|
||||
showChildren (item) {
|
||||
return item.children && (item.children.length > 1 || (item.meta && item.meta.showAlways))
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<div class="menu-collapsed" v-show="collapsed" :list="menuList">
|
||||
<template v-for="item in menuList">
|
||||
<collapsed-menu v-if="item.children && item.children.length > 1" @on-click="handleSelect" hide-title :root-icon-size="rootIconSize" :icon-size="iconSize" :theme="theme" :parent-item="item" :key="`drop-menu-${item.name}`"></collapsed-menu>
|
||||
<Tooltip transfer v-else :content="(item.meta && item.meta.title) || (item.children && item.children[0] && item.children[0].meta.title)" placement="right" :key="`drop-menu-${item.name}`">
|
||||
<Tooltip transfer v-else :content="showTitle(item.children && item.children[0] ? item.children[0] : item)" placement="right" :key="`drop-menu-${item.name}`">
|
||||
<a @click="handleSelect(getNameOrHref(item, true))" class="drop-menu-a" :style="{textAlign: 'center'}"><common-icon :size="rootIconSize" :color="textColor" :type="item.icon || (item.children && item.children[0].icon)"/></a>
|
||||
</Tooltip>
|
||||
</template>
|
||||
|
|
@ -81,7 +81,7 @@ export default {
|
|||
return this.$route.matched.map(item => item.name).filter(item => item !== name)
|
||||
},
|
||||
updateOpenName (name) {
|
||||
if (name === 'home') this.openedNames = []
|
||||
if (name === this.$config.homeName) this.openedNames = []
|
||||
else this.openedNames = this.getOpenedNamesByActiveName(name)
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -71,10 +71,10 @@
|
|||
margin: 0;
|
||||
padding: 5px 0;
|
||||
background: #fff;
|
||||
z-index: 100;
|
||||
z-index: 1000;
|
||||
list-style-type: none;
|
||||
border-radius: 4px;
|
||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
|
||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .1);
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 5px 15px;
|
||||
|
|
|
|||
|
|
@ -33,9 +33,10 @@
|
|||
ref="tagsPageOpened"
|
||||
:key="`tag-nav-${index}`"
|
||||
:name="item.name"
|
||||
:data-route-item="item"
|
||||
@on-close="handleClose(item)"
|
||||
@click.native="handleClick(item)"
|
||||
:closable="item.name !== 'home'"
|
||||
:closable="item.name !== $config.homeName"
|
||||
:color="isCurrentTag(item) ? 'primary' : 'default'"
|
||||
@contextmenu.prevent.native="contextMenu(item, $event)"
|
||||
>{{ showTitleInside(item) }}</Tag>
|
||||
|
|
@ -108,14 +109,14 @@ export default {
|
|||
handleTagsOption (type) {
|
||||
if (type.includes('all')) {
|
||||
// 关闭所有,除了home
|
||||
let res = this.list.filter(item => item.name === 'home')
|
||||
let res = this.list.filter(item => item.name === this.$config.homeName)
|
||||
this.$emit('on-close', res, 'all')
|
||||
} else if (type.includes('others')) {
|
||||
// 关闭除当前页和home页的其他页
|
||||
let res = this.list.filter(item => routeEqual(this.currentRouteObj, item) || item.name === 'home')
|
||||
let res = this.list.filter(item => routeEqual(this.currentRouteObj, item) || item.name === this.$config.homeName)
|
||||
this.$emit('on-close', res, 'others', this.currentRouteObj)
|
||||
setTimeout(() => {
|
||||
this.getTagElementByName(this.currentRouteObj.name)
|
||||
this.getTagElementByRoute(this.currentRouteObj)
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
|
|
@ -159,11 +160,11 @@ export default {
|
|||
this.tagBodyLeft = -(tag.offsetLeft - (outerWidth - this.outerPadding - tag.offsetWidth))
|
||||
}
|
||||
},
|
||||
getTagElementByName (name) {
|
||||
getTagElementByRoute (route) {
|
||||
this.$nextTick(() => {
|
||||
this.refsTag = this.$refs.tagsPageOpened
|
||||
this.refsTag.forEach((item, index) => {
|
||||
if (name === item.name) {
|
||||
if (routeEqual(route, item.$attrs['data-route-item'])) {
|
||||
let tag = this.refsTag[index].$el
|
||||
this.moveToView(tag)
|
||||
}
|
||||
|
|
@ -171,7 +172,7 @@ export default {
|
|||
})
|
||||
},
|
||||
contextMenu (item, e) {
|
||||
if (item.name === 'home') {
|
||||
if (item.name === this.$config.homeName) {
|
||||
return
|
||||
}
|
||||
this.visible = true
|
||||
|
|
@ -185,7 +186,7 @@ export default {
|
|||
},
|
||||
watch: {
|
||||
'$route' (to) {
|
||||
this.getTagElementByName(to.name)
|
||||
this.getTagElementByRoute(to)
|
||||
},
|
||||
visible (value) {
|
||||
if (value) {
|
||||
|
|
@ -197,7 +198,7 @@ export default {
|
|||
},
|
||||
mounted () {
|
||||
setTimeout(() => {
|
||||
this.getTagElementByName(this.$route.name)
|
||||
this.getTagElementByRoute(this.$route)
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
.user{
|
||||
&-avator-dropdown{
|
||||
&-avatar-dropdown{
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
// height: 64px;
|
||||
vertical-align: middle;
|
||||
// line-height: 64px;
|
||||
.ivu-badge-dot{
|
||||
top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
<template>
|
||||
<div class="user-avator-dropdown">
|
||||
<div class="user-avatar-dropdown">
|
||||
<Dropdown @on-click="handleClick">
|
||||
<Avatar :src="userAvator"/>
|
||||
<Badge :dot="!!messageUnreadCount">
|
||||
<Avatar :src="userAvatar"/>
|
||||
</Badge>
|
||||
<Icon :size="18" type="md-arrow-dropdown"></Icon>
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem name="message">
|
||||
消息中心<Badge style="margin-left: 10px" :count="messageUnreadCount"></Badge>
|
||||
</DropdownItem>
|
||||
<DropdownItem name="logout">退出登录</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
|
|
@ -16,23 +21,36 @@ import { mapActions } from 'vuex'
|
|||
export default {
|
||||
name: 'User',
|
||||
props: {
|
||||
userAvator: {
|
||||
userAvatar: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
messageUnreadCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
'handleLogOut'
|
||||
]),
|
||||
handleClick (name) {
|
||||
switch (name) {
|
||||
case 'logout':
|
||||
logout () {
|
||||
this.handleLogOut().then(() => {
|
||||
this.$router.push({
|
||||
name: 'login'
|
||||
})
|
||||
})
|
||||
},
|
||||
message () {
|
||||
this.$router.push({
|
||||
name: 'message_page'
|
||||
})
|
||||
},
|
||||
handleClick (name) {
|
||||
switch (name) {
|
||||
case 'logout': this.logout()
|
||||
break
|
||||
case 'message': this.message()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@
|
|||
<Layout>
|
||||
<Header class="header-con">
|
||||
<header-bar :collapsed="collapsed" @on-coll-change="handleCollapsedChange">
|
||||
<user :user-avator="userAvator"/>
|
||||
<language @on-lang-change="setLocal" style="margin-right: 10px;" :lang="local"/>
|
||||
<user :message-unread-count="unreadCount" :user-avatar="userAvatar"/>
|
||||
<language v-if="$config.useI18n" @on-lang-change="setLocal" style="margin-right: 10px;" :lang="local"/>
|
||||
<error-store v-if="$config.plugin['error-store'] && $config.plugin['error-store'].showInHeader" :has-read="hasReadErrorPage" :count="errorCount"></error-store>
|
||||
<fullscreen v-model="isFullscreen" style="margin-right: 10px;"/>
|
||||
</header-bar>
|
||||
</Header>
|
||||
|
|
@ -26,6 +27,7 @@
|
|||
<keep-alive :include="cacheList">
|
||||
<router-view/>
|
||||
</keep-alive>
|
||||
<ABackTop :height="100" :bottom="80" :right="50" container=".content-wrapper"></ABackTop>
|
||||
</Content>
|
||||
</Layout>
|
||||
</Content>
|
||||
|
|
@ -37,10 +39,13 @@ import SideMenu from './components/side-menu'
|
|||
import HeaderBar from './components/header-bar'
|
||||
import TagsNav from './components/tags-nav'
|
||||
import User from './components/user'
|
||||
import ABackTop from './components/a-back-top'
|
||||
import Fullscreen from './components/fullscreen'
|
||||
import Language from './components/language'
|
||||
import { mapMutations, mapActions } from 'vuex'
|
||||
import { getNewTagList, getNextRoute, routeEqual } from '@/libs/util'
|
||||
import ErrorStore from './components/error-store'
|
||||
import { mapMutations, mapActions, mapGetters } from 'vuex'
|
||||
import { getNewTagList, routeEqual } from '@/libs/util'
|
||||
import routers from '@/router/routers'
|
||||
import minLogo from '@/assets/images/logo-min.jpg'
|
||||
import maxLogo from '@/assets/images/logo.jpg'
|
||||
import './main.less'
|
||||
|
|
@ -52,7 +57,9 @@ export default {
|
|||
Language,
|
||||
TagsNav,
|
||||
Fullscreen,
|
||||
User
|
||||
ErrorStore,
|
||||
User,
|
||||
ABackTop
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
|
@ -63,23 +70,33 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'errorCount'
|
||||
]),
|
||||
tagNavList () {
|
||||
return this.$store.state.app.tagNavList
|
||||
},
|
||||
tagRouter () {
|
||||
return this.$store.state.app.tagRouter
|
||||
},
|
||||
userAvator () {
|
||||
return this.$store.state.user.avatorImgPath
|
||||
userAvatar () {
|
||||
return this.$store.state.user.avatarImgPath
|
||||
},
|
||||
cacheList () {
|
||||
return this.tagNavList.length ? this.tagNavList.filter(item => !(item.meta && item.meta.notCache)).map(item => item.name) : []
|
||||
const list = ['ParentView', ...this.tagNavList.length ? this.tagNavList.filter(item => !(item.meta && item.meta.notCache)).map(item => item.name) : []]
|
||||
return list
|
||||
},
|
||||
menuList () {
|
||||
return this.$store.getters.menuList
|
||||
},
|
||||
local () {
|
||||
return this.$store.state.app.local
|
||||
},
|
||||
hasReadErrorPage () {
|
||||
return this.$store.state.app.hasReadErrorPage
|
||||
},
|
||||
unreadCount () {
|
||||
return this.$store.state.user.unreadCount
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -87,10 +104,13 @@ export default {
|
|||
'setBreadCrumb',
|
||||
'setTagNavList',
|
||||
'addTag',
|
||||
'setLocal'
|
||||
'setLocal',
|
||||
'setHomeRoute',
|
||||
'closeTag'
|
||||
]),
|
||||
...mapActions([
|
||||
'handleLogin'
|
||||
'handleLogin',
|
||||
'getUnreadMessageCount'
|
||||
]),
|
||||
turnToPage (route) {
|
||||
let { name, params, query } = {}
|
||||
|
|
@ -114,13 +134,13 @@ export default {
|
|||
this.collapsed = state
|
||||
},
|
||||
handleCloseTag (res, type, route) {
|
||||
if (type !== 'others') {
|
||||
if (type === 'all') {
|
||||
this.turnToPage('home')
|
||||
} else if (routeEqual(this.$route, route)) {
|
||||
if (type === 'others') {
|
||||
this.turnToPage(this.$config.homeName)
|
||||
} else {
|
||||
const nextRoute = getNextRoute(this.tagNavList, route)
|
||||
this.$router.push(nextRoute)
|
||||
if (routeEqual(this.$route, route)) {
|
||||
this.closeTag(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setTagNavList(res)
|
||||
|
|
@ -146,33 +166,22 @@ export default {
|
|||
* @description 初始化设置面包屑导航和标签导航
|
||||
*/
|
||||
this.setTagNavList()
|
||||
this.setHomeRoute(routers)
|
||||
const { name, params, query, meta } = this.$route
|
||||
this.addTag({
|
||||
route: this.$store.state.app.homeRoute
|
||||
route: { name, params, query, meta }
|
||||
})
|
||||
this.setBreadCrumb(this.$route)
|
||||
// 设置初始语言
|
||||
this.setLocal(this.$i18n.locale)
|
||||
// 文档提示
|
||||
this.$Notice.info({
|
||||
title: '想快速上手,去看文档吧',
|
||||
duration: 0,
|
||||
render: (h) => {
|
||||
return h('p', {
|
||||
style: {
|
||||
fontSize: '13px'
|
||||
}
|
||||
}, [
|
||||
'点击',
|
||||
h('a', {
|
||||
attrs: {
|
||||
href: 'https://lison16.github.io/iview-admin-doc/#/',
|
||||
target: '_blank'
|
||||
}
|
||||
}, 'iview-admin2.0文档'),
|
||||
'快速查看'
|
||||
])
|
||||
}
|
||||
// 如果当前打开页面不在标签栏中,跳到homeName页
|
||||
if (!this.tagNavList.find(item => item.name === this.$route.name)) {
|
||||
this.$router.push({
|
||||
name: this.$config.homeName
|
||||
})
|
||||
}
|
||||
// 获取未读消息条数
|
||||
this.getUnreadMessageCount()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import Simplemde from 'simplemde'
|
||||
import 'simplemde/dist/simplemde.min.css'
|
||||
export default {
|
||||
naem: 'MarkdownEditor',
|
||||
name: 'MarkdownEditor',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,21 @@
|
|||
<template>
|
||||
<router-view/>
|
||||
<keep-alive :include="cacheList" :exclude="notCacheName">
|
||||
<router-view ref="child"/>
|
||||
</keep-alive>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'ParentView'
|
||||
name: 'ParentView',
|
||||
computed: {
|
||||
tagNavList () {
|
||||
return this.$store.state.app.tagNavList
|
||||
},
|
||||
notCacheName () {
|
||||
return [(this.$route.meta && this.$route.meta.notCache) ? this.$route.name : '']
|
||||
},
|
||||
cacheList () {
|
||||
return ['ParentView', ...this.tagNavList.length ? this.tagNavList.filter(item => !(item.meta && item.meta.notCache)).map(item => item.name) : []]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ export default {
|
|||
'on-save-edit': (params) => {
|
||||
this.value[params.row.initRowIndex][params.column.key] = this.edittingText
|
||||
this.$emit('input', this.value)
|
||||
this.$emit('on-save-edit', Object.assign(params, {value: this.edittingText}))
|
||||
this.$emit('on-save-edit', Object.assign(params, { value: this.edittingText }))
|
||||
this.edittingCellId = ''
|
||||
}
|
||||
}
|
||||
|
|
@ -265,7 +265,7 @@ export default {
|
|||
},
|
||||
value (val) {
|
||||
this.handleTableData()
|
||||
this.handleSearch()
|
||||
if (this.searchable) this.handleSearch()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
export { default } from './tree-select.vue'
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
<template>
|
||||
<Tree
|
||||
:data="data"
|
||||
@on-check-change="handleCheckSelect"
|
||||
v-on="parent.$listeners"
|
||||
v-bind="parent.$attrs"
|
||||
:load-data="loadDataCallback"
|
||||
show-checkbox
|
||||
></Tree>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Emitter from 'iview/src/mixins/emitter.js'
|
||||
|
||||
const arrayEqual = (arr1, arr2) => {
|
||||
// 判断数组的长度
|
||||
if (arr1.length !== arr2.length) {
|
||||
return false
|
||||
} else {
|
||||
// 循环遍历数组的值进行比较
|
||||
for (let i = 0; i < arr1.length; i++) {
|
||||
if (arr1[i] !== arr2[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'TreeSelectTree',
|
||||
mixins: [Emitter],
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
selectedArray: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
loadData: Function
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
flatDic: {},
|
||||
checkedArray: []
|
||||
}
|
||||
},
|
||||
inject: ['parent'],
|
||||
computed: {
|
||||
expandAll () {
|
||||
return this.parent.$attrs['expand-all']
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data (newData, oldVal) {
|
||||
this.updateFlagDic(newData)
|
||||
let selectArray = []
|
||||
this.selectedArray.forEach(id => {
|
||||
if (id in this.flatDic) selectArray.push(id)
|
||||
})
|
||||
this.$emit('on-check', selectArray.map(id => this.flatDic[id]))
|
||||
if (this.expandAll) this.checkData(newData, false, true)
|
||||
},
|
||||
selectedArray (newVal, oldVal) {
|
||||
if (arrayEqual(newVal, oldVal)) return
|
||||
const filtedNewVal = newVal.filter(id => id in this.flatDic)
|
||||
this.$emit('on-check', filtedNewVal.map(id => this.flatDic[id]))
|
||||
this.$emit('on-clear')
|
||||
this.$nextTick(() => {
|
||||
this.checkData(this.data, true)
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkEmit (value, label) {
|
||||
this.dispatch('iSelect', 'on-select-selected', {
|
||||
value,
|
||||
label
|
||||
})
|
||||
this.$emit('on-select-selected', {
|
||||
value,
|
||||
label
|
||||
})
|
||||
},
|
||||
updateFlagDic (newData) {
|
||||
let newFlagDic = {}
|
||||
this.setFlagDic(newData, item => {
|
||||
newFlagDic[item.id] = item
|
||||
})
|
||||
this.flatDic = newFlagDic
|
||||
},
|
||||
setFlagDic (data, callback) {
|
||||
data.forEach(item => {
|
||||
if (item.children && item.children.length) { this.setFlagDic(item.children, callback) }
|
||||
callback(item)
|
||||
})
|
||||
},
|
||||
handleCheckSelect (selectArray, selectItem) {
|
||||
this.$emit('on-check', selectArray)
|
||||
this.parent.$emit('on-change', selectArray)
|
||||
},
|
||||
checkData (data, emit, expandAll) {
|
||||
data.forEach(item => {
|
||||
if (this.selectedArray.includes(item.id)) {
|
||||
this.$set(item, 'checked', true)
|
||||
this.checkedArray.push(item)
|
||||
if (emit) this.checkEmit(item.id, item.title)
|
||||
} else this.$set(item, 'checked', false)
|
||||
if (item.children && item.children.length) {
|
||||
if (this.expandAll && expandAll) this.$set(item, 'expand', true)
|
||||
this.checkData(item.children, emit, expandAll)
|
||||
}
|
||||
})
|
||||
},
|
||||
loadDataCallback (item, callback) {
|
||||
this.loadData(item, data => {
|
||||
return (() => {
|
||||
callback(data)
|
||||
this.updateFlagDic(this.data)
|
||||
})(data)
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.checkData(this.data, false, true)
|
||||
this.$nextTick(() => {
|
||||
this.$emit('on-check', this.checkedArray)
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
<template>
|
||||
<Select
|
||||
ref="select"
|
||||
class="tree-select"
|
||||
v-bind="$attrs"
|
||||
@on-change="handleChange"
|
||||
multiple
|
||||
>
|
||||
<tree-select-tree-item
|
||||
:selectedArray="value"
|
||||
:data="data"
|
||||
@on-clear="handleClear"
|
||||
:load-data="loadData"
|
||||
@on-check="handleTreeCheck"
|
||||
></tree-select-tree-item>
|
||||
</Select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Emitter from 'iview/src/mixins/emitter'
|
||||
import TreeSelectTreeItem from './tree-select-tree.vue'
|
||||
export default {
|
||||
name: 'TreeSelect',
|
||||
mixins: [Emitter],
|
||||
components: {
|
||||
TreeSelectTreeItem
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
loadData: Function
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isChangedByTree: true,
|
||||
isInit: true
|
||||
}
|
||||
},
|
||||
provide () {
|
||||
return {
|
||||
parent: this
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChange (selected) {
|
||||
if (!this.isChangedByTree) this.$emit('input', selected)
|
||||
this.isChangedByTree = false
|
||||
},
|
||||
handleTreeCheck (selectedArray) {
|
||||
this.isChangedByTree = true
|
||||
this.$emit('input', selectedArray.map(item => item.id))
|
||||
},
|
||||
handleClear () {
|
||||
this.$refs.select.reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.tree-select {
|
||||
.ivu-select-dropdown {
|
||||
padding: 0 6px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
export default {
|
||||
/**
|
||||
* @description 配置显示在浏览器标签的title
|
||||
*/
|
||||
title: 'iView-admin',
|
||||
/**
|
||||
* @description token在Cookie中存储的天数,默认1天
|
||||
*/
|
||||
|
|
@ -19,5 +23,14 @@ export default {
|
|||
/**
|
||||
* @description 默认打开的首页的路由name值,默认为home
|
||||
*/
|
||||
homeName: 'home'
|
||||
homeName: 'home',
|
||||
/**
|
||||
* @description 需要加载的插件
|
||||
*/
|
||||
plugin: {
|
||||
'error-store': {
|
||||
showInHeader: true, // 设为false后不会在顶部显示错误日志徽标
|
||||
developmentOff: true // 设为true后在开发环境不会收集错误信息,方便开发中排查错误
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +1,9 @@
|
|||
import { on } from '@/libs/tools'
|
||||
import draggable from './module/draggable'
|
||||
import clipboard from './module/clipboard'
|
||||
|
||||
const directives = {
|
||||
draggable: {
|
||||
inserted: (el, binding, vnode) => {
|
||||
let triggerDom = document.querySelector(binding.value.trigger)
|
||||
triggerDom.style.cursor = 'move'
|
||||
let bodyDom = document.querySelector(binding.value.body)
|
||||
let pageX = 0
|
||||
let pageY = 0
|
||||
let transformX = 0
|
||||
let transformY = 0
|
||||
let canMove = false
|
||||
const handleMousedown = e => {
|
||||
let transform = /\(.*\)/.exec(bodyDom.style.transform)
|
||||
if (transform) {
|
||||
transform = transform[0].slice(1, transform[0].length - 1)
|
||||
let splitxy = transform.split('px, ')
|
||||
transformX = parseFloat(splitxy[0])
|
||||
transformY = parseFloat(splitxy[1].split('px')[0])
|
||||
}
|
||||
pageX = e.pageX
|
||||
pageY = e.pageY
|
||||
canMove = true
|
||||
}
|
||||
const handleMousemove = e => {
|
||||
let xOffset = e.pageX - pageX + transformX
|
||||
let yOffset = e.pageY - pageY + transformY
|
||||
if (canMove) bodyDom.style.transform = `translate(${xOffset}px, ${yOffset}px)`
|
||||
}
|
||||
const handleMouseup = e => {
|
||||
canMove = false
|
||||
}
|
||||
on(triggerDom, 'mousedown', handleMousedown)
|
||||
on(document, 'mousemove', handleMousemove)
|
||||
on(document, 'mouseup', handleMouseup)
|
||||
},
|
||||
update: (el, binding, vnode) => {
|
||||
if (!binding.value.recover) return
|
||||
let bodyDom = document.querySelector(binding.value.body)
|
||||
bodyDom.style.transform = ''
|
||||
}
|
||||
}
|
||||
draggable,
|
||||
clipboard
|
||||
}
|
||||
|
||||
export default directives
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@ const importDirective = Vue => {
|
|||
* }
|
||||
*/
|
||||
Vue.directive('draggable', directive.draggable)
|
||||
/**
|
||||
* clipboard指令 v-draggable="options"
|
||||
* options = {
|
||||
* value: /在输入框中使用v-model绑定的值/,
|
||||
* success: /复制成功后的回调/,
|
||||
* error: /复制失败后的回调/
|
||||
* }
|
||||
*/
|
||||
Vue.directive('clipboard', directive.clipboard)
|
||||
}
|
||||
|
||||
export default importDirective
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import Clipboard from 'clipboard'
|
||||
export default {
|
||||
bind: (el, binding) => {
|
||||
const clipboard = new Clipboard(el, {
|
||||
text: () => binding.value.value
|
||||
})
|
||||
el.__success_callback__ = binding.value.success
|
||||
el.__error_callback__ = binding.value.error
|
||||
clipboard.on('success', e => {
|
||||
const callback = el.__success_callback__
|
||||
callback && callback(e)
|
||||
})
|
||||
clipboard.on('error', e => {
|
||||
const callback = el.__error_callback__
|
||||
callback && callback(e)
|
||||
})
|
||||
el.__clipboard__ = clipboard
|
||||
},
|
||||
update: (el, binding) => {
|
||||
el.__clipboard__.text = () => binding.value.value
|
||||
el.__success_callback__ = binding.value.success
|
||||
el.__error_callback__ = binding.value.error
|
||||
},
|
||||
unbind: (el, binding) => {
|
||||
delete el.__success_callback__
|
||||
delete el.__error_callback__
|
||||
el.__clipboard__.destroy()
|
||||
delete el.__clipboard__
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import { on } from '@/libs/tools'
|
||||
export default {
|
||||
inserted: (el, binding, vnode) => {
|
||||
let triggerDom = document.querySelector(binding.value.trigger)
|
||||
triggerDom.style.cursor = 'move'
|
||||
let bodyDom = document.querySelector(binding.value.body)
|
||||
let pageX = 0
|
||||
let pageY = 0
|
||||
let transformX = 0
|
||||
let transformY = 0
|
||||
let canMove = false
|
||||
const handleMousedown = e => {
|
||||
let transform = /\(.*\)/.exec(bodyDom.style.transform)
|
||||
if (transform) {
|
||||
transform = transform[0].slice(1, transform[0].length - 1)
|
||||
let splitxy = transform.split('px, ')
|
||||
transformX = parseFloat(splitxy[0])
|
||||
transformY = parseFloat(splitxy[1].split('px')[0])
|
||||
}
|
||||
pageX = e.pageX
|
||||
pageY = e.pageY
|
||||
canMove = true
|
||||
}
|
||||
const handleMousemove = e => {
|
||||
let xOffset = e.pageX - pageX + transformX
|
||||
let yOffset = e.pageY - pageY + transformY
|
||||
if (canMove) bodyDom.style.transform = `translate(${xOffset}px, ${yOffset}px)`
|
||||
}
|
||||
const handleMouseup = e => {
|
||||
canMove = false
|
||||
}
|
||||
on(triggerDom, 'mousedown', handleMousedown)
|
||||
on(document, 'mousemove', handleMousemove)
|
||||
on(document, 'mouseup', handleMouseup)
|
||||
},
|
||||
update: (el, binding, vnode) => {
|
||||
if (!binding.value.recover) return
|
||||
let bodyDom = document.querySelector(binding.value.body)
|
||||
bodyDom.style.transform = ''
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,17 @@
|
|||
import axios from 'axios'
|
||||
import store from '@/store'
|
||||
// import { Spin } from 'iview'
|
||||
const addErrorLog = errorInfo => {
|
||||
const { statusText, status, request: { responseURL } } = errorInfo
|
||||
let info = {
|
||||
type: 'ajax',
|
||||
code: status,
|
||||
mes: statusText,
|
||||
url: responseURL
|
||||
}
|
||||
if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
|
||||
}
|
||||
|
||||
class HttpRequest {
|
||||
constructor (baseUrl = baseURL) {
|
||||
this.baseUrl = baseUrl
|
||||
|
|
@ -39,6 +51,16 @@ class HttpRequest {
|
|||
return { data, status }
|
||||
}, error => {
|
||||
this.destroy(url)
|
||||
let errorInfo = error.response
|
||||
if (!errorInfo) {
|
||||
const { request: { statusText, status }, config } = JSON.parse(JSON.stringify(error))
|
||||
errorInfo = {
|
||||
statusText,
|
||||
status,
|
||||
request: { responseURL: config.url }
|
||||
}
|
||||
}
|
||||
addErrorLog(errorInfo)
|
||||
return Promise.reject(error)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
export default {
|
||||
name: 'RenderDom',
|
||||
functional: true,
|
||||
props: {
|
||||
render: Function
|
||||
},
|
||||
render: (h, ctx) => {
|
||||
return ctx.props.render(h)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,12 @@ import Cookies from 'js-cookie'
|
|||
// cookie保存的天数
|
||||
import config from '@/config'
|
||||
import { forEach, hasOneOf, objEqual } from '@/libs/tools'
|
||||
const { title, cookieExpires, useI18n } = config
|
||||
|
||||
export const TOKEN_KEY = 'token'
|
||||
|
||||
export const setToken = (token) => {
|
||||
Cookies.set(TOKEN_KEY, token, {expires: config.cookieExpires || 1})
|
||||
Cookies.set(TOKEN_KEY, token, { expires: cookieExpires || 1 })
|
||||
}
|
||||
|
||||
export const getToken = () => {
|
||||
|
|
@ -53,12 +54,17 @@ export const getMenuByRouter = (list, access) => {
|
|||
* @returns {Array}
|
||||
*/
|
||||
export const getBreadCrumbList = (route, homeRoute) => {
|
||||
let homeItem = { ...homeRoute, icon: homeRoute.meta.icon }
|
||||
let routeMetched = route.matched
|
||||
if (routeMetched.some(item => item.name === homeRoute.name)) return [homeItem]
|
||||
let res = routeMetched.filter(item => {
|
||||
return item.meta === undefined || !item.meta.hide
|
||||
return item.meta === undefined || !item.meta.hideInBread
|
||||
}).map(item => {
|
||||
let meta = {...item.meta}
|
||||
if (meta.title && typeof meta.title === 'function') meta.title = meta.title(route)
|
||||
let meta = { ...item.meta }
|
||||
if (meta.title && typeof meta.title === 'function') {
|
||||
meta.__titleIsFunction__ = true
|
||||
meta.title = meta.title(route)
|
||||
}
|
||||
let obj = {
|
||||
icon: (item.meta && item.meta.icon) || '',
|
||||
name: item.name,
|
||||
|
|
@ -69,18 +75,34 @@ export const getBreadCrumbList = (route, homeRoute) => {
|
|||
res = res.filter(item => {
|
||||
return !item.meta.hideInMenu
|
||||
})
|
||||
return [Object.assign(homeRoute, { to: homeRoute.path }), ...res]
|
||||
return [{ ...homeItem, to: homeRoute.path }, ...res]
|
||||
}
|
||||
|
||||
export const getRouteTitleHandled = route => {
|
||||
let router = {...route}
|
||||
let meta = {...route.meta}
|
||||
if (meta.title && typeof meta.title === 'function') meta.title = meta.title(router)
|
||||
export const getRouteTitleHandled = (route) => {
|
||||
let router = { ...route }
|
||||
let meta = { ...route.meta }
|
||||
let title = ''
|
||||
if (meta.title) {
|
||||
if (typeof meta.title === 'function') {
|
||||
meta.__titleIsFunction__ = true
|
||||
title = meta.title(router)
|
||||
} else title = meta.title
|
||||
}
|
||||
meta.title = title
|
||||
router.meta = meta
|
||||
return router
|
||||
}
|
||||
|
||||
export const showTitle = (item, vm) => vm.$config.useI18n ? vm.$t(item.name) : ((item.meta && item.meta.title) || item.name)
|
||||
export const showTitle = (item, vm) => {
|
||||
let { title, __titleIsFunction__ } = item.meta
|
||||
if (!title) return
|
||||
if (useI18n) {
|
||||
if (title.includes('{{') && title.includes('}}') && useI18n) title = title.replace(/({{[\s\S]+?}})/, (m, str) => str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim())))
|
||||
else if (__titleIsFunction__) title = item.meta.title
|
||||
else title = vm.$t(item.name)
|
||||
} else title = (item.meta && item.meta.title) || item.name
|
||||
return title
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 本地存储和获取标签导航列表
|
||||
|
|
@ -107,7 +129,7 @@ export const getHomeRoute = (routers, homeName = 'home') => {
|
|||
while (++i < len) {
|
||||
let item = routers[i]
|
||||
if (item.children && item.children.length) {
|
||||
let res = getHomeRoute(item.children)
|
||||
let res = getHomeRoute(item.children, homeName)
|
||||
if (res.name) return res
|
||||
} else {
|
||||
if (item.name === homeName) homeRoute = item
|
||||
|
|
@ -183,7 +205,6 @@ export const getNextRoute = (list, route) => {
|
|||
res = getHomeRoute(list)
|
||||
} else {
|
||||
const index = list.findIndex(item => routeEqual(item, route))
|
||||
console.log(route, index, list.length)
|
||||
if (index === list.length - 1) res = list[list.length - 2]
|
||||
else res = list[index + 1]
|
||||
}
|
||||
|
|
@ -328,3 +349,51 @@ export const localSave = (key, value) => {
|
|||
export const localRead = (key) => {
|
||||
return localStorage.getItem(key) || ''
|
||||
}
|
||||
|
||||
// scrollTop animation
|
||||
export const scrollTop = (el, from = 0, to, duration = 500, endCallback) => {
|
||||
if (!window.requestAnimationFrame) {
|
||||
window.requestAnimationFrame = (
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function (callback) {
|
||||
return window.setTimeout(callback, 1000 / 60)
|
||||
}
|
||||
)
|
||||
}
|
||||
const difference = Math.abs(from - to)
|
||||
const step = Math.ceil(difference / duration * 50)
|
||||
|
||||
const scroll = (start, end, step) => {
|
||||
if (start === end) {
|
||||
endCallback && endCallback()
|
||||
return
|
||||
}
|
||||
|
||||
let d = (start + step > end) ? end : start + step
|
||||
if (start > end) {
|
||||
d = (start - step < end) ? end : start - step
|
||||
}
|
||||
|
||||
if (el === window) {
|
||||
window.scrollTo(d, d)
|
||||
} else {
|
||||
el.scrollTop = d
|
||||
}
|
||||
window.requestAnimationFrame(() => scroll(d, end, step))
|
||||
}
|
||||
scroll(from, to, step)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据当前跳转的路由设置显示在浏览器标签的title
|
||||
* @param {Object} routeItem 路由对象
|
||||
* @param {Object} vm Vue实例
|
||||
*/
|
||||
export const setTitle = (routeItem, vm) => {
|
||||
const handledRoute = getRouteTitleHandled(routeItem)
|
||||
const pageTitle = showTitle(handledRoute, vm)
|
||||
const resTitle = pageTitle ? `${title} - ${pageTitle}` : title
|
||||
window.document.title = resTitle
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export default {
|
||||
home: 'Home',
|
||||
login: 'Login',
|
||||
components: 'Components',
|
||||
count_to_page: 'Count-to',
|
||||
tables_page: 'Table',
|
||||
|
|
@ -15,9 +16,13 @@ export default {
|
|||
update_paste_page: 'Paste Table Data',
|
||||
multilevel: 'multilevel',
|
||||
directive_page: 'Directive',
|
||||
level_1: 'level-1',
|
||||
level_2: 'level-2',
|
||||
level_2_1: 'level-2-1',
|
||||
level_1: 'Level-1',
|
||||
level_2: 'Level-2',
|
||||
level_2_1: 'Level-2-1',
|
||||
level_2_3: 'Level-2-3',
|
||||
level_2_2: 'Level-2-2',
|
||||
level_2_2_1: 'Level-2-2-1',
|
||||
level_2_2_2: 'Level-2-2-2',
|
||||
excel: 'Excel',
|
||||
'upload-excel': 'Upload Excel',
|
||||
'export-excel': 'Export Excel',
|
||||
|
|
@ -27,5 +32,15 @@ export default {
|
|||
modalTitle: 'Modal Title',
|
||||
content: 'This is the modal box content.',
|
||||
buttonText: 'Show Modal',
|
||||
'i18n-tip': 'Note: Only this page is multi-language, other pages do not add language content to the multi-language package.'
|
||||
'i18n-tip': 'Note: Only this page is multi-language, other pages do not add language content to the multi-language package.',
|
||||
error_store_page: 'Error Collection',
|
||||
error_logger_page: 'Error Logger',
|
||||
query: 'Query',
|
||||
params: 'Params',
|
||||
cropper_page: 'Cropper',
|
||||
message_page: 'Message Center',
|
||||
tree_table_page: 'Tree Table',
|
||||
org_tree_page: 'Org Tree',
|
||||
drag_drawer_page: 'Draggable Drawer',
|
||||
tree_select_page: 'Tree Selector'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export default {
|
||||
home: '首页',
|
||||
login: '登录',
|
||||
components: '组件',
|
||||
count_to_page: '数字渐变',
|
||||
tables_page: '多功能表格',
|
||||
|
|
@ -15,9 +16,13 @@ export default {
|
|||
update_paste_page: '粘贴表格数据',
|
||||
multilevel: '多级菜单',
|
||||
directive_page: '指令',
|
||||
level_1: 'level-1',
|
||||
level_2: 'level-2',
|
||||
level_2_1: 'level-2-1',
|
||||
level_1: 'Level-1',
|
||||
level_2: 'Level-2',
|
||||
level_2_1: 'Level-2-1',
|
||||
level_2_3: 'Level-2-3',
|
||||
level_2_2: 'Level-2-2',
|
||||
level_2_2_1: 'Level-2-2-1',
|
||||
level_2_2_2: 'Level-2-2-2',
|
||||
excel: 'Excel',
|
||||
'upload-excel': '上传excel',
|
||||
'export-excel': '导出excel',
|
||||
|
|
@ -27,5 +32,15 @@ export default {
|
|||
modalTitle: '模态框题目',
|
||||
content: '这是模态框内容',
|
||||
buttonText: '显示模态框',
|
||||
'i18n-tip': '注:仅此页做了多语言,其他页面没有在多语言包中添加语言内容'
|
||||
'i18n-tip': '注:仅此页做了多语言,其他页面没有在多语言包中添加语言内容',
|
||||
error_store_page: '错误收集',
|
||||
error_logger_page: '错误日志',
|
||||
query: '带参路由',
|
||||
params: '动态路由',
|
||||
cropper_page: '图片裁剪',
|
||||
message_page: '消息中心',
|
||||
tree_table_page: '树状表格',
|
||||
org_tree_page: '组织结构树',
|
||||
drag_drawer_page: '可拖动抽屉',
|
||||
tree_select_page: '树状下拉选择器'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export default {
|
||||
home: '首頁',
|
||||
login: '登錄',
|
||||
components: '组件',
|
||||
count_to_page: '数字渐变',
|
||||
tables_page: '多功能表格',
|
||||
|
|
@ -15,9 +16,13 @@ export default {
|
|||
update_paste_page: '粘貼表格數據',
|
||||
multilevel: '多级菜单',
|
||||
directive_page: '指令',
|
||||
level_1: 'level-1',
|
||||
level_2: 'level-2',
|
||||
level_2_1: 'level-2-1',
|
||||
level_1: 'Level-1',
|
||||
level_2: 'Level-2',
|
||||
level_2_1: 'Level-2-1',
|
||||
level_2_3: 'Level-2-3',
|
||||
level_2_2: 'Level-2-2',
|
||||
level_2_2_1: 'Level-2-2-1',
|
||||
level_2_2_2: 'Level-2-2-2',
|
||||
excel: 'Excel',
|
||||
'upload-excel': '上傳excel',
|
||||
'export-excel': '導出excel',
|
||||
|
|
@ -27,5 +32,15 @@ export default {
|
|||
modalTitle: '模態框題目',
|
||||
content: '這是模態框內容',
|
||||
buttonText: '顯示模態框',
|
||||
'i18n-tip': '注:僅此頁做了多語言,其他頁面沒有在多語言包中添加語言內容'
|
||||
'i18n-tip': '注:僅此頁做了多語言,其他頁面沒有在多語言包中添加語言內容',
|
||||
error_store_page: '錯誤收集',
|
||||
error_logger_page: '錯誤日誌',
|
||||
query: '帶參路由',
|
||||
params: '動態路由',
|
||||
cropper_page: '圖片裁剪',
|
||||
message_page: '消息中心',
|
||||
tree_table_page: '樹狀表格',
|
||||
org_tree_page: '組織結構樹',
|
||||
drag_drawer_page: '可拖動抽屜',
|
||||
tree_select_page: '樹狀下拉選擇器'
|
||||
}
|
||||
|
|
|
|||
16
src/main.js
|
|
@ -8,9 +8,13 @@ import iView from 'iview'
|
|||
import i18n from '@/locale'
|
||||
import config from '@/config'
|
||||
import importDirective from '@/directive'
|
||||
import 'iview/dist/styles/iview.css'
|
||||
import { directive as clickOutside } from 'v-click-outside-x'
|
||||
import installPlugin from '@/plugin'
|
||||
import './index.less'
|
||||
import '@/assets/icons/iconfont.css'
|
||||
import TreeTable from 'tree-table-vue'
|
||||
import VOrgTree from 'v-org-tree'
|
||||
import 'v-org-tree/dist/v-org-tree.css'
|
||||
// 实际打包时应该不引入mock
|
||||
/* eslint-disable */
|
||||
if (process.env.NODE_ENV !== 'production') require('@/mock')
|
||||
|
|
@ -18,6 +22,15 @@ if (process.env.NODE_ENV !== 'production') require('@/mock')
|
|||
Vue.use(iView, {
|
||||
i18n: (key, value) => i18n.t(key, value)
|
||||
})
|
||||
Vue.use(TreeTable)
|
||||
Vue.use(VOrgTree)
|
||||
/**
|
||||
* @description 注册admin内置插件
|
||||
*/
|
||||
installPlugin(Vue)
|
||||
/**
|
||||
* @description 生产环境关掉提示
|
||||
*/
|
||||
Vue.config.productionTip = false
|
||||
/**
|
||||
* @description 全局注册应用配置
|
||||
|
|
@ -27,6 +40,7 @@ Vue.prototype.$config = config
|
|||
* 注册指令
|
||||
*/
|
||||
importDirective(Vue)
|
||||
Vue.directive('clickOutside', clickOutside)
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import Mock from 'mockjs'
|
||||
import { doCustomTimes } from '@/libs/util'
|
||||
import orgData from './data/org-data'
|
||||
import { treeData } from './data/tree-select'
|
||||
const Random = Mock.Random
|
||||
|
||||
export const getTableData = req => {
|
||||
|
|
@ -24,3 +26,15 @@ export const getDragList = req => {
|
|||
})
|
||||
return dragList
|
||||
}
|
||||
|
||||
export const uploadImage = req => {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
export const getOrgData = req => {
|
||||
return orgData
|
||||
}
|
||||
|
||||
export const getTreeSelectData = req => {
|
||||
return treeData
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
export default {
|
||||
id: 0,
|
||||
label: 'XXX科技有限公司',
|
||||
children: [
|
||||
{
|
||||
id: 2,
|
||||
label: '产品研发部',
|
||||
children: [
|
||||
{
|
||||
id: 5,
|
||||
label: '研发-前端'
|
||||
}, {
|
||||
id: 6,
|
||||
label: '研发-后端'
|
||||
}, {
|
||||
id: 9,
|
||||
label: 'UI设计'
|
||||
}, {
|
||||
id: 10,
|
||||
label: '产品经理'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: '销售部',
|
||||
children: [
|
||||
{
|
||||
id: 7,
|
||||
label: '销售一部'
|
||||
}, {
|
||||
id: 8,
|
||||
label: '销售二部'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: '财务部'
|
||||
}, {
|
||||
id: 11,
|
||||
label: 'HR人事'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
export const treeData = [
|
||||
{
|
||||
id: 1,
|
||||
title: '1',
|
||||
children: [
|
||||
{
|
||||
id: 11,
|
||||
title: '1-1',
|
||||
loading: false,
|
||||
children: [
|
||||
// {
|
||||
// id: 111,
|
||||
// title: '1-1-1'
|
||||
// },
|
||||
// {
|
||||
// id: 112,
|
||||
// title: '1-1-2'
|
||||
// },
|
||||
// {
|
||||
// id: 113,
|
||||
// title: '1-1-3'
|
||||
// },
|
||||
// {
|
||||
// id: 114,
|
||||
// title: '1-1-4'
|
||||
// }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
title: '1-2',
|
||||
children: [
|
||||
{
|
||||
id: 121,
|
||||
title: '1-2-1'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export const newTreeData = [
|
||||
{
|
||||
id: 'a',
|
||||
title: 'a',
|
||||
children: [
|
||||
{
|
||||
id: 'a1',
|
||||
title: 'a-1',
|
||||
children: [
|
||||
{
|
||||
id: 112,
|
||||
title: '1-1-2'
|
||||
},
|
||||
{
|
||||
id: 'a12',
|
||||
title: 'a-1-2'
|
||||
},
|
||||
{
|
||||
id: 'a13',
|
||||
title: 'a-1-3'
|
||||
},
|
||||
{
|
||||
id: 'a14',
|
||||
title: 'a-1-4'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'a2',
|
||||
title: 'a-2',
|
||||
children: [
|
||||
{
|
||||
id: 'a21',
|
||||
title: 'b-2-1'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
import Mock from 'mockjs'
|
||||
import { login, logout, getUserInfo } from './login'
|
||||
import { getTableData, getDragList } from './data'
|
||||
import { getTableData, getDragList, uploadImage, getOrgData, getTreeSelectData } from './data'
|
||||
import { getMessageInit, getContentByMsgId, hasRead, removeReaded, restoreTrash, messageCount } from './user'
|
||||
|
||||
// 配置Ajax请求延时,可用来测试网络延迟大时项目中一些效果
|
||||
Mock.setup({
|
||||
timeout: 1000
|
||||
})
|
||||
|
||||
// 登录相关和获取用户信息
|
||||
Mock.mock(/\/login/, login)
|
||||
|
|
@ -8,5 +14,15 @@ Mock.mock(/\/get_info/, getUserInfo)
|
|||
Mock.mock(/\/logout/, logout)
|
||||
Mock.mock(/\/get_table_data/, getTableData)
|
||||
Mock.mock(/\/get_drag_list/, getDragList)
|
||||
Mock.mock(/\/save_error_logger/, 'success')
|
||||
Mock.mock(/\/image\/upload/, uploadImage)
|
||||
Mock.mock(/\/message\/init/, getMessageInit)
|
||||
Mock.mock(/\/message\/content/, getContentByMsgId)
|
||||
Mock.mock(/\/message\/has_read/, hasRead)
|
||||
Mock.mock(/\/message\/remove_readed/, removeReaded)
|
||||
Mock.mock(/\/message\/restore/, restoreTrash)
|
||||
Mock.mock(/\/message\/count/, messageCount)
|
||||
Mock.mock(/\/get_org_data/, getOrgData)
|
||||
Mock.mock(/\/get_tree_select_data/, getTreeSelectData)
|
||||
|
||||
export default Mock
|
||||
|
|
|
|||
|
|
@ -5,20 +5,20 @@ const USER_MAP = {
|
|||
user_id: '1',
|
||||
access: ['super_admin', 'admin'],
|
||||
token: 'super_admin',
|
||||
avator: 'https://file.iviewui.com/dist/a0e88e83800f138b94d2414621bd9704.png'
|
||||
avatar: 'https://file.iviewui.com/dist/a0e88e83800f138b94d2414621bd9704.png'
|
||||
},
|
||||
admin: {
|
||||
name: 'admin',
|
||||
user_id: '2',
|
||||
access: ['admin'],
|
||||
token: 'admin',
|
||||
avator: 'https://avatars0.githubusercontent.com/u/20942571?s=460&v=4'
|
||||
avatar: 'https://avatars0.githubusercontent.com/u/20942571?s=460&v=4'
|
||||
}
|
||||
}
|
||||
|
||||
export const login = req => {
|
||||
req = JSON.parse(req.body)
|
||||
return {token: USER_MAP[req.userName].token}
|
||||
return { token: USER_MAP[req.userName].token }
|
||||
}
|
||||
|
||||
export const getUserInfo = req => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
import Mock from 'mockjs'
|
||||
import { doCustomTimes } from '@/libs/util'
|
||||
const Random = Mock.Random
|
||||
|
||||
export const getMessageInit = () => {
|
||||
let unreadList = []
|
||||
doCustomTimes(3, () => {
|
||||
unreadList.push(Mock.mock({
|
||||
title: Random.cword(10, 15),
|
||||
create_time: '@date',
|
||||
msg_id: Random.increment(100)
|
||||
}))
|
||||
})
|
||||
let readedList = []
|
||||
doCustomTimes(4, () => {
|
||||
readedList.push(Mock.mock({
|
||||
title: Random.cword(10, 15),
|
||||
create_time: '@date',
|
||||
msg_id: Random.increment(100)
|
||||
}))
|
||||
})
|
||||
let trashList = []
|
||||
doCustomTimes(2, () => {
|
||||
trashList.push(Mock.mock({
|
||||
title: Random.cword(10, 15),
|
||||
create_time: '@date',
|
||||
msg_id: Random.increment(100)
|
||||
}))
|
||||
})
|
||||
return {
|
||||
unread: unreadList,
|
||||
readed: readedList,
|
||||
trash: trashList
|
||||
}
|
||||
}
|
||||
|
||||
export const getContentByMsgId = () => {
|
||||
return `<divcourier new',="" monospace;font-weight:="" normal;font-size:="" 12px;line-height:="" 18px;white-space:="" pre;"=""><div> <span style="font-size: medium;">这是消息内容,这个内容是使用<span style="color: rgb(255, 255, 255); background-color: rgb(28, 72, 127);">富文本编辑器</span>编辑的,所以你可以看到一些<span style="text-decoration-line: underline; font-style: italic; color: rgb(194, 79, 74);">格式</span></span></div><ol><li>你可以查看Mock返回的数据格式,和api请求的接口,来确定你的后端接口的开发</li><li>使用你的真实接口后,前端页面基本不需要修改即可满足基本需求</li><li>快来试试吧</li></ol><p>${Random.csentence(100, 200)}</p></divcourier>`
|
||||
}
|
||||
|
||||
export const hasRead = () => {
|
||||
return true
|
||||
}
|
||||
|
||||
export const removeReaded = () => {
|
||||
return true
|
||||
}
|
||||
|
||||
export const restoreTrash = () => {
|
||||
return true
|
||||
}
|
||||
|
||||
export const messageCount = () => {
|
||||
return 3
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import store from '@/store'
|
||||
export default {
|
||||
install (Vue, options) {
|
||||
if (options.developmentOff && process.env.NODE_ENV === 'development') return
|
||||
Vue.config.errorHandler = (error, vm, mes) => {
|
||||
let info = {
|
||||
type: 'script',
|
||||
code: 0,
|
||||
mes: error.message,
|
||||
url: window.location.href
|
||||
}
|
||||
Vue.nextTick(() => {
|
||||
store.dispatch('addErrorLog', info)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import config from '@/config'
|
||||
const { plugin } = config
|
||||
|
||||
export default (Vue) => {
|
||||
for (let name in plugin) {
|
||||
const value = plugin[name]
|
||||
Vue.use(require(`./${name}`).default, typeof value === 'object' ? value : undefined)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,9 @@ import Router from 'vue-router'
|
|||
import routes from './routers'
|
||||
import store from '@/store'
|
||||
import iView from 'iview'
|
||||
import { getToken, canTurnTo } from '@/libs/util'
|
||||
import { setToken, getToken, canTurnTo, setTitle } from '@/libs/util'
|
||||
import config from '@/config'
|
||||
const { homeName } = config
|
||||
|
||||
Vue.use(Router)
|
||||
const router = new Router({
|
||||
|
|
@ -31,7 +33,7 @@ router.beforeEach((to, from, next) => {
|
|||
} else if (token && to.name === LOGIN_PAGE_NAME) {
|
||||
// 已登录且要跳转的页面是登录页
|
||||
next({
|
||||
name: 'home' // 跳转到home页
|
||||
name: homeName // 跳转到homeName页
|
||||
})
|
||||
} else {
|
||||
if (store.state.user.hasGetInfo) {
|
||||
|
|
@ -41,6 +43,7 @@ router.beforeEach((to, from, next) => {
|
|||
// 拉取用户信息,通过用户权限和跳转的页面的name来判断是否有权限访问;access必须是一个数组,如:['super_admin'] ['super_admin', 'admin']
|
||||
turnTo(to, user.access, next)
|
||||
}).catch(() => {
|
||||
setToken('')
|
||||
next({
|
||||
name: 'login'
|
||||
})
|
||||
|
|
@ -50,6 +53,7 @@ router.beforeEach((to, from, next) => {
|
|||
})
|
||||
|
||||
router.afterEach(to => {
|
||||
setTitle(to, router.app)
|
||||
iView.LoadingBar.finish()
|
||||
window.scrollTo(0, 0)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,8 +4,13 @@ import parentView from '@/components/parent-view'
|
|||
/**
|
||||
* iview-admin中meta除了原生参数外可配置的参数:
|
||||
* meta: {
|
||||
* title: { String|Number|Function }
|
||||
* 显示在侧边栏、面包屑和标签栏的文字
|
||||
* 使用'{{ 多语言字段 }}'形式结合多语言使用,例子看多语言的路由配置;
|
||||
* 可以传入一个回调函数,参数是当前路由对象,例子看动态路由和带参路由
|
||||
* hideInBread: (false) 设为true后此级路由将不会出现在面包屑中,示例看QQ群路由配置
|
||||
* hideInMenu: (false) 设为true后在左侧菜单不会显示该页面选项
|
||||
* notCache: (false) 设为true后页面不会缓存
|
||||
* notCache: (false) 设为true后页面在切换标签后不会缓存,如果需要缓存,无需设置这个字段,而且需要设置页面组件name属性和路由配置的name一致
|
||||
* access: (null) 可访问该页面的权限数组,当前路由设置的权限会影响子路由
|
||||
* icon: (-) 该页面在左侧菜单、面包屑和标签导航处显示的图标,如果是自定义图标,需要在图标名称前加下划线'_'
|
||||
* beforeCloseName: (-) 设置该字段,则在关闭当前tab页时会去'@/router/before-close.js'里寻找该字段名对应的方法,作为关闭前的钩子函数
|
||||
|
|
@ -58,6 +63,9 @@ export default [
|
|||
path: '/join',
|
||||
name: 'join',
|
||||
component: Main,
|
||||
meta: {
|
||||
hideInBread: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'join_page',
|
||||
|
|
@ -70,6 +78,26 @@ export default [
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/message',
|
||||
name: 'message',
|
||||
component: Main,
|
||||
meta: {
|
||||
hideInBread: true,
|
||||
hideInMenu: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'message_page',
|
||||
name: 'message_page',
|
||||
meta: {
|
||||
icon: 'md-notifications',
|
||||
title: '消息中心'
|
||||
},
|
||||
component: () => import('@/view/single-page/message/index.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/components',
|
||||
name: 'components',
|
||||
|
|
@ -79,6 +107,15 @@ export default [
|
|||
},
|
||||
component: Main,
|
||||
children: [
|
||||
{
|
||||
path: 'tree_select_page',
|
||||
name: 'tree_select_page',
|
||||
meta: {
|
||||
icon: 'md-arrow-dropdown-circle',
|
||||
title: '树状下拉选择器'
|
||||
},
|
||||
component: () => import('@/view/components/tree-select/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'count_to_page',
|
||||
name: 'count_to_page',
|
||||
|
|
@ -97,6 +134,42 @@ export default [
|
|||
},
|
||||
component: () => import('@/view/components/drag-list/drag-list.vue')
|
||||
},
|
||||
{
|
||||
path: 'drag_drawer_page',
|
||||
name: 'drag_drawer_page',
|
||||
meta: {
|
||||
icon: 'md-list',
|
||||
title: '可拖拽抽屉'
|
||||
},
|
||||
component: () => import('@/view/components/drag-drawer')
|
||||
},
|
||||
{
|
||||
path: 'org_tree_page',
|
||||
name: 'org_tree_page',
|
||||
meta: {
|
||||
icon: 'ios-people',
|
||||
title: '组织结构树'
|
||||
},
|
||||
component: () => import('@/view/components/org-tree')
|
||||
},
|
||||
{
|
||||
path: 'tree_table_page',
|
||||
name: 'tree_table_page',
|
||||
meta: {
|
||||
icon: 'md-git-branch',
|
||||
title: '树状表格'
|
||||
},
|
||||
component: () => import('@/view/components/tree-table/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'cropper_page',
|
||||
name: 'cropper_page',
|
||||
meta: {
|
||||
icon: 'md-crop',
|
||||
title: '图片裁剪'
|
||||
},
|
||||
component: () => import('@/view/components/cropper/cropper.vue')
|
||||
},
|
||||
{
|
||||
path: 'tables_page',
|
||||
name: 'tables_page',
|
||||
|
|
@ -206,7 +279,7 @@ export default [
|
|||
path: '/tools_methods',
|
||||
name: 'tools_methods',
|
||||
meta: {
|
||||
hide: true
|
||||
hideInBread: true
|
||||
},
|
||||
component: Main,
|
||||
children: [
|
||||
|
|
@ -226,7 +299,7 @@ export default [
|
|||
path: '/i18n',
|
||||
name: 'i18n',
|
||||
meta: {
|
||||
hide: true
|
||||
hideInBread: true
|
||||
},
|
||||
component: Main,
|
||||
children: [
|
||||
|
|
@ -235,17 +308,56 @@ export default [
|
|||
name: 'i18n_page',
|
||||
meta: {
|
||||
icon: 'md-planet',
|
||||
title: '指令'
|
||||
title: 'i18n - {{ i18n_page }}'
|
||||
},
|
||||
component: () => import('@/view/i18n/i18n-page.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/error_store',
|
||||
name: 'error_store',
|
||||
meta: {
|
||||
hideInBread: true
|
||||
},
|
||||
component: Main,
|
||||
children: [
|
||||
{
|
||||
path: 'error_store_page',
|
||||
name: 'error_store_page',
|
||||
meta: {
|
||||
icon: 'ios-bug',
|
||||
title: '错误收集'
|
||||
},
|
||||
component: () => import('@/view/error-store/error-store.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/error_logger',
|
||||
name: 'error_logger',
|
||||
meta: {
|
||||
hideInBread: true,
|
||||
hideInMenu: true
|
||||
},
|
||||
component: Main,
|
||||
children: [
|
||||
{
|
||||
path: 'error_logger_page',
|
||||
name: 'error_logger_page',
|
||||
meta: {
|
||||
icon: 'ios-bug',
|
||||
title: '错误收集'
|
||||
},
|
||||
component: () => import('@/view/single-page/error-logger.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/directive',
|
||||
name: 'directive',
|
||||
meta: {
|
||||
hide: true
|
||||
hideInBread: true
|
||||
},
|
||||
component: Main,
|
||||
children: [
|
||||
|
|
@ -296,7 +408,16 @@ export default [
|
|||
icon: 'md-funnel',
|
||||
title: '三级'
|
||||
},
|
||||
component: () => import('@/view/multilevel/level-2-2/level-3-1.vue')
|
||||
component: () => import('@/view/multilevel/level-2-2/level-2-2-1.vue')
|
||||
},
|
||||
{
|
||||
path: 'level_2_2_2',
|
||||
name: 'level_2_2_2',
|
||||
meta: {
|
||||
icon: 'md-funnel',
|
||||
title: '三级'
|
||||
},
|
||||
component: () => import('@/view/multilevel/level-2-2/level-2-2-2.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -308,7 +429,7 @@ export default [
|
|||
title: '二级-3'
|
||||
},
|
||||
component: () => import('@/view/multilevel/level-2-3.vue')
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -324,7 +445,7 @@ export default [
|
|||
name: 'params',
|
||||
meta: {
|
||||
icon: 'md-flower',
|
||||
title: route => `动态路由-${route.params.id}`,
|
||||
title: route => `{{ params }}-${route.params.id}`,
|
||||
notCache: true,
|
||||
beforeCloseName: 'before_close_normal'
|
||||
},
|
||||
|
|
@ -335,7 +456,7 @@ export default [
|
|||
name: 'query',
|
||||
meta: {
|
||||
icon: 'md-flower',
|
||||
title: route => `带参路由-${route.query.id}`,
|
||||
title: route => `{{ query }}-${route.query.id}`,
|
||||
notCache: true
|
||||
},
|
||||
component: () => import('@/view/argu-page/query.vue')
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
localSave,
|
||||
localRead
|
||||
} from '@/libs/util'
|
||||
import beforeClose from '@/router/before-close'
|
||||
import { saveErrorLogger } from '@/api/data'
|
||||
import router from '@/router'
|
||||
import routers from '@/router/routers'
|
||||
import config from '@/config'
|
||||
|
|
@ -29,42 +29,48 @@ export default {
|
|||
state: {
|
||||
breadCrumbList: [],
|
||||
tagNavList: [],
|
||||
homeRoute: getHomeRoute(routers, homeName),
|
||||
local: localRead('local')
|
||||
homeRoute: {},
|
||||
local: localRead('local'),
|
||||
errorList: [],
|
||||
hasReadErrorPage: false
|
||||
},
|
||||
getters: {
|
||||
menuList: (state, getters, rootState) => getMenuByRouter(routers, rootState.user.access)
|
||||
menuList: (state, getters, rootState) => getMenuByRouter(routers, rootState.user.access),
|
||||
errorCount: state => state.errorList.length
|
||||
},
|
||||
mutations: {
|
||||
setBreadCrumb (state, route) {
|
||||
state.breadCrumbList = getBreadCrumbList(route, state.homeRoute)
|
||||
},
|
||||
setHomeRoute (state, routes) {
|
||||
state.homeRoute = getHomeRoute(routes, homeName)
|
||||
},
|
||||
setTagNavList (state, list) {
|
||||
let tagList = []
|
||||
if (list) {
|
||||
state.tagNavList = [...list]
|
||||
setTagNavListInLocalstorage([...list])
|
||||
} else state.tagNavList = getTagNavListFromLocalstorage()
|
||||
tagList = [...list]
|
||||
} else tagList = getTagNavListFromLocalstorage() || []
|
||||
if (tagList[0] && tagList[0].name !== homeName) tagList.shift()
|
||||
let homeTagIndex = tagList.findIndex(item => item.name === homeName)
|
||||
if (homeTagIndex > 0) {
|
||||
let homeTag = tagList.splice(homeTagIndex, 1)[0]
|
||||
tagList.unshift(homeTag)
|
||||
}
|
||||
state.tagNavList = tagList
|
||||
setTagNavListInLocalstorage([...tagList])
|
||||
},
|
||||
closeTag (state, route) {
|
||||
let tag = state.tagNavList.filter(item => routeEqual(item, route))
|
||||
route = tag[0] ? tag[0] : null
|
||||
if (!route) return
|
||||
if (route.meta && route.meta.beforeCloseName && route.meta.beforeCloseName in beforeClose) {
|
||||
new Promise(beforeClose[route.meta.beforeCloseName]).then(close => {
|
||||
if (close) {
|
||||
closePage(state, route)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
closePage(state, route)
|
||||
}
|
||||
},
|
||||
addTag (state, { route, type = 'unshift' }) {
|
||||
let router = getRouteTitleHandled(route)
|
||||
if (!routeHasExist(state.tagNavList, router)) {
|
||||
if (type === 'push') state.tagNavList.push(router)
|
||||
else {
|
||||
if (router.name === 'home') state.tagNavList.unshift(router)
|
||||
if (router.name === homeName) state.tagNavList.unshift(router)
|
||||
else state.tagNavList.splice(1, 0, router)
|
||||
}
|
||||
setTagNavListInLocalstorage([...state.tagNavList])
|
||||
|
|
@ -73,6 +79,28 @@ export default {
|
|||
setLocal (state, lang) {
|
||||
localSave('local', lang)
|
||||
state.local = lang
|
||||
},
|
||||
addError (state, error) {
|
||||
state.errorList.push(error)
|
||||
},
|
||||
setHasReadErrorLoggerStatus (state, status = true) {
|
||||
state.hasReadErrorPage = status
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
addErrorLog ({ commit, rootState }, info) {
|
||||
if (!window.location.href.includes('error_logger_page')) commit('setHasReadErrorLoggerStatus', false)
|
||||
const { user: { token, userId, userName } } = rootState
|
||||
let data = {
|
||||
...info,
|
||||
time: Date.parse(new Date()),
|
||||
token,
|
||||
userId,
|
||||
userName
|
||||
}
|
||||
saveErrorLogger(info).then(() => {
|
||||
commit('addError', data)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,33 @@
|
|||
import { login, logout, getUserInfo } from '@/api/user'
|
||||
import {
|
||||
login,
|
||||
logout,
|
||||
getUserInfo,
|
||||
getMessage,
|
||||
getContentByMsgId,
|
||||
hasRead,
|
||||
removeReaded,
|
||||
restoreTrash,
|
||||
getUnreadCount
|
||||
} from '@/api/user'
|
||||
import { setToken, getToken } from '@/libs/util'
|
||||
|
||||
export default {
|
||||
state: {
|
||||
userName: '',
|
||||
userId: '',
|
||||
avatorImgPath: '',
|
||||
avatarImgPath: '',
|
||||
token: getToken(),
|
||||
access: '',
|
||||
hasGetInfo: false
|
||||
hasGetInfo: false,
|
||||
unreadCount: 0,
|
||||
messageUnreadList: [],
|
||||
messageReadedList: [],
|
||||
messageTrashList: [],
|
||||
messageContentStore: {}
|
||||
},
|
||||
mutations: {
|
||||
setAvator (state, avatorPath) {
|
||||
state.avatorImgPath = avatorPath
|
||||
setAvatar (state, avatarPath) {
|
||||
state.avatarImgPath = avatarPath
|
||||
},
|
||||
setUserId (state, id) {
|
||||
state.userId = id
|
||||
|
|
@ -29,11 +44,37 @@ export default {
|
|||
},
|
||||
setHasGetInfo (state, status) {
|
||||
state.hasGetInfo = status
|
||||
},
|
||||
setMessageCount (state, count) {
|
||||
state.unreadCount = count
|
||||
},
|
||||
setMessageUnreadList (state, list) {
|
||||
state.messageUnreadList = list
|
||||
},
|
||||
setMessageReadedList (state, list) {
|
||||
state.messageReadedList = list
|
||||
},
|
||||
setMessageTrashList (state, list) {
|
||||
state.messageTrashList = list
|
||||
},
|
||||
updateMessageContentStore (state, { msg_id, content }) {
|
||||
state.messageContentStore[msg_id] = content
|
||||
},
|
||||
moveMsg (state, { from, to, msg_id }) {
|
||||
const index = state[from].findIndex(_ => _.msg_id === msg_id)
|
||||
const msgItem = state[from].splice(index, 1)[0]
|
||||
msgItem.loading = false
|
||||
state[to].unshift(msgItem)
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
messageUnreadCount: state => state.messageUnreadList.length,
|
||||
messageReadedCount: state => state.messageReadedList.length,
|
||||
messageTrashCount: state => state.messageTrashList.length
|
||||
},
|
||||
actions: {
|
||||
// 登录
|
||||
handleLogin ({ commit }, {userName, password}) {
|
||||
handleLogin ({ commit }, { userName, password }) {
|
||||
userName = userName.trim()
|
||||
return new Promise((resolve, reject) => {
|
||||
login({
|
||||
|
|
@ -70,8 +111,8 @@ export default {
|
|||
try {
|
||||
getUserInfo(state.token).then(res => {
|
||||
const data = res.data
|
||||
commit('setAvator', data.avator)
|
||||
commit('setUserName', data.user_name)
|
||||
commit('setAvatar', data.avatar)
|
||||
commit('setUserName', data.name)
|
||||
commit('setUserId', data.user_id)
|
||||
commit('setAccess', data.access)
|
||||
commit('setHasGetInfo', true)
|
||||
|
|
@ -83,6 +124,94 @@ export default {
|
|||
reject(error)
|
||||
}
|
||||
})
|
||||
},
|
||||
// 此方法用来获取未读消息条数,接口只返回数值,不返回消息列表
|
||||
getUnreadMessageCount ({ state, commit }) {
|
||||
getUnreadCount().then(res => {
|
||||
const { data } = res
|
||||
commit('setMessageCount', data)
|
||||
})
|
||||
},
|
||||
// 获取消息列表,其中包含未读、已读、回收站三个列表
|
||||
getMessageList ({ state, commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getMessage().then(res => {
|
||||
const { unread, readed, trash } = res.data
|
||||
commit('setMessageUnreadList', unread.sort((a, b) => new Date(b.create_time) - new Date(a.create_time)))
|
||||
commit('setMessageReadedList', readed.map(_ => {
|
||||
_.loading = false
|
||||
return _
|
||||
}).sort((a, b) => new Date(b.create_time) - new Date(a.create_time)))
|
||||
commit('setMessageTrashList', trash.map(_ => {
|
||||
_.loading = false
|
||||
return _
|
||||
}).sort((a, b) => new Date(b.create_time) - new Date(a.create_time)))
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 根据当前点击的消息的id获取内容
|
||||
getContentByMsgId ({ state, commit }, { msg_id }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let contentItem = state.messageContentStore[msg_id]
|
||||
if (contentItem) {
|
||||
resolve(contentItem)
|
||||
} else {
|
||||
getContentByMsgId(msg_id).then(res => {
|
||||
const content = res.data
|
||||
commit('updateMessageContentStore', { msg_id, content })
|
||||
resolve(content)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 把一个未读消息标记为已读
|
||||
hasRead ({ state, commit }, { msg_id }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
hasRead(msg_id).then(() => {
|
||||
commit('moveMsg', {
|
||||
from: 'messageUnreadList',
|
||||
to: 'messageReadedList',
|
||||
msg_id
|
||||
})
|
||||
commit('setMessageCount', state.unreadCount - 1)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 删除一个已读消息到回收站
|
||||
removeReaded ({ commit }, { msg_id }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
removeReaded(msg_id).then(() => {
|
||||
commit('moveMsg', {
|
||||
from: 'messageReadedList',
|
||||
to: 'messageTrashList',
|
||||
msg_id
|
||||
})
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 还原一个已删除消息到已读消息
|
||||
restoreTrash ({ commit }, { msg_id }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
restoreTrash(msg_id).then(() => {
|
||||
commit('moveMsg', {
|
||||
from: 'messageTrashList',
|
||||
to: 'messageReadedList',
|
||||
msg_id
|
||||
})
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,32 @@
|
|||
<div>
|
||||
<Card>
|
||||
<h2>ID: {{ $route.params.id }}</h2>
|
||||
<Button @click="close">调用closeTag方法关闭本页</Button>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
export default {
|
||||
name: 'argu_page'
|
||||
name: 'params',
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'closeTag'
|
||||
]),
|
||||
close () {
|
||||
/**
|
||||
* 如果是调用closeTag方法,普通的页面传入的对象参数只需要写name字段即可
|
||||
* 如果是动态路由和带参路由,需要传入query或params字段,用来区别关闭的是参数为多少的页面
|
||||
*/
|
||||
this.closeTag({
|
||||
name: 'params',
|
||||
params: {
|
||||
id: this.$route.params.id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,32 @@
|
|||
<div>
|
||||
<Card>
|
||||
<h2>ID: {{ $route.query.id }}</h2>
|
||||
<Button @click="close">调用closeTag方法关闭本页</Button>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
export default {
|
||||
name: 'query'
|
||||
name: 'query',
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'closeTag'
|
||||
]),
|
||||
close () {
|
||||
/**
|
||||
* 如果是调用closeTag方法,普通的页面传入的对象参数只需要写name字段即可
|
||||
* 如果是动态路由和带参路由,需要传入query或params字段,用来区别关闭的是参数为多少的页面
|
||||
*/
|
||||
this.closeTag({
|
||||
name: 'query',
|
||||
query: {
|
||||
id: this.$route.query.id
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<div>
|
||||
<Row>
|
||||
<i-col span="12">
|
||||
<Card>
|
||||
<div class="cropper-example cropper-first">
|
||||
<cropper
|
||||
:src="exampleImageSrc"
|
||||
crop-button-text="确认提交"
|
||||
@on-crop="handleCroped"
|
||||
></cropper>
|
||||
</div>
|
||||
</Card>
|
||||
</i-col>
|
||||
</Row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Cropper from '@/components/cropper'
|
||||
import { uploadImg } from '@/api/data'
|
||||
export default {
|
||||
name: 'cropper_page',
|
||||
components: {
|
||||
Cropper
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
exampleImageSrc: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleCroped (blob) {
|
||||
const formData = new FormData()
|
||||
formData.append('croppedImg', blob)
|
||||
uploadImg(formData).then(() => {
|
||||
this.$Message.success('Upload success~')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.cropper-example{
|
||||
height: 400px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
<template>
|
||||
<Card>
|
||||
<h3 style="padding: 10px 0;">drag-drawer组件是对iview的drawer组件的封装,在支持drawer所有api的基础上,支持可拖动和footer底部插槽</h3>
|
||||
<div style="padding: 10px 0">
|
||||
<b>
|
||||
方向
|
||||
<i-switch v-model="placement">
|
||||
<span slot="open">左</span>
|
||||
<span slot="close">右</span>
|
||||
</i-switch>
|
||||
</b>
|
||||
<b>
|
||||
是否可拖动
|
||||
<i-switch v-model="draggable"></i-switch>
|
||||
</b>
|
||||
<Button @click="showContainerBDrawer = !showContainerBDrawer" type="primary" style="margin-left: 10px">{{ showContainerBDrawer ? '关闭' : '打开' }}容器内抽屉</Button>
|
||||
<Button @click="showWindowBDrawer = true" type="primary" style="margin-left: 10px">打开全屏抽屉</Button>
|
||||
</div>
|
||||
<div class="drag-drawer-inner-box">
|
||||
<drag-drawer v-model="showContainerBDrawer"
|
||||
:width.sync="width2"
|
||||
min-width="30px"
|
||||
:inner="true"
|
||||
:transfer="false"
|
||||
:placement="placementComputed"
|
||||
:draggable="draggable"
|
||||
@on-resize="handleResize"
|
||||
:scrollable="true">
|
||||
<div slot="header">
|
||||
<Icon type="md-aperture" :size="18"></Icon>
|
||||
<b>这是标题</b>
|
||||
</div>
|
||||
<p v-for="n in 200" :key="n">{{ n }}</p>
|
||||
<div slot="footer">
|
||||
<p>123123</p>
|
||||
<p>21312</p>
|
||||
</div>
|
||||
</drag-drawer>
|
||||
</div>
|
||||
<drag-drawer v-model="showWindowBDrawer"
|
||||
:width.sync="width1"
|
||||
:min-width="300"
|
||||
:placement="placementComputed"
|
||||
:draggable="draggable"
|
||||
:scrollable="true">
|
||||
<div slot="header">
|
||||
<Icon type="md-aperture" :size="18"></Icon>
|
||||
<b>这是标题</b>
|
||||
</div>
|
||||
<Button @click="showBDrawer3 = true">显示多层</Button>
|
||||
<p v-for="n in 200" :key="n">{{ n }}</p>
|
||||
</drag-drawer>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DragDrawer from '_c/drag-drawer'
|
||||
export default {
|
||||
name: 'drag_drawer_page',
|
||||
components: {
|
||||
DragDrawer
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showWindowBDrawer: false,
|
||||
showContainerBDrawer: false,
|
||||
showBDrawer3: false,
|
||||
width1: 300,
|
||||
width2: 200,
|
||||
placement: false,
|
||||
draggable: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
placementComputed () {
|
||||
return this.placement ? 'left' : 'right'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleResize (event) {
|
||||
const { atMin } = event
|
||||
/* eslint-disable */
|
||||
console.log(atMin);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.drag-drawer-inner-box{
|
||||
position: relative;
|
||||
width: 500px;
|
||||
height: 400px;
|
||||
background: pink;
|
||||
border: 1px solid pink;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<editor ref="editor" :value="content" @on-change="handleChange"/>
|
||||
<button @click="changeContent">修改编辑器内容</button>
|
||||
<Button @click="changeContent">修改编辑器内容</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,172 @@
|
|||
<template>
|
||||
<div
|
||||
ref="dragWrapper"
|
||||
class="org-tree-drag-wrapper"
|
||||
@mousedown="mousedownView"
|
||||
@contextmenu="handleDocumentContextmenu"
|
||||
>
|
||||
<div class="org-tree-wrapper" :style="orgTreeStyle">
|
||||
<v-org-tree
|
||||
v-if="data"
|
||||
:data="data"
|
||||
:node-render="nodeRender"
|
||||
:expand-all="true"
|
||||
@on-node-click="handleNodeClick"
|
||||
collapsable
|
||||
></v-org-tree>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { on, off } from '@/libs/tools'
|
||||
const menuList = [
|
||||
{
|
||||
key: 'edit',
|
||||
label: '编辑部门'
|
||||
},
|
||||
{
|
||||
key: 'detail',
|
||||
label: '查看部门'
|
||||
},
|
||||
{
|
||||
key: 'new',
|
||||
label: '新增子部门'
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
label: '删除部门'
|
||||
}
|
||||
]
|
||||
export default {
|
||||
name: 'OrgView',
|
||||
props: {
|
||||
zoomHandled: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
data: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
currentContextMenuId: '',
|
||||
orgTreeOffsetLeft: 0,
|
||||
orgTreeOffsetTop: 0,
|
||||
initPageX: 0,
|
||||
initPageY: 0,
|
||||
oldMarginLeft: 0,
|
||||
oldMarginTop: 0,
|
||||
canMove: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
orgTreeStyle () {
|
||||
return {
|
||||
transform: `translate(-50%, -50%) scale(${this.zoomHandled}, ${
|
||||
this.zoomHandled
|
||||
})`,
|
||||
marginLeft: `${this.orgTreeOffsetLeft}px`,
|
||||
marginTop: `${this.orgTreeOffsetTop}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleNodeClick (e, data, expand) {
|
||||
expand()
|
||||
},
|
||||
closeMenu () {
|
||||
this.currentContextMenuId = ''
|
||||
},
|
||||
getBgColor (data) {
|
||||
return this.currentContextMenuId === data.id
|
||||
? data.isRoot
|
||||
? '#0d7fe8'
|
||||
: '#5d6c7b'
|
||||
: ''
|
||||
},
|
||||
nodeRender (h, data) {
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
'custom-org-node',
|
||||
data.children && data.children.length ? 'has-children-label' : ''
|
||||
]}
|
||||
on-mousedown={event => event.stopPropagation()}
|
||||
on-contextmenu={this.contextmenu.bind(this, data)}
|
||||
>
|
||||
{data.label}
|
||||
<dropdown
|
||||
trigger="custom"
|
||||
class="context-menu"
|
||||
visible={this.currentContextMenuId === data.id}
|
||||
nativeOn-click={this.handleDropdownClick}
|
||||
on-on-click={this.handleContextMenuClick.bind(this, data)}
|
||||
style={{
|
||||
transform: `scale(${1 / this.zoomHandled}, ${1 /
|
||||
this.zoomHandled})`
|
||||
}}
|
||||
v-click-outside={this.closeMenu}
|
||||
>
|
||||
<dropdown-menu slot="list">
|
||||
{menuList.map(item => {
|
||||
return (
|
||||
<dropdown-item name={item.key}>{item.label}</dropdown-item>
|
||||
)
|
||||
})}
|
||||
</dropdown-menu>
|
||||
</dropdown>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
contextmenu (data, $event) {
|
||||
let event = $event || window.event
|
||||
event.preventDefault
|
||||
? event.preventDefault()
|
||||
: (event.returnValue = false)
|
||||
this.currentContextMenuId = data.id
|
||||
},
|
||||
setDepartmentData (data) {
|
||||
data.isRoot = true
|
||||
this.departmentData = data
|
||||
},
|
||||
mousedownView (event) {
|
||||
this.canMove = true
|
||||
this.initPageX = event.pageX
|
||||
this.initPageY = event.pageY
|
||||
this.oldMarginLeft = this.orgTreeOffsetLeft
|
||||
this.oldMarginTop = this.orgTreeOffsetTop
|
||||
on(document, 'mousemove', this.mousemoveView)
|
||||
on(document, 'mouseup', this.mouseupView)
|
||||
},
|
||||
mousemoveView (event) {
|
||||
if (!this.canMove) return
|
||||
const { pageX, pageY } = event
|
||||
this.orgTreeOffsetLeft = this.oldMarginLeft + pageX - this.initPageX
|
||||
this.orgTreeOffsetTop = this.oldMarginTop + pageY - this.initPageY
|
||||
},
|
||||
mouseupView () {
|
||||
this.canMove = false
|
||||
off(document, 'mousemove', this.mousemoveView)
|
||||
off(document, 'mouseup', this.mouseupView)
|
||||
},
|
||||
handleDropdownClick (event) {
|
||||
event.stopPropagation()
|
||||
},
|
||||
handleDocumentContextmenu () {
|
||||
this.canMove = false
|
||||
},
|
||||
handleContextMenuClick (data, key) {
|
||||
this.$emit('on-menu-click', { data, key })
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
on(document, 'contextmenu', this.handleDocumentContextmenu)
|
||||
},
|
||||
beforeDestroy () {
|
||||
off(document, 'contextmenu', this.handleDocumentContextmenu)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<template>
|
||||
<div class="zoom-wrapper">
|
||||
<button class="zoom-button" @click="scale('down')">
|
||||
<Icon type="md-remove" :size="14" color="#fff"/>
|
||||
</button>
|
||||
<span class="zoom-number">{{ value }}%</span>
|
||||
<button class="zoom-button" @click="scale('up')">
|
||||
<Icon type="md-add" :size="14" color="#fff"/>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ZoomController',
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
step: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
min: {
|
||||
type: Number,
|
||||
default: 10
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
default: 200
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scale (type) {
|
||||
const zoom = this.value + (type === 'down' ? -this.step : this.step)
|
||||
if (
|
||||
(zoom < this.min && type === 'down') ||
|
||||
(zoom > this.max && type === 'up')
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.$emit('input', zoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.trans(@duration) {
|
||||
transition: ~"all @{duration} ease-in";
|
||||
}
|
||||
.zoom-wrapper {
|
||||
.zoom-button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 10px;
|
||||
border-radius: 50%;
|
||||
background: rgba(157, 162, 172, 1);
|
||||
box-shadow: 0px 2px 8px 0px rgba(218, 220, 223, 0.7);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
&:active {
|
||||
box-shadow: 0px 0px 2px 2px rgba(218, 220, 223, 0.2) inset;
|
||||
}
|
||||
.trans(0.1s);
|
||||
&:hover {
|
||||
background: #1890ff;
|
||||
.trans(0.1s);
|
||||
}
|
||||
}
|
||||
.zoom-number {
|
||||
color: #657180;
|
||||
padding: 0 8px;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
@wrapper: ~'department';
|
||||
.percent-100 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.@{wrapper}-outer {
|
||||
.percent-100;
|
||||
overflow: hidden;
|
||||
.tip-box{
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
z-index: 12;
|
||||
}
|
||||
.zoom-box {
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
bottom: 30px;
|
||||
z-index: 2;
|
||||
}
|
||||
.view-box {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
cursor: move;
|
||||
.org-tree-drag-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.org-tree-wrapper {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transition: transform 0.2s ease-out;
|
||||
.org-tree-node-label {
|
||||
box-shadow: 0px 2px 12px 0px rgba(143, 154, 165, 0.4);
|
||||
border-radius: 4px;
|
||||
.org-tree-node-label-inner {
|
||||
padding: 0;
|
||||
.custom-org-node {
|
||||
padding: 14px 41px;
|
||||
background: #738699;
|
||||
user-select: none;
|
||||
word-wrap: none;
|
||||
white-space: nowrap;
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
transition: background 0.1s ease-in;
|
||||
cursor: default;
|
||||
&:hover {
|
||||
background: #5d6c7b;
|
||||
transition: background 0.1s ease-in;
|
||||
}
|
||||
&.has-children-label {
|
||||
cursor: pointer;
|
||||
}
|
||||
.context-menu{
|
||||
position: absolute;
|
||||
right: -10px;
|
||||
bottom: 20px;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<template>
|
||||
<Card shadow style="height: 100%;width: 100%;overflow:hidden">
|
||||
<div class="department-outer">
|
||||
<div class="tip-box">
|
||||
<b style="margin-right: 20px;">powered by <a target="blank" href="https://github.com/lison16">Lison</a></b>
|
||||
<a target="blank" href="https://github.com/lison16/v-org-tree" style="margin-right: 10px;">v-org-tree文档</a>
|
||||
</div>
|
||||
<div class="zoom-box">
|
||||
<zoom-controller v-model="zoom" :min="20" :max="200"></zoom-controller>
|
||||
</div>
|
||||
<div class="view-box">
|
||||
<org-view
|
||||
v-if="data"
|
||||
:data="data"
|
||||
:zoom-handled="zoomHandled"
|
||||
@on-menu-click="handleMenuClick"
|
||||
></org-view>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OrgView from './components/org-view.vue'
|
||||
import ZoomController from './components/zoom-controller.vue'
|
||||
import { getOrgData } from '@/api/data'
|
||||
import './index.less'
|
||||
const menuDic = {
|
||||
edit: '编辑部门',
|
||||
detail: '查看部门',
|
||||
new: '新增子部门',
|
||||
delete: '删除部门'
|
||||
}
|
||||
export default {
|
||||
name: 'org_tree_page',
|
||||
components: {
|
||||
OrgView,
|
||||
ZoomController
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
data: null,
|
||||
zoom: 100
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
zoomHandled () {
|
||||
return this.zoom / 100
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setDepartmentData (data) {
|
||||
data.isRoot = true
|
||||
return data
|
||||
},
|
||||
handleMenuClick ({ data, key }) {
|
||||
this.$Message.success({
|
||||
duration: 5,
|
||||
content: `点击了《${data.label}》节点的'${menuDic[key]}'菜单`
|
||||
})
|
||||
},
|
||||
getDepartmentData () {
|
||||
getOrgData().then(res => {
|
||||
const { data } = res
|
||||
this.data = data
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.getDepartmentData()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -18,9 +18,9 @@ export default {
|
|||
data () {
|
||||
return {
|
||||
columns: [
|
||||
{title: 'Name', key: 'name', sortable: true},
|
||||
{title: 'Email', key: 'email', editable: true},
|
||||
{title: 'Create-Time', key: 'createTime'},
|
||||
{ title: 'Name', key: 'name', sortable: true },
|
||||
{ title: 'Email', key: 'email', editable: true },
|
||||
{ title: 'Create-Time', key: 'createTime' },
|
||||
{
|
||||
title: 'Handle',
|
||||
key: 'handle',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<div>
|
||||
<tree-select
|
||||
v-model="treeSelected"
|
||||
style="width: 300px;"
|
||||
check-strictly
|
||||
:expand-all="true"
|
||||
:load-data="loadData"
|
||||
@on-change="handleTreeSelectChange"
|
||||
@on-toggle-expand="handleTreeSelectExpand"
|
||||
@on-check-change="handleTreeSelectCheckChange"
|
||||
@on-select-change="handleTreeSelectClick"
|
||||
:data="treeData"
|
||||
></tree-select>
|
||||
<Button @click="changeTreeSelectData">更新选中数据</Button>
|
||||
<Button @click="changeTreeData">更新树数据</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TreeSelect from '_c/tree-select'
|
||||
import { newTreeData } from '@/mock/data/tree-select'
|
||||
import { getTreeSelectData } from '@/api/data'
|
||||
export default {
|
||||
name: 'tree_select_page',
|
||||
components: {
|
||||
TreeSelect
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
treeSelected: [112, 113],
|
||||
treeData: []
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
getTreeSelectData().then(res => {
|
||||
const { data } = res
|
||||
this.treeData = data
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
changeTreeSelectData () {
|
||||
this.treeSelected = [111, 114]
|
||||
},
|
||||
changeTreeData () {
|
||||
this.treeData = newTreeData
|
||||
// this.treeSelected = [];
|
||||
},
|
||||
handleTreeSelectChange (list) {
|
||||
// console.log('=-========', list);
|
||||
},
|
||||
handleTreeSelectExpand (item) {
|
||||
// console.log('toggle expand', item);
|
||||
},
|
||||
handleTreeSelectCheckChange (selectedArray, item) {
|
||||
// console.log(selectedArray, item);
|
||||
},
|
||||
handleTreeSelectClick (selectArray, item) {
|
||||
// console.log(selectArray, item);
|
||||
},
|
||||
loadData (item, callback) {
|
||||
setTimeout(() => {
|
||||
let data = [
|
||||
{
|
||||
id: 111,
|
||||
title: '1-1-1'
|
||||
},
|
||||
{
|
||||
id: 112,
|
||||
title: '1-1-2'
|
||||
},
|
||||
{
|
||||
id: 113,
|
||||
title: '1-1-3'
|
||||
},
|
||||
{
|
||||
id: 114,
|
||||
title: '1-1-4'
|
||||
}
|
||||
]
|
||||
callback(data)
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
<template>
|
||||
<div>
|
||||
<Card shadow>
|
||||
树状表格组件tree-table-vue,基于<a href="https://github.com/MisterTaki/vue-table-with-tree-grid">vue-table-with-tree-grid</a>进行开发,修复了一些bug,添加了一些新属性
|
||||
<p><b>支持使用slot-scope进行自定义列渲染内容</b></p>
|
||||
<p>文档请看<a href="https://github.com/lison16/tree-table-vue">https://github.com/lison16/tree-table-vue</a></p>
|
||||
<tree-table expand-key="sex" :expand-type="false" :selectable="false" :columns="columns" :data="data" >
|
||||
<template slot="likes" slot-scope="scope">
|
||||
<Button @click="handle(scope)">123</Button>
|
||||
</template>
|
||||
</tree-table>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'tree_table_page',
|
||||
data () {
|
||||
return {
|
||||
columns: [
|
||||
{
|
||||
title: 'name',
|
||||
key: 'name',
|
||||
width: '400px'
|
||||
},
|
||||
{
|
||||
title: 'sex',
|
||||
key: 'sex',
|
||||
minWidth: '50px'
|
||||
},
|
||||
{
|
||||
title: 'score',
|
||||
key: 'score'
|
||||
},
|
||||
{
|
||||
title: 'likes',
|
||||
key: 'likes',
|
||||
minWidth: '200px',
|
||||
type: 'template',
|
||||
template: 'likes'
|
||||
}
|
||||
],
|
||||
data: [
|
||||
{
|
||||
name: 'Jack',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 10,
|
||||
children: [
|
||||
{
|
||||
name: 'Ashley',
|
||||
sex: 'female',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20,
|
||||
children: [
|
||||
{
|
||||
name: 'Ashley',
|
||||
sex: 'female',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20
|
||||
},
|
||||
{
|
||||
name: 'Taki',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 10,
|
||||
children: [
|
||||
{
|
||||
name: 'Ashley',
|
||||
sex: 'female',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20
|
||||
},
|
||||
{
|
||||
name: 'Taki',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 10,
|
||||
children: [
|
||||
{
|
||||
name: 'Ashley',
|
||||
sex: 'female',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20
|
||||
},
|
||||
{
|
||||
name: 'Taki',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Taki',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Tom',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20,
|
||||
children: [
|
||||
{
|
||||
name: 'Ashley',
|
||||
sex: 'female',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20,
|
||||
children: [
|
||||
{
|
||||
name: 'Ashley',
|
||||
sex: 'female',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20
|
||||
},
|
||||
{
|
||||
name: 'Taki',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Taki',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 10,
|
||||
children: [
|
||||
{
|
||||
name: 'Ashley',
|
||||
sex: 'female',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20
|
||||
},
|
||||
{
|
||||
name: 'Taki',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Tom',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20
|
||||
},
|
||||
{
|
||||
name: 'Tom',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20,
|
||||
children: [
|
||||
{
|
||||
name: 'Ashley',
|
||||
sex: 'female',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 20
|
||||
},
|
||||
{
|
||||
name: 'Taki',
|
||||
sex: 'male',
|
||||
likes: ['football', 'basketball'],
|
||||
score: 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handle (scope) {
|
||||
console.log(scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -4,12 +4,12 @@
|
|||
<i-col>
|
||||
<Card>
|
||||
<Row>
|
||||
<i-col span="5">
|
||||
<i-col span="8">
|
||||
<Button type="primary" @click="showModal">显示可拖动弹窗</Button>
|
||||
<br/>
|
||||
<Button v-draggable="buttonOptions" class="draggable-btn">这个按钮也是可以拖动的</Button>
|
||||
</i-col>
|
||||
<i-col span="19">
|
||||
<i-col span="16">
|
||||
<div class="intro-con">
|
||||
<Modal v-draggable="options" v-model="visible">标题</Modal>
|
||||
<pre class="code-con">
|
||||
|
|
@ -27,6 +27,42 @@
|
|||
拖动这里即可拖动整个弹窗
|
||||
</Modal>
|
||||
</Row>
|
||||
<Row style="margin-top: 10px;">
|
||||
<i-col>
|
||||
<Card>
|
||||
<Row>
|
||||
<i-col span="8">
|
||||
<Input style="width: 60%" v-model="inputValue">
|
||||
<Button slot="append" v-clipboard="clipOptions">copy</Button>
|
||||
</Input>
|
||||
</i-col>
|
||||
<i-col span="16">
|
||||
<div class="intro-con">
|
||||
<Input style="width: 60%" v-model="inputValue">
|
||||
<br/>
|
||||
<Button slot="append" v-clipboard="clipOptions">copy</Button>
|
||||
<br/>
|
||||
</Input>
|
||||
<pre class="code-con">
|
||||
clipOptions: {
|
||||
value: this.inputValue,
|
||||
success: (e) => {
|
||||
this.$Message.success('复制成功')
|
||||
},
|
||||
error: () => {
|
||||
this.$Message.error('复制失败')
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
</i-col>
|
||||
</Row>
|
||||
</Card>
|
||||
</i-col>
|
||||
<Modal v-draggable="options" v-model="modalVisible">
|
||||
拖动这里即可拖动整个弹窗
|
||||
</Modal>
|
||||
</Row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -45,7 +81,21 @@ export default {
|
|||
trigger: '.draggable-btn',
|
||||
body: '.draggable-btn'
|
||||
},
|
||||
statu: 1
|
||||
statu: 1,
|
||||
inputValue: '这是输入的内容'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
clipOptions () {
|
||||
return {
|
||||
value: this.inputValue,
|
||||
success: (e) => {
|
||||
this.$Message.success('复制成功')
|
||||
},
|
||||
error: () => {
|
||||
this.$Message.error('复制失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<Button size="large" type="text" @click="backHome">返回首页</Button>
|
||||
<Button size="large" type="text">返回上一页({{ second }}s)</Button>
|
||||
<Button size="large" type="text" @click="backPrev">返回上一页({{ second }}s)</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ export default {
|
|||
methods: {
|
||||
backHome () {
|
||||
this.$router.replace({
|
||||
name: 'home'
|
||||
name: this.$config.homeName
|
||||
})
|
||||
},
|
||||
backPrev () {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="error-page">
|
||||
<div class="content-con">
|
||||
<img :src="src" alt="404">
|
||||
<img :src="src" :alt="code">
|
||||
<div class="text-con">
|
||||
<h4>{{ code }}</h4>
|
||||
<h5>{{ desc }}</h5>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<template>
|
||||
<div>
|
||||
<Card>
|
||||
iview-admin会自动将你程序中的错误收集起来,你可以将错误日志发给后端保存起来。如果你不需要这个功能,将'./src/config/index.js'里的plugin的'error-store'属性删掉即可。
|
||||
另外在开发环境下,你程序中的错误都会被收集起来,这样可能不利于你排查错误,你可以将'./src/config/index.js'的'error-store'的'developmentOff'设为true。
|
||||
如果你只是想收集错误日志,不希望登录用户看到错误日志,你可以不提供查看日志的入口,只需将'./src/config/index.js'的'error-store'的'showInHeader'设为false。
|
||||
</Card>
|
||||
<Card style="margin-top: 20px;">
|
||||
<Row>
|
||||
<i-col span="8">
|
||||
<Button @click="click" style="display: block">点击测试触发程序错误</Button>
|
||||
<Button @click="ajaxClick" style="margin-top:10px;">点击测试触发ajax接口请求错误</Button>
|
||||
</i-col>
|
||||
<i-col span="16">
|
||||
ajax接口请求是请求easy-mock的一个不存在接口,所以服务端会报404错误,错误收集机制会收集这个错误,测试的时候有一定网络延迟,所以点击按钮之后稍等一会才会收集到错误。
|
||||
</i-col>
|
||||
</Row>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { errorReq } from '@/api/data'
|
||||
export default {
|
||||
name: 'error_store_page',
|
||||
methods: {
|
||||
click () {
|
||||
console.log(admin)
|
||||
},
|
||||
ajaxClick () {
|
||||
errorReq()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -1,44 +1,66 @@
|
|||
<template>
|
||||
<div>
|
||||
<Row :gutter="20">
|
||||
<Card shadow title="社区">
|
||||
<row class="join-page" :gutter="32">
|
||||
<i-col span="10">
|
||||
<img class="qq-group-img" src="../assets/images/icon-qr-qq-wechat.png">
|
||||
<row type="flex" justify="center">
|
||||
<i-col span="12">
|
||||
<Card title="iview-admin交流群(已满)" shadow>
|
||||
<img class="qq-group-img" :src="qqFans" alt="">
|
||||
<p class="qq-group-intro">本群为使用iview-admin或者对iview-admin感兴趣的开发者提供交流平台,在这里,解决你开发中的疑惑,共同进步。</p>
|
||||
</Card>
|
||||
<p>QQ 群号:621780943</p>
|
||||
</i-col>
|
||||
<i-col span="12">
|
||||
<Card title="iview-admin交流群2" shadow>
|
||||
<img class="qq-group-img" :src="qqFans2" alt="">
|
||||
<p class="qq-group-intro">本群为使用iview-admin或者对iview-admin感兴趣的开发者提供交流平台,在这里,解决你开发中的疑惑,共同进步。</p>
|
||||
</Card>
|
||||
<i-col span="12"></i-col>
|
||||
</row>
|
||||
</i-col>
|
||||
</Row>
|
||||
<i-col span="14">
|
||||
<div class="join-page-other">
|
||||
<Button to="https://zhuanlan.zhihu.com/feview" target="_blank" size="large">
|
||||
<img src="../assets/images/icon-social-zhihu.svg" class="join-page-other-icon">
|
||||
iView 知乎专栏
|
||||
</Button>
|
||||
<Button to="https://juejin.im/user/56fe494539b0570054f2e032" target="_blank" size="large">
|
||||
<img src="../assets/images/icon-social-juejin.svg" class="join-page-other-icon">
|
||||
掘金
|
||||
</Button>
|
||||
<Button to="https://live.bilibili.com/1353202" target="_blank" size="large">
|
||||
<img src="../assets/images/icon-social-bilibili.svg" class="join-page-other-icon">
|
||||
活动直播间
|
||||
</Button>
|
||||
<Button to="https://twitter.com/iViewUI" target="_blank" size="large">
|
||||
<img src="../assets/images/icon-social-twitter.svg" class="join-page-other-icon">
|
||||
Twitter
|
||||
</Button>
|
||||
</div>
|
||||
</i-col>
|
||||
</row>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import qqFans from '@/assets/images/qq-fance.jpg'
|
||||
import qqFans2 from '@/assets/images/qq-fance2.jpg'
|
||||
export default {
|
||||
name: 'join_page',
|
||||
data () {
|
||||
return {
|
||||
qqFans,
|
||||
qqFans2
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.qq-group-img{
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 240px;
|
||||
}
|
||||
.qq-group-intro{
|
||||
padding: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.join-page{
|
||||
text-align: center;
|
||||
}
|
||||
.qq-group-img{
|
||||
width: 100%;
|
||||
}
|
||||
.join-page-other-icon{
|
||||
width: 20px;
|
||||
vertical-align: middle;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.join-page-other{
|
||||
text-align: left;
|
||||
}
|
||||
.join-page-other .ivu-btn{
|
||||
margin-right: 6px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export default {
|
|||
this.handleLogin({ userName, password }).then(res => {
|
||||
this.getUserInfo().then(res => {
|
||||
this.$router.push({
|
||||
name: 'home'
|
||||
name: this.$config.homeName
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
<template>
|
||||
<div>
|
||||
<h3>多级菜单 -> 二级-2 -> 3级1</h3>
|
||||
<Input v-model="val" style="width: 200px"></Input>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'level_2_2_1',
|
||||
data () {
|
||||
return {
|
||||
val: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<template>
|
||||
<div>
|
||||
<h3>多级菜单 -> 二级-2 -> 3级2</h3>
|
||||
<Input v-model="val" style="width: 200px"></Input>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'level_2_2_2',
|
||||
data () {
|
||||
return {
|
||||
val: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<template>
|
||||
<div>多级菜单 -> 二级-2 -> 3级</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'level_3_1'
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
<template>
|
||||
<div>
|
||||
<Button @click="exportData" type="primary" style="margin: 0 10px 10px 0;">导出日志记录</Button>
|
||||
<b>注:这里只会显示成功保存到服务端的错误日志,而且页面错误日志不会在浏览器持久化存储,刷新页面即会丢失</b>
|
||||
<Table ref="table" :columns="columns" :data="errorList"></Table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from 'dayjs'
|
||||
import { mapMutations } from 'vuex'
|
||||
export default {
|
||||
name: 'error_logger_page',
|
||||
data () {
|
||||
return {
|
||||
columns: [
|
||||
{
|
||||
type: 'index',
|
||||
title: '序号',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
key: 'type',
|
||||
title: '类型',
|
||||
width: 100,
|
||||
render: (h, { row }) => {
|
||||
return (
|
||||
<div>
|
||||
<icon size={16} type={row.type === 'ajax' ? 'md-link' : 'md-code-working'}></icon>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'code',
|
||||
title: '编码',
|
||||
render: (h, { row }) => {
|
||||
return (
|
||||
<span>{ row.code === 0 ? '-' : row.code }</span>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'mes',
|
||||
title: '信息'
|
||||
},
|
||||
{
|
||||
key: 'url',
|
||||
title: 'URL'
|
||||
},
|
||||
{
|
||||
key: 'time',
|
||||
title: '时间',
|
||||
render: (h, { row }) => {
|
||||
return (
|
||||
<span>{ dayjs(row.time).format('YYYY-MM-DD HH:mm:ss') }</span>
|
||||
)
|
||||
},
|
||||
sortable: true,
|
||||
sortType: 'desc'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
errorList () {
|
||||
return this.$store.state.app.errorList
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([
|
||||
'setHasReadErrorLoggerStatus'
|
||||
]),
|
||||
exportData () {
|
||||
this.$refs.table.exportCsv({
|
||||
filename: '错误日志.csv'
|
||||
})
|
||||
}
|
||||
},
|
||||
activated () {
|
||||
this.setHasReadErrorLoggerStatus()
|
||||
},
|
||||
mounted () {
|
||||
this.setHasReadErrorLoggerStatus()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
@ -52,36 +52,36 @@ export default {
|
|||
name: '运营商/网络服务',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {normal: {
|
||||
areaStyle: { normal: {
|
||||
color: '#2d8cf0'
|
||||
}},
|
||||
} },
|
||||
data: [120, 132, 101, 134, 90, 230, 210]
|
||||
},
|
||||
{
|
||||
name: '银行/证券',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {normal: {
|
||||
areaStyle: { normal: {
|
||||
color: '#10A6FF'
|
||||
}},
|
||||
} },
|
||||
data: [257, 358, 278, 234, 290, 330, 310]
|
||||
},
|
||||
{
|
||||
name: '游戏/视频',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {normal: {
|
||||
areaStyle: { normal: {
|
||||
color: '#0C17A6'
|
||||
}},
|
||||
} },
|
||||
data: [379, 268, 354, 269, 310, 478, 358]
|
||||
},
|
||||
{
|
||||
name: '餐饮/外卖',
|
||||
type: 'line',
|
||||
stack: '总量',
|
||||
areaStyle: {normal: {
|
||||
areaStyle: { normal: {
|
||||
color: '#4608A6'
|
||||
}},
|
||||
} },
|
||||
data: [320, 332, 301, 334, 390, 330, 320]
|
||||
},
|
||||
{
|
||||
|
|
@ -94,9 +94,9 @@ export default {
|
|||
position: 'top'
|
||||
}
|
||||
},
|
||||
areaStyle: {normal: {
|
||||
areaStyle: { normal: {
|
||||
color: '#398DBF'
|
||||
}},
|
||||
} },
|
||||
data: [820, 645, 546, 745, 872, 624, 258]
|
||||
}
|
||||
]
|
||||
|
|
@ -104,11 +104,11 @@ export default {
|
|||
this.$nextTick(() => {
|
||||
this.dom = echarts.init(this.$refs.dom)
|
||||
this.dom.setOption(option)
|
||||
on(window, 'resize', this.resize())
|
||||
on(window, 'resize', this.resize)
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
off(window, 'resize', this.resize())
|
||||
off(window, 'resize', this.resize)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||