Commit b40afef2 authored by 赵啸非's avatar 赵啸非

添加基础前端工程

parent 77bf29e3
......@@ -7,4 +7,8 @@ VUE_APP_USER_KEY=admin.user
VUE_APP_SETTING_KEY=admin.setting
VUE_APP_TBAS_KEY=admin.tabs
VUE_APP_TBAS_TITLES_KEY=admin.tabs.titles
VUE_APP_API_BASE_URL=http://api.iczer.com
\ No newline at end of file
# 顶层区域id
VUE_APP_topParent=四川省
#VUE_APP_API_BASE_URL=http://api.iczer.com
#门户
VUE_APP_API_portal_URL=http://192.168.0.98:11072
\ No newline at end of file
VUE_APP_API_BASE_URL=http://dev.iczer.com
#开发环境
NODE_ENV = "development"
VUE_APP_API_BASE_URL=http://192.168.0.98:11078/base
#VUE_APP_API_BASE_URL=http://192.168.0.98:11023
#VUE_APP_API_BASE_URL=http://192.168.0.217:17311
\ No newline at end of file
#生产环境
NODE_ENV = "production"
VUE_APP_API_BASE_URL=http://192.168.0.218:11078/base
#VUE_APP_API_BASE_URL=http://192.168.0.98:11071/base
\ No newline at end of file
#测试环境
NODE_ENV = "test"
VUE_APP_API_BASE_URL=http://192.168.0.98:11071/base
\ No newline at end of file
简体中文 | [English](./README.en-US.md)
<h1 align="center">Vue Antd Admin</h1>
<div align="center">
[Ant Design Pro](https://github.com/ant-design/ant-design-pro) 的 Vue 实现版本
开箱即用的中后台前端/设计解决方案
[![MIT](https://img.shields.io/github/license/iczer/vue-antd-admin)](https://github.com/iczer/vue-antd-admin/blob/master/LICENSE)
[![Dependence](https://img.shields.io/david/iczer/vue-antd-admin)](https://david-dm.org/iczer/vue-antd-admin)
[![DevDependencies](https://img.shields.io/david/dev/iczer/vue-antd-admin)](https://david-dm.org/iczer/vue-antd-admin?type=dev)
[![Release](https://img.shields.io/github/v/release/iczer/vue-antd-admin)](https://github.com/iczer/vue-antd-admin/releases/latest)
![image](./src/assets/img/preview.png)
多种主题模式可选:
![image](./src/assets/img/preview-nine.png)
</div>
- 预览地址:https://iczer.gitee.io/vue-antd-admin
- 使用文档:https://iczer.gitee.io/vue-antd-admin-docs
- 常见问题:https://iczer.gitee.io/vue-antd-admin-docs/start/faq.html
- 国内镜像:https://gitee.com/iczer/vue-antd-admin
## 浏览器支持
现代浏览器及 IE10
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --- | --- | --- | --- | --- |
| IE10, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 使用
### clone
### 政务服务4.0.1
```bash
$ git clone https://github.com/iczer/vue-antd-admin.git
1、4.0.1
1.1、效能监察系统2.0
1.1.1、窗口管理
1.1.2、设备管理
1.1.3、监察模型
1.1.4、实时视频
1.1.5、视频回放
1.1.6、监察记录
1.1.7、监察申诉
1.1.8、分析报表
1.1.9、平台设置
```
### yarn
```bash
......@@ -43,20 +24,5 @@ $ yarn serve
$ npm install
$ npm run serve
```
更多信息参考 [使用文档](https://iczer.gitee.io/vue-antd-admin-docs)
## 参与贡献
我们非常欢迎你的贡献,你可以通过以下方式和我们一起共建 :star2::
- 在你的公司或个人项目中使用 Vue Antd Admin。
- 通过 [Issue](https://github.com/iczer/vue-antd-admin/issues) 报告:bug:或进行咨询。
- 提交 [Pull Request](https://github.com/iczer/vue-antd-admin/pulls) 改进 Admin 的代码。
- 加入社群,与小伙伴们一同交流心得。QQ群:942083829、 812277510(已满)、610090280(已满)
## 打赏
如果该项目对您有所帮助,可以请作者喝一杯咖啡。
<p>
<img src="./src/assets/img/alipay.png" width="320px" style="display: inline-block;" />
<img src="./src/assets/img/wechatpay.png" width="320px" style="display: inline-block; margin-left: 24px;" />
</p>
......@@ -5,7 +5,8 @@
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build": "vue-cli-service build --mode production",
"test": "vue-cli-service build --mode text",
"lint": "vue-cli-service lint",
"predeploy": "yarn build",
"deploy": "gh-pages -d dist -b pages -r https://gitee.com/iczer/vue-antd-admin.git",
......@@ -18,17 +19,26 @@
"animate.css": "^4.1.0",
"ant-design-vue": "1.7.2",
"axios": "^0.19.2",
"china-division": "^2.5.0",
"clipboard": "^2.0.6",
"core-js": "^3.6.5",
"date-fns": "^2.14.0",
"echarts": "^5.2.2",
"enquire.js": "^2.1.6",
"file-saver": "^2.0.5",
"highlight.js": "^10.2.1",
"html2canvas": "^1.4.1",
"js-cookie": "^2.2.1",
"mockjs": "^1.1.0",
"moment": "^2.24.0",
"nprogress": "^0.2.0",
"v-viewer": "^1.6.4",
"viser-vue": "^2.4.8",
"vue": "^2.6.11",
"vue-i18n": "^8.18.2",
"vue-jsonp": "^2.0.0",
"vue-quill-editor": "^3.0.6",
"vue-resource": "^1.5.2",
"vue-router": "^3.3.4",
"vuedraggable": "^2.23.2",
"vuex": "^3.4.0"
......@@ -48,6 +58,7 @@
"eslint-plugin-vue": "^6.2.2",
"fast-deep-equal": "^3.1.3",
"gh-pages": "^3.1.0",
"js-export-excel": "^1.1.4",
"less-loader": "^6.1.1",
"style-resources-loader": "^1.3.2",
"vue-cli-plugin-style-resources-loader": "^0.1.4",
......@@ -68,7 +79,10 @@
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
"rules": {
"no-debugger": "off",
"no-console": "off"
}
},
"browserslist": [
"> 1%",
......
......@@ -5,11 +5,13 @@
<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><%= process.env.VUE_APP_NAME %></title>
<!-- <title><%= process.env.VUE_APP_NAME %></title> -->
<title>智慧政务一体化综合管理平台</title>
<!-- require cdn assets css -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
<% } %>
</head>
<body>
<noscript>
......
<template>
<a-config-provider :locale="locale" :get-popup-container="popContainer">
<router-view/>
<router-view />
</a-config-provider>
</template>
<script>
import {enquireScreen} from './utils/util'
import {mapState, mapMutations} from 'vuex'
import themeUtil from '@/utils/themeUtil';
import {getI18nKey} from '@/utils/routerUtil'
import { enquireScreen } from "./utils/util";
import { mapState, mapMutations } from "vuex";
import themeUtil from "@/utils/themeUtil";
// import { getI18nKey } from "@/utils/routerUtil";
export default {
name: 'App',
name: "App",
data() {
return {
locale: {}
}
locale: {},
};
},
created () {
this.setHtmlTitle()
this.setLanguage(this.lang)
enquireScreen(isMobile => this.setDevice(isMobile))
created() {
// this.setHtmlTitle();
this.setLanguage(this.lang);
enquireScreen((isMobile) => this.setDevice(isMobile));
},
mounted() {
this.setWeekModeTheme(this.weekMode)
this.setWeekModeTheme(this.weekMode);
},
watch: {
weekMode(val) {
this.setWeekModeTheme(val)
this.setWeekModeTheme(val);
},
lang(val) {
this.setLanguage(val)
this.setHtmlTitle()
this.setLanguage(val);
// this.setHtmlTitle()
},
$route() {
this.setHtmlTitle()
// $route() {
// this.setHtmlTitle()
// },
"theme.mode": function (val) {
let closeMessage = this.$message.loading(
`您选择了主题模式 ${val}, 正在切换...`
);
themeUtil.changeThemeColor(this.theme.color, val).then(closeMessage);
},
'theme.mode': function(val) {
let closeMessage = this.$message.loading(`您选择了主题模式 ${val}, 正在切换...`)
themeUtil.changeThemeColor(this.theme.color, val).then(closeMessage)
"theme.color": function (val) {
let closeMessage = this.$message.loading(
`您选择了主题色 ${val}, 正在切换...`
);
themeUtil.changeThemeColor(val, this.theme.mode).then(closeMessage);
},
'theme.color': function(val) {
let closeMessage = this.$message.loading(`您选择了主题色 ${val}, 正在切换...`)
themeUtil.changeThemeColor(val, this.theme.mode).then(closeMessage)
layout: function () {
window.dispatchEvent(new Event("resize"));
},
'layout': function() {
window.dispatchEvent(new Event('resize'))
}
},
computed: {
...mapState('setting', ['layout', 'theme', 'weekMode', 'lang'])
...mapState("setting", ["layout", "theme", "weekMode", "lang"]),
},
methods: {
...mapMutations('setting', ['setDevice']),
...mapMutations("setting", ["setDevice"]),
setWeekModeTheme(weekMode) {
if (weekMode) {
document.body.classList.add('week-mode')
document.body.classList.add("week-mode");
} else {
document.body.classList.remove('week-mode')
document.body.classList.remove("week-mode");
}
},
setLanguage(lang) {
this.$i18n.locale = lang
this.$i18n.locale = lang;
switch (lang) {
case 'CN':
this.locale = require('ant-design-vue/es/locale-provider/zh_CN').default
break
case 'HK':
this.locale = require('ant-design-vue/es/locale-provider/zh_TW').default
break
case 'US':
case "CN":
this.locale =
require("ant-design-vue/es/locale-provider/zh_CN").default;
break;
case "HK":
this.locale =
require("ant-design-vue/es/locale-provider/zh_TW").default;
break;
case "US":
default:
this.locale = require('ant-design-vue/es/locale-provider/en_US').default
break
this.locale =
require("ant-design-vue/es/locale-provider/en_US").default;
break;
}
},
setHtmlTitle() {
const route = this.$route
const key = route.path === '/' ? 'home.name' : getI18nKey(route.matched[route.matched.length - 1].path)
document.title = process.env.VUE_APP_NAME + ' | ' + this.$t(key)
},
// setHtmlTitle() {
// const route = this.$route
// const key = route.path === '/' ? 'home.name' : getI18nKey(route.matched[route.matched.length - 1].path)
// document.title = process.env.VUE_APP_NAME + ' | ' + this.$t(key)
// },
popContainer() {
return document.getElementById("popContainer")
}
}
}
return document.getElementById("popContainer");
},
},
};
</script>
<style lang="less" scoped>
#id{
}
</style>
/* 颜色 */
.primary{
color:#1890FF;
}
.delete{
color:#FF4D4F;
}
.green{
color:#1BBC9B;
}
.clofff{
color:#fff;
}
.bgdel{
background-color: #FF4D4F;
}
.bgpr{
background-color: #1890FF;
}
.bgg{
background-color:#1BBC9B;
}
/* 版心 */
.container{
width:1200px;
}
/* 弹性布局 */
.flex{
display: flex;
}
.flex1{
flex:1
}
.flexc{
flex-direction: column;
}
.flexwrap{
flex-wrap: wrap;
}
.jcc{
justify-content: center;
}
.jca{
justify-content: space-around;
}
.jcb{
justify-content: space-between;
}
.jce{
justify-content: space-evenly;
}
.aic{
align-items: center;
}
.aca{
align-content: space-around;
}
.acb{
align-content: space-between;
}
.ace{
align-content: space-evenly;
}
/* margin */
.m10{
margin:10px
}
.m15{
margin:15px;
}
.m20{
margin:20px;
}
.mt10{
margin-top:10px;
}
.mt15{
margin-top:15px;
}
.mt20{
margin-top:20px;
}
.ml10{
margin-left:10px;
}
.ml15{
margin-left:15px;
}
.ml20{
margin-left:20px;
}
.ml25{
margin-left:25px;
}
.mr10{
margin-right:10px;
}
.mr15{
margin-right:15px;
}
.mr20{
margin-right:20px;
}
.mr25{
margin-right:25px;
}
.mb10{
margin-bottom:10px;
}
.mb15{
margin-bottom:15px;
}
.mb20{
margin-bottom:20px;
}
.mb25{
margin-bottom:25px;
}
/* padding */
.pd10{
padding:10px;
}
.pd15{
padding:15px;
}
.pd20{
padding:20px;
}
.pdt10{
padding-top:10px;
}
.pdt15{
padding-top:15px;
}
.pdt20{
padding-top:20px;
}
.pdt30{
padding-top:30px;
}
.pdl10{
padding-left:10px;
}
.pdl15{
padding-left:15px;
}
.pdl20{
padding-left:20px;
}
.pdr10{
padding-right:10px;
}
.pdr15{
padding-right:15px;
}
.pdr20{
padding-right:20px;
}
.pdb10{
padding-bottom:10px;
}
.pdb15{
padding-bottom:15px;
}
.pdb20{
padding-bottom:20px;
}
/* 字体大小 */
.font16{
font-size:16px;
}
.font18{
font-size:18px;
}
.font20{
font-size:20px;
}
.font22{
font-size:22px;
}
.font24{
font-size:24px;
}
.font26{
font-size:26px;
}
.font28{
font-size:28px;
}
.font30{
font-size:30px;
}
/* 字体位置 */
.tac{
text-align: center;
}
.tal{
text-align: left;
}
.tar{
text-align: right;
}
/* 加粗 */
.fontw600{
font-weight:600;
}
.fontw700{
font-weight:700;
}
.fontw800{
font-weight:800;
}
\ No newline at end of file
@import './common.less';
@import '../../theme/default/color.less';
// 字体大小
@fz18: 18px;
@fz16: 16px;
@fz14: 14px;
@fz26: 26px;
// 字体颜色
@clfff: #fff;
@cl999: #999;
@cl000: #000;//表头
@cl333: #333;//表体
@cl8B: #8B96A6;
@dlecl: #FA4D4C;//表格删除
@redact: #1890FF;//表格编辑
// 按钮背景色
@addbg: linear-gradient(90deg, #5ab6ff 0%, #2e9aff 100%);//新增
@delbg: #FA4D4C;//删除
@qubg: #E1F0FE;//取消 重置
// 分页显示位置
.pagination{
text-align: right;
}
/* 溢出表格滚动条 */
/* 表格 */
/*.table 为全局表格自定义样式*/
// .ant-table-body,
// .ant-table-header {
// overflow-y: auto !important;
// }
.ant-table-fixed-header .ant-table-scroll .ant-table-header {
overflow: hidden!important;
margin-bottom: 0!important;
padding-right: 5px;
}
::-webkit-scrollbar {
width: 5px;
overflow-y: auto;
}
::-webkit-scrollbar-thumb {
border-radius: 5px;
background-color: rgba(144, 147, 153, .5);
}
::-webkit-scrollbar-track {
border-radius: 5px;
background: #fff;
}
.ant-modal {
box-shadow: none !important;
}
.ant-form-item {
margin-bottom: 0;
display: flex;
align-items: center;
}
.ant-form-item-children {
display: flex;
align-items: center;
}
.ant-form-item-children input,
.ant-form-item-children textarea {
font-size: 14px;
font-weight: 400;
color: #999;
}
.ant-form-item-label label {
font-size: 14px;
font-weight: 400;
color: #8B96A6;
}
.ant-modal {
box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.1);
}
.ant-modal-title {
color: #1890FF !important;
font-size: 18px;
font-weight: bold;
}
.ant-modal-close {
color: #188fff !important;
}
.ant-modal-close svg {
font-size: 26px !important;
}
.ant-vue-dark .ant-table-thead .ant-table-column-title {
font-size: 16px;
font-weight: 500;
color: #000;
}
.ant-vue-dark .ant-table-tbody {
font-size: 14px;
font-weight: 400;
color: #333;
}
.ant-vue-light .ant-table-thead .ant-table-column-title {
font-size: 16px;
font-weight: 500;
color: #000;
}
.ant-vue-light .ant-table-tbody {
font-size: 14px;
font-weight: 400;
color: #333;
}
.del {
color: #FA4D4C;
padding: 0 4px;
display: inline-block;
}
.del:hover {
color: #FA4D4C;
cursor: pointer;
}
.redact {
color: #1890FF;
padding: 0 4px;
display: inline-block;
}
.redact:hover {
color: #1890FF;
cursor: pointer;
}
.search input {
font-size: 14px;
color: #BFBFBF;
}
.search .chaxun {
color: #fff;
border: 1px solid #5ab6ff;
padding: 0 14px;
background: linear-gradient(90deg, #5ab6ff 0%, #2e9aff 100%);
}
.btn {
margin-top: 20px;
}
.btnclass {
font-size: 14px;
border-radius: 4px;
border: none;
margin-right: 12px;
}
.delclass {
background: #FA4D4C !important;
color: #fff !important;
}
.addclass {
background: linear-gradient(90deg, #5ab6ff 0%, #2e9aff 100%) !important;
color: #fff !important;
}
.quclass {
background: #E1F0FE !important;
color: #42A5FA !important;
border: 1px solid #E1F0FE;
}
/**
* 上传图片、文件父级添加class
* 文字和控件将向上对齐
*/
.up_load_file .ant-form-item {
align-items: flex-start;
}
.up_load_file .ant-form-item-label {
position: relative;
top: -4px;
}
.up_load_pic .ant-form-item {
align-items: flex-start;
}
.up_load_pic .ant-upload-list {
float: left;
}
th {
text-align: center !important;
}
td {
text-align: center;
}
.btn_box {
display: flex;
align-items: center;
justify-content: center;
}
.search_block {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
}
.card_title {
font-size: 16px;
font-weight: 600;
color: #464646;
padding-left: 10px;
position: relative;
margin-bottom: 15px;
}
.card_title::before {
content: '';
position: absolute;
background: #1890ff;
border-color: #1890FF;
border-style: solid;
border-width: 2px;
height: 15px;
top: 4px;
left: 0;
}
.ant-tabs-nav-wrap {
background: #fff;
}
.ant-tabs-bar {
background: #fff;
padding-right: 20px !important;
}
.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab {
border-left: none !important;
border-top: none !important;
border-right: none !important;
border-bottom: none !important;
color: #999 !important;
}
.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab-active {
border-left: none !important;
border-top: none !important;
border-right: none !important;
}
.tabs-view-content {
background: #fff;
margin: 0 24px;
padding: 20px 24px;
min-height: 80vh;
}
.admin-layout .admin-layout-content {
padding: 20px 0 0 !important;
background: #F0F2F5;
}
.ant-pagination-item-active {
background: #1890FF;
border-radius: 4px;
}
.ant-pagination-item-active a {
color: #fff;
}
@import './common.less';
.ant-modal{
box-shadow: none !important;
}
// 表单
.ant-form-item {
margin-bottom: 15px;
// display: flex;
// align-items: center;
}
.ant-form-item-with-help{
margin-bottom: 0;
}
.ant-form-explain, .ant-form-extra{
margin-bottom: -5px;
}
.ant-form-item-children {
display: flex;
align-items: center;
input,
textarea {
font-size: @fz14;
font-weight: 400;
color: @cl999;
}
}
.ant-form-item-label {
label {
font-size: @fz14;
font-weight: 400;
color: @cl8B ;
}
}
// 弹框
.ant-modal {
box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.1);
}
.ant-modal-title {
color: #1890FF !important;
font-size: @fz18;
font-weight: bold;
}
.ant-modal-close {
color: #188fff !important;
svg {
font-size: @fz26 !important;
}
}
// 深色风格表格样式
.ant-vue-dark{
// 表头
.ant-table-thead {
.ant-table-column-title {
font-size: @fz16;
font-weight: 500;
color: @cl000;
}
}
// 表格内容
.ant-table-tbody {
font-size: @fz14;
font-weight: 400;
color: @cl333;
}
}
// 浅色风格表格样式
.ant-vue-light{
// 表头
.ant-table-thead {
.ant-table-column-title {
font-size: @fz16;
font-weight: 500;
color: @cl000;
}
}
// 表格内容
.ant-table-tbody {
font-size: @fz14;
font-weight: 400;
color: @cl333;
}
}
// 表格删除
.del {
color: @dlecl;
padding: 0 4px;
display: inline-block;
}
.del:hover {
color: @dlecl;
cursor: pointer;
}
// 表格编辑
.redact {
color: @redact;
padding: 0 4px;
display: inline-block;
}
.redact:hover {
color: @redact;
cursor: pointer;
}
// 带按钮搜索框
.search {
input {
font-size: @fz14;
color: #BFBFBF;
}
.chaxun {
color: @clfff;
border: 1px solid #5ab6ff;
padding: 0 14px;
background: @addbg;
}
}
// 按钮
.btn {
// display: flex;
margin-top: 20px;
}
.btnclass {
font-size: @fz14;
border-radius: 4px;
border: none;
margin-right: 12px;
}
// 删除按钮
.delclass {
background: @delbg !important;
color: #fff !important;
}
//新增按钮
.addclass {
background: @addbg !important;
color: #fff !important;
}
// 取消重置
.quclass {
background: @qubg !important;
color: #42A5FA !important;
border: 1px solid @qubg;
}
/**
* 上传图片、文件父级添加class
* 文字和控件将向上对齐
*/
.up_load_file {
.ant-form-item{
align-items: flex-start;
}
.ant-form-item-label{
position: relative;
top: -4px;
}
}
.up_load_pic {
.ant-form-item{
align-items: flex-start;
}
.ant-upload-list{
float: left;
}
}
th{
text-align: center !important;
}
td{
text-align: center;
}
.btn_box{
display: flex;
align-items: center;
justify-content: center;
}
.search_block{
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
}
.card_title{
font-size: 16px;
font-weight: 600;
color: #464646;
padding-left: 10px;
position: relative;
margin-bottom: 15px;
}
.card_title::before{
content: '';
position: absolute;
background: #1890ff;
border-color: #1890FF;
border-style: solid;
border-width: 2px;
height: 15px;
top: 4px;
left: 0;
}
// 面包屑
.ant-tabs-nav-wrap{
background: #fff;
}
.ant-tabs-bar{
background: #fff;
padding-right: 20px !important;
}
.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab{
border-left: none !important;
border-top: none !important;
border-right: none !important;
border-bottom: none !important;
color: #999 !important;
}
.ant-tabs.ant-tabs-card .ant-tabs-card-bar .ant-tabs-tab-active{
border-left: none !important;
border-top: none !important;
border-right: none !important;
}
// 内容
.tabs-view-content{
// background: #fff;
// margin: 0 24px;
// padding: 20px 24px;
min-height: 80vh;
}
.admin-layout .admin-layout-content{
padding: 0 !important;
background: #F0F2F5;
}
.ant-pagination-item-active{
background: #1890FF;
border-radius: 4px;
}
.ant-pagination-item-active a{
color: #fff
}
// 设备管理卡片
.device-item{
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 6px;
min-height: 200px;
position: relative;
background-color: #fafafa;
.device-item-icon{
position: absolute;
left: 0;
top: 0;
width: 40%;
height: 100%;
background-color: #fff;
padding:0 10px;
box-sizing: border-box;
img{
display: block;
width: 100%;
// height: 100%;
}
}
.device-item-body{
margin-left: 40%;
padding:10px;
position: relative;
h4{
font-weight: bold;
}
p{
font-size: 12px;
margin-bottom: 5px;
display: flex;
}
.p-label{
text-align: right;
width: 80px;
}
.p-value{
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.more{
position: absolute;
top: 8px;
right: 2px;
}
}
}
.device-item-add{
cursor: pointer;
}
.device-item-add>div{
text-align: center;
font-size: 16px;
}
.text-row{
display: flex;
& + .text-row{
margin-top: 5px;
}
.lable{
text-align: left;
}
.val{
flex: 1;
color: #000;
text-align: right;
}
}
// 导航菜单颜色
.admin-header.head{
background: #2681e8 !important;
.ant-menu-dark{
background: #2681e8 !important;
}
.ant-menu-submenu-selected{
color: #fff !important;
}
}
.viewbox{
margin:20px 20px 0 20px;
}
\ No newline at end of file
@import './common.less';
.b{
border: 1px solid red;
box-sizing: border-box;
}
//主轴水平
.flex_row{
display: -webkit-box; /* 老版本语法: Safari, iOS, Android browser, older WebKit browsers. */
display: -moz-box; /* 老版本语法: Firefox (buggy) */
display: -ms-flexbox; /* 混合版本语法: IE 10 */
display: -webkit-flex; /* 新版本语法: Chrome 21+ */
display: flex;
flex-direction:row;
}
//主轴横向
.flex_col{
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
flex-direction:column;
}
.flex_wrap {
flex-wrap: wrap;
}
.flex_align_s {
align-items: flex-start;
}
.flex_align_e {
align-items: flex-end;
}
.flex_align_c {
align-items: center;
}
.flex_justify_s {
justify-content: flex-start;
}
.flex_justify_c {
justify-content: center;
}
.flex_-justify_e {
justify-content: flex-end;
}
.flex_justify_b {
justify-content: space-between;
}
.flex_justify_a {
justify-content: space-around;
}
.mt{
margin-top: 20px;
}
.mb{
margin-bottom: 20px;
}
.mr{
margin-right: 20px;
}
.ml{
margin-left: 20px;
}
.ff{
background-color: #fff;
}
.br{
border-radius: 8px;
}
.b-b{
border-bottom: 1px solid @gray-5;
}
.primary-color{
color:@primary-color
}
.danger-color{
color:@error-color
}
.form-title{
color:@primary-color;
font-size: 14px;
padding-left: 10px;
position: relative;
&::after{
content: "";
display: block;
border-left: 3px solid @primary-color;
left: 0;
top: 0;
bottom: 0;
position: absolute;
}
}
.p-t-15{
padding-top: 15px;
}
.p-l-15{
padding-left: 15px;
}
.p-r-15{
padding-right: 15px;
}
.p-b-15{
padding-bottom: 15px;
}
.p15{
padding:15px
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="42px" height="34px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -141 -574 )">
<path d="M 12.3529411764706 24.4754464285714 L 12.3529411764706 30.9642857142857 L 19.7647058823529 27.3214285714286 L 19.7647058823529 21.3638392857143 L 12.3529411764706 24.4754464285714 Z M 3.31985294117647 19.0680803571429 L 11.1176470588235 22.3504464285714 L 18.9154411764706 19.0680803571429 L 11.1176470588235 15.7857142857143 L 3.31985294117647 19.0680803571429 Z M 32.1176470588235 24.4754464285714 L 32.1176470588235 30.9642857142857 L 39.5294117647059 27.3214285714286 L 39.5294117647059 21.3638392857143 L 32.1176470588235 24.4754464285714 Z M 23.0845588235294 19.0680803571429 L 30.8823529411765 22.3504464285714 L 38.6801470588235 19.0680803571429 L 30.8823529411765 15.7857142857143 L 23.0845588235294 19.0680803571429 Z M 22.2352941176471 11.7254464285714 L 22.2352941176471 16.7912946428571 L 29.6470588235294 13.6607142857143 L 29.6470588235294 8.61383928571429 L 22.2352941176471 11.7254464285714 Z M 12.4880514705882 6.01450892857143 L 21 9.60044642857143 L 29.5119485294118 6.01450892857143 L 21 2.42857142857143 L 12.4880514705882 6.01450892857143 Z M 41.5946691176471 18.1004464285714 C 41.8648897058824 18.5052083333333 42 18.9479166666667 42 19.4285714285714 L 42 27.3214285714286 C 42 27.7767857142857 41.8777573529412 28.2005208333333 41.6332720588235 28.5926339285714 C 41.3887867647059 28.9847470238095 41.0542279411765 29.281994047619 40.6295955882353 29.484375 L 31.9825367647059 33.734375 C 31.6608455882353 33.9114583333333 31.2941176470588 34 30.8823529411765 34 C 30.4705882352941 34 30.1038602941176 33.9114583333333 29.7821691176471 33.734375 L 21.1351102941176 29.484375 C 21.0836397058824 29.4590773809524 21.0386029411765 29.4337797619048 21 29.4084821428571 C 20.9742647058824 29.4337797619048 20.9292279411765 29.4590773809524 20.8648897058824 29.484375 L 12.2178308823529 33.734375 C 11.8961397058824 33.9114583333333 11.5294117647059 34 11.1176470588235 34 C 10.7058823529412 34 10.3391544117647 33.9114583333333 10.0174632352941 33.734375 L 1.37040441176471 29.484375 C 0.945772058823529 29.281994047619 0.611213235294118 28.9847470238095 0.366727941176471 28.5926339285714 C 0.122242647058824 28.2005208333333 0 27.7767857142857 0 27.3214285714286 L 0 19.4285714285714 C 0 18.9479166666667 0.138327205882353 18.5052083333333 0.414981617647059 18.1004464285714 C 0.691636029411765 17.6956845238095 1.05514705882353 17.3921130952381 1.50551470588235 17.1897321428571 L 9.88235294117647 13.6607142857143 L 9.88235294117647 6.07142857142857 C 9.88235294117647 5.59077380952381 10.0206801470588 5.14806547619048 10.2973345588235 4.74330357142857 C 10.5739889705882 4.33854166666667 10.9375 4.03497023809523 11.3878676470588 3.83258928571429 L 20.0349264705882 0.189732142857141 C 20.3308823529412 0.0632440476190521 20.6525735294118 0 21 0 C 21.3474264705882 0 21.6691176470588 0.0632440476190521 21.9650735294118 0.189732142857141 L 30.6121323529412 3.83258928571429 C 31.0625 4.03497023809523 31.4260110294118 4.33854166666667 31.7026654411765 4.74330357142857 C 31.9793198529412 5.14806547619048 32.1176470588235 5.59077380952381 32.1176470588235 6.07142857142857 L 32.1176470588235 13.6607142857143 L 40.4944852941176 17.1897321428571 C 40.9577205882353 17.3921130952381 41.3244485294118 17.6956845238095 41.5946691176471 18.1004464285714 Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 141 574 )" />
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="38px" height="36px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -555 -573 )">
<path d="M 10.1333333333333 12.8571428571429 C 10.1333333333333 14.71875 10.6677083333333 16.4330357142857 11.7364583333333 18 C 9.59895833333333 18.0669642857143 7.85069444444444 18.9241071428571 6.49166666666667 20.5714285714286 L 3.83958333333333 20.5714285714286 C 2.75763888888889 20.5714285714286 1.84722222222222 20.3002232142857 1.10833333333333 19.7578125 C 0.369444444444444 19.2154017857143 0 18.421875 0 17.3772321428571 C 0 12.6495535714286 0.818055555555555 10.2857142857143 2.45416666666667 10.2857142857143 C 2.53333333333333 10.2857142857143 2.8203125 10.4263392857143 3.31510416666667 10.7075892857143 C 3.80989583333333 10.9888392857143 4.453125 11.2734375 5.24479166666667 11.5613839285714 C 6.03645833333333 11.8493303571429 6.82152777777778 11.9933035714286 7.6 11.9933035714286 C 8.48402777777778 11.9933035714286 9.36145833333333 11.8392857142857 10.2322916666667 11.53125 C 10.1663194444444 12.0267857142857 10.1333333333333 12.46875 10.1333333333333 12.8571428571429 Z M 32.8640625 28.7176339285714 C 32.9102430555556 29.3939732142857 32.9333333333333 30.0870535714286 32.9333333333333 30.796875 C 32.9333333333333 32.4040178571429 32.4517361111111 33.6729910714286 31.4885416666667 34.6037946428571 C 30.5253472222222 35.5345982142857 29.2454861111111 36 27.6489583333333 36 L 10.3510416666667 36 C 8.75451388888889 36 7.47465277777778 35.5345982142857 6.51145833333333 34.6037946428571 C 5.54826388888889 33.6729910714286 5.06666666666667 32.4040178571429 5.06666666666667 30.796875 C 5.06666666666667 30.0870535714286 5.08975694444444 29.3939732142857 5.1359375 28.7176339285714 C 5.18211805555556 28.0412946428571 5.27447916666667 27.3113839285714 5.41302083333333 26.5279017857143 C 5.5515625 25.7444196428571 5.72638888888889 25.0178571428571 5.9375 24.3482142857143 C 6.14861111111111 23.6785714285714 6.43229166666667 23.0256696428571 6.78854166666667 22.3895089285714 C 7.14479166666667 21.7533482142857 7.55381944444444 21.2109375 8.015625 20.7622767857143 C 8.47743055555556 20.3136160714286 9.04149305555556 19.9553571428571 9.7078125 19.6875 C 10.3741319444444 19.4196428571429 11.1097222222222 19.2857142857143 11.9145833333333 19.2857142857143 C 12.0465277777778 19.2857142857143 12.3302083333333 19.4296875 12.765625 19.7176339285714 C 13.2010416666667 20.0055803571429 13.6826388888889 20.3270089285714 14.2104166666667 20.6819196428571 C 14.7381944444444 21.0368303571429 15.4440972222222 21.3582589285714 16.328125 21.6462053571429 C 17.2121527777778 21.9341517857143 18.1027777777778 22.078125 19 22.078125 C 19.8972222222222 22.078125 20.7878472222222 21.9341517857143 21.671875 21.6462053571429 C 22.5559027777778 21.3582589285714 23.2618055555556 21.0368303571429 23.7895833333333 20.6819196428571 C 24.3173611111111 20.3270089285714 24.7989583333333 20.0055803571429 25.234375 19.7176339285714 C 25.6697916666667 19.4296875 25.9534722222222 19.2857142857143 26.0854166666667 19.2857142857143 C 26.8902777777778 19.2857142857143 27.6258680555556 19.4196428571429 28.2921875 19.6875 C 28.9585069444444 19.9553571428571 29.5225694444444 20.3136160714286 29.984375 20.7622767857143 C 30.4461805555556 21.2109375 30.8552083333333 21.7533482142857 31.2114583333333 22.3895089285714 C 31.5677083333333 23.0256696428571 31.8513888888889 23.6785714285714 32.0625 24.3482142857143 C 32.2736111111111 25.0178571428571 32.4484375 25.7444196428571 32.5869791666667 26.5279017857143 C 32.7255208333333 27.3113839285714 32.8178819444444 28.0412946428571 32.8640625 28.7176339285714 Z M 11.1822916666667 1.50669642857143 C 12.171875 2.51116071428571 12.6666666666667 3.72321428571428 12.6666666666667 5.14285714285714 C 12.6666666666667 6.5625 12.171875 7.77455357142857 11.1822916666667 8.77901785714286 C 10.1927083333333 9.78348214285714 8.99861111111111 10.2857142857143 7.6 10.2857142857143 C 6.20138888888889 10.2857142857143 5.00729166666667 9.78348214285714 4.01770833333333 8.77901785714286 C 3.028125 7.77455357142857 2.53333333333333 6.5625 2.53333333333333 5.14285714285714 C 2.53333333333333 3.72321428571428 3.028125 2.51116071428571 4.01770833333333 1.50669642857143 C 5.00729166666667 0.502232142857145 6.20138888888889 0 7.6 0 C 8.99861111111111 0 10.1927083333333 0.502232142857145 11.1822916666667 1.50669642857143 Z M 24.3734375 7.40290178571428 C 25.8578125 8.90959821428572 26.6 10.7276785714286 26.6 12.8571428571429 C 26.6 14.9866071428571 25.8578125 16.8046875 24.3734375 18.3113839285714 C 22.8890625 19.8180803571429 21.0979166666667 20.5714285714286 19 20.5714285714286 C 16.9020833333333 20.5714285714286 15.1109375 19.8180803571429 13.6265625 18.3113839285714 C 12.1421875 16.8046875 11.4 14.9866071428571 11.4 12.8571428571429 C 11.4 10.7276785714286 12.1421875 8.90959821428572 13.6265625 7.40290178571428 C 15.1109375 5.89620535714286 16.9020833333333 5.14285714285714 19 5.14285714285714 C 21.0979166666667 5.14285714285714 22.8890625 5.89620535714286 24.3734375 7.40290178571428 Z M 35.5458333333333 10.2857142857143 C 37.1819444444445 10.2857142857143 38 12.6495535714286 38 17.3772321428571 C 38 18.421875 37.6305555555556 19.2154017857143 36.8916666666667 19.7578125 C 36.1527777777778 20.3002232142857 35.2423611111111 20.5714285714286 34.1604166666667 20.5714285714286 L 31.5083333333333 20.5714285714286 C 30.1493055555556 18.9241071428571 28.4010416666667 18.0669642857143 26.2635416666667 18 C 27.3322916666667 16.4330357142857 27.8666666666667 14.71875 27.8666666666667 12.8571428571429 C 27.8666666666667 12.46875 27.8336805555556 12.0267857142857 27.7677083333333 11.53125 C 28.6385416666667 11.8392857142857 29.5159722222222 11.9933035714286 30.4 11.9933035714286 C 31.1784722222222 11.9933035714286 31.9635416666667 11.8493303571429 32.7552083333333 11.5613839285714 C 33.546875 11.2734375 34.1901041666667 10.9888392857143 34.6848958333333 10.7075892857143 C 35.1796875 10.4263392857143 35.4666666666667 10.2857142857143 35.5458333333333 10.2857142857143 Z M 33.9822916666667 1.50669642857143 C 34.971875 2.51116071428571 35.4666666666667 3.72321428571428 35.4666666666667 5.14285714285714 C 35.4666666666667 6.5625 34.971875 7.77455357142857 33.9822916666667 8.77901785714286 C 32.9927083333333 9.78348214285714 31.7986111111111 10.2857142857143 30.4 10.2857142857143 C 29.0013888888889 10.2857142857143 27.8072916666667 9.78348214285714 26.8177083333333 8.77901785714286 C 25.828125 7.77455357142857 25.3333333333333 6.5625 25.3333333333333 5.14285714285714 C 25.3333333333333 3.72321428571428 25.828125 2.51116071428571 26.8177083333333 1.50669642857143 C 27.8072916666667 0.502232142857145 29.0013888888889 0 30.4 0 C 31.7986111111111 0 32.9927083333333 0.502232142857145 33.9822916666667 1.50669642857143 Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 555 573 )" />
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="39px" height="34px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -1719 -574 )">
<path d="M 13.9285714285714 3 L 13.9285714285714 6 L 25.0714285714286 6 L 25.0714285714286 3 L 13.9285714285714 3 Z M 4.875 5.66666666666667 L 7 5.66666666666667 L 7 34 L 4.875 34 C 3.54017857142857 34 2.39397321428571 33.5130208333333 1.43638392857143 32.5390625 C 0.478794642857143 31.5651041666667 0 30.3993055555556 0 29.0416666666667 L 0 10.625 C 0 9.26736111111111 0.478794642857143 8.1015625 1.43638392857143 7.12760416666667 C 2.39397321428571 6.15364583333333 3.54017857142857 5.66666666666667 4.875 5.66666666666667 Z M 27.8571428571429 5.66666666666667 L 30 5.66666666666667 L 30 34 L 9 34 L 9 5.66666666666667 L 11.1428571428571 5.66666666666667 L 11.1428571428571 2.125 C 11.1428571428571 1.53472222222222 11.3459821428571 1.03298611111111 11.7522321428571 0.619791666666665 C 12.1584821428571 0.206597222222221 12.6517857142857 0 13.2321428571429 0 L 25.7678571428571 0 C 26.3482142857143 0 26.8415178571429 0.206597222222221 27.2477678571429 0.619791666666665 C 27.6540178571429 1.03298611111111 27.8571428571429 1.53472222222222 27.8571428571429 2.125 L 27.8571428571429 5.66666666666667 Z M 37.5636160714286 7.12760416666667 C 38.5212053571429 8.1015625 39 9.26736111111111 39 10.625 L 39 29.0416666666667 C 39 30.3993055555556 38.5212053571429 31.5651041666667 37.5636160714286 32.5390625 C 36.6060267857143 33.5130208333333 35.4598214285714 34 34.125 34 L 32 34 L 32 5.66666666666667 L 34.125 5.66666666666667 C 35.4598214285714 5.66666666666667 36.6060267857143 6.15364583333333 37.5636160714286 7.12760416666667 Z " fill-rule="nonzero" fill="#ffffff" stroke="none" transform="matrix(1 0 0 1 1719 574 )" />
</g>
</svg>
\ No newline at end of file
<template>
<quill-editor
class="editor"
ref="myTextEditor"
v-model="content"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@ready="onEditorReady($event)"
@change="onEditorChange($event)"
>
</quill-editor>
</template>
<script>
export default {
data() {
return {
content: null,
editorOption: {
modules: {
toolbar: [
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
["blockquote", "code-block"], // 引用 代码块
[{ header: 1 }, { header: 2 }], // 1、2 级标题
[{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
[{ script: "sub" }, { script: "super" }], // 上标/下标
[{ indent: "-1" }, { indent: "+1" }], // 缩进
// [{'direction': 'rtl'}], // 文本方向
[{ size: ["small", false, "large", "huge"] }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
[{ font: [] }], // 字体种类
[{ align: [] }], // 对齐方式
["clean"], // 清除文本格式
["link", "image", "video"], // 链接、图片、视频
], //工具菜单栏配置
},
placeholder: "请在这里添加产品描述", //提示
readyOnly: false, //是否只读
theme: "snow", //主题 snow/bubble
syntax: true, //语法检测
},
};
},
methods: {
// 失去焦点
onEditorBlur(editor) {
console.log(editor);
},
// 获得焦点
onEditorFocus(editor) {
console.log(editor);
},
// 开始
onEditorReady(editor) {
console.log(editor);
},
// 值发生变化
onEditorChange(editor) {
this.content = editor.html;
console.log(editor);
},
},
computed: {
editor() {
return this.$refs.myTextEditor.quillEditor;
},
},
mounted() {
// console.log('this is my editor',this.editor);
},
};
</script>
<style>
.editor {
line-height: normal !important;
height: 100%;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {
content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: "保存";
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode="video"]::before {
content: "请输入视频地址:";
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
content: "32px";
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: "标题4";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: "标题5";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6";
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
content: "等宽字体";
}
</style>
\ No newline at end of file
<template>
<div>
<!-- 删除弹出框 -->
<a-modal
class="modal"
v-model="visible"
@cancel="handleCancel"
:footer="null"
title="系统提示"
>
<a-icon
type="close-circle"
slot="closeIcon"
theme="filled"
/>
<div class="t_center">
<div>此操作将删除该{{message}}信息,是否继续?</div>
<a-button class="addclass btnclass" @click="handleClick(delkey)"> 确认 </a-button>
<a-button class="quclass btnclass btn" @click="handleCancel"> 取消 </a-button>
</div>
</a-modal>
</div>
</template>
<script>
export default {
props: {
// 提示信息
message: {
type: String,
default: ''
},
// 要删除的表格KEY
delkey: {
type: [String, Number],
default: ''
}
},
data () {
return {
visible: false
}
},
methods: {
show(){
this.visible = true
},
// 确定
handleClick (val) {
this.$emit('delList', val)
this.visible = false
},
// 取消
handleCancel () {
this.$message.error('取消删除')
this.visible = false
}
}
}
</script>
<style scoped lang="less">
.t_center{
text-align: center;
}
</style>
<template>
<div></div>
</template>
<script>
export default {
props:{
option:Object //配置参数
},
data(){
return{
myChart:null
}
},
watch:{
option:function(v){
this.myChart.setOption(v)
}
},
mounted(){
this.myChart = this.$echarts.init(this.$el);
const option = {
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: []
},
yAxis: {
type: 'value'
},
series: [
{
data: [],
type: 'bar',
barWidth: '50%',
}
]
};
this.myChart.setOption(option)
window.onresize = () => {
this.myChart.resize();
};
}
}
</script>
\ No newline at end of file
<template>
<div></div>
</template>
<script>
export default {
props:{
option:Object //配置参数
},
data(){
return{
myChart:null
}
},
watch:{
option:function(v){
this.myChart.setOption(v)
}
},
mounted(){
this.myChart = this.$echarts.init(this.$el);
const option = {
tooltip: {
show:false,
},
legend: {},
grid: {
left: '0%',
top: '3%',
right: '5%',
bottom: '3%',
// containLabel: true
},
xAxis: {
type: 'value',
show:false,
},
yAxis:{
show:false,
type: 'category',
axisLine: {
show: false
},
axisTick: {
show: false
},
data: []
},
series: [
{
type: 'bar',
showBackground: true,
barWidth: '10px',
z: 3,
itemStyle:{
normal:{
barBorderRadius: 10,
color: new this.$echarts.graphic.LinearGradient(0, 0, 1, 1, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' }
])
},
},
label: {
normal: {
color: '#2681e8',
show: true,
position: 'right',
textStyle: {
fontSize: 14
},
}
},
data: []
},
{
barGap: '-100%',
type: 'bar',
barWidth: '10px',
z: 2,
itemStyle:{
normal:{
barBorderRadius: 10
}
},
label: {
normal: {
color: '#2681e8',
show: true,
position: [0, '-24px'],
textStyle: {
fontSize: 14
},
formatter: function (a) {
return a.name
}
}
},
data: []
}
]
};
this.myChart.setOption(option)
window.onresize = () => {
this.myChart.resize();
};
}
}
</script>
\ No newline at end of file
<template>
<div></div>
</template>
<script>
export default {
props:{
option:Object //配置参数
},
data(){
return{
myChart:null
}
},
watch:{
option:function(v){
this.myChart.setOption(v)
}
},
mounted(){
this.myChart = this.$echarts.init(this.$el);
const option = {
grid: {
left: 10,
containLabel: true,
bottom: 10,
top: 10,
right: 30
},
series: [
{
type: 'gauge',
startAngle: 180,
endAngle: 0,
min: 0,
max: 1,
splitNumber: 8,
axisLine: {
lineStyle: {
width: 6,
color: [
[0.25, '#FF6E76'],
[0.5, '#FDDD60'],
[0.75, '#58D9F9'],
[1, '#7CFFB2']
]
}
},
pointer: {
icon: 'path://M12.8,0.7l12,40.1H0.7L12.8,0.7z',
length: '12%',
width: 10,
offsetCenter: [0, '-60%'],
itemStyle: {
color: 'auto'
}
},
axisTick: {
length: 12,
lineStyle: {
color: 'auto',
width: 2
}
},
splitLine: {
length: 20,
lineStyle: {
color: 'auto',
width: 5
}
},
axisLabel: {
color: '#464646',
fontSize: 14,
distance: -60,
formatter: function (value) {
if (value === 0.875) {
return '优秀';
} else if (value === 0.625) {
return '良好';
} else if (value === 0.375) {
return '一般';
} else if (value === 0.125) {
return '极低';
}
return '';
}
},
title: {
offsetCenter: [0, '-20%'],
fontSize: 16
},
detail: {
fontSize: 20,
offsetCenter: [0, '0%'],
valueAnimation: true,
formatter: function (value) {
return Math.round(value * 100) + '';
},
color: 'auto'
},
data: [
{
value: 0.7,
name: '综合正确率'
}
]
}
]
};
this.myChart.setOption(option)
window.onresize = () => {
this.myChart.resize();
};
}
}
</script>
\ No newline at end of file
<template>
<div></div>
</template>
<script>
export default {
props:{
option:Object //配置参数
},
data(){
return{
myChart:null
}
},
watch:{
option:function(v){
this.myChart.setOption(v)
}
},
mounted(){
this.myChart = this.$echarts.init(this.$el);
const option = {
series: [
{
type: 'gauge',
startAngle: 360,
endAngle: 0,
min: 0,
max: 1,
splitNumber: 12,
pointer: {
show:false
},
axisTick:{
show:false
},
splitLine:{
show:false
},
axisLabel:{
show:false
},
itemStyle: {
color: '#2681e8',
shadowColor: 'rgba(0,138,255,0.45)',
shadowBlur: 10,
shadowOffsetX: 2,
shadowOffsetY: 2
},
progress: {
show: true,
roundCap: true,
width: 5
},
axisLine: {
roundCap: false,
lineStyle: {
width: 5
}
},
title: {
offsetCenter: [0, '-20%'],
fontSize: 12
},
detail: {
fontSize: 12,
offsetCenter: [0, '20%'],
valueAnimation: true,
formatter: function (value) {
return Math.round(value * 100) + '%';
},
color: 'auto'
},
data: [
{
value: 0.9,
name: '正确率'
}
]
}]
};
this.myChart.setOption(option)
window.onresize = () => {
this.myChart.resize();
};
}
}
</script>
\ No newline at end of file
import gauge from "./gauge"
import gaugePie from "./gaugePie"
import pieCalendar from "./pieCalendar"
import bar from "./bar"
import barloading from "./barloading"
export{
gauge,
gaugePie,
pieCalendar,
bar,
barloading
}
\ No newline at end of file
<template>
<div></div>
</template>
<script>
import moment from "moment"
export default {
props:{
option:Object, //配置参数
moments:String,//月份
info:Array//数据
},
data(){
return{
myChart:null,
nowMoment:moment().format('YYYY-MM'), //当前月份
nextMoment:moment().startOf('month').subtract('month', -1).format('YYYY-MM')//下个月
}
},
watch:{
info:function(v){
const echarts = this.$echarts
let scatterData = this.getVirtulData()
const cellSize = ['auto', 50];
setTimeout(()=>{
const option = {
tooltip: {},
legend: {
data: ['Work', 'Entertainment', 'Sleep'],
bottom: 20
},
calendar: {
top: 'middle',
left: 'center',
orient: 'vertical',
cellSize: cellSize,
yearLabel: {
show: false,
fontSize: 30
},
dayLabel: {
margin: 20,
firstDay: 1,
nameMap: ['周天', '周一', '周二', '周三', '周四', '周五', '周六', '周天']
},
monthLabel: {
show: false
},
range: [this.nowMoment]
},
series: [
{
id: 'label',
type: 'scatter',
coordinateSystem: 'calendar',
symbolSize: 1,
label: {
show: true,
formatter: function (params) {
return echarts.format.formatTime('dd', params.value[0]);
},
offset: [-cellSize[0] / 2 + 10, -cellSize[1] / 2 + 10],
fontSize: 12
},
data: scatterData
}
]
};
this.myChart.setOption(option,true);
})
setTimeout(()=>{
this.myChart.setOption({
series: this.getPieSeries(scatterData,this.myChart,v)
});
},10)
},
moments:function(v){
if(v){
this.nowMoment = v
this.nextMoment = moment(v).month(moment(v).month()+1).format('YYYY-MM')
}
}
},
mounted(){
this.myChart = this.$echarts.init(this.$el);
const echarts = this.$echarts
const cellSize = ['auto', 50];
let scatterData = this.getVirtulData()
const option = {
tooltip: {},
legend: {
data: ['Work', 'Entertainment', 'Sleep'],
bottom: 20
},
calendar: {
top: 'middle',
left: 'center',
orient: 'vertical',
cellSize: cellSize,
yearLabel: {
show: false,
fontSize: 30
},
dayLabel: {
margin: 20,
firstDay: 1,
nameMap: ['周天', '周一', '周二', '周三', '周四', '周五', '周六', '周天']
},
monthLabel: {
show: false
},
range: [this.nowMoment]
},
series: [
{
id: 'label',
type: 'scatter',
coordinateSystem: 'calendar',
symbolSize: 1,
label: {
show: true,
formatter: function (params) {
return echarts.format.formatTime('dd', params.value[0]);
},
offset: [-cellSize[0] / 2 + 10, -cellSize[1] / 2 + 10],
fontSize: 12
},
data: scatterData
}
]
};
this.myChart.setOption(option)
window.onresize = () => {
this.myChart.resize();
};
},
methods:{
getVirtulData(){
const echarts = this.$echarts
let date = +echarts.number.parseDate(`${this.nowMoment}-01`);
let end = +echarts.number.parseDate(`${this.nextMoment}-01`);
let dayTime = 3600 * 24 * 1000;
let data = [];
for (let time = date; time < end; time += dayTime) {
data.push([
echarts.format.formatTime('yyyy-MM-dd', time),
Math.floor(Math.random() * 10000)
]);
}
return data;
},
getPieSeries(scatterData,chart,v) {
return scatterData.map(function (item, index) {
let warn = v.map(val=>{
let arr = val.warn.map(em=>{
return {name:em.label,value:em.count}
})
return {day:val.day,val:arr}
})
let valArr = warn.find(it=>it.day == item[0])
var center = chart.convertToPixel('calendar', item);
return {
id: index + 'pie',
type: 'pie',
center: center,
label: {
formatter: '{c}',
position: 'inside'
},
radius: 25,
data: valArr.val
};
});
}
}
}
</script>
\ No newline at end of file
<template>
<span @click="getmodelfile">
<slot>
<div>空模板</div>
</slot>
</span>
</template>
<script>
import {modelfile} from "@/services/default"
export default {
props:['keyword'],
methods:{
getmodelfile(){
modelfile({keyword:this.keyword}).then(res=>{
const {code,data,msg} = res.data
if(code == 0){
window.open(data, '_blank')
}else{
this.$message.error(msg)
}
})
}
}
}
</script>
\ No newline at end of file
<template>
<span @click="onExportExcel">
<slot>
<div>{{title}}</div>
</slot>
</span>
</template>
<script>
import ExportJsonExcel from "js-export-excel"
import {request} from "@/utils/request"
export default {
props:{
columns:Array,//表头数据
dataSource:{
type:Array,
default:()=>[]
},//数据
all:{
type:Boolean,
default:true
},//是否导出全部
fileName:{
type:String,
default:'Excel'
},//文件名称
action:String//文件导出接口
},
data(){
return{
excelData:[]//导出数据
}
},
computed:{
title:function(){
return this.dataSource.length == 0?'导出全部':'导出选中'
}
},
methods:{
// 导出全部
async onExportAll(){
return request(this.action,'GET',{page:1,size:-1}).then(res=>{
const {code,data} = res.data
if(code == 0){
this.excelData = data.data?data.data:data
}
}).catch(error=>{
console.log(error)
this.$message.error(`接口请求错误:${error}`)
})
},
async onExportExcel(){
if(this.dataSource.length == 0){
await this.onExportAll()
}else{
this.excelData = this.dataSource
}
let sheetFilter = []
let sheetHeader = []
let columnWidths = []
this.columns.forEach(v=>{
if(v.dataIndex){
sheetFilter.push(v.dataIndex)
sheetHeader.push(v.title)
columnWidths.push(v.width?parseInt(v.width.replace(/px/,'')):10)
}
})
console.log(sheetFilter)
console.log(sheetHeader)
console.log(columnWidths)
let option = {
fileName:this.fileName,
datas:[
{
sheetData: this.excelData,
sheetName: "sheet",
sheetFilter: sheetFilter,
sheetHeader: sheetHeader,
columnWidths: columnWidths,
}
]
}
let toExcel = new ExportJsonExcel(option);
toExcel.saveExcel(); //保存
}
}
}
</script>
\ No newline at end of file
<template>
<a-upload
list-type="text"
class="file-uploader"
:show-upload-list="false"
:action="action"
:headers="headers"
@change="fileChange"
>
<slot>
<div>导入</div>
</slot>
</a-upload>
</template>
<script>
import {mapMutations} from "vuex"
import {getCookie} from "@/utils/request"
export default {
props:{
action:String
},
data(){
return{
headers:getCookie()
}
},
methods:{
...mapMutations('fileloading',['settip','setspinning']),
/**
* 导入文件监听
*/
fileChange(info){
if (info.file.status === 'uploading') {
this.settip('文件导入中...')
this.setspinning(true)
return;
}
if (info.file.status === 'error') {
this.$message.error("导入失败")
}
if (info.file.status === 'done') {
this.$message("导入成功")
// 导出成功
this.$emit("success",'addfile')
}
this.setspinning(false)
this.settip('加载中...')
}
}
}
</script>
<style lang="less" scoped>
</style>
\ No newline at end of file
<template>
<img :src="imgsrc">
</template>
<script>
export default {
props:['src'],
computed:{
imgsrc:function(){
return this.src?`${process.env.VUE_APP_API_BASE_URL}/${this.src}`:require('./thumb.jpg')
}
}
}
</script>
\ No newline at end of file
<template>
<div class="thumb" >
<img :src="images[index]" v-if="src" @click="show">
<img src="./thumb.jpg" v-else>
</div>
</template>
<script>
export default {
props:{
src:[String,Array],
index:{
type:Number,
default:0
}
},
data(){
return{
images:[]
}
},
watch:{
src:{
handler:function(v){
if(v){
if(typeof v == 'string'){
this.images = v.split(",").map(v=>{
return this.publicSrc(v)
})
}else{
this.images = v.map(v=>{
return this.publicSrc(v)
})
}
}
},
immediate:true
}
},
methods:{
publicSrc(src){
return `${process.env.VUE_APP_API_BASE_URL}/${src}`
},
show(){
this.$viewerApi({
images: this.images,
options: {
initialViewIndex: this.index
},
})
}
}
}
</script>
<style lang="less" scoped>
.thumb{
width: 50px;
height: 60px;
img{
display: inline-block;
width: 100%;
height: 100%;
}
}
</style>
\ No newline at end of file
This diff is collapsed.
......@@ -15,70 +15,71 @@
<script>
export default {
name: 'Contextmenu',
name: "Contextmenu",
props: {
visible: {
type: Boolean,
required: false,
default: false
default: false,
},
itemList: {
type: Array,
required: true,
default: () => []
}
default: () => [],
},
data () {
},
data() {
return {
left: 0,
top: 0,
target: null,
meta: null,
selectedKeys: []
}
selectedKeys: [],
};
},
computed: {
style () {
style() {
return {
left: this.left + 'px',
top: this.top + 'px'
}
}
left: this.left + "px",
top: this.top + "px",
};
},
},
created () {
window.addEventListener('click', this.closeMenu)
window.addEventListener('contextmenu', this.setPosition)
created() {
window.addEventListener("click", this.closeMenu);
window.addEventListener("contextmenu", this.setPosition);
},
beforeDestroy() {
window.removeEventListener('click', this.closeMenu)
window.removeEventListener('contextmenu', this.setPosition)
window.removeEventListener("click", this.closeMenu);
window.removeEventListener("contextmenu", this.setPosition);
},
methods: {
closeMenu () {
this.$emit('update:visible', false)
closeMenu() {
this.$emit("update:visible", false);
},
setPosition (e) {
this.left = e.clientX
this.top = e.clientY
this.target = e.target
this.meta = e.meta
setPosition(e) {
this.left = e.clientX;
this.top = e.clientY;
this.target = e.target;
this.meta = e.meta;
},
handleClick ({ key }) {
this.$emit('select', key, this.target, this.meta)
this.closeMenu()
}
}
}
handleClick({ key }) {
this.$emit("select", key, this.target, this.meta);
this.closeMenu();
},
},
};
</script>
<style lang="less" scoped>
.contextmenu{
.contextmenu {
position: fixed;
z-index: 1000;
border-radius: 4px;
box-shadow: -4px 4px 16px 1px @shadow-color !important;
}
.ant-menu-item {
}
.ant-menu-item {
margin: 0 !important // 菜单项之间的缝隙会影响点击
}
;
}
</style>
<template>
<a-layout-sider :theme="sideTheme" :class="['side-menu', 'beauty-scroll', isMobile ? null : 'shadow']" width="256px" :collapsible="collapsible" v-model="collapsed" :trigger="null">
<a-layout-sider
:theme="sideTheme"
:class="['side-menu', 'beauty-scroll', isMobile ? null : 'shadow']"
width="256px"
:collapsible="collapsible"
v-model="collapsed"
:trigger="null"
>
<div :class="['logo', theme]">
<router-link to="/dashboard/workplace">
<img src="@/assets/img/logo.png">
<h1>{{systemName}}</h1>
<img src="@/assets/img/logo.png" />
<h1>{{ systemName }}</h1>
</router-link>
</div>
<i-menu :theme="theme" :collapsed="collapsed" :options="menuData" @select="onSelect" class="menu"/>
<i-menu
:theme="theme"
:collapsed="collapsed"
:options="menuData"
@select="onSelect"
class="menu"
/>
</a-layout-sider>
</template>
<script>
import IMenu from './menu'
import {mapState} from 'vuex'
import IMenu from "./menu";
import { mapState } from "vuex";
export default {
name: 'SideMenu',
components: {IMenu},
name: "SideMenu",
components: { IMenu },
props: {
collapsible: {
type: Boolean,
required: false,
default: false
default: false,
},
collapsed: {
type: Boolean,
required: false,
default: false
default: false,
},
menuData: {
type: Array,
required: true
required: true,
},
theme: {
type: String,
required: false,
default: 'dark'
}
default: "dark",
},
},
computed: {
sideTheme() {
// return this.theme == 'light' ? this.theme : 'dark'
return this.theme
return this.theme;
},
...mapState('setting', ['isMobile', 'systemName'])
...mapState("setting", ["isMobile", "systemName"]),
},
methods: {
onSelect (obj) {
this.$emit('menuSelect', obj)
}
}
}
onSelect(obj) {
this.$emit("menuSelect", obj);
},
},
};
</script>
<style lang="less" scoped>
......
......@@ -235,7 +235,7 @@ export default {
let matches = this.$route.matched
const route = matches[matches.length - 1]
let chose = this.routesMap[route.path]
if (chose.meta && chose.meta.highlight) {
if (chose && chose.meta && chose.meta.highlight) {
chose = this.routesMap[chose.meta.highlight]
const resolve = this.$router.resolve({path: chose.fullPath})
matches = (resolve.resolved && resolve.resolved.matched) || matches
......
......@@ -29,8 +29,8 @@
:default-values="[layout]"
>
<img-checkbox :title="$t('navigate.side')" img="https://gw.alipayobjects.com/zos/rmsportal/JopDzEhOqwOjeNTXkoje.svg" value="side"/>
<!-- <img-checkbox :title="$t('navigate.head')" img="https://gw.alipayobjects.com/zos/rmsportal/KDNDBbriJhLwuqMoxcAr.svg" value="head"/> -->
<!-- <img-checkbox :title="$t('navigate.mix')" img="https://gw.alipayobjects.com/zos/antfincdn/x8Ob%26B8cy8/LCkqqYNmvBEbokSDscrm.svg" value="mix"/> -->
<img-checkbox :title="$t('navigate.head')" img="https://gw.alipayobjects.com/zos/rmsportal/KDNDBbriJhLwuqMoxcAr.svg" value="head"/>
<img-checkbox :title="$t('navigate.mix')" img="https://gw.alipayobjects.com/zos/antfincdn/x8Ob%26B8cy8/LCkqqYNmvBEbokSDscrm.svg" value="mix"/>
</img-checkbox-group>
</setting-item>
<setting-item>
......
<template>
<div class="sitetree ff">
<span style="font-weight: 600">站点结构</span>
<div class="box">
<a-tree
:load-data="onLoadData"
:tree-data="treeData"
:replaceFields="{ title: 'label', key: 'id' }"
@select="onSelect"
>
</a-tree>
</div>
</div>
</template>
<script>
// api
import {
getListByParentId,
areaList,
// getSiteList
} from "@/services/basicsetFun";
import local from "@/utils/local";
export default {
data() {
return {
treeData: [], //树结构
id: "",
topParent: process.env.VUE_APP_topParent,
};
},
created() {
this.getAreaList();
},
methods: {
// 获取区域
async getAreaList() {
let res = await areaList({ name: this.topParent });
const { data, code } = res.data;
if (code === 1) {
console.log(data.data);
data.data = data.data.map((v) => {
return {
label: v.name,
id: v.iid,
};
});
this.treeData = data.data;
}
},
// 异步获取子区域
onLoadData(treeNode) {
return new Promise((resolve) => {
console.log(treeNode.dataRef.id);
getListByParentId({
parentId: treeNode.dataRef.id,
}).then((res) => {
const { data } = res.data;
treeNode.dataRef.children = data.data;
this.treeData = [...this.treeData];
console.log(this.treeData);
resolve();
});
// if (treeNode.dataRef.children) {
// return;
// }
});
// let { id } = treeNode.dataRef;
// // 获取区域站点列表
// getSiteList({ areaID: id }).then((res) => {
// let { code, data } = res.data;
// if (code === 1) {
// console.log(">>", treeNode.dataRef);
// treeNode.dataRef.children = data.data;
// this.treeData = [...this.treeData];
// resolve();
// }
// });
// // 获取子区域
// getListByParentId({
// parentId: treeNode.dataRef.id,
// }).then((res) => {
// const { data } = res.data;
// treeNode.dataRef.children = data.data;
// this.treeData = [...this.treeData];
// resolve();
// });
// console.log("树", this.treeData);
// });
},
onSelect(num, node) {
if (num && node.selectedNodes.length > 0) {
let { dataRef } = node.selectedNodes[0].data.props;
let obj;
if (dataRef.areaCode) {
obj = {
areaCode: dataRef.areaCode,
id: dataRef.id,
label: dataRef.label,
};
this.$emit("getArea", obj);
local.setLocal("areaInfo", obj);
}
}
},
},
};
</script>
<style lang="less" scoped>
.sitetree {
padding-top: 10px;
.box {
width: 224px;
height: calc(100vh - 160px);
overflow-y: auto;
}
}
</style>
\ No newline at end of file
<template>
<div class="site-tree ff">
<span style="font-weight: 600">站点结构</span>
<div class="box">
<a-tree
:tree-data="treeData"
:selectable="false"
:replaceFields="{
children: 'children',
title: 'label',
key: 'areaCode',
}"
>
<!-- <template slot="icon" slot-scope="text">
<span v-if="text.children">
<a-icon type="caret-right" />
<a-icon type="caret-down" />
</span>
</template> -->
<template slot="custom" slot-scope="item">
<div v-if="Array.isArray(item.id) && Array.isArray(item.label)">
<span
:class="{ active: isActive === v.id }"
v-show="item.count === i"
v-for="(v, i) in item.siteData"
:key="v.id"
@click="onSelect(v.id, v.label)"
>{{ v.label }}</span
>
<!-- <span ref="siteName">{{ item.label[0] }}</span> -->
<a-popover placement="right" :overlayStyle="{ minWidth: '150px' }">
<template slot="content">
<p
class="site-item"
v-for="(v, i) in item.siteData"
:key="v.id"
@click="switchover(v.id, i, v.label)"
>
{{ v.label }}
</p>
</template>
<a-badge
:count="item.siteData.length"
:number-style="{
marginLeft: '30px',
backgroundColor: '#fff',
color: '#999',
boxShadow: '0 0 0 1px #d9d9d9 inset',
}"
/>
<!-- <span class="tips">{{ item.id.length }}</span> -->
</a-popover>
</div>
<p v-else>
<span
:class="{ active: isActive === item.id }"
@click="onSelect(item.id, item.label)"
>{{ item.label }}</span
>
</p>
</template>
</a-tree>
</div>
</div>
</template>
<script>
import { getSiteTree } from "@/services/basicsetFun";
import local from "@/utils/local";
export default {
data() {
return {
isActive: "",
treeData: [],
};
},
created() {
this.getSiteTreeData();
},
methods: {
// 拆分站点
splitSiteTree(arr) {
return arr.map((v) => {
if (v.id.includes(",") && v.label.includes(",")) {
v.id = v.id.split(",");
v.label = v.label.split(",");
for (let i = 0; i < v.id.length; i++) {
v.siteData.push({
id: v.id[i],
label: v.label[i],
});
}
}
if (v.children && v.children.length > 0) this.splitSiteTree(v.children);
return v;
});
},
// 添加树slot字段
addscopedSlots(arr) {
arr.forEach((v) => {
v.siteData = [];
v.count = 0;
v.scopedSlots = { title: "custom" };
if (v.children && v.children.length > 0) {
this.addscopedSlots(v.children);
}
});
return arr;
},
editLeaf(arr) {
return arr.map((v) => {
if (v.children && v.children.length > 0) {
this.editLeaf(v.children);
} else {
v.isLeaf = true;
// delete v.children;
}
return v;
});
},
// 获取站点结构
async getSiteTreeData() {
let res = await getSiteTree({});
let { siteTree } = res.data.data;
this.treeData = this.addscopedSlots(siteTree);
this.treeData = this.splitSiteTree(this.treeData);
this.treeData = this.editLeaf(this.treeData);
},
// 选中树节点
onSelect(num, name) {
this.isActive = num;
if (/^[0-9]+$/.test(num)) {
this.$emit("getSite", { id: num, label: name });
local.setLocal("siteInfo", { id: num, label: name });
} else {
this.$emit("clickArea");
}
},
// 查找id
findId(arr, id, index) {
arr.forEach((v) => {
if (v.siteData && v.siteData.length > 0) {
v.siteData.forEach((j) => {
if (j.id && j.id === id) {
v.count = index;
} else {
this.findId(v.children, id, index);
}
});
} else if (v.children && v.children.length > 0) {
this.findId(v.children, id, index);
}
});
return arr;
},
// 切换
switchover(id, index, name) {
this.treeData = this.findId(this.treeData, id, index);
this.onSelect(id, name);
},
},
};
</script>
<style lang="less" scoped>
.site-tree {
padding-top: 10px;
height: 100%;
.box {
width: 224px;
height: 100%;
overflow-y: auto;
}
}
.tips {
margin-left: 30px;
font-weight: 600;
color: #0595fd;
}
.site-item {
border-bottom: 1px solid rgb(231, 230, 230);
cursor: pointer;
text-align: center;
&:hover {
color: #0595fd;
}
}
.active {
color: #0595fd;
background-color: #e6f7ff;
}
// /deep/.ant-tree-treenode-switcher-close {
// height: 36px;
// }
.ant-badge {
margin-bottom: 3px;
}
</style>
\ No newline at end of file
<template>
<span>
<span class="redact mr" @click="onedit" v-if="edit">编辑</span>
<a-popconfirm
title="删除后不可恢复,确定要删除吗?"
ok-text="确定"
cancel-text="再想想"
@confirm="delConfirm"
>
<span class="del" v-if="del">删除</span>
</a-popconfirm>
<span class="redact mr" @click="onshow" v-if="show">详情</span>
</span>
</template>
<script>
export default {
props:{
record:Object,
edit:{
type:Boolean,
default:true
},
del:{
type:Boolean,
default:true
},
show:{
type:Boolean,
default:false
}
},
methods:{
delConfirm(){
this.$emit('del',this.record)
},
onedit(){
this.$emit('edit',this.record)
},
onshow(){
this.$emit('show',this.record)
}
}
}
</script>
\ No newline at end of file
<template>
<div>
<!-- 上传一张图片 -->
<a-upload
v-if="filetype === 'images' && limit === 1"
name="file"
:list-type="listtype"
:show-upload-list="false"
:multiple="true"
:action="action"
:before-upload="beforeUpload"
@change="handleChange"
>
<div class="images1">
<img v-if="imageUrl" :src="publicSrc(imageUrl)" alt="avatar" />
<div v-else>
<a-icon :type="loading ? 'loading' : 'plus'" />
<div class="ant-upload-text">
上传
</div>
</div>
</div>
</a-upload>
<!-- 上传文件 -->
<div v-else>
<a-button type="primary" @click="visible = true"> {{filetype === 'images'?'上传多图':'上传文件'}} </a-button>
<a-modal
:visible="visible"
@ok="handleOk"
@cancel="visible = false"
>
<!-- 上传多图 -->
<div class="clearfix" v-if="filetype === 'images'">
<a-upload
:action="action"
:list-type="listtype"
:file-list="fileList"
:multiple="multiple"
@preview="handlePreview"
@change="handleChange"
>
<div v-if="fileList.length < limit">
<a-icon type="plus" />
<div class="ant-upload-text">
上传
</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="previewVisible = false">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
<!-- 上传多文件 -->
<div class="clearfix" v-if="filetype === 'file'">
<a-upload-dragger
name="file"
:file-list="fileList"
:multiple="multiple"
:action="action"
:before-upload="beforeUploadFile"
@change="handleChange"
>
<p class="ant-upload-drag-icon">
<a-icon type="inbox" />
</p>
<p class="ant-upload-text">
点击或拖动到此区域上传
</p>
<p class="ant-upload-hint" v-if="multiple">
支持单个或批量上传,严禁上传公司资料
</p>
<p class="ant-upload-hint" v-else>
支持单个上传,严禁上传公司资料,<span style="color:red">最多上传{{limit}}个文件(已选择{{fileCount}}个)</span>
</p>
</a-upload-dragger>
</div>
</a-modal>
</div>
</div>
</template>
<script>
function getBase64(img, callback) {
const reader = new FileReader()
reader.addEventListener('load', () => callback(reader.result))
reader.readAsDataURL(img)
}
import {api} from "@/services/api"
export default {
model: {
prop: 'value',
event: 'change'
},
props:{
value:{
type:String
},
action:{
type:String,
default:api.file || ''
},
limit:{
type:Number,
default:1
},
filetype:{
type:String,
default:'file'
},
multiple:{
type:Boolean,
default:true
}
},
data () {
return {
visible:false,//多图模态
loading:false,//单图加载
imageUrl:"",//单图预览
listtype:"",//预览类型
fileList:[],//图片列表
previewImage:"",//预览文件
previewVisible: false,//预览模态
}
},
computed:{
fileCount:function(vm){
return vm.fileList.length
}
},
watch:{
value:{
handler:function(v){
if(this.filetype == 'images'){
this.imageUrl = v
}else{
// this.listtype = "text"
}
},
immediate:true
}
},
created(){
if(this.filetype == 'images'){
this.listtype = "picture-card"
}else{
this.listtype = "text"
}
},
methods: {
publicSrc(src){
return `${process.env.VUE_APP_API_BASE_URL}/${src}`
},
handleChange(info) {
if(this.filetype === 'file'){
let fileArr = []
info.fileList.forEach(element => {
if(element.status){
fileArr.push(element)
}
});
this.fileList = fileArr
}else{
this.fileList = info.fileList
}
if (info.file.status === 'error') {
this.loading = false;
this.$message.error('上传失败')
return;
}
if (info.file.status === 'uploading') {
this.loading = true;
return;
}
if (info.file.status === 'done') {
const {code,data,msg} = info.file.response
if(code == 0){
this.imageUrl = data;
this.loading = false;
this.success()
}else{
this.$message.error(msg)
}
// getBase64(info.file.originFileObj, imageUrl => {
// this.imageUrl = imageUrl;
// this.loading = false;
// });
}
},
beforeUploadFile(){
if(this.limit<=this.fileList.length){
this.$message.error(`上传失败,最多上传${this.limit}个文件`);
return false
}else{
return true
}
},
beforeUpload(file) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
this.$message.error('请上传jpeg/png文件!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error('图片必须小于 2MB!');
}
return isJpgOrPng && isLt2M;
},
handleOk(){
console.log(this.fileList)
},
async handlePreview(file) {
if (!file.url && !file.preview) {
getBase64(file.originFileObj,imageUrl => {
file.preview = imageUrl;
this.previewImage = file.url || file.preview;
this.previewVisible = true;
});
}
},
success(){
this.$emit("change",this.imageUrl)
}
}
}
</script>
<style scoped lang="less">
.ant-upload-text {
margin-top: 8px;
color: #666;
}
.images1{
width: 120px;
max-height: 180px;
overflow: hidden;
img{
display: block;
width: 100%;
}
}
</style>
<template>
<div>
<a-checkbox :checked="value" @change="onChange">
{{ checkText }}</a-checkbox
>
</div>
</template>
<script>
export default {
model: {
prop: "checked",
event: "change",
},
props: {
checked: {
required: true,
},
checkText: {
required: true,
default: "",
},
},
computed: {
value() {
return this.checked === 1 || this.checked === "1";
},
},
methods: {
onChange(e) {
this.$emit("change", e.target.checked ? 1 : 0);
},
},
};
</script>
<style lang="less" scoped>
</style>
\ No newline at end of file
<template>
<div>
<!-- <a-checkbox @change="onChange" :checked="value"> Checkbox </a-checkbox> -->
<a-switch
:checked-children="checkedChildren"
:un-checked-children="unCheckedChildren"
:disabled="disabled"
:checked="value"
@change="onChange"
/>
</div>
</template>
<script>
export default {
model: {
prop: "checked",
event: "change",
},
props: {
checkedChildren: {
default: "",
},
unCheckedChildren: {
default: "",
},
checked: {
required: true,
},
disabled: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
value() {
return this.checked === 1 || this.checked === "1";
},
},
methods: {
onChange(checked) {
this.$emit("change", checked ? 1 : 0);
},
},
};
</script>
<style lang="less" scoped>
</style>
\ No newline at end of file
// 自定义配置,参考 ./default/setting.config.js,需要自定义的属性在这里配置即可
module.exports = {
theme: {
color: '#13c2c2',
mode: 'dark',
},
multiPage: true,
// theme: {
// color: '#13c2c2',
// mode: 'dark',
// },
layout: 'side', //导航布局,可选 side 和 head,分别为侧边导航和顶部导航
fixedHeader: false, //固定头部状态栏,true:固定,false:不固定
pageWidth: 'fluid', //内容区域宽度,fixed:固定宽度,fluid:流式宽度
multiPage: false,
asyncRoutes:false,
animate: {
name: 'lightSpeed',
direction: 'left'
}
},
}
......@@ -14,7 +14,7 @@ module.exports = {
fixedTabs: false, //固定页签头,true:固定,false:不固定
pageWidth: 'fixed', //内容区域宽度,fixed:固定宽度,fluid:流式宽度
weekMode: false, //色弱模式,true:开启,false:不开启
multiPage: false, //多页签模式,true:开启,false:不开启
multiPage: true, //多页签模式,true:开启,false:不开启
cachePage: true, //是否缓存页面数据,仅多页签模式下生效,true 缓存, false 不缓存
hideSetting: false, //隐藏设置抽屉,true:隐藏,false:不隐藏
systemName: '智慧政务一体化综 合 管 理 平 台', //系统名称
......@@ -23,7 +23,7 @@ module.exports = {
showPageTitle: true, //是否显示页面标题(PageLayout 布局中的页面标题),true:显示,false:不显示
filterMenu: true, //根据权限过滤菜单,true:过滤,false:不过滤
animate: { //动画设置
disabled: false, //禁用动画,true:禁用,false:启用
disabled: true, //禁用动画,true:禁用,false:启用
name: 'bounce', //动画效果,支持的动画效果可参考 ./animate.config.js
direction: 'left' //动画方向,切换页面时动画的方向,参考 ./animate.config.js
},
......
......@@ -14,50 +14,49 @@
*/
const cssResolve = {
'.ant-checkbox-checked .ant-checkbox-inner::after': {
resolve(cssText, cssObj) {
resolve (cssText, cssObj) {
cssObj.rules.push('border-top:0', 'border-left:0')
return cssObj.toText()
}
},
'.ant-tree-checkbox-checked .ant-tree-checkbox-inner::after': {
resolve(cssText, cssObj) {
resolve (cssText, cssObj) {
cssObj.rules.push('border-top:0', 'border-left:0')
return cssObj.toText()
}
},
'.ant-checkbox-checked .ant-checkbox-inner:after': {
resolve(cssText, cssObj) {
resolve (cssText, cssObj) {
cssObj.rules.push('border-top:0', 'border-left:0')
return cssObj.toText()
}
},
'.ant-tree-checkbox-checked .ant-tree-checkbox-inner:after': {
resolve(cssText, cssObj) {
resolve (cssText, cssObj) {
cssObj.rules.push('border-top:0', 'border-left:0')
return cssObj.toText()
}
},
'.ant-menu-dark .ant-menu-inline.ant-menu-sub': {
resolve(cssText, cssObj) {
resolve (cssText, cssObj) {
cssObj.rules = cssObj.rules.filter(rule => rule.indexOf('box-shadow') == -1)
return cssObj.toText()
}
},
'.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu:hover,.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-submenu-selected': {
resolve(cssText, cssObj) {
resolve (cssText, cssObj) {
cssObj.selector = cssObj.selector.replace(/.ant-menu-horizontal/g, '.ant-menu-horizontal:not(.ant-menu-dark)')
return cssObj.toText()
}
},
'.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover': {
resolve(cssText, cssObj) {
resolve (cssText, cssObj) {
cssObj.selector = cssObj.selector.replace(/.ant-menu-horizontal/g, '.ant-menu-horizontal:not(.ant-menu-dark)')
return cssObj.toText()
}
},
'.ant-layout-sider': {
resolve(cssText, cssObj) {
console.log(cssObj)
resolve (cssText, cssObj) {
cssObj.selector = '.ant-layout-sider-dark'
return cssObj.toText()
}
......
import moment from 'moment';
// 时间格式 年月日时分秒
export function dateFormat (val){
return moment(val).format('YYYY-MM-DD HH:mm:ss')
}
// 时分秒
export function times (val){
return moment(val).format('HH:mm:ss')
}
// 年
export function year (val){
return moment(val).format('YYYY')
}
// 号数
export function days (val){
return moment(val).format('MM-DD')
}
\ No newline at end of file
<template>
<a-layout :class="['admin-layout', 'beauty-scroll']">
<drawer v-if="isMobile" v-model="drawerOpen">
<side-menu :theme="theme.mode" :menuData="menuData" :collapsed="false" :collapsible="false" @menuSelect="onMenuSelect"/>
<side-menu
:theme="theme.mode"
:menuData="menuData"
:collapsed="false"
:collapsible="false"
@menuSelect="onMenuSelect"
/>
</drawer>
<side-menu :class="[fixedSideBar ? 'fixed-side' : '']" :theme="theme.mode" v-else-if="layout === 'side' || layout === 'mix'" :menuData="sideMenuData" :collapsed="collapsed" :collapsible="true" />
<div v-if="fixedSideBar && !isMobile" :style="`width: ${sideMenuWidth}; min-width: ${sideMenuWidth};max-width: ${sideMenuWidth};`" class="virtual-side"></div>
<drawer v-if="!hideSetting" v-model="showSetting" placement="right">
<side-menu
:class="[fixedSideBar ? 'fixed-side' : '']"
:theme="theme.mode"
v-else-if="layout === 'side' || layout === 'mix'"
:menuData="sideMenuData"
:collapsed="collapsed"
:collapsible="true"
/>
<div
v-if="fixedSideBar && !isMobile"
:style="`width: ${sideMenuWidth}; min-width: ${sideMenuWidth};max-width: ${sideMenuWidth};`"
class="virtual-side"
></div>
<!-- <drawer v-if="!hideSetting" v-model="showSetting" placement="right">
<div class="setting" slot="handler">
<a-icon :type="showSetting ? 'close' : 'setting'"/>
<a-icon :type="showSetting ? 'close' : 'setting'" />
</div>
<setting />
</drawer>
</drawer> -->
<a-layout class="admin-layout-main beauty-scroll">
<admin-header :class="[{'fixed-tabs': fixedTabs, 'fixed-header': fixedHeader, 'multi-page': multiPage}]" :style="headerStyle" :menuData="headMenuData" :collapsed="collapsed" @toggleCollapse="toggleCollapse"/>
<a-layout-header :class="['virtual-header', {'fixed-tabs' : fixedTabs, 'fixed-header': fixedHeader, 'multi-page': multiPage}]" v-show="fixedHeader"></a-layout-header>
<a-layout-content class="admin-layout-content" :style="`min-height: ${minHeight}px;`">
<div style="position: relative;height:100%">
<admin-header
:class="[
{
'fixed-tabs': fixedTabs,
'fixed-header': fixedHeader,
'multi-page': multiPage,
},
]"
:style="headerStyle"
:menuData="headMenuData"
:collapsed="collapsed"
@toggleCollapse="toggleCollapse"
/>
<a-layout-header
:class="[
'virtual-header',
{
'fixed-tabs': fixedTabs,
'fixed-header': fixedHeader,
'multi-page': multiPage,
},
]"
v-show="fixedHeader"
></a-layout-header>
<a-layout-content
class="admin-layout-content"
:style="`min-height: ${minHeight}px;`"
>
<div style="position: relative; height: 100%">
<slot></slot>
</div>
</a-layout-content>
......@@ -27,140 +69,155 @@
</template>
<script>
import AdminHeader from './header/AdminHeader'
import PageFooter from './footer/PageFooter'
import Drawer from '../components/tool/Drawer'
import SideMenu from '../components/menu/SideMenu'
import Setting from '../components/setting/Setting'
import {mapState, mapMutations, mapGetters} from 'vuex'
import AdminHeader from "./header/AdminHeader";
import PageFooter from "./footer/PageFooter";
import Drawer from "../components/tool/Drawer";
import SideMenu from "../components/menu/SideMenu";
// import Setting from "../components/setting/Setting";
import { mapState, mapMutations, mapGetters } from "vuex";
// const minHeight = window.innerHeight - 64 - 122
export default {
name: 'AdminLayout',
components: {Setting, SideMenu, Drawer, PageFooter, AdminHeader},
data () {
name: "AdminLayout",
components: { SideMenu, Drawer, PageFooter, AdminHeader },
data() {
return {
minHeight: window.innerHeight - 64 - 41,
collapsed: false,
showSetting: false,
drawerOpen: false
}
drawerOpen: false,
};
},
provide() {
return {
adminLayout: this
}
adminLayout: this,
};
},
watch: {
$route(val) {
this.setActivated(val)
this.setActivated(val);
},
layout() {
this.setActivated(this.$route)
this.setActivated(this.$route);
},
isMobile(val) {
console.log(val)
if(!val) {
this.drawerOpen = false
}
if (!val) {
this.drawerOpen = false;
}
},
},
computed: {
...mapState('setting', ['isMobile', 'theme', 'layout', 'footerLinks', 'copyright', 'fixedHeader', 'fixedSideBar',
'fixedTabs', 'hideSetting', 'multiPage']),
...mapGetters('setting', ['firstMenu', 'subMenu', 'menuData']),
...mapState("setting", [
"isMobile",
"theme",
"layout",
"footerLinks",
"copyright",
"fixedHeader",
"fixedSideBar",
"fixedTabs",
"hideSetting",
"multiPage",
]),
...mapGetters("setting", ["firstMenu", "subMenu", "menuData"]),
sideMenuWidth() {
return this.collapsed ? '80px' : '256px'
return this.collapsed ? "80px" : "256px";
},
headerStyle() {
let width = (this.fixedHeader && this.layout !== 'head' && !this.isMobile) ? `calc(100% - ${this.sideMenuWidth})` : '100%'
let position = this.fixedHeader ? 'fixed' : 'static'
return `width: ${width}; position: ${position};`
let width =
this.fixedHeader && this.layout !== "head" && !this.isMobile
? `calc(100% - ${this.sideMenuWidth})`
: "100%";
let position = this.fixedHeader ? "fixed" : "static";
return `width: ${width}; position: ${position};`;
},
headMenuData() {
const {layout, menuData, firstMenu} = this
return layout === 'mix' ? firstMenu : menuData
const { layout, menuData, firstMenu } = this;
// 自定义 || head模式展示一级菜单
return layout === "mix" || layout === "head" ? firstMenu : menuData;
},
sideMenuData() {
const {layout, menuData, subMenu} = this
return layout === 'mix' ? subMenu : menuData
}
const { layout, menuData, subMenu } = this;
return layout === "mix" ? subMenu : menuData;
},
},
methods: {
...mapMutations('setting', ['correctPageMinHeight', 'setActivatedFirst']),
toggleCollapse () {
this.collapsed = !this.collapsed
...mapMutations("setting", ["correctPageMinHeight", "setActivatedFirst"]),
toggleCollapse() {
this.collapsed = !this.collapsed;
},
onMenuSelect () {
this.toggleCollapse()
onMenuSelect() {
this.toggleCollapse();
},
setActivated(route) {
if (this.layout === 'mix') {
let matched = route.matched
matched = matched.slice(0, matched.length - 1)
const {firstMenu} = this
// 自定义 || head模式展示一级菜单
if (this.layout === "mix" || this.layout === "head") {
let matched = route.matched;
matched = matched.slice(0, matched.length - 1);
const { firstMenu } = this;
for (let menu of firstMenu) {
if (matched.findIndex(item => item.path === menu.fullPath) !== -1) {
this.setActivatedFirst(menu.fullPath)
break
}
if (matched.findIndex((item) => item.path === menu.fullPath) !== -1) {
this.setActivatedFirst(menu.fullPath);
break;
}
}
}
},
},
created() {
this.correctPageMinHeight(this.minHeight - 24)
this.setActivated(this.$route)
let _this = this
window.onresize = function(){
_this.minHeight = window.innerHeight - 64 - 41
}
this.correctPageMinHeight(this.minHeight - 24);
this.setActivated(this.$route);
let _this = this;
window.onresize = function () {
_this.minHeight = window.innerHeight - 64 - 41;
};
},
beforeDestroy() {
this.correctPageMinHeight(-this.minHeight + 24)
}
}
this.correctPageMinHeight(-this.minHeight + 24);
},
};
</script>
<style lang="less" scoped>
.admin-layout{
.side-menu{
&.fixed-side{
.admin-layout {
.side-menu {
&.fixed-side {
position: fixed;
height: 100vh;
left: 0;
top: 0;
}
}
.virtual-side{
.virtual-side {
transition: all 0.2s;
}
.virtual-header{
.virtual-header {
transition: all 0.2s;
opacity: 0;
&.fixed-tabs.multi-page:not(.fixed-header){
&.fixed-tabs.multi-page:not(.fixed-header) {
height: 0;
}
}
.admin-layout-main{
.admin-header{
.admin-layout-main {
.admin-header {
top: 0;
right: 0;
overflow: hidden;
transition: all 0.2s;
&.fixed-tabs.multi-page:not(.fixed-header){
&.fixed-tabs.multi-page:not(.fixed-header) {
height: 0;
}
}
}
.admin-layout-content{
.admin-layout-content {
padding: 24px 24px 0;
// overflow-x: hidden;
min-height: calc(100vh - 64px - 41px);
}
.setting{
.setting {
background-color: @primary-color;
color: @base-bg-color;
border-radius: 5px 0 0 5px;
......@@ -170,5 +227,5 @@ export default {
height: 40px;
box-shadow: -2px 0 8px @shadow-color;
}
}
}
</style>
<template>
<div class="pageCard">
<div class="c-head b-b">
<span
><a-icon
type="database"
theme="filled"
class="primary-color"
style="padding-right: 5px"
/>{{ title }}</span
>
<div class="c-head-r">
<slot name="head-right" />
</div>
</div>
<div class="c-body">
<slot />
</div>
</div>
</template>
<script>
export default {
props: ["title", "icon"],
};
</script>
<style lang="less" scoped>
.c-head {
display: flex;
align-items: center;
& > span {
flex: 1;
font-size: 14px;
font-weight: 600;
}
height: 45px;
padding: 0 10px;
}
.c-body {
padding: 10px 0;
}
</style>
\ No newline at end of file
<template>
<div class="page-layout">
<page-header ref="pageHeader" :style="`margin-top: ${multiPage ? 0 : -24}px`" :breadcrumb="breadcrumb" :title="pageTitle" :logo="logo" :avatar="avatar">
<page-header
ref="pageHeader"
:style="`margin-top: ${multiPage ? 0 : -24}px`"
:breadcrumb="breadcrumb"
:title="pageTitle"
:logo="logo"
:avatar="avatar"
>
<slot name="action" slot="action"></slot>
<slot slot="content" name="headerContent"></slot>
<div slot="content" v-if="!this.$slots.headerContent && desc">
<p>{{desc}}</p>
<p>{{ desc }}</p>
<div v-if="this.linkList" class="link">
<template v-for="(link, index) in linkList">
<a :key="index" :href="link.href"><a-icon :type="link.icon" />{{link.title}}</a>
<a :key="index" :href="link.href"
><a-icon :type="link.icon" />{{ link.title }}</a
>
</template>
</div>
</div>
<slot v-if="this.$slots.extra" slot="extra" name="extra"></slot>
</page-header>
<div ref="page" :class="['page-content', layout, pageWidth]" >
<div ref="page" :class="['page-content', layout, pageWidth]">
<slot></slot>
</div>
</div>
</template>
<script>
import PageHeader from '@/components/page/header/PageHeader'
import {mapState, mapMutations} from 'vuex'
import {getI18nKey} from '@/utils/routerUtil'
import PageHeader from "@/components/page/header/PageHeader";
import { mapState, mapMutations } from "vuex";
import { getI18nKey } from "@/utils/routerUtil";
export default {
name: 'PageLayout',
components: {PageHeader},
props: ['desc', 'logo', 'title', 'avatar', 'linkList', 'extraImage'],
data () {
name: "PageLayout",
components: { PageHeader },
props: ["desc", "logo", "title", "avatar", "linkList", "extraImage"],
data() {
return {
page: {},
pageHeaderHeight: 0,
}
};
},
watch: {
$route() {
this.page = this.$route.meta.page
}
this.page = this.$route.meta.page;
},
},
updated() {
if (!this._inactive) {
this.updatePageHeight()
this.updatePageHeight();
}
},
activated() {
this.updatePageHeight()
this.updatePageHeight();
},
deactivated() {
this.updatePageHeight(0)
this.updatePageHeight(0);
},
mounted() {
this.updatePageHeight()
this.updatePageHeight();
},
created() {
this.page = this.$route.meta.page
this.page = this.$route.meta.page;
},
beforeDestroy() {
this.updatePageHeight(0)
this.updatePageHeight(0);
},
computed: {
...mapState('setting', ['layout', 'multiPage', 'pageMinHeight', 'pageWidth', 'customTitles']),
...mapState("setting", [
"layout",
"multiPage",
"pageMinHeight",
"pageWidth",
"customTitles",
]),
pageTitle() {
let pageTitle = this.page && this.page.title
return this.customTitle || (pageTitle && this.$t(pageTitle)) || this.title || this.routeName
let pageTitle = this.page && this.page.title;
return (
this.customTitle ||
(pageTitle && this.$t(pageTitle)) ||
this.title ||
this.routeName
);
},
routeName() {
const route = this.$route
return this.$t(getI18nKey(route.matched[route.matched.length - 1].path))
const route = this.$route;
return this.$t(getI18nKey(route.matched[route.matched.length - 1].path));
},
breadcrumb() {
let page = this.page
let breadcrumb = page && page.breadcrumb
let page = this.page;
let breadcrumb = page && page.breadcrumb;
if (breadcrumb) {
let i18nBreadcrumb = []
breadcrumb.forEach(item => {
i18nBreadcrumb.push(this.$t(item))
})
return i18nBreadcrumb
let i18nBreadcrumb = [];
breadcrumb.forEach((item) => {
i18nBreadcrumb.push(this.$t(item));
});
return i18nBreadcrumb;
} else {
return this.getRouteBreadcrumb()
return this.getRouteBreadcrumb();
}
},
marginCorrect() {
return this.multiPage ? 24 : 0
}
return this.multiPage ? 24 : 0;
},
},
methods: {
...mapMutations('setting', ['correctPageMinHeight']),
...mapMutations("setting", ["correctPageMinHeight"]),
getRouteBreadcrumb() {
let routes = this.$route.matched
const path = this.$route.path
let breadcrumb = []
routes.filter(item => path.includes(item.path))
.forEach(route => {
const path = route.path.length === 0 ? '/home' : route.path
breadcrumb.push(this.$t(getI18nKey(path)))
})
let pageTitle = this.page && this.page.title
let routes = this.$route.matched;
const path = this.$route.path;
let breadcrumb = [];
routes
.filter((item) => path.includes(item.path))
.forEach((route) => {
const path = route.path.length === 0 ? "/home" : route.path;
breadcrumb.push(this.$t(getI18nKey(path)));
});
let pageTitle = this.page && this.page.title;
if (this.customTitle || pageTitle) {
breadcrumb[breadcrumb.length - 1] = this.customTitle || pageTitle
breadcrumb[breadcrumb.length - 1] = this.customTitle || pageTitle;
}
return breadcrumb
return breadcrumb;
},
/**
* 用于计算页面内容最小高度
* @param newHeight
*/
updatePageHeight(newHeight = this.$refs.pageHeader.$el.offsetHeight + this.marginCorrect) {
this.correctPageMinHeight(this.pageHeaderHeight - newHeight)
this.pageHeaderHeight = newHeight
}
}
}
updatePageHeight(
newHeight = this.$refs.pageHeader.$el.offsetHeight + this.marginCorrect
) {
this.correctPageMinHeight(this.pageHeaderHeight - newHeight);
this.pageHeaderHeight = newHeight;
},
},
};
</script>
<style lang="less">
.page-header{
.page-header {
margin: 0 -24px 0;
}
.link{
}
.link {
/*margin-top: 16px;*/
line-height: 24px;
a{
a {
font-size: 14px;
margin-right: 32px;
i{
i {
font-size: 22px;
margin-right: 8px;
}
}
}
.page-content{
}
.page-content {
position: relative;
padding: 24px 0 0;
&.side{
}
&.head.fixed{
&.head.fixed {
margin: 0 auto;
max-width: 1400px;
}
}
}
</style>
<template>
<div class="tableview viewbox">
<div class="head b-b">
<router-link :to="item.fullPath" v-for="(item,index) in subMenu" :key="index"><a-icon :type="item.meta.icon" /> {{item.name}}</router-link>
</div>
<router-view />
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
computed:{
...mapGetters('setting', ['subMenu']),
},
created(){
console.log(this.subMenu)
}
}
</script>
<style lang="less" scoped>
.tableview{
border-radius: 8px;
overflow: hidden;
.head{
padding:0 10px;
background: #fff;
a{
margin-right:30px;
color: #202020;
font-size: 14px;
padding: 10px 0;
display: inline-block;
}
.router-link-active{
color: #2681e8;
position: relative;
&::after{
content: "";
display: block;
border-bottom: 2px solid #2681e8;
position: absolute;
left: 0;
bottom: 0;
right: 0;
}
}
}
}
</style>
\ No newline at end of file
<template>
<div class="footer">
<div class="copyright">
Copyright<a-icon type="copyright" />{{copyright}}
Copyright<a-icon type="copyright" />{{ copyright }}
</div>
</div>
</template>
<script>
export default {
name: 'PageFooter',
props: ['copyright', 'linkList']
}
name: "PageFooter",
props: ["copyright", "linkList"],
};
</script>
<style lang="less" scoped>
.footer{
padding: 10px 16px 10px;
.footer {
padding-bottom: 10px;
/*margin: 48px 0 24px;*/
text-align: center;
.copyright{
.copyright {
color: @text-color-second;
font-size: 14px;
i {
margin: 0 4px;
}
}
.links{
.links {
margin-bottom: 8px;
a:not(:last-child) {
margin-right: 40px;
}
a{
a {
color: @text-color-second;
-webkit-transition: all .3s;
transition: all .3s;
}
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
}
}
</style>
<template>
<a-layout-header :class="[headerTheme, headerThememode, 'admin-header']">
<a-layout-header
:class="[layout, headerTheme, headerThememode, 'admin-header']"
>
<div :class="['admin-header-wide', layout, pageWidth]">
<router-link v-if="isMobile || layout === 'head'" to="/" :class="['logo', isMobile ? null : 'pc', headerTheme]">
<router-link
v-if="isMobile || layout === 'head'"
to="/"
:class="['logo', isMobile ? null : 'pc', headerTheme]"
>
<img width="32" src="@/assets/img/logo.png" />
<h1 v-if="!isMobile">{{systemName}}</h1>
<h1 v-if="!isMobile" style="padding-left: 10px">{{ systemName }}</h1>
</router-link>
<a-divider v-if="isMobile" type="vertical" />
<a-icon v-if="layout !== 'head'" class="trigger" :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click="toggleCollapse"/>
<div v-if="layout !== 'side' && !isMobile" class="admin-header-menu" :style="`width: ${menuWidth};`">
<i-menu class="head-menu" :theme="headerTheme" mode="horizontal" :options="menuData" @select="onSelect"/>
<a-icon
v-if="layout !== 'head'"
class="trigger"
:type="collapsed ? 'menu-unfold' : 'menu-fold'"
@click="toggleCollapse"
/>
<!-- <HeaderSite /> -->
<div
v-if="layout !== 'side' && !isMobile"
class="admin-header-menu"
:style="`width: ${menuWidth};`"
>
<i-menu
class="head-menu"
:theme="headerTheme"
mode="horizontal"
:options="menuData"
@select="onSelect"
/>
</div>
<div :class="['admin-header-right', headerTheme]">
<a-tooltip class="header-item" title="返回门户" placement="bottom" >
<a href="" target="_blank">
<a-tooltip class="header-item" title="返回门户" placement="bottom">
<a :href="portalUrl + '/#/home/siteArrange'">
<a-icon type="home" /> 返回门户
</a>
</a-tooltip>
<a-tooltip class="header-item" title="平台设置" placement="bottom" >
<a href="" target="_blank">
<a-icon type="setting" /> 平台设置
</a>
</a-tooltip>
<header-notice class="header-item"/>
<header-avatar class="header-item"/>
<a-dropdown class="lang header-item">
<div>
<a-icon type="global"/> {{langAlias}}
</div>
<a-menu @click="val => setLang(val.key)" :selected-keys="[lang]" slot="overlay">
<a-menu-item v-for=" lang in langList" :key="lang.key">{{lang.key.toLowerCase() + ' ' + lang.name}}</a-menu-item>
<!-- <a-tooltip class="header-item" title="数据可视化" placement="bottom">
<a href="" target="_blank"> <a-icon type="setting" /> 数据可视化 </a>
</a-tooltip> -->
<!-- <header-notice class="header-item" /> -->
<!-- <header-avatar class="header-item" /> -->
<!-- <a-dropdown class="lang header-item">
<div><a-icon type="global" /> {{ langAlias }}</div>
<a-menu
@click="(val) => setLang(val.key)"
:selected-keys="[lang]"
slot="overlay"
>
<a-menu-item v-for="lang in langList" :key="lang.key">{{
lang.key.toLowerCase() + " " + lang.name
}}</a-menu-item>
</a-menu>
</a-dropdown>
</a-dropdown> -->
</div>
</div>
</a-layout-header>
......@@ -38,57 +62,71 @@
<script>
// import HeaderSearch from './HeaderSearch'
import HeaderNotice from './HeaderNotice'
import HeaderAvatar from './HeaderAvatar'
import IMenu from '@/components/menu/menu'
import {mapState, mapMutations} from 'vuex'
// import HeaderNotice from './HeaderNotice'
// import HeaderSite from "./HeaderSite";
// import HeaderAvatar from "./HeaderAvatar";
import IMenu from "@/components/menu/menu";
import { mapState, mapMutations } from "vuex";
export default {
name: 'AdminHeader',
components: {IMenu, HeaderAvatar, HeaderNotice},
props: ['collapsed', 'menuData'],
name: "AdminHeader",
components: { IMenu },
props: ["collapsed", "menuData"],
data() {
return {
langList: [
{key: 'CN', name: '简体中文', alias: '简体'},
{key: 'HK', name: '繁體中文', alias: '繁體'},
{key: 'US', name: 'English', alias: 'English'}
{ key: "CN", name: "简体中文", alias: "简体" },
{ key: "HK", name: "繁體中文", alias: "繁體" },
{ key: "US", name: "English", alias: "English" },
],
searchActive: false
}
searchActive: false,
portalUrl: process.env.VUE_APP_API_portal_URL,
};
},
computed: {
...mapState('setting', ['theme', 'isMobile', 'layout', 'systemName', 'lang', 'pageWidth']),
headerTheme () {
if (this.layout == 'side' && this.theme.mode == 'dark' && !this.isMobile) {
return 'light'
...mapState("setting", [
"theme",
"isMobile",
"layout",
"systemName",
"lang",
"pageWidth",
]),
headerTheme() {
if (
this.layout == "side" &&
this.theme.mode == "dark" &&
!this.isMobile
) {
return "light";
}
return this.theme.mode
return this.theme.mode;
},
headerThememode () {
return `header-${this.theme.mode}`
headerThememode() {
return `header-${this.theme.mode}`;
},
langAlias() {
let lang = this.langList.find(item => item.key == this.lang)
return lang.alias
let lang = this.langList.find((item) => item.key == this.lang);
return lang.alias;
},
menuWidth() {
const {layout, searchActive} = this
const headWidth = layout === 'head' ? '100% - 188px' : '100%'
const extraWidth = searchActive ? '600px' : '400px'
return `calc(${headWidth} - ${extraWidth})`
}
const { layout, searchActive } = this;
const headWidth = layout === "head" ? "100% - 188px" : "100%";
const extraWidth = searchActive ? "600px" : "500px";
return `calc(${headWidth} - ${extraWidth})`;
},
},
created() {},
methods: {
toggleCollapse () {
this.$emit('toggleCollapse')
toggleCollapse() {
this.$emit("toggleCollapse");
},
onSelect (obj) {
this.$emit('menuSelect', obj)
onSelect(obj) {
this.$emit("menuSelect", obj);
},
...mapMutations('setting', ['setLang'])
}
}
...mapMutations("setting", ["setLang"]),
},
};
</script>
<style lang="less" scoped>
......
<template>
<div class="header-search">
<a-icon type="search" class="search-icon" @click="enterSearchMode"/>
<a-auto-complete
ref="input"
:getPopupContainer="e => {return e.parentNode || document.body}"
:dataSource="dataSource"
:class="['search-input', searchMode ? 'enter' : 'leave']"
placeholder="站内搜索"
@blur="leaveSearchMode"
>
</a-auto-complete>
</div>
</template>
<script>
export default {
name: 'HeaderSearch',
data () {
return {
dataSource: ['选项一', '选项二'],
searchMode: false
}
},
methods: {
enterSearchMode () {
this.searchMode = true
this.$emit('active', true)
setTimeout(() => this.$refs.input.focus(), 300)
},
leaveSearchMode () {
this.searchMode = false
setTimeout(() => this.$emit('active', false), 300)
}
}
}
</script>
<style lang="less">
.header-search{
.search-icon{
font-size: 16px;
cursor: pointer;
}
.search-input{
border: 0;
border-bottom: 1px solid @border-color-split;
transition: width 0.3s ease-in-out;
input{
border: 0;
box-shadow: 0 0 0 0;
}
&.leave{
width: 0px;
input{
display: none;
}
}
&.enter{
width: 200px;
input:focus{
box-shadow: 0 0 0 0;
}
}
}
}
</style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment