提交 247ebd82 编写于 作者: XuanDai's avatar XuanDai

[ADD]上传Vue-xdorg源代码

上级 165367bb
......@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2021 xdorg
Copyright 2021 XDORG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
'use strict'
module.exports = {
title: 'VUE-XDORG1',
vueClientPort: 8080,
goServerPort: 8888,
baseCdnUrl: '//cdn.staticfile.org',
cdns: [
/**
* 如果设置path属性, { name: 'vue', scope: 'Vue', path: '/vue/2.6.9/vue.min.js' } 即编译出来以[baseCdnUrl][path]
* 否则自动拼写 [baseCdnUrl]/[name]/[version]/[name].min.js
* */
{ name: 'vue', scope: 'Vue' },
{ name: 'vue-router', scope: 'VueRouter' },
{ name: 'vuex', scope: 'Vuex' },
{ name: 'axios', scope: 'axios' },
{ name: 'element-ui', scope: 'ELEMENT', path: '/element-ui/2.12.0/index.js'},
]
};
/*
商用代码公司自用产品无需授权
若作为代码出售的产品(任何涉及代码交付第三方作为后续开发)必须保留此脚本
或标注原作者信息
否则将依法维权
*/
var child_process = require("child_process");
var url = "https://blog.csdn.net/xuan_xuan_2?spm=1001.2100.3001.5343",
cmd = '';
console.log(process.platform)
switch (process.platform) {
case 'win32':
cmd = 'start';
child_process.exec(cmd + ' ' + url);
break;
case 'darwin':
cmd = 'open';
child_process.exec(cmd + ' ' + url);
break;
}
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
{
"name": "vue-xdorg",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@antv/dom-util": "2.0.2",
"@antv/g-canvas": "^0.4.12",
"@antv/g6": "3.5.2",
"@antv/matrix-util": "2.0.7",
"@antv/util": "~2.0.9",
"@moefe/vue-aplayer": "^2.0.0-beta.5",
"axios": "^0.21.1",
"element-ui": "^2.12.0",
"highlight.js": "^10.6.0",
"marked": "^2.0.0",
"path": "^0.12.7",
"qs": "^6.8.0",
"quill": "^1.3.7",
"screenfull": "^5.0.2",
"script-ext-html-webpack-plugin": "^2.1.4",
"spark-md5": "^3.0.1",
"timeline-vuejs": "1.1.1",
"vue": "^2.6.10",
"vue-particle-line": "^0.1.4",
"vue-router": "^3.1.3",
"vue-simple-uploader": "^0.7.4",
"vuescroll": "^4.14.4",
"vuex": "^3.1.1",
"vuex-persist": "^2.1.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.5.6",
"@vue/cli-plugin-eslint": "^4.5.6",
"@vue/cli-service": "^4.5.13",
"babel-eslint": "^10.1.0",
"babel-plugin-component": "^1.1.1",
"babel-preset-es2015": "^6.24.1",
"core-js": "^3.3.2",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"node-sass": "^4.12.0",
"numericjs": "^1.2.6",
"raw-loader": "^3.1.0",
"sass-loader": "^8.0.0",
"vue-template-compiler": "^2.6.10"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<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><%=htmlWebpackPlugin.options.title%></title>
<% if(process.env.NODE_ENV!=='development'){ %>
<% htmlWebpackPlugin.options.cdns.forEach(function(item){ if(item.js){ %>
<script type="text/javascript" src="<%= item.js %>"></script>
<% } }) %>
<% } %>
</head>
<body>
<noscript>
<strong>We're sorry but VUE-XDORG doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
import { checkDB } from "@/api/initdb"
export default {
name: 'app',
async created(){
await checkDB()
}
}
</script>
<style lang="scss">
// 引入初始化样式
@import '@/style/main.scss';
@import '@/style/base.scss';
@import '@/style/mobile.scss';
#app {
background: #eee;
height: 100vh;
overflow: hidden;
}
</style>
import service from '@/utils/request'
// @Tags api
// @Summary 分页获取角色列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body modelInterface.PageInfo true "分页获取用户列表"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/getApiList [post]
// {
// page int
// pageSize int
// }
export const getApiList = (data) => {
return service({
url: "/api/getApiList",
method: 'post',
data
})
}
// @Tags Api
// @Summary 创建基础api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateApiParams true "创建api"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/createApi [post]
export const createApi = (data) => {
return service({
url: "/api/createApi",
method: 'post',
data
})
}
// @Tags menu
// @Summary 根据id获取菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.GetById true "根据id获取菜单"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /menu/getApiById [post]
export const getApiById = (data) => {
return service({
url: "/api/getApiById",
method: 'post',
data
})
}
// @Tags Api
// @Summary 更新api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateApiParams true "更新api"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /api/updateApi [post]
export const updateApi = (data) => {
return service({
url: "/api/updateApi",
method: 'post',
data
})
}
// @Tags Api
// @Summary 更新api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateApiParams true "更新api"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /api/setAuthApi [post]
export const setAuthApi = (data) => {
return service({
url: "/api/setAuthApi",
method: 'post',
data
})
}
// @Tags Api
// @Summary 获取所有的Api 不分页
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/getAllApis [post]
export const getAllApis = (data) => {
return service({
url: "/api/getAllApis",
method: 'post',
data
})
}
// @Tags Api
// @Summary 删除指定api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body dbModel.Api true "删除api"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /api/deleteApi [post]
export const deleteApi = (data) => {
return service({
url: "/api/deleteApi",
method: 'post',
data
})
}
// @Tags SysApi
// @Summary 删除选中Api
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "ID"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /api/deleteApisByIds [delete]
export const deleteApisByIds = (data) => {
return service({
url: "/api/deleteApisByIds",
method: 'delete',
data
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Router /authority/getAuthorityList [post]
export const getAuthorityList = (data) => {
return service({
url: "/authority/getAuthorityList",
method: 'post',
data
})
}
// @Summary 删除角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body {authorityId uint} true "删除角色"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /authority/deleteAuthority [post]
export const deleteAuthority = (data) => {
return service({
url: "/authority/deleteAuthority",
method: 'post',
data
})
}
// @Summary 创建角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateAuthorityPatams true "创建角色"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /authority/createAuthority [post]
export const createAuthority = (data) => {
return service({
url: "/authority/createAuthority",
method: 'post',
data
})
}
// @Tags authority
// @Summary 拷贝角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateAuthorityPatams true "拷贝角色"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"拷贝成功"}"
// @Router /authority/copyAuthority [post]
export const copyAuthority = (data) => {
return service({
url: "/authority/copyAuthority",
method: 'post',
data
})
}
// @Summary 设置角色资源权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body sysModel.SysAuthority true "设置角色资源权限"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
// @Router /authority/setDataAuthority [post]
export const setDataAuthority = (data) => {
return service({
url: "/authority/setDataAuthority",
method: 'post',
data
})
}
// @Summary 修改角色
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysAuthority true "修改角色"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
// @Router /authority/setDataAuthority [post]
export const updateAuthority = (data) => {
return service({
url: "/authority/updateAuthority",
method: 'put',
data
})
}
\ No newline at end of file
import service from '@/utils/request'
export const preview = (data) => {
return service({
url: "/autoCode/preview",
method: 'post',
data,
})
}
export const createTemp = (data) => {
return service({
url: "/autoCode/createTemp",
method: 'post',
data,
responseType: 'blob'
})
}
// @Tags SysApi
// @Summary 获取当前所有数据库
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/getDatabase [get]
export const getDB = () => {
return service({
url: "/autoCode/getDB",
method: 'get',
})
}
// @Tags SysApi
// @Summary 获取当前数据库所有表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/getTables [get]
export const getTable = (params) => {
return service({
url: "/autoCode/getTables",
method: 'get',
params,
})
}
// @Tags SysApi
// @Summary 获取当前数据库所有表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"创建成功"}"
// @Router /autoCode/getColumn [get]
export const getColumn = (params) => {
return service({
url: "/autoCode/getColumn",
method: 'get',
params,
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Summary 设置角色资源权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body sysModel.SysAuthority true "设置角色资源权限"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"设置成功"}"
// @Router /authority/setDataAuthority [post]
export const findFile = (params) => {
return service({
url: "/fileUploadAndDownload/findFile",
method: 'get',
params
})
}
export const breakpointContinueFinish = (params) => {
return service({
url: "/fileUploadAndDownload/breakpointContinueFinish",
method: 'post',
params
})
}
export const removeChunk = (data, params) => {
return service({
url: "/fileUploadAndDownload/removeChunk",
method: 'post',
data,
params
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Tags authority
// @Summary 更改角色api权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateAuthorityPatams true "更改角色api权限"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /casbin/UpdateCasbin [post]
export const UpdateCasbin = (data) => {
return service({
url: "/casbin/updateCasbin",
method: 'post',
data
})
}
// @Tags casbin
// @Summary 获取权限列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.CreateAuthorityPatams true "获取权限列表"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /casbin/getPolicyPathByAuthorityId [post]
export const getPolicyPathByAuthorityId = (data) => {
return service({
url: "/casbin/getPolicyPathByAuthorityId",
method: 'post',
data
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Tags SysApi
// @Summary 删除客户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body dbModel.ExaCustomer true "删除客户"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /customer/customer [post]
export const createExaCustomer = (data) => {
return service({
url: "/customer/customer",
method: 'post',
data
})
}
// @Tags SysApi
// @Summary 更新客户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body dbModel.ExaCustomer true "更新客户信息"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /customer/customer [put]
export const updateExaCustomer = (data) => {
return service({
url: "/customer/customer",
method: 'put',
data
})
}
// @Tags SysApi
// @Summary 创建客户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body dbModel.ExaCustomer true "创建客户"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /customer/customer [delete]
export const deleteExaCustomer = (data) => {
return service({
url: "/customer/customer",
method: 'delete',
data
})
}
// @Tags SysApi
// @Summary 获取单一客户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body dbModel.ExaCustomer true "获取单一客户信息"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /customer/customer [get]
export const getExaCustomer = (params) => {
return service({
url: "/customer/customer",
method: 'get',
params
})
}
// @Tags SysApi
// @Summary 获取权限客户列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body modelInterface.PageInfo true "获取权限客户列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /customer/customerList [get]
export const getExaCustomerList = (params) => {
return service({
url: "/customer/customerList",
method: 'get',
params
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Tags email
// @Summary 发送测试邮件
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /email/emailTest [post]
export const emailTest = (data) => {
return service({
url: "/email/emailTest",
method: 'post',
data
})
}
\ No newline at end of file
import service from '@/utils/request';
import { Message } from 'element-ui';
const handleFileError = (res, fileName) => {
if (typeof(res.data) !== "undefined") {
if (res.data.type == "application/json") {
const reader = new FileReader();
reader.onload = function() {
let message = JSON.parse(reader.result).msg;
Message({
showClose: true,
message: message,
type: 'error'
})
};
reader.readAsText(new Blob([res.data]));
}
} else {
var downloadUrl = window.URL.createObjectURL(new Blob([res]));
var a = document.createElement('a');
a.style.display = 'none';
a.href = downloadUrl;
a.download = fileName;
var event = new MouseEvent("click");
a.dispatchEvent(event);
}
}
// @Tags excel
// @Summary 导出Excel
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/octet-stream
// @Param data body model.ExcelInfo true "导出Excel文件信息"
// @Success 200
// @Router /excel/exportExcel [post]
export const exportExcel = (tableData, fileName) => {
service({
url: "/excel/exportExcel",
method: 'post',
data: {
fileName: fileName,
infoList: tableData
},
responseType: 'blob'
}).then((res) => {
handleFileError(res, fileName)
})
}
// @Tags excel
// @Summary 导入Excel文件
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param file formData file true "导入Excel文件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"导入成功"}"
// @Router /excel/importExcel [post]
export const loadExcelData = () => {
return service({
url: "/excel/loadExcel",
method: 'get'
})
}
// @Tags excel
// @Summary 下载模板
// @Security ApiKeyAuth
// @accept multipart/form-data
// @Produce application/json
// @Param fileName query fileName true "模板名称"
// @Success 200
// @Router /excel/downloadTemplate [get]
export const downloadTemplate = (fileName) => {
return service({
url: "/excel/downloadTemplate",
method: 'get',
params: {
fileName: fileName
},
responseType: 'blob'
}).then((res) => {
handleFileError(res, fileName)
})
}
\ No newline at end of file
import service from '@/utils/request';
// @Tags FileUploadAndDownload
// @Summary 分页文件列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body modelInterface.PageInfo true "分页获取文件户列表"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /fileUploadAndDownload/getFileList [post]
export const getFileList = (data) => {
return service({
url: "/fileUploadAndDownload/getFileList",
method: "post",
data
})
}
// @Tags FileUploadAndDownload
// @Summary 删除文件
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body dbModel.FileUploadAndDownload true "传入文件里面id即可"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /fileUploadAndDownload/deleteFile [post]
export const deleteFile = (data) => {
return service({
url: "/fileUploadAndDownload/deleteFile",
method: "post",
data
})
}
\ No newline at end of file
import axios from "axios";
import { Loading } from "element-ui";
let loadingInstance;
let service = axios.create();
service.interceptors.request.use((config) => {
loadingInstance = Loading.service({ fullscreen: true });
return config;
});
service.interceptors.response.use((resp) => {
loadingInstance.close();
return resp;
}, (error) => {
loadingInstance.close();
return error;
});
export function Commits(page) {
return service({
url: "https://codechina.csdn.net/xdorg/vue-xdorg/-/commits/master?page=" +
page,
method: "get",
});
}
export function Members() {
return service({
url: "https://codechina.csdn.net/xdorg/vue-xdorg/-/project_members",
method: "get",
});
}
\ No newline at end of file
import service from '@/utils/request'
// @Tags InitDB
// @Summary 初始化用户数据库
// @Produce application/json
// @Param data body request.InitDB true "初始化数据库参数"
// @Success 200 {string} string "{"code":0,"data":{},"msg":"自动创建数据库成功"}"
// @Router /init/initdb [post]
export const initDB = (data) => {
return service({
url: "/init/initdb",
method: 'post',
data
})
}
// @Tags CheckDB
// @Summary 初始化用户数据库
// @Produce application/json
// @Success 200 {string} string "{"code":0,"data":{},"msg":"探测完成"}"
// @Router /init/checkdb [post]
export const checkDB = () => {
return service({
url: "/init/checkdb",
method: 'post',
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Tags jwt
// @Summary jwt加入黑名单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"拉黑成功"}"
// @Router /jwt/jsonInBlacklist [post]
export const jsonInBlacklist = () => {
return service({
url: "/jwt/jsonInBlacklist",
method: 'post',
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Summary 用户登录 获取动态路由
// @Produce application/json
// @Param 可以什么都不填 调一下即可
// @Router /menu/getMenu [post]
export const asyncMenu = () => {
return service({
url: "/menu/getMenu",
method: 'post',
})
}
// @Summary 获取menu列表
// @Produce application/json
// @Param {
// page int
// pageSize int
// }
// @Router /menu/getMenuList [post]
export const getMenuList = (data) => {
return service({
url: "/menu/getMenuList",
method: 'post',
data
})
}
// @Summary 新增基础menu
// @Produce application/json
// @Param menu Object
// @Router /menu/getMenuList [post]
export const addBaseMenu = (data) => {
return service({
url: "/menu/addBaseMenu",
method: 'post',
data
})
}
// @Summary 获取基础路由列表
// @Produce application/json
// @Param 可以什么都不填 调一下即可
// @Router /menu/getBaseMenuTree [post]
export const getBaseMenuTree = () => {
return service({
url: "/menu/getBaseMenuTree",
method: 'post',
})
}
// @Summary 添加用户menu关联关系
// @Produce application/json
// @Param menus Object authorityId string
// @Router /menu/getMenuList [post]
export const addMenuAuthority = (data) => {
return service({
url: "/menu/addMenuAuthority",
method: 'post',
data
})
}
// @Summary 获取用户menu关联关系
// @Produce application/json
// @Param authorityId string
// @Router /menu/getMenuAuthority [post]
export const getMenuAuthority = (data) => {
return service({
url: "/menu/getMenuAuthority",
method: 'post',
data
})
}
// @Summary 获取用户menu关联关系
// @Produce application/json
// @Param ID float64
// @Router /menu/deleteBaseMenu [post]
export const deleteBaseMenu = (data) => {
return service({
url: "/menu/deleteBaseMenu",
method: 'post',
data
})
}
// @Summary 修改menu列表
// @Produce application/json
// @Param menu Object
// @Router /menu/updateBaseMenu [post]
export const updateBaseMenu = (data) => {
return service({
url: "/menu/updateBaseMenu",
method: 'post',
data
})
}
// @Tags menu
// @Summary 根据id获取菜单
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.GetById true "根据id获取菜单"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /menu/getBaseMenuById [post]
export const getBaseMenuById = (data) => {
return service({
url: "/menu/getBaseMenuById",
method: 'post',
data
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Tags SimpleUploader
// @Summary 断点续传插件版示例
// @Security ApiKeyAuth
// @Produce application/json
// @Param params md5 get "测试文件是否已经存在和判断已经上传过的切片"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /simpleUploader/checkFileMd5 [get]
export const checkFileMd5 = (params) => {
return service({
url: "/simpleUploader/checkFileMd5",
method: 'get',
params
})
}
// @Tags SimpleUploader
// @Summary 合并文件
// @Security ApiKeyAuth
// @Produce application/json
// @Param params md5 get "合并文件"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"合并成功"}"
// @Router /simpleUploader/mergeFileMd5 [get]
export const mergeFileMd5 = (params) => {
return service({
url: "/simpleUploader/mergeFileMd5",
method: 'get',
params
})
}
import service from '@/utils/request'
// @Tags SysDictionary
// @Summary 创建SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionary true "创建SysDictionary"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionary/createSysDictionary [post]
export const createSysDictionary = (data) => {
return service({
url: "/sysDictionary/createSysDictionary",
method: 'post',
data
})
}
// @Tags SysDictionary
// @Summary 删除SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionary true "删除SysDictionary"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysDictionary/deleteSysDictionary [delete]
export const deleteSysDictionary = (data) => {
return service({
url: "/sysDictionary/deleteSysDictionary",
method: 'delete',
data
})
}
// @Tags SysDictionary
// @Summary 更新SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionary true "更新SysDictionary"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysDictionary/updateSysDictionary [put]
export const updateSysDictionary = (data) => {
return service({
url: "/sysDictionary/updateSysDictionary",
method: 'put',
data
})
}
// @Tags SysDictionary
// @Summary 用id查询SysDictionary
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionary true "用id查询SysDictionary"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysDictionary/findSysDictionary [get]
export const findSysDictionary = (params) => {
return service({
url: "/sysDictionary/findSysDictionary",
method: 'get',
params
})
}
// @Tags SysDictionary
// @Summary 分页获取SysDictionary列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "分页获取SysDictionary列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionary/getSysDictionaryList [get]
export const getSysDictionaryList = (params) => {
return service({
url: "/sysDictionary/getSysDictionaryList",
method: 'get',
params
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Tags SysDictionaryDetail
// @Summary 创建SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionaryDetail true "创建SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionaryDetail/createSysDictionaryDetail [post]
export const createSysDictionaryDetail = (data) => {
return service({
url: "/sysDictionaryDetail/createSysDictionaryDetail",
method: 'post',
data
})
}
// @Tags SysDictionaryDetail
// @Summary 删除SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionaryDetail true "删除SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysDictionaryDetail/deleteSysDictionaryDetail [delete]
export const deleteSysDictionaryDetail = (data) => {
return service({
url: "/sysDictionaryDetail/deleteSysDictionaryDetail",
method: 'delete',
data
})
}
// @Tags SysDictionaryDetail
// @Summary 更新SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionaryDetail true "更新SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /sysDictionaryDetail/updateSysDictionaryDetail [put]
export const updateSysDictionaryDetail = (data) => {
return service({
url: "/sysDictionaryDetail/updateSysDictionaryDetail",
method: 'put',
data
})
}
// @Tags SysDictionaryDetail
// @Summary 用id查询SysDictionaryDetail
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysDictionaryDetail true "用id查询SysDictionaryDetail"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /sysDictionaryDetail/findSysDictionaryDetail [get]
export const findSysDictionaryDetail = (params) => {
return service({
url: "/sysDictionaryDetail/findSysDictionaryDetail",
method: 'get',
params
})
}
// @Tags SysDictionaryDetail
// @Summary 分页获取SysDictionaryDetail列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "分页获取SysDictionaryDetail列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysDictionaryDetail/getSysDictionaryDetailList [get]
export const getSysDictionaryDetailList = (params) => {
return service({
url: "/sysDictionaryDetail/getSysDictionaryDetailList",
method: 'get',
params
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Tags SysOperationRecord
// @Summary 删除SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysOperationRecord true "删除SysOperationRecord"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysOperationRecord/deleteSysOperationRecord [delete]
export const deleteSysOperationRecord = (data) => {
return service({
url: "/sysOperationRecord/deleteSysOperationRecord",
method: 'delete',
data
})
}
// @Tags SysOperationRecord
// @Summary 批量删除SysOperationRecord
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "删除SysOperationRecord"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /sysOperationRecord/deleteSysOperationRecord [delete]
export const deleteSysOperationRecordByIds = (data) => {
return service({
url: "/sysOperationRecord/deleteSysOperationRecordByIds",
method: 'delete',
data
})
}
// @Tags SysOperationRecord
// @Summary 分页获取SysOperationRecord列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "分页获取SysOperationRecord列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /sysOperationRecord/getSysOperationRecordList [get]
export const getSysOperationRecordList = (params) => {
return service({
url: "/sysOperationRecord/getSysOperationRecordList",
method: 'get',
params
})
}
\ No newline at end of file
import service from "@/utils/request";
// @Tags systrm
// @Summary 获取配置文件内容
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /system/getSystemConfig [post]
export const getSystemConfig = () => {
return service({
url: "/system/getSystemConfig",
method: "post",
});
};
// @Tags system
// @Summary 设置配置文件内容
// @Security ApiKeyAuth
// @Produce application/json
// @Param data body sysModel.System true
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /system/setSystemConfig [post]
export const setSystemConfig = (data) => {
return service({
url: "/system/setSystemConfig",
method: "post",
data,
});
};
// @Tags system
// @Summary 获取服务器运行状态
// @Security ApiKeyAuth
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"返回成功"}"
// @Router /system/getServerInfo [post]
export const getSystemState = () => {
return service({
url: "/system/getServerInfo",
method: "post",
donNotShowLoading: true
});
};
\ No newline at end of file
import service from '@/utils/request'
// @Summary 用户登录
// @Produce application/json
// @Param data body {username:"string",password:"string"}
// @Router /base/login [post]
export const login = (data) => {
return service({
url: "/base/login",
method: 'post',
data: data
})
}
// @Summary 获取验证码
// @Produce application/json
// @Param data body {username:"string",password:"string"}
// @Router /base/captcha [post]
export const captcha = (data) => {
return service({
url: "/base/captcha",
method: 'post',
data: data
})
}
// @Summary 用户注册
// @Produce application/json
// @Param data body {username:"string",password:"string"}
// @Router /base/resige [post]
export const register = (data) => {
return service({
url: "/user/register",
method: 'post',
data: data
})
}
// @Summary 修改密码
// @Produce application/json
// @Param data body {username:"string",password:"string",newPassword:"string"}
// @Router /user/changePassword [post]
export const changePassword = (data) => {
return service({
url: "/user/changePassword",
method: 'post',
data: data
})
}
// @Tags User
// @Summary 分页获取用户列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body modelInterface.PageInfo true "分页获取用户列表"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /user/getUserList [post]
export const getUserList = (data) => {
return service({
url: "/user/getUserList",
method: 'post',
data: data
})
}
// @Tags User
// @Summary 设置用户权限
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body api.SetUserAuth true "设置用户权限"
// @Success 200 {string} json "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/setUserAuthority [post]
export const setUserAuthority = (data) => {
return service({
url: "/user/setUserAuthority",
method: 'post',
data: data
})
}
// @Tags SysUser
// @Summary 删除用户
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.SetUserAuth true "删除用户"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/deleteUser [delete]
export const deleteUser = (data) => {
return service({
url: "/user/deleteUser",
method: 'delete',
data: data
})
}
// @Tags SysUser
// @Summary 设置用户信息
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.SysUser true "设置用户信息"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"修改成功"}"
// @Router /user/setUserInfo [put]
export const setUserInfo = (data) => {
return service({
url: "/user/setUserInfo",
method: 'put',
data: data
})
}
\ No newline at end of file
import service from '@/utils/request'
// @Tags WorkflowProcess
// @Summary 创建WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "创建WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/createWorkflowProcess [post]
export const createWorkflowProcess = (data) => {
return service({
url: "/workflowProcess/createWorkflowProcess",
method: 'post',
data
})
}
// @Tags WorkflowProcess
// @Summary 删除WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "删除WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /workflowProcess/deleteWorkflowProcess [delete]
export const deleteWorkflowProcess = (data) => {
return service({
url: "/workflowProcess/deleteWorkflowProcess",
method: 'delete',
data
})
}
// @Tags WorkflowProcess
// @Summary 删除WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.IdsReq true "批量删除WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"删除成功"}"
// @Router /workflowProcess/deleteWorkflowProcess [delete]
export const deleteWorkflowProcessByIds = (data) => {
return service({
url: "/workflowProcess/deleteWorkflowProcessByIds",
method: 'delete',
data
})
}
// @Tags WorkflowProcess
// @Summary 更新WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "更新WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"更新成功"}"
// @Router /workflowProcess/updateWorkflowProcess [put]
export const updateWorkflowProcess = (data) => {
return service({
url: "/workflowProcess/updateWorkflowProcess",
method: 'put',
data
})
}
// @Tags WorkflowProcess
// @Summary 用id查询WorkflowProcess
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "用id查询WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /workflowProcess/findWorkflowProcess [get]
export const findWorkflowProcess = (params) => {
return service({
url: "/workflowProcess/findWorkflowProcess",
method: 'get',
params
})
}
// @Tags WorkflowProcess
// @Summary 分页获取WorkflowProcess列表
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.PageInfo true "分页获取WorkflowProcess列表"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getWorkflowProcessList [get]
export const getWorkflowProcessList = (params) => {
return service({
url: "/workflowProcess/getWorkflowProcessList",
method: 'get',
params
})
}
// @Tags WorkflowProcess
// @Summary 用id查询工作流步骤
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body model.WorkflowProcess true "用id查询WorkflowProcess"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"查询成功"}"
// @Router /workflowProcess/findWorkflowStep [get]
export const findWorkflowStep = (params) => {
return service({
url: "/workflowProcess/findWorkflowStep",
method: 'get',
params
})
}
// @Tags ExaWfLeave
// @Summary 创建ExaWfLeave
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/startWorkflow [post]
export const startWorkflow = (data, params = { businessType: data.wf.businessType }) => {
return service({
url: "/workflowProcess/startWorkflow",
method: 'post',
data,
params
})
}
// @Tags ExaWfLeave
// @Summary 创建ExaWfLeave
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/completeWorkflowMove [post]
export const completeWorkflowMove = (data, params = { businessType: data.wf.businessType }) => {
return service({
url: "/workflowProcess/completeWorkflowMove",
method: 'post',
data,
params
})
}
// @Tags WorkflowProcess
// @Summary 我发起的工作流
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getMyStated [get]
export const getMyStated = () => {
return service({
url: "/workflowProcess/getMyStated",
method: 'get',
})
}
// @Tags WorkflowProcess
// @Summary 我发起的工作流
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getMyNeed [get]
export const getMyNeed = () => {
return service({
url: "/workflowProcess/getMyNeed",
method: 'get',
})
}
// @Tags WorkflowProcess
// @Summary 根据id获取当前节点详情和历史
// @Security ApiKeyAuth
// @accept application/json
// @Produce application/json
// @Param data body request.GetById true "根据id获取当前节点详情和过往"
// @Success 200 {string} string "{"success":true,"data":{},"msg":"获取成功"}"
// @Router /workflowProcess/getWorkflowMoveByID [get]
export const getWorkflowMoveByID = (params) => {
return service({
url: "/workflowProcess/getWorkflowMoveByID",
method: 'get',
params
})
}
\ No newline at end of file
<svg xmlns='http://www.w3.org/2000/svg' width='100%'><rect fill='#29adff' width='540' height='450'/><defs><linearGradient id='a' gradientUnits='userSpaceOnUse' x1='0' x2='0' y1='0' y2='100%' gradientTransform='rotate(279,720,373)'><stop offset='0' stop-color='#29adff'/><stop offset='1' stop-color='#42b983'/></linearGradient><pattern patternUnits='userSpaceOnUse' id='b' width='300' height='250' x='0' y='0' viewBox='0 0 1080 900'><g fill-opacity='0'><polygon fill='#444' points='90 150 0 300 180 300'/><polygon points='90 150 180 0 0 0'/><polygon fill='#AAA' points='270 150 360 0 180 0'/><polygon fill='#DDD' points='450 150 360 300 540 300'/><polygon fill='#999' points='450 150 540 0 360 0'/><polygon points='630 150 540 300 720 300'/><polygon fill='#DDD' points='630 150 720 0 540 0'/><polygon fill='#444' points='810 150 720 300 900 300'/><polygon fill='#FFF' points='810 150 900 0 720 0'/><polygon fill='#DDD' points='990 150 900 300 1080 300'/><polygon fill='#444' points='990 150 1080 0 900 0'/><polygon fill='#DDD' points='90 450 0 600 180 600'/><polygon points='90 450 180 300 0 300'/><polygon fill='#666' points='270 450 180 600 360 600'/><polygon fill='#AAA' points='270 450 360 300 180 300'/><polygon fill='#DDD' points='450 450 360 600 540 600'/><polygon fill='#999' points='450 450 540 300 360 300'/><polygon fill='#999' points='630 450 540 600 720 600'/><polygon fill='#FFF' points='630 450 720 300 540 300'/><polygon points='810 450 720 600 900 600'/><polygon fill='#DDD' points='810 450 900 300 720 300'/><polygon fill='#AAA' points='990 450 900 600 1080 600'/><polygon fill='#444' points='990 450 1080 300 900 300'/><polygon fill='#222' points='90 750 0 900 180 900'/><polygon points='270 750 180 900 360 900'/><polygon fill='#DDD' points='270 750 360 600 180 600'/><polygon points='450 750 540 600 360 600'/><polygon points='630 750 540 900 720 900'/><polygon fill='#444' points='630 750 720 600 540 600'/><polygon fill='#AAA' points='810 750 720 900 900 900'/><polygon fill='#666' points='810 750 900 600 720 600'/><polygon fill='#999' points='990 750 900 900 1080 900'/><polygon fill='#999' points='180 0 90 150 270 150'/><polygon fill='#444' points='360 0 270 150 450 150'/><polygon fill='#FFF' points='540 0 450 150 630 150'/><polygon points='900 0 810 150 990 150'/><polygon fill='#222' points='0 300 -90 450 90 450'/><polygon fill='#FFF' points='0 300 90 150 -90 150'/><polygon fill='#FFF' points='180 300 90 450 270 450'/><polygon fill='#666' points='180 300 270 150 90 150'/><polygon fill='#222' points='360 300 270 450 450 450'/><polygon fill='#FFF' points='360 300 450 150 270 150'/><polygon fill='#444' points='540 300 450 450 630 450'/><polygon fill='#222' points='540 300 630 150 450 150'/><polygon fill='#AAA' points='720 300 630 450 810 450'/><polygon fill='#666' points='720 300 810 150 630 150'/><polygon fill='#FFF' points='900 300 810 450 990 450'/><polygon fill='#999' points='900 300 990 150 810 150'/><polygon points='0 600 -90 750 90 750'/><polygon fill='#666' points='0 600 90 450 -90 450'/><polygon fill='#AAA' points='180 600 90 750 270 750'/><polygon fill='#444' points='180 600 270 450 90 450'/><polygon fill='#444' points='360 600 270 750 450 750'/><polygon fill='#999' points='360 600 450 450 270 450'/><polygon fill='#666' points='540 600 630 450 450 450'/><polygon fill='#222' points='720 600 630 750 810 750'/><polygon fill='#FFF' points='900 600 810 750 990 750'/><polygon fill='#222' points='900 600 990 450 810 450'/><polygon fill='#DDD' points='0 900 90 750 -90 750'/><polygon fill='#444' points='180 900 270 750 90 750'/><polygon fill='#FFF' points='360 900 450 750 270 750'/><polygon fill='#AAA' points='540 900 630 750 450 750'/><polygon fill='#FFF' points='720 900 810 750 630 750'/><polygon fill='#222' points='900 900 990 750 810 750'/><polygon fill='#222' points='1080 300 990 450 1170 450'/><polygon fill='#FFF' points='1080 300 1170 150 990 150'/><polygon points='1080 600 990 750 1170 750'/><polygon fill='#666' points='1080 600 1170 450 990 450'/><polygon fill='#DDD' points='1080 900 1170 750 990 750'/></g></pattern></defs><rect x='0' y='0' fill='url(#a)' width='100%' height='100%'/><rect x='0' y='0' fill='url(#b)' width='100%' height='100%'/></svg>
\ No newline at end of file
<template>
<el-drawer title="媒体库" :visible.sync="drawer">
<div style="display:flex;justify-content:space-around;flex-wrap:wrap;padding-top:40px">
<el-image
class="header-img-box-list"
:src="(item.url && item.url.slice(0, 4) !== 'http')?path+item.url:item.url"
v-for="(item,key) in picList"
:key="key"
@click.native="chooseImg(item.url,target,targetKey)"
>
<div slot="error" class="header-img-box-list">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
</div>
</el-drawer>
</template>
<script>
const path = process.env.VUE_APP_BASE_API
import { getFileList } from "@/api/fileUploadAndDownload";
export default {
props: {
target: [Object],
targetKey: [String]
},
data() {
return {
drawer: false,
picList: [],
path:path
};
},
methods: {
chooseImg(url, target, targetKey) {
if(target&&targetKey){
target[targetKey] = url;
}
this.$emit("enter-img", url);
this.drawer = false;
},
async open() {
const res = await getFileList({ page: 1, pageSize: 9999 });
this.picList = res.data.list;
this.drawer = true;
}
}
};
</script>
<style lang="scss">
.header-img-box-list {
width: 180px;
height: 180px;
border: 1px dashed #ccc;
border-radius: 20px;
text-align: center;
line-height: 180px;
cursor: pointer;
}
</style>
\ No newline at end of file
<template>
<span class="headerAvatar">
<template v-if="picType === 'avatar'">
<el-avatar :size="30" :src="avatar" v-if="userInfo.headerImg"></el-avatar>
<el-avatar :size="30" :src="require('@/assets/noBody.png')" v-else></el-avatar>
</template>
<template v-if="picType === 'img'">
<img :src="avatar" class="avatar" v-if="userInfo.headerImg" />
<img :src="require('@/assets/noBody.png')" class="avatar" v-else/>
</template>
<template v-if="picType === 'file'">
<img :src="file" class="file"/>
</template>
</span>
</template>
<script>
import { mapGetters } from 'vuex'
const path = process.env.VUE_APP_BASE_API
export default {
name: "customPic",
props: {
picType: {
type: String,
required: false,
default: "avatar"
},
picSrc: {
type: String,
required: false,
default: ""
}
},
data(){
return{
path: path,
}
},
computed:{
...mapGetters('user', ['userInfo']),
avatar(){
if(this.picSrc === ''){
if(this.userInfo.headerImg !== '' && this.userInfo.headerImg.slice(0, 4) === "http"){
return this.userInfo.headerImg
}
return this.path + this.userInfo.headerImg
}else{
if(this.picSrc !== '' && this.picSrc.slice(0, 4) === "http"){
return this.picSrc
}
return this.path + this.picSrc
}
},
file(){
if(this.picSrc && this.picSrc.slice(0, 4) !== "http"){
return this.path + this.picSrc
}
return this.picSrc
}
}
}
</script>
<style scoped>
.headerAvatar{
display: flex;
justify-content: center;
align-items: center;
}
.file{
width: 80px;
height: 80px;
position: relative;
}
</style>
\ No newline at end of file
<!--
<div>
带压缩的上传
<upload-image v-model="imageUrl" :fileSize="512" />
已上传文件 {{ imageUrl }}
</div>
-->
<template>
<div>
<el-upload
class="image-uploader"
:action="`${path}/fileUploadAndDownload/upload`"
:headers="{ 'x-token': token }"
:show-file-list="false"
:on-success="handleImageSuccess"
:before-upload="beforeImageUpload"
:multiple="false"
>
<img v-if="imageUrl" :src="path + imageUrl" class="image" />
<i v-else class="el-icon-plus image-uploader-icon"></i>
</el-upload>
</div>
</template>
<script>
const path = process.env.VUE_APP_BASE_API;
import { mapGetters } from "vuex";
import ImageCompress from "@/utils/image.js";
export default {
name: "upload-image",
model: {
prop: "imageUrl",
event: "change",
},
props: {
imageUrl: {
type: String,
default: "",
},
fileSize: {
type: Number,
default: 2048, // 2M 超出后执行压缩
},
maxWH: {
type: Number,
default: 1920, // 图片长宽上限
},
},
data() {
return {
path: path,
};
},
computed: {
...mapGetters("user", ["userInfo", "token"]),
},
methods: {
beforeImageUpload(file) {
let isRightSize = file.size / 1024 < this.fileSize;
if (!isRightSize) {
// 压缩
let compress = new ImageCompress(file, this.fileSize, this.maxWH);
return compress.compress();
}
return isRightSize;
},
handleImageSuccess(res) {
// this.imageUrl = URL.createObjectURL(file.raw);
const { data } = res;
if (data.file) {
this.$emit("change", data.file.url);
}
},
},
};
</script>
<style lang="scss" scoped>
.image-uploader {
border: 1px dashed #d9d9d9;
width: 180px;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.image-uploader {
border-color: #409eff;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.image {
width: 178px;
height: 178px;
display: block;
}
</style>
// 权限按钮展示指令
import { store } from '@/store/index'
export const auth = (Vue) => {
Vue.directive('auth', {
// 当被绑定的元素插入到 DOM 中时……
bind: function (el, binding) {
const userInfo = store.getters['user/userInfo']
let type = ""
switch (Object.prototype.toString.call(binding.value)) {
case "[object Array]":
type = "Array"
break;
case "[object String]":
type = "String"
break;
case "[object Number]":
type = "Number"
break;
default:
type = ""
break;
}
if (type === "") {
/* eslint-disable */
console.error("v-auth必须是Array,Number,String属性,暂不支持其他属性")
/* eslint-enable */
return
}
const waitUse = binding.value.toString().split(",")
let flag = waitUse.some(item=>item==userInfo.authorityId)
if (binding.modifiers.not) {
flag = !flag
}
if(!flag){
el.style.display = 'none'
}
}
})
}
import Vue from 'vue'
import App from './App.vue'
// 按需引入element
import {
Button,
Select,
Dialog,
Form,
Input,
FormItem,
Option,
Loading,
Message,
Container,
Card,
Dropdown,
DropdownMenu,
DropdownItem,
Row,
Col,
Menu,
Submenu,
MenuItem,
Aside,
Main,
Badge,
Header,
Tabs,
Breadcrumb,
BreadcrumbItem,
Scrollbar,
Avatar,
TabPane,
Divider,
Table,
TableColumn,
Cascader,
Checkbox,
CheckboxGroup,
Pagination,
Tag,
Drawer,
Tree,
Popover,
Switch,
Collapse,
CollapseItem,
Tooltip,
DatePicker,
InputNumber,
Steps,
Upload,
Progress,
MessageBox,
Image
} from 'element-ui';
Vue.use(Button);
Vue.use(Select);
Vue.use(Dialog);
Vue.use(Form);
Vue.use(FormItem);
Vue.use(Input);
Vue.use(Option);
Vue.use(Container);
Vue.use(Card);
Vue.use(Dropdown);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Row);
Vue.use(Col);
Vue.use(Menu);
Vue.use(Submenu);
Vue.use(MenuItem);
Vue.use(Aside);
Vue.use(Main);
Vue.use(Badge);
Vue.use(Header);
Vue.use(Tabs);
Vue.use(Breadcrumb);
Vue.use(BreadcrumbItem);
Vue.use(Avatar);
Vue.use(TabPane);
Vue.use(Divider);
Vue.use(Table);
Vue.use(TableColumn);
Vue.use(Checkbox);
Vue.use(Cascader);
Vue.use(Tag);
Vue.use(Pagination);
Vue.use(Drawer);
Vue.use(Tree);
Vue.use(CheckboxGroup);
Vue.use(Popover);
Vue.use(InputNumber);
Vue.use(Switch);
Vue.use(Collapse);
Vue.use(CollapseItem);
Vue.use(Tooltip);
Vue.use(DatePicker);
Vue.use(Steps);
Vue.use(Upload);
Vue.use(Progress);
Vue.use(Scrollbar);
Vue.use(Loading.directive);
Vue.use(Image)
Vue.prototype.$loading = Loading.service;
Vue.prototype.$message = Message;
Vue.prototype.$confirm = MessageBox.confirm;
Dialog.props.closeOnClickModal.default = false
// 引入封装的router
import router from '@/router/index'
// time line css
import '../node_modules/timeline-vuejs/dist/timeline-vuejs.css'
import '@/permission'
import { store } from '@/store/index'
Vue.config.productionTip = false
// 路由守卫
import Bus from '@/utils/bus.js'
Vue.use(Bus)
import APlayer from '@moefe/vue-aplayer';
Vue.use(APlayer, {
defaultCover: 'https://github.com/u3u.png',
productionTip: true,
});
import { auth } from '@/directive/auth'
// 按钮权限指令
auth(Vue)
import uploader from 'vue-simple-uploader'
Vue.use(uploader)
export default new Vue({
render: h => h(App),
router,
store
}).$mount('#app')
console.log(`
欢迎使用 Vue-XDORG
当前版本: V1.0
微信公众号: 编程者联盟
默认自动化文档地址:http://127.0.0.1:` + process.env.VUE_APP_SERVER_PORT + `/swagger/index.html
默认前端文件运行地址:http://127.0.0.1:`+ process.env.VUE_APP_CLI_PORT`
合作邮箱:xdorg1268@163.com
`)
\ No newline at end of file
import { getDict } from "@/utils/dictionary";
export default {
data() {
return {
page: 1,
total: 10,
pageSize: 10,
tableData: [],
searchInfo: {}
}
},
methods: {
filterDict(value, type) {
const rowLabel = this[type + "Options"] && this[type + "Options"].filter(item => item.value == value)
return rowLabel && rowLabel[0] && rowLabel[0].label
},
async getDict(type) {
const dicts = await getDict(type)
this[type + "Options"] = dicts
return dicts
},
handleSizeChange(val) {
this.pageSize = val
this.getTableData()
},
handleCurrentChange(val) {
this.page = val
this.getTableData()
},
async getTableData(page = this.page, pageSize = this.pageSize) {
const table = await this.listApi({ page, pageSize, ...this.searchInfo })
if (table.code == 0) {
this.tableData = table.data.list
this.total = table.data.total
this.page = table.data.page
this.pageSize = table.data.pageSize
}
}
}
}
\ No newline at end of file
import router from './router'
import { store } from '@/store/index'
import getPageTitle from '@/utils/page'
let asyncRouterFlag = 0
const whiteList = ['login','init']
router.beforeEach(async(to, from, next) => {
const token = store.getters['user/token']
// 在白名单中的判断情况
//修改网页标签名称
document.title = getPageTitle(to.meta.title)
if (whiteList.indexOf(to.name) > -1) {
if (token) {
next({ name: store.getters["user/userInfo"].authority.defaultRouter })
} else {
next()
}
} else {
// 不在白名单中并且已经登陆的时候
if (token) {
// 添加flag防止多次获取动态路由和栈溢出
if (!asyncRouterFlag && store.getters['router/asyncRouters'].length == 0) {
asyncRouterFlag++
await store.dispatch('router/SetAsyncRouter')
const asyncRouters = store.getters['router/asyncRouters']
router.addRoutes(asyncRouters)
next({...to, replace: true })
} else {
next()
}
}
// 不在白名单中并且未登陆的时候
if (!token) {
next({
name: "login",
query: {
redirect: document.location.hash
}
})
}
}
})
\ No newline at end of file
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
//获取原型对象上的push函数
const originalPush = Router.prototype.push
//修改原型对象中的push方法
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
const baseRouters = [{
path: '/',
redirect: '/login'
},
{
path: "/init",
name: 'init',
component: () =>
import('@/view/init/init.vue')
},
{
path: '/login',
name: 'login',
component: () =>
import('@/view/login/login.vue')
}
]
// 需要通过后台数据来生成的组件
const createRouter = () => new Router({
routes: baseRouters
})
const router = createRouter()
export default router
import Vue from 'vue'
import Vuex from 'vuex'
import VuexPersistence from 'vuex-persist'
import { user } from "@/store/module/user"
import { router } from "@/store/module/router"
import { dictionary } from "@/store/module/dictionary"
Vue.use(Vuex)
const vuexLocal = new VuexPersistence({
storage: window.localStorage,
modules: ['user']
})
export const store = new Vuex.Store({
modules: {
user,
router,
dictionary
},
plugins: [vuexLocal.plugin]
})
\ No newline at end of file
import { findSysDictionary } from '@/api/sysDictionary'
export const dictionary = {
namespaced: true,
state: {
dictionaryMap: {},
},
mutations: {
setDictionaryMap(state, dictionaryMap) {
state.dictionaryMap = { ...state.dictionaryMap, ...dictionaryMap }
},
},
actions: {
// 从后台获取动态路由
async getDictionary({ commit, state }, type) {
if (state.dictionaryMap[type]) {
return state.dictionaryMap[type]
} else {
const res = await findSysDictionary({ type })
if (res.code == 0) {
const dictionaryMap = {}
const dict = []
res.data.resysDictionary.sysDictionaryDetails && res.data.resysDictionary.sysDictionaryDetails.map(item => {
dict.push({
label: item.label,
value: item.value
})
})
dictionaryMap[res.data.resysDictionary.type] = dict
commit("setDictionaryMap", dictionaryMap)
return state.dictionaryMap[type]
}
}
}
},
getters:{
getDictionary(state){
return state.dictionaryMap
}
}
}
\ No newline at end of file
import { asyncRouterHandle } from '@/utils/asyncRouter';
import { asyncMenu } from '@/api/menu'
const routerList = []
const formatRouter = (routes) => {
routes && routes.map(item => {
if ((!item.children || item.children.every(ch => ch.hidden)) && item.name != '404') {
routerList.push({ label: item.meta.title, value: item.name })
}
if (item.children && item.children.length > 0) {
formatRouter(item.children)
}
})
}
export const router = {
namespaced: true,
state: {
asyncRouters: [],
routerList: routerList,
},
mutations: {
setRouterList(state, routerList) {
state.routerList = routerList
},
// 设置动态路由
setAsyncRouter(state, asyncRouters) {
state.asyncRouters = asyncRouters
},
},
actions: {
// 从后台获取动态路由
async SetAsyncRouter({ commit }) {
const baseRouter = [{
path: '/layout',
name: 'layout',
component: "view/layout/index.vue",
meta: {
title: "底层layout"
},
children: []
}]
const asyncRouterRes = await asyncMenu()
if(asyncRouterRes.code !=0){
return
}
const asyncRouter = asyncRouterRes.data&&asyncRouterRes.data.menus
asyncRouter.push({
path: "404",
name: "404",
hidden: true,
meta: {
title: "迷路了*。*",
},
component: 'view/error/index.vue'
})
formatRouter(asyncRouter)
baseRouter[0].children = asyncRouter
baseRouter.push({
path: '*',
redirect: '/layout/404'
})
asyncRouterHandle(baseRouter)
commit('setAsyncRouter', baseRouter)
commit('setRouterList', routerList)
return true
}
},
getters: {
// 获取动态路由
asyncRouters(state) {
return state.asyncRouters
},
routerList(state) {
return state.routerList
},
defaultRouter(state) {
return state.defaultRouter
}
}
}
\ No newline at end of file
import { login } from '@/api/user'
import { jsonInBlacklist } from '@/api/jwt'
import router from '@/router/index'
export const user = {
namespaced: true,
state: {
userInfo: {
uuid: "",
nickName: "",
headerImg: "",
authority: "",
},
token: "",
},
mutations: {
setUserInfo(state, userInfo) {
// 这里的 `state` 对象是模块的局部状态
state.userInfo = userInfo
},
setToken(state, token) {
// 这里的 `state` 对象是模块的局部状态
state.token = token
},
NeedInit(state){
state.userInfo = {}
state.token = ""
sessionStorage.clear()
router.push({ name: 'init', replace: true })
},
LoginOut(state) {
state.userInfo = {}
state.token = ""
sessionStorage.clear()
router.push({ name: 'login', replace: true })
window.location.reload()
},
ResetUserInfo(state, userInfo = {}) {
state.userInfo = {...state.userInfo,
...userInfo
}
}
},
actions: {
async LoginIn({ commit, dispatch, rootGetters, getters }, loginInfo) {
const res = await login(loginInfo)
if (res.code == 0) {
commit('setUserInfo', res.data.user)
commit('setToken', res.data.token)
await dispatch('router/SetAsyncRouter', {}, { root: true })
const asyncRouters = rootGetters['router/asyncRouters']
router.addRoutes(asyncRouters)
// const redirect = router.history.current.query.redirect
// console.log(redirect)
// if (redirect) {
// router.push({ path: redirect })
// } else {
router.push({ name: getters["userInfo"].authority.defaultRouter })
// }
return true
}
},
async LoginOut({ commit }) {
const res = await jsonInBlacklist()
if (res.code == 0) {
commit("LoginOut")
}
}
},
getters: {
userInfo(state) {
return state.userInfo
},
token(state) {
return state.token
},
}
}
\ No newline at end of file
body {
background-color: #fffaf0;
}
ul {
padding: 0;
}
li {
list-style: none;
}
.container {
background-image: linear-gradient(to top, #fcf3d8 30%, #eaafc8, #654ea3);
background-image: -webkit-linear-gradient(to bottom, #fcf3d8 30%, #eaafc8, #654ea3);
background-color: #654ea3;
height: 450px;
width: 450px;
border-radius: 100%;
position: relative;
transform: translate(-50%, -50%);
left: 50%;
top: 225px;
overflow: hidden;
}
.mountain-range {
position: absolute;
width: 100%;
height: 100px;
top: 50%;
display: flex;
justify-content: center;
padding: 0;
}
.mountain-range .mountain:nth-child(1) {
width: 0;
height: 0;
margin-top: 32px;
margin-left: -60%;
border-left: 183px solid transparent;
border-right: 183px solid transparent;
border-bottom: 91.5px solid #75bbff;
}
.mountain-range .mountain:nth-child(2) {
width: 0;
height: 0;
margin-top: 27px;
margin-left: -60%;
border-left: 195px solid transparent;
border-right: 195px solid transparent;
border-bottom: 97.5px solid #75bbff;
}
.mountain-range .mountain:nth-child(3) {
width: 0;
height: 0;
margin-top: 24px;
margin-left: -60%;
border-left: 198px solid transparent;
border-right: 198px solid transparent;
border-bottom: 99px solid #75bbff;
}
.mountain-range .mountain:nth-child(4) {
width: 0;
height: 0;
margin-top: 35px;
margin-left: -60%;
border-left: 154px solid transparent;
border-right: 154px solid transparent;
border-bottom: 77px solid #75bbff;
}
.mountain-range .mountain:nth-child(5) {
width: 0;
height: 0;
margin-top: 20px;
margin-left: -60%;
border-left: 150px solid transparent;
border-right: 150px solid transparent;
border-bottom: 75px solid #75bbff;
}
.mountain-range .mountain:nth-child(6) {
width: 0;
height: 0;
margin-top: 33px;
margin-left: -60%;
border-left: 198px solid transparent;
border-right: 198px solid transparent;
border-bottom: 99px solid #75bbff;
}
.mountain-range .mountain:nth-child(7) {
width: 0;
height: 0;
margin-top: 37px;
margin-left: -60%;
border-left: 152px solid transparent;
border-right: 152px solid transparent;
border-bottom: 76px solid #75bbff;
}
.mountain-range .mountain:nth-child(8) {
width: 0;
height: 0;
margin-top: 27px;
margin-left: -60%;
border-left: 166px solid transparent;
border-right: 166px solid transparent;
border-bottom: 83px solid #75bbff;
}
.forest {
position: absolute;
width: 100%;
height: 100px;
top: 65%;
}
.forest .hill {
position: absolute;
background-color: #82d9a2;
}
.forest .hill:nth-child(1) {
width: 600px;
height: 300px;
top: -10px;
left: -150px;
border-top-left-radius: 300px 150px;
border-top-right-radius: 300px 150px;
border-bottom-left-radius: 300px 150px;
border-bottom-right-radius: 300px 150px;
box-shadow: inset 20px 30px 50px #2d79a0;
}
.forest .hill:nth-child(2) {
width: 500px;
height: 250px;
top: -5px;
left: 100px;
border-top-left-radius: 250px 125px;
border-top-right-radius: 250px 125px;
border-bottom-left-radius: 250px 125px;
border-bottom-right-radius: 250px 125px;
box-shadow: inset 20px 30px 50px #2d79a0;
}
.forest .hill:nth-child(3) {
width: 500px;
height: 250px;
top: 17px;
left: -180px;
border-top-left-radius: 250px 125px;
border-top-right-radius: 250px 125px;
border-bottom-left-radius: 250px 125px;
border-bottom-right-radius: 250px 125px;
box-shadow: inset 20px 30px 50px #2d79a0;
}
.grass {
position: absolute;
width: 600px;
height: 300px;
border-radius: 300px / 150px;
top: 75%;
left: -100px;
background: #82d9a2;
box-shadow: inset 20px 30px 60px #2d79a0;
}
.pokemon {
position: absolute;
width: 300px;
height: 110px;
left: calc(53% - 150px);
}
.poke {
position: absolute;
width: 100px;
height: 100px;
}
#bulbasaur:before {
content: '';
position: absolute;
width: 100px;
height: 50px;
background: rgba(0, 0, 0, 0.2);
border-radius: 100%;
top: 50px;
left: 15px;
transform: rotate(-15deg);
}
#bulbasaur .head {
position: absolute;
width: 60px;
height: 45px;
background-color: #00efd0;
border-top-left-radius: 50% 25px;
border-top-right-radius: 50% 25px;
border-bottom-left-radius: 18px;
border-bottom-right-radius: 18px;
left: 55px;
}
#bulbasaur .ear {
position: absolute;
height: 20px;
width: 23px;
background-color: #00efd0;
border-top-left-radius: 50px 90px;
border-top-right-radius: 50px 90px;
transform-origin: center bottom;
}
#bulbasaur .ear:nth-child(1) {
transform: rotate(-45deg);
left: 52px;
top: -5px;
animation: rotateLeftBulbEar 2s alternate infinite;
}
#bulbasaur .ear:nth-child(2) {
transform: rotate(45deg);
left: 87px;
top: -5px;
animation: rotateRightBulbEar 2s alternate infinite;
}
#bulbasaur .bulba-body {
position: relative;
width: 65px;
height: 55px;
background-color: #00efd0;
left: 42px;
top: 20px;
border-radius: 100%;
box-shadow: inset 10px -10px #00dbbe;
animation: bodyBreathe 2s alternate infinite;
}
#bulbasaur .bulba-body:before,
#bulbasaur .bulba-body:after {
content: '';
position: absolute;
}
#bulbasaur .bulba-body:before {
width: 10px;
height: 13px;
top: 33px;
left: 8px;
background-color: #00c6ac;
border-bottom-left-radius: 100%;
border-bottom-right-radius: 30%;
border-top-right-radius: 30%;
border-top-left-radius: 50%;
transform: rotate(-45deg);
}
#bulbasaur .bulba-body:after {
width: 8px;
height: 8px;
top: 30px;
left: 53px;
background-color: #00dbbe;
border-bottom-left-radius: 100%;
border-bottom-right-radius: 30%;
border-top-right-radius: 30%;
border-top-left-radius: 50%;
transform: rotate(65deg);
}
#bulbasaur .leg {
position: absolute;
width: 20px;
height: 40px;
background-color: #00efd0;
border-bottom-left-radius: 35px 110%;
border-bottom-right-radius: 35px 110%;
box-shadow: inset 10px -20px #00d6ba;
left: 90px;
top: 30px;
}
#bulbasaur .bulbs {
position: absolute;
top: -1px;
width: 55px;
height: 55px;
left: 50px;
transform-origin: center;
transform: rotate(45deg);
z-index: 3;
animation: bulbaBreathe 2s alternate infinite;
}
#bulbasaur .bulbs:before,
#bulbasaur .bulbs:after {
content: '';
position: absolute;
height: 45px;
width: 45px;
border-radius: 0 50% 50% 50%;
}
#bulbasaur .bulbs:before {
transform: translate(-5px, 10px) rotate(7deg);
background-color: #007061;
}
#bulbasaur .bulbs:after {
transform: translate(10px, -5px) rotate(-7deg);
background-color: #008a78;
}
#bulbasaur .bulb {
position: absolute;
top: 10px;
right: 2px;
left: 3px;
width: 90%;
height: 90%;
border-radius: 0 50% 100% 50%;
background-color: #00a38e;
z-index: 4;
box-shadow: inset 1px -5px #009480;
}
#pikachu {
left: -.1em;
}
#pikachu:before {
content: '';
position: absolute;
width: 60px;
height: 80px;
background: rgba(0, 0, 0, 0.2);
border-radius: 100%;
top: 50px;
left: 115px;
transform: rotate(40deg);
}
#pikachu .ear {
position: absolute;
height: 40px;
width: 18px;
background-color: #fff069;
border-top-left-radius: 60px 150px;
border-top-right-radius: 60px 150px;
transform-origin: center bottom;
overflow: hidden;
}
#pikachu .ear:nth-child(1) {
transform: rotate(-35deg);
left: 125px;
top: -35px;
animation: rotateLeftEar 1s alternate infinite;
}
#pikachu .ear:nth-child(1):after {
content: '';
position: absolute;
background-color: #444;
width: 150%;
height: 15px;
left: -8px;
transform: rotate(-30deg);
}
#pikachu .ear:nth-child(2) {
transform: rotate(50deg);
left: 157px;
top: -30px;
animation: rotateRightEar 1s alternate infinite;
}
#pikachu .ear:nth-child(2):after {
content: '';
position: absolute;
background-color: #444;
width: 150%;
height: 15px;
left: 2px;
transform: rotate(30deg);
}
#pikachu .hand {
position: absolute;
height: 38px;
width: 15px;
background-color: #fff069;
border-top-left-radius: 60px 150px;
border-top-right-radius: 60px 150px;
transform-origin: center bottom;
left: 123px;
top: 5px;
z-index: 5;
transform: rotate(-40deg);
animation: pikaPat .7s alternate infinite;
}
#pikachu .head {
position: absolute;
width: 60px;
height: 45px;
background-color: #fff069;
border-top-left-radius: 50% 25px;
border-top-right-radius: 50% 25px;
border-bottom-left-radius: 18px;
border-bottom-right-radius: 18px;
left: 120px;
width: 60px;
height: 55px;
top: -12px;
}
#pikachu .pika-body {
position: absolute;
width: 55px;
height: 55px;
background-color: #fff069;
left: 122px;
top: 20px;
border-radius: 22px;
}
#pikachu .pika-body:before,
#pikachu .pika-body:after {
content: '';
position: absolute;
background-color: #9c5200;
width: 70%;
height: 7px;
left: 13px;
border-radius: 100%;
}
#pikachu .pika-body:before {
top: 15px;
z-index: 2;
}
#pikachu .pika-body:after {
top: 30px;
}
#pikachu .pika-tail {
position: absolute;
height: 25px;
width: 16px;
background: #9c5200;
border-radius: 5px;
left: 150px;
top: 40px;
transform-origin: bottom center;
transform: rotate(55deg);
box-shadow: -2px 2px 1px rgba(68, 68, 68, 0.2);
z-index: 2;
animation: rotateTail 2s alternate infinite;
}
#pikachu .pika-tail:before,
#pikachu .pika-tail:after {
content: '';
transform-origin: bottom center;
position: absolute;
background-color: #fff069;
}
#pikachu .pika-tail:before {
height: 1.45rem;
width: 1.4rem;
top: -2rem;
left: 0.25rem;
transform: rotate(-90deg);
border: 1px solid #9c5200;
border-bottom-right-radius: 5px;
z-index: 4;
border-top: 1px solid #fff069;
}
#pikachu .pika-tail:after {
background: #fff069;
height: 3rem;
width: 2rem;
top: -2.8rem;
left: -2.5rem;
border-radius: 5px 5px 0 5px;
border: 1px solid #9c5200;
}
.moon {
position: absolute;
width: 75px;
height: 75px;
background: #FFEFBA;
background: -webkit-linear-gradient(135deg, #FFFFFF, #FFEFBA);
background: linear-gradient(135deg, #FFFFFF, #FFEFBA);
border: 5px solid #fffaf0;
top: 10%;
left: calc(50% - 45px);
padding: 0;
border-radius: 100%;
}
.moon li {
position: absolute;
border-radius: 100%;
}
.moon li:nth-child(1) {
background: #ffe691;
background: -webkit-linear-gradient(45deg, rgba(255, 250, 240, 0.1), #ffe691);
background: linear-gradient(45deg, rgba(255, 250, 240, 0.1), #ffe691);
width: 20px;
height: 20px;
left: 5px;
top: 30px;
}
.moon li:nth-child(2) {
background: #ffe691;
background: -webkit-linear-gradient(to left, rgba(255, 250, 240, 0.1), #ffe691);
background: linear-gradient(to left, rgba(255, 250, 240, 0.1), #ffe691);
width: 35px;
height: 35px;
left: 35px;
top: 35px;
}
.moon li:nth-child(3) {
background: #ffe691;
background: -webkit-linear-gradient(-120deg, rgba(255, 250, 240, 0.1), #ffe691);
background: linear-gradient(-120deg, rgba(255, 250, 240, 0.1), #ffe691);
width: 25px;
height: 25px;
left: 25px;
top: 5px;
}
.sparkles {
position: absolute;
width: 120%;
height: 190px;
top: 30%;
left: -45px;
}
.sparkles .sparkle {
position: absolute;
width: 11px;
height: 11px;
border-radius: 100%;
}
.sparkles .sparkle:nth-child(1) {
background-color: #e9fbff;
box-shadow: 0px 0px 10px #e9fbff;
}
.sparkles .sparkle:nth-child(2) {
background-color: #e9fbff;
box-shadow: 0px 0px 10px #e9fbff;
}
.sparkles .sparkle:nth-child(3) {
background-color: #fffce6;
box-shadow: 0px 0px 10px #fffce6;
}
.sparkles .sparkle:nth-child(4) {
background-color: #e9fbff;
box-shadow: 0px 0px 10px #e9fbff;
}
.sparkles .sparkle:nth-child(5) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(6) {
background-color: #fffce6;
box-shadow: 0px 0px 10px #fffce6;
}
.sparkles .sparkle:nth-child(7) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(8) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(9) {
background-color: #ffeefc;
box-shadow: 0px 0px 10px #ffeefc;
}
.sparkles .sparkle:nth-child(10) {
background-color: #fffce6;
box-shadow: 0px 0px 10px #fffce6;
}
.sparkles .sparkle:nth-child(11) {
background-color: #ffeefc;
box-shadow: 0px 0px 10px #ffeefc;
}
.sparkles .sparkle:nth-child(12) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(13) {
background-color: #e9fbff;
box-shadow: 0px 0px 10px #e9fbff;
}
.sparkles .sparkle:nth-child(14) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(15) {
background-color: #ffeefc;
box-shadow: 0px 0px 10px #ffeefc;
}
.sparkles .sparkle:nth-child(16) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(17) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(18) {
background-color: #ffeefc;
box-shadow: 0px 0px 10px #ffeefc;
}
.sparkles .sparkle:nth-child(19) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(20) {
background-color: #ffeefc;
box-shadow: 0px 0px 10px #ffeefc;
}
.sparkles .sparkle:nth-child(21) {
background-color: #fffce6;
box-shadow: 0px 0px 10px #fffce6;
}
.sparkles .sparkle:nth-child(22) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(23) {
background-color: #e9fbff;
box-shadow: 0px 0px 10px #e9fbff;
}
.sparkles .sparkle:nth-child(24) {
background-color: #fffce6;
box-shadow: 0px 0px 10px #fffce6;
}
.sparkles .sparkle:nth-child(25) {
background-color: #e9fbff;
box-shadow: 0px 0px 10px #e9fbff;
}
.sparkles .sparkle:nth-child(26) {
background-color: #ffeefc;
box-shadow: 0px 0px 10px #ffeefc;
}
.sparkles .sparkle:nth-child(27) {
background-color: #fffce6;
box-shadow: 0px 0px 10px #fffce6;
}
.sparkles .sparkle:nth-child(28) {
background-color: #e9fbff;
box-shadow: 0px 0px 10px #e9fbff;
}
.sparkles .sparkle:nth-child(29) {
background-color: #e9fbff;
box-shadow: 0px 0px 10px #e9fbff;
}
.sparkles .sparkle:nth-child(30) {
background-color: #ffeefc;
box-shadow: 0px 0px 10px #ffeefc;
}
.sparkles .sparkle:nth-child(31) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.sparkles .sparkle:nth-child(32) {
background-color: #f3ffe4;
box-shadow: 0px 0px 10px #f3ffe4;
}
.one {
left: 0;
top: 0;
}
@keyframes flyOne {
95% {
opacity: 1;
}
100% {
transform: translate(270px, 75px) scale(0);
opacity: 0;
}
}
.one:nth-child(1) {
animation: flyOne 15s 0s infinite;
}
.one:nth-child(2) {
animation: flyOne 15s 6.44s infinite;
}
.one:nth-child(3) {
animation: flyOne 15s 12.88s infinite;
}
.one:nth-child(4) {
animation: flyOne 15s 19.32s infinite;
}
.two {
right: 0;
}
@keyframes flyTwo {
95% {
opacity: 1;
}
100% {
transform: translate(-270px, 75px) scale(0);
opacity: 0;
}
}
.two:nth-child(5) {
animation: flyTwo 21s 2.7s infinite;
}
.two:nth-child(6) {
animation: flyTwo 21s 8s infinite;
}
.two:nth-child(7) {
animation: flyTwo 21s 13.3s infinite;
}
.two:nth-child(8) {
animation: flyTwo 21s 18.6s infinite;
}
.three {
left: 0;
top: 100%;
}
@keyframes flyThree {
95% {
opacity: 1;
}
100% {
transform: translate(270px, -75px) scale(0);
opacity: 0;
}
}
.three:nth-child(9) {
animation: flyThree 17s 1.4s infinite;
}
.three:nth-child(10) {
animation: flyThree 17s 9.9s infinite;
}
.three:nth-child(11) {
animation: flyThree 17s 18.4s infinite;
}
.three:nth-child(12) {
animation: flyThree 17s 26.9s infinite;
}
.four {
right: 0;
top: 100%;
}
@keyframes flyFour {
95% {
opacity: 1;
}
100% {
transform: translate(-270px, -75px) scale(0);
opacity: 0;
}
}
.four:nth-child(13) {
animation: flyFour 25s 5.8s infinite;
}
.four:nth-child(14) {
animation: flyFour 25s 10.4s infinite;
}
.four:nth-child(15) {
animation: flyFour 25s 15s infinite;
}
.four:nth-child(16) {
animation: flyFour 25s 19.6s infinite;
}
.five {
left: 0;
top: 50%;
}
@keyframes flyFive {
95% {
opacity: 1;
}
100% {
transform: translate(270px, 0px) scale(0);
opacity: 0;
}
}
.five:nth-child(17) {
animation: flyFive 35s 8.7s infinite;
}
.five:nth-child(18) {
animation: flyFive 35s 14.4s infinite;
}
.five:nth-child(19) {
animation: flyFive 35s 20.1s infinite;
}
.five:nth-child(20) {
animation: flyFive 35s 25.8s infinite;
}
.six {
right: 0;
top: 50%;
}
@keyframes flySix {
95% {
opacity: 1;
}
100% {
transform: translate(-270px, 0px) scale(0);
opacity: 0;
}
}
.six:nth-child(21) {
animation: flySix 23.5s 10.6s infinite;
}
.six:nth-child(22) {
animation: flySix 23.5s 15s infinite;
}
.six:nth-child(23) {
animation: flySix 23.5s 19.4s infinite;
}
.six:nth-child(24) {
animation: flySix 23.5s 23.8s infinite;
}
.seven {
left: 0;
top: 25%;
}
@keyframes flySeven {
95% {
opacity: 1;
}
100% {
transform: translate(270px, 37px) scale(0);
opacity: 0;
}
}
.seven:nth-child(25) {
animation: flySeven 29s 5s infinite;
}
.seven:nth-child(26) {
animation: flySeven 29s 12.67s infinite;
}
.seven:nth-child(27) {
animation: flySeven 29s 20.34s infinite;
}
.seven:nth-child(28) {
animation: flySeven 29s 28.01s infinite;
}
.eight {
right: 0;
top: 25%;
}
@keyframes flyEight {
95% {
opacity: 1;
}
100% {
transform: translate(-270px, 37px) scale(0);
opacity: 0;
}
}
.eight:nth-child(29) {
animation: flyEight 28.5s 1.6s infinite;
}
.eight:nth-child(30) {
animation: flyEight 28.5s 5.34s infinite;
}
.eight:nth-child(31) {
animation: flyEight 28.5s 9.08s infinite;
}
.eight:nth-child(32) {
animation: flyEight 28.5s 12.82s infinite;
}
@keyframes pikaPat {
from {
transform: rotate(-40deg);
}
to {
transform: rotate(-50deg);
}
}
@keyframes rotateTail {
from {
transform: rotate(55deg);
}
to {
transform: rotate(65deg);
}
}
@keyframes rotateLeftEar {
from {
transform: rotate(-35deg);
}
to {
transform: rotate(-40deg);
}
}
@keyframes rotateRightEar {
from {
transform: rotate(50deg);
}
to {
transform: rotate(60deg);
}
}
@keyframes bulbaBreathe {
from {
transform: rotate(45deg) scale(1);
}
to {
transform: rotate(45deg) scale(1.01);
}
}
@keyframes bodyBreathe {
from {
transform: scale(1);
}
to {
transform: scale(1.05);
}
}
@keyframes rotateLeftBulbEar {
from {
transform: rotate(-45deg);
}
to {
transform: rotate(-55deg);
}
}
@keyframes rotateRightBulbEar {
from {
transform: rotate(45deg);
}
to {
transform: rotate(55deg);
}
}
\ No newline at end of file
.clearflex {
*zoom: 1;
}
.clearflex:after {
content: '';
display: block;
height: 0;
visibility: hidden;
clear: both;
}
.fl-left {
float: left;
}
.fl-right {
float: right;
}
.mg {
margin: 10px !important;
}
.left-mg-xs {
margin-left: 6px !important;
}
.left-mg-sm {
margin-left: 10px !important;
}
.left-mg-md {
margin-left: 14px !important;
}
.top-mg-lg {
margin-top: 20px !important;
}
.tb-mg-lg {
margin: 20px 0 !important;
}
.bottom-mg-lg {
margin-bottom: 20px !important;
}
.left-mg-lg {
margin-left: 18px !important;
}
.title-1 {
text-align: center;
font-size: 32px;
}
.title-3 {
text-align: center;
}
.el-pager li.active{
color: #409EFF !important;
border: 1px solid #409EFF;
}
.el-pager li:hover{
color: #409EFF !important;
border: 1px solid #409EFF;
}
\ No newline at end of file
// basice
$font-size: 14px;
$icon-size:17px;
$active-color:#1890ff;
$bg-main:#f0f2f5;
$border-color: #f4f4f4;
$white-bg:#fff;
$el-icon-small:30px;
$el-icon-mini:24px;
// aside
$width-aside:220px;
$width-hideside-aside:54px;
$width-mobile-aside:210px;
$color-aside:rgba(255, 255, 255,.9);
$icon-arrow-size-aside:12px;
$width-submenu-aside:55px;
$bg-aside:#191a23;
$height-aside-tilte:64px;
$height-aside-img:30px;
$width-aside-img:30px;
// header
$height-header: 60px;
// nav-scroll
$height-nav-scroll:40px;
$active-bg-tabs-item-nav-scroll:#409eff;
$bg-tabs-item-nav-scroll:#ddd;
// table
$bg-color-table-thead:#fafafa;
$border-color-table:#ededed;
$height-table-cell:45px;
$color-table-tbody:#595959;
$color-table-thead:#262626;
// dashboard
$height-car:68px;
// mobile
$padding-xs: 5px;
$margin-xs: 5px;
.login-register-box {
height: 100vh;
.login-box {
width: 40vw;
position: absolute;
left: 50%;
margin-left: -22vw;
top: 5vh;
.logo {
height: 35vh;
width: 35vh;
}
}
}
.link-icon {
width: 20px;
min-width: 20px;
height: 20px;
border-radius: 10px;
}
.vPic {
width: 33%;
height: 38px;
float: right !important;
background: #ccc;
img {
cursor: pointer;
vertical-align: middle;
}
}
.logo_login {
width: 100px;
}
#userLayout.user-layout-wrapper {
height: 100%;
position: relative;
&.mobile {
.container {
.main {
max-width: 368px;
width: 98%;
}
}
}
.container {
position: relative;
overflow: auto;
width: 100%;
min-height: 100%;
background: #f0f2f5 url(~@/assets/background.svg) no-repeat 50%;
background-size: 100%;
padding: 110px 0 144px;
a {
text-decoration: none;
}
.top {
text-align: center;
margin-top: -40px;
.header {
height: 44px;
line-height: 44px;
margin-bottom: 30px;
.badge {
position: absolute;
display: inline-block;
line-height: 1;
vertical-align: middle;
margin-left: -12px;
margin-top: -10px;
opacity: 0.8;
}
.logo {
height: 44px;
vertical-align: top;
margin-right: 16px;
border-style: none;
}
.title {
font-size: 33px;
color: rgba(0, 0, 0, 0.85);
font-family: Avenir, "Helvetica Neue", Arial, Helvetica, sans-serif;
font-weight: 600;
position: relative;
top: 2px;
}
}
.desc {
font-size: 14px;
color: rgba(0, 0, 0, 0.45);
margin-top: 12px;
}
}
.main {
min-width: 260px;
width: 368px;
margin: 0 auto;
}
.footer {
position: relative;
width: 100%;
padding: 0 20px;
margin: 40px 0 10px;
text-align: center;
.links {
margin-bottom: 8px;
font-size: 14px;
width: 330px;
display: inline-flex;
flex-direction: row;
justify-content: space-between;
padding-right: 40px;
a {
color: rgba(0, 0, 0, 0.45);
transition: all 0.3s;
}
}
.copyright {
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
padding-right: 40px;
}
}
}
}
\ No newline at end of file
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
@import '@/style/basics.scss';
html {
line-height: 1.15;
/* 1 */
-webkit-text-size-adjust: 100%;
/* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box;
/* 1 */
height: 0;
/* 1 */
overflow: visible;
/* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace;
/* 1 */
font-size: 1em;
/* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none;
/* 1 */
text-decoration: underline;
/* 2 */
text-decoration: underline dotted;
/* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace;
/* 1 */
font-size: 1em;
/* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
/* 1 */
font-size: 100%;
/* 1 */
line-height: 1.15;
/* 1 */
margin: 0;
/* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input {
/* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select {
/* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box;
/* 1 */
color: inherit;
/* 2 */
display: table;
/* 1 */
max-width: 100%;
/* 1 */
padding: 0;
/* 3 */
white-space: normal;
/* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box;
/* 1 */
padding: 0;
/* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield;
/* 1 */
outline-offset: -2px;
/* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button;
/* 1 */
font: inherit;
/* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}
HTML,
body,
div,
h1,
h2,
h3,
h4,
h5,
h6,
ul,
ol,
dl,
li,
dt,
dd,
p,
blockquote,
pre,
form,
fieldset,
table,
th,
td {
border: none;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
font-size: 14px;
margin: 0px;
padding: 0px;
}
html,
body {
height: 100%;
width: 100%;
}
address,
caption,
cite,
code,
dfn,
em,
strong,
th,
var {
font-style: normal;
font-weight: normal;
}
a {
text-decoration: none;
}
a:link {
color: #fff;
}
a:visited {
color: #fff;
}
a:hover {
color: #fff;
}
a:active {
color: #fff;
}
input::-ms-clear {
display: none;
}
input::-ms-reveal {
display: none;
}
input {
-webkit-appearance: none;
margin: 0;
outline: none;
padding: 0;
}
input::-webkit-input-placeholder {
color: #ccc;
}
input::-ms-input-placeholder {
color: #ccc;
}
input::-moz-placeholder {
color: #ccc;
}
input[type=submit],
input[type=button] {
cursor: pointer;
}
button[disabled],
input[disabled] {
cursor: default;
}
img {
border: none;
}
ul,
ol,
li {
list-style-type: none;
}
// 导航
#app {
.el-container {
position: relative;
height: 100%;
width: 100%;
}
.el-container.mobile.openside {
position: fixed;
top: 0;
}
.el-aside {
-webkit-transition: width .2s;
transition: width .2s;
width: $width-aside;
background-color: $bg-aside;
height: 100%;
position: fixed;
font-size: 0;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
.el-menu {
border-right: none;
}
.tilte {
min-height: $height-aside-tilte;
line-height: $height-aside-tilte;
background: $bg-aside;
text-align: center;
.logoimg {
width: $width-aside-img;
height: $height-aside-img;
vertical-align: middle;
background: #fff;
border-radius: 50%;
padding: 3px;
}
.tit-text {
display: inline-block;
color: #fff;
font-weight: 600;
font-size: 20px;
vertical-align: middle;
padding-left: 10px;
}
}
}
.aside {
.el-menu-vertical {
background-color: $bg-aside;
}
.el-submenu {
background-color: $bg-aside;
.el-menu {
.el-menu-item {
background-color: #000408;
height: 44px;
line-height: 44px;
}
.is-active {
background-color: #1890ff;
// 关闭三级菜单二级菜单样式
ul{
border:none;
}
}
// 关闭三级菜单二级菜单样式
.is-active.is-opened{
background-color: #191a23;
ul{
border:none;
}
}
}
}
.el-menu-item:focus, .el-menu-item:hover{
background-color: transparent;
}
.el-menu-item:hover i,
.el-menu-item:hover span {
color: #fff;
}
.el-submenu__title:hover {
background-color: $bg-aside;
}
.el-submenu__title:hover i,
.el-submenu__title:hover span {
color: #fff;
}
.el-menu--inline {
border-left: 5px solid #2c3b41;
}
}
.hideside {
.aside {
width: $width-hideside-aside;
}
}
.mobile.hideside {
.el-aside {
-webkit-transition-duration: .2s;
transition-duration: .2s;
-webkit-transform: translate3d(-210px, 0, 0);
transform: translate3d(-220px, 0, 0);
}
}
.mobile {
.el-aside {
-webkit-transition: -webkit-transform .28s;
transition: -webkit-transform .28s;
transition: transform .28s;
transition: transform .28s, -webkit-transform .28s;
width: $width-mobile-aside;
}
}
.main-cont.el-main {
min-height: 100%;
-webkit-transition: margin-left .28s;
transition: margin-left .28s;
margin-left: $width-aside;
position: relative;
}
.hideside {
.main-cont.el-main {
margin-left: 54px;
}
}
.mobile {
.main-cont.el-main {
margin-left: 0px;
}
}
.openside.mobile {
.shadowBg {
background: #000;
opacity: .3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
left: 0;
}
}
}
// layout
.layout-cont {
.main-cont {
position: relative;
&.el-main {
background-color: $bg-main;
padding: 0;
}
}
}
.admin-box {
padding: 15px 20px;
.el-button {
padding: 7px 10px;
}
.el-input__inner {
height: 30px;
line-height: 30px;
}
.el-input__icon {
line-height: 30px;
}
}
.admin-box {
min-height: calc(100vh - 200px);
background-color: $white-bg;
padding: 15px;
margin: 115px 15px 20px;
border-radius: 2px;
.el-table--border {
border-radius: 4px;
margin-bottom: 15px;
}
.el-table {
thead {
color: $color-table-thead;
}
th {
padding: 5px 0;
.cell {
min-height: 34px;
line-height: 34px;
}
}
td {
padding: 8px 0;
}
td,
th.is-leaf {
border-bottom: 1px solid #e8e8e8;
}
}
.search-term {
border-left: none;
border-right: none;
padding: 0 5px;
.el-form-item {
margin-bottom: 10px;
}
}
.el-pagination {
padding: 20px 0 0 0;
}
.upload-demo,
.upload {
padding: 0;
}
.system {
padding: 0;
}
.el-form.el-form--inline {
.el-form-item:last-child {
margin-bottom: 0;
}
}
.edit_container,
.edit {
padding: 0;
}
}
.admin-box:after,
.admin-box:before {
content: "";
display: block;
clear: both;
}
.button-box {
background: $white-bg;
border: none;
padding: 0 0 10px 0px;
}
.search-term {
background: $white-bg;
padding: 0 15px;
border-left: 1px solid #ebeef5;
border-right: 1px solid #ebeef5;
.demo-form-inline {
margin-bottom: 10px;
}
}
// table
.has-gutter {
tr {
th {
background-color: #fafafa;
}
}
}
.el-table--striped {
.el-table__body {
tr.el-table__row--striped {
td {
background: #fff !important;
}
}
}
}
.el-table th,
.el-table tr {
background-color: #fafafa;
}
.el-pagination {
.btn-prev,
.btn-next {
border: 1px solid #ddd;
border-radius: 4px;
}
.el-pager {
li {
color: #666;
font-size: 12px;
margin: 0 5px;
border: 1px solid #ddd;
border-radius: 4px;
}
}
padding: 20px 0 !important;
}
.el-row {
padding: 10px 0;
.el-col>label {
line-height: 30px;
text-align: right;
width: 80%;
padding-right: 15px;
display: inline-block;
}
.line {
line-height: 30px;
text-align: center;
}
}
// edit_container
.edit_container {
background-color: $white-bg;
padding: 15px;
.el-button {
margin: 15px 0;
}
}
.edit {
background-color: $white-bg;
padding: 15px;
.el-button {
margin: 15px 0;
}
}
// upload-demo
.upload-demo,
.upload {
background-color: $white-bg;
padding: 15px;
.el-upload-list__item-status-label {
right: 0;
left: 120px;
}
.el-upload__tip {
margin: 10px 0;
}
}
// system
.system {
padding: 15px;
.el-input__inner {
width: 80%;
}
}
// .el-menu .el-menu--inline {
// background: #2c3b41;
// }
// .el-submenu .el-submenu {
// background-color: #000408 !important;
// }
// .aside .el-scrollbar .el-scrollbar__view .el-submenu__title:hover {
// background-color: $bg-aside !important;
// }
// .el-menu--vertical {
// .el-menu {
// margin-left: -8px;
// background-color: rgb(48, 65, 86);
// .el-menu-item {
// background-color: rgb(48, 65, 86);
// }
// .el-menu-item:focus,
// .el-menu-item:hover {
// background-color: #263445;
// color: #fff;
// }
// }
// }
// 导航*****
// add 5.13
.el-container {
// .admin-box {
// padding: 15px;
// margin: 115px 15px 20px;
// border-radius: 2px;
// .button-box {
// border: none;
// padding: 0 0 10px 0px;
// }
// .el-table--border {
// border-radius: 4px;
// margin-bottom: 15px;
// }
// .el-table {
// thead {
// color: $color-table-thead;
// }
// th {
// padding: 5px 0;
// .cell {
// min-height: 34px;
// line-height: 34px;
// }
// }
// td {
// padding: 8px 0;
// }
// td,
// th.is-leaf {
// border-bottom: 1px solid #e8e8e8;
// }
// }
// .search-term {
// border-left: none;
// border-right: none;
// padding: 0 5px;
// .el-form-item {
// margin-bottom: 10px;
// }
// }
// .el-pagination {
// padding: 20px 0 0 0;
// }
// .upload-demo,
// .upload {
// padding: 0;
// }
// .system {
// padding: 0;
// }
// .el-form.el-form--inline {
// .el-form-item:last-child {
// margin-bottom: 0;
// }
// }
// .edit_container,
// .edit {
// padding: 0;
// }
// }
// .admin-box:after,
// .admin-box:before {
// content: "";
// display: block;
// clear: both;
// }
.tips {
margin-top: 10px;
font-size: 14px;
font-weight: 400;
color: #606266;
}
}
.el-container.layout-cont {
// .header-cont,
// .breadcrumb {
// height: 40px !important;
// line-height: 40px !important;
// }
.main-cont.el-main {
background-color: $bg-main;
.menu-total {
font-size: 22px;
color: #838383;
margin-top: 16px;
}
// background-color: #f0f2f5;
}
}
.el-container.layout-cont {
.main-cont {
.router-history {
// box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
background: #fff;
padding: 0 6px;
border-top: 1px solid $border-color;
padding: 0;
.el-tabs__header {
margin: 0px 0 0 0;
.el-tabs__item {
height: $height-nav-scroll;
height: $height-nav-scroll;
border: none;
border-left: 1px solid $border-color;
}
.el-tabs__item::before {
content: "";
width: 9px;
height: 9px;
margin-right: 8px;
display: inline-block;
background-color: #ddd;
border-radius: 50%;
transition: background-color .2s;
}
.el-tabs__item.is-active::before {
background-color: #409eff;
}
.el-tabs__item.is-active {
background-color: rgba(64, 158, 255, .08);
}
.el-tabs__nav {
border: none;
}
}
}
}
}
.el-table__row {
.el-button.el-button--text.el-button--small {
position: relative;
}
// .el-button.el-button--text.el-button--small::after {
// content: '';
// position: absolute;
// width: 1px;
// height: 50%;
// top: 5px;
// margin-left: 15px;
// background-color: #e8e8e8;
// }
.cell {
button:last-child::after {
content: '' !important;
position: absolute !important;
width: 0px !important;
}
}
}
.clear:after,
.clear:before {
content: "";
display: block;
clear: both;
}
.el-table--striped .el-table__body tr.el-table__row--level-1 td:first-child {
.cell {
.el-table__indent {
border-right: 1.5px solid #ccc;
margin-left: 6px;
}
.el-table__placeholder {
width: 10px;
}
}
}
.el-table--striped .el-table__body tr.el-table__row--level-2 td:first-child {
.cell {
.el-table__indent {
border-right: 1.5px solid #ccc;
margin-left: 6px;
}
.el-table__placeholder {
width: 10px;
}
}
}
.el-input-number__decrease,
.el-input-number__increase {
position: absolute;
z-index: 1;
top: 6px !important;
width: 42px;
height: 26px;
line-height: 26px;
text-align: center;
background: #F5F7FA;
color: #606266;
cursor: pointer;
font-size: 13px;
}
.table-button+span {
margin-left: 10px !important;
}
$headerHigh: 52px;
$mainHight: 100vh;
.dropdown-group {
min-width: 100px;
}
.topfix {
position: fixed;
top: 0;
box-sizing: border-box;
z-index: 999;
>.el-row{
padding: 0;
.el-col-lg-14{
height: 60px;
}
}
}
.el-scrollbar__wrap {
padding-bottom: 17px;
}
.layout-cont {
.right-box {
height: $height-header;
line-height: $height-header;
text-align: center;
vertical-align: middle;
margin-right: 40px;
img {
vertical-align: middle;
border: 1px solid #ccc;
border-radius: 6px;
}
}
.header-cont {
height: $height-header;
background: #fff;
}
.main-cont {
.breadcrumb {
height: $height-header;
line-height: $height-header;
display: inline-block;
background-color: #fff;
padding: 0 24px;
}
.fl-right {
// height: $height-header;
// line-height: $height-header;
}
&.el-main {
overflow: auto;
background: #fff;
}
height: $mainHight !important;
overflow: visible;
position: relative;
.menu-total {
float: left;
margin-top: 10px;
width: 30px;
height: 30px;
line-height: 30px;
font-size: 30px;
}
.aside {
overflow: auto;
// background: #fff;
&::-webkit-scrollbar {
display: none;
}
}
.el-menu-vertical {
height: calc(100vh - 64px) !important;
visibility: auto;
&:not(.el-menu--collapse) {
width: 220px;
}
}
.el-menu--collapse {
width: 54px;
li {
.el-tooltip,
.el-submenu__title {
padding: 0px 15px !important;
}
}
}
&::-webkit-scrollbar {
display: none;
}
&.main-left {
width: auto !important;
}
&.main-right {
.admin-title {
float: left;
font-size: 16px;
vertical-align: middle;
margin-left: 20px;
img {
vertical-align: middle;
}
&.collapse {
width: 53px;
}
}
}
}
}
.screenfull {
display: inline-block;
}
.header-avatar {
display: flex;
justify-content: center;
align-items: center;
}
.search-component {
display: inline-block;
overflow: hidden;
height: 60px;
width: 120px;
text-align: center;
.el-input__inner {
border: none;
border-bottom: 1px solid #606266;
}
.el-dropdown-link {
cursor: pointer;
}
.search-icon {
font-size: $icon-size;
margin-right: 14px;
display: inline-block;
vertical-align: middle;
box-sizing: border-box;
color: #606266;
}
.dropdown-group {
min-width: 100px;
}
}
.transition-box {
overflow: hidden;
width: 120px;
text-align: center;
}
.screenfull {
overflow: hidden;
width: 40px;
text-align: center;
}
.el-dropdown {
overflow: hidden;
height: 60px;
}
// dashboard
.card {
background-color: $white-bg;
padding: 20px;
border-radius: 4px;
overflow: hidden;
.car-left {
height: $height-car;
// width: 70%;
// float: left;
}
.car-right {
height: $height-car;
// width: 29%;
// float: left;
.flow,
.user-number,
.feedback {
width: $el-icon-mini;
height: $el-icon-mini;
display: inline-block;
border-radius: 50%;
line-height: $el-icon-mini;
text-align: center;
font-size: 13px;
margin-right: 5px;
}
.flow {
background-color: #fff7e8;
border-color: #feefd0;
color: #faad14;
}
.user-number {
background-color: #ecf5ff;
border-color: #d9ecff;
color: #409eff;
}
.feedback {
background-color: #eef9e8;
border-color: #dcf3d1;
color: #52c41a;
}
.car-item {
text-align: right;
b {
display: block;
}
}
}
.card-img {
width: $height-car;
height: $height-car;
display: inline-block;
float: left;
overflow: hidden;
img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.text {
height: $height-car;
margin-left: 10px;
float: left;
margin-top: 14px;
h4 {
font-size: 20px;
color: #262626;
font-weight: 500;
white-space: nowrap;
word-break: break-all;
text-overflow: ellipsis;
}
.tips-text {
color: #8c8c8c;
margin-top: 8px;
.el-icon{
margin-right: 8px;
display:inline-block;
}
}
}
}
.shadow {
margin: 5px 0;
.grid-content {
background-color: $white-bg;
border-radius: 4px;
text-align: center;
padding: 10px 0;
cursor: pointer;
.el-icon {
width: $el-icon-small;
height: $el-icon-small;
font-size: $el-icon-small;
margin-bottom: 8px;
}
}
}
::-webkit-scrollbar-track-piece {
background-color: #f8f8f8;
}
::-webkit-scrollbar {
width: 9px;
height: 9px;
}
::-webkit-scrollbar-thumb {
background-color: #dddddd;
background-clip: padding-box;
min-height: 28px;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background-color: #bbb;
}
\ No newline at end of file
@import '@/style/basics.scss';
@media screen and (min-width: 320px)and (max-width: 750px){
.el-header{
padding: 0 $padding-xs;
}
.layout-cont {
.main-cont{
.breadcrumb{
padding: 0 $padding-xs;
}
}
}
.layout-cont{
.right-box{
margin-right: $margin-xs;
}
}
.search-component{
width: 30px;
}
.screenfull{
width: 26px;
text-align: center;
}
.el-main{
.admin-box{
margin-left: 0;
margin-right: 0;
}
.big.admin-box{
padding: 0 0 15px 0;
}
.big {
.bottom {
.chart-player{
height: auto!important;
margin-bottom: 15px;
}
.todoapp{
background-color: #fff;
padding-bottom: 10px;
}
}
}
}
.card .car-left,
.card .car-right{
width: 100%;
height: 100%;
}
.card{
padding-left: $padding-xs;
padding-right: $padding-xs;
}
.card {
.text{
width: 100%;
h4{
white-space: break-spaces;
}
}
}
.shadow{
margin-left: 5px;
margin-right: 5px;
.grid-content{
margin-bottom: 10px;
padding: 0;
}
}
.el-dialog{
width: 90%;
}
.el-transfer{
.el-transfer-panel{
width: 40%;
display: inline-block;
}
.el-transfer__buttons{
padding: 0 5px;
display: inline-block;
}
}
}
\ No newline at end of file
module.exports = file => () => {
return import ('@/' + file)
}
\ No newline at end of file
const _import = require('./_import') //获取组件的方法
export const asyncRouterHandle = (asyncRouter) => {
asyncRouter.map(item => {
if (item.component) {
item.component = _import(item.component)
} else {
delete item['component']
}
if (item.children) {
asyncRouterHandle(item.children)
}
})
}
\ No newline at end of file
const install = (Vue) => {
const Bus = new Vue({
methods: {
emit(event, ...args) {
this.$emit(event, ...args)
},
on(event, cb) {
this.$on(event, cb)
},
off(event, cb) {
this.$off(event, cb)
}
},
})
Vue.prototype.$bus = Bus
}
export default install
\ No newline at end of file
// 对Date的扩展,将 Date 转化为指定格式的String
// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
Date.prototype.Format = function(fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
export function formatTimeToStr(times, pattern) {
var d = new Date(times).Format("yyyy-MM-dd hh:mm:ss");
if (pattern) {
d = new Date(times).Format(pattern);
}
return d.toLocaleString();
}
\ No newline at end of file
import { store } from '@/store/index'
// 获取字典方法 使用示例 getDict('sex').then(res) 或者 async函数下 const res = await getDict('sex')
export const getDict = async (type) => {
await store.dispatch("dictionary/getDictionary", type)
return store.getters["dictionary/getDictionary"][type]
}
\ No newline at end of file
export const downloadImage = (imgsrc, name) => { //下载图片地址和图片名
var image = new Image();
image.setAttribute("crossOrigin", "anonymous");
image.onload = function() {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext("2d");
context.drawImage(image, 0, 0, image.width, image.height);
var url = canvas.toDataURL("image/png"); //得到图片的base64编码数据
var a = document.createElement("a"); // 生成一个a元素
var event = new MouseEvent("click"); // 创建一个单击事件
a.download = name || "photo"; // 设置图片名称
a.href = url; // 将生成的URL设置为a.href属性
a.dispatchEvent(event); // 触发a的单击事件
};
image.src = imgsrc;
}
\ No newline at end of file
export default class ImageCompress {
constructor(file, fileSize, maxWH = 1920) {
this.file = file
this.fileSize = fileSize
this.maxWH = maxWH // 最大长宽
}
compress() {
// 压缩
const fileType = this.file.type
const fileSize = this.file.size / 1024
return new Promise(resolve => {
const reader = new FileReader();
reader.readAsDataURL(this.file);
reader.onload = () => {
const canvas = document.createElement('canvas');
const img = document.createElement('img');
img.src = reader.result;
img.onload = () => {
const ctx = canvas.getContext('2d');
let _dWH = this.dWH(img.width, img.height, this.maxWH)
canvas.width = _dWH.width
canvas.height = _dWH.height
// 清空后, 重写画布
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
let newImgData = canvas.toDataURL(fileType, 0.90)
// 压缩宽高后的图像大小
let newImgSize = this.fileSizeKB(newImgData)
if (newImgSize > this.fileSize) {
console.log('图片尺寸太大!' + fileSize + " >> " + newImgSize)
}
let blob = this.dataURLtoBlob(newImgData, fileType)
let nfile = new File([blob], this.file.name);
resolve(nfile)
};
};
});
}
/*
* 长宽等比缩小
* 图像的一边(长或宽)为最大目标值
* */
dWH(srcW, srcH, dMax) {
let defaults = {
width: srcW,
height: srcH
}
if (Math.max(srcW, srcH) > dMax) {
if (srcW > srcH) {
defaults.width = dMax
defaults.height = Math.round(srcH * (dMax / srcW))
return defaults
} else {
defaults.height = dMax
defaults.width = Math.round(srcW * (dMax / srcH))
return defaults
}
} else {
return defaults
}
}
fileSizeKB(dataURL) {
let sizeKB = 0
sizeKB = Math.round((dataURL.split(',')[1].length * 3 / 4) / 1024)
return sizeKB
}
/*
* 转为Blob
* */
dataURLtoBlob(dataURL, fileType) {
let byteString = atob(dataURL.split(',')[1])
let mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0]
let ab = new ArrayBuffer(byteString.length)
let ia = new Uint8Array(ab)
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i)
}
if (fileType) {
mimeString = fileType
}
return new Blob([ab], { type: mimeString, lastModifiedDate: new Date() })
}
}
\ No newline at end of file
const title = 'VUE-XDORG'
export default function getPageTitle(pageTitle) {
if (pageTitle) {
return `${pageTitle} - ${title}`
}
return `${title}`
}
\ No newline at end of file
import axios from 'axios'; // 引入axios
import { Message } from 'element-ui';
import { store } from '@/store/index'
import context from '@/main.js'
import router from '@/router/index'
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 99999
})
let acitveAxios = 0
let timer
const showLoading = () => {
acitveAxios++
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
if (acitveAxios > 0) {
context.$bus.emit("showLoading")
}
}, 400);
}
const closeLoading = () => {
acitveAxios--
if (acitveAxios <= 0) {
clearTimeout(timer)
context.$bus.emit("closeLoading")
}
}
//http request 拦截器
service.interceptors.request.use(
config => {
if (!config.donNotShowLoading) {
showLoading()
}
const token = store.getters['user/token']
const user = store.getters['user/userInfo']
config.data = JSON.stringify(config.data);
config.headers = {
'Content-Type': 'application/json',
'x-token': token,
'x-user-id': user.ID
}
return config;
},
error => {
closeLoading()
Message({
showClose: true,
message: error,
type: 'error'
})
return error;
}
);
//http response 拦截器
service.interceptors.response.use(
response => {
closeLoading()
if (response.headers["new-token"]) {
store.commit('user/setToken', response.headers["new-token"])
}
if(response.data.code == 0){
if(response.data.data?.needInit){
Message({
type:"info",
message:"您是第一次使用,请初始化"
})
store.commit("user/NeedInit")
router.push({name:"init"})
}
}
if (response.data.code == 0 || response.headers.success === "true") {
return response.data
} else {
Message({
showClose: true,
message: response.data.msg || decodeURI(response.headers.msg),
type: response.headers.msgtype||'error',
})
if (response.data.data && response.data.data.reload) {
store.commit('user/LoginOut')
}
return response.data.msg ? response.data : response
}
},
error => {
closeLoading()
Message({
showClose: true,
message: error,
type: 'error'
})
return error
}
)
export default service
\ No newline at end of file
/* eslint-disable */
export const toUpperCase = (str) => {
if (str[0]) {
return str.replace(str[0], str[0].toUpperCase())
} else {
return ""
}
}
export const toLowerCase = (str) => {
if (str[0]) {
return str.replace(str[0], str[0].toLowerCase())
} else {
return ""
}
}
// 驼峰转换下划线
export const toSQLLine = (str) => {
if (str == "ID") return "ID"
return str.replace(/([A-Z])/g, "_$1").toLowerCase();
}
// 下划线转换驼峰
export const toHump = (name) => {
return name.replace(/\_(\w)/g, function(all, letter) {
return letter.toUpperCase();
});
}
\ No newline at end of file
<template>
<div>
<el-row :gutter="10">
<el-col :span="12">
<el-card>
<div slot="header">vue-xdorg</div>
<div>
<el-row>
<el-col :span="8" :offset="8">
<a href="https://codechina.csdn.net/xdorg/vue-xdorg">
<img
class="org-img dom-center"
src="@/assets/logo.png"
alt="vue-xdorg"
/>
</a>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="8">
<a href="https://codechina.csdn.net/xdorg/vue-xdorg">
<img
class="dom-center"
src="https://img.shields.io/github/watchers/xdorg/vue-xdorg.svg?label=Watch"
alt=""
/>
</a>
</el-col>
<el-col :span="8">
<a href="https://codechina.csdn.net/xdorg/vue-xdorg">
<img
class="dom-center"
src="https://img.shields.io/github/stars/xdorg/vue-xdorg.svg?style=social"
alt=""/></a
></el-col>
<el-col :span="8">
<a href="https://codechina.csdn.net/xdorg/vue-xdorg">
<img
class="dom-center"
src="https://img.shields.io/github/forks/xdorg/vue-xdorg.svg?label=Fork"
alt=""/></a
></el-col>
</el-row>
</div>
</el-card>
<el-card style="margin-top: 20px">
<div slot="header">XDORG团队</div>
<div>
<el-row>
<el-col :span="8" :offset="8">
<a href="https://codechina.csdn.net/xdorg">
<img
class="org-img dom-center"
src="@/assets/xdorg.png"
alt="xdorg"
/>
</a>
</el-col>
</el-row>
<el-row style="margin-left: 40px" :gutter="20">
<template v-for="(item, index) in members">
<el-col :span="8" :key="index">
<a :href="item.html_url">
<img class="avatar-img" :src="item.avatar_url" />
<a class="author-name" style="">{{ item.login }}</a>
</a>
</el-col>
</template>
</el-row>
</div>
</el-card>
</el-col>
<el-col :span="12">
<el-card>
<div slot="header">
提交记录
</div>
<div>
<Timeline
:timeline-items="dataTimeline"
:message-when-no-items="messageWhenNoItems"
:uniqueTimeline="true"
:unique-year="true"
:show-day-and-month="true"
order="desc"
dateLocale="zh-CN"
/>
</div>
<el-button class="load-more" @click="loadMore" type="text"
>Load more</el-button
>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { Commits, Members } from "@/api/github";
import Timeline from "timeline-vuejs";
export default {
name: "Test",
components: {
Timeline,
},
data() {
return {
messageWhenNoItems: "There arent commits",
members: [],
dataTimeline: [],
page: 0,
};
},
created() {
this.loadCommits();
this.loadMembers();
},
methods: {
loadMore() {
this.page++;
this.loadCommits();
},
loadCommits() {
Commits(this.page).then(({ data }) => {
data.forEach((element) => {
if (element.commit.message) {
this.dataTimeline.push({
from: new Date(element.commit.author.date),
title: element.commit.author.name,
showDayAndMonth: true,
description: `<a style="color: #26191b" href="${element.html_url}">${element.commit.message}</a>`,
});
}
});
});
},
loadMembers() {
Members().then(({ data }) => {
this.members = data;
this.members.sort();
});
},
},
};
</script>
<style scoped>
.load-more {
margin-left: 120px;
}
.avatar-img {
float: left;
height: 40px;
width: 40px;
border-radius: 50%;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
margin-top: 15px;
}
.org-img {
height: 150px;
width: 150px;
}
.author-name {
float: left;
line-height: 65px !important;
margin-left: 10px;
color: darkblue;
line-height: 100px;
font-family: "Lucida Sans", "Lucida Sans Regular", "Lucida Grande",
"Lucida Sans Unicode", Geneva, Verdana, sans-serif;
}
.dom-center {
margin-left: 50%;
transform: translateX(-50%);
}
</style>
<template>
<div>
<div style="width: 100%">
<APlayer :audio="audio"></APlayer>
</div>
</div>
</template>
<script>
import { APlayer } from '@moefe/vue-aplayer';
export default {
name: "musicPlayer",
components:{
APlayer
},
data(){
return {
audio :[
{
name: '东西(Cover:林俊呈)',
artist: '纳豆',
url: 'http://music.163.com/song/media/outer/url?id=1321594530.mp3',
cover: 'https://p1.music.126.net/5zs7IvmLv7KahY3BFzUmrg==/109951163635241613.jpg?param=300y300', // prettier-ignore
lrc: 'https://cdn.moefe.org/music/lrc/thing.lrc',
},
{
name: '响喜乱舞(Cover:MARiA)',
artist: '泠鸢yousa',
url: 'http://music.163.com/song/media/outer/url?id=1318962459.mp3',
cover: 'https://p1.music.126.net/AUGVPQ_rVrngDH9ocQrn3Q==/109951163613037822.jpg?param=300y300', // prettier-ignore
lrc: 'https://cdn.moefe.org/music/lrc/kyoukiranbu.lrc',
},
{
name: '啵唧',
artist: 'Hanser',
url: 'http://music.163.com/song/media/outer/url?id=1321424246.mp3',
cover: 'https://p1.music.126.net/K0-IPcIQ9QFvA0jXTBqoWQ==/109951163636756693.jpg?param=300y300', // prettier-ignore
lrc: 'https://cdn.moefe.org/music/lrc/kiss.lrc',
},
]
}
}
}
</script>
<style scoped>
</style>
<template>
<li :class="{ completed: todo.done, editing: editing }" class="todo">
<div class="view">
<input
:checked="todo.done"
class="toggle"
type="checkbox"
@change="toggleTodo( todo)"
>
<label @dblclick="editing = true" v-text="todo.text" />
<button class="destroy" @click="deleteTodo( todo )" />
</div>
<input
v-show="editing"
v-focus="editing"
:value="todo.text"
class="edit"
@keyup.enter="doneEdit"
@keyup.esc="cancelEdit"
@blur="doneEdit"
>
</li>
</template>
<script>
export default {
name: 'Todo',
directives: {
focus(el, { value }, { context }) {
if (value) {
context.$nextTick(() => {
el.focus()
})
}
}
},
props: {
todo: {
type: Object,
default: function() {
return {}
}
}
},
data() {
return {
editing: false
}
},
methods: {
deleteTodo(todo) {
this.$emit('deleteTodo', todo)
},
editTodo({ todo, value }) {
this.$emit('editTodo', { todo, value })
},
toggleTodo(todo) {
this.$emit('toggleTodo', todo)
},
doneEdit(e) {
const value = e.target.value.trim()
const { todo } = this
if (!value) {
this.deleteTodo({
todo
})
} else if (this.editing) {
this.editTodo({
todo,
value
})
this.editing = false
}
},
cancelEdit(e) {
e.target.value = this.todo.text
this.editing = false
}
}
}
</script>
.todoapp {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
color: #4d4d4d;
min-width: 230px;
max-width: 666px;
margin: 0 auto ;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
background: #fff;
z-index: 1;
position: relative;
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
:focus {
outline: 0;
}
.hidden {
display: none;
}
.todoapp {
background: #fff;
margin: 130px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.todoapp input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp input::input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp h1 {
position: absolute;
top: -155px;
width: 100%;
font-size: 100px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, 0.15);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
.new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 18px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.new-todo {
padding: 10px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}
.main {
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
}
.toggle-all {
text-align: center;
border: none;
/* Mobile Safari */
opacity: 0;
position: absolute;
}
.toggle-all+label {
width: 60px;
height: 34px;
font-size: 0;
position: absolute;
top: -52px;
left: -13px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.toggle-all+label:before {
content: '❯';
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
.toggle-all:checked+label:before {
color: #737373;
}
.todo-list {
margin: 0;
padding: 0;
list-style: none;
}
.todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
}
.todo-list li:last-child {
border-bottom: none;
}
.todo-list li.editing {
border-bottom: none;
padding: 0;
}
.todo-list li.editing .edit {
display: block;
width: 506px;
padding: 12px 16px;
margin: 0 0 0 43px;
}
.todo-list li.editing .view {
display: none;
}
.todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none;
/* Mobile Safari */
-webkit-appearance: none;
appearance: none;
}
.todo-list li .toggle {
opacity: 0;
}
.todo-list li .toggle+label {
/*
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
*/
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
background-repeat: no-repeat;
background-position: center left;
background-size: 36px;
}
.todo-list li .toggle:checked+label {
background-size: 36px;
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
}
.todo-list li label {
word-break: break-all;
padding: 15px 15px 15px 50px;
display: block;
line-height: 1.0;
font-size: 14px;
transition: color 0.4s;
}
.todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
.todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
transition: color 0.2s ease-out;
cursor: pointer;
}
.todo-list li .destroy:hover {
color: #af5b5e;
}
.todo-list li .destroy:after {
content: '×';
}
.todo-list li:hover .destroy {
display: block;
}
.todo-list li .edit {
display: none;
}
.todo-list li.editing:last-child {
margin-bottom: -1px;
}
.footer {
color: #777;
position: relative;
padding: 10px 15px;
height: 40px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
.footer:before {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 40px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
.todo-count {
float: left;
text-align: left;
}
.todo-count strong {
font-weight: 300;
}
.filters {
margin: 0;
padding: 0;
position: relative;
z-index: 1;
list-style: none;
}
.filters li {
display: inline;
}
.filters li a {
color: inherit;
font-size: 12px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.clear-completed,
html .clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
}
.clear-completed:hover {
text-decoration: underline;
}
.info {
margin: 65px auto 0;
color: #bfbfbf;
font-size: 10px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
.info p {
line-height: 1;
}
.info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
.info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
.toggle-all,
.todo-list li .toggle {
background: none;
}
.todo-list li .toggle {
height: 40px;
}
}
@media (max-width: 430px) {
.footer {
height: 50px;
}
.filters {
bottom: 10px;
}
}
}
<template>
<section class="todoapp">
<!-- header -->
<header class="header">
<input class="new-todo" autocomplete="off" placeholder="Todo List" @keyup.enter="addTodo">
</header>
<!-- main section -->
<section v-show="todos.length" class="main">
<input id="toggle-all" :checked="allChecked" class="toggle-all" type="checkbox" @change="toggleAll({ done: !allChecked })">
<label for="toggle-all" />
<ul class="todo-list">
<todo
v-for="(todo, index) in filteredTodos"
:key="index"
:todo="todo"
@toggleTodo="toggleTodo"
@editTodo="editTodo"
@deleteTodo="deleteTodo"
/>
</ul>
</section>
<!-- footer -->
<footer v-show="todos.length" class="footer">
<span class="todo-count">
<strong>{{ remaining }}</strong>
{{ remaining | pluralize('item') }} left
</span>
<ul class="filters">
<li v-for="(val, key) in filters" :key="key">
<a :class="{ selected: visibility === key }" @click.prevent="visibility = key">{{ key | capitalize }}</a>
</li>
</ul>
<!-- <button class="clear-completed" v-show="todos.length > remaining" @click="clearCompleted">
Clear completed
</button> -->
</footer>
</section>
</template>
<script>
import Todo from './Todo.vue'
const STORAGE_KEY = 'todos'
const filters = {
all: todos => todos,
active: todos => todos.filter(todo => !todo.done),
completed: todos => todos.filter(todo => todo.done)
}
const defalutList = [
{ text: '工作流功能绘制工具', done: false },
{ text: '工作流流转方法', done: false },
{ text: '自动化代码优化', done: false }
]
export default {
components: { Todo },
filters: {
pluralize: (n, w) => n === 1 ? w : w + 's',
capitalize: s => s.charAt(0).toUpperCase() + s.slice(1)
},
data() {
return {
visibility: 'all',
filters,
// todos: JSON.parse(window.localStorage.getItem(STORAGE_KEY)) || defalutList
todos: defalutList
}
},
computed: {
allChecked() {
return this.todos.every(todo => todo.done)
},
filteredTodos() {
return filters[this.visibility](this.todos)
},
remaining() {
return this.todos.filter(todo => !todo.done).length
}
},
methods: {
setLocalStorage() {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(this.todos))
},
addTodo(e) {
const text = e.target.value
if (text.trim()) {
this.todos.push({
text,
done: false
})
this.setLocalStorage()
}
e.target.value = ''
},
toggleTodo(val) {
val.done = !val.done
this.setLocalStorage()
},
deleteTodo(todo) {
this.todos.splice(this.todos.indexOf(todo), 1)
this.setLocalStorage()
},
editTodo({ todo, value }) {
todo.text = value
this.setLocalStorage()
},
clearCompleted() {
this.todos = this.todos.filter(todo => !todo.done)
this.setLocalStorage()
},
toggleAll({ done }) {
this.todos.forEach(todo => {
todo.done = done
this.setLocalStorage()
})
}
}
}
</script>
<style lang="scss">
@import './index.scss';
</style>
<template>
<div class="big">
<el-row>
<div class="card">
<el-col :xs="24" :lg="16" :md="16" >
<div class="car-left">
<el-row>
<div>
<el-col :xs="4" :md="3" :lg="3">
<span class="card-img">
<img :src="userInfo.headerImg" alt="" />
</span>
</el-col>
<el-col :xs="20" :lg="12" :md="12">
<div class="text">
<h4>早安,管理员, 请开始您一天的工作吧!</h4>
<p class="tips-text">
<i class="el-icon-sunny el-icon"></i>
<span>今日晴,0℃ - 10℃,天气寒冷,注意添加衣物。</span>
</p>
</div>
</el-col>
</div>
</el-row>
</div>
</el-col>
<el-col :xs="24" :lg='8' :md="8">
<div class="car-right">
<el-row>
<el-col :span="8"
><div class="car-item">
<span class="flow"><i class="el-icon-s-grid"></i></span>
<span>今日流量 </span>
<b>13260</b>
</div></el-col
>
<el-col :span="8"
><div class="car-item">
<span class="user-number">
<i class="el-icon-s-custom"></i>
</span>
<span>总用户 </span>
<b>48286</b>
</div></el-col
>
<el-col :span="8"
><div class="car-item">
<span class="feedback">
<i class="el-icon-star-on"></i>
</span>
<span>好评率 </span>
<b>98%</b>
</div></el-col
>
</el-row>
</div>
</el-col>
</div>
</el-row>
<el-row>
<el-card shadow="hover">
<h2>
基础学习:<a style="color:#409EFF" target="view_window" href="https://edu.csdn.net/course/detail/31858">https://edu.csdn.net/course/detail/31858</a>
</h2>
<br>
<h2>
源码路径:<a style="color:#409EFF" target="view_window" href="https://codechina.csdn.net/xdorg">https://codechina.csdn.net/xdorg</a>
</h2>
<div></div>
</el-card>
</el-row>
<div class="shadow">
<el-row :gutter="20">
<el-col
:span="4"
v-for="(card, key) in toolCards"
:key="key"
@click.native="toTarget(card.name)"
:xs="8"
>
<el-card shadow="hover" class="grid-content">
<i :class="card.icon" :style="{ color: card.color }"></i>
<p>{{ card.label }}</p>
</el-card>
</el-col>
</el-row>
</div>
<div class="bottom">
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="12">
<div class="chart-player">
<musicPlayer />
</div>
</el-col>
<el-col :xs="24" :sm="24" :lg="12">
<div class="chart-player">
<todo-list />
</div>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import musicPlayer from "./component/musicPlayer";
import TodoList from "./component/todoList";
import { mapGetters } from "vuex";
export default {
name: "Dashboard",
data() {
return {
toolCards: [
{
label: "用户管理",
icon: "el-icon el-icon-monitor",
name: "user",
color: "#ff9c6e",
},
{
label: "角色管理",
icon: "el-icon el-icon-setting",
name: "authority",
color: "#69c0ff",
},
{
label: "菜单管理",
icon: "el-icon el-icon-menu",
name: "menu",
color: "#b37feb",
},
{
label: "代码生成器",
icon: "el-icon el-icon-cpu",
name: "autoCode",
color: "#ffd666",
},
{
label: "表单生成器",
icon: "el-icon el-icon-document-checked",
name: "formCreate",
color: "#ff85c0",
},
{
label: "关于我们",
icon: "el-icon el-icon-user",
name: "about",
color: "#5cdbd3",
},
],
};
},
computed: {
...mapGetters("user", ["userInfo"]),
},
components: {
musicPlayer, //音乐播放器
TodoList, //TodoList
// RaddarChart, //雷达图
// stackMap, //堆叠图
// Sunburst, //旭日图
},
methods: {
toTarget(name) {
this.$router.push({ name });
},
},
};
</script>
<style lang="scss" scoped>
.big {
margin: 100px 0 0 0;
padding-top: 0;
background-color: rgb(243, 243, 243);
padding-top: 15px;
.top {
width: 100%;
height: 360px;
margin-top: 20px;
overflow: hidden;
.chart-container {
position: relative;
width: 100%;
height: 100%;
padding: 20px;
background-color: #fff;
}
}
.mid {
width: 100%;
height: 380px;
.chart-wrapper {
height: 340px;
background: #fff;
padding: 16px 16px 0;
margin-bottom: 32px;
}
}
.bottom {
width: 100%;
height: 300px;
// margin: 20px 0;
.el-row {
margin-right: 4px !important;
}
.chart-player {
width: 100%;
height: 270px;
padding: 10px;
background-color: #fff;
}
}
}
</style>
<template>
<div>
<div class="big">
<div class="inner">
<img src="../../assets/notFound.png">
<p>页面被神秘力量吸走了,请联系我们修复</p>
<p style="font-size:18px;line-height:40px;">常见问题为菜单未分配仪表盘,可自行分配仪表盘或修改默认路由</p>
<p></p>
<img src="../../assets/xdorgw.png" class="leftPic">
</div>
</div>
</div>
</template>
<script>
export default {
name:"Login"
}
</script>
<style lang="scss">
.big{
width: 100%;
height: calc(100vh - 220px);
background-color: rgb(244,244,244);
position: relative;
}
.inner{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.inner p {
text-align: center;
font-size: 24px;
}
.inner .leftPic{
width: 60px;
height: 60px;
margin-left: 44%;
margin-top: 20px;
}
</style>
\ No newline at end of file
<template>
<div class="hello">
<el-divider content-position="left">大文件上传</el-divider>
<form id="fromCont" method="post" >
<div class="fileUpload" @click="inputChange">
选择文件
<input v-show="false" @change="choseFile" id="file" multiple="multiple" type="file" ref="Input" />
</div>
</form>
<el-button @click="getFile" :disabled="limitFileSize" type="primary" size="medium" class="uploadBtn">上传文件</el-button>
<div class="el-upload__tip">请上传不超过5MB的文件</div>
<div class="list">
<transition name="list" tag="p">
<div class="list-item" v-if="file" >
<i class="el-icon-document"></i>
<span>{{ file.name }}</span>
<span class="percentage" >{{percentage}}%</span>
<el-progress :show-text='false' :text-inside="false" :stroke-width="2" :percentage="percentage"></el-progress>
</div>
</transition>
</div>
<!-- <span
v-if="this.file"
>{{Math.floor(((this.formDataList.length-this.waitNum)/this.formDataList.length)*100)}}%</span> -->
<div class="tips">此版本为先行体验功能测试版,样式美化和性能优化正在进行中,上传切片文件和合成的完整文件分别再QMPlusserver目录的breakpointDir文件夹和fileDir文件夹</div>
</div>
</template>
<script>
import SparkMD5 from 'spark-md5'
import axios from 'axios'
import {
findFile,
breakpointContinueFinish,
removeChunk
} from '@/api/breakpoint'
export default {
name: 'HelloWorld',
data() {
return {
file: null,
fileMd5: '',
formDataList: [],
waitUpLoad: [],
waitNum: 0,
limitFileSize: false,
percentage:0,
percentageFlage: true,
customColor: '#409eff'
}
},
created(){
},
methods: {
// 选中文件的函数
async choseFile(e) {
const fileR = new FileReader() // 创建一个reader用来读取文件流
const file = e.target.files[0] // 获取当前文件
const maxSize = 5*1024*1024
this.file = file // file 丢全局方便后面用 可以改进为func传参形式
this.percentage = 0
if(file.size<maxSize){
fileR.readAsArrayBuffer(file) // 把文件读成ArrayBuffer 主要为了保持跟后端的流一致
fileR.onload = async e => {
// 读成arrayBuffer的回调 e 为方法自带参数 相当于 dom的e 流存在e.target.result 中
const blob = e.target.result
let spark = new SparkMD5.ArrayBuffer() // 创建md5制造工具 (md5用于检测文件一致性 这里不懂就打电话问我)
spark.append(blob) // 文件流丢进工具
this.fileMd5 = spark.end() // 工具结束 产生一个a 总文件的md5
const FileSliceCap = 1 * 1024 * 1024 // 分片字节数
let start = 0 // 定义分片开始切的地方
let end = 0 // 每片结束切的地方a
let i = 0 // 第几片
this.formDataList = [] // 分片存储的一个池子 丢全局
while (end < file.size) {
// 当结尾数字大于文件总size的时候 结束切片
start = i * FileSliceCap // 计算每片开始位置
end = (i + 1) * FileSliceCap // 计算每片结束位置
var fileSlice = this.file.slice(start, end) // 开始切 file.slice 为 h5方法 对文件切片 参数为 起止字节数
const formData = new window.FormData() // 创建FormData用于存储传给后端的信息
formData.append('fileMd5', this.fileMd5) // 存储总文件的Md5 让后端知道自己是谁的切片
formData.append('file', fileSlice) //当前的切片
formData.append('chunkNumber', i) // 当前是第几片
formData.append('fileName', this.file.name) //当前文件的文件名 用于后端文件切片的命名 formData.appen 为 formData对象添加参数的方法
this.formDataList.push({ key: i, formData }) // 把当前切片信息 自己是第几片 存入我们方才准备好的池子
i++
}
const params = {
fileName: this.file.name,
fileMd5: this.fileMd5,
chunkTotal: this.formDataList.length
}
const res = await findFile(params)
// 全部切完以后 发一个请求给后端 拉当前文件后台存储的切片信息 用于检测有多少上传成功的切片
const finishList = res.data.file.ExaFileChunk // 上传成功的切片
const IsFinish = res.data.file.IsFinish // 是否是同文件不同命 (文件md5相同 文件名不同 则默认是同一个文件但是不同文件名 此时后台数据库只需要拷贝一下数据库文件即可 不需要上传文件 即秒传功能)
if (!IsFinish) {
// 当是断点续传时候
this.waitUpLoad = this.formDataList.filter(all => {
return !(
finishList &&
finishList.some(fi => fi.FileChunkNumber === all.key)
) // 找出需要上传的切片
})
} else {
this.waitUpLoad = [] // 秒传则没有需要上传的切片
}
this.waitNum = this.waitUpLoad.length // 记录长度用于百分比展示
}
} else {
this.limitFileSize = true
this.$message('请上传小于5M文件')
}
},
getFile() {
// 确定按钮
if (this.file == null) {
this.$message('请先上传文件')
return
}
this.percentage = Math.floor(((this.formDataList.length-this.waitNum)/this.formDataList.length)*100)
if(this.percentage == 100){
this.percentageFlage = false
}
this.sliceFile() // 上传切片
},
sliceFile() {
this.waitUpLoad &&
this.waitUpLoad.map(item => {
//需要上传的切片
item.formData.append('chunkTotal', this.formDataList.length) // 切片总数携带给后台 总有用的
const fileR = new FileReader() // 功能同上
const file = item.formData.get('file')
fileR.readAsArrayBuffer(file)
fileR.onload = e => {
let spark = new SparkMD5.ArrayBuffer()
spark.append(e.target.result)
item.formData.append('chunkMd5', spark.end()) // 获取当前切片md5 后端用于验证切片完整性
this.upLoadFileSlice(item)
}
})
},
async upLoadFileSlice(item) {
// 切片上传
await axios.post(process.env.VUE_APP_BASE_API+"/fileUploadAndDownload/breakpointContinue",item.formData)
this.waitNum-- // 百分数增加
if (this.waitNum == 0) {
// 切片传完以后 合成文件
const params = {
fileName: this.file.name,
fileMd5: this.fileMd5
}
const res = await breakpointContinueFinish(params)
if (res.success) {
// 合成文件过后 删除缓存切片
const params = {
fileName: this.file.name,
fileMd5: this.fileMd5,
filePath: res.data.filePath
}
await removeChunk(params)
}
}
},
inputChange(){
this.$refs.Input.dispatchEvent(new MouseEvent('click'))
}
}
}
</script>
<style lang='scss' scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
#fromCont{
display: inline-block;
}
.fileUpload{
padding: 4px 10px;
height: 20px;
line-height: 20px;
position: relative;
cursor: pointer;
color: #000;
border: 1px solid #c1c1c1;
border-radius: 4px;
overflow: hidden;
display: inline-block;
input{
position: absolute;
font-size: 100px;
right: 0;
top: 0;
opacity: 0;
cursor: pointer;
}
}
.fileName{
display: inline-block;
vertical-align: top;
margin: 6px 15px 0 15px;
}
.uploadBtn{
position: relative;
top: -10px;
margin-left: 15px;
}
.tips{
margin-top: 30px;
font-size: 14px;
font-weight: 400;
color: #606266;
}
.el-divider{
margin: 0 0 30px 0;
}
.list{
margin-top:15px;
}
.list-item {
display: block;
margin-right: 10px;
color: #606266;
line-height: 25px;
margin-bottom: 5px;
width: 40%;
.percentage{
float: right;
}
}
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to
/* .list-leave-active for below version 2.1.8 */ {
opacity: 0;
transform: translateY(-30px);
}
</style>
\ No newline at end of file
<template>
<div>
<div class="search-term">
<el-form :inline="true" :model="searchInfo" class="demo-form-inline">
<el-form-item>
<el-button @click="openDialog" type="primary">新增客户</el-button>
</el-form-item>
</el-form>
</div>
<el-table
:data="tableData"
border
ref="multipleTable"
stripe
style="width: 100%"
tooltip-effect="dark"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="接入日期" width="180">
<template slot-scope="scope">{{ scope.row.CreatedAt|formatDate }}</template>
</el-table-column>
<el-table-column label="姓名" prop="customerName" width="120"></el-table-column>
<el-table-column label="电话" prop="customerPhoneData" width="120"></el-table-column>
<el-table-column label="接入人ID" prop="sysUserId" width="120"></el-table-column>
<el-table-column label="按钮组" min-width="160">
<template slot-scope="scope">
<el-button @click="updateCustomer(scope.row)" size="small" type="text">变更</el-button>
<el-popover placement="top" width="160" v-model="scope.row.visible">
<p>确定要删除吗?</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="scope.row.visible = false">取消</el-button>
<el-button type="primary" size="mini" @click="deleteCustomer(scope.row)">确定</el-button>
</div>
<el-button type="danger" icon="el-icon-delete" size="mini" slot="reference">删除</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="[10, 30, 50, 100]"
:style="{float:'right',padding:'20px'}"
:total="total"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
<el-dialog :before-close="closeDialog" :visible.sync="dialogFormVisible" title="客户">
<el-form :inline="true" :model="form" label-width="80px">
<el-form-item label="客户名">
<el-input autocomplete="off" v-model="form.customerName"></el-input>
</el-form-item>
<el-form-item label="客户电话">
<el-input autocomplete="off" v-model="form.customerPhoneData"></el-input>
</el-form-item>
</el-form>
<div class="dialog-footer" slot="footer">
<el-button @click="closeDialog">取 消</el-button>
<el-button @click="enterDialog" type="primary">确 定</el-button>
</div>
</el-dialog>
<div class="tips">在资源权限中将此角色的资源权限清空 或者不包含创建者的角色 即可屏蔽此客户资源的显示</div>
</div>
</template>
<script>
import {
createExaCustomer,
updateExaCustomer,
deleteExaCustomer,
getExaCustomer,
getExaCustomerList
} from "@/api/customer";
import { formatTimeToStr } from "@/utils/date";
import infoList from "@/mixins/infoList";
export default {
name: "Customer",
mixins: [infoList],
data() {
return {
listApi: getExaCustomerList,
dialogFormVisible: false,
type: "",
form: {
customerName: "",
customerPhoneData: ""
}
};
},
filters: {
formatDate: function(time) {
if (time != null && time != "") {
var date = new Date(time);
return formatTimeToStr(date, "yyyy-MM-dd hh:mm:ss");
} else {
return "";
}
}
},
methods: {
async updateCustomer(row) {
const res = await getExaCustomer({ ID: row.ID });
this.type = "update";
if (res.code == 0) {
this.form = res.data.customer;
this.dialogFormVisible = true;
}
},
closeDialog() {
this.dialogFormVisible = false;
this.form = {
customerName: "",
customerPhoneData: ""
};
},
async deleteCustomer(row) {
row.visible = false;
const res = await deleteExaCustomer({ ID: row.ID });
if (res.code == 0) {
this.$message({
type: "success",
message: ""
});
if (this.tableData.length == 1) {
this.page--;
}
this.getTableData();
}
},
async enterDialog() {
let res;
switch (this.type) {
case "create":
res = await createExaCustomer(this.form);
break;
case "update":
res = await updateExaCustomer(this.form);
break;
default:
res = await createExaCustomer(this.form);
break;
}
if (res.code == 0) {
this.closeDialog();
this.getTableData();
}
},
openDialog() {
this.type = "create";
this.dialogFormVisible = true;
}
},
created() {
this.getTableData();
}
};
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="upload">
<el-row>
<el-col :span="2">
<el-upload
:action="`${path}/excel/importExcel`"
:headers="{'x-token':token}"
:on-success="loadExcel"
:show-file-list="false"
>
<el-button size="small" type="primary" icon="el-icon-upload2">导入</el-button>
</el-upload>
</el-col>
<el-col :span="2">
<el-button size="small" type="primary" icon="el-icon-download" @click="handleExcelExport('ExcelExport.xlsx')">导出</el-button>
</el-col>
<el-col :span="2">
<el-button size="small" type="success" icon="el-icon-download" @click="downloadExcelTemplate()">下载模板</el-button>
</el-col>
</el-row>
<el-table :data="tableData" border row-key="ID" stripe>
<el-table-column label="ID" min-width="100" prop="ID"></el-table-column>
<el-table-column label="路由Name" min-width="160" prop="name"></el-table-column>
<el-table-column label="路由Path" min-width="160" prop="path"></el-table-column>
<el-table-column label="是否隐藏" min-width="100" prop="hidden">
<template slot-scope="scope">
<span>{{scope.row.hidden?"隐藏":"显示"}}</span>
</template>
</el-table-column>
<el-table-column label="父节点" min-width="90" prop="parentId"></el-table-column>
<el-table-column label="排序" min-width="70" prop="sort"></el-table-column>
<el-table-column label="文件路径" min-width="360" prop="component"></el-table-column>
</el-table>
</div>
</template>
<script>
const path = process.env.VUE_APP_BASE_API;
import { mapGetters } from 'vuex';
import infoList from "@/mixins/infoList";
import { exportExcel, loadExcelData, downloadTemplate } from "@/api/excel";
import { getMenuList } from "@/api/menu";
export default {
name: 'Excel',
mixins: [infoList],
data() {
return {
listApi: getMenuList,
path: path
}
},
computed: {
...mapGetters('user', ['userInfo', 'token'])
},
methods: {
handleExcelExport(fileName) {
if (!fileName || typeof fileName !== "string") {
fileName = "ExcelExport.xlsx";
}
exportExcel(this.tableData, fileName);
},
loadExcel() {
this.listApi = loadExcelData;
this.getTableData();
},
downloadExcelTemplate() {
downloadTemplate('ExcelTemplate.xlsx')
}
},
created() {
this.pageSize = 999;
this.getTableData();
}
}
</script>
\ No newline at end of file
<template>
<div>
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
<script>
export default {
name: "Example",
};
</script>
<style lang="scss"></style>
<template>
<uploader
:options="options"
:file-status-text="statusText"
:autoStart="false"
@file-added="fileAdded"
@file-progress="onFileProgress"
@file-success="onFileSuccess"
@file-error="onFileError"
class="uploader-example"
>
<uploader-unsupport></uploader-unsupport>
<uploader-drop>
<p>拖拽文件至此或点击</p>
<uploader-btn>选择文件</uploader-btn>
</uploader-drop>
<uploader-list></uploader-list>
</uploader>
</template>
<script>
var notUploadedChunks = []; // 已经上传过的文件chunkNumber数组
var isUploaded = false; // 文件已经上传成功了
import { mapGetters } from "vuex";
import { checkFileMd5,mergeFileMd5 } from "@/api/simpleUploader";
import SparkMD5 from "spark-md5";
const path = process.env.VUE_APP_BASE_API;
export default {
name: "simpleUploader",
data(){
return{
md5:""
}
},
computed: {
...mapGetters("user", ["userInfo", "token"]),
statusText() {
return {
success: "成功了",
error: "出错了",
uploading: "上传中",
paused: "暂停中",
waiting: "等待中"
};
},
options() {
return {
target: path + "/simpleUploader/upload",
testChunks: false,
simultaneousUploads: 5,
chunkSize: 2 * 1024 * 1024,
headers: {
"x-token": this.token,
"x-user-id": this.userInfo.ID
},
checkChunkUploadedByResponse(chunk) {
if (isUploaded) {
return true; // return true 会忽略当前文件,不会再发送给后台
} else {
// 根据已经上传过的切片来进行忽略
return (
notUploadedChunks &&
notUploadedChunks.some(
item => item.chunkNumber == chunk.offset + 1
)
);
}
}
};
}
},
methods: {
// 上传单个文件
fileAdded(file) {
this.computeMD5(file); // 生成MD5
},
// 计算MD5值
computeMD5(file) {
var that = this;
isUploaded = false; // 这个文件是否已经上传成功过
notUploadedChunks = []; // 未成功的chunkNumber
var fileReader = new FileReader();
var md5 = "";
file.pause();
fileReader.readAsArrayBuffer(file.file);
fileReader.onload = async function(e) {
if (file.size != e.target.result.byteLength) {
this.error(
"Browser reported success but could not read the file until the end."
);
return false;
}
md5 = SparkMD5.ArrayBuffer.hash(e.target.result, false);
file.uniqueIdentifier = md5;
if (md5 != "") {
const res = await checkFileMd5({ md5: md5 });
if (res.code == 0) {
if (res.data.isDone) {
// 上传成功过
isUploaded = true;
that.$message({
message: "该文件已经上传成功过了,秒传成功。",
type: "success"
});
file.cancel();
} else {
isUploaded = false;
notUploadedChunks = res.data.chunks;
if(notUploadedChunks.length){
file.resume();
}
}
}
}
};
fileReader.onerror = function() {
this.error(
"generater md5 时FileReader异步读取文件出错了,FileReader onerror was triggered, maybe the browser aborted due to high memory usage."
);
return false;
};
},
// 上传进度
onFileProgress() {},
// 上传成功
async onFileSuccess(rootFile, file) {
await mergeFileMd5({md5:file.uniqueIdentifier,fileName:file.name})
},
onFileError(rootFile, file, response) {
this.$message({
message: response,
type: "error"
});
}
}
};
</script>
<style>
.uploader-example {
width: 880px;
padding: 15px;
margin: 115px 15px 20px;
font-size: 12px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}
.uploader-example .uploader-btn {
margin-right: 4px;
}
.uploader-example .uploader-list {
max-height: 440px;
overflow: auto;
overflow-x: hidden;
overflow-y: auto;
}
</style>
\ No newline at end of file
<template>
<div v-loading.fullscreen.lock="fullscreenLoading">
<div class="upload">
<el-row>
<el-col :span="12">
<el-upload
:action="`${path}/fileUploadAndDownload/upload`"
:before-upload="checkFile"
:headers="{ 'x-token': token }"
:on-error="uploadError"
:on-success="uploadSuccess"
:show-file-list="false"
>
<el-button size="small" type="primary">点击上传</el-button>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
</el-col>
<el-col :span="12">
带压缩的上传, (512(k)为压缩限制)
<upload-image v-model="imageUrl" :fileSize="512" :maxWH="1080" />
已上传文件 {{ imageUrl }}
</el-col>
</el-row>
<el-table :data="tableData" border stripe>
<el-table-column label="预览" width="100">
<template slot-scope="scope">
<CustomPic picType="file" :picSrc="scope.row.url" />
</template>
</el-table-column>
<el-table-column label="日期" prop="UpdatedAt" width="180">
<template slot-scope="scope">
<div>{{ scope.row.UpdatedAt | formatDate }}</div>
</template>
</el-table-column>
<el-table-column label="文件名" prop="name" width="180"></el-table-column>
<el-table-column label="链接" prop="url" min-width="300"></el-table-column>
<el-table-column label="标签" prop="tag" width="100">
<template slot-scope="scope">
<el-tag
:type="scope.row.tag === 'jpg' ? 'primary' : 'success'"
disable-transitions
>{{ scope.row.tag }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button @click="downloadFile(scope.row)" size="small" type="text">下载</el-button>
<el-button @click="deleteFile(scope.row)" size="small" type="text">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="[10, 30, 50, 100]"
:style="{ float: 'right', padding: '20px' }"
:total="total"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
</div>
</div>
</template>
<script>
const path = process.env.VUE_APP_BASE_API;
import { mapGetters } from "vuex";
import infoList from "@/mixins/infoList";
import { getFileList, deleteFile } from "@/api/fileUploadAndDownload";
import { downloadImage } from "@/utils/downloadImg";
import { formatTimeToStr } from "@/utils/date";
import CustomPic from "@/components/customPic";
import UploadImage from "@/components/upload/image.vue";
export default {
name: "Upload",
mixins: [infoList],
components: {
CustomPic,
UploadImage
},
data() {
return {
fullscreenLoading: false,
listApi: getFileList,
path: path,
tableData: [],
imageUrl: ""
};
},
computed: {
...mapGetters("user", ["userInfo", "token"])
},
filters: {
formatDate: function(time) {
if (time != null && time != "") {
var date = new Date(time);
return formatTimeToStr(date, "yyyy-MM-dd hh:mm:ss");
} else {
return "";
}
}
},
methods: {
async deleteFile(row) {
this.$confirm("此操作将永久文件, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(async () => {
const res = await deleteFile(row);
if (res.code == 0) {
this.$message({
type: "success",
message: "删除成功!"
});
if (this.tableData.length == 1) {
this.page--;
}
this.getTableData();
}
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除"
});
});
},
checkFile(file) {
this.fullscreenLoading = true;
const isJPG = file.type === "image/jpeg";
const isPng = file.type === "image/png";
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG && !isPng) {
this.$message.error("上传头像图片只能是 JPG或png 格式!");
this.fullscreenLoading = false;
}
if (!isLt2M) {
this.$message.error("上传头像图片大小不能超过 2MB!");
this.fullscreenLoading = false;
}
return (isPng || isJPG) && isLt2M;
},
uploadSuccess(res) {
this.fullscreenLoading = false;
if (res.code == 0) {
this.$message({
type: "success",
message: "上传成功"
});
if (res.code == 0) {
this.getTableData();
}
} else {
this.$message({
type: "warning",
message: res.msg
});
}
},
uploadError() {
this.$message({
type: "error",
message: "上传失败"
});
this.fullscreenLoading = false;
},
downloadFile(row) {
downloadImage(row.url, row.name);
}
},
created() {
this.getTableData();
}
};
</script>
<template>
<ul class="icon-list clearfix">
<li v-for="item in iconList" :key="item">
<span>
<i :class="item"></i>
<span class="icon-name">{{item}}</span>
</span>
</li>
</ul>
</template>
<script>
export default {
name: 'IconList',
data() {
return {
iconList : [
"el-icon-platform-eleme",
"el-icon-eleme",
"el-icon-delete-solid",
"el-icon-delete",
"el-icon-s-tools",
"el-icon-setting",
"el-icon-user-solid",
"el-icon-user",
"el-icon-phone",
"el-icon-phone-outline",
"el-icon-more",
"el-icon-more-outline",
"el-icon-star-on",
"el-icon-star-off",
"el-icon-s-goods",
"el-icon-goods",
"el-icon-warning",
"el-icon-warning-outline",
"el-icon-question",
"el-icon-info",
"el-icon-remove",
"el-icon-circle-plus",
"el-icon-success",
"el-icon-error",
"el-icon-zoom-in",
"el-icon-zoom-out",
"el-icon-remove-outline",
"el-icon-circle-plus-outline",
"el-icon-circle-check",
"el-icon-circle-close",
"el-icon-s-help",
"el-icon-help",
"el-icon-minus",
"el-icon-plus",
"el-icon-check",
"el-icon-close",
"el-icon-picture",
"el-icon-picture-outline",
"el-icon-picture-outline-round",
"el-icon-upload",
"el-icon-upload2",
"el-icon-download",
"el-icon-camera-solid",
"el-icon-camera",
"el-icon-video-camera-solid",
"el-icon-video-camera",
"el-icon-message-solid",
"el-icon-bell",
"el-icon-s-cooperation",
"el-icon-s-order",
"el-icon-s-platform",
"el-icon-s-fold",
"el-icon-s-unfold",
"el-icon-s-operation",
"el-icon-s-promotion",
"el-icon-s-home",
"el-icon-s-release",
"el-icon-s-ticket",
"el-icon-s-management",
"el-icon-s-open",
"el-icon-s-shop",
"el-icon-s-marketing",
"el-icon-s-flag",
"el-icon-s-comment",
"el-icon-s-finance",
"el-icon-s-claim",
"el-icon-s-custom",
"el-icon-s-opportunity",
"el-icon-s-data",
"el-icon-s-check",
"el-icon-s-grid",
"el-icon-menu",
"el-icon-share",
"el-icon-d-caret",
"el-icon-caret-left",
"el-icon-caret-right",
"el-icon-caret-bottom",
"el-icon-caret-top",
"el-icon-bottom-left",
"el-icon-bottom-right",
"el-icon-back",
"el-icon-right",
"el-icon-bottom",
"el-icon-top",
"el-icon-top-left",
"el-icon-top-right",
"el-icon-arrow-left",
"el-icon-arrow-right",
"el-icon-arrow-down",
"el-icon-arrow-up",
"el-icon-d-arrow-left",
"el-icon-d-arrow-right",
"el-icon-video-pause",
"el-icon-video-play",
"el-icon-refresh",
"el-icon-refresh-right",
"el-icon-refresh-left",
"el-icon-finished",
"el-icon-sort",
"el-icon-sort-up",
"el-icon-sort-down",
"el-icon-rank",
"el-icon-loading",
"el-icon-view",
"el-icon-c-scale-to-original",
"el-icon-date",
"el-icon-edit",
"el-icon-edit-outline",
"el-icon-folder",
"el-icon-folder-opened",
"el-icon-folder-add",
"el-icon-folder-remove",
"el-icon-folder-delete",
"el-icon-folder-checked",
"el-icon-tickets",
"el-icon-document-remove",
"el-icon-document-delete",
"el-icon-document-copy",
"el-icon-document-checked",
"el-icon-document",
"el-icon-document-add",
"el-icon-printer",
"el-icon-paperclip",
"el-icon-takeaway-box",
"el-icon-search",
"el-icon-monitor",
"el-icon-attract",
"el-icon-mobile",
"el-icon-scissors",
"el-icon-umbrella",
"el-icon-headset",
"el-icon-brush",
"el-icon-mouse",
"el-icon-coordinate",
"el-icon-magic-stick",
"el-icon-reading",
"el-icon-data-line",
"el-icon-data-board",
"el-icon-pie-chart",
"el-icon-data-analysis",
"el-icon-collection-tag",
"el-icon-film",
"el-icon-suitcase",
"el-icon-suitcase-1",
"el-icon-receiving",
"el-icon-collection",
"el-icon-files",
"el-icon-notebook-1",
"el-icon-notebook-2",
"el-icon-toilet-paper",
"el-icon-office-building",
"el-icon-school",
"el-icon-table-lamp",
"el-icon-house",
"el-icon-no-smoking",
"el-icon-smoking",
"el-icon-shopping-cart-full",
"el-icon-shopping-cart-1",
"el-icon-shopping-cart-2",
"el-icon-shopping-bag-1",
"el-icon-shopping-bag-2",
"el-icon-sold-out",
"el-icon-sell",
"el-icon-present",
"el-icon-box",
"el-icon-bank-card",
"el-icon-money",
"el-icon-coin",
"el-icon-wallet",
"el-icon-discount",
"el-icon-price-tag",
"el-icon-news",
"el-icon-guide",
"el-icon-male",
"el-icon-female",
"el-icon-thumb",
"el-icon-cpu",
"el-icon-link",
"el-icon-connection",
"el-icon-open",
"el-icon-turn-off",
"el-icon-set-up",
"el-icon-chat-round",
"el-icon-chat-line-round",
"el-icon-chat-square",
"el-icon-chat-dot-round",
"el-icon-chat-dot-square",
"el-icon-chat-line-square",
"el-icon-message",
"el-icon-postcard",
"el-icon-position",
"el-icon-turn-off-microphone",
"el-icon-microphone",
"el-icon-close-notification",
"el-icon-bangzhu",
"el-icon-time",
"el-icon-odometer",
"el-icon-crop",
"el-icon-aim",
"el-icon-switch-button",
"el-icon-full-screen",
"el-icon-copy-document",
"el-icon-mic",
"el-icon-stopwatch",
"el-icon-medal-1",
"el-icon-medal",
"el-icon-trophy",
"el-icon-trophy-1",
"el-icon-first-aid-kit",
"el-icon-discover",
"el-icon-place",
"el-icon-location",
"el-icon-location-outline",
"el-icon-location-information",
"el-icon-add-location",
"el-icon-delete-location",
"el-icon-map-location",
"el-icon-alarm-clock",
"el-icon-timer",
"el-icon-watch-1",
"el-icon-watch",
"el-icon-lock",
"el-icon-unlock",
"el-icon-key",
"el-icon-service",
"el-icon-mobile-phone",
"el-icon-bicycle",
"el-icon-truck",
"el-icon-ship",
"el-icon-basketball",
"el-icon-football",
"el-icon-soccer",
"el-icon-baseball",
"el-icon-wind-power",
"el-icon-light-rain",
"el-icon-lightning",
"el-icon-heavy-rain",
"el-icon-sunrise",
"el-icon-sunrise-1",
"el-icon-sunset",
"el-icon-sunny",
"el-icon-cloudy",
"el-icon-partly-cloudy",
"el-icon-cloudy-and-sunny",
"el-icon-moon",
"el-icon-moon-night",
"el-icon-dish",
"el-icon-dish-1",
"el-icon-food",
"el-icon-chicken",
"el-icon-fork-spoon",
"el-icon-knife-fork",
"el-icon-burger",
"el-icon-tableware",
"el-icon-sugar",
"el-icon-dessert",
"el-icon-ice-cream",
"el-icon-hot-water",
"el-icon-water-cup",
"el-icon-coffee-cup",
"el-icon-cold-drink",
"el-icon-goblet",
"el-icon-goblet-full",
"el-icon-goblet-square",
"el-icon-goblet-square-full",
"el-icon-refrigerator",
"el-icon-grape",
"el-icon-watermelon",
"el-icon-cherry",
"el-icon-apple",
"el-icon-pear",
"el-icon-orange",
"el-icon-coffee",
"el-icon-ice-tea",
"el-icon-ice-drink",
"el-icon-milk-tea",
"el-icon-potato-strips",
"el-icon-lollipop",
"el-icon-ice-cream-square",
"el-icon-ice-cream-round",
]
}
},
}
</script>
<style lang="scss" scoped>
.icon-list{
-webkit-tap-highlight-color: transparent;
font-family: icomoon!important;
font-style: normal;
font-weight: 400;
font-variant: normal;
text-transform: none;
-webkit-font-smoothing: antialiased;
overflow: hidden;
list-style: none;
padding: 0!important;
border: 1px solid #eaeefb;
border-radius: 4px;
font-size: 14px;
color: #5e6d82;
line-height: 2em;
li{
-webkit-tap-highlight-color: transparent;
font-family: icomoon!important;
font-style: normal;
font-weight: 400;
font-variant: normal;
text-transform: none;
-webkit-font-smoothing: antialiased;
list-style: none;
float: left;
width: 16.66%;
text-align: center;
height: 120px;
line-height: 120px;
color: #666;
font-size: 13px;
border-right: 1px solid #eee;
border-bottom: 1px solid #eee;
margin-right: -1px;
margin-bottom: -1px;
span{
-webkit-tap-highlight-color: transparent;
font-style: normal;
font-weight: 400;
font-variant: normal;
text-transform: none;
-webkit-font-smoothing: antialiased;
list-style: none;
text-align: center;
font-size: 13px;
display: inline-block;
vertical-align: middle;
line-height: normal;
font-family: Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,SimSun,sans-serif;
color: #99a9bf;
transition: color .15s linear;
i{
-webkit-tap-highlight-color: transparent;
list-style: none;
text-align: center;
font-family: element-icons!important;
font-style: normal;
font-weight: 400;
font-variant: normal;
text-transform: none;
line-height: 1;
vertical-align: baseline;
-webkit-font-smoothing: antialiased;
display: block;
font-size: 32px;
margin-bottom: 15px;
color: #606266;
transition: color .15s linear;
}
}
}
}
</style>
<template>
<div class="init">
<p class="in-one a-fadeinT">欢迎使用VUE-XDORG</p>
<p class="in-two a-fadeinT">您需要初始化您的数据库并且填充初始数据</p>
<div class="form-card in-three a-fadeinB">
<el-form ref="form" :model="form" label-width="100px">
<el-form-item label="数据库类型">
<el-select disabled v-model="form.sqlType" placeholder="请选择">
<el-option key="mysql" label="mysql(目前只支持mysql)" value="mysql">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="host">
<el-input v-model="form.host" placeholder="请输入数据库链接"></el-input>
</el-form-item>
<el-form-item label="port">
<el-input v-model="form.port" placeholder="请输入数据库端口"></el-input>
</el-form-item>
<el-form-item label="userName">
<el-input v-model="form.userName" placeholder="请输入数据库用户名"></el-input>
</el-form-item>
<el-form-item label="password">
<el-input
v-model="form.password"
placeholder="请输入数据库密码(没有则为空)"
></el-input>
</el-form-item>
<el-form-item label="dbName">
<el-input v-model="form.dbName" placeholder="请输入数据库名称"></el-input>
</el-form-item>
<el-form-item>
<div style="text-align: right">
<el-button type="primary" @click="onSubmit">立即初始化</el-button>
</div>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { initDB } from "@/api/initdb";
export default {
name: "Init",
data() {
return {
form: {
sqlType: "mysql",
host: "127.0.0.1",
port: "3306",
userName: "root",
password: "",
dbName: "xdorg",
},
};
},
methods: {
async onSubmit() {
const loading = this.$loading({
lock: true,
text: "正在初始化数据库,请稍候",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)",
});
try {
const res = await initDB(this.form);
if (res.code == 0) {
this.$message({
type: "success",
message: res.msg,
});
this.$router.push({name:"login"})
}
loading.close();
} catch (err) {
loading.close();
}
},
},
};
</script>
<style lang="scss">
.init {
height: 100vh;
flex-direction: column;
display: flex;
align-items: center;
background: #fff;
}
.in-one {
font-size: 26px;
line-height: 98px;
}
.in-two {
font-size: 22px;
}
.form-card {
margin-top: 60px;
box-shadow: 0px 0px 5px 0px rgba(5, 12, 66, 0.15);
width: 60vw;
height: auto;
background: #fff;
padding: 20px;
border-radius: 6px;
}
</style>
<template>
<el-submenu :popper-append-to-body="false" ref="subMenu" :index="routerInfo.name">
<template slot="title">
<i :class="'el-icon-'+routerInfo.meta.icon"></i>
<span slot="title">{{routerInfo.meta.title}}</span>
</template>
<slot></slot>
</el-submenu>
</template>
<script>
export default {
name: 'AsyncSubmenu',
props: {
routerInfo: {
default: function() {
return null
},
type: Object
}
}
}
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<component :is="menuComponent" :routerInfo="routerInfo" v-if="!routerInfo.hidden">
<template v-if="routerInfo.children&&routerInfo.children.length">
<AsideComponent :key="item.name" :routerInfo="item" v-for="item in routerInfo.children" />
</template>
</component>
</template>
<script>
import MenuItem from './menuItem'
import AsyncSubmenu from './asyncSubmenu'
export default {
name: 'AsideComponent',
computed: {
menuComponent() {
if (this.routerInfo.children&&this.routerInfo.children.filter(item=>!item.hidden).length) {
return 'AsyncSubmenu'
} else {
return 'MenuItem'
}
}
},
props: {
routerInfo: {
default: function() {
return null
},
type: Object
}
},
components: {
MenuItem,
AsyncSubmenu
}
}
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<el-menu-item :index="routerInfo.name" :route="{parameters:routerInfo.parameters}">
<i :class="'el-icon-'+routerInfo.meta.icon"></i>
<span slot="title">{{routerInfo.meta.title}}</span>
</el-menu-item>
</template>
<script>
export default {
name: 'MenuItem',
props: {
routerInfo: {
default: function() {
return null
},
type: Object
}
}
}
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<div class="router-history">
<el-tabs
:closable="!(historys.length==1&&this.$route.name==defaultRouter)"
@contextmenu.prevent.native="openContextMenu($event)"
@tab-click="changeTab"
@tab-remove="removeTab"
type="card"
v-model="activeValue"
>
<el-tab-pane
:key="item.name + JSON.stringify(item.query)+JSON.stringify(item.params)"
:label="item.meta.title"
:name="item.name + JSON.stringify(item.query)+JSON.stringify(item.params)"
:tab="item"
v-for="item in historys"
></el-tab-pane>
</el-tabs>
<!--自定义右键菜单html代码-->
<ul :style="{left:left+'px',top:top+'px'}" class="contextmenu" v-show="contextMenuVisible">
<li @click="closeAll">关闭所有</li>
<li @click="closeLeft">关闭左侧</li>
<li @click="closeRight">关闭右侧</li>
<li @click="closeOther">关闭其他</li>
</ul>
</div>
</template>
<script>
import { mapGetters } from "vuex";
const getFmtString = (item)=>{
return item.name +
JSON.stringify(item.query) +
JSON.stringify(item.params)
}
export default {
name: "HistoryComponent",
data() {
return {
historys: [],
activeValue: "",
contextMenuVisible: false,
left: 0,
top: 0,
isCollapse: false,
isMobile: false,
rightActive: ""
};
},
computed: {
...mapGetters("user", ["userInfo"]),
defaultRouter() {
return this.userInfo.authority.defaultRouter;
}
},
created() {
this.$bus.on("mobile", isMobile => {
this.isMobile = isMobile;
});
this.$bus.on("collapse", isCollapse => {
this.isCollapse = isCollapse;
});
const initHistorys = [
{
name: this.defaultRouter,
meta: {
title: "首页"
},
query: {},
params: {}
}
];
this.historys =
JSON.parse(sessionStorage.getItem("historys")) || initHistorys;
if(!window.sessionStorage.getItem("activeValue")){
this.activeValue = getFmtString(this.$route)
}else{
this.activeValue = window.sessionStorage.getItem("activeValue");
}
this.setTab(this.$route);
},
beforeDestroy() {
this.$bus.off("collapse");
this.$bus.off("mobile");
},
methods: {
openContextMenu(e) {
if (this.historys.length == 1 && this.$route.name == this.defaultRouter) {
return false;
}
if (e.srcElement.id) {
this.contextMenuVisible = true;
let width;
if (this.isCollapse) {
width = 54;
} else {
width = 220;
}
if (this.isMobile) {
width = 0;
}
this.left = e.clientX - width;
this.top = e.clientY + 10;
this.rightActive = e.srcElement.id.split("-")[1];
}
},
closeAll() {
this.historys = [
{
name: this.defaultRouter,
meta: {
title: "首页"
},
query: {},
params: {}
}
];
this.$router.push({ name: this.defaultRouter });
this.contextMenuVisible = false;
sessionStorage.setItem("historys", JSON.stringify(this.historys));
},
closeLeft() {
let right;
const rightIndex = this.historys.findIndex(item => {
if (getFmtString(item) == this.rightActive) {
right = item;
}
return (
getFmtString(item) == this.rightActive
);
});
const activeIndex = this.historys.findIndex(
item => getFmtString(item) == this.activeValue
);
this.historys.splice(0, rightIndex);
if (rightIndex > activeIndex) {
this.$router.push(right);
}
sessionStorage.setItem("historys", JSON.stringify(this.historys));
},
closeRight() {
let right;
const leftIndex = this.historys.findIndex(item => {
if ( getFmtString(item) == this.rightActive ) {
right = item;
}
return ( getFmtString(item) == this.rightActive );
});
const activeIndex = this.historys.findIndex(
item => getFmtString(item) == this.activeValue
);
this.historys.splice(leftIndex + 1, this.historys.length);
if (leftIndex < activeIndex) {
this.$router.push(right);
}
sessionStorage.setItem("historys", JSON.stringify(this.historys));
},
closeOther() {
let right;
this.historys = this.historys.filter(item => {
if ( getFmtString(item) == this.rightActive
) {
right = item;
}
return ( getFmtString(item) == this.rightActive
);
});
this.$router.push(right);
sessionStorage.setItem("historys", JSON.stringify(this.historys));
},
isSame(route1, route2) {
if (route1.name != route2.name) {
return false;
}
for (let key in route1.query) {
if (route1.query[key] != route2.query[key]) {
return false;
}
}
for (let key in route1.params) {
if (route1.params[key] != route2.params[key]) {
return false;
}
}
return true;
},
setTab(route) {
if (!this.historys.some(item => this.isSame(item, route))) {
const obj = {};
obj.name = route.name;
obj.meta = route.meta;
obj.query = route.query;
obj.params = route.params;
this.historys.push(obj);
}
window.sessionStorage.setItem(
"activeValue",
getFmtString(this.$route)
);
},
changeTab(component) {
const tab = component.$attrs.tab;
this.$router.push({
name: tab.name,
query: tab.query,
params: tab.params
});
},
removeTab(tab) {
const index = this.historys.findIndex(
item => getFmtString(item) == tab
);
if (
getFmtString(this.$route) == tab
) {
if (this.historys.length == 1) {
this.$router.push({ name: this.defaultRouter });
} else {
if (index < this.historys.length - 1) {
this.$router.push({
name: this.historys[index + 1].name,
query: this.historys[index + 1].query,
params: this.historys[index + 1].params
});
} else {
this.$router.push({
name: this.historys[index - 1].name,
query: this.historys[index - 1].query,
params: this.historys[index - 1].params
});
}
}
}
this.historys.splice(index, 1);
}
},
watch: {
contextMenuVisible() {
if (this.contextMenuVisible) {
document.body.addEventListener("click", () => {
this.contextMenuVisible = false;
});
} else {
document.body.removeEventListener("click", () => {
this.contextMenuVisible = false;
});
}
},
$route(to, now) {
this.historys = this.historys.filter(item => !item.meta.closeTab);
this.setTab(to);
sessionStorage.setItem("historys", JSON.stringify(this.historys));
this.activeValue = window.sessionStorage.getItem("activeValue");
if (now && to && now.name == to.name) {
this.$bus.$emit("reload");
}
}
}
};
</script>
<style lang="scss">
.contextmenu {
width: 100px;
margin: 0;
border: 1px solid #ccc;
background: #fff;
z-index: 3000;
position: absolute;
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
font-size: 14px;
color: #333;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.2);
}
.contextmenu li {
margin: 0;
padding: 7px 16px;
}
.contextmenu li:hover {
background: #f2f2f2;
cursor: pointer;
}
</style>
\ No newline at end of file
<template>
<div>
<el-scrollbar style="height:calc(100vh - 64px)">
<transition :duration="{ enter: 800, leave: 100 }" mode="out-in" name="el-fade-in-linear">
<el-menu
:collapse="isCollapse"
:collapse-transition="true"
:default-active="active"
@select="selectMenuItem"
active-text-color="#fff"
class="el-menu-vertical"
text-color="rgb(191, 203, 217)"
unique-opened
>
<template v-for="item in asyncRouters[0].children">
<aside-component :key="item.name" :routerInfo="item" v-if="!item.hidden" />
</template>
</el-menu>
</transition>
</el-scrollbar>
</div>
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
import AsideComponent from "@/view/layout/aside/asideComponent";
export default {
name: "Aside",
data() {
return {
active: "",
isCollapse: false
};
},
methods: {
...mapMutations("history", ["addHistory"]),
selectMenuItem(index, _, ele) {
const query = {};
const params = {};
ele.route.parameters &&
ele.route.parameters.map(item => {
if (item.type == "query") {
query[item.key] = item.value;
} else {
params[item.key] = item.value;
}
});
if (index === this.$route.name) return;
if (index.indexOf("http://") > -1 || index.indexOf("https://") > -1) {
window.open(index);
} else {
this.$router.push({ name: index, query, params });
}
}
},
computed: {
...mapGetters("router", ["asyncRouters"])
},
components: {
AsideComponent
},
created() {
this.active = this.$route.name;
let screenWidth = document.body.clientWidth;
if (screenWidth < 1000) {
this.isCollapse = !this.isCollapse;
}
this.$bus.on("collapse", item => {
this.isCollapse = item;
});
},
watch: {
$route() {
this.active = this.$route.name;
}
},
beforeDestroy() {
this.$bus.off("collapse");
}
};
</script>
<style lang="scss">
.el-scrollbar {
.el-scrollbar__view {
height: 100%;
}
}
.menu-info {
.menu-contorl {
line-height: 52px;
font-size: 20px;
display: table-cell;
vertical-align: middle;
}
}
</style>
\ No newline at end of file
<template>
<div class="bottom-info">
<div>
<span>Powered by</span>
<span>
<a href="https://codechina.csdn.net/xdorg/vue-xdorg">XDORG</a>
</span>
<el-divider direction="vertical"></el-divider>
<span>Copyright</span>
<span>
<a href="https://codechina.csdn.net/xdorg">XDORG团队</a>
</span>
</div>
</div>
</template>
<script>
export default {
name:"BottomInfo"
}
</script>
<style lang="scss">
.bottom-info {
color: #888;
height: 30px;
line-height: 12px;
a {
color: #888;
}
div {
display: flex;
justify-content: center;
span{
margin: 0 3px;
}
}
}
</style>
<template>
<el-container class="layout-cont">
<el-container :class="[isSider?'openside':'hideside',isMobile ? 'mobile': '']">
<el-row :class="[isShadowBg?'shadowBg':'']" @click.native="changeShadow()"></el-row>
<el-aside class="main-cont main-left">
<div class="tilte">
<img alt class="logoimg" src="~@/assets/nav_logo.png" />
<h2 class="tit-text" v-if="isSider">Gin-Vue-XDORG</h2>
</div>
<Aside class="aside" />
</el-aside>
<!-- 分块滑动功能 -->
<el-main class="main-cont main-right">
<transition :duration="{ enter: 800, leave: 100 }" mode="out-in" name="el-fade-in-linear">
<div
:style="{width: `calc(100% - ${isMobile?'0px':isCollapse?'54px':'220px'})`}"
class="topfix"
>
<el-row>
<!-- :xs="8" :sm="6" :md="4" :lg="3" :xl="1" -->
<el-header class="header-cont">
<el-col :xs="2" :lg="1" :md="1" :sm="1" :xl="1">
<div @click="totalCollapse" class="menu-total">
<i class="el-icon-s-unfold" v-if="isCollapse"></i>
<i class="el-icon-s-fold" v-else></i>
</div>
</el-col>
<el-col :xs="10" :lg="14" :md='14' :sm="9" :xl="14">
<el-breadcrumb class="breadcrumb" separator-class="el-icon-arrow-right">
<el-breadcrumb-item
:key="item.path"
v-for="item in matched.slice(1,matched.length)"
>{{item.meta.title}}</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
<el-col :xs="12" :lg="9" :md="9" :sm="14" :xl="9">
<div class="fl-right right-box">
<Search />
<Screenfull class="screenfull" :style="{cursor:'pointer'}"></Screenfull>
<el-dropdown>
<span class="header-avatar">
<CustomPic/>
<span style="margin-left: 5px">{{userInfo.nickName}}</span>
<i class="el-icon-arrow-down"></i>
</span>
<el-dropdown-menu class="dropdown-group" slot="dropdown">
<el-dropdown-item>
<span>
更多信息
<el-badge is-dot />
</span>
</el-dropdown-item>
<el-dropdown-item @click.native="toPerson" icon="el-icon-s-custom">个人信息</el-dropdown-item>
<el-dropdown-item @click.native="LoginOut" icon="el-icon-table-lamp">登 出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</el-col>
</el-header>
</el-row>
<!-- 当前面包屑用路由自动生成可根据需求修改 -->
<!--
:to="{ path: item.path }" 暂时注释不用-->
<HistoryComponent />
</div>
</transition>
<transition mode="out-in" name="el-fade-in-linear">
<keep-alive>
<router-view v-loading="loadingFlag" element-loading-text="正在加载中" class="admin-box" v-if="$route.meta.keepAlive && reloadFlag"></router-view>
</keep-alive>
</transition>
<transition mode="out-in" name="el-fade-in-linear">
<router-view v-loading="loadingFlag" element-loading-text="正在加载中" class="admin-box" v-if="!$route.meta.keepAlive && reloadFlag"></router-view>
</transition>
<BottomInfo />
</el-main>
</el-container>
</el-container>
</template>
<script>
import Aside from '@/view/layout/aside'
import HistoryComponent from '@/view/layout/aside/historyComponent/history'
import Screenfull from '@/view/layout/screenfull'
import Search from '@/view/layout/search/search'
import BottomInfo from '@/view/layout/bottomInfo/bottomInfo'
import { mapGetters, mapActions } from 'vuex'
import CustomPic from '@/components/customPic'
export default {
name: 'Layout',
data() {
return {
show: false,
isCollapse: false,
isSider: true,
isMobile: false,
isShadowBg: false,
loadingFlag:false,
reloadFlag:true,
value: ''
}
},
components: {
Aside,
HistoryComponent,
Screenfull,
Search,
BottomInfo,
CustomPic
},
methods: {
...mapActions('user', ['LoginOut']),
reload(){
this.reloadFlag = false
this.$nextTick(()=>{
this.reloadFlag = true
})
},
totalCollapse() {
this.isCollapse = !this.isCollapse
this.isSider = !this.isCollapse
this.isShadowBg = !this.isCollapse
this.$bus.emit('collapse', this.isCollapse)
},
toPerson() {
this.$router.push({ name: 'person' })
},
changeShadow() {
this.isShadowBg = !this.isShadowBg
this.isSider = !!this.isCollapse
this.totalCollapse()
},
},
computed: {
...mapGetters('user', ['userInfo']),
title() {
return this.$route.meta.title || '当前页面'
},
matched() {
return this.$route.matched
}
},
mounted() {
let screenWidth = document.body.clientWidth
if (screenWidth < 1000) {
this.isMobile = true
this.isSider = false
this.isCollapse = true
} else if (screenWidth >= 1000 && screenWidth < 1200) {
this.isMobile = false
this.isSider = false
this.isCollapse = true
} else {
this.isMobile = false
this.isSider = true
this.isCollapse = false
}
this.$bus.emit('collapse', this.isCollapse)
this.$bus.emit('mobile', this.isMobile)
this.$bus.on("reload",this.reload)
this.$bus.on("showLoading",()=>{
this.loadingFlag = true
})
this.$bus.on("closeLoading",()=>{
this.loadingFlag = false
})
window.onresize = () => {
return (() => {
let screenWidth = document.body.clientWidth
if (screenWidth < 1000) {
this.isMobile = true
this.isSider = false
this.isCollapse = true
} else if (screenWidth >= 1000 && screenWidth < 1200) {
this.isMobile = false
this.isSider = false
this.isCollapse = true
} else {
this.isMobile = false
this.isSider = true
this.isCollapse = false
}
this.$bus.emit('collapse', this.isCollapse)
this.$bus.emit('mobile', this.isMobile)
})()
}
}
}
</script>
<style lang="scss">
@import '@/style/mobile.scss';
// $headerHigh: 52px;
// $mainHight: 100vh;
// .dropdown-group {
// min-width: 100px;
// }
// .topfix {
// position: fixed;
// top: 0;
// box-sizing: border-box;
// z-index: 999;
// }
// .admin-box {
// min-height: calc(100vh - 240px);
// background-color: rgb(255, 255, 255);
// margin-top: 100px;
// }
// .el-scrollbar__wrap {
// padding-bottom: 17px;
// }
// .layout-cont {
// .right-box {
// text-align: center;
// vertical-align: middle;
// img {
// vertical-align: middle;
// border: 1px solid #ccc;
// border-radius: 6px;
// }
// }
// .header-cont {
// height: $headerHigh !important;
// background: #fff;
// box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
// line-height: $headerHigh;
// }
// .main-cont {
// .breadcrumb {
// line-height: 48px;
// display: inline-block;
// padding: 0 24px;
// // padding: 6px;
// // border-bottom: 1px solid #eee;
// }
// &.el-main {
// overflow: auto;
// background: #fff;
// // padding: 0px 10px;
// // background: #fff;
// }
// height: $mainHight !important;
// overflow: visible;
// position: relative;
// .menu-total {
// // z-index: 5;
// // position: absolute;
// // top: 10px;
// // right: -35px;
// margin-left: -10px;
// float: left;
// margin-top: 10px;
// width: 30px;
// height: 30px;
// line-height: 30px;
// font-size: 30px;
// // border: 0 solid #ffffff;
// // border-radius: 50%;
// // background: #fff;
// }
// .aside {
// overflow: auto;
// // background: #fff;
// &::-webkit-scrollbar {
// display: none;
// }
// }
// .el-menu-vertical {
// height: calc(100vh - 64px) !important;
// visibility: auto;
// &:not(.el-menu--collapse) {
// width: 220px;
// }
// }
// .el-menu--collapse {
// width: 54px;
// li {
// .el-tooltip,
// .el-submenu__title {
// padding: 0px 15px !important;
// }
// }
// }
// &::-webkit-scrollbar {
// display: none;
// }
// &.main-left {
// width: auto !important;
// }
// &.main-right {
// .admin-title {
// float: left;
// font-size: 16px;
// vertical-align: middle;
// margin-left: 20px;
// img {
// vertical-align: middle;
// }
// &.collapse {
// width: 53px;
// }
// }
// }
// }
// }
// .tilte {
// background: #001529;
// min-height: 64px;
// line-height: 64px;
// background: #002140;
// text-align: center;
// .logoimg {
// width: 30px;
// height: 30px;
// vertical-align: middle;
// background: #fff;
// border-radius: 50%;
// padding: 3px;
// }
// .tit-text {
// display: inline-block;
// color: #fff;
// font-weight: 600;
// font-size: 20px;
// vertical-align: middle;
// }
// }
// .screenfull {
// display: inline-block;
// }
// .header-avatar{
// display: flex;
// justify-content: center;
// align-items: center;
// }
</style>
<template>
<div @click="click">
<!-- <svg
t="1508738709248"
class="screenfull-svg"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2069"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="32"
height="32"
v-if="isShow"
>
<path
d="M333.493443 428.647617 428.322206 333.832158 262.572184 168.045297 366.707916 64.444754 64.09683 64.444754 63.853283 366.570793 167.283957 262.460644Z"
p-id="2070"/>
<path
d="M854.845439 760.133334 688.61037 593.95864 593.805144 688.764889 759.554142 854.56096 655.44604 958.161503 958.055079 958.161503 958.274066 656.035464Z"
p-id="2071"/>
<path
d="M688.535669 428.550403 854.31025 262.801405 957.935352 366.921787 957.935352 64.34754 655.809313 64.081481 759.919463 167.535691 593.70793 333.731874Z"
p-id="2072"/>
<path
d="M333.590658 594.033341 167.8171 759.804852 64.218604 655.67219 64.218604 958.270996 366.342596 958.502263 262.234493 855.071589 428.421466 688.86108Z"
p-id="2073"/>
</svg> -->
<svg t="1590133227479" class="screenfull-svg" viewBox="0 0 1024 1024" version="1.1" width="20" height="20" xmlns="http://www.w3.org/2000/svg"
v-if="isShow">
<path id="svg_1" d="m928.512,959.744a32,32 0 0 1 -32,-32l0,-256a32,32 0 0 1 64,0l0,256a32,32 0 0 1 -32,32z" />
<path id="svg_2"
d="m960.512,927.744a32,32 0 0 1 -32,32l-256,0a32,32 0 0 1 0,-64l256,0a32,32 0 0 1 32,32zm-864.768,-863.488a32,32 0 0 1 32,32l0,256a32,32 0 0 1 -64,0l0,-256a32,32 0 0 1 32,-32z" />
<path id="svg_3" d="m63.744,96.256a32,32 0 0 1 32,-32l256,0a32,32 0 0 1 0,64l-256,0a32,32 0 0 1 -32,-32z" />
<path id="svg_4" d="m958.030718,91.777575a32,32 0 0 1 -32,32l-256,0a32,32 0 0 1 0,-64l256,0a32,32 0 0 1 32,32z" />
<path id="svg_5" d="m926.030718,59.777575a32,32 0 0 1 32,32l0,256a32,32 0 0 1 -64,0l0,-256a32,32 0 0 1 32,-32z" />
<path id="svg_6"
d="m940.622718,69.250038a32,32 0 0 1 0,45.248l-247.936,247.936a32,32 0 0 1 -45.248,-45.248l247.936,-247.936a31.936,31.936 0 0 1 45.248,0z" />
<path id="svg_7" d="m61.649508,930.478492a32,32 0 0 1 32,-32l256,0a32,32 0 0 1 0,64l-256,0a32,32 0 0 1 -32,-32z" />
<path id="svg_8" d="m93.649508,962.478492a32,32 0 0 1 -32,-32l0,-256a32,32 0 0 1 64,0l0,256a32,32 0 0 1 -32,32z" />
<path id="svg_9"
d="m79.121508,945.070492a32,32 0 0 1 0,-45.248l247.936,-247.936a32,32 0 0 1 45.248,45.248l-247.936,247.936a32,32 0 0 1 -45.248,0z" />
</svg>
<svg t="1590133734869" class="screenfull-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1862"
xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="20" v-else>
<path d="M928.512 959.744a32 32 0 0 1-32-32v-256a32 32 0 0 1 64 0v256a32 32 0 0 1-32 32z" fill="" p-id="1863"></path>
<path
d="M960.512 927.744a32 32 0 0 1-32 32h-256a32 32 0 0 1 0-64h256a32 32 0 0 1 32 32zM95.744 64.256a32 32 0 0 1 32 32v256a32 32 0 0 1-64 0v-256a32 32 0 0 1 32-32z"
fill="" p-id="1864"></path>
<path d="M63.744 96.256a32 32 0 0 1 32-32h256a32 32 0 0 1 0 64h-256a32 32 0 0 1-32-32z" fill="" p-id="1865"></path>
<path d="M384.064 671.744a32 32 0 0 1-32 32h-256a32 32 0 0 1 0-64h256a32 32 0 0 1 32 32z" fill="" p-id="1866"></path>
<path d="M352.064 639.744a32 32 0 0 1 32 32v256a32 32 0 0 1-64 0v-256a32 32 0 0 1 32-32z" fill="" p-id="1867"></path>
<path d="M366.656 657.216a32 32 0 0 1 0 45.248L118.72 950.4a32 32 0 0 1-45.248-45.248l247.936-247.936a31.936 31.936 0 0 1 45.248 0z" fill=""
p-id="1868"></path>
<path d="M639.616 352.512a32 32 0 0 1 32-32h256a32 32 0 0 1 0 64h-256a32 32 0 0 1-32-32z" fill="" p-id="1869"></path>
<path d="M671.616 384.512a32 32 0 0 1-32-32v-256a32 32 0 0 1 64 0v256a32 32 0 0 1-32 32z" fill="" p-id="1870"></path>
<path d="M657.088 367.104a32 32 0 0 1 0-45.248l247.936-247.936a32 32 0 0 1 45.248 45.248l-247.936 247.936a32 32 0 0 1-45.248 0z" fill=""
p-id="1871"></path>
</svg>
</div>
</template>
<script>
import screenfull from 'screenfull' //引入screenfull
export default {
name: 'Screenfull',
props: {
width: {
type: Number,
default: 22,
},
height: {
type: Number,
default: 22,
},
fill: {
type: String,
default: '#48576a',
},
},
data() {
return {
isShow: true,
}
},
mounted() {
if (screenfull.isEnabled) {
screenfull.on('change', this.changeFullShow)
}
},
methods: {
click() {
if (screenfull.isEnabled) {
screenfull.toggle()
}
},
changeFullShow() {
this.isShow = !screenfull.isFullscreen
},
},
destroyed() {
screenfull.off('change', this.changeFullShow)
},
}
</script>
<style scoped>
.screenfull-svg {
width: 17px;
height: 17px;
cursor: pointer;
fill: #606266;
vertical-align: middle;
margin-right: 15px;
}
</style>
<template>
<div class="search-component">
<transition name="el-fade-in-linear">
<div class="transition-box" style="display: inline-block; " v-show="show">
<el-select
ref="search-input"
@blur="hiddenSearch"
@change="changeRouter"
filterable
placeholder="请选择"
v-model="value"
>
<el-option
:key="item.value"
:label="item.label"
:value="item.value"
v-for="item in routerList"
></el-option>
</el-select>
</div>
</transition>
<div
:style="{display:'inline-block',float:'right',width:'31px',textAlign:'left',fontSize:'16px',paddingTop:'2px'}"
class="user-box"
>
<i @click="$bus.$emit('reload')" :style="{cursor:'pointer'}" class="el-icon-refresh" />
</div>
<div :style="{display:'inline-block',float:'right'}" class="user-box">
<i :style="{cursor:'pointer'}" @click="showSearch()" class="el-icon-search search-icon"></i>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "searchComponent",
data() {
return {
value: "",
show: false
};
},
computed: {
...mapGetters("router", ["routerList"])
},
methods: {
changeRouter() {
this.$router.push({ name: this.value });
this.value = "";
},
hiddenSearch() {
this.show = false;
},
showSearch() {
this.show = true;
this.$nextTick(() => {
this.$refs["search-input"].focus();
});
}
}
};
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<div id="userLayout" class="user-layout-wrapper">
<div class="container">
<div class="top">
<div class="desc">
<img class="logo_login" src="@/assets/logo_login.png" alt="" />
</div>
<div class="header">
<a href="/">
<!-- <img src="~@/assets/logo.png" class="logo" alt="logo" /> -->
<span class="title">编程者联盟</span>
</a>
</div>
</div>
<div class="main">
<el-form
:model="loginForm"
:rules="rules"
ref="loginForm"
@keyup.enter.native="submitForm"
>
<el-form-item prop="username">
<el-input placeholder="请输入用户名" v-model="loginForm.username">
<i class="el-input__icon el-icon-user" slot="suffix"></i
></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
:type="lock === 'lock' ? 'password' : 'text'"
placeholder="请输入密码"
v-model="loginForm.password"
>
<i
:class="'el-input__icon el-icon-' + lock"
@click="changeLock"
slot="suffix"
></i>
</el-input>
</el-form-item>
<el-form-item style="position: relative">
<el-input
v-model="loginForm.captcha"
name="logVerify"
placeholder="请输入验证码"
style="width: 60%"
/>
<div class="vPic">
<img
v-if="picPath"
:src="picPath"
width="100%"
height="100%"
alt="请输入验证码"
@click="loginVefify()"
/>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm" style="width: 100%"
>登 录</el-button
>
</el-form-item>
</el-form>
</div>
<div class="footer">
<div class="links">
<a href="https://blog.csdn.net/xuan_xuan_2/"
><img src="@/assets/xdorg.png" class="link-icon"
/></a>
<a href="https://golang.google.cn/"
><img src="@/assets/gorm.png" class="link-icon"
/></a>
<a href="https://codechina.csdn.net/xdorg/vue-xdorg"
><img src="@/assets/code_china.png" class="link-icon"
/></a>
<a href="https://edu.csdn.net/course/detail/31858"
><img src="@/assets/video.png" class="link-icon"
/></a>
</div>
<div class="copyright">Copyright &copy; {{ curYear }} 💖XDORG</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions } from "vuex";
import { captcha } from "@/api/user";
export default {
name: "Login",
data() {
const checkUsername = (rule, value, callback) => {
if (value.length < 5 || value.length > 12) {
return callback(new Error("请输入正确的用户名"));
} else {
callback();
}
};
const checkPassword = (rule, value, callback) => {
if (value.length < 6 || value.length > 12) {
return callback(new Error("请输入正确的密码"));
} else {
callback();
}
};
return {
curYear: 0,
lock: "lock",
loginForm: {
username: "",
password: "",
captcha: "",
captchaId: "",
},
rules: {
username: [{ validator: checkUsername, trigger: "blur" }],
password: [{ validator: checkPassword, trigger: "blur" }],
},
logVerify: "",
picPath: "",
};
},
created() {
this.loginVefify();
this.curYear = new Date().getFullYear();
},
methods: {
...mapActions("user", ["LoginIn"]),
async login() {
return await this.LoginIn(this.loginForm);
},
async submitForm() {
this.$refs.loginForm.validate(async (v) => {
if (v) {
const flag = await this.login();
if (!flag) {
this.loginVefify();
}
} else {
this.$message({
type: "error",
message: "请正确填写登录信息",
showClose: true,
});
this.loginVefify();
return false;
}
});
},
changeLock() {
this.lock === "lock" ? (this.lock = "unlock") : (this.lock = "lock");
},
loginVefify() {
captcha({}).then((ele) => {
this.picPath = ele.data.picPath;
this.loginForm.captchaId = ele.data.captchaId;
});
},
},
};
</script>
<style scoped lang="scss">
@import "@/style/login.scss";
</style>
<template>
<div>
<el-row>
<el-col :span="6">
<div class="fl-left avatar-box">
<div class="user-card">
<div class="user-headpic-update" :style="{ 'background-image': `url(${(userInfo.headerImg && userInfo.headerImg.slice(0, 4) !== 'http')?path+userInfo.headerImg:userInfo.headerImg})`,'background-repeat':'no-repeat','background-size':'cover' }" >
<span class="update" @click="openChooseImg">
<i class="el-icon-edit"></i>
重新上传</span>
</div>
<div class="user-personality">
<p class="nickname">{{userInfo.nickName}}</p>
<p class="person-info">这个家伙很懒,什么都没有留下</p>
</div>
<div class="user-information">
<ul>
<li>
<i class="el-icon-user"></i>{{userInfo.nickName}}
</li>
<li>
<i class="el-icon-data-analysis"></i>编程者联盟出品
</li>
<li>
<i class="el-icon-video-camera-solid"></i>中国·杭州市·滨江区
</li>
<li>
<i class="el-icon-medal-1"></i>goLang/JavaScript/Vue/Gorm
</li>
</ul>
</div>
</div>
</div>
</el-col>
<el-col :span="18">
<div class="user-addcount">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="账号绑定" name="second">
<ul>
<li>
<p class="title">密保手机</p>
<p class="desc">
已绑定手机:1245678910
<a href="#">立即修改</a>
</p>
</li>
<li>
<p class="title">密保邮箱</p>
<p class="desc">
已绑定邮箱:vue-xdorg@google.com.cn
<a href="#">立即修改</a>
</p>
</li>
<li>
<p class="title">密保问题</p>
<p class="desc">
未设置密保问题
<a href="#">去设置</a>
</p>
</li>
<li>
<p class="title">修改密码</p>
<p class="desc">
修改个人密码
<a href="#" @click="showPassword=true">修改密码</a>
</p>
</li>
</ul>
</el-tab-pane>
</el-tabs>
</div>
</el-col>
</el-row>
<ChooseImg ref="chooseImg" @enter-img="enterImg" />
<el-dialog :visible.sync="showPassword" @close="clearPassword" title="修改密码" width="360px">
<el-form :model="pwdModify" :rules="rules" label-width="80px" ref="modifyPwdForm">
<el-form-item :minlength="6" label="原密码" prop="password">
<el-input show-password v-model="pwdModify.password"></el-input>
</el-form-item>
<el-form-item :minlength="6" label="新密码" prop="newPassword">
<el-input show-password v-model="pwdModify.newPassword"></el-input>
</el-form-item>
<el-form-item :minlength="6" label="确认密码" prop="confirmPassword">
<el-input show-password v-model="pwdModify.confirmPassword"></el-input>
</el-form-item>
</el-form>
<div class="dialog-footer" slot="footer">
<el-button @click="showPassword=false">取 消</el-button>
<el-button @click="savePassword" type="primary">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import ChooseImg from "@/components/chooseImg";
import { setUserInfo,changePassword } from "@/api/user";
import { mapGetters, mapMutations } from "vuex";
const path = process.env.VUE_APP_BASE_API;
export default {
name: "Person",
data() {
return {
path: path,
activeName: "second",
showPassword: false,
pwdModify: {},
rules: {
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 6, message: "最少6个字符", trigger: "blur" }
],
newPassword: [
{ required: true, message: "请输入新密码", trigger: "blur" },
{ min: 6, message: "最少6个字符", trigger: "blur" }
],
confirmPassword: [
{ required: true, message: "请输入确认密码", trigger: "blur" },
{ min: 6, message: "最少6个字符", trigger: "blur" },
{
validator: (rule, value, callback) => {
if (value !== this.pwdModify.newPassword) {
callback(new Error("两次密码不一致"));
} else {
callback();
}
},
trigger: "blur"
}
]
}
};
},
components: {
ChooseImg
},
computed: {
...mapGetters("user", ["userInfo", "token"])
},
methods: {
...mapMutations("user", ["ResetUserInfo"]),
savePassword() {
this.$refs.modifyPwdForm.validate(valid => {
if (valid) {
changePassword({
username: this.userInfo.userName,
password: this.pwdModify.password,
newPassword: this.pwdModify.newPassword
}).then((res) => {
if(res.code == 0){
this.$message.success("修改密码成功!");
}
this.showPassword = false;
});
} else {
return false;
}
});
},
clearPassword() {
this.pwdModify = {
password: "",
newPassword: "",
confirmPassword: ""
};
this.$refs.modifyPwdForm.clearValidate();
},
openChooseImg() {
this.$refs.chooseImg.open();
},
async enterImg(url) {
const res = await setUserInfo({ headerImg: url, ID: this.userInfo.ID });
if (res.code == 0) {
this.ResetUserInfo({ headerImg: url });
this.$message({
type: "success",
message: "设置成功"
});
}
},
handleClick(tab, event) {
console.log(tab, event);
}
}
};
</script>
<style lang="scss">
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
.avatar-box {
box-shadow: -2px 0 20px -16px;
width: 80%;
height: 100%;
.user-card {
min-height: calc(90vh - 200px);
padding: 30px 20px;
text-align: center;
.el-avatar {
border-radius: 50%;
}
.user-personality {
padding: 24px 0;
text-align: center;
p {
font-size: 16px;
}
.nickname {
font-size: 26px;
}
.person-info{
margin-top: 6px;
font-size: 14px;
color:#999
}
}
.user-information {
width: 100%;
height: 100%;
text-align: left;
ul {
display: inline-block;
height: 100%;
li {
i {
margin-right: 8px;
}
padding: 20px 0;
font-size: 16px;
font-weight: 400;
color: #606266;
}
}
}
}
}
.user-addcount {
ul {
li {
.title {
padding: 10px;
font-size: 18px;
color: #696969;
}
.desc {
font-size: 16px;
padding: 0 10px 20px 10px;
color: #a9a9a9;
a {
color: rgb(64, 158, 255);
float: right;
}
}
border-bottom: 2px solid #f0f2f5;
}
}
}
.user-headpic-update{
width: 120px;
height: 120px;
line-height: 120px;
margin: 0 auto;
display: flex;
justify-content: center;
border-radius: 20px;
&:hover{
color: #fff;
background: linear-gradient(to bottom, rgba(255,255,255,0.15) 0%, rgba(0,0,0,0.15) 100%), radial-gradient(at top center, rgba(255,255,255,0.40) 0%, rgba(0,0,0,0.40) 120%) #989898;
background-blend-mode: multiply,multiply;
.update{
color:#fff ;
}
}
.update{
height: 120px;
width: 120px;
text-align: center;
color:transparent;
}
}
</style>
\ No newline at end of file
<template>
<!-- 此路由可作为父类路由通用路由页面使用 如需自定义父类路由页面 请参考 @/view/superAdmin/index.vue -->
<div>
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
<script>
export default {
name: "RouterHolder",
};
</script>
<style lang="scss"></style>
<template>
<div>
<div class="search-term">
<el-form :inline="true" :model="searchInfo" class="demo-form-inline">
<el-form-item label="路径">
<el-input placeholder="路径" v-model="searchInfo.path"></el-input>
</el-form-item>
<el-form-item label="描述">
<el-input placeholder="描述" v-model="searchInfo.description"></el-input>
</el-form-item>
<el-form-item label="api组">
<el-input placeholder="api组" v-model="searchInfo.apiGroup"></el-input>
</el-form-item>
<el-form-item label="请求">
<el-select clearable placeholder="请选择" v-model="searchInfo.method">
<el-option
:key="item.value"
:label="`${item.label}(${item.value})`"
:value="item.value"
v-for="item in methodOptions"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="onSubmit" type="primary">查询</el-button>
</el-form-item>
<el-form-item>
<el-button @click="openDialog('addApi')" type="primary">新增api</el-button>
</el-form-item>
<el-form-item>
<el-popover placement="top" v-model="deleteVisible" width="160">
<p>确定要删除吗?</p>
<div style="text-align: right; margin: 0">
<el-button @click="deleteVisible = false" size="mini" type="text">取消</el-button>
<el-button @click="onDelete" size="mini" type="primary">确定</el-button>
</div>
<el-button icon="el-icon-delete" size="mini" slot="reference" type="danger">批量删除</el-button>
</el-popover>
</el-form-item>
</el-form>
</div>
<el-table :data="tableData" @sort-change="sortChange" border stripe @selection-change="handleSelectionChange">
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column label="id" min-width="60" prop="ID" sortable="custom"></el-table-column>
<el-table-column label="api路径" min-width="150" prop="path" sortable="custom"></el-table-column>
<el-table-column label="api分组" min-width="150" prop="apiGroup" sortable="custom"></el-table-column>
<el-table-column label="api简介" min-width="150" prop="description" sortable="custom"></el-table-column>
<el-table-column label="请求" min-width="150" prop="method" sortable="custom">
<template slot-scope="scope">
<div>
{{scope.row.method}}
<el-tag
:key="scope.row.methodFiletr"
:type="scope.row.method|tagTypeFiletr"
effect="dark"
size="mini"
>{{scope.row.method|methodFiletr}}</el-tag>
<!-- {{scope.row.method|methodFiletr}} -->
</div>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="200">
<template slot-scope="scope">
<el-button @click="editApi(scope.row)" size="small" type="primary" icon="el-icon-edit">编辑</el-button>
<el-button
@click="deleteApi(scope.row)"
size="small"
type="danger"
icon="el-icon-delete"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="[10, 30, 50, 100]"
:style="{float:'right',padding:'20px'}"
:total="total"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
<el-dialog :before-close="closeDialog" :title="dialogTitle" :visible.sync="dialogFormVisible">
<el-form :inline="true" :model="form" :rules="rules" label-width="80px" ref="apiForm">
<el-form-item label="路径" prop="path">
<el-input autocomplete="off" v-model="form.path"></el-input>
</el-form-item>
<el-form-item label="请求" prop="method">
<el-select placeholder="请选择" v-model="form.method">
<el-option
:key="item.value"
:label="`${item.label}(${item.value})`"
:value="item.value"
v-for="item in methodOptions"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="api分组" prop="apiGroup">
<el-input autocomplete="off" v-model="form.apiGroup"></el-input>
</el-form-item>
<el-form-item label="api简介" prop="description">
<el-input autocomplete="off" v-model="form.description"></el-input>
</el-form-item>
</el-form>
<div class="warning">新增Api需要在角色管理内配置权限才可使用</div>
<div class="dialog-footer" slot="footer">
<el-button @click="closeDialog">取 消</el-button>
<el-button @click="enterDialog" type="primary">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
// 获取列表内容封装在mixins内部 getTableData方法 初始化已封装完成 条件搜索时候 请把条件安好后台定制的结构体字段 放到 this.searchInfo 中即可实现条件搜索
import {
getApiById,
getApiList,
createApi,
updateApi,
deleteApi,
deleteApisByIds
} from "@/api/api";
import infoList from "@/mixins/infoList";
import { toSQLLine } from "@/utils/stringFun";
const methodOptions = [
{
value: "POST",
label: "创建",
type: "success"
},
{
value: "GET",
label: "查看",
type: ""
},
{
value: "PUT",
label: "更新",
type: "warning"
},
{
value: "DELETE",
label: "删除",
type: "danger"
}
];
export default {
name: "Api",
mixins: [infoList],
data() {
return {
deleteVisible:false,
listApi: getApiList,
dialogFormVisible: false,
dialogTitle: "新增Api",
apis:[],
form: {
path: "",
apiGroup: "",
method: "",
description: ""
},
methodOptions: methodOptions,
type: "",
rules: {
path: [{ required: true, message: "请输入api路径", trigger: "blur" }],
apiGroup: [
{ required: true, message: "请输入组名称", trigger: "blur" }
],
method: [
{ required: true, message: "请选择请求方式", trigger: "blur" }
],
description: [
{ required: true, message: "请输入api介绍", trigger: "blur" }
]
}
};
},
methods: {
// 选中api
handleSelectionChange(val) {
this.apis = val;
},
async onDelete(){
const ids = this.apis.map(item=>item.ID)
const res = await deleteApisByIds({ids})
if(res.code==0){
this.$message({
type:"success",
message:res.msg
})
if (this.tableData.length == ids.length) {
this.page--;
}
this.deleteVisible = false
this.getTableData()
}
},
// 排序
sortChange({ prop, order }) {
if (prop) {
this.searchInfo.orderKey = toSQLLine(prop);
this.searchInfo.desc = order == "descending";
}
this.getTableData();
},
//条件搜索前端看此方法
onSubmit() {
this.page = 1;
this.pageSize = 10;
this.getTableData();
},
initForm() {
this.$refs.apiForm.resetFields();
this.form = {
path: "",
apiGroup: "",
method: "",
description: ""
};
},
closeDialog() {
this.initForm();
this.dialogFormVisible = false;
},
openDialog(type) {
switch (type) {
case "addApi":
this.dialogTitle = "新增Api";
break;
case "edit":
this.dialogTitle = "编辑Api";
break;
default:
break;
}
this.type = type;
this.dialogFormVisible = true;
},
async editApi(row) {
const res = await getApiById({ id: row.ID });
this.form = res.data.api;
this.openDialog("edit");
},
async deleteApi(row) {
this.$confirm("此操作将永久删除所有角色下该api, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(async () => {
const res = await deleteApi(row);
if (res.code == 0) {
this.$message({
type: "success",
message: "删除成功!"
});
if (this.tableData.length == 1) {
this.page--;
}
this.getTableData();
}
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除"
});
});
},
async enterDialog() {
this.$refs.apiForm.validate(async valid => {
if (valid) {
switch (this.type) {
case "addApi":
{
const res = await createApi(this.form);
if (res.code == 0) {
this.$message({
type: "success",
message: "添加成功",
showClose: true
});
}
this.getTableData();
this.closeDialog();
}
break;
case "edit":
{
const res = await updateApi(this.form);
if (res.code == 0) {
this.$message({
type: "success",
message: "编辑成功",
showClose: true
});
}
this.getTableData();
this.closeDialog();
}
break;
default:
{
this.$message({
type: "error",
message: "未知操作",
showClose: true
});
}
break;
}
}
});
}
},
filters: {
methodFiletr(value) {
const target = methodOptions.filter(item => item.value === value)[0];
// return target && `${target.label}(${target.value})`
return target && `${target.label}`;
},
tagTypeFiletr(value) {
const target = methodOptions.filter(item => item.value === value)[0];
return target && `${target.type}`;
}
},
created() {
this.getTableData();
}
};
</script>
<style scoped lang="scss">
.button-box {
padding: 10px 20px;
.el-button {
float: right;
}
}
.el-tag--mini {
margin-left: 5px;
}
.warning {
color: #dc143c;
}
</style>
\ No newline at end of file
<template>
<div class="authority">
<div class="button-box clearflex">
<el-button @click="addAuthority('0')" type="primary">新增角色</el-button>
</div>
<el-table
:data="tableData"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
border
row-key="authorityId"
stripe
style="width: 100%"
>
<el-table-column label="角色id" min-width="180" prop="authorityId"></el-table-column>
<el-table-column label="角色名称" min-width="180" prop="authorityName"></el-table-column>
<el-table-column fixed="right" label="操作" width="460">
<template slot-scope="scope">
<el-button @click="opdendrawer(scope.row)" size="small" type="primary">设置权限</el-button>
<el-button
@click="addAuthority(scope.row.authorityId)"
icon="el-icon-plus"
size="small"
type="primary"
>新增子角色</el-button>
<el-button
@click="copyAuthority(scope.row)"
icon="el-icon-copy-document"
size="small"
type="primary"
>拷贝</el-button>
<el-button
@click="editAuthority(scope.row)"
icon="el-icon-edit"
size="small"
type="primary"
>编辑</el-button>
<el-button
@click="deleteAuth(scope.row)"
icon="el-icon-delete"
size="small"
type="danger"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 新增角色弹窗 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogFormVisible">
<el-form :model="form" :rules="rules" ref="authorityForm">
<el-form-item label="父级角色" prop="parentId">
<el-cascader
:disabled="dialogType=='add'"
:options="AuthorityOption"
:props="{ checkStrictly: true,label:'authorityName',value:'authorityId',disabled:'disabled',emitPath:false}"
:show-all-levels="false"
filterable
v-model="form.parentId"
></el-cascader>
</el-form-item>
<el-form-item label="角色ID" prop="authorityId">
<el-input :disabled="dialogType=='edit'" autocomplete="off" v-model="form.authorityId"></el-input>
</el-form-item>
<el-form-item label="角色姓名" prop="authorityName">
<el-input autocomplete="off" v-model="form.authorityName"></el-input>
</el-form-item>
</el-form>
<div class="dialog-footer" slot="footer">
<el-button @click="closeDialog">取 消</el-button>
<el-button @click="enterDialog" type="primary">确 定</el-button>
</div>
</el-dialog>
<el-drawer :visible.sync="drawer" :with-header="false" size="40%" title="角色配置" v-if="drawer">
<el-tabs :before-leave="autoEnter" class="role-box" type="border-card">
<el-tab-pane label="角色菜单">
<Menus :row="activeRow" ref="menus" />
</el-tab-pane>
<el-tab-pane label="角色api">
<apis :row="activeRow" ref="apis" />
</el-tab-pane>
<el-tab-pane label="资源权限">
<Datas :authority="tableData" :row="activeRow" ref="datas" />
</el-tab-pane>
</el-tabs>
</el-drawer>
</div>
</template>
<script>
// 获取列表内容封装在mixins内部 getTableData方法 初始化已封装完成
import {
getAuthorityList,
deleteAuthority,
createAuthority,
updateAuthority,
copyAuthority
} from "@/api/authority";
import Menus from "@/view/superAdmin/authority/components/menus";
import Apis from "@/view/superAdmin/authority/components/apis";
import Datas from "@/view/superAdmin/authority/components/datas";
import infoList from "@/mixins/infoList";
export default {
name: "Authority",
mixins: [infoList],
data() {
var mustUint = (rule, value, callback) => {
if (!/^[0-9]*[1-9][0-9]*$/.test(value)) {
return callback(new Error("请输入正整数"));
}
return callback();
};
return {
AuthorityOption: [
{
authorityId: "0",
authorityName: "根角色"
}
],
listApi: getAuthorityList,
drawer: false,
dialogType: "add",
activeRow: {},
activeUserId: 0,
dialogTitle: "新增角色",
dialogFormVisible: false,
apiDialogFlag: false,
copyForm: {},
form: {
authorityId: "",
authorityName: "",
parentId: "0"
},
rules: {
authorityId: [
{ required: true, message: "请输入角色ID", trigger: "blur" },
{ validator: mustUint, trigger: "blur" }
],
authorityName: [
{ required: true, message: "请输入角色名", trigger: "blur" }
],
parentId: [
{ required: true, message: "请选择请求方式", trigger: "blur" }
]
}
};
},
components: {
Menus,
Apis,
Datas
},
methods: {
autoEnter(activeName, oldActiveName) {
const paneArr = ["menus", "apis", "datas"];
if (oldActiveName) {
if (this.$refs[paneArr[oldActiveName]].needConfirm) {
this.$refs[paneArr[oldActiveName]].enterAndNext();
this.$refs[paneArr[oldActiveName]].needConfirm = false;
}
}
},
// 拷贝角色
copyAuthority(row) {
this.setOptions();
this.dialogTitle = "拷贝角色";
this.dialogType = "copy";
for (let k in this.form) {
this.form[k] = row[k];
}
this.copyForm = row;
this.dialogFormVisible = true;
},
opdendrawer(row) {
this.drawer = true;
this.activeRow = row;
},
// 删除角色
deleteAuth(row) {
this.$confirm("此操作将永久删除该角色, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(async () => {
const res = await deleteAuthority({ authorityId: row.authorityId });
if (res.code == 0) {
this.$message({
type: "success",
message: "删除成功!"
});
if (this.tableData.length == 1) {
this.page--;
}
this.getTableData();
}
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除"
});
});
},
// 初始化表单
initForm() {
if (this.$refs.authorityForm) {
this.$refs.authorityForm.resetFields();
}
this.form = {
authorityId: "",
authorityName: "",
parentId: "0"
};
},
// 关闭窗口
closeDialog() {
this.initForm();
this.dialogFormVisible = false;
this.apiDialogFlag = false;
},
// 确定弹窗
async enterDialog() {
if (this.form.authorityId == "0") {
this.$message({
type: "error",
message: "角色id不能为0"
});
return false;
}
this.$refs.authorityForm.validate(async valid => {
if (valid) {
switch (this.dialogType) {
case "add":
{
const res = await createAuthority(this.form);
if (res.code == 0) {
this.$message({
type: "success",
message: "添加成功!"
});
this.getTableData();
this.closeDialog();
}
}
break;
case "edit":
{
const res = await updateAuthority(this.form);
if (res.code == 0) {
this.$message({
type: "success",
message: "添加成功!"
});
this.getTableData();
this.closeDialog();
}
}
break;
case "copy": {
const data = {
authority: {
authorityId: "string",
authorityName: "string",
datauthorityId: [],
parentId: "string"
},
oldAuthorityId: 0
};
data.authority.authorityId = this.form.authorityId;
data.authority.authorityName = this.form.authorityName;
data.authority.parentId = this.form.parentId;
data.authority.dataAuthorityId = this.copyForm.dataAuthorityId;
data.oldAuthorityId = this.copyForm.authorityId;
const res = await copyAuthority(data);
if (res.code == 0) {
this.$message({
type: "success",
message: "复制成功!"
});
this.getTableData();
}
}
}
this.initForm();
this.dialogFormVisible = false;
}
});
},
setOptions() {
this.AuthorityOption = [
{
authorityId: "0",
authorityName: "根角色"
}
];
this.setAuthorityOptions(this.tableData, this.AuthorityOption, false);
},
setAuthorityOptions(AuthorityData, optionsData, disabled) {
this.form.authorityId = String(this.form.authorityId);
AuthorityData &&
AuthorityData.map(item => {
if (item.children && item.children.length) {
const option = {
authorityId: item.authorityId,
authorityName: item.authorityName,
disabled: disabled || item.authorityId == this.form.authorityId,
children: []
};
this.setAuthorityOptions(
item.children,
option.children,
disabled || item.authorityId == this.form.authorityId
);
optionsData.push(option);
} else {
const option = {
authorityId: item.authorityId,
authorityName: item.authorityName,
disabled: disabled || item.authorityId == this.form.authorityId
};
optionsData.push(option);
}
});
},
// 增加角色
addAuthority(parentId) {
this.initForm();
this.dialogTitle = "新增角色";
this.dialogType = "add";
this.form.parentId = parentId;
this.setOptions();
this.dialogFormVisible = true;
},
// 编辑角色
editAuthority(row) {
this.setOptions();
this.dialogTitle = "编辑角色";
this.dialogType = "edit";
for (let key in this.form) {
this.form[key] = row[key];
}
this.setOptions();
this.dialogFormVisible = true;
}
},
async created() {
this.pageSize = 999;
await this.getTableData();
}
};
</script>
<style lang="scss">
.authority {
.el-input-number {
margin-left: 15px;
span {
display: none;
}
}
.button-box {
padding: 10px 20px;
.el-button {
float: right;
}
}
}
.role-box {
.el-tabs__content {
height: calc(100vh - 150px);
overflow: auto;
}
}
</style>
\ No newline at end of file
<template>
<div>
<div class="clearflex">
<el-button @click="authApiEnter" class="fl-right" size="small" type="primary">确 定</el-button>
</div>
<el-tree
:data="apiTreeData"
:default-checked-keys="apiTreeIds"
:props="apiDefaultProps"
@check="nodeChange"
default-expand-all
highlight-current
node-key="onlyId"
ref="apiTree"
show-checkbox
></el-tree>
</div>
</template>
<script>
import { getAllApis } from '@/api/api'
import { UpdateCasbin, getPolicyPathByAuthorityId } from '@/api/casbin'
export default {
name: 'Apis',
props: {
row: {
default: function() {
return {}
},
type: Object
}
},
data() {
return {
apiTreeData: [],
apiTreeIds: [],
needConfirm:false,
apiDefaultProps: {
children: 'children',
label: 'description'
}
}
},
methods: {
nodeChange(){
this.needConfirm = true
},
// 暴露给外层使用的切换拦截统一方法
enterAndNext(){
this.authApiEnter()
},
// 创建api树方法
buildApiTree(apis) {
const apiObj = new Object()
apis &&
apis.map(item => {
item.onlyId = "p:"+item.path+"m:"+item.method
if (Object.prototype.hasOwnProperty.call(apiObj,item.apiGroup)) {
apiObj[item.apiGroup].push(item)
} else {
Object.assign(apiObj, { [item.apiGroup]: [item] })
}
})
const apiTree = []
for (const key in apiObj) {
const treeNode = {
ID: key,
description: key + '',
children: apiObj[key]
}
apiTree.push(treeNode)
}
return apiTree
},
// 关联关系确定
async authApiEnter() {
const checkArr = this.$refs.apiTree.getCheckedNodes(true)
var casbinInfos = []
checkArr&&checkArr.map(item=>{
var casbinInfo = {
path:item.path,
method:item.method
}
casbinInfos.push(casbinInfo)
})
const res = await UpdateCasbin({
authorityId: this.activeUserId,
casbinInfos
})
if (res.code == 0) {
this.$message({ type: 'success', message: "api设置成功" })
}
}
},
async created() {
// 获取api并整理成树结构
const res2 = await getAllApis()
const apis = res2.data.apis
this.apiTreeData = this.buildApiTree(apis)
const res = await getPolicyPathByAuthorityId({
authorityId: this.row.authorityId
})
this.activeUserId = this.row.authorityId
this.apiTreeIds = []
res.data.paths&&res.data.paths.map(item=>{
this.apiTreeIds.push("p:"+item.path+"m:"+item.method)
})
}
}
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<div>
<div class="clearflex" style="margin:18px">
<el-button @click="authDataEnter" class="fl-right" size="small" type="primary">确 定</el-button>
<el-button @click="all" class="fl-left" size="small" type="primary">全选</el-button>
<el-button @click="self" class="fl-left" size="small" type="primary">本角色</el-button>
<el-button @click="selfAndChildren" class="fl-left" size="small" type="primary">本角色及子角色</el-button>
</div>
<el-checkbox-group v-model="dataAuthorityId" @change="selectAuthority">
<el-checkbox v-for="(item,key) in authoritys" :label="item" :key="key">{{item.authorityName}}</el-checkbox>
</el-checkbox-group>
</div>
</template>
<script>
import {setDataAuthority} from '@/api/authority'
export default {
name: 'Datas',
data() {
return {
authoritys:[],
dataAuthorityId:[],
needConfirm:false
}
},
props: {
row: {
default: function() {
return {}
},
type: Object
},
authority: {
default: function() {
return {}
},
type: Array
}
},
methods:{
// 暴露给外层使用的切换拦截统一方法
enterAndNext(){
this.authDataEnter()
},
all(){
this.dataAuthorityId = [...this.authoritys]
this.row.dataAuthorityId = this.dataAuthorityId
this.needConfirm = true
},
self(){
this.dataAuthorityId = this.authoritys.filter(item=>item.authorityId===this.row.authorityId)
this.row.dataAuthorityId = this.dataAuthorityId
this.needConfirm = true
},
selfAndChildren(){
const arrBox = []
this.getChildrenId(this.row,arrBox)
this.dataAuthorityId = this.authoritys.filter(item=>arrBox.indexOf(item.authorityId)>-1)
this.row.dataAuthorityId = this.dataAuthorityId
this.needConfirm = true
},
getChildrenId(row,arrBox){
arrBox.push(row.authorityId)
row.children&&row.children.map(item=>{
this.getChildrenId(item,arrBox)
})
},
// 提交
async authDataEnter(){
const res = await setDataAuthority(this.row)
if(res.code == 0){
this.$message({ type: 'success', message: "资源设置成功" })
}
},
// 平铺角色
roundAuthority(authoritys){
authoritys&&authoritys.map(item=>{
const obj = {}
obj.authorityId = item.authorityId
obj.authorityName = item.authorityName
this.authoritys.push(obj)
if(item.children&&item.children.length){
this.roundAuthority(item.children)
}
})
},
// 选择
selectAuthority(){
this.row.dataAuthorityId = this.dataAuthorityId
this.needConfirm = true
}
},
created() {
this.authoritys = []
this.dataAuthorityId = []
this.roundAuthority(this.authority)
this.row.dataAuthorityId&&this.row.dataAuthorityId.map(item=>{
const obj = this.authoritys&&this.authoritys.filter(au=>au.authorityId === item.authorityId)&&this.authoritys.filter(au=>au.authorityId === item.authorityId)[0]
this.dataAuthorityId.push(obj)
})
}
}
</script>
<style lang="less">
</style>
\ No newline at end of file
<template>
<div>
<div class="clearflex">
<el-button @click="relation" class="fl-right" size="small" type="primary">确 定</el-button>
</div>
<el-tree
:data="menuTreeData"
:default-checked-keys="menuTreeIds"
:props="menuDefaultProps"
@check="nodeChange"
default-expand-all
highlight-current
node-key="ID"
ref="menuTree"
show-checkbox
>
<span class="custom-tree-node" slot-scope="{ node , data }">
<span>{{ node.label }}</span>
<span>
<el-button
type="text"
size="mini"
:style="{color:row.defaultRouter == data.name?'#E6A23C':'#85ce61'}"
:disabled="!node.checked"
@click="() => setDefault(data)">
{{row.defaultRouter == data.name?"首页":"设为首页"}}
</el-button>
</span>
</span>
</el-tree>
</div>
</template>
<script>
import { getBaseMenuTree, getMenuAuthority, addMenuAuthority } from '@/api/menu'
import {
updateAuthority,
} from "@/api/authority";
export default {
name: 'Menus',
props: {
row: {
default: function() {
return {}
},
type: Object
}
},
data() {
return {
menuTreeData: [],
menuTreeIds: [],
needConfirm:false,
menuDefaultProps: {
children: 'children',
label: function(data){
return data.meta.title
}
}
}
},
methods: {
async setDefault(data){
const res = await updateAuthority({authorityId: this.row.authorityId,AuthorityName: this.row.authorityName,parentId: this.row.parentId,defaultRouter:data.name})
if(res.code == 0){
this.$message({type:"success",message:"设置成功"})
this.row.defaultRouter = res.data.authority.defaultRouter
}
},
nodeChange(){
this.needConfirm = true
},
// 暴露给外层使用的切换拦截统一方法
enterAndNext(){
this.relation()
},
// 关联树 确认方法
async relation() {
const checkArr = this.$refs.menuTree.getCheckedNodes(false, true)
const res = await addMenuAuthority({
menus: checkArr,
authorityId: this.row.authorityId
})
if (res.code == 0) {
this.$message({
type: 'success',
message: '菜单设置成功!'
})
}
}
},
async created() {
// 获取所有菜单树
const res = await getBaseMenuTree()
this.menuTreeData = res.data.menus
const res1 = await getMenuAuthority({ authorityId: this.row.authorityId })
const menus = res1.data.menus
const arr = []
menus.map(item => {
// 防止直接选中父级造成全选
if (!menus.some(same => same.parentId === item.menuId)) {
arr.push(Number(item.menuId))
}
})
this.menuTreeIds = arr
}
}
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<div>
<div class="search-term">
<el-form :inline="true" :model="searchInfo" class="demo-form-inline">
<el-form-item label="字典名(中)">
<el-input placeholder="搜索条件" v-model="searchInfo.name"></el-input>
</el-form-item>
<el-form-item label="字典名(英)">
<el-input placeholder="搜索条件" v-model="searchInfo.type"></el-input>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="searchInfo.status" clear placeholder="请选择">
<el-option key="true" label="是" value="true"></el-option>
<el-option key="false" label="否" value="false"></el-option>
</el-select>
</el-form-item>
<el-form-item label="描述">
<el-input placeholder="搜索条件" v-model="searchInfo.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="onSubmit" type="primary">查询</el-button>
</el-form-item>
<el-form-item>
<el-button @click="openDialog" type="primary">新增字典</el-button>
</el-form-item>
</el-form>
</div>
<el-table
:data="tableData"
border
ref="multipleTable"
stripe
style="width: 100%"
tooltip-effect="dark"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="日期" width="180">
<template slot-scope="scope">{{scope.row.CreatedAt|formatDate}}</template>
</el-table-column>
<el-table-column label="字典名(中)" prop="name" width="120"></el-table-column>
<el-table-column label="字典名(英)" prop="type" width="120"></el-table-column>
<el-table-column label="状态" prop="status" width="120">
<template slot-scope="scope">{{scope.row.status|formatBoolean}}</template>
</el-table-column>
<el-table-column label="描述" prop="desc" width="280"></el-table-column>
<el-table-column label="按钮组">
<template slot-scope="scope">
<el-button @click="toDetile(scope.row)" size="small" type="success">详情</el-button>
<el-button @click="updateSysDictionary(scope.row)" size="small" type="primary">变更</el-button>
<el-popover placement="top" width="160" v-model="scope.row.visible">
<p>确定要删除吗?</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="scope.row.visible = false">取消</el-button>
<el-button type="primary" size="mini" @click="deleteSysDictionary(scope.row)">确定</el-button>
</div>
<el-button type="danger" icon="el-icon-delete" size="mini" slot="reference" style="margin-left:10px">删除</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="[10, 30, 50, 100]"
:style="{float:'right',padding:'20px'}"
:total="total"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
<el-dialog :before-close="closeDialog" :visible.sync="dialogFormVisible" title="弹窗操作">
<el-form ref="elForm" :model="formData" :rules="rules" size="medium" label-width="110px">
<el-form-item label="字典名(中)" prop="name">
<el-input
v-model="formData.name"
placeholder="请输入字典名(中)"
clearable
:style="{width: '100%'}"
></el-input>
</el-form-item>
<el-form-item label="字典名(英)" prop="type">
<el-input
v-model="formData.type"
placeholder="请输入字典名(英)"
clearable
:style="{width: '100%'}"
></el-input>
</el-form-item>
<el-form-item label="状态" prop="status" required>
<el-switch v-model="formData.status" active-text="开启" inactive-text="停用"></el-switch>
</el-form-item>
<el-form-item label="描述" prop="desc">
<el-input v-model="formData.desc" placeholder="请输入描述" clearable :style="{width: '100%'}"></el-input>
</el-form-item>
</el-form>
<div class="dialog-footer" slot="footer">
<el-button @click="closeDialog">取 消</el-button>
<el-button @click="enterDialog" type="primary">确 定</el-button>
</div>
</el-dialog>
<div style="margin-top:40px;color:red">获取字典且缓存方法已在前端utils/dictionary 已经封装完成 不必自己书写 使用方法查看文件内注释</div>
</div>
</template>
<script>
import {
createSysDictionary,
deleteSysDictionary,
updateSysDictionary,
findSysDictionary,
getSysDictionaryList
} from "@/api/sysDictionary"; // 此处请自行替换地址
import { formatTimeToStr } from "@/utils/date";
import infoList from "@/mixins/infoList";
export default {
name: "SysDictionary",
mixins: [infoList],
data() {
return {
listApi: getSysDictionaryList,
dialogFormVisible: false,
type: "",
formData: {
name: null,
type: null,
status: true,
desc: null
},
rules: {
name: [
{
required: true,
message: "请输入字典名(中)",
trigger: "blur"
}
],
type: [
{
required: true,
message: "请输入字典名(英)",
trigger: "blur"
}
],
desc: [
{
required: true,
message: "请输入描述",
trigger: "blur"
}
]
}
};
},
filters: {
formatDate: function(time) {
if (time != null && time != "") {
var date = new Date(time);
return formatTimeToStr(date, "yyyy-MM-dd hh:mm:ss");
} else {
return "";
}
},
formatBoolean: function(bool) {
if (bool != null) {
return bool ? "" : "";
} else {
return "";
}
}
},
methods: {
toDetile(row) {
this.$router.push({
name: "dictionaryDetail",
params: {
id: row.ID
}
});
},
//条件搜索前端看此方法
onSubmit() {
this.page = 1;
this.pageSize = 10;
if (this.searchInfo.status == "") {
this.searchInfo.status = null;
}
this.getTableData();
},
async updateSysDictionary(row) {
const res = await findSysDictionary({ ID: row.ID });
this.type = "update";
if (res.code == 0) {
this.formData = res.data.resysDictionary;
this.dialogFormVisible = true;
}
},
closeDialog() {
this.dialogFormVisible = false;
this.formData = {
name: null,
type: null,
status: true,
desc: null
};
},
async deleteSysDictionary(row) {
row.visible = false;
const res = await deleteSysDictionary({ ID: row.ID });
if (res.code == 0) {
this.$message({
type: "success",
message: "删除成功"
});
if (this.tableData.length == 1) {
this.page--;
}
this.getTableData();
}
},
async enterDialog() {
this.$refs["elForm"].validate(async valid => {
if (!valid) return;
let res;
switch (this.type) {
case "create":
res = await createSysDictionary(this.formData);
break;
case "update":
res = await updateSysDictionary(this.formData);
break;
default:
res = await createSysDictionary(this.formData);
break;
}
if (res.code == 0) {
this.closeDialog();
this.getTableData();
}
});
},
openDialog() {
this.type = "create";
this.dialogFormVisible = true;
}
},
async created() {
this.getTableData();
}
};
</script>
<style>
</style>
\ No newline at end of file
<template>
<div>
<div class="search-term">
<el-form :inline="true" :model="searchInfo" class="demo-form-inline">
<el-form-item label="展示值">
<el-input placeholder="搜索条件" v-model="searchInfo.label"></el-input>
</el-form-item>
<el-form-item label="字典值">
<el-input placeholder="搜索条件" v-model="searchInfo.value"></el-input>
</el-form-item>
<el-form-item label="启用状态" prop="status">
<el-select v-model="searchInfo.status" placeholder="请选择">
<el-option key="true" label="是" value="true"></el-option>
<el-option key="false" label="否" value="false"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="onSubmit" type="primary">查询</el-button>
</el-form-item>
<el-form-item>
<el-button @click="openDialog" type="primary">新增字典项</el-button>
</el-form-item>
</el-form>
</div>
<el-table
:data="tableData"
border
ref="multipleTable"
stripe
style="width: 100%"
tooltip-effect="dark"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="日期" width="180">
<template slot-scope="scope">{{scope.row.CreatedAt|formatDate}}</template>
</el-table-column>
<el-table-column label="展示值" prop="label" width="120"></el-table-column>
<el-table-column label="字典值" prop="value" width="120"></el-table-column>
<el-table-column label="启用状态" prop="status" width="120">
<template slot-scope="scope">{{scope.row.status|formatBoolean}}</template>
</el-table-column>
<el-table-column label="排序标记" prop="sort" width="120"></el-table-column>
<el-table-column label="按钮组">
<template slot-scope="scope">
<el-button @click="updateSysDictionaryDetail(scope.row)" size="small" type="primary">变更</el-button>
<el-popover placement="top" width="160" v-model="scope.row.visible">
<p>确定要删除吗?</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="scope.row.visible = false">取消</el-button>
<el-button type="primary" size="mini" @click="deleteSysDictionaryDetail(scope.row)">确定</el-button>
</div>
<el-button type="danger" icon="el-icon-delete" size="mini" slot="reference">删除</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="[10, 30, 50, 100]"
:style="{float:'right',padding:'20px'}"
:total="total"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
<el-dialog :before-close="closeDialog" :visible.sync="dialogFormVisible" title="弹窗操作">
<el-form ref="elForm" :model="formData" :rules="rules" size="medium" label-width="110px">
<el-form-item label="展示值" prop="label">
<el-input
v-model="formData.label"
placeholder="请输入展示值"
clearable
:style="{width: '100%'}"
></el-input>
</el-form-item>
<el-form-item label="字典值" prop="value">
<el-input-number
v-model.number="formData.value"
step-strictly
:step="1"
placeholder="请输入字典值"
clearable
:style="{width: '100%'}"
></el-input-number>
</el-form-item>
<el-form-item label="启用状态" prop="status" required>
<el-switch v-model="formData.status" active-text="开启" inactive-text="停用"></el-switch>
</el-form-item>
<el-form-item label="排序标记" prop="sort">
<el-input-number v-model.number="formData.sort" placeholder="排序标记"></el-input-number>
</el-form-item>
</el-form>
<div class="dialog-footer" slot="footer">
<el-button @click="closeDialog">取 消</el-button>
<el-button @click="enterDialog" type="primary">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
createSysDictionaryDetail,
deleteSysDictionaryDetail,
updateSysDictionaryDetail,
findSysDictionaryDetail,
getSysDictionaryDetailList
} from "@/api/sysDictionaryDetail"; // 此处请自行替换地址
import { formatTimeToStr } from "@/utils/date";
import infoList from "@/mixins/infoList";
export default {
name: "SysDictionaryDetail",
mixins: [infoList],
data() {
return {
listApi: getSysDictionaryDetailList,
dialogFormVisible: false,
type: "",
formData: {
label: null,
value: null,
status: true,
sort: null
},
rules: {
label: [
{
required: true,
message: "请输入展示值",
trigger: "blur"
}
],
value: [
{
required: true,
message: "请输入字典值",
trigger: "blur"
}
],
sort: [
{
required: true,
message: "排序标记",
trigger: "blur"
}
]
}
};
},
filters: {
formatDate: function(time) {
if (time != null && time != "") {
var date = new Date(time);
return formatTimeToStr(date, "yyyy-MM-dd hh:mm:ss");
} else {
return "";
}
},
formatBoolean: function(bool) {
if (bool != null) {
return bool ? "" : "";
} else {
return "";
}
}
},
methods: {
//条件搜索前端看此方法
onSubmit() {
this.page = 1;
this.pageSize = 10;
if (this.searchInfo.status == "") {
this.searchInfo.status = null;
}
this.getTableData();
},
async updateSysDictionaryDetail(row) {
const res = await findSysDictionaryDetail({ ID: row.ID });
this.type = "update";
if (res.code == 0) {
this.formData = res.data.resysDictionaryDetail;
this.dialogFormVisible = true;
}
},
closeDialog() {
this.dialogFormVisible = false;
this.formData = {
label: null,
value: null,
status: true,
sort: null,
sysDictionaryID: ""
};
},
async deleteSysDictionaryDetail(row) {
row.visible = false;
const res = await deleteSysDictionaryDetail({ ID: row.ID });
if (res.code == 0) {
this.$message({
type: "success",
message: "删除成功"
});
if (this.tableData.length == 1) {
this.page--;
}
this.getTableData();
}
},
async enterDialog() {
this.formData.sysDictionaryID = Number(this.$route.params.id);
this.$refs["elForm"].validate(async valid => {
if (!valid) return;
let res;
switch (this.type) {
case "create":
res = await createSysDictionaryDetail(this.formData);
break;
case "update":
res = await updateSysDictionaryDetail(this.formData);
break;
default:
res = await createSysDictionaryDetail(this.formData);
break;
}
if (res.code == 0) {
this.$message({
type: "success",
message: "创建/更改成功"
});
this.closeDialog();
this.getTableData();
}
});
},
openDialog() {
this.type = "create";
this.dialogFormVisible = true;
}
},
created() {
this.searchInfo.sysDictionaryID = Number(this.$route.params.id);
this.getTableData();
}
};
</script>
<style>
</style>
\ No newline at end of file
<template>
<div>
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
<script>
export default {
name: "SuperAdmin",
};
</script>
<style lang="scss"></style>
<template>
<div>
<el-form
:inline="true"
label-width="85px"
ref="menuForm"
label-position="top"
>
<el-form-item prop="icon" style="width:100%">
<i
class="icon"
:class="'el-icon-'+ meta.icon"
style="position: absolute; z-index: 9999; padding: 5px 10px; "
></i>
<el-select clearable filterable class="gva-select" v-model="meta.icon" placeholder="请选择">
<el-option v-for="item in options" :key="item.key" :label="item.key" :value="item.key">
<span class="icon" :class="item.label"></span>
<span style="float: left">{{ item.key }}</span>
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "icon",
data() {
return {
input: "",
options: [
{ key: "platform-eleme", label: "el-icon-platform-eleme" },
{ key: "eleme", label: "el-icon-eleme" },
{ key: "delete-solid", label: "el-icon-delete-solid" },
{ key: "delete", label: "el-icon-delete" },
{ key: "s-tools", label: "el-icon-s-tools" },
{ key: "setting", label: "el-icon-setting" },
{ key: "user-solid", label: "el-icon-user-solid" },
{ key: "user", label: "el-icon-user" },
{ key: "phone", label: "el-icon-phone" },
{ key: "phone-outline", label: "el-icon-phone-outline" },
{ key: "more", label: "el-icon-more" },
{ key: "more-outline", label: "el-icon-more-outline" },
{ key: "star-on", label: "el-icon-star-on" },
{ key: "star-off", label: "el-icon-star-off" },
{ key: "s-goods", label: "el-icon-s-goods" },
{ key: "goods", label: "el-icon-goods" },
{ key: "warning", label: "el-icon-warning" },
{ key: "warning-outline", label: "el-icon-warning-outline" },
{ key: "question", label: "el-icon-question" },
{ key: "info", label: "el-icon-info" },
{ key: "remove", label: "el-icon-remove" },
{ key: "circle-plus", label: "el-icon-circle-plus" },
{ key: "success", label: "el-icon-success" },
{ key: "error", label: "el-icon-error" },
{ key: "zoom-in", label: "el-icon-zoom-in" },
{ key: "zoom-out", label: "el-icon-zoom-out" },
{ key: "remove-outline", label: "el-icon-remove-outline" },
{ key: "circle-plus-outline", label: "el-icon-circle-plus-outline" },
{ key: "circle-check", label: "el-icon-circle-check" },
{ key: "circle-close", label: "el-icon-circle-close" },
{ key: "s-help", label: "el-icon-s-help" },
{ key: "help", label: "el-icon-help" },
{ key: "minus", label: "el-icon-minus" },
{ key: "plus", label: "el-icon-plus" },
{ key: "check", label: "el-icon-check" },
{ key: "close", label: "el-icon-close" },
{ key: "picture", label: "el-icon-picture" },
{ key: "picture-outline", label: "el-icon-picture-outline" },
{
key: "picture-outline-round",
label: "el-icon-picture-outline-round"
},
{ key: "upload", label: "el-icon-upload" },
{ key: "upload2", label: "el-icon-upload2" },
{ key: "download", label: "el-icon-download" },
{ key: "camera-solid", label: "el-icon-camera-solid" },
{ key: "camera", label: "el-icon-camera" },
{ key: "video-camera-solid", label: "el-icon-video-camera-solid" },
{ key: "video-camera", label: "el-icon-video-camera" },
{ key: "message-solid", label: "el-icon-message-solid" },
{ key: "bell", label: "el-icon-bell" },
{ key: "s-cooperation", label: "el-icon-s-cooperation" },
{ key: "s-order", label: "el-icon-s-order" },
{ key: "s-platform", label: "el-icon-s-platform" },
{ key: "s-fold", label: "el-icon-s-fold" },
{ key: "s-unfold", label: "el-icon-s-unfold" },
{ key: "s-operation", label: "el-icon-s-operation" },
{ key: "s-promotion", label: "el-icon-s-promotion" },
{ key: "s-home", label: "el-icon-s-home" },
{ key: "s-release", label: "el-icon-s-release" },
{ key: "s-ticket", label: "el-icon-s-ticket" },
{ key: "s-management", label: "el-icon-s-management" },
{ key: "s-open", label: "el-icon-s-open" },
{ key: "s-shop", label: "el-icon-s-shop" },
{ key: "s-marketing", label: "el-icon-s-marketing" },
{ key: "s-flag", label: "el-icon-s-flag" },
{ key: "s-comment", label: "el-icon-s-comment" },
{ key: "s-finance", label: "el-icon-s-finance" },
{ key: "s-claim", label: "el-icon-s-claim" },
{ key: "s-custom", label: "el-icon-s-custom" },
{ key: "s-opportunity", label: "el-icon-s-opportunity" },
{ key: "s-data", label: "el-icon-s-data" },
{ key: "s-check", label: "el-icon-s-check" },
{ key: "s-grid", label: "el-icon-s-grid" },
{ key: "menu", label: "el-icon-menu" },
{ key: "share", label: "el-icon-share" },
{ key: "d-caret", label: "el-icon-d-caret" },
{ key: "caret-left", label: "el-icon-caret-left" },
{ key: "caret-right", label: "el-icon-caret-right" },
{ key: "caret-bottom", label: "el-icon-caret-bottom" },
{ key: "caret-top", label: "el-icon-caret-top" },
{ key: "bottom-left", label: "el-icon-bottom-left" },
{ key: "bottom-right", label: "el-icon-bottom-right" },
{ key: "back", label: "el-icon-back" },
{ key: "right", label: "el-icon-right" },
{ key: "bottom", label: "el-icon-bottom" },
{ key: "top", label: "el-icon-top" },
{ key: "top-left", label: "el-icon-top-left" },
{ key: "top-right", label: "el-icon-top-right" },
{ key: "arrow-left", label: "el-icon-arrow-left" },
{ key: "arrow-right", label: "el-icon-arrow-right" },
{ key: "arrow-down", label: "el-icon-arrow-down" },
{ key: "arrow-up", label: "el-icon-arrow-up" },
{ key: "d-arrow-left", label: "el-icon-d-arrow-left" },
{ key: "d-arrow-right", label: "el-icon-d-arrow-right" },
{ key: "video-pause", label: "el-icon-video-pause" },
{ key: "video-play", label: "el-icon-video-play" },
{ key: "refresh", label: "el-icon-refresh" },
{ key: "refresh-right", label: "el-icon-refresh-right" },
{ key: "refresh-left", label: "el-icon-refresh-left" },
{ key: "finished", label: "el-icon-finished" },
{ key: "sort", label: "el-icon-sort" },
{ key: "sort-up", label: "el-icon-sort-up" },
{ key: "sort-down", label: "el-icon-sort-down" },
{ key: "rank", label: "el-icon-rank" },
{ key: "loading", label: "el-icon-loading" },
{ key: "view", label: "el-icon-view" },
{ key: "c-scale-to-original", label: "el-icon-c-scale-to-original" },
{ key: "date", label: "el-icon-date" },
{ key: "edit", label: "el-icon-edit" },
{ key: "edit-outline", label: "el-icon-edit-outline" },
{ key: "folder", label: "el-icon-folder" },
{ key: "folder-opened", label: "el-icon-folder-opened" },
{ key: "folder-add", label: "el-icon-folder-add" },
{ key: "folder-remove", label: "el-icon-folder-remove" },
{ key: "folder-delete", label: "el-icon-folder-delete" },
{ key: "folder-checked", label: "el-icon-folder-checked" },
{ key: "tickets", label: "el-icon-tickets" },
{ key: "document-remove", label: "el-icon-document-remove" },
{ key: "document-delete", label: "el-icon-document-delete" },
{ key: "document-copy", label: "el-icon-document-copy" },
{ key: "document-checked", label: "el-icon-document-checked" },
{ key: "document", label: "el-icon-document" },
{ key: "document-add", label: "el-icon-document-add" },
{ key: "printer", label: "el-icon-printer" },
{ key: "paperclip", label: "el-icon-paperclip" },
{ key: "takeaway-box", label: "el-icon-takeaway-box" },
{ key: "search", label: "el-icon-search" },
{ key: "monitor", label: "el-icon-monitor" },
{ key: "attract", label: "el-icon-attract" },
{ key: "mobile", label: "el-icon-mobile" },
{ key: "scissors", label: "el-icon-scissors" },
{ key: "umbrella", label: "el-icon-umbrella" },
{ key: "headset", label: "el-icon-headset" },
{ key: "brush", label: "el-icon-brush" },
{ key: "mouse", label: "el-icon-mouse" },
{ key: "coordinate", label: "el-icon-coordinate" },
{ key: "magic-stick", label: "el-icon-magic-stick" },
{ key: "reading", label: "el-icon-reading" },
{ key: "data-line", label: "el-icon-data-line" },
{ key: "data-board", label: "el-icon-data-board" },
{ key: "pie-chart", label: "el-icon-pie-chart" },
{ key: "data-analysis", label: "el-icon-data-analysis" },
{ key: "collection-tag", label: "el-icon-collection-tag" },
{ key: "film", label: "el-icon-film" },
{ key: "suitcase", label: "el-icon-suitcase" },
{ key: "suitcase-1", label: "el-icon-suitcase-1" },
{ key: "receiving", label: "el-icon-receiving" },
{ key: "collection", label: "el-icon-collection" },
{ key: "files", label: "el-icon-files" },
{ key: "notebook-1", label: "el-icon-notebook-1" },
{ key: "notebook-2", label: "el-icon-notebook-2" },
{ key: "toilet-paper", label: "el-icon-toilet-paper" },
{ key: "office-building", label: "el-icon-office-building" },
{ key: "school", label: "el-icon-school" },
{ key: "table-lamp", label: "el-icon-table-lamp" },
{ key: "house", label: "el-icon-house" },
{ key: "no-smoking", label: "el-icon-no-smoking" },
{ key: "smoking", label: "el-icon-smoking" },
{ key: "shopping-cart-full", label: "el-icon-shopping-cart-full" },
{ key: "shopping-cart-1", label: "el-icon-shopping-cart-1" },
{ key: "shopping-cart-2", label: "el-icon-shopping-cart-2" },
{ key: "shopping-bag-1", label: "el-icon-shopping-bag-1" },
{ key: "shopping-bag-2", label: "el-icon-shopping-bag-2" },
{ key: "sold-out", label: "el-icon-sold-out" },
{ key: "sell", label: "el-icon-sell" },
{ key: "present", label: "el-icon-present" },
{ key: "box", label: "el-icon-box" },
{ key: "bank-card", label: "el-icon-bank-card" },
{ key: "money", label: "el-icon-money" },
{ key: "coin", label: "el-icon-coin" },
{ key: "wallet", label: "el-icon-wallet" },
{ key: "discount", label: "el-icon-discount" },
{ key: "price-tag", label: "el-icon-price-tag" },
{ key: "news", label: "el-icon-news" },
{ key: "guide", label: "el-icon-guide" },
{ key: "male", label: "el-icon-male" },
{ key: "female", label: "el-icon-female" },
{ key: "thumb", label: "el-icon-thumb" },
{ key: "cpu", label: "el-icon-cpu" },
{ key: "link", label: "el-icon-link" },
{ key: "connection", label: "el-icon-connection" },
{ key: "open", label: "el-icon-open" },
{ key: "turn-off", label: "el-icon-turn-off" },
{ key: "set-up", label: "el-icon-set-up" },
{ key: "chat-round", label: "el-icon-chat-round" },
{ key: "chat-line-round", label: "el-icon-chat-line-round" },
{ key: "chat-square", label: "el-icon-chat-square" },
{ key: "chat-dot-round", label: "el-icon-chat-dot-round" },
{ key: "chat-dot-square", label: "el-icon-chat-dot-square" },
{ key: "chat-line-square", label: "el-icon-chat-line-square" },
{ key: "message", label: "el-icon-message" },
{ key: "postcard", label: "el-icon-postcard" },
{ key: "position", label: "el-icon-position" },
{ key: "turn-off-microphone", label: "el-icon-turn-off-microphone" },
{ key: "microphone", label: "el-icon-microphone" },
{ key: "close-notification", label: "el-icon-close-notification" },
{ key: "bangzhu", label: "el-icon-bangzhu" },
{ key: "time", label: "el-icon-time" },
{ key: "odometer", label: "el-icon-odometer" },
{ key: "crop", label: "el-icon-crop" },
{ key: "aim", label: "el-icon-aim" },
{ key: "switch-button", label: "el-icon-switch-button" },
{ key: "full-screen", label: "el-icon-full-screen" },
{ key: "copy-document", label: "el-icon-copy-document" },
{ key: "mic", label: "el-icon-mic" },
{ key: "stopwatch", label: "el-icon-stopwatch" },
{ key: "medal-1", label: "el-icon-medal-1" },
{ key: "medal", label: "el-icon-medal" },
{ key: "trophy", label: "el-icon-trophy" },
{ key: "trophy-1", label: "el-icon-trophy-1" },
{ key: "first-aid-kit", label: "el-icon-first-aid-kit" },
{ key: "discover", label: "el-icon-discover" },
{ key: "place", label: "el-icon-place" },
{ key: "location", label: "el-icon-location" },
{ key: "location-outline", label: "el-icon-location-outline" },
{ key: "location-information", label: "el-icon-location-information" },
{ key: "add-location", label: "el-icon-add-location" },
{ key: "delete-location", label: "el-icon-delete-location" },
{ key: "map-location", label: "el-icon-map-location" },
{ key: "alarm-clock", label: "el-icon-alarm-clock" },
{ key: "timer", label: "el-icon-timer" },
{ key: "watch-1", label: "el-icon-watch-1" },
{ key: "watch", label: "el-icon-watch" },
{ key: "lock", label: "el-icon-lock" },
{ key: "unlock", label: "el-icon-unlock" },
{ key: "key", label: "el-icon-key" },
{ key: "service", label: "el-icon-service" },
{ key: "mobile-phone", label: "el-icon-mobile-phone" },
{ key: "bicycle", label: "el-icon-bicycle" },
{ key: "truck", label: "el-icon-truck" },
{ key: "ship", label: "el-icon-ship" },
{ key: "basketball", label: "el-icon-basketball" },
{ key: "football", label: "el-icon-football" },
{ key: "soccer", label: "el-icon-soccer" },
{ key: "baseball", label: "el-icon-baseball" },
{ key: "wind-power", label: "el-icon-wind-power" },
{ key: "light-rain", label: "el-icon-light-rain" },
{ key: "lightning", label: "el-icon-lightning" },
{ key: "heavy-rain", label: "el-icon-heavy-rain" },
{ key: "sunrise", label: "el-icon-sunrise" },
{ key: "sunrise-1", label: "el-icon-sunrise-1" },
{ key: "sunset", label: "el-icon-sunset" },
{ key: "sunny", label: "el-icon-sunny" },
{ key: "cloudy", label: "el-icon-cloudy" },
{ key: "partly-cloudy", label: "el-icon-partly-cloudy" },
{ key: "cloudy-and-sunny", label: "el-icon-cloudy-and-sunny" },
{ key: "moon", label: "el-icon-moon" },
{ key: "moon-night", label: "el-icon-moon-night" },
{ key: "dish", label: "el-icon-dish" },
{ key: "dish-1", label: "el-icon-dish-1" },
{ key: "food", label: "el-icon-food" },
{ key: "chicken", label: "el-icon-chicken" },
{ key: "fork-spoon", label: "el-icon-fork-spoon" },
{ key: "knife-fork", label: "el-icon-knife-fork" },
{ key: "burger", label: "el-icon-burger" },
{ key: "tableware", label: "el-icon-tableware" },
{ key: "sugar", label: "el-icon-sugar" },
{ key: "dessert", label: "el-icon-dessert" },
{ key: "ice-cream", label: "el-icon-ice-cream" },
{ key: "hot-water", label: "el-icon-hot-water" },
{ key: "water-cup", label: "el-icon-water-cup" },
{ key: "coffee-cup", label: "el-icon-coffee-cup" },
{ key: "cold-drink", label: "el-icon-cold-drink" },
{ key: "goblet", label: "el-icon-goblet" },
{ key: "goblet-full", label: "el-icon-goblet-full" },
{ key: "goblet-square", label: "el-icon-goblet-square" },
{ key: "goblet-square-full", label: "el-icon-goblet-square-full" },
{ key: "refrigerator", label: "el-icon-refrigerator" },
{ key: "grape", label: "el-icon-grape" },
{ key: "watermelon", label: "el-icon-watermelon" },
{ key: "cherry", label: "el-icon-cherry" },
{ key: "apple", label: "el-icon-apple" },
{ key: "pear", label: "el-icon-pear" },
{ key: "orange", label: "el-icon-orange" },
{ key: "coffee", label: "el-icon-coffee" },
{ key: "ice-tea", label: "el-icon-ice-tea" },
{ key: "ice-drink", label: "el-icon-ice-drink" },
{ key: "potato-strips", label: "el-icon-potato-strips" },
{ key: "lollipop", label: "el-icon-lollipop" },
{ key: "ice-cream-square", label: "el-icon-ice-cream-square" },
{ key: "ice-cream-round", label: "el-icon-ice-cream-round" }
],
value: ""
};
},
props: {
meta: {
default: function() {
return {};
},
type: Object
}
},
methods: {}
};
</script>
<style lang="scss">
.icon {
float: left;
color: rgb(132, 146, 166);
font-size: 13px;
line-height: 34px;
margin-right: 10px;
}
.gva-select .el-input__inner {
padding:0 30px !important
}
</style>
<template>
<div>
<div class="button-box clearflex">
<el-button @click="addMenu('0')" type="primary">新增根菜单</el-button>
</div>
<!-- 由于此处菜单跟左侧列表一一对应所以不需要分页 pageSize默认999 -->
<el-table :data="tableData" border row-key="ID" stripe>
<el-table-column label="ID" min-width="100" prop="ID"></el-table-column>
<el-table-column label="路由Name" min-width="160" prop="name"></el-table-column>
<el-table-column label="路由Path" min-width="160" prop="path"></el-table-column>
<el-table-column label="是否隐藏" min-width="100" prop="hidden">
<template slot-scope="scope">
<span>{{scope.row.hidden?"隐藏":"显示"}}</span>
</template>
</el-table-column>
<el-table-column label="父节点" min-width="90" prop="parentId"></el-table-column>
<el-table-column label="排序" min-width="70" prop="sort"></el-table-column>
<el-table-column label="文件路径" min-width="360" prop="component"></el-table-column>
<el-table-column label="展示名称" min-width="120" prop="authorityName">
<template slot-scope="scope">
<span>{{scope.row.meta.title}}</span>
</template>
</el-table-column>
<el-table-column label="图标" min-width="140" prop="authorityName">
<template slot-scope="scope">
<i :class="`el-icon-${scope.row.meta.icon}`"></i>
<span>{{scope.row.meta.icon}}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="300">
<template slot-scope="scope">
<el-button
@click="addMenu(scope.row.ID)"
size="small"
type="primary"
icon="el-icon-edit"
>添加子菜单</el-button>
<el-button
@click="editMenu(scope.row.ID)"
size="small"
type="primary"
icon="el-icon-edit"
>编辑</el-button>
<el-button
@click="deleteMenu(scope.row.ID)"
size="small"
type="danger"
icon="el-icon-delete"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :before-close="handleClose" :title="dialogTitle" :visible.sync="dialogFormVisible">
<el-form
:inline="true"
:model="form"
:rules="rules"
label-position="top"
label-width="85px"
ref="menuForm"
>
<el-form-item label="路由name" prop="path" style="width:30%">
<el-input
@change="changeName"
autocomplete="off"
placeholder="唯一英文字符串"
v-model="form.name"
></el-input>
</el-form-item>
<el-form-item prop="path" style="width:30%">
<div style="display:inline-block" slot="label">
路由path
<el-checkbox style="float:right;margin-left:20px;" v-model="checkFlag">添加参数</el-checkbox>
</div>
<el-input
:disabled="!checkFlag"
autocomplete="off"
placeholder="建议只在后方拼接参数"
v-model="form.path"
></el-input>
</el-form-item>
<el-form-item label="是否隐藏" style="width:30%">
<el-select placeholder="是否在列表隐藏" v-model="form.hidden">
<el-option :value="false" label="否"></el-option>
<el-option :value="true" label="是"></el-option>
</el-select>
</el-form-item>
<el-form-item label="父节点Id" style="width:30%">
<el-cascader
:disabled="!this.isEdit"
:options="menuOption"
:props="{ checkStrictly: true,label:'title',value:'ID',disabled:'disabled',emitPath:false}"
:show-all-levels="false"
filterable
v-model="form.parentId"
></el-cascader>
</el-form-item>
<el-form-item label="文件路径" prop="component" style="width:60%">
<el-input autocomplete="off" v-model="form.component"></el-input>
<span style="font-size:12px;margin-right:12px;">如果菜单包含子菜单,请创建router-view二级路由页面或者</span><el-button size="mini" @click="form.component = 'view/routerHolder.vue'">点我设置</el-button>
</el-form-item>
<el-form-item label="展示名称" prop="meta.title" style="width:30%">
<el-input autocomplete="off" v-model="form.meta.title"></el-input>
</el-form-item>
<el-form-item label="图标" prop="meta.icon" style="width:30%">
<icon :meta="form.meta">
<template slot="prepend">el-icon-</template>
</icon>
</el-form-item>
<el-form-item label="排序标记" prop="sort" style="width:30%">
<el-input autocomplete="off" v-model.number="form.sort"></el-input>
</el-form-item>
<el-form-item label="keepAlive" prop="meta.keepAlive" style="width:30%">
<el-select placeholder="是否keepAlive缓存页面" v-model="form.meta.keepAlive">
<el-option :value="false" label="否"></el-option>
<el-option :value="true" label="是"></el-option>
</el-select>
</el-form-item>
<el-form-item label="closeTab" prop="meta.closeTab" style="width:30%">
<el-select placeholder="是否自动关闭tab" v-model="form.meta.closeTab">
<el-option :value="false" label="否"></el-option>
<el-option :value="true" label="是"></el-option>
</el-select>
</el-form-item>
</el-form>
<div class="warning">新增菜单需要在角色管理内配置权限才可使用</div>
<div>
<el-button
size="small"
type="primary"
icon="el-icon-edit"
@click="addParameter(form)"
>新增菜单参数</el-button>
<el-table :data="form.parameters" stripe style="width: 100%">
<el-table-column prop="type" label="参数类型" width="180">
<template slot-scope="scope">
<el-select v-model="scope.row.type" placeholder="请选择">
<el-option key="query" value="query" label="query"></el-option>
<el-option key="params" value="params" label="params"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column prop="key" label="参数key" width="180">
<template slot-scope="scope">
<div>
<el-input v-model="scope.row.key"></el-input>
</div>
</template>
</el-table-column>
<el-table-column prop="value" label="参数值">
<template slot-scope="scope">
<div>
<el-input v-model="scope.row.value"></el-input>
</div>
</template>
</el-table-column>
<el-table-column>
<template slot-scope="scope">
<div>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
@click="deleteParameter(form.parameters,scope.$index)"
>删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="dialog-footer" slot="footer">
<el-button @click="closeDialog">取 消</el-button>
<el-button @click="enterDialog" type="primary">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
// 获取列表内容封装在mixins内部 getTableData方法 初始化已封装完成
import {
updateBaseMenu,
getMenuList,
addBaseMenu,
deleteBaseMenu,
getBaseMenuById
} from "@/api/menu";
import infoList from "@/mixins/infoList";
import icon from "@/view/superAdmin/menu/icon";
export default {
name: "Menus",
mixins: [infoList],
data() {
return {
checkFlag: false,
listApi: getMenuList,
dialogFormVisible: false,
dialogTitle: "新增菜单",
menuOption: [
{
ID: "0",
title: "根菜单"
}
],
form: {
ID: 0,
path: "",
name: "",
hidden: "",
parentId: "",
component: "",
meta: {
title: "",
icon: "",
defaultMenu: false,
closeTab: false,
keepAlive: false
},
parameters: []
},
rules: {
path: [{ required: true, message: "请输入菜单name", trigger: "blur" }],
component: [
{ required: true, message: "请输入文件路径", trigger: "blur" }
],
"meta.title": [
{ required: true, message: "请输入菜单展示名称", trigger: "blur" }
]
},
isEdit: false,
test: ""
};
},
components: {
icon
},
methods: {
addParameter(form) {
if (!form.parameters) {
this.$set(form, "parameters", []);
}
form.parameters.push({
type: "query",
key: "",
value: ""
});
},
deleteParameter(parameters, index) {
parameters.splice(index, 1);
},
changeName() {
this.form.path = this.form.name;
},
setOptions() {
this.menuOption = [
{
ID: "0",
title: "根目录"
}
];
this.setMenuOptions(this.tableData, this.menuOption, false);
},
setMenuOptions(menuData, optionsData, disabled) {
menuData &&
menuData.map(item => {
if (item.children && item.children.length) {
const option = {
title: item.meta.title,
ID: String(item.ID),
disabled: disabled || item.ID == this.form.ID,
children: []
};
this.setMenuOptions(
item.children,
option.children,
disabled || item.ID == this.form.ID
);
optionsData.push(option);
} else {
const option = {
title: item.meta.title,
ID: String(item.ID),
disabled: disabled || item.ID == this.form.ID
};
optionsData.push(option);
}
});
},
handleClose(done) {
this.initForm();
done();
},
// 懒加载子菜单
load(tree, treeNode, resolve) {
resolve([
{
id: 31,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄"
},
{
id: 32,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄"
}
]);
},
// 删除菜单
deleteMenu(ID) {
this.$confirm("此操作将永久删除所有角色下该菜单, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(async () => {
const res = await deleteBaseMenu({ ID });
if (res.code == 0) {
this.$message({
type: "success",
message: "删除成功!"
});
if (this.tableData.length == 1) {
this.page--;
}
this.getTableData();
}
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除"
});
});
},
// 初始化弹窗内表格方法
initForm() {
this.checkFlag = false;
this.$refs.menuForm.resetFields();
this.form = {
ID: 0,
path: "",
name: "",
hidden: "",
parentId: "",
component: "",
meta: {
title: "",
icon: "",
defaultMenu: false,
keepAlive: ""
}
};
},
// 关闭弹窗
closeDialog() {
this.initForm();
this.dialogFormVisible = false;
},
// 添加menu
async enterDialog() {
this.$refs.menuForm.validate(async valid => {
if (valid) {
let res;
if (this.isEdit) {
res = await updateBaseMenu(this.form);
} else {
res = await addBaseMenu(this.form);
}
if (res.code == 0) {
this.$message({
type: "success",
message: this.isEdit ? "编辑成功" : "添加成功!"
});
this.getTableData();
}
this.initForm();
this.dialogFormVisible = false;
}
});
},
// 添加菜单方法,id为 0则为添加根菜单
addMenu(id) {
this.dialogTitle = "新增菜单";
this.form.parentId = String(id);
this.isEdit = false;
this.setOptions();
this.dialogFormVisible = true;
},
// 修改菜单方法
async editMenu(id) {
this.dialogTitle = "编辑菜单";
const res = await getBaseMenuById({ id });
this.form = res.data.menu;
this.isEdit = true;
this.setOptions();
this.dialogFormVisible = true;
}
},
async created() {
this.pageSize = 999;
await this.getTableData();
}
};
</script>
<style scoped lang="scss">
.button-box {
padding: 10px 20px;
.el-button {
float: right;
}
}
.warning {
color: #dc143c;
}
</style>
<template>
<div>
<div class="search-term">
<el-form :inline="true" :model="searchInfo" class="demo-form-inline">
<el-form-item label="请求方法">
<el-input placeholder="搜索条件" v-model="searchInfo.method"></el-input>
</el-form-item>
<el-form-item label="请求路径">
<el-input placeholder="搜索条件" v-model="searchInfo.path"></el-input>
</el-form-item>
<el-form-item label="结果状态码">
<el-input placeholder="搜索条件" v-model="searchInfo.status"></el-input>
</el-form-item>
<el-form-item>
<el-button @click="onSubmit" type="primary">查询</el-button>
</el-form-item>
<el-form-item>
<el-popover placement="top" v-model="deleteVisible" width="160">
<p>确定要删除吗?</p>
<div style="text-align: right; margin: 0">
<el-button @click="deleteVisible = false" size="mini" type="text">取消</el-button>
<el-button @click="onDelete" size="mini" type="primary">确定</el-button>
</div>
<el-button icon="el-icon-delete" size="mini" slot="reference" type="danger">批量删除</el-button>
</el-popover>
</el-form-item>
</el-form>
</div>
<el-table
:data="tableData"
@selection-change="handleSelectionChange"
border
ref="multipleTable"
stripe
style="width: 100%"
tooltip-effect="dark"
>
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="操作人" width="140">
<template slot-scope="scope">
<div>{{scope.row.user.userName}}({{scope.row.user.nickName}})</div>
</template>
</el-table-column>
<el-table-column label="日期" width="180">
<template slot-scope="scope">{{scope.row.CreatedAt|formatDate}}</template>
</el-table-column>
<el-table-column label="状态码" prop="status" width="120">
<template slot-scope="scope">
<div>
<el-tag type="success">{{ scope.row.status }}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="请求ip" prop="ip" width="120"></el-table-column>
<el-table-column label="请求方法" prop="method" width="120"></el-table-column>
<el-table-column label="请求路径" prop="path" width="240"></el-table-column>
<el-table-column label="请求" prop="path" width="80">
<template slot-scope="scope">
<div>
<el-popover placement="top-start" trigger="hover" v-if="scope.row.body">
<div class="popover-box">
<pre>{{fmtBody(scope.row.body)}}</pre>
</div>
<i class="el-icon-view" slot="reference"></i>
</el-popover>
<span v-else></span>
</div>
</template>
</el-table-column>
<el-table-column label="响应" prop="path" width="80">
<template slot-scope="scope">
<div>
<el-popover placement="top-start" trigger="hover" v-if="scope.row.resp">
<div class="popover-box">
<pre>{{fmtBody(scope.row.resp)}}</pre>
</div>
<i class="el-icon-view" slot="reference"></i>
</el-popover>
<span v-else></span>
</div>
</template>
</el-table-column>
<el-table-column label="按钮组">
<template slot-scope="scope">
<el-popover placement="top" v-model="scope.row.visible" width="160">
<p>确定要删除吗?</p>
<div style="text-align: right; margin: 0">
<el-button @click="scope.row.visible = false" size="mini" type="text">取消</el-button>
<el-button @click="deleteSysOperationRecord(scope.row)" size="mini" type="primary">确定</el-button>
</div>
<el-button icon="el-icon-delete" size="mini" slot="reference" type="danger">删除</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="[10, 30, 50, 100]"
:style="{float:'right',padding:'20px'}"
:total="total"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
</div>
</template>
<script>
import {
deleteSysOperationRecord,
getSysOperationRecordList,
deleteSysOperationRecordByIds
} from "@/api/sysOperationRecord"; // 此处请自行替换地址
import { formatTimeToStr } from "@/utils/date";
import infoList from "@/mixins/infoList";
export default {
name: "SysOperationRecord",
mixins: [infoList],
data() {
return {
listApi: getSysOperationRecordList,
dialogFormVisible: false,
type: "",
deleteVisible: false,
multipleSelection: [],
formData: {
ip: null,
method: null,
path: null,
status: null,
latency: null,
agent: null,
error_message: null,
user_id: null
}
};
},
filters: {
formatDate: function(time) {
if (time != null && time != "") {
var date = new Date(time);
return formatTimeToStr(date, "yyyy-MM-dd hh:mm:ss");
} else {
return "";
}
},
formatBoolean: function(bool) {
if (bool != null) {
return bool ? "" : "";
} else {
return "";
}
}
},
methods: {
//条件搜索前端看此方法
onSubmit() {
this.page = 1;
this.pageSize = 10;
this.getTableData();
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
async onDelete() {
const ids = [];
this.multipleSelection &&
this.multipleSelection.map(item => {
ids.push(item.ID);
});
const res = await deleteSysOperationRecordByIds({ ids });
if (res.code == 0) {
this.$message({
type: "success",
message: "删除成功"
});
if (this.tableData.length == ids.length) {
this.page--;
}
this.deleteVisible = false;
this.getTableData();
}
},
async deleteSysOperationRecord(row) {
row.visible = false;
const res = await deleteSysOperationRecord({ ID: row.ID });
if (res.code == 0) {
this.$message({
type: "success",
message: "删除成功"
});
if (this.tableData.length == 1) {
this.page--;
}
this.getTableData();
}
},
fmtBody(value) {
try {
return JSON.parse(value);
} catch (err) {
return value;
}
}
},
created() {
this.getTableData();
}
};
</script>
<style lang="scss">
.table-expand {
padding-left: 60px;
font-size: 0;
label {
width: 90px;
color: #99a9bf;
.el-form-item {
margin-right: 0;
margin-bottom: 0;
width: 50%;
}
}
}
.popover-box {
background: #112435;
color: #f08047;
height: 600px;
width: 420px;
overflow: auto;
}
.popover-box::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
</style>
\ No newline at end of file
<template>
<div>
<div class="button-box clearflex">
<el-button @click="addUser" type="primary">新增用户</el-button>
</div>
<el-table :data="tableData" border stripe>
<el-table-column label="头像" min-width="50">
<template slot-scope="scope">
<div :style="{'textAlign':'center'}">
<CustomPic :picSrc="scope.row.headerImg" />
</div>
</template>
</el-table-column>
<el-table-column label="uuid" min-width="250" prop="uuid"></el-table-column>
<el-table-column label="用户名" min-width="150" prop="userName"></el-table-column>
<el-table-column label="昵称" min-width="150" prop="nickName"></el-table-column>
<el-table-column label="用户角色" min-width="150">
<template slot-scope="scope">
<el-cascader
@change="changeAuthority(scope.row)"
v-model="scope.row.authority.authorityId"
:options="authOptions"
:show-all-levels="false"
:props="{ checkStrictly: true,label:'authorityName',value:'authorityId',disabled:'disabled',emitPath:false}"
filterable
></el-cascader>
</template>
</el-table-column>
<el-table-column label="操作" min-width="150">
<template slot-scope="scope">
<el-popover placement="top" width="160" v-model="scope.row.visible">
<p>确定要删除此用户吗</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="scope.row.visible = false">取消</el-button>
<el-button type="primary" size="mini" @click="deleteUser(scope.row)">确定</el-button>
</div>
<el-button type="danger" icon="el-icon-delete" size="small" slot="reference">删除</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="[10, 30, 50, 100]"
:style="{float:'right',padding:'20px'}"
:total="total"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
<el-dialog :visible.sync="addUserDialog" custom-class="user-dialog" title="新增用户">
<el-form :rules="rules" ref="userForm" :model="userInfo">
<el-form-item label="用户名" label-width="80px" prop="username">
<el-input v-model="userInfo.username"></el-input>
</el-form-item>
<el-form-item label="密码" label-width="80px" prop="password">
<el-input v-model="userInfo.password"></el-input>
</el-form-item>
<el-form-item label="别名" label-width="80px" prop="nickName">
<el-input v-model="userInfo.nickName"></el-input>
</el-form-item>
<el-form-item label="头像" label-width="80px">
<div style="display:inline-block" @click="openHeaderChange">
<img class="header-img-box" v-if="userInfo.headerImg" :src="userInfo.headerImg" />
<div v-else class="header-img-box">从媒体库选择</div>
</div>
</el-form-item>
<el-form-item label="用户角色" label-width="80px" prop="authorityId">
<el-cascader
v-model="userInfo.authorityId"
:options="authOptions"
:show-all-levels="false"
:props="{ checkStrictly: true,label:'authorityName',value:'authorityId',disabled:'disabled',emitPath:false}"
filterable
></el-cascader>
</el-form-item>
</el-form>
<div class="dialog-footer" slot="footer">
<el-button @click="closeAddUserDialog">取 消</el-button>
<el-button @click="enterAddUserDialog" type="primary">确 定</el-button>
</div>
</el-dialog>
<ChooseImg ref="chooseImg" :target="userInfo" :targetKey="`headerImg`"/>
</div>
</template>
<script>
// 获取列表内容封装在mixins内部 getTableData方法 初始化已封装完成
const path = process.env.VUE_APP_BASE_API;
import {
getUserList,
setUserAuthority,
register,
deleteUser
} from "@/api/user";
import { getAuthorityList } from "@/api/authority";
import infoList from "@/mixins/infoList";
import { mapGetters } from "vuex";
import CustomPic from "@/components/customPic";
import ChooseImg from "@/components/chooseImg";
export default {
name: "Api",
mixins: [infoList],
components: { CustomPic,ChooseImg },
data() {
return {
listApi: getUserList,
path: path,
authOptions: [],
addUserDialog: false,
userInfo: {
username: "",
password: "",
nickName: "",
headerImg: "",
authorityId: ""
},
rules: {
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
{ min: 6, message: "最低6位字符", trigger: "blur" }
],
password: [
{ required: true, message: "请输入用户密码", trigger: "blur" },
{ min: 6, message: "最低6位字符", trigger: "blur" }
],
nickName: [
{ required: true, message: "请输入用户昵称", trigger: "blur" }
],
authorityId: [
{ required: true, message: "请选择用户角色", trigger: "blur" }
]
}
};
},
computed: {
...mapGetters("user", ["token"])
},
methods: {
openHeaderChange(){
this.$refs.chooseImg.open()
},
setOptions(authData) {
this.authOptions = [];
this.setAuthorityOptions(authData, this.authOptions);
},
setAuthorityOptions(AuthorityData, optionsData) {
AuthorityData &&
AuthorityData.map(item => {
if (item.children && item.children.length) {
const option = {
authorityId: item.authorityId,
authorityName: item.authorityName,
children: []
};
this.setAuthorityOptions(item.children, option.children);
optionsData.push(option);
} else {
const option = {
authorityId: item.authorityId,
authorityName: item.authorityName
};
optionsData.push(option);
}
});
},
async deleteUser(row) {
const res = await deleteUser({ id: row.ID });
if (res.code == 0) {
this.getTableData();
row.visible = false;
}
},
async enterAddUserDialog() {
this.$refs.userForm.validate(async valid => {
if (valid) {
const res = await register(this.userInfo);
if (res.code == 0) {
this.$message({ type: "success", message: "创建成功" });
}
await this.getTableData();
this.closeAddUserDialog();
}
});
},
closeAddUserDialog() {
this.$refs.userForm.resetFields();
this.addUserDialog = false;
},
handleAvatarSuccess(res) {
this.userInfo.headerImg = res.data.file.url;
},
addUser() {
this.addUserDialog = true;
},
async changeAuthority(row) {
const res = await setUserAuthority({
uuid: row.uuid,
authorityId: row.authority.authorityId
});
if (res.code == 0) {
this.$message({ type: "success", message: "角色设置成功" });
}
}
},
async created() {
this.getTableData();
const res = await getAuthorityList({ page: 1, pageSize: 999 });
this.setOptions(res.data.list);
}
};
</script>
<style lang="scss">
.button-box {
padding: 10px 20px;
.el-button {
float: right;
}
}
.user-dialog {
.header-img-box {
width: 200px;
height: 200px;
border: 1px dashed #ccc;
border-radius: 20px;
text-align: center;
line-height: 200px;
cursor: pointer;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
border: 1px dashed #d9d9d9 !important;
border-radius: 6px;
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
}
</style>
\ No newline at end of file
<template>
<div>
<el-row :gutter="15" class="system_state">
<el-col :span="12">
<el-card v-if="state.os" class="card_item">
<div slot="header">Runtime</div>
<div>
<el-row :gutter="10">
<el-col :span="12">os:</el-col>
<el-col :span="12" v-text="state.os.goos"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">cpu nums:</el-col>
<el-col :span="12" v-text="state.os.numCpu"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">compiler:</el-col>
<el-col :span="12" v-text="state.os.compiler"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">go version:</el-col>
<el-col :span="12" v-text="state.os.goVersion"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">goroutine nums:</el-col>
<el-col :span="12" v-text="state.os.numGoroutine"></el-col>
</el-row>
</div>
</el-card>
</el-col>
<el-col :span="12">
<el-card v-if="state.disk" class="card_item">
<div slot="header">Disk</div>
<div>
<el-row :gutter="10">
<el-col :span="12">
<el-row :gutter="10">
<el-col :span="12">total (MB)</el-col>
<el-col :span="12" v-text="state.disk.totalMb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (MB)</el-col>
<el-col :span="12" v-text="state.disk.usedMb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">total (GB)</el-col>
<el-col :span="12" v-text="state.disk.totalGb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (GB)</el-col>
<el-col :span="12" v-text="state.disk.usedGb"></el-col>
</el-row>
</el-col>
<el-col :span="12">
<el-progress
type="dashboard"
:percentage="state.disk.usedPercent"
:color="colors"
></el-progress>
</el-col>
</el-row>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="15" class="system_state">
<el-col :span="12">
<el-card
class="card_item"
v-if="state.cpu"
:body-style="{ height: '180px', 'overflow-y': 'scroll' }"
>
<div slot="header">CPU</div>
<div>
<el-row :gutter="10">
<el-col :span="12">physical number of cores:</el-col>
<el-col :span="12" v-text="state.cpu.cores"> </el-col>
</el-row>
<template v-for="(item, index) in state.cpu.cpus">
<el-row :key="index" :gutter="10">
<el-col :span="12">core {{ index }}:</el-col>
<el-col :span="12"
><el-progress
type="line"
:percentage="+item.toFixed(0)"
:color="colors"
></el-progress
></el-col>
</el-row>
</template>
</div>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="card_item" v-if="state.ram">
<div slot="header">Ram</div>
<div>
<el-row :gutter="10">
<el-col :span="12">
<el-row :gutter="10">
<el-col :span="12">total (MB)</el-col>
<el-col :span="12" v-text="state.ram.totalMb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (MB)</el-col>
<el-col :span="12" v-text="state.ram.usedMb"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">total (GB)</el-col>
<el-col :span="12" v-text="state.ram.totalMb / 1024"></el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12">used (GB)</el-col>
<el-col
:span="12"
v-text="(state.ram.usedMb / 1024).toFixed(2)"
></el-col>
</el-row>
</el-col>
<el-col :span="12">
<el-progress
type="dashboard"
:percentage="state.ram.usedPercent"
:color="colors"
></el-progress>
</el-col>
</el-row>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { getSystemState } from "@/api/system.js";
export default {
name: "State",
data() {
return {
timer:null,
state: {},
colors: [
{ color: "#5cb87a", percentage: 20 },
{ color: "#e6a23c", percentage: 40 },
{ color: "#f56c6c", percentage: 80 },
],
};
},
created() {
this.reload();
this.timer = setInterval(() => {
this.reload();
}, 1000*10);
},
beforeDestroy(){
clearInterval(this.timer)
this.timer = null
},
methods: {
async reload() {
const { data } = await getSystemState();
this.state = data.server;
},
},
};
</script>
<style>
.system_state {
padding: 10px;
}
.card_item {
height: 280px;
}
</style>
<template>
<div>
<span style="color:red">搜索时如果条件为LIKE只支持字符串</span>
<el-form
:model="dialogMiddle"
ref="fieldDialogFrom"
label-width="120px"
label-position="left"
:rules="rules"
>
<el-form-item label="Field名称" prop="fieldName">
<el-col :span="6">
<el-input v-model="dialogMiddle.fieldName" autocomplete="off"></el-input>
</el-col>
<el-col :offset="1" :span="2">
<el-button @click="autoFill">自动填充</el-button>
</el-col>
</el-form-item>
<el-form-item label="Field中文名" prop="fieldDesc">
<el-col :span="6">
<el-input v-model="dialogMiddle.fieldDesc" autocomplete="off"></el-input>
</el-col>
</el-form-item>
<el-form-item label="FieldJSON" prop="fieldJson">
<el-col :span="6">
<el-input v-model="dialogMiddle.fieldJson" autocomplete="off"></el-input>
</el-col>
</el-form-item>
<el-form-item label="数据库字段名" prop="columnName">
<el-col :span="6">
<el-input v-model="dialogMiddle.columnName" autocomplete="off"></el-input>
</el-col>
</el-form-item>
<el-form-item label="数据库字段描述" prop="comment">
<el-col :span="6">
<el-input v-model="dialogMiddle.comment" autocomplete="off"></el-input>
</el-col>
</el-form-item>
<el-form-item label="Field数据类型" prop="fieldType">
<el-col :span="8">
<el-select
v-model="dialogMiddle.fieldType"
placeholder="请选择field数据类型"
@change="getDbfdOptions"
clearable
>
<el-option
v-for="item in typeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item label="数据库字段类型" prop="dataType">
<el-col :span="8">
<el-select
:disabled="!dialogMiddle.fieldType"
v-model="dialogMiddle.dataType"
placeholder="请选择数据库字段类型"
clearable
>
<el-option
v-for="item in dbfdOptions"
:key="item.label"
:label="item.label"
:value="item.label"
></el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item label="数据库字段长度" prop="dataTypeLong">
<el-col :span="8">
<el-input placeholder="自定义类型必须指定长度" :disabled="!dialogMiddle.dataType" v-model="dialogMiddle.dataTypeLong"></el-input>
</el-col>
</el-form-item>
<el-form-item label="Field查询条件" prop="fieldSearchType">
<el-col :span="8">
<el-select v-model="dialogMiddle.fieldSearchType" placeholder="请选择Field查询条件" clearable>
<el-option
v-for="item in typeSearchOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item label="关联字典" prop="dictType">
<el-col :span="8">
<el-select :disabled="dialogMiddle.fieldType!='int'" v-model="dialogMiddle.dictType" placeholder="请选择字典" clearable>
<el-option
v-for="item in dictOptions"
:key="item.type"
:label="`${item.type}(${item.name})`"
:value="item.type"
></el-option>
</el-select>
</el-col>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { getDict } from "@/utils/dictionary";
import { toSQLLine , toLowerCase } from "@/utils/stringFun.js";
import { getSysDictionaryList } from "@/api/sysDictionary";
export default {
name: "FieldDialog",
props: {
dialogMiddle: {
type: Object,
default: function() {
return {};
}
}
},
data() {
return {
dbfdOptions: [],
dictOptions: [],
typeSearchOptions: [
{
label: "=",
value: "="
},
{
label: "<>",
value: "<>"
},
{
label: ">",
value: ">"
},
{
label: "<",
value: "<"
},
{
label: "LIKE",
value: "LIKE"
}
],
typeOptions: [
{
label: "字符串",
value: "string"
},
{
label: "整型",
value: "int"
},
{
label: "布尔值",
value: "bool"
},
{
label: "浮点型",
value: "float64"
},
{
label: "时间",
value: "time.Time"
}
],
rules: {
fieldName: [
{ required: true, message: "请输入field英文名", trigger: "blur" }
],
fieldDesc: [
{ required: true, message: "请输入field中文名", trigger: "blur" }
],
fieldJson: [
{ required: true, message: "请输入field格式化json", trigger: "blur" }
],
columnName: [
{ required: true, message: "请输入数据库字段", trigger: "blur" }
],
fieldType: [
{ required: true, message: "请选择field数据类型", trigger: "blur" }
]
}
};
},
methods: {
autoFill(){
this.dialogMiddle.fieldJson = toLowerCase(this.dialogMiddle.fieldName)
this.dialogMiddle.columnName = toSQLLine(this.dialogMiddle.fieldJson)
},
async getDbfdOptions() {
this.dialogMiddle.dataType = ""
this.dialogMiddle.dataTypeLong = ""
this.dialogMiddle.fieldSearchType = ""
this.dialogMiddle.dictType = ""
if (this.dialogMiddle.fieldType) {
const res = await getDict(this.dialogMiddle.fieldType);
this.dbfdOptions = res;
}
}
},
async created() {
const dictRes = await getSysDictionaryList({
page: 1,
pageSize: 999999
});
this.dictOptions = dictRes.data.list
},
};
</script>
<style lang="scss">
</style>
<template>
<div class="previewCode">
<el-tabs v-model="activeName">
<el-tab-pane :label="key" :name="key" v-for="(item,key) in previewCode" :key="key">
<div style="background:#fff;padding:0 20px" :id="key"></div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import marked from "marked"
import hljs from "highlight.js";
// import 'highlight.js/styles/atelier-cave-light.css';
import 'highlight.js/styles/atelier-plateau-light.css';
export default {
props:{
previewCode:{
type:Object,
default(){
return {}
}
}
},
data(){
return{
activeName: "",
}
},
mounted(){
marked.setOptions({
renderer: new marked.Renderer(),
highlight: function(code) {
return hljs.highlightAuto(code).value;
},
pedantic: false,
gfm: true,
tables: true,
breaks: false,
sanitize: false,
smartLists: true,
smartypants: false,
xhtml: false
}
);
for(const key in this.previewCode){
if(this.activeName == ""){
this.activeName = key
}
document.getElementById(key).innerHTML = marked(this.previewCode[key])
}
}
}
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<div>
<!-- 从数据库直接获取字段 -->
<el-collapse v-model="activeNames">
<el-collapse-item name="1">
<template slot="title">
<div :style="{fontSize:'16px',paddingLeft:'20px'}">
点这里从现有数据库创建代码
<i class="header-icon el-icon-thumb"></i>
</div>
</template>
<el-form ref="getTableForm" :inline="true" :model="dbform" label-width="120px">
<el-form-item label="数据库名" prop="structName">
<el-select @change="getTable" v-model="dbform.dbName" filterable placeholder="请选择数据库">
<el-option
v-for="item in dbOptions"
:key="item.database"
:label="item.database"
:value="item.database"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="表名" prop="structName">
<el-select
v-model="dbform.tableName"
:disabled="!dbform.dbName"
filterable
placeholder="请选择表"
>
<el-option
v-for="item in tableOptions"
:key="item.tableName"
:label="item.tableName"
:value="item.tableName"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="getColumn" type="primary">使用此表创建</el-button>
</el-form-item>
</el-form>
</el-collapse-item>
</el-collapse>
<el-divider></el-divider>
<!-- 初始版本自动化代码工具 -->
<el-form ref="autoCodeForm" :rules="rules" :model="form" label-width="120px" :inline="true">
<el-form-item label="Struct名称" prop="structName">
<el-input v-model="form.structName" placeholder="首字母自动转换大写"></el-input>
</el-form-item>
<el-form-item label="tableName" prop="tableName">
<el-input v-model="form.tableName" placeholder="指定表名(非必填)"></el-input>
</el-form-item>
<el-form-item label="Struct简称" prop="abbreviation">
<el-input v-model="form.abbreviation" placeholder="简称会作为入参对象名和路由group"></el-input>
</el-form-item>
<el-form-item label="Struct中文名称" prop="description">
<el-input v-model="form.description" placeholder="中文描述作为自动api描述"></el-input>
</el-form-item>
<el-form-item label="文件名称" prop="packageName">
<el-input v-model="form.packageName" placeholder="生成文件的默认名称"></el-input>
</el-form-item>
<el-form-item label="自动创建api">
<el-checkbox v-model="form.autoCreateApiToSql"></el-checkbox>
</el-form-item>
<el-form-item label="自动移动文件">
<el-checkbox v-model="form.autoMoveFile"></el-checkbox>
</el-form-item>
</el-form>
<!-- 组件列表 -->
<div class="button-box clearflex">
<el-button @click="editAndAddField()" type="primary">新增Field</el-button>
</div>
<el-table :data="form.fields" border stripe>
<el-table-column type="index" label="序列" width="100"></el-table-column>
<el-table-column prop="fieldName" label="Field名"></el-table-column>
<el-table-column prop="fieldDesc" label="中文名"></el-table-column>
<el-table-column prop="fieldJson" label="FieldJson"></el-table-column>
<el-table-column prop="fieldType" label="Field数据类型" width="130"></el-table-column>
<el-table-column prop="dataType" label="数据库字段类型" width="130"></el-table-column>
<el-table-column prop="dataTypeLong" label="数据库字段长度" width="130"></el-table-column>
<el-table-column prop="columnName" label="数据库字段" width="130"></el-table-column>
<el-table-column prop="comment" label="数据库字段描述" width="130"></el-table-column>
<el-table-column prop="fieldSearchType" label="搜索条件" width="130"></el-table-column>
<el-table-column prop="dictType" label="字典" width="130"></el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-button
size="mini"
type="primary"
icon="el-icon-edit"
@click="editAndAddField(scope.row)"
>编辑</el-button>
<el-button
size="mini"
type="text"
:disabled="scope.$index == 0"
@click="moveUpField(scope.$index)"
>上移</el-button>
<el-button
size="mini"
type="text"
:disabled="(scope.$index + 1) == form.fields.length"
@click="moveDownField(scope.$index)"
>下移</el-button>
<el-popover placement="top" v-model="scope.row.visible">
<p>确定删除吗?</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="scope.row.visible = false">取消</el-button>
<el-button type="primary" size="mini" @click="deleteField(scope.$index)">确定</el-button>
</div>
<el-button size="mini" type="danger" icon="el-icon-delete" slot="reference">删除</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
<el-tag type="danger">id , created_at , updated_at , deleted_at 会自动生成请勿重复创建</el-tag>
<!-- 组件列表 -->
<div class="button-box clearflex">
<el-button @click="enterForm(true)" type="primary">预览代码</el-button>
<el-button @click="enterForm(false)" type="primary">生成代码</el-button>
</div>
<!-- 组件弹窗 -->
<el-dialog title="组件内容" :visible.sync="dialogFlag">
<FieldDialog v-if="dialogFlag" :dialogMiddle="dialogMiddle" ref="fieldDialog" />
<div slot="footer" class="dialog-footer">
<el-button @click="closeDialog">取 消</el-button>
<el-button type="primary" @click="enterDialog">确 定</el-button>
</div>
</el-dialog>
<el-dialog :visible.sync="previewFlag">
<PreviewCodeDialg v-if="previewFlag" :previewCode="preViewCode"></PreviewCodeDialg>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="previewFlag = false">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
const fieldTemplate = {
fieldName: "",
fieldDesc: "",
fieldType: "",
dataType: "",
fieldJson: "",
columnName: "",
dataTypeLong: "",
comment: "",
fieldSearchType: "",
dictType: ""
};
import FieldDialog from "@/view/systemTools/autoCode/component/fieldDialog.vue";
import PreviewCodeDialg from "@/view/systemTools/autoCode/component/previewCodeDialg.vue";
import { toUpperCase, toHump } from "@/utils/stringFun.js";
import { createTemp, getDB, getTable, getColumn, preview } from "@/api/autoCode.js";
import { getDict } from "@/utils/dictionary";
export default {
name: "autoCode",
data() {
return {
activeNames: [""],
preViewCode:{},
dbform: {
dbName: "",
tableName: ""
},
dbOptions: [],
tableOptions: [],
addFlag: "",
fdMap: {},
form: {
structName: "",
tableName: "",
packageName: "",
abbreviation: "",
description: "",
autoCreateApiToSql: false,
autoMoveFile: false,
fields: []
},
rules: {
structName: [
{ required: true, message: "请输入结构体名称", trigger: "blur" }
],
abbreviation: [
{ required: true, message: "请输入结构体简称", trigger: "blur" }
],
description: [
{ required: true, message: "请输入结构体描述", trigger: "blur" }
],
packageName: [
{
required: true,
message: "文件名称:sys_xxxx_xxxx",
trigger: "blur"
}
]
},
dialogMiddle: {},
bk: {},
dialogFlag: false,
previewFlag:false
};
},
components: {
FieldDialog,
PreviewCodeDialg
},
methods: {
editAndAddField(item) {
this.dialogFlag = true;
if (item) {
this.addFlag = "edit";
this.bk = JSON.parse(JSON.stringify(item));
this.dialogMiddle = item;
} else {
this.addFlag = "add";
this.dialogMiddle = JSON.parse(JSON.stringify(fieldTemplate));
}
},
moveUpField(index) {
if (index == 0) {
return;
}
const oldUpField = this.form.fields[index - 1];
this.form.fields.splice(index - 1, 1);
this.form.fields.splice(index, 0, oldUpField);
},
moveDownField(index) {
const fCount = this.form.fields.length;
if (index == fCount - 1) {
return;
}
const oldDownField = this.form.fields[index + 1];
this.form.fields.splice(index + 1, 1);
this.form.fields.splice(index, 0, oldDownField);
},
enterDialog() {
this.$refs.fieldDialog.$refs.fieldDialogFrom.validate(valid => {
if (valid) {
this.dialogMiddle.fieldName = toUpperCase(
this.dialogMiddle.fieldName
);
if (this.addFlag == "add") {
this.form.fields.push(this.dialogMiddle);
}
this.dialogFlag = false;
} else {
return false;
}
});
},
closeDialog() {
if (this.addFlag == "edit") {
this.dialogMiddle = this.bk;
}
this.dialogFlag = false;
},
deleteField(index) {
this.form.fields.splice(index, 1);
},
async enterForm(isPreview) {
if (this.form.fields.length <= 0) {
this.$message({
type: "error",
message: "请填写至少一个field"
});
return false;
}
if (
this.form.fields.some(item => item.fieldName == this.form.structName)
) {
this.$message({
type: "error",
message: "存在与结构体同名的字段"
});
return false;
}
this.$refs.autoCodeForm.validate(async valid => {
if (valid) {
this.form.structName = toUpperCase(this.form.structName);
if (this.form.structName == this.form.abbreviation) {
this.$message({
type: "error",
message: "structName和struct简称不能相同"
});
return false;
}
if(isPreview){
const data = await preview(this.form);
console.log(data.code == 0)
this.preViewCode = data.data.autoCode
this.previewFlag = true
}else{
const data = await createTemp(this.form);
if (data.headers?.success == "false") {
return;
} else {
this.$message({
type: "success",
message: "自动化代码创建成功,正在下载"
});
}
const blob = new Blob([data]);
const fileName = "gin-vue-xdorg.zip";
if ("download" in document.createElement("a")) {
// 不是IE浏览器
let url = window.URL.createObjectURL(blob);
let link = document.createElement("a");
link.style.display = "none";
link.href = url;
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link); // 下载完成移除元素
window.URL.revokeObjectURL(url); // 释放掉blob对象
} else {
// IE 10+
window.navigator.msSaveBlob(blob, fileName);
}
}
} else {
return false;
}
});
},
async getDb() {
const res = await getDB();
if (res.code == 0) {
this.dbOptions = res.data.dbs;
}
},
async getTable() {
const res = await getTable({ dbName: this.dbform.dbName });
if (res.code == 0) {
this.tableOptions = res.data.tables;
}
this.dbform.tableName = "";
},
async getColumn() {
const gormModelList = ["id", "created_at", "updated_at", "deleted_at"];
const res = await getColumn(this.dbform);
if (res.code == 0) {
const tbHump = toHump(this.dbform.tableName);
this.form.structName = toUpperCase(tbHump);
this.form.tableName = this.dbform.tableName;
this.form.packageName = tbHump;
this.form.abbreviation = tbHump;
this.form.description = tbHump + "";
this.form.autoCreateApiToSql = true;
this.form.fields = [];
res.data.columns &&
res.data.columns.map(item => {
if (!gormModelList.some(gormfd => gormfd == item.columnName)) {
const fbHump = toHump(item.columnName);
this.form.fields.push({
fieldName: toUpperCase(fbHump),
fieldDesc: item.columnComment || fbHump + "字段",
fieldType: this.fdMap[item.dataType],
dataType: item.dataType,
fieldJson: fbHump,
dataTypeLong: item.dataTypeLong,
columnName: item.columnName,
comment: item.columnComment,
fieldSearchType: "",
dictType: ""
});
}
});
}
},
async setFdMap() {
const fdTypes = ["string", "int", "bool", "float64", "time.Time"];
fdTypes.map(async fdtype => {
const res = await getDict(fdtype);
res&&res.map(item => {
this.fdMap[item.label] = fdtype;
});
});
}
},
created() {
this.getDb();
this.setFdMap();
}
};
</script>
<style scope lang="scss">
.button-box {
padding: 10px 20px;
.el-button {
margin-right: 20px;
float: right;
}
}
</style>
<template>
<div style="height:80vh">
<iframe width="100%" height="100%" :src="basePath+':8888/form-generator/#/'" frameborder="0"></iframe>
</div>
</template>
<script>
var path = process.env.VUE_APP_BASE_PATH
export default {
name:"FormGenerator",
data(){
return{
basePath:path
}
},
};
</script>
<style lang="scss">
</style>
\ No newline at end of file
<template>
<div>
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
<script>
export default {
name: "System",
};
</script>
<style lang="scss"></style>
<template>
<div class="system">
<el-form :model="config" label-width="100px" ref="form" class="system">
<!-- System start -->
<h2>系统配置</h2>
<el-form-item label="环境值">
<el-input v-model="config.system.env"></el-input>
</el-form-item>
<el-form-item label="端口值">
<el-input v-model.number="config.system.addr"></el-input>
</el-form-item>
<el-form-item label="数据库类型">
<el-select v-model="config.system.dbType">
<el-option value="mysql"></el-option>
<el-option value="sqlite"></el-option>
<el-option value="sqlserver"></el-option>
<el-option value="postgresql"></el-option>
</el-select>
</el-form-item>
<el-form-item label="Oss类型">
<el-select v-model="config.system.ossType">
<el-option value="local"></el-option>
<el-option value="qiniu"></el-option>
<el-option value="tencent-cos"></el-option>
<el-option value="aliyun-oss"></el-option>
</el-select>
</el-form-item>
<el-form-item label="配置文件环境变量名">
<el-input v-model.number="config.system.configEnv"></el-input>
</el-form-item>
<el-form-item label="数据初始化">
<el-checkbox v-model="config.system.needInitData">开启</el-checkbox>
</el-form-item>
<el-form-item label="多点登录拦截">
<el-checkbox v-model="config.system.useMultipoint">开启</el-checkbox>
</el-form-item>
<!-- System end -->
<!-- JWT start -->
<h2>jwt签名</h2>
<el-form-item label="jwt签名">
<el-input v-model="config.jwt.signingKey"></el-input>
</el-form-item>
<!-- JWT end -->
<!-- Zap start -->
<h2>Zap日志配置</h2>
<el-form-item label="级别">
<el-input v-model.number="config.zap.level"></el-input>
</el-form-item>
<el-form-item label="输出">
<el-input v-model="config.zap.format"></el-input>
</el-form-item>
<el-form-item label="日志前缀">
<el-input v-model="config.zap.prefix"></el-input>
</el-form-item>
<el-form-item label="日志文件夹">
<el-input v-model="config.zap.director"></el-input>
</el-form-item>
<el-form-item label="软链接名称">
<el-input v-model="config.zap.linkName"></el-input>
</el-form-item>
<el-form-item label="编码级">
<el-input v-model="config.zap.encodeLevel"></el-input>
</el-form-item>
<el-form-item label="栈名">
<el-input v-model="config.zap.stacktraceKey"></el-input>
</el-form-item>
<el-form-item label="显示行">
<el-checkbox v-model="config.zap.showLine"></el-checkbox>
</el-form-item>
<el-form-item label="输出控制台">
<el-checkbox v-model="config.zap.logInConsole"></el-checkbox>
</el-form-item>
<!-- Zap end -->
<!-- Redis start -->
<h2>Redis admin数据库配置</h2>
<el-form-item label="db">
<el-input v-model="config.redis.db"></el-input>
</el-form-item>
<el-form-item label="addr">
<el-input v-model="config.redis.addr"></el-input>
</el-form-item>
<el-form-item label="password">
<el-input v-model="config.redis.password"></el-input>
</el-form-item>
<!-- Redis end -->
<!-- Email start -->
<h2>邮箱配置</h2>
<el-form-item label="接收者邮箱">
<el-input v-model="config.email.to" placeholder="可多个,以逗号分隔"></el-input>
</el-form-item>
<el-form-item label="端口">
<el-input v-model.number="config.email.port"></el-input>
</el-form-item>
<el-form-item label="发送者邮箱">
<el-input v-model="config.email.from"></el-input>
</el-form-item>
<el-form-item label="host">
<el-input v-model="config.email.host"></el-input>
</el-form-item>
<el-form-item label="是否为ssl">
<el-checkbox v-model="config.email.isSSL"></el-checkbox>
</el-form-item>
<el-form-item label="secret">
<el-input v-model="config.email.secret"></el-input>
</el-form-item>
<el-form-item label="测试邮件">
<el-button @click="email">测试邮件</el-button>
</el-form-item>
<!-- Email end -->
<!-- Casbin start -->
<h2>casbin配置</h2>
<el-form-item label="模型地址">
<el-input v-model="config.casbin.modelPath"></el-input>
</el-form-item>
<!-- Casbin end -->
<!-- Captcha start -->
<h2>验证码配置</h2>
<el-form-item label="keyLong">
<el-input v-model.number="config.captcha.keyLong"></el-input>
</el-form-item>
<el-form-item label="imgWidth">
<el-input v-model.number="config.captcha.imgWidth"></el-input>
</el-form-item>
<el-form-item label="imgHeight">
<el-input v-model.number="config.captcha.imgHeight"></el-input>
</el-form-item>
<!-- Captcha end -->
<!-- dbType start -->
<template v-if="config.system.dbType == 'mysql'">
<h2>mysql admin数据库配置</h2>
<el-form-item label="username">
<el-input v-model="config.mysql.username"></el-input>
</el-form-item>
<el-form-item label="password">
<el-input v-model="config.mysql.password"></el-input>
</el-form-item>
<el-form-item label="path">
<el-input v-model="config.mysql.path"></el-input>
</el-form-item>
<el-form-item label="dbname">
<el-input v-model="config.mysql.dbname"></el-input>
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.mysql.maxIdleConns"></el-input>
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.mysql.maxOpenConns"></el-input>
</el-form-item>
<el-form-item label="logMode">
<el-checkbox v-model="config.mysql.logMode"></el-checkbox>
</el-form-item>
</template>
<template v-if="config.system.dbType == 'sqlite'">
<h2>sqlite admin数据库配置</h2>
<el-form-item label="path">
<el-input v-model="config.mysql.path"></el-input>
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.mysql.maxIdleConns"></el-input>
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.mysql.maxOpenConns"></el-input>
</el-form-item>
<el-form-item label="logger">
<el-checkbox v-model="config.mysql.logger"></el-checkbox>
</el-form-item>
</template>
<template v-if="config.system.dbType == 'sqlserver'">
<h2>sqlserver admin数据库配置</h2>
<el-form-item label="username">
<el-input v-model="config.sqlserver.username"></el-input>
</el-form-item>
<el-form-item label="password">
<el-input v-model="config.sqlserver.password"></el-input>
</el-form-item>
<el-form-item label="path">
<el-input v-model="config.sqlserver.path"></el-input>
</el-form-item>
<el-form-item label="dbname">
<el-input v-model="config.sqlserver.dbname"></el-input>
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.sqlserver.maxIdleConns"></el-input>
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.sqlserver.maxOpenConns"></el-input>
</el-form-item>
<el-form-item label="logger">
<el-checkbox v-model="config.sqlserver.logger"></el-checkbox>
</el-form-item>
</template>
<template v-if="config.system.dbType == 'postgresql'">
<h2>postgresql admin数据库配置</h2>
<el-form-item label="username">
<el-input v-model="config.mysql.username"></el-input>
</el-form-item>
<el-form-item label="password">
<el-input v-model="config.mysql.password"></el-input>
</el-form-item>
<el-form-item label="dbName">
<el-input v-model="config.mysql.dbName"></el-input>
</el-form-item>
<el-form-item label="port">
<el-input v-model="config.mysql.port"></el-input>
</el-form-item>
<el-form-item label="config">
<el-input v-model="config.mysql.config"></el-input>
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.mysql.maxIdleConns"></el-input>
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.mysql.maxOpenConns"></el-input>
</el-form-item>
<el-form-item label="logger">
<el-checkbox v-model="config.mysql.logger"></el-checkbox>
</el-form-item>
<el-form-item label="prefer-simple-protocol">
<el-checkbox v-model="config.mysql.preferSimpleProtocol"></el-checkbox>
</el-form-item>
</template>
<!-- dbType end -->
<!-- ossType start -->
<template v-if="config.system.ossType == 'local'">
<h2>本地上传配置</h2>
<el-form-item label="本地文件路径">
<el-input v-model="config.local.path"></el-input>
</el-form-item>
</template>
<template v-if="config.system.ossType == 'qiniu'">
<h2>qiniu上传配置</h2>
<el-form-item label="存储区域">
<el-input v-model="config.qiniu.zone"></el-input>
</el-form-item>
<el-form-item label="空间名称">
<el-input v-model="config.qiniu.bucket"></el-input>
</el-form-item>
<el-form-item label="CDN加速域名">
<el-input v-model="config.qiniu.imgPath"></el-input>
</el-form-item>
<el-form-item label="是否使用https">
<el-checkbox v-model="config.qiniu.useHttps">开启</el-checkbox>
</el-form-item>
<el-form-item label="accessKey">
<el-input v-model="config.qiniu.accessKey"></el-input>
</el-form-item>
<el-form-item label="secretKey">
<el-input v-model="config.qiniu.secretKey"></el-input>
</el-form-item>
<el-form-item label="上传是否使用CDN上传加速">
<el-checkbox v-model="config.qiniu.useCdnDomains">开启</el-checkbox>
</el-form-item>
</template>
<template v-if="config.system.ossType == 'tencent-cos'">
<h2>腾讯云COS上传配置</h2>
<el-form-item label="bucket">
<el-input v-model="config.tencentCOS.bucket"></el-input>
</el-form-item>
<el-form-item label="region">
<el-input v-model="config.tencentCOS.region"></el-input>
</el-form-item>
<el-form-item label="secretID">
<el-input v-model="config.tencentCOS.secretID"></el-input>
</el-form-item>
<el-form-item label="secretKey">
<el-input v-model="config.tencentCOS.secretKey"></el-input>
</el-form-item>
<el-form-item label="pathPrefix">
<el-input v-model="config.tencentCOS.pathPrefix"></el-input>
</el-form-item>
<el-form-item label="baseURL">
<el-input v-model="config.tencentCOS.baseURL"></el-input>
</el-form-item>
</template>
<template v-if="config.system.ossType == 'aliyun-oss'">
<h2>阿里云OSS上传配置</h2>
<el-form-item label="endpoint">
<el-input v-model="config.aliyunOSS.endpoint"></el-input>
</el-form-item>
<el-form-item label="accessKeyId">
<el-input v-model="config.aliyunOSS.accessKeyId"></el-input>
</el-form-item>
<el-form-item label="accessKeySecret">
<el-input v-model="config.aliyunOSS.accessKeySecret"></el-input>
</el-form-item>
<el-form-item label="bucketName">
<el-input v-model="config.aliyunOSS.bucketName"></el-input>
</el-form-item>
<el-form-item label="bucketUrl">
<el-input v-model="config.aliyunOSS.bucketUrl"></el-input>
</el-form-item>
</template>
<!-- ossType end -->
<el-form-item>
<el-button @click="update" type="primary">立即更新</el-button>
<el-button @click="reload" type="primary">重启服务(开发中)</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import { getSystemConfig, setSystemConfig } from "@/api/system";
import { emailTest } from "@/api/email";
export default {
name: "Config",
data() {
return {
config: {
system: {},
jwt: {},
casbin: {},
mysql: {},
sqlite: {},
redis: {},
qiniu: {},
tencentCOS:{},
aliyunOSS:{},
captcha: {},
zap: {},
local: {},
email: {}
}
};
},
async created() {
await this.initForm();
},
methods: {
async initForm() {
const res = await getSystemConfig();
if (res.code == 0) {
this.config = res.data.config;
}
},
reload() {},
async update() {
const res = await setSystemConfig({ config: this.config });
if (res.code == 0) {
this.$message({
type: "success",
message: "配置文件设置成功"
});
await this.initForm();
}
},
async email() {
const res = await emailTest();
if (res.code == 0) {
this.$message({
type: "success",
message: "邮件发送成功"
});
await this.initForm();
} else {
this.$message({
type: "error",
message: "邮件发送失败"
});
}
}
}
};
</script>
<style lang="scss">
.system {
h2 {
padding: 10px;
margin: 10px 0;
font-size: 16px;
box-shadow: -4px 1px 3px 0px #e7e8e8;
}
}
</style>
'use strict'
const path = require('path')
const buildConf = require('./build.config')
const packageConf = require('./package.json')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
// 基础配置 详情看文档
publicPath: './',
outputDir: 'dist',
assetsDir: 'static',
lintOnSave: process.env.NODE_ENV === 'development',
productionSourceMap: false,
devServer: {
port: process.env.VUE_APP_CLI_PORT,
open: true,
overlay: {
warnings: false,
errors: true
},
proxy: {
// 把key的路径代理到target位置
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: { //需要代理的路径 例如 '/api'
target: `${process.env.VUE_APP_BASE_PATH}:${process.env.VUE_APP_SERVER_PORT}/`, //代理到 目标路径
changeOrigin: true,
pathRewrite: { // 修改路径数据
['^' + process.env.VUE_APP_BASE_API]: '' // 举例 '^/api:""' 把路径中的/api字符串删除
}
}
},
},
configureWebpack: {
// @路径走src文件夹
resolve: {
alias: {
'@': resolve('src')
}
}
},
chainWebpack(config) {
// set preserveWhitespace
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap(options => {
options.compilerOptions.preserveWhitespace = true
return options
})
.end()
config
// https://webpack.js.org/configuration/devtool/#development
.when(process.env.NODE_ENV === 'development',
config => config.devtool('cheap-source-map')
)
config
.when(process.env.NODE_ENV !== 'development',
config => {
// 不打包 begin
// 1.目前已经测试通过[vue,axios,echarts]可以cdn引用,其它组件测试通过后可继续添加
// 2.此处添加不打包后,需在public/index.html head中添加相应cdn资源链接
config.set('externals', buildConf.cdns.reduce((p, a) => {
p[a.name] = a.scope
return p
},{}))
// 不打包 end
config.plugin('html')
.tap(args => {
if(buildConf.title) {
args[0].title = buildConf.title
}
if(buildConf.cdns.length > 0) {
args[0].cdns = buildConf.cdns.map(conf => {
if (conf.path) {
conf.js = `${buildConf.baseCdnUrl}${conf.path}`
} else {
conf.js = `${buildConf.baseCdnUrl}/${conf.name}/${packageConf.dependencies[conf.name].replace('^', '')}/${conf.name}.min.js`
}
return conf
})
}
return args
})
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [{
// `runtime` must same as runtimeChunk name. default is `runtime`
inline: /single\..*\.js$/
}])
.end()
config
.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial' // only package third parties that are initially dependent
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
},
commons: {
name: 'chunk-commons',
test: resolve('src/components'), // can customize your rules
minChunks: 3, // minimum common number
priority: 5,
reuseExistingChunk: true
}
}
})
config.optimization.runtimeChunk('single')
}
)
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册