1
3
.browserslistrc
Normal file
@@ -0,0 +1,3 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
28
.eslintrc.js
Normal file
@@ -0,0 +1,28 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true
|
||||
},
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended'
|
||||
],
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
},
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'**/__tests__/*.{j,t}s?(x)',
|
||||
'**/tests/unit/**/*.spec.{j,t}s?(x)'
|
||||
],
|
||||
env: {
|
||||
mocha: true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# ---> VisualStudioCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
/node_modules
|
||||
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
7
Vue3版本使用说明.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
前端vue3环境配置,如果没有安装过环境:
|
||||
1、先卸载原来vue2脚手架
|
||||
npm uninstall vue-cli -g
|
||||
2、安装vue3脚手架
|
||||
npm install -g @vue/cli (如果安装很慢,切换成taobao镜像 npm config set registry https://registry.npm.taobao.org)
|
||||
3、回滚原来vue2脚手架(vue init webpack test)
|
||||
npm i -g @vue/cli-init
|
||||
5
babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
84
config/buttons.js
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
let buttons = [{
|
||||
name: "查 询",
|
||||
value: 'Search',
|
||||
icon: 'el-icon-search',
|
||||
class: '',
|
||||
type: 'primary',
|
||||
onClick: function () {
|
||||
this.search();
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "新 建",
|
||||
icon: 'el-icon-plus',
|
||||
value: 'Add',
|
||||
class: '',
|
||||
// plain:true,
|
||||
type: 'success',
|
||||
// plain:true,
|
||||
onClick: function () {
|
||||
this.add();
|
||||
}
|
||||
},{
|
||||
name: "编 辑",
|
||||
icon: 'el-icon-edit',
|
||||
value: 'Update',
|
||||
// plain:true,
|
||||
class: '',
|
||||
type: 'primary',
|
||||
onClick: function () {
|
||||
this.edit();
|
||||
}
|
||||
}, {
|
||||
name: "删 除",
|
||||
icon: 'el-icon-delete',
|
||||
class: '',
|
||||
value: 'Delete',
|
||||
type: 'danger',
|
||||
onClick: function () {
|
||||
this.del();
|
||||
}
|
||||
}, {
|
||||
name: "审 核",
|
||||
icon: 'el-icon-check',
|
||||
class: '',
|
||||
value: 'Audit',
|
||||
plain:true,
|
||||
type: 'primary',
|
||||
onClick: function () {
|
||||
this.audit();
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "导 入",
|
||||
icon: 'el-icon-top',
|
||||
class: '',
|
||||
type:'success',
|
||||
plain:true,
|
||||
value: 'Import',
|
||||
onClick: function () {
|
||||
this.import();
|
||||
}
|
||||
}, {
|
||||
name: "导 出",
|
||||
icon: 'el-icon-bottom',
|
||||
type:'success',
|
||||
plain:true,
|
||||
value: 'Export',
|
||||
onClick: function () {
|
||||
this.export();
|
||||
}
|
||||
}
|
||||
// , {
|
||||
// name: "数据结构",
|
||||
// icon: 'ios-cog',
|
||||
// class: '',
|
||||
// value: '',
|
||||
// onClick: function () {
|
||||
// this.openViewColumns();
|
||||
// }
|
||||
// }
|
||||
]
|
||||
|
||||
export default buttons
|
||||
1
install.bat
Normal file
@@ -0,0 +1 @@
|
||||
npm install
|
||||
33772
package-lock.json
generated
Normal file
75
package.json
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"name": "imes.vue3",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
|
||||
"build": "set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build",
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chenfengyuan/vue-qrcode": "^2.0.0",
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"@microsoft/signalr": "^6.0.4",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"echarts": "^5.0.2",
|
||||
"element-plus": "^2.2.15",
|
||||
"file-save": "^0.2.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"less": "^4.1.1",
|
||||
"magix": "^3.8.16",
|
||||
"qrcode": "^1.5.1",
|
||||
"qrcode.vue": "^3.3.3",
|
||||
"qrcodejs2": "0.0.2",
|
||||
"sortable.js": "^0.3.0",
|
||||
"sortablejs": "^1.15.0",
|
||||
"uuidv1": "^1.6.14",
|
||||
"vue": "^3.2.37",
|
||||
"vue-draggable-next": "^2.0.1",
|
||||
"vue-i18n": "^9.13.1",
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vuex": "^4.0.0-0",
|
||||
"wangeditor": "^4.7.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-plugin-unit-mocha": "~4.5.0",
|
||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vue/test-utils": "^2.0.0-0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"chai": "^4.1.2",
|
||||
"less": "^4.1.1",
|
||||
"less-loader": "^7.3.0",
|
||||
"stylus": "^0.54.7",
|
||||
"stylus-loader": "^3.0.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"@vue/standard"
|
||||
],
|
||||
"rules": {
|
||||
"indent": [
|
||||
1,
|
||||
4
|
||||
]
|
||||
},
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
},
|
||||
"eslintIgnore": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
134
public/index.html
Normal file
@@ -0,0 +1,134 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<meta name="keywords" content=".netccore,dotnet core,vue,element,element plus,vue3" />
|
||||
<meta name="description" content="iMES-您的新一代工厂管家【商业版】" />
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
|
||||
Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
<% if (process.env.NODE_ENV === 'production' ) { %>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?eb00554ca26601489c051a64e4915d60";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
<% } %>
|
||||
</body>
|
||||
</html>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
*{
|
||||
box-sizing:border-box;
|
||||
}
|
||||
.el-loading {
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
.el-table th {
|
||||
display: table-cell !important;
|
||||
}
|
||||
.el-loading .el-loading-spinner {
|
||||
padding: 7px;
|
||||
background: #ececec;
|
||||
width: 200px;
|
||||
color: red;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #a0a0a0;
|
||||
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.v-dialog {
|
||||
border-radius: 5px;
|
||||
top: 50%;
|
||||
/* margin-top: -220px !important; */
|
||||
}
|
||||
.v-dialog .el-dialog__header {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
padding: 0px 13px;
|
||||
line-height: 53px;
|
||||
border-bottom: 1px solid #e2e2e2;
|
||||
height: 50px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
background-image: linear-gradient(135deg, #0cd7bd 10%, #50c3f7);
|
||||
}
|
||||
|
||||
.v-dialog .el-dialog__header .el-dialog__headerbtn {
|
||||
top: 3px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.v-dialog .el-dialog__header .el-dialog__headerbtn .el-dialog__close {
|
||||
font-size: 19px;
|
||||
color: white;
|
||||
}
|
||||
.v-dialog .el-dialog__body{
|
||||
padding: 0;
|
||||
}
|
||||
.el-message{
|
||||
z-index: 3500 !important;
|
||||
}
|
||||
.v-date-range .el-input__inner{
|
||||
padding:0 15px 0 8px
|
||||
}
|
||||
.v-date-range .el-input__suffix .el-input__icon{
|
||||
display: table-caption;
|
||||
background: white;
|
||||
margin: 1px;
|
||||
height: auto;
|
||||
margin-right: -4px;
|
||||
height: 33px;
|
||||
width: 19px;
|
||||
font-size: 13px;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
.v-date-range .el-icon-circle-check {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.v-dialog .el-dialog__header {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.el-button--small {
|
||||
padding: 15px 15px !important;
|
||||
}
|
||||
</style>
|
||||
63
src/App.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div id="nav"></div>
|
||||
<el-config-provider :locale="locale">
|
||||
<router-view />
|
||||
</el-config-provider>
|
||||
</template>
|
||||
<script>
|
||||
import { ElConfigProvider } from "element-plus";
|
||||
import zhCn from "element-plus/lib/locale/lang/zh-cn";
|
||||
export default {
|
||||
name: "imes_app",
|
||||
components: {
|
||||
[ElConfigProvider.name]: ElConfigProvider, //添加组件
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
locale: zhCn,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="stylus">
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.el-alert--error.is-light {
|
||||
border: 1px solid #ffe0e0;
|
||||
}
|
||||
|
||||
.el-alert--error.is-light {
|
||||
color: #f74444 !important;
|
||||
}
|
||||
|
||||
.el-alert--warning.is-light {
|
||||
border: 1px solid #ffe6c1;
|
||||
}
|
||||
|
||||
.el-alert--info.is-light {
|
||||
border: 1px solid #e6e5e5;
|
||||
}
|
||||
|
||||
.el-alert--info .el-alert__description {
|
||||
color: #6b6b6b !important;
|
||||
}
|
||||
|
||||
.el-alert--warning.is-light {
|
||||
background-color: #fdf6ec;
|
||||
color: #d68409 !important;
|
||||
}
|
||||
|
||||
.el-alert--success.is-light {
|
||||
border: 1px solid #cdf7b8;
|
||||
}
|
||||
|
||||
.el-alert--success.is-light .el-alert__description {
|
||||
color: #3baf02 !important;
|
||||
}
|
||||
</style>
|
||||
315
src/api/http.js
Normal file
@@ -0,0 +1,315 @@
|
||||
import axios from 'axios'
|
||||
import store from '../store/index'
|
||||
// import {getCurrentInstance} from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
//const router = useRouter();
|
||||
axios.defaults.timeout = 50000;
|
||||
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
|
||||
|
||||
import { ElLoading as Loading, ElMessage as Message } from 'element-plus';
|
||||
|
||||
|
||||
let loadingInstance;
|
||||
let loadingStatus = false;
|
||||
if (process.env.NODE_ENV == 'development') {
|
||||
axios.defaults.baseURL = 'http://localhost:9991/';
|
||||
}
|
||||
else if (process.env.NODE_ENV == 'debug') {
|
||||
axios.defaults.baseURL = 'http://localhost:9991/';
|
||||
}
|
||||
|
||||
else if (process.env.NODE_ENV == 'production') {
|
||||
axios.defaults.baseURL = 'http://120.48.150.78:8881/';
|
||||
}
|
||||
if (!axios.defaults.baseURL.endsWith('/')) {
|
||||
axios.defaults.baseURL+="/";
|
||||
}
|
||||
let ipAddress = axios.defaults.baseURL;
|
||||
let webAddress = "https://imes.625sc.com";
|
||||
axios.interceptors.request.use((config) => {
|
||||
return config;
|
||||
}, (error) => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
axios.interceptors.response.use((res) => {
|
||||
|
||||
closeLoading();
|
||||
|
||||
checkResponse(res);
|
||||
|
||||
return Promise.resolve(res);
|
||||
}, (error) => {
|
||||
closeLoading();
|
||||
let httpMessage = '';
|
||||
if (error.response) {
|
||||
if (error.response.status == '401') {
|
||||
if (error.response.data && error.response.data.code == 401) {
|
||||
toLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
if (error.response.status == '404') {
|
||||
httpMessage = "未找到请求地址";
|
||||
}
|
||||
else if (error.response.data && error.response.data.message) {
|
||||
httpMessage = error.response.data.message;
|
||||
}
|
||||
}
|
||||
else {
|
||||
httpMessage = '服务器处理异常'
|
||||
}
|
||||
redirect(httpMessage);
|
||||
return Promise.reject(error.response || {}, httpMessage);
|
||||
});
|
||||
function closeLoading () {
|
||||
if (loadingInstance) {
|
||||
loadingInstance.close();
|
||||
}
|
||||
if (loadingStatus) {
|
||||
loadingStatus = false;
|
||||
if (loadingInstance) {
|
||||
loadingInstance.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
function checkResponse (res) {
|
||||
//刷新token
|
||||
if (!res.headers) {
|
||||
if (res.getResponseHeader("vol_exp") == "1") {
|
||||
replaceToken();
|
||||
}
|
||||
}
|
||||
else if (res.headers.vol_exp == "1") {
|
||||
replaceToken();
|
||||
}
|
||||
}
|
||||
|
||||
const _Authorization = 'Authorization';
|
||||
|
||||
function showLoading (loading) {
|
||||
if (!loading || loadingStatus) {
|
||||
return;
|
||||
}
|
||||
loadingInstance = Loading.service({
|
||||
lock: true,
|
||||
text: 'Loading',
|
||||
customClass:"http-loading",
|
||||
background: typeof loading == "string" ? loading : '正在处理.....',
|
||||
background: 'rgba(58, 61, 63, 0.32)'
|
||||
});
|
||||
}
|
||||
|
||||
function getToken () {
|
||||
return store.getters.getToken();
|
||||
}
|
||||
|
||||
/*
|
||||
url
|
||||
params请求后台的参数,如:{name:123,values:['a','b','c']}
|
||||
loading是否显示遮罩层,可以传入true.false.及提示文本
|
||||
config配置信息,如{timeout:3000,headers:{token:123}}
|
||||
*/
|
||||
function post (url, params, loading, config) {
|
||||
showLoading(loading);
|
||||
axios.defaults.headers[_Authorization] = getToken();
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.post(url, params, config)
|
||||
.then(response => {
|
||||
resolve(response.data);
|
||||
}, err => {
|
||||
reject(err && err.data && err.data.message ? err.data.message : '服务器处理异常');
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//=true异步请求时会显示遮罩层,=字符串,异步请求时遮罩层显示当前字符串
|
||||
function get (url, param, loading, config) {
|
||||
showLoading(loading);
|
||||
axios.defaults.headers[_Authorization] = getToken();
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.get(url, config)
|
||||
.then(response => {
|
||||
resolve(response.data)
|
||||
}, err => {
|
||||
reject(err)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//url:url地址
|
||||
//params:请求参数
|
||||
//fileName:下载的文件名
|
||||
//loading:是否显示加载状态
|
||||
function download (url, params, fileName, loading,callback) {
|
||||
fileName = fileName.replace(">", ">").replace("<", "<");
|
||||
post(url, params, loading, { responseType: 'blob' }).then(content => {
|
||||
const blob = new Blob([content])
|
||||
if ('download' in document.createElement('a')) { // 非IE下载
|
||||
const elink = document.createElement('a')
|
||||
elink.download = fileName
|
||||
elink.style.display = 'none'
|
||||
elink.href = URL.createObjectURL(blob)
|
||||
document.body.appendChild(elink)
|
||||
elink.click()
|
||||
URL.revokeObjectURL(elink.href) // 释放URL 对象
|
||||
document.body.removeChild(elink)
|
||||
} else { // IE10+下载
|
||||
navigator.msSaveBlob(blob, fileName)
|
||||
}
|
||||
callback&&callback();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function createXHR () {
|
||||
if (XMLHttpRequest) {
|
||||
return new XMLHttpRequest();
|
||||
}
|
||||
if (ActiveXObject) {
|
||||
if (typeof arguments.callee.activeXString != "string") {
|
||||
var versions = [
|
||||
"MSXML2.XMLHttp.6.0",
|
||||
"MSXML2.XMLHttp",
|
||||
"MSXML2.XMLHttp.3.0"
|
||||
];
|
||||
for (var i = 0; i < versions.length; i++) {
|
||||
try {
|
||||
new ActiveXObject(versions[i]);
|
||||
arguments.callee.activeXString = versions[i];
|
||||
break;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ActiveXObject(arguments.callee.activeXString);
|
||||
}
|
||||
}
|
||||
|
||||
function redirect (responseText, message) {
|
||||
try {
|
||||
let responseData = typeof responseText == 'string' ? JSON.parse(responseText) : responseText;
|
||||
if ((responseData.hasOwnProperty('code') && responseData.code == 401)
|
||||
|| (responseData.data && responseData.data.code == 401)) {
|
||||
closeLoading();
|
||||
toLogin();
|
||||
} else {
|
||||
if (message) {
|
||||
Message.error({
|
||||
showClose: true,
|
||||
message: message,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
Message.error({
|
||||
showClose: true,
|
||||
message: responseText,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function toLogin () {
|
||||
// const vueinstance= getCurrentInstance();
|
||||
if (window.location.hash) {
|
||||
window.location.href = window.location.origin + '/#/login'
|
||||
return
|
||||
}
|
||||
window.location.href = window.location.origin + '/login'
|
||||
// router.push({ path: '/login', params: { r: Math.random() } });
|
||||
}
|
||||
//动态刷新token
|
||||
function replaceToken () {
|
||||
ajax({
|
||||
url: "/api/User/replaceToken",
|
||||
param: {},
|
||||
json: true,
|
||||
success: function (x) {
|
||||
if (x.status) {
|
||||
let userInfo = store.getters.getUserInfo();
|
||||
userInfo.token = x.data;
|
||||
store.commit('setUserInfo', userInfo);
|
||||
} else {
|
||||
console.log(x.message);
|
||||
toLogin();
|
||||
}
|
||||
},
|
||||
errror: function (ex) {
|
||||
console.log(ex);
|
||||
toLogin();
|
||||
},
|
||||
type: "post",
|
||||
async: false
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function ajax (param) {
|
||||
let httpParam =
|
||||
Object.assign({
|
||||
url: '', headers: {},
|
||||
param: {}, json: true,
|
||||
success: function () { },
|
||||
errror: function () { },
|
||||
type: 'post', async: true
|
||||
}, param);
|
||||
|
||||
httpParam.url = axios.defaults.baseURL + httpParam.url.replace(/\/?/, '');
|
||||
httpParam.headers[_Authorization] = getToken();
|
||||
var xhr = createXHR();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.status == 403 || xhr.status == 401) {
|
||||
redirect(xhr.responseText);
|
||||
return;
|
||||
}
|
||||
checkResponse(xhr);
|
||||
if (xhr.readyState == 4 && xhr.status == 200) {
|
||||
httpParam.success(httpParam.json ? JSON.parse(xhr.responseText) : xhr.responseText);
|
||||
return;
|
||||
}
|
||||
if (xhr.status != 0 && xhr.readyState != 1) {
|
||||
httpParam.errror(xhr);
|
||||
}
|
||||
};
|
||||
//初始化请求
|
||||
xhr.open(
|
||||
httpParam.type,
|
||||
httpParam.url,
|
||||
httpParam.async
|
||||
);
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
for (const key in httpParam.headers) {
|
||||
xhr.setRequestHeader(key, httpParam.headers[key]);
|
||||
}
|
||||
let dataStr = '';
|
||||
for (const key in httpParam.param) {
|
||||
dataStr += key + "=" + httpParam.param[key];
|
||||
}
|
||||
try {
|
||||
xhr.send(dataStr);
|
||||
} catch (error) {
|
||||
toLogin();
|
||||
}
|
||||
}
|
||||
|
||||
ajax.post = function (url, param, success, errror) {
|
||||
ajax({ url: url, param: param, success: success, error: errror, type: 'post' })
|
||||
}
|
||||
ajax.get = function (url, param, success, errror) {
|
||||
ajax({ url: url, param: param, success: success, error: errror, type: 'get' })
|
||||
}
|
||||
export default { post, get,download, ajax, ipAddress, webAddress }
|
||||
43
src/api/permission.js
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
import http from '@/../src/api/http.js'
|
||||
import buttons from '@/../config/buttons.js'
|
||||
import store from '../store/index'
|
||||
import { useRouter } from 'vue-router'
|
||||
let permission = {
|
||||
getMenu() {
|
||||
return http.get("/api/getTreeMenu");
|
||||
}, getButtons(path, extra, table, tableName) {//extra自定额外按钮
|
||||
//table获取指定表的权限
|
||||
if (table) { table = '/' + table; }
|
||||
let permission = store.getters.getPermission(table || path);
|
||||
if (!permission) {
|
||||
permission = store.getters.getPermission(path.substring(1));
|
||||
if (!permission) {
|
||||
permission = store.getters.getPermission("/" + tableName);
|
||||
if (!permission) {
|
||||
to401();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let permissions = permission.permission;//.split(',');
|
||||
let gridButtons = buttons.filter(item => {
|
||||
return !item.value || permissions.indexOf(item.value) != -1
|
||||
});
|
||||
if (extra && extra instanceof Array) {
|
||||
gridButtons.push(...extra)
|
||||
}
|
||||
return gridButtons;
|
||||
}, to401() {
|
||||
to401();
|
||||
}
|
||||
}
|
||||
function to401() {
|
||||
const router = useRouter();
|
||||
router.push({
|
||||
path: '/401'
|
||||
});
|
||||
}
|
||||
|
||||
export default permission;
|
||||
9
src/api/useTest.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const tipxx = {
|
||||
install: function (vue) {
|
||||
alert(1);
|
||||
vue.prototype.$tip = function () {
|
||||
alert('测试use')
|
||||
};
|
||||
}
|
||||
}
|
||||
export default { tipxx }
|
||||
75
src/assets/css/common.less
Normal file
@@ -0,0 +1,75 @@
|
||||
*{
|
||||
box-sizing:border-box;
|
||||
-moz-box-sizing:border-box; /* Firefox */
|
||||
-webkit-box-sizing:border-box; /* Safari */
|
||||
}
|
||||
.el-pager li{
|
||||
font-weight: 100;
|
||||
margin-right: 9px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 3px;
|
||||
min-width: 28px;
|
||||
}
|
||||
.el-pager li.active,.el-pager li:hover{
|
||||
background: #ed4014;
|
||||
color: white;
|
||||
}
|
||||
.el-pagination__editor.el-input .el-input__inner{
|
||||
height: 23px;
|
||||
}
|
||||
|
||||
|
||||
.animated {
|
||||
-webkit-animation-duration: 0.5s;
|
||||
animation-duration: 0.5s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
@media (print), (prefers-reduced-motion) {
|
||||
.animated {
|
||||
-webkit-animation: unset !important;
|
||||
animation: unset !important;
|
||||
-webkit-transition: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeInDown {
|
||||
from {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate3d(0, -100%, 0);
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, -100%, 0);
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.fadeInDown {
|
||||
-webkit-animation-name: fadeInDown;
|
||||
animation-name: fadeInDown;
|
||||
}
|
||||
.ivu-message{
|
||||
z-index: 999999999 !important;
|
||||
}
|
||||
.ivu-form-item-content{
|
||||
text-align: left;
|
||||
}
|
||||
BIN
src/assets/element-icon/fonts/element-icons.ttf
Normal file
BIN
src/assets/element-icon/fonts/element-icons.woff
Normal file
1
src/assets/element-icon/icon.css
Normal file
BIN
src/assets/imgs/error-img.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/assets/imgs/error.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/assets/imgs/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/assets/imgs/log.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
src/assets/imgs/logo.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src/assets/imgs/miniapp.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
src/assets/imgs/qq.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
src/assets/imgs/wechat.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
2
src/assets/script/common.js
Normal file
@@ -0,0 +1,2 @@
|
||||
var test1 = function () { alert(11) }
|
||||
export { test1 }
|
||||
5
src/assets/script/extend.js
Normal file
@@ -0,0 +1,5 @@
|
||||
//对vue参数进行扩展
|
||||
var extend = function (param) {
|
||||
console.log(param)
|
||||
}
|
||||
export { extend }
|
||||
5
src/assets/script/printer_view.js
Normal file
15
src/assets/script/testFormExtend.js
Normal file
@@ -0,0 +1,15 @@
|
||||
//对vue参数进行扩展
|
||||
var extend = function ($vueParam) {
|
||||
$vueParam.methods.mesBoxFrom = function () {
|
||||
this.$Message.info("扩展js,增加弹出消息");
|
||||
this.$refs.mesBoxFrom.show();
|
||||
}
|
||||
//修改data属性:
|
||||
let data = $vueParam.data();
|
||||
data.formFileds['extend'] = "动态扩展字段";
|
||||
data.formOptions.splice(0,0,{ filed: "extend", title: "动态增加字段", type: "text", required: true });
|
||||
$vueParam.data = function () {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
export { extend }
|
||||
10
src/components/basic/AsyncLoading.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div style="text-align: center;font-size: 16px;padding: 20px;">正在加载资源...</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
created() {
|
||||
// console.log('loading')
|
||||
}
|
||||
};
|
||||
</script>
|
||||
59
src/components/basic/Audit.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<el-alert
|
||||
:title="'当前选中' + auditParam.rows + '条记录待审核..'"
|
||||
type="success"
|
||||
:closable="false"
|
||||
>
|
||||
</el-alert>
|
||||
<div class="item">
|
||||
<label>审核结果:</label>
|
||||
<el-radio-group v-model="auditParam.status">
|
||||
<el-radio
|
||||
v-for="item in auditParam.data"
|
||||
:key="item.status"
|
||||
:label="item.status"
|
||||
>
|
||||
<span>{{ item.text }}</span>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="item">
|
||||
<label style="margin-right: 13px;">备 注:</label>
|
||||
<el-input
|
||||
v-model="auditParam.reason"
|
||||
type="textarea"
|
||||
style="margin-right: 13px;"
|
||||
:autosize="{ minRows: 4, maxRows: 10 }"
|
||||
placeholder="审核备注..."
|
||||
></el-input>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
auditParam: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
auditParam: {
|
||||
rows: 0,
|
||||
model: false,
|
||||
status: -1,
|
||||
reason: "",
|
||||
data: [], //[{ text: "通过", status: 1 }, { text: "拒绝", status: 2 }]
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.item{
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
> label{
|
||||
width: 86px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
3
src/components/basic/Empty.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
3
src/components/basic/ErrorMsg.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<div id="test"></div>
|
||||
</template>
|
||||
345
src/components/basic/Icons.vue
Normal file
@@ -0,0 +1,345 @@
|
||||
<template>
|
||||
<div data-v-394040b0 class="icons">
|
||||
<div
|
||||
@click="select(index)"
|
||||
v-for="(item, index) in icons"
|
||||
:key="index"
|
||||
class="icons-item"
|
||||
>
|
||||
<i
|
||||
:class="[item, selectIndex == index ? 'active' : '']"
|
||||
style="font-size: 32px"
|
||||
></i>
|
||||
<p>{{ item }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
onSelect: {
|
||||
type: Function,
|
||||
default: () => {
|
||||
return "";
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
select(index) {
|
||||
this.selectIndex = index;
|
||||
this.onSelect(index < 0 ? "" : this.icons[index]);
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectIndex: -1,
|
||||
icons: [
|
||||
//ivu-icon ivu-icon-ios-add
|
||||
"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="less" scoped>
|
||||
.icons-item {
|
||||
float: left;
|
||||
margin: 6px 6px 6px 0;
|
||||
width: 115px;
|
||||
text-align: center;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
height: 100px;
|
||||
color: #5c6b77;
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.active {
|
||||
border: 1px solid;
|
||||
background: #f44336;
|
||||
color: white;
|
||||
font-size: 32px;
|
||||
}
|
||||
</style>
|
||||
185
src/components/basic/MesBox.vue
Normal file
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div class="vol-dialog">
|
||||
|
||||
<el-dialog v-model="vmodel" :close-on-click-modal="false" :close-on-press-escape="false"
|
||||
:width="width" :draggable="draggable" :modal="modal" :before-close="handleClose">
|
||||
<template #header> <i :class="icon"></i> {{ title }} </template>
|
||||
<el-scrollbar :max-height="contentHeight">
|
||||
|
||||
<div v-if="inited" style="min-height: 50px;" class="srcoll-content" :style="{ padding: padding + 'px' }">
|
||||
<slot name="content"></slot>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<template #footer>
|
||||
<div class="dia-footer" v-if="footer">
|
||||
<slot name="footer"></slot>
|
||||
<el-button type="primary" v-if="!footer" size="mini" @click="handleClose()"><i
|
||||
class="el-icon-close"></i>关闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, ref, watch, watchEffect } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
modelValue: false,
|
||||
lazy: {
|
||||
//是否开启懒加载2020.12.06
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'el-icon-warning-outline'
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '基本信息'
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 650
|
||||
},
|
||||
padding: {
|
||||
type: Number,
|
||||
default: 16
|
||||
},
|
||||
modal: { //是否需要遮罩层
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
draggable: { //启用可拖拽功能
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
mask: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
onModelClose: {
|
||||
//2021.07.11增加弹出框关闭事件
|
||||
type: Function,
|
||||
default: (iconClick) => {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
footer:{ //是否显示底部按钮
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
|
||||
},
|
||||
setup(props, context) {
|
||||
const clientHeight = document.body.clientHeight * 0.95 - 60;
|
||||
const inited = ref(true);
|
||||
const vmodel = ref(false);
|
||||
const footer = ref(false);
|
||||
const top = ref(100);
|
||||
vmodel.value = props.modelValue;
|
||||
footer.value = !!context.slots.footer;
|
||||
const contentHeight = ref(200);
|
||||
contentHeight.value = props.height;
|
||||
const handleClose = (done, iconClose) => {
|
||||
let result = props.onModelClose(!!iconClose);
|
||||
if (result === false) return;
|
||||
vmodel.value = false;
|
||||
context.emit('update:modelValue', false);
|
||||
done && done();
|
||||
};
|
||||
const calcHeight = (val) => {
|
||||
// if (props.height > clientHeight) {
|
||||
// if(true){
|
||||
contentHeight.value = clientHeight - 30;
|
||||
return clientHeight / -2 + 'px';
|
||||
// }
|
||||
// contentHeight.value = val || props.height;
|
||||
// return (props.height + 56) / -2 + 'px';
|
||||
};
|
||||
|
||||
top.value = calcHeight();
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal, oldVal) => {
|
||||
vmodel.value = newVal;
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => props.height,
|
||||
(newVal, oldVal) => {
|
||||
top.value = calcHeight();
|
||||
}
|
||||
);
|
||||
return {
|
||||
handleClose,
|
||||
inited,
|
||||
vmodel,
|
||||
footer,
|
||||
top,
|
||||
calcHeight,
|
||||
contentHeight
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.dia-footer {
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
border-top: 1px solid #e2e2e2;
|
||||
text-align: right;
|
||||
padding: 6px 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped lang="less">
|
||||
.vol-dialog ::v-deep(.el-overlay-dialog) {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.vol-dialog ::v-deep(.el-dialog) {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.vol-dialog ::v-deep(.el-dialog) {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.vol-dialog ::v-deep(.el-dialog__header) {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
padding: 0px 13px;
|
||||
line-height: 53px;
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
height: 50px;
|
||||
color: rgb(79, 79, 79);
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
// background-image: linear-gradient(135deg, #0cd7bd 10%, #50c3f7);
|
||||
}
|
||||
|
||||
.vol-dialog ::v-deep(.el-dialog__footer),
|
||||
.vol-dialog ::v-deep(.el-dialog__body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.vol-dialog ::v-deep(.el-dialog__headerbtn) {
|
||||
top: 0;
|
||||
padding-top: 8px;
|
||||
height: 50px;
|
||||
}
|
||||
// .vol-dialog ::v-deep(.el-dialog__headerbtn .el-dialog__close) {
|
||||
// color: #fff;
|
||||
// }
|
||||
</style>
|
||||
197
src/components/basic/MesElementMenu.vue
Normal file
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<div class="mes-el-menu">
|
||||
<el-menu
|
||||
close="mes-el-menu--vertical"
|
||||
:default-openeds="openedIds"
|
||||
:default-active="defaultActive"
|
||||
:unique-opened="true"
|
||||
@select="select"
|
||||
:collapse="isCollapse"
|
||||
@open="handleOpen"
|
||||
@close="handleClose"
|
||||
@contextmenu.prevent="bindRightClickMenu"
|
||||
>
|
||||
<template v-for="item in convertTree(list)">
|
||||
<el-sub-menu
|
||||
:key="item.id"
|
||||
:index="'' + item.id"
|
||||
v-if="item.children.length && (!enable || item.enable == 1)"
|
||||
>
|
||||
<template #title>
|
||||
<i class="menu-icon" :class="item.icon"></i>
|
||||
<span>{{$t(item.name)}}</span>
|
||||
</template>
|
||||
<mes-element-menu-child
|
||||
:enable="enable"
|
||||
:list="item.children"
|
||||
></mes-element-menu-child>
|
||||
</el-sub-menu>
|
||||
<template v-else>
|
||||
<el-menu-item
|
||||
class="menu-item-lv1"
|
||||
v-if="!enable || item.enable == 1"
|
||||
:key="item.id"
|
||||
:index="'' + item.id"
|
||||
>
|
||||
<i :class="item.icon"></i>
|
||||
<span>{{$t(item.name)}}</span>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
</el-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MesElementMenuChild from './MesElementMenuChild';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import {
|
||||
defineComponent,
|
||||
reactive,
|
||||
watch,
|
||||
ref,
|
||||
toRef,
|
||||
toRefs,
|
||||
getCurrentInstance
|
||||
// onMounted,
|
||||
} from 'vue';
|
||||
export default defineComponent({
|
||||
components: {
|
||||
'mes-element-menu-child': MesElementMenuChild
|
||||
},
|
||||
props: {
|
||||
enable: {
|
||||
type: Boolean,
|
||||
default: false //是否判断enable=1
|
||||
},
|
||||
isCollapse: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
onSelect: {
|
||||
type: Function,
|
||||
default: (x) => {}
|
||||
},
|
||||
openSelect: {
|
||||
//打开的时候是否触发选中事件
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
rootId: {
|
||||
type: String,
|
||||
default: '0'
|
||||
},
|
||||
currentMenuId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
// const { list } = toRefs(props);
|
||||
// const treeList = ref([]);
|
||||
const getTree = (id, node, data) => {
|
||||
if (!node.children) {
|
||||
node.children = [];
|
||||
}
|
||||
data.forEach((x) => {
|
||||
if (x.parentId == id && !node.children.some((c) => c.id === x.id)) {
|
||||
node.children.push(x);
|
||||
getTree(x.id, x, data);
|
||||
}
|
||||
});
|
||||
};
|
||||
let rootTreeId = !isNaN(props.rootId) ? ~~props.rootId : props.rootId;
|
||||
props.list.forEach((x) => {
|
||||
if (!x.icon || x.icon.substring(0, 3) != 'el-') {
|
||||
x.icon = 'el-icon-menu';
|
||||
}
|
||||
x.children = [];
|
||||
x.isRoot = x.parentId === rootTreeId;
|
||||
});
|
||||
const convertTree = (data) => {
|
||||
var root_data = [];
|
||||
data.forEach((x) => {
|
||||
if (x.parentId === rootTreeId) {
|
||||
if (!x.hasOwnProperty('enable')) x.enable = 1;
|
||||
root_data.push(x);
|
||||
getTree(x.id, x, data);
|
||||
}
|
||||
});
|
||||
return root_data;
|
||||
};
|
||||
const openedIds = reactive([props.currentMenuId]);
|
||||
const defaultActive = ref(props.currentMenuId + '');
|
||||
let _base = getCurrentInstance().appContext.config.globalProperties.base;
|
||||
watch(
|
||||
() => props.currentMenuId,
|
||||
(newVal, oldVal) => {
|
||||
defaultActive.value = newVal + '';
|
||||
openedIds.splice(0);
|
||||
openedIds.push(
|
||||
..._base.getTreeAllParent(newVal, props.list).map((c) => {
|
||||
return c.id;
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
const router = useRouter();
|
||||
let eventSelect = false;
|
||||
const select = (index, path) => {
|
||||
if (eventSelect) {
|
||||
return;
|
||||
}
|
||||
eventSelect = true;
|
||||
setTimeout(() => {
|
||||
eventSelect = false;
|
||||
}, 20);
|
||||
let _item = props.list.find((x) => {
|
||||
return x.id == index;
|
||||
});
|
||||
props.onSelect(index, _item);
|
||||
router.push({ path: _item.path || '' });
|
||||
};
|
||||
|
||||
const handleOpen = (index, path) => {
|
||||
if (props.openSelect) {
|
||||
select(index, path);
|
||||
}
|
||||
};
|
||||
const handleClose = () => {};
|
||||
|
||||
/**
|
||||
* 菜单导航右键事件
|
||||
* @param {*} enable 是否启用右键事件[true:启用;false:禁用;]
|
||||
*/
|
||||
const bindRightClickMenu = (enable) => {
|
||||
if (!enable) return;
|
||||
};
|
||||
|
||||
return {
|
||||
// treeList,
|
||||
// list,
|
||||
select,
|
||||
convertTree,
|
||||
handleOpen,
|
||||
handleClose,
|
||||
bindRightClickMenu,
|
||||
openedIds,
|
||||
defaultActive
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.mes-el-menu {
|
||||
box-sizing: content-box;
|
||||
width: 100%;
|
||||
.menu-icon {
|
||||
font-size: 18px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
56
src/components/basic/MesElementMenuChild.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div class="mes-el-menu-item">
|
||||
<template v-for="(item) in list">
|
||||
<template v-if="item.children&&item.children.length">
|
||||
<el-menu-item :key="item.id"
|
||||
:index="'' + item.id"
|
||||
v-if="!item.children.length && (!enable || item.enable == 1)">
|
||||
<template #title></template>
|
||||
<span>{{$t(item.name)}}</span>
|
||||
</el-menu-item>
|
||||
<el-sub-menu :key="item.id"
|
||||
:index="'' + item.id"
|
||||
v-if="item.children.length && (!enable || item.enable == 1)">
|
||||
<template #title>
|
||||
<span>{{$t(item.name)}}</span>
|
||||
</template>
|
||||
<mes-element-menu-child :list="item.children" />
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-menu-item :key="item.id"
|
||||
:index="'' + item.id"
|
||||
v-if="(!enable || item.enable == 1)">
|
||||
<template #title></template>
|
||||
<span> {{$t(item.name)}}</span>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "mes-element-menu-child",
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
enable: {
|
||||
type: Boolean,
|
||||
default: false, //是否判断enable=1
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.mes-el-menu-item ::v-deep(.el-menu-item) {
|
||||
height: 42px !important;
|
||||
line-height: 42px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
1485
src/components/basic/MesForm.vue
Normal file
14
src/components/basic/MesForm/MesFormRender.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { h } from 'vue';
|
||||
|
||||
export default {
|
||||
name: "FormExpand",
|
||||
functional: true,
|
||||
props: {
|
||||
render: Function,
|
||||
par: {}//测试参数
|
||||
},
|
||||
render: ({ render, par }) => {
|
||||
return render(h, { par }); //h();
|
||||
}
|
||||
};
|
||||
|
||||
156
src/components/basic/MesFormDraggable/DownloadForm.js
Normal file
@@ -0,0 +1,156 @@
|
||||
import templateCode from './templateCode'
|
||||
export default function () {
|
||||
let code = templateCode;
|
||||
let _formOptions = this.options.formOptions.map(m => {
|
||||
let _op = m.map((m1, i) => {
|
||||
let _obj;
|
||||
//.data[0].hasOwnProperty("key")
|
||||
if (m1.data && m1.data.length && !m1.dataKey) {
|
||||
let m2 = JSON.parse(JSON.stringify(m1));
|
||||
m2.data = m2.data.map(c => {
|
||||
return { key: c.label || c.key, value: c.label }
|
||||
})
|
||||
_obj = JSON.stringify(m2)
|
||||
} else {
|
||||
_obj = JSON.stringify(m1)
|
||||
}
|
||||
return (i === 0 ? '' : '\n\t\t\t\t') + _obj
|
||||
}).join(',');
|
||||
//return JSON.stringify(m, null, '')
|
||||
return _op;
|
||||
})
|
||||
code = code.replace('{#fields}', JSON.stringify(this.options.fields))
|
||||
.replace('{#formOptions}', '[' + _formOptions.join('],\n\t\t\t\t[') + ']');
|
||||
code = code.replace('}],', '\t\t\t\t\t}],')
|
||||
.replace("[{#tableOptions}]", JSON.stringify(this.options.tables, null, '\t'))
|
||||
.replace("[{#tabsOptions}]", JSON.stringify(this.options.tabs, null, '\t'))
|
||||
// fields: {#fields},
|
||||
// formOptions: [{#formOptions}],
|
||||
// tables: [{#tables}],
|
||||
// tabs: [{#tabs}]
|
||||
var tabsText = this.options.tabs.length ? ` <div class="tables"
|
||||
style="padding-bottom: 10px">
|
||||
<el-tabs v-model="tabsModel"
|
||||
@tab-click="() => {}">
|
||||
<el-tab-pane style="padding: 0"
|
||||
class="table-item"
|
||||
v-for="(item, index) in tabs"
|
||||
:label="item.name"
|
||||
:name="index+''"
|
||||
:key="index">
|
||||
<div class="table-header">
|
||||
<div class="header-text">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div class="header-btns">
|
||||
<el-button type="primary"
|
||||
size="mini"
|
||||
:key="bindex"
|
||||
:icon="btnItem.icon"
|
||||
plain
|
||||
@click="tabsTableBtnClick(item, bindex, index)"
|
||||
v-for="(btnItem, bindex) in item.buttons">
|
||||
{{ btnItem.name }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<mes-table :url="item.url"
|
||||
:load-key="false"
|
||||
:index="true"
|
||||
:ref="'tabsTable' + index"
|
||||
:tableData="item.tableData"
|
||||
:columns="item.columns"
|
||||
:max-height="250"
|
||||
:pagination-hide="item.pagination"
|
||||
:column-index="true"
|
||||
:ck="true"></mes-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>`: ''
|
||||
code = code.replace('{#tabs}', tabsText);
|
||||
if (this.options.tables.length || this.options.tabs.length) {
|
||||
code = code.replace("{import_MesTable}", "import MesTable from '@/components/basic/MesTable'")
|
||||
code = code.replace(",{component_table}", ",'mes-table': MesTable")
|
||||
} else {
|
||||
code = code.replace("{import_MesTable}", '')
|
||||
code = code.replace("{component_table}", '')
|
||||
}
|
||||
|
||||
if (this.options.tables.length) {
|
||||
|
||||
code = code.replace('{table_ms}', `
|
||||
tableBtnClick (item, btnIndex, index) {
|
||||
if (item.buttons[btnIndex].value == "add") {
|
||||
this.$refs["table" + index][0].addRow({});
|
||||
return;
|
||||
}
|
||||
if (item.buttons[btnIndex].value == "del") {
|
||||
this.$refs["table" + index][0].delRow();
|
||||
return;
|
||||
}
|
||||
},
|
||||
tabsTableBtnClick (item, btnIndex, index) {
|
||||
if (item.buttons[btnIndex].value == "add") {
|
||||
this.$refs["tabsTable" + index][0].addRow({});
|
||||
return;
|
||||
}
|
||||
if (item.buttons[btnIndex].value == "del") {
|
||||
this.$refs["tabsTable" + index][0].delRow();
|
||||
return;
|
||||
}
|
||||
},`)
|
||||
code = code.replace('{#tables}',
|
||||
`
|
||||
<!--table配置 -->
|
||||
<div class="tables">
|
||||
<div class="table-item"
|
||||
v-for="(item, index) in tables"
|
||||
:key="index">
|
||||
<div class="table-header">
|
||||
<div class="header-text">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div class="header-btns">
|
||||
<el-button type="primary"
|
||||
size="mini"
|
||||
:key="bindex"
|
||||
plain
|
||||
@click="tableBtnClick(item, bindex, index)"
|
||||
:icon="btnItem.icon"
|
||||
v-for="(btnItem, bindex) in item.buttons">
|
||||
{{ btnItem.name }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<mes-table :url="item.url"
|
||||
:load-key="false"
|
||||
:index="true"
|
||||
:ref="'table' + index"
|
||||
:tableData="item.tableData"
|
||||
:columns="item.columns"
|
||||
:max-height="250"
|
||||
:pagination-hide="item.pagination"
|
||||
:column-index="true"
|
||||
:ck="true"></mes-table>
|
||||
</div>
|
||||
</div>`);
|
||||
|
||||
} else {
|
||||
|
||||
code = code.replace('{table_ms}', '')
|
||||
code = code.replace('{#tables}', '');
|
||||
}
|
||||
const blob = new Blob([code], { type: "text/plain;charset=utf-8" })
|
||||
if ('download' in document.createElement('a')) { // 非IE下载
|
||||
const elink = document.createElement('a')
|
||||
elink.download = `code${new Date().valueOf()}.vue`;
|
||||
elink.style.display = 'none'
|
||||
elink.href = URL.createObjectURL(blob)
|
||||
document.body.appendChild(elink)
|
||||
elink.click()
|
||||
URL.revokeObjectURL(elink.href) // 释放URL 对象
|
||||
document.body.removeChild(elink)
|
||||
} else {
|
||||
navigator.msSaveBlob(blob, fileName)
|
||||
}
|
||||
}
|
||||
1155
src/components/basic/MesFormDraggable/MesFormDraggable.vue
Normal file
206
src/components/basic/MesFormDraggable/MesFormPreview.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<div style="padding: 15px 20px 15px 5px">
|
||||
<div class="pre-text">{{ text }}</div>
|
||||
<mes-form
|
||||
ref="form"
|
||||
:labelWidth="80"
|
||||
:load-key="false"
|
||||
:formFields="options.fields"
|
||||
:formRules="options.formOptions"
|
||||
>
|
||||
</mes-form>
|
||||
<div class="tables">
|
||||
<div
|
||||
class="table-item"
|
||||
v-for="(item, index) in options.tables"
|
||||
:key="index"
|
||||
>
|
||||
<div class="table-header">
|
||||
<div class="header-text">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div class="header-btns">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:key="bindex"
|
||||
plain
|
||||
@click="tableBtnClick(item, bindex, index)"
|
||||
:icon="btnItem.icon"
|
||||
v-for="(btnItem, bindex) in item.buttons"
|
||||
>
|
||||
{{ btnItem.name }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<mes-table
|
||||
:url="item.url"
|
||||
:load-key="false"
|
||||
:index="true"
|
||||
:ref="'table' + index"
|
||||
:tableData="item.tableData"
|
||||
:columns="item.columns"
|
||||
:max-height="250"
|
||||
:pagination-hide="item.pagination"
|
||||
:column-index="true"
|
||||
:ck="true"
|
||||
></mes-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tables" style="padding-bottom: 10px">
|
||||
<el-tabs
|
||||
v-model="tabsModel"
|
||||
v-show="options.tabs.length"
|
||||
@tab-click="() => {}"
|
||||
>
|
||||
<el-tab-pane
|
||||
style="padding: 0"
|
||||
class="table-item"
|
||||
v-for="(item, index) in options.tabs"
|
||||
:label="item.name"
|
||||
:name="index"
|
||||
:key="index"
|
||||
>
|
||||
<div class="table-header">
|
||||
<div class="header-text">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div class="header-btns">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:key="bindex"
|
||||
:icon="btnItem.icon"
|
||||
plain
|
||||
@click="tabsTableBtnClick(item, bindex, index)"
|
||||
v-for="(btnItem, bindex) in item.buttons"
|
||||
>
|
||||
{{ btnItem.name }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<mes-table
|
||||
:url="item.url"
|
||||
:load-key="false"
|
||||
:index="true"
|
||||
:ref="'tabsTable' + index"
|
||||
:tableData="item.tableData"
|
||||
:columns="item.columns"
|
||||
:max-height="250"
|
||||
:pagination-hide="item.pagination"
|
||||
:column-index="true"
|
||||
:ck="true"
|
||||
></mes-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<div class="form-btns">
|
||||
<el-button type="primary" @click="submit" icon="el-icon-check" size="small"
|
||||
>提交</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="reset"
|
||||
plain
|
||||
icon="el-icon-refresh-right"
|
||||
size="small"
|
||||
>重置</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="download"
|
||||
plain
|
||||
icon="el-icon-refresh-right"
|
||||
size="small"
|
||||
>下载代码</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MesTable from "./../MesTable";
|
||||
import MesBox from "./../MesBox";
|
||||
import MesForm from "./../MesForm";
|
||||
import downloadForm from "./DownloadForm";
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return { fields: {}, formOptions: [], tables: [], tabs: [] };
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: "",
|
||||
tabsModel: 0,
|
||||
};
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
tableBtnClick(item, btnIndex, index) {
|
||||
if (item.buttons[btnIndex].value == "add") {
|
||||
this.$refs["table" + index].addRow({});
|
||||
return;
|
||||
}
|
||||
if (item.buttons[btnIndex].value == "del") {
|
||||
this.$refs["table" + index].delRow();
|
||||
return;
|
||||
}
|
||||
},
|
||||
tabsTableBtnClick(item, btnIndex, index) {
|
||||
if (item.buttons[btnIndex].value == "add") {
|
||||
this.$refs["tabsTable" + index].addRow({});
|
||||
return;
|
||||
}
|
||||
if (item.buttons[btnIndex].value == "del") {
|
||||
this.$refs["tabsTable" + index].delRow();
|
||||
return;
|
||||
}
|
||||
},
|
||||
submit() {},
|
||||
reset() {
|
||||
this.$refs.form.reset();
|
||||
this.$Message.success("表单已重置");
|
||||
},
|
||||
download() {
|
||||
downloadForm.call(this);
|
||||
},
|
||||
},
|
||||
components: {
|
||||
"mes-table": MesTable,
|
||||
"mes-box": MesBox,
|
||||
"mes-form": MesForm,
|
||||
},
|
||||
};
|
||||
|
||||
MesForm;
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.form-btns {
|
||||
text-align: center;
|
||||
}
|
||||
.tables {
|
||||
padding-left: 15px;
|
||||
.table-item {
|
||||
padding: 10px;
|
||||
}
|
||||
.table-header {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.header-text {
|
||||
position: relative;
|
||||
bottom: -9px;
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
}
|
||||
.header-btns {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
664
src/components/basic/MesFormDraggable/formTemplate.js
Normal file
@@ -0,0 +1,664 @@
|
||||
|
||||
|
||||
let options1 = [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "输入框",
|
||||
"type": "text",
|
||||
"value": "",
|
||||
"icon": "el-icon-document",
|
||||
"field": "field1630258884671",
|
||||
"width": 20,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "日期",
|
||||
"type": "date",
|
||||
"icon": "el-icon-date",
|
||||
"value": null,
|
||||
"field": "field1630258891760",
|
||||
"width": 20,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "下拉框",
|
||||
"value": null,
|
||||
"key": "",
|
||||
"data": [
|
||||
{
|
||||
"label": "请设置数据源",
|
||||
"value": "请设置数据源"
|
||||
}
|
||||
],
|
||||
"type": "select",
|
||||
"icon": "el-icon-arrow-down",
|
||||
"field": "field1630258904862",
|
||||
"width": 30,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "下拉多选",
|
||||
"type": "selectList",
|
||||
"key": "",
|
||||
"values": [],
|
||||
"data": [
|
||||
{
|
||||
"label": "请设置数据源",
|
||||
"value": "请设置数据源"
|
||||
}
|
||||
],
|
||||
"icon": "el-icon-arrow-down",
|
||||
"field": "field1630258924442",
|
||||
"width": 30,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 81,
|
||||
"name": "级联",
|
||||
"type": "cascader",
|
||||
"icon": "el-icon-share",
|
||||
"values": [],
|
||||
"key": "",
|
||||
"data": [
|
||||
{
|
||||
"value": "请配置数据源",
|
||||
"label": "请配置数据源",
|
||||
"children": [
|
||||
{
|
||||
"value": "具体",
|
||||
"label": "菜单:下拉框绑定设置"
|
||||
},
|
||||
{
|
||||
"value": "color",
|
||||
"label": "可参照字典编号[tree_roles]"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"field": "field1630259518082",
|
||||
"width": 20,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "多选",
|
||||
"values": [
|
||||
"发货"
|
||||
],
|
||||
"type": "checkbox",
|
||||
"key": "ordertype",
|
||||
"data": [
|
||||
{
|
||||
"key": "1",
|
||||
"value": "发货"
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"value": "退货"
|
||||
},
|
||||
{
|
||||
"key": "3",
|
||||
"value": "返单"
|
||||
}
|
||||
],
|
||||
"icon": "el-icon-circle-check",
|
||||
"field": "field1630259033241",
|
||||
"width": 30,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "单选",
|
||||
"type": "radio",
|
||||
"icon": "el-icon-aim",
|
||||
"value": 0,
|
||||
"data": [
|
||||
{
|
||||
"key": "0",
|
||||
"value": "否"
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"value": "xx11"
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"value": "是"
|
||||
}
|
||||
],
|
||||
"key": "enable",
|
||||
"field": "field1630259538490",
|
||||
"width": 30,
|
||||
"readonly": false,
|
||||
"required": false,
|
||||
"values": [
|
||||
"否"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "switch",
|
||||
"type": "switch",
|
||||
"icon": "el-icon-turn-off",
|
||||
"value": 0,
|
||||
"field": "field1630259172794",
|
||||
"width": 20,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "分段信息",
|
||||
"type": "line",
|
||||
"icon": "el-icon-guide",
|
||||
"field": "field1630259600186",
|
||||
"width": 100,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "图片",
|
||||
"type": "img",
|
||||
"url": "api/SellOrder/upload",
|
||||
"maxSize": 3,
|
||||
"fileInfo": [],
|
||||
"multiple": false,
|
||||
"autoUpload": false,
|
||||
"maxFile": 5,
|
||||
"icon": "el-icon-picture-outline",
|
||||
"field": "field1630259295154",
|
||||
"width": 100,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "excel",
|
||||
"url": "api/SellOrder/upload",
|
||||
"maxSize": 3,
|
||||
"multiple": false,
|
||||
"autoUpload": true,
|
||||
"maxFile": 5,
|
||||
"fileInfo": [],
|
||||
"type": "excel",
|
||||
"icon": "el-icon-upload",
|
||||
"field": "field1630259610476",
|
||||
"width": 100,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "单选",
|
||||
"type": "radio",
|
||||
"icon": "el-icon-aim",
|
||||
"value": 0,
|
||||
"data": [
|
||||
{
|
||||
"key": "0",
|
||||
"value": "审核中"
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"value": "审核通过"
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"value": "审核未通过"
|
||||
}
|
||||
],
|
||||
"key": "audit",
|
||||
"field": "field1630258969346",
|
||||
"width": 40,
|
||||
"readonly": false,
|
||||
"required": false,
|
||||
"values": [
|
||||
"审核中"
|
||||
]
|
||||
}
|
||||
];
|
||||
let options2=[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "输入框",
|
||||
"type": "text",
|
||||
"value": "",
|
||||
"icon": "el-icon-document",
|
||||
"field": "field1630258884671",
|
||||
"width": 20,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "日期",
|
||||
"type": "date",
|
||||
"icon": "el-icon-date",
|
||||
"value": null,
|
||||
"field": "field1630258891760",
|
||||
"width": 20,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "下拉框",
|
||||
"value": null,
|
||||
"key": "",
|
||||
"data": [
|
||||
{
|
||||
"label": "请设置数据源",
|
||||
"value": "请设置数据源"
|
||||
}
|
||||
],
|
||||
"type": "select",
|
||||
"icon": "el-icon-arrow-down",
|
||||
"field": "field1630258904862",
|
||||
"width": 30,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "下拉多选",
|
||||
"type": "selectList",
|
||||
"key": "",
|
||||
"values": [],
|
||||
"data": [
|
||||
{
|
||||
"label": "请设置数据源",
|
||||
"value": "请设置数据源"
|
||||
}
|
||||
],
|
||||
"icon": "el-icon-arrow-down",
|
||||
"field": "field1630258924442",
|
||||
"width": 30,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "textarea",
|
||||
"type": "textarea",
|
||||
"value": "",
|
||||
"icon": "el-icon-document-copy",
|
||||
"field": "field1630260207393",
|
||||
"width": 100,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "表格",
|
||||
"type": "table",
|
||||
"tabs": true,
|
||||
"columns": [
|
||||
{
|
||||
"title": "运单号",
|
||||
"field": "TranNo",
|
||||
"show": true,
|
||||
"required": false,
|
||||
"edit": true,
|
||||
"dataType": null,
|
||||
"dataSource": null,
|
||||
"width": "140",
|
||||
"orderNo": null,
|
||||
"elementIndex": 0
|
||||
},
|
||||
{
|
||||
"title": "销售订单号",
|
||||
"field": "SellNo",
|
||||
"show": true,
|
||||
"required": false,
|
||||
"edit": true,
|
||||
"dataType": null,
|
||||
"dataSource": null,
|
||||
"width": "140",
|
||||
"orderNo": null,
|
||||
"elementIndex": 1
|
||||
},
|
||||
{
|
||||
"title": "订单类型",
|
||||
"field": "OrderType",
|
||||
"show": true,
|
||||
"required": false,
|
||||
"edit": true,
|
||||
"dataType": null,
|
||||
"dataSource": "ordertype",
|
||||
"width": 120,
|
||||
"orderNo": null,
|
||||
"elementIndex": 2,
|
||||
"editType": "select"
|
||||
},
|
||||
{
|
||||
"title": "销售数量",
|
||||
"field": "Qty",
|
||||
"show": true,
|
||||
"required": false,
|
||||
"edit": true,
|
||||
"dataType": null,
|
||||
"dataSource": null,
|
||||
"width": "80",
|
||||
"orderNo": null,
|
||||
"elementIndex": 3
|
||||
},
|
||||
{
|
||||
"field": "CreateDate",
|
||||
"elementIndex": 4,
|
||||
"show": 1,
|
||||
"required": 0,
|
||||
"edit": 0,
|
||||
"title": "订单时间",
|
||||
"dataType": "date",
|
||||
"width": "100"
|
||||
}
|
||||
],
|
||||
"tableData": [
|
||||
{
|
||||
"field1": "field1",
|
||||
"field2": "field2",
|
||||
"field3": "field3",
|
||||
"field4": "field4"
|
||||
},
|
||||
{
|
||||
"field1": "field1",
|
||||
"field2": "field2",
|
||||
"field3": "field3",
|
||||
"field4": "field4"
|
||||
},
|
||||
{
|
||||
"field1": "field1",
|
||||
"field2": "field2",
|
||||
"field3": "field3",
|
||||
"field4": "field4"
|
||||
}
|
||||
],
|
||||
"height": 200,
|
||||
"icon": "el-icon-c-scale-to-original",
|
||||
"url": "api/SellOrder/getPageData",
|
||||
"index": false,
|
||||
"columnIndex": false,
|
||||
"ck": true,
|
||||
"buttons": [
|
||||
{
|
||||
"name": "添加行",
|
||||
"ck": false,
|
||||
"icon": "el-icon-plus",
|
||||
"value": "add"
|
||||
},
|
||||
{
|
||||
"name": "删除行",
|
||||
"ck": false,
|
||||
"icon": "el-icon-delete",
|
||||
"value": "del"
|
||||
},
|
||||
{
|
||||
"name": "刷新",
|
||||
"ck": false,
|
||||
"icon": "el-icon-refresh-right",
|
||||
"value": "ref"
|
||||
}
|
||||
],
|
||||
"field": "field1630260242867",
|
||||
"width": 100,
|
||||
"readonly": false,
|
||||
"required": false,
|
||||
"pagination": false
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "表格",
|
||||
"type": "table",
|
||||
"tabs": true,
|
||||
"columns": [
|
||||
{
|
||||
"title": "字段1",
|
||||
"field": "field1",
|
||||
"show": true,
|
||||
"required": false,
|
||||
"edit": false,
|
||||
"dataType": null,
|
||||
"dataSource": null,
|
||||
"width": 120,
|
||||
"orderNo": null
|
||||
},
|
||||
{
|
||||
"title": "字段2",
|
||||
"field": "field2",
|
||||
"show": true,
|
||||
"required": false,
|
||||
"edit": false,
|
||||
"dataType": null,
|
||||
"dataSource": null,
|
||||
"width": 120,
|
||||
"orderNo": null
|
||||
},
|
||||
{
|
||||
"title": "字段3",
|
||||
"field": "field3",
|
||||
"show": true,
|
||||
"required": false,
|
||||
"edit": false,
|
||||
"dataType": null,
|
||||
"dataSource": null,
|
||||
"width": 120,
|
||||
"orderNo": null
|
||||
},
|
||||
{
|
||||
"title": "字段4",
|
||||
"field": "field4",
|
||||
"show": true,
|
||||
"required": false,
|
||||
"edit": false,
|
||||
"dataType": null,
|
||||
"dataSource": null,
|
||||
"width": 120,
|
||||
"orderNo": null
|
||||
}
|
||||
],
|
||||
"tableData": [
|
||||
{
|
||||
"field1": "field1",
|
||||
"field2": "field2",
|
||||
"field3": "field3",
|
||||
"field4": "field4"
|
||||
},
|
||||
{
|
||||
"field1": "field1",
|
||||
"field2": "field2",
|
||||
"field3": "field3",
|
||||
"field4": "field4"
|
||||
},
|
||||
{
|
||||
"field1": "field1",
|
||||
"field2": "field2",
|
||||
"field3": "field3",
|
||||
"field4": "field4"
|
||||
}
|
||||
],
|
||||
"height": 200,
|
||||
"icon": "el-icon-c-scale-to-original",
|
||||
"url": null,
|
||||
"index": false,
|
||||
"columnIndex": false,
|
||||
"ck": true,
|
||||
"buttons": [
|
||||
{
|
||||
"name": "添加行",
|
||||
"ck": false,
|
||||
"icon": "el-icon-plus",
|
||||
"value": "add"
|
||||
},
|
||||
{
|
||||
"name": "删除行",
|
||||
"ck": false,
|
||||
"icon": "el-icon-delete",
|
||||
"value": "del"
|
||||
},
|
||||
{
|
||||
"name": "刷新",
|
||||
"ck": false,
|
||||
"icon": "el-icon-refresh-right",
|
||||
"value": "ref"
|
||||
}
|
||||
],
|
||||
"field": "field1630260481283",
|
||||
"width": 100,
|
||||
"readonly": false,
|
||||
"required": false,
|
||||
"pagination": true
|
||||
}
|
||||
]
|
||||
|
||||
let options3=[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "输入框",
|
||||
"type": "text",
|
||||
"value": "",
|
||||
"icon": "el-icon-document",
|
||||
"field": "field1630258884671",
|
||||
"width": 20,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "日期",
|
||||
"type": "date",
|
||||
"icon": "el-icon-date",
|
||||
"value": null,
|
||||
"field": "field1630258891760",
|
||||
"width": 20,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "下拉框",
|
||||
"value": null,
|
||||
"key": "",
|
||||
"data": [
|
||||
{
|
||||
"label": "请设置数据源",
|
||||
"value": "请设置数据源"
|
||||
}
|
||||
],
|
||||
"type": "select",
|
||||
"icon": "el-icon-arrow-down",
|
||||
"field": "field1630258904862",
|
||||
"width": 30,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "下拉多选",
|
||||
"type": "selectList",
|
||||
"key": "",
|
||||
"values": [],
|
||||
"data": [
|
||||
{
|
||||
"label": "请设置数据源",
|
||||
"value": "请设置数据源"
|
||||
}
|
||||
],
|
||||
"icon": "el-icon-arrow-down",
|
||||
"field": "field1630258924442",
|
||||
"width": 30,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "单选",
|
||||
"type": "radio",
|
||||
"icon": "el-icon-aim",
|
||||
"value": 0,
|
||||
"data": [
|
||||
{
|
||||
"key": "0",
|
||||
"value": "否"
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"value": "xx11"
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"value": "是"
|
||||
}
|
||||
],
|
||||
"key": "enable",
|
||||
"field": "field1630260669595",
|
||||
"width": 50,
|
||||
"readonly": false,
|
||||
"required": false,
|
||||
"values": [
|
||||
"否"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "多选",
|
||||
"values": [
|
||||
"否"
|
||||
],
|
||||
"type": "checkbox",
|
||||
"key": "enable",
|
||||
"data": [
|
||||
{
|
||||
"key": "0",
|
||||
"value": "否"
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"value": "xx11"
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"value": "是"
|
||||
}
|
||||
],
|
||||
"icon": "el-icon-circle-check",
|
||||
"field": "field1630260695322",
|
||||
"width": 50,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "textarea",
|
||||
"type": "textarea",
|
||||
"value": "",
|
||||
"icon": "el-icon-document-copy",
|
||||
"field": "field1630260207393",
|
||||
"width": 100,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "编辑器",
|
||||
"type": "editor",
|
||||
"value": "",
|
||||
"url": "",
|
||||
"height": 200,
|
||||
"icon": "el-icon-notebook-2",
|
||||
"field": "field1630260646842",
|
||||
"width": 100,
|
||||
"readonly": false,
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
export { options1, options2,options3 }
|
||||
3
src/components/basic/MesFormDraggable/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import MesFormDraggable from './MesFormDraggable'
|
||||
|
||||
export default MesFormDraggable;
|
||||
226
src/components/basic/MesFormDraggable/options.js
Normal file
@@ -0,0 +1,226 @@
|
||||
const components = [
|
||||
{
|
||||
id: 1,
|
||||
name: "输入框",
|
||||
type: "text",
|
||||
value: "",
|
||||
icon: "el-icon-document",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "textarea",
|
||||
type: "textarea",
|
||||
value: "",
|
||||
icon: "el-icon-document-copy",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "日期",
|
||||
type: "date",
|
||||
icon: "el-icon-date",
|
||||
value: null,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "switch",
|
||||
type: "switch",
|
||||
icon: "el-icon-turn-off",
|
||||
value: 0,
|
||||
},
|
||||
{ id: 5, name: "单选", type: "radio", icon: "el-icon-aim", value: 0, data: [{ label: "0", value: "请设置数据源1" }, { label: "1", value: "请设置数据源2" }], key: "" },
|
||||
{
|
||||
id: 6,
|
||||
name: "多选",
|
||||
values: [],
|
||||
type: "checkbox",
|
||||
key: "",
|
||||
data: [{ label: "请设置数据源", value: "请设置数据源" }],
|
||||
icon: "el-icon-circle-check",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "下拉框",
|
||||
value: null,
|
||||
key: "",
|
||||
data: [{ label: "请设置数据源", value: "请设置数据源" }],
|
||||
type: "select",
|
||||
icon: "el-icon-arrow-down",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "下拉框多选",
|
||||
type: "selectList",
|
||||
key: "",
|
||||
values: [],
|
||||
data: [{ label: "请设置数据源", value: "请设置数据源" }],
|
||||
icon: "el-icon-arrow-down",
|
||||
},
|
||||
{
|
||||
id: 81,
|
||||
name: "级联",
|
||||
type: "cascader",
|
||||
icon: "el-icon-share",
|
||||
values: [],
|
||||
key: "",
|
||||
data: [
|
||||
{
|
||||
value: "请配置数据源",
|
||||
label: "请配置数据源",
|
||||
children: [
|
||||
{
|
||||
value: "具体",
|
||||
label: "菜单:下拉框绑定设置",
|
||||
},
|
||||
{
|
||||
value: "color",
|
||||
label: "可参照字典编号[tree_roles]",
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "图片上传",
|
||||
type: "img",
|
||||
url: "",
|
||||
maxSize: 3,
|
||||
fileInfo: [],
|
||||
multiple: false,
|
||||
autoUpload: false,
|
||||
maxFile: 5,
|
||||
icon: "el-icon-picture-outline",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "excel上传",
|
||||
url: "",
|
||||
maxSize: 3,
|
||||
multiple: false,
|
||||
autoUpload: false,
|
||||
maxFile: 5, //最多可上传5个文件
|
||||
fileInfo: [],
|
||||
type: "excel",
|
||||
icon: "el-icon-upload",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "文件上传",
|
||||
type: "file",
|
||||
url: "",
|
||||
maxSize: 3,
|
||||
multiple: false,
|
||||
autoUpload: false,
|
||||
maxFile: 5,
|
||||
fileInfo: [],
|
||||
icon: "el-icon-folder-opened",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "分段信息",
|
||||
type: "line",
|
||||
icon: "el-icon-guide",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: "编辑器",
|
||||
type: "editor",
|
||||
value: "",
|
||||
url: "",
|
||||
height: 200,
|
||||
icon: "el-icon-notebook-2",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: "弹出框",
|
||||
type: "box",
|
||||
value: "",
|
||||
url: "",
|
||||
height: 250,
|
||||
icon: "el-icon-notebook-2",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: "表格",
|
||||
type: "table",
|
||||
tabs: false,
|
||||
columns: [
|
||||
{ title: "字段1", field: "field1", show: true, required: false, edit: false, dataType: null, dataSource: null, width: 120, orderNo: null },
|
||||
{ title: "字段2", field: "field2", show: true, required: false, edit: false, dataType: null, dataSource: null, width: 120, orderNo: null },
|
||||
{ title: "字段3", field: "field3", show: true, required: false, edit: false, dataType: null, dataSource: null, width: 120, orderNo: null },
|
||||
{ title: "字段4", field: "field4", show: true, required: false, edit: false, dataType: null, dataSource: null, width: 120, orderNo: null },
|
||||
// { title: "字段5", field: "Field5", width: 120 },
|
||||
],
|
||||
tableData: [
|
||||
{
|
||||
field1: "field1",
|
||||
field2: "field2",
|
||||
field3: "field3",
|
||||
field4: "field4",
|
||||
},
|
||||
{
|
||||
field1: "field1",
|
||||
field2: "field2",
|
||||
field3: "field3",
|
||||
field4: "field4",
|
||||
},
|
||||
{
|
||||
field1: "field1",
|
||||
field2: "field2",
|
||||
field3: "field3",
|
||||
field4: "field4",
|
||||
},
|
||||
],
|
||||
height: 150,
|
||||
icon: "el-icon-c-scale-to-original",
|
||||
url: null,
|
||||
index: false, //item.index,
|
||||
height: 200,
|
||||
index: false,
|
||||
columnIndex: false,
|
||||
ck: true,
|
||||
buttons: [
|
||||
{ name: '添加行', ck: false, icon: 'el-icon-plus',value:'add' },
|
||||
{ name: '删除行', ck: false, icon: 'el-icon-delete',value:'del' },
|
||||
{ name: '刷新', ck: false ,icon:'el-icon-refresh-right',value:'ref'}],
|
||||
},
|
||||
]
|
||||
const tableOption = [
|
||||
{ field: 'field', title: '字段', edit: { type: "text", keep: true }, width: 160 },
|
||||
{ field: 'title', title: '字段中文名', edit: { type: "text", keep: true }, width: 120 },
|
||||
{ field: 'show', title: '是否显示', edit: { type: "switch", keep: true }, width: 90 },
|
||||
{
|
||||
field: 'dataType', title: '显示类型', edit: { type: "select", keep: true }, width: 120, bind: {
|
||||
key: '', data: [
|
||||
{ "key": "switch", "value": "单选" },
|
||||
{ "key": "date", "value": "年月日" },
|
||||
{ "key": "img", "value": "图片" },
|
||||
{ "key": "excel", "value": "excel" },
|
||||
{ "key": "file", "value": "文件" }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{ field: 'required', title: '是否必填', edit: { type: "switch", keep: true }, width: 90 },
|
||||
{ field: 'edit', title: '是否可编辑', edit: { type: "switch", keep: true }, width: 90 },
|
||||
{
|
||||
field: 'editType', title: '编辑类型', edit: { type: "select", keep: true, }, width: 120, bind: {
|
||||
key: '', data: [{ "key": "text", "value": "输入框" },
|
||||
{ "key": "switch", "value": "单选" },
|
||||
{ "key": "select", "value": "下拉框" },
|
||||
{ "key": "selectList", "value": "下拉框多选" },
|
||||
{ "key": "date", "value": "日期" },
|
||||
{ "key": "datetime", "value": "日期时分秒" },
|
||||
{ "key": "checkbox", "value": "复选框多选" },
|
||||
{ "key": "mail", "value": "邮箱地址" },
|
||||
{ "key": "number", "value": "数字" },
|
||||
{ "key": "decimal", "value": "小数" },
|
||||
{ "key": "phone", "value": "手机号" },
|
||||
]
|
||||
}
|
||||
},
|
||||
{ field: 'dataSource', title: '数据源', edit: { type: "select", keep: true, data: [] }, bind: { key: '', data: [] }, width: 120 },
|
||||
{ field: 'width', title: '列宽度', edit: { type: "text", keep: true }, width: 80 },
|
||||
{ field: 'orderNo', title: '列显示顺序', edit: { type: "text", keep: true }, width: 100 }
|
||||
];
|
||||
export { components, tableOption }
|
||||
95
src/components/basic/MesFormDraggable/templateCode.js
Normal file
@@ -0,0 +1,95 @@
|
||||
var code = `<template>
|
||||
<div style="padding: 15px 20px 15px 5px">
|
||||
<div class="pre-text">{{ text }}</div>
|
||||
<mes-form ref="form"
|
||||
:labelWidth="80"
|
||||
:load-key="false"
|
||||
:formFields="fields"
|
||||
:formRules="formOptions">
|
||||
</mes-form>
|
||||
{#tables}
|
||||
{#tabs}
|
||||
|
||||
<div class="form-btns">
|
||||
<el-button type="primary"
|
||||
@click="submit"
|
||||
icon="el-icon-check"
|
||||
size="mini">提交</el-button>
|
||||
<el-button type="primary"
|
||||
@click="reset"
|
||||
plain
|
||||
icon="el-icon-refresh-right"
|
||||
size="mini">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 使用方式:
|
||||
// 1、新建一个vue页面,把此页面内容复制进去
|
||||
// 2、router->index.js配置路由,页面上输入地址即可看到数据(也可以把菜单配置上)
|
||||
// 3、或者参照表单设计页面做动态页面
|
||||
//**表单设计器的table下载还在开发中
|
||||
{import_MesTable}
|
||||
import MesForm from '@/components/basic/MesForm'
|
||||
export default {
|
||||
components: {"mes-form": MesForm,{component_table}},
|
||||
data () {
|
||||
return {
|
||||
text: "",
|
||||
tabsModel: "0",
|
||||
fields: {#fields},
|
||||
formOptions: [{#formOptions}],
|
||||
tables: [{#tableOptions}],
|
||||
tabs: [{#tabsOptions}]
|
||||
};
|
||||
},
|
||||
created () {
|
||||
|
||||
},
|
||||
methods: {{table_ms}
|
||||
submit () {
|
||||
this.$Message.success("submit")
|
||||
return;
|
||||
this.http.post("url",this.fields,true).then(result=>{
|
||||
|
||||
})
|
||||
},
|
||||
reset () {
|
||||
this.$refs.form.reset();
|
||||
this.$Message.success("表单已重置")
|
||||
},
|
||||
download () {
|
||||
this.$Message.info("111")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MesForm;
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.form-btns {
|
||||
text-align: center;
|
||||
}
|
||||
.tables {
|
||||
padding-left: 15px;
|
||||
.table-item {
|
||||
padding: 10px;
|
||||
}
|
||||
.table-header {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.header-text {
|
||||
position: relative;
|
||||
bottom: -9px;
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
}
|
||||
.header-btns {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>`
|
||||
|
||||
export default code
|
||||
67
src/components/basic/MesHeader.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="v-header">
|
||||
<div class="v-left-text">
|
||||
<!-- <i size="20" :class="icon" class="h-icon"/> -->
|
||||
<span>{{ title || text }}</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<slot name="content"></slot>
|
||||
</div>
|
||||
<div class="v-right-content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: '未定义名称'
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.v-header {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #dcdee2;
|
||||
.v-left-text {
|
||||
margin-top: 3px;
|
||||
padding-bottom: 6px;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
color: #484848;
|
||||
white-space: nowrap;
|
||||
border-bottom: 2px solid #676767;
|
||||
margin-bottom: -1px;
|
||||
letter-spacing: 1px;
|
||||
> span {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
line-height: 25px;
|
||||
padding-left: 10px;
|
||||
padding: 6px 0 0 10px;
|
||||
}
|
||||
.v-right-content {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
}
|
||||
.h-icon {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1614
src/components/basic/MesTable.vue
Normal file
14
src/components/basic/MesTable/MesTableRender.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { h } from 'vue';
|
||||
export default {
|
||||
name: "TableExpand",
|
||||
functional: true,
|
||||
props: {
|
||||
render: Function,
|
||||
row: {},//当前行的数据
|
||||
column: {},//当前行的配置信息
|
||||
index: { type: Number, default: 0 }//当前所在行
|
||||
},
|
||||
render: ({ render,row ,column,index }) => {
|
||||
return render(h, {row ,column,index}); //h();
|
||||
}
|
||||
};
|
||||
738
src/components/basic/MesUpload.vue
Normal file
@@ -0,0 +1,738 @@
|
||||
<template>
|
||||
<div class="upload-container">
|
||||
<div>
|
||||
<div class="input-btns" style="margin-bottom: 10px">
|
||||
<input
|
||||
ref="input"
|
||||
type="file"
|
||||
style="display: none"
|
||||
@change="handleChange"
|
||||
:multiple="multiple"
|
||||
/>
|
||||
<div v-if="img" class="upload-img">
|
||||
<!-- v-for="(file,index) in fileInfo.length>0?fileInfo: files" -->
|
||||
<div v-for="(file, index) in files" :key="index" class="img-item">
|
||||
<div class="operation">
|
||||
<div class="action">
|
||||
<i class="el-icon-view view" @click="previewImg(index)"></i>
|
||||
<i class="el-icon-delete remove" @click="removeFile(index)"></i>
|
||||
</div>
|
||||
<div class="mask"></div>
|
||||
</div>
|
||||
|
||||
<img :src="getImgSrc(file, index)" :onerror="errorImg" />
|
||||
</div>
|
||||
<div
|
||||
v-show="!autoUpload || (autoUpload && files.length < maxFile)"
|
||||
class="img-selector"
|
||||
:class="getSelector()"
|
||||
>
|
||||
<div class="selector" @click="handleClick">
|
||||
<i class="el-icon-camera-solid"></i>
|
||||
</div>
|
||||
<div
|
||||
v-if="!autoUpload"
|
||||
class="s-btn"
|
||||
:class="{ readonly: changed }"
|
||||
@click="upload"
|
||||
>
|
||||
<div>{{ loadText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-button v-else @click="handleClick"
|
||||
>选择{{ img ? "图片" : "文件" }}</el-button
|
||||
>
|
||||
|
||||
<el-button
|
||||
v-if="!autoUpload && !img"
|
||||
type="info"
|
||||
:disabled="changed"
|
||||
@click="upload(true)"
|
||||
:loading="loadingStatus"
|
||||
>上传文件</el-button
|
||||
>
|
||||
</div>
|
||||
<slot></slot>
|
||||
<div v-if="desc">
|
||||
<el-alert
|
||||
:title="getText() + '文件大小不超过' + (maxSize || 50) + 'M'"
|
||||
type="info"
|
||||
show-icon
|
||||
>
|
||||
</el-alert>
|
||||
</div>
|
||||
<slot name="content"></slot>
|
||||
<div v-if="!img">
|
||||
<ul class="upload-list" v-show="fileList">
|
||||
<li class="list-file" v-for="(file, index) in files" :key="index">
|
||||
<a>
|
||||
<span @click="fileOnClick(index, file)">
|
||||
<i :class="format(file)"></i>
|
||||
{{ file.name }}
|
||||
</span>
|
||||
</a>
|
||||
<span @click="removeFile(index)" class="file-remove">
|
||||
<i class="el-icon-close"></i>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<slot name="tip"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
desc: {
|
||||
//是否显示默认介绍
|
||||
//是否多选
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
fileInfo: {
|
||||
//用于接收上传的文件,也可以加以默认值,显示已上传的文件,用户上传后会覆盖默认值
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}, //格式[{name:'1.jpg',path:'127.0.01/1.jpg'}]
|
||||
},
|
||||
downLoad: {
|
||||
//是否可以点击文件下载
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
multiple: {
|
||||
//是否多选
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
maxFile: {
|
||||
//最多可选文件数量,必须multiple=true,才会生效
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
maxSize: {
|
||||
//文件限制大小3M
|
||||
type: Number,
|
||||
default: 50,
|
||||
},
|
||||
|
||||
autoUpload: {
|
||||
//选择文件后是否自动上传
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
img: {
|
||||
//图片类型 img>excel>fileTypes三种文件类型优先级
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
excel: {
|
||||
//excel文件
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
fileTypes: {
|
||||
//指定上传文件的类型
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
url: {
|
||||
//上传的url
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
uploadBefore: {
|
||||
//返回false会中止执行
|
||||
//上传前
|
||||
type: Function,
|
||||
default: (files) => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
uploadAfter: {
|
||||
//返回false会中止执行
|
||||
//上传后
|
||||
type: Function,
|
||||
default: (result, files) => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
onChange: {
|
||||
//选择文件时 //返回false会中止执行
|
||||
type: Function,
|
||||
default: (files) => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
// clear: {
|
||||
// //上传完成后是否清空文件列表
|
||||
// type: Boolean,
|
||||
// default: true
|
||||
// },
|
||||
fileList: {
|
||||
//是否显示选择的文件列表
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
fileClick: {
|
||||
//点击文件事件
|
||||
type: Function,
|
||||
default: (index, file, files) => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
removeBefore: {
|
||||
//移除文件事件
|
||||
type: Function,
|
||||
default: (index, file, files) => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
append: {
|
||||
//此属性已废弃,多文件上传,默认追加文件
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
compress: {
|
||||
//开启图片压缩,后面根据需要再完善
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
errorImg: 'this.src="' + require("@/assets/imgs/error-img.png") + '"',
|
||||
changed: false, //手动上传成功后禁止重复上传,必须重新选择
|
||||
model: true,
|
||||
files: [],
|
||||
bigImg: "",
|
||||
loadingStatus: false,
|
||||
loadText: "上传文件",
|
||||
};
|
||||
},
|
||||
created() {
|
||||
//默认有图片的禁止上传操作
|
||||
if (this.fileInfo) {
|
||||
this.changed = true;
|
||||
}
|
||||
this.cloneFile(this.fileInfo);
|
||||
},
|
||||
watch: {
|
||||
fileInfo: {
|
||||
handler(files) {
|
||||
this.cloneFile(files);
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
cloneFile(files) {
|
||||
this.files = files.map((x) => {
|
||||
return {
|
||||
name: x.name || this.getFileName(x.path),
|
||||
path: x.path,
|
||||
};
|
||||
});
|
||||
},
|
||||
getFileName(path) {
|
||||
if (!path) {
|
||||
return "未定义文件名";
|
||||
}
|
||||
let _index = path.lastIndexOf("/");
|
||||
return path.substring(_index + 1);
|
||||
},
|
||||
previewImg(index) {
|
||||
//查看大图预览模式待完
|
||||
this.base.previewImg(this.getImgSrc(this.files[index]));
|
||||
// window.open(this.getImgSrc((this.files.length>0?this.files:this.fileInfo)[index]));
|
||||
},
|
||||
getSelector() {
|
||||
if (this.autoUpload) {
|
||||
return "auto-selector";
|
||||
}
|
||||
return "submit-selector";
|
||||
},
|
||||
getImgSrc(file, index) {
|
||||
if (file.hasOwnProperty("path")) {
|
||||
if (this.base.isUrl(file.path)) {
|
||||
return file.path;
|
||||
}
|
||||
//2020.12.27增加base64图片操作
|
||||
if (file.path.indexOf("/9j/") != -1) {
|
||||
return "data:image/jpeg;base64," + file.path;
|
||||
}
|
||||
if (file.path.substr(0, 1) == "/") {
|
||||
file.path = file.path.substr(1);
|
||||
}
|
||||
return this.http.ipAddress + file.path;
|
||||
}
|
||||
return window.URL.createObjectURL(file);
|
||||
},
|
||||
fileOnClick(index, file) {
|
||||
if (!this.fileClick(index, file, this.files)) {
|
||||
return;
|
||||
}
|
||||
//点击不下载
|
||||
if (!this.downLoad) {
|
||||
return;
|
||||
}
|
||||
if (!file.path) {
|
||||
this.$message.error("请先上传文件");
|
||||
return;
|
||||
}
|
||||
this.base.dowloadFile(
|
||||
file.path,
|
||||
file.name,
|
||||
{
|
||||
Authorization: this.$store.getters.getToken(),
|
||||
},
|
||||
this.http.ipAddress
|
||||
);
|
||||
},
|
||||
getText() {
|
||||
if (this.img) {
|
||||
return "只能上传图片,";
|
||||
} else if (this.excel) {
|
||||
return "只能上传excel文件,";
|
||||
}
|
||||
},
|
||||
handleClick() {
|
||||
this.$refs.input.click();
|
||||
},
|
||||
handleChange(e) {
|
||||
//this.compress开启图片压缩,后面根据需要再完善
|
||||
// this.clearFiles();
|
||||
var result = this.checkFile(e.target.files);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.changed = false;
|
||||
//如果传入了FileInfo需要自行处理移除FileInfo
|
||||
if (!this.onChange(e.target.files)) {
|
||||
return;
|
||||
}
|
||||
for (let index = 0; index < e.target.files.length; index++) {
|
||||
const element = e.target.files[index];
|
||||
element.input = true;
|
||||
}
|
||||
if (!this.multiple) {
|
||||
this.files.splice(0);
|
||||
}
|
||||
this.files.push(...e.target.files);
|
||||
|
||||
this.$refs.input.value = null;
|
||||
if (this.autoUpload && result) {
|
||||
this.upload(false);
|
||||
}
|
||||
},
|
||||
removeFile(index) {
|
||||
//如果传入了FileInfo需要自行处理移除FileInfo
|
||||
//t移除文件
|
||||
let removeFile = this.files[index];
|
||||
//删除的还没上传的文件
|
||||
if (removeFile.input) {
|
||||
this.files.splice(index, 1);
|
||||
} else {
|
||||
this.fileInfo.splice(index, 1);
|
||||
}
|
||||
if (!this.removeBefore(index, removeFile, this.fileInfo)) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
clearFiles() {
|
||||
this.files.splice(0);
|
||||
},
|
||||
getFiles() {
|
||||
return this.files;
|
||||
},
|
||||
upload(vail) {
|
||||
if (vail && !this.checkFile()) return false;
|
||||
if (!this.url) {
|
||||
return this.$message.error("没有配置好Url");
|
||||
}
|
||||
if (!this.files || this.files.length == 0) {
|
||||
return this.$message.error("请选择文件");
|
||||
}
|
||||
if (!this.uploadBefore(this.files)) {
|
||||
return;
|
||||
}
|
||||
var forms = new FormData();
|
||||
this.files.forEach(function (file) {
|
||||
if (file.input) {
|
||||
forms.append("fileInput", file, file.name);
|
||||
}
|
||||
});
|
||||
// forms.append("fileInput", this.files);
|
||||
this.loadingStatus = true;
|
||||
this.loadText = "上传中..";
|
||||
this.http
|
||||
.post(this.url, forms, this.autoUpload ? "正在上传文件" : "")
|
||||
.then(
|
||||
(x) => {
|
||||
// this.$refs.uploadFile.clearFiles();
|
||||
this.loadingStatus = false;
|
||||
this.loadText = "上传文件";
|
||||
if (!this.uploadAfter(x, this.files)) {
|
||||
this.changed = false;
|
||||
return;
|
||||
} else {
|
||||
this.changed = true;
|
||||
}
|
||||
this.$message.success(x.message);
|
||||
this.changed = x.status;
|
||||
if (!x.status) {
|
||||
// this.files = null;
|
||||
return;
|
||||
}
|
||||
//单选清除以前的数据
|
||||
// if (!this.multiple) {
|
||||
this.fileInfo.splice(0);
|
||||
// }
|
||||
let _files = this.files.map((file) => {
|
||||
return {
|
||||
name: file.name,
|
||||
path: file.path || x.data + file.name,
|
||||
};
|
||||
});
|
||||
this.fileInfo.push(..._files);
|
||||
//2021.09.25修复文件上传后不能同时下载的问题
|
||||
this.files = _files;
|
||||
},
|
||||
(error) => {
|
||||
this.loadText = "上传文件";
|
||||
this.loadingStatus = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
format(file, checkFileType) {
|
||||
const format = file.name.split(".").pop().toLocaleLowerCase() || "";
|
||||
let fileIcon = "el-icon-document";
|
||||
if (this.fileTypes.length > 0 && checkFileType != undefined) {
|
||||
if (this.fileTypes.indexOf(format) != -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
checkFileType &&
|
||||
!(checkFileType instanceof Array) &&
|
||||
checkFileType != "img" &&
|
||||
checkFileType != "excel"
|
||||
) {
|
||||
if (checkFileType.indexOf(format) > -1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
checkFileType == "img" ||
|
||||
["gif", "jpg", "jpeg", "png", "bmp", "webp"].indexOf(format) > -1
|
||||
) {
|
||||
if (checkFileType == "img") {
|
||||
if (
|
||||
["gif", "jpg", "jpeg", "png", "bmp", "webp"].indexOf(format) > -1
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fileIcon = "el-icon-picture-outline";
|
||||
}
|
||||
if (
|
||||
["mp4", "m3u8", "rmvb", "avi", "swf", "3gp", "mkv", "flv"].indexOf(
|
||||
format
|
||||
) > -1
|
||||
) {
|
||||
fileIcon = "el-icon-document";
|
||||
}
|
||||
if (["mp3", "wav", "wma", "ogg", "aac", "flac"].indexOf(format) > -1) {
|
||||
fileIcon = "el-icon-document";
|
||||
}
|
||||
if (["doc", "txt", "docx", "pages", "epub", "pdf"].indexOf(format) > -1) {
|
||||
fileIcon = "el-icon-document";
|
||||
}
|
||||
if (
|
||||
checkFileType == "excel" ||
|
||||
["numbers", "csv", "xls", "xlsx"].indexOf(format) > -1
|
||||
) {
|
||||
if (checkFileType == "excel") {
|
||||
if (["numbers", "csv", "xls", "xlsx"].indexOf(format) > -1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fileIcon = "el-icon-document";
|
||||
}
|
||||
return fileIcon;
|
||||
},
|
||||
beforeUpload() {},
|
||||
checkFile(inputFiles) {
|
||||
const files = this.files;
|
||||
|
||||
if (
|
||||
this.multiple &&
|
||||
files.length + (inputFiles || []).length > (this.maxFile || 5)
|
||||
) {
|
||||
this.$message.error(
|
||||
"最多只能选【" +
|
||||
(this.maxFile || 5) +
|
||||
"】" +
|
||||
(this.img ? "张图片" : "个文件") +
|
||||
""
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!inputFiles) {
|
||||
inputFiles = this.files.filter((x) => {
|
||||
return x.input;
|
||||
});
|
||||
}
|
||||
let names = [];
|
||||
for (let index = 0; index < inputFiles.length; index++) {
|
||||
const file = inputFiles[index];
|
||||
if (names.indexOf(file.name) != -1) {
|
||||
file.name = "(" + index + ")" + file.name;
|
||||
}
|
||||
names.push(file.name);
|
||||
if (this.img && !this.format(file, "img")) {
|
||||
this.$message.error("选择的文件【" + file.name + "】只能是图片格式");
|
||||
return false;
|
||||
}
|
||||
if (this.excel && !this.format(file, "excel")) {
|
||||
this.$message.error("选择的文件【" + file.name + "】只能是excel文件");
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
this.fileTypes &&
|
||||
this.fileTypes.length > 0 &&
|
||||
!this.format(file, this.fileTypes)
|
||||
) {
|
||||
this.$message.error(
|
||||
"选择的文件【" +
|
||||
file.name +
|
||||
"】只能是【" +
|
||||
this.fileTypes.join(",") +
|
||||
"】格式"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (file.size > (this.maxSize || 50) * 1024 * 1024) {
|
||||
this.$message.error(
|
||||
"选择的文件【" +
|
||||
file.name +
|
||||
"】不能超过:" +
|
||||
(this.maxSize || 50) +
|
||||
"M"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.upload-list {
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
.list-file {
|
||||
line-height: 20px;
|
||||
padding: 4px;
|
||||
color: #515a6e;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
font-size: 13px;
|
||||
.file-remove {
|
||||
display: none;
|
||||
right: 0;
|
||||
// margin-left: 50px;
|
||||
color: #0e9286;
|
||||
}
|
||||
}
|
||||
.list-file:hover {
|
||||
cursor: pointer;
|
||||
.file-remove {
|
||||
display: initial;
|
||||
}
|
||||
color: #2d8cf0;
|
||||
}
|
||||
}
|
||||
.upload-container {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
// padding: 10px;
|
||||
|
||||
// min-height: 250px;
|
||||
border-radius: 5px;
|
||||
.alert {
|
||||
margin-top: 43px;
|
||||
}
|
||||
.button-group > * {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.file-info > span {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
.upload-img {
|
||||
display: inline-block;
|
||||
.img-item:hover .operation {
|
||||
display: block;
|
||||
}
|
||||
.img-item,
|
||||
.img-selector {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
margin: 0 10px 10px 0;
|
||||
float: left;
|
||||
width: 65px;
|
||||
height: 65px;
|
||||
border: 1px solid #c7c7c7;
|
||||
overflow: hidden;
|
||||
border-radius: 5px;
|
||||
box-sizing: content-box;
|
||||
img {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.operation {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
.action {
|
||||
opacity: 0.6;
|
||||
text-align: center;
|
||||
background: #151515de;
|
||||
font-size: 14px;
|
||||
position: absolute;
|
||||
z-index: 90;
|
||||
width: 100%;
|
||||
bottom: 3px;
|
||||
bottom: 0;
|
||||
color: #ded5d5;
|
||||
padding-right: 7px;
|
||||
padding-bottom: 3px;
|
||||
line-height: 20px;
|
||||
.el-icon-view {
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
.mask {
|
||||
opacity: 0.6;
|
||||
background: #9e9e9e;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
.img-selector {
|
||||
font-size: 50px;
|
||||
text-align: center;
|
||||
i {
|
||||
position: relative;
|
||||
font-size: 40px;
|
||||
color: #6f6f6f;
|
||||
}
|
||||
}
|
||||
|
||||
.auto-selector {
|
||||
.selector {
|
||||
line-height: 64px;
|
||||
}
|
||||
}
|
||||
.selector {
|
||||
color: #a0a0a0;
|
||||
}
|
||||
.submit-selector {
|
||||
.s-btn {
|
||||
line-height: 22px;
|
||||
font-size: 12px;
|
||||
top: -6px;
|
||||
// padding: 2px;
|
||||
position: relative;
|
||||
background: #2db7f5;
|
||||
color: white;
|
||||
}
|
||||
.selector {
|
||||
line-height: 50px;
|
||||
}
|
||||
.readonly {
|
||||
background: #8c8c8c;
|
||||
}
|
||||
}
|
||||
}
|
||||
.big-model {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.m-img {
|
||||
}
|
||||
.mask {
|
||||
position: absolute;
|
||||
opacity: 0.6;
|
||||
background: #eee;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.auto-upload {
|
||||
z-index: 9999999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
.j-content {
|
||||
text-align: center;
|
||||
font-size: 17px;
|
||||
top: 40%;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 240px;
|
||||
/* height: 100%; */
|
||||
margin: auto;
|
||||
background: white;
|
||||
/* bottom: 30px; */
|
||||
line-height: 50px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #d2d2d2;
|
||||
}
|
||||
.mask {
|
||||
cursor: pointer;
|
||||
opacity: 0.6;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #101010;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
152
src/components/basic/QuickSearch.vue
Normal file
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-select
|
||||
style="width: 150px"
|
||||
v-if="['select', 'selectList'].indexOf(singleSearch.type) != -1"
|
||||
v-model="searchFormFields[singleSearch.field]"
|
||||
:filterable="
|
||||
singleSearch.filter || singleSearch.data.length > 10 ? true : false
|
||||
"
|
||||
:placeholder="'请选择' + singleSearch.title"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in singleSearch.data"
|
||||
:key="item.key"
|
||||
:label="item.value"
|
||||
:value="item.key"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<div
|
||||
class="date-range"
|
||||
v-else-if="['date', 'datetime'].indexOf(singleSearch.type) != -1"
|
||||
>
|
||||
<el-date-picker
|
||||
style="width: 210px"
|
||||
:clearable="false"
|
||||
unlink-panels
|
||||
v-model="searchFormFields[singleSearch.field]"
|
||||
type="daterange"
|
||||
:value-format="getDateFormat(singleSearch)"
|
||||
:placeholder="singleSearch.title"
|
||||
>
|
||||
</el-date-picker>
|
||||
<i
|
||||
class="el-icon-circle-close"
|
||||
@click="dateRangeClear(singleSearch.field)"
|
||||
></i>
|
||||
</div>
|
||||
<el-cascader
|
||||
style="width: 210px"
|
||||
clearable
|
||||
v-model="searchFormFields[singleSearch.field]"
|
||||
v-else-if="singleSearch.type == 'cascader'"
|
||||
:options="singleSearch.data"
|
||||
:props="{ checkStrictly: true }"
|
||||
>
|
||||
</el-cascader>
|
||||
<el-input
|
||||
clearable
|
||||
v-else
|
||||
style="width: 150px"
|
||||
size="default"
|
||||
v-model="searchFormFields[singleSearch.field]"
|
||||
:placeholder="singleSearch.title"
|
||||
@keypress="tiggerPress"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
singleSearch: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
searchFormFields: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
tiggerPress: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
compareDate(date1, date2) {
|
||||
if (!date2) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
date1.valueOf() <
|
||||
(typeof date2 == "number" ? date2 : new Date(date2).valueOf())
|
||||
);
|
||||
},
|
||||
getDateFormat(item) {
|
||||
//见https://day.js.org/docs/zh-CN/display/format
|
||||
return item.type == "date" ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm:ss";
|
||||
},
|
||||
getDateOptions(date, item) {
|
||||
if ((!item.min && !item.max) || !date) {
|
||||
return false;
|
||||
}
|
||||
if (item.min && item.min.indexOf(" ") == -1) {
|
||||
//不设置时分秒,后面会自动加上 08:00
|
||||
item.min = item.min + " 00:00:000";
|
||||
}
|
||||
return (
|
||||
this.compareDate(date, item.min) || !this.compareDate(date, item.max)
|
||||
);
|
||||
},
|
||||
dateRangeClear(field) {
|
||||
this.searchFormFields[field]=[undefined,undefined];
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.singleSearch.dateType = this.singleSearch.type + "range";
|
||||
if (
|
||||
this.singleSearch.type == "date" ||
|
||||
this.singleSearch.type == "datetime"
|
||||
) {
|
||||
var _dateVal = this.searchFormFields[this.singleSearch.field];
|
||||
if (
|
||||
typeof this.singleSearch.range == "boolean" &&
|
||||
!this.singleSearch.range
|
||||
) {
|
||||
this.searchFormFields[this.singleSearch.field] = "";
|
||||
this.singleSearch.dateType = this.singleSearch.type;
|
||||
return this.singleSearch.dateType;
|
||||
} else if (!(_dateVal instanceof Array)) {
|
||||
this.searchFormFields[this.singleSearch.field] = ["", ""];
|
||||
} else if (_dateVal.length != 2) {
|
||||
_dateVal.splice(0);
|
||||
_dateVal.push(...["", ""]);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.date-range{
|
||||
position: relative;
|
||||
> i{
|
||||
display: none;
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
right: 1px;
|
||||
top: 3px;
|
||||
font-size: 13px;
|
||||
color: #b4adad;
|
||||
position: absolute;
|
||||
padding: 0 6px 0 3px;
|
||||
background: #ffff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.date-range:hover > i{
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
105
src/components/basic/RouterLoading.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div class="router-loading" style="background: #eeeeee5c;">
|
||||
<div class="spanner">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.router-loading {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 100px;
|
||||
text-align: center;
|
||||
padding-top: 200px;
|
||||
color: #808080;
|
||||
z-index: 9999;
|
||||
}
|
||||
.spanner {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.router-loading span {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: #66b1ff;
|
||||
position: absolute;
|
||||
animation: r_load 1.04s ease infinite;
|
||||
}
|
||||
@keyframes r_load {
|
||||
0% {
|
||||
transform: scale(1.2);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: scale(0.3);
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
.router-loading span:nth-child(1) {
|
||||
left: 0;
|
||||
top: 50%;
|
||||
margin-top: -10px;
|
||||
animation-delay: 0.13s;
|
||||
}
|
||||
.router-loading span:nth-child(2) {
|
||||
left: 14px;
|
||||
top: 14px;
|
||||
animation-delay: 0.26s;
|
||||
}
|
||||
.router-loading span:nth-child(3) {
|
||||
left: 50%;
|
||||
top: 0;
|
||||
margin-left: -10px;
|
||||
animation-delay: 0.39s;
|
||||
}
|
||||
.router-loading span:nth-child(4) {
|
||||
top: 14px;
|
||||
right: 14px;
|
||||
animation-delay: 0.52s;
|
||||
}
|
||||
.router-loading span:nth-child(5) {
|
||||
right: 0;
|
||||
top: 50%;
|
||||
margin-top: -10px;
|
||||
animation-delay: 0.65s;
|
||||
}
|
||||
.router-loading span:nth-child(6) {
|
||||
right: 14px;
|
||||
bottom: 14px;
|
||||
animation-delay: 0.78s;
|
||||
}
|
||||
.router-loading span:nth-child(7) {
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
margin-left: -10px;
|
||||
animation-delay: 0.91s;
|
||||
}
|
||||
.router-loading span:nth-child(8) {
|
||||
bottom: 14px;
|
||||
left: 14px;
|
||||
animation-delay: 1.04s;
|
||||
}
|
||||
</style>
|
||||
221
src/components/basic/UploadExcel.vue
Normal file
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<div class="upload-container">
|
||||
<a :href="template.url" ref="template"></a>
|
||||
<div class="button-group">
|
||||
<el-upload
|
||||
style="float: left"
|
||||
ref="uploadFile"
|
||||
:max-size="maxSize"
|
||||
:on-change="clearMsg"
|
||||
:before-upload="beforeUpload"
|
||||
:action="url"
|
||||
>
|
||||
<el-button size="small"
|
||||
><i class="el-icon-folder-opened"></i>选择文件</el-button
|
||||
>
|
||||
</el-upload>
|
||||
<el-button
|
||||
v-if="template.url"
|
||||
style="margin-left: 10px"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="dowloadTemplate"
|
||||
:loading="loadingStatus"
|
||||
>
|
||||
<i class="el-icon-bottom"></i>
|
||||
下载模板</el-button
|
||||
>
|
||||
<el-button
|
||||
type="success"
|
||||
size="small"
|
||||
@click="upload"
|
||||
:loading="loadingStatus"
|
||||
>
|
||||
<i class="el-icon-top"></i>
|
||||
上传文件</el-button
|
||||
>
|
||||
</div>
|
||||
<div class="alert">
|
||||
<el-alert title="上传说明" type="warning" :closable="false" show-icon
|
||||
>只能上传excel文件,文件大小不超过{{ maxSize }}M</el-alert
|
||||
>
|
||||
</div>
|
||||
|
||||
<div v-if="file">
|
||||
<h3>文件列表</h3>
|
||||
<div class="file-info">
|
||||
<span>文件名:{{ file.name }}</span>
|
||||
<span>大小{{ (file.size / 1024).toFixed(2) }}KB</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="message" class="v-r-message">
|
||||
<h3 class="title">上传结果</h3>
|
||||
<div class="text" :class="resultClass" v-html="message"></div>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
//目前只支持单个Excel上传,其他功能开发中...
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
template: {
|
||||
//下载模板配置
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
url: '', //模板下载路径,如果没有模板路径,则不显示下载模板功能
|
||||
fileName: '未定义文件名' //下载模板的文件名
|
||||
};
|
||||
}
|
||||
},
|
||||
importExcelBefore: {
|
||||
type: Function,
|
||||
default: (file) => {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
maxSize: 100,
|
||||
model: true,
|
||||
file: null,
|
||||
loadingStatus: false,
|
||||
message: '',
|
||||
resultClass: ''
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
clearMsg() {
|
||||
this.message = '';
|
||||
},
|
||||
reset() {
|
||||
this.file = null;
|
||||
this.message = '';
|
||||
this.resultClass = '';
|
||||
},
|
||||
getFileType() {
|
||||
let fileName =
|
||||
this.file.name
|
||||
.split('.')
|
||||
.pop()
|
||||
.toLocaleLowerCase() || '';
|
||||
if (['numbers', 'csv', 'xls', 'xlsx'].indexOf(fileName) == -1) {
|
||||
this.$Message.error('只能选择excel文件');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
beforeUpload(file) {
|
||||
this.file = file;
|
||||
if (!this.getFileType()) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
upload() {
|
||||
let _url = this.url;
|
||||
if (!_url) {
|
||||
return this.$Message.error('没有配置好Url');
|
||||
}
|
||||
|
||||
if (!this.file) {
|
||||
return this.$Message.error('请选择文件');
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append('fileInput', this.file);
|
||||
if (!this.importExcelBefore(formData)) {
|
||||
return;
|
||||
}
|
||||
this.loadingStatus = true;
|
||||
this.http.post(_url, formData).then(
|
||||
(x) => {
|
||||
// this.$refs.uploadFile.clearFiles();
|
||||
this.loadingStatus = false;
|
||||
this.file = null;
|
||||
if (x.status) {
|
||||
this.$emit('importExcelAfter', x);
|
||||
}
|
||||
|
||||
this.message = x.message;
|
||||
this.resultClass = x.status ? 'v-r-success' : 'v-r-error';
|
||||
},
|
||||
(error) => {
|
||||
this.loadingStatus = false;
|
||||
}
|
||||
);
|
||||
},
|
||||
dowloadTemplate() {
|
||||
let url = this.template.url;
|
||||
let xmlResquest = new XMLHttpRequest();
|
||||
xmlResquest.open('GET', url, true);
|
||||
xmlResquest.setRequestHeader('Content-type', 'application/json');
|
||||
xmlResquest.setRequestHeader(
|
||||
'Authorization',
|
||||
this.$store.getters.getToken()
|
||||
);
|
||||
let fileName = this.template.fileName + '.xlsx';
|
||||
let elink = this.$refs.template;
|
||||
xmlResquest.responseType = 'blob';
|
||||
let $_vue = this;
|
||||
this.loadingStatus = true;
|
||||
xmlResquest.onload = function(oEvent) {
|
||||
$_vue.loadingStatus = false;
|
||||
if (xmlResquest.response.type == 'application/json') {
|
||||
return $_vue.message.error('未找到下载文件');
|
||||
}
|
||||
let content = xmlResquest.response;
|
||||
elink.download = fileName;
|
||||
let blob = new Blob([content]);
|
||||
elink.href = URL.createObjectURL(blob);
|
||||
elink.click();
|
||||
};
|
||||
xmlResquest.send();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.upload-container {
|
||||
min-height: 270px !important;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px dashed #989898;
|
||||
min-height: 250px;
|
||||
border-radius: 5px;
|
||||
.alert {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.el-button-group > * {
|
||||
display: flex;
|
||||
}
|
||||
h3 {
|
||||
margin: 9px 0px;
|
||||
}
|
||||
.file-info > span {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.v-r-message {
|
||||
margin-top: 10px;
|
||||
.title {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
> .text {
|
||||
font-size: 13px;
|
||||
}
|
||||
.v-r-success {
|
||||
color: #02b702;
|
||||
}
|
||||
.v-r-error {
|
||||
color: #dc0909;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
46
src/components/basic/ViewGrid/AuditHis.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<mes-table
|
||||
:tableData="tableData"
|
||||
:columns="columns"
|
||||
:height="411"
|
||||
:pagination-hide="true"
|
||||
:load-key="false"
|
||||
:text-inline="false"
|
||||
:ck="false"
|
||||
></mes-table>
|
||||
</template>
|
||||
<script>
|
||||
import MesTable from '@/components/basic/MesTable.vue';
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
reactive,
|
||||
toRefs,
|
||||
getCurrentInstance
|
||||
} from 'vue';
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MesTable
|
||||
},
|
||||
props: {
|
||||
tableData: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const columns = reactive([
|
||||
{ title: '节点', field: 'stepName' },
|
||||
{ title: '审批人', field: 'auditor' },
|
||||
{ title: '审批结果', field: 'auditStatus' },
|
||||
{ title: '审批时间', field: 'auditDate',width:150 },
|
||||
{ title: '备注', field: 'remark' }
|
||||
]);
|
||||
return {
|
||||
columns
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
179
src/components/basic/ViewGrid/ViewGrid.less
Normal file
@@ -0,0 +1,179 @@
|
||||
.view-container {
|
||||
// padding: 15px;
|
||||
background: white;
|
||||
.grid-search {
|
||||
padding-top: 15px;
|
||||
//padding: 15px 15px 0 15px;
|
||||
}
|
||||
.grid-container,
|
||||
.grid-body {
|
||||
padding: 0 15px;
|
||||
}
|
||||
.view-header {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.fs-line {
|
||||
height: 9px;
|
||||
background: #f1f1f1;
|
||||
margin-top: -10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
.view-header {
|
||||
height: 45px;
|
||||
position: relative;
|
||||
padding-bottom: 11px;
|
||||
display: flex;
|
||||
.search-line {
|
||||
min-width: 150px;
|
||||
}
|
||||
.search-line > div {
|
||||
margin-left: 5px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.search-line > div > div {
|
||||
width: 200px;
|
||||
text-align: left;
|
||||
}
|
||||
.search-line > div:first-child {
|
||||
flex: 1;
|
||||
}
|
||||
.search-line > div .ivu-select-dropdown {
|
||||
max-height: 300px;
|
||||
}
|
||||
.btn-group {
|
||||
white-space: nowrap;
|
||||
button {
|
||||
margin-left: 10px;
|
||||
// padding: 5px 16px;
|
||||
}
|
||||
}
|
||||
.btn-group .ivu-dropdown-item {
|
||||
text-align: left !important;
|
||||
}
|
||||
.btn-group .ivu-dropdown-item:not(:last-child) {
|
||||
border-bottom: 1px dotted #eee;
|
||||
}
|
||||
.desc-text {
|
||||
margin-top: 5px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 3px;
|
||||
font-size: 14px;
|
||||
color: #313131;
|
||||
white-space: nowrap;
|
||||
border-bottom: 2px solid #646565;
|
||||
i {
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
.search-box {
|
||||
background: #fefefe;
|
||||
margin-top: 45px;
|
||||
border: 1px solid #ececec;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 25px 40px;
|
||||
padding-bottom: 0;
|
||||
box-shadow: 0px 7px 18px -12px #bdc0bb;
|
||||
}
|
||||
.notice {
|
||||
font-size: 13px;
|
||||
color: #6b6b6b;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
top: 12px;
|
||||
flex: 1;
|
||||
left: 10px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-info-cell-title {
|
||||
background-color: #f5f5f5 !important;
|
||||
}
|
||||
.box-com {
|
||||
> div.item {
|
||||
// margin-bottom: 10px;
|
||||
padding: 15px 17px 0 8px;
|
||||
margin-bottom: 12px;
|
||||
background: white;
|
||||
}
|
||||
> div.form-item {
|
||||
padding: 19px 16px 0px 5px;
|
||||
//box-shadow: 0 1px 7px rgb(199, 199, 199);
|
||||
}
|
||||
> div.table-item {
|
||||
padding: 0 10px;
|
||||
border-top: 1.5px solid #eaeaea;
|
||||
}
|
||||
.v-text {
|
||||
line-height: 27px;
|
||||
}
|
||||
.form-text {
|
||||
position: relative;
|
||||
border-bottom: 1px solid #eee;
|
||||
font-size: 14px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-closex {
|
||||
text-align: right;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
.form-closex button {
|
||||
margin-left: 10px;
|
||||
padding: 4px 13px;
|
||||
}
|
||||
.toolbar {
|
||||
padding: 3px 0px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
.title {
|
||||
line-height: 29px;
|
||||
border-bottom: none;
|
||||
font-size: 13px;
|
||||
font-weight: bolder;
|
||||
margin-bottom: 0;
|
||||
color: #5d5c5c;
|
||||
.icon {
|
||||
color: #009688;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
i {
|
||||
line-height: 29px;
|
||||
border-bottom: none;
|
||||
font-weight: bolder;
|
||||
margin-bottom: 0;
|
||||
color: #5d5c5c;
|
||||
position: relative;
|
||||
margin-top: -4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.btns {
|
||||
line-height: 28px;
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
button {
|
||||
// border: none;
|
||||
// margin-left:15px;
|
||||
border: 0px;
|
||||
padding: 0px 9px;
|
||||
}
|
||||
// button:hover{
|
||||
// color: #FF9800;
|
||||
// border-color: #FF9800;
|
||||
// border: none;
|
||||
// }
|
||||
}
|
||||
}
|
||||
804
src/components/basic/ViewGrid/ViewGrid.vue
Normal file
@@ -0,0 +1,804 @@
|
||||
<template>
|
||||
<div class="layout-container">
|
||||
<a :href="exportHref" ref="export"></a>
|
||||
<!--开启懒加载2020.12.06 -->
|
||||
<mes-box
|
||||
:on-model-close="closeCustomModel"
|
||||
v-model="viewModel"
|
||||
:height="520"
|
||||
:width="500"
|
||||
:padding="0"
|
||||
:lazy="true"
|
||||
title="设置"
|
||||
>
|
||||
<template #content>
|
||||
<custom-column :view-columns="viewColumns"></custom-column>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div style="text-align: center">
|
||||
<el-button type="default" size="small" @click="closeCustomModel"
|
||||
><i class="el-icon-close"></i>取消</el-button
|
||||
>
|
||||
<el-button type="success" size="small" @click="initViewColumns(true)"
|
||||
><i class="el-icon-refresh"></i>重置</el-button
|
||||
>
|
||||
<el-button type="primary" size="small" @click="saveColumnConfig"
|
||||
><i class="el-icon-check"></i>确定</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</mes-box>
|
||||
<ViewGridAudit @auditClick="saveAudit" :option="table" ref="audit">
|
||||
|
||||
</ViewGridAudit>
|
||||
<!--开启懒加载2020.12.06 -->
|
||||
<!--审核(异步点击按钮时才加载待完)-->
|
||||
<!-- <mes-box
|
||||
v-model="auditParam.model"
|
||||
:height="auditParam.height"
|
||||
:width="750"
|
||||
:lazy="true"
|
||||
:padding="0"
|
||||
title="审批"
|
||||
>
|
||||
<template #content>
|
||||
<el-tabs type="card">
|
||||
<el-tab-pane label="当前审批">
|
||||
<div class="v-steps">
|
||||
<div
|
||||
:class="{ 'step-current': item.isCurrent }"
|
||||
class="step-item"
|
||||
v-for="(item, index) in workFlowSteps"
|
||||
:key="index"
|
||||
>
|
||||
<div class="left-item">
|
||||
<div>审批时间</div>
|
||||
<div class="left-date">{{ item.auditDate || '待审批' }}</div>
|
||||
</div>
|
||||
<div class="right-item">
|
||||
<div class="step-line"></div>
|
||||
<i class="step-circle"></i>
|
||||
<div class="step-title">
|
||||
{{ item.stepName }}
|
||||
</div>
|
||||
<div class="step-text">审批人:{{ item.auditor }}</div>
|
||||
<div class="step-text">
|
||||
状 态: {{ getAuditStatus(item.auditStatus) }}
|
||||
</div>
|
||||
<div class="step-text">备 注: {{ item.remark || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:style="{
|
||||
'margin-top': workFlowSteps.length ? '20px' : '-17px'
|
||||
}"
|
||||
class="audit-content"
|
||||
v-show="auditParam.showAction"
|
||||
>
|
||||
<div style="margin-bottom:10px;">
|
||||
审批:
|
||||
<el-radio-group
|
||||
style="margin-left:15px"
|
||||
v-model="auditParam.value"
|
||||
>
|
||||
<el-radio
|
||||
v-for="item in auditParam.data"
|
||||
:key="item.value"
|
||||
:label="item.value"
|
||||
>
|
||||
<span>{{ item.text }}</span>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<el-input
|
||||
v-model="auditParam.reason"
|
||||
type="textarea"
|
||||
style="margin-right: 13px;"
|
||||
:autosize="{ minRows: 4, maxRows: 10 }"
|
||||
placeholder="请输入备注..."
|
||||
></el-input>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-if="workFlowSteps.length" label="审批记录">
|
||||
<audit-his :table-data="auditParam.auditHis"></audit-his>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div style="text-align: center;">
|
||||
<el-button size="small" @click="auditParam.model = false"
|
||||
><i class="el-icon-close"></i>关闭</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
v-show="auditParam.showAction"
|
||||
size="small"
|
||||
@click="saveAudit"
|
||||
><i class="el-icon-check"></i>审核</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</mes-box> -->
|
||||
|
||||
<!--导入excel功能-->
|
||||
<!--2020.10.31添加导入前的方法-->
|
||||
<!--开启懒加载2020.12.06 -->
|
||||
<!-- 2022.01.08增加明细表导入判断 -->
|
||||
<mes-box
|
||||
v-if="upload.url"
|
||||
v-model="upload.excel"
|
||||
:height="350"
|
||||
:width="600"
|
||||
:lazy="true"
|
||||
:title="(boxModel ? detailOptions.cnName : table.cnName) + '-导入'"
|
||||
>
|
||||
<UploadExcel
|
||||
ref="upload_excel"
|
||||
@importExcelAfter="importExcelAfter"
|
||||
:importExcelBefore="importExcelBefore"
|
||||
:url="upload.url"
|
||||
:template="upload.template"
|
||||
></UploadExcel>
|
||||
</mes-box>
|
||||
<!--头部自定义组件-->
|
||||
<component
|
||||
:is="dynamicComponent.gridHeader"
|
||||
ref="gridHeader"
|
||||
@parentCall="parentCall"
|
||||
></component>
|
||||
<!--主界面查询与table表单布局-->
|
||||
<div class="view-container">
|
||||
<!-- 2020.09.11增加固定查询表单 -->
|
||||
<!--查询条件-->
|
||||
<div class="grid-search">
|
||||
<div
|
||||
:class="[fiexdSearchForm ? 'fiexd-search-box' : 'search-box']"
|
||||
v-show="searchBoxShow"
|
||||
>
|
||||
<!-- 2020.09.13增加formFileds拼写错误兼容处理 -->
|
||||
<mes-form
|
||||
ref="searchForm"
|
||||
:load-key="false"
|
||||
style="padding: 0 15px"
|
||||
:label-width="labelWidth"
|
||||
:formRules="searchFormOptions"
|
||||
:formFields="searchFormFields"
|
||||
:select2Count="select2Count"
|
||||
>
|
||||
<template #footer>
|
||||
<div v-if="!fiexdSearchForm" class="form-closex">
|
||||
<el-button size="small" type="primary" plain @click="search">
|
||||
<i class="el-icon-search" />查询
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
size="small"
|
||||
type="success"
|
||||
plain
|
||||
@click="resetSearch"
|
||||
>
|
||||
<i class="el-icon-refresh-right" />重置
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
plain
|
||||
@click="searchBoxShow = !searchBoxShow"
|
||||
>
|
||||
<i class="el-icon-switch-button" />关闭
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</mes-form>
|
||||
<div v-if="fiexdSearchForm" class="fs-line"></div>
|
||||
</div>
|
||||
<div class="view-header">
|
||||
<div class="desc-text">
|
||||
<i class="el-icon-s-grid" />
|
||||
<span>{{ table.cnName }}</span>
|
||||
</div>
|
||||
<div class="notice">
|
||||
<a class="text" :title="extend.text">{{ extend.text }}</a>
|
||||
</div>
|
||||
<!--快速查询字段-->
|
||||
<div class="search-line" v-if="!fiexdSearchForm">
|
||||
<QuickSearch
|
||||
v-if="singleSearch"
|
||||
:singleSearch="singleSearch"
|
||||
:searchFormFields="searchFormFields"
|
||||
:tiggerPress="quickSearchKeyPress"
|
||||
></QuickSearch>
|
||||
</div>
|
||||
<!--操作按钮组-->
|
||||
<!-- 2020.11.29增加查询界面hidden属性 -->
|
||||
|
||||
<div class="btn-group">
|
||||
<template
|
||||
:key="bIndex"
|
||||
v-for="(btn, bIndex) in buttons.slice(0, maxBtnLength)"
|
||||
>
|
||||
<el-dropdown size="small" v-if="btn.data" :split-button="false">
|
||||
<el-button
|
||||
:color="btn.color"
|
||||
:dark="false"
|
||||
:type="btn.type"
|
||||
:plain="btn.plain"
|
||||
>
|
||||
{{ btn.name }}<i class="el-icon-arrow-down el-icon--right"></i
|
||||
></el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="(item, index) in btn.data"
|
||||
:key="index"
|
||||
>
|
||||
<div @click="onClick(item.onClick)">
|
||||
<i :class="item.icon"></i>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button
|
||||
v-else
|
||||
:type="btn.type"
|
||||
size="small"
|
||||
:color="btn.color"
|
||||
:dark="false"
|
||||
:class="btn.class"
|
||||
:plain="btn.plain"
|
||||
v-show="!btn.hidden"
|
||||
@click="onClick(btn.onClick)"
|
||||
>
|
||||
<i :class="btn.icon"></i> {{ btn.name }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-button
|
||||
type="default"
|
||||
style="padding: 0px 10px"
|
||||
size="small"
|
||||
:plain="true"
|
||||
v-if="showCustom"
|
||||
@click="showCustomModel"
|
||||
>
|
||||
<i class="el-icon-s-grid"></i>
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
size="small"
|
||||
@click="changeDropdown"
|
||||
v-if="buttons.length > maxBtnLength"
|
||||
>
|
||||
<el-button type="primary" plain size="small">
|
||||
更多<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
@click="changeDropdown(item.name)"
|
||||
:name="item.name"
|
||||
v-show="!item.hidden"
|
||||
v-for="(item, dIndex) in buttons.slice(
|
||||
maxBtnLength,
|
||||
buttons.length
|
||||
)"
|
||||
:key="dIndex"
|
||||
>
|
||||
<i :class="item.icon"></i> {{ item.name }}</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分割位置 -->
|
||||
<mes-box
|
||||
v-if="boxInit"
|
||||
v-model="boxModel"
|
||||
:title="boxOptions.title"
|
||||
:width="boxOptions.width"
|
||||
:height="boxOptions.height"
|
||||
:modal="boxOptions.modal"
|
||||
:draggable="boxOptions.draggable"
|
||||
:padding="0"
|
||||
:on-model-close="onGridModelClose"
|
||||
>
|
||||
<!--明细头部自定义组件-->
|
||||
<template #content>
|
||||
<div class="box-com">
|
||||
<component
|
||||
:is="dynamicComponent.modelHeader"
|
||||
ref="modelHeader"
|
||||
@parentCall="parentCall"
|
||||
></component>
|
||||
<!-- <div v-show="isBoxAudit" class="flow-step">
|
||||
<div v-for="(item, index) in workFlowSteps" :key="index">
|
||||
{{ item.stepName }}
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="item form-item">
|
||||
<mes-form
|
||||
ref="form"
|
||||
:editor="editor"
|
||||
:load-key="false"
|
||||
:label-width="boxOptions.labelWidth"
|
||||
:formRules="editFormOptions"
|
||||
:formFields="editFormFields"
|
||||
:select2Count="select2Count"
|
||||
></mes-form>
|
||||
</div>
|
||||
<!--明细body自定义组件-->
|
||||
<component
|
||||
:is="dynamicComponent.modelBody"
|
||||
ref="modelBody"
|
||||
@parentCall="parentCall"
|
||||
></component>
|
||||
<div
|
||||
v-show="hasDetail"
|
||||
v-if="detail.columns && detail.columns.length > 0"
|
||||
class="grid-detail table-item item"
|
||||
>
|
||||
<div class="toolbar">
|
||||
<div class="title form-text">
|
||||
<span>
|
||||
<i class="el-icon-menu" />
|
||||
{{ detail.cnName }}
|
||||
</span>
|
||||
</div>
|
||||
<!--明细表格按钮-->
|
||||
<div class="btns" v-show="!isBoxAudit">
|
||||
<el-button
|
||||
v-for="(btn, bIndex) in detailOptions.buttons"
|
||||
:key="bIndex"
|
||||
:plain="btn.plain"
|
||||
v-show="!(typeof btn.hidden == 'boolean' && btn.hidden)"
|
||||
@click="onClick(btn.onClick)"
|
||||
size="small"
|
||||
><i :class="btn.icon"></i>{{ btn.name }}</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<mes-table
|
||||
ref="detail"
|
||||
@loadBefore="loadInternalDetailTableBefore"
|
||||
@loadAfter="loadDetailTableAfter"
|
||||
@rowChange="detailRowOnChange"
|
||||
@rowClick="detailRowOnClick"
|
||||
:url="detailOptions.url"
|
||||
:load-key="false"
|
||||
:index="true"
|
||||
:tableData="detailOptions.data"
|
||||
:columns="detailOptions.columns"
|
||||
:pagination="detailOptions.pagination"
|
||||
:height="detailOptions.height"
|
||||
:single="detailOptions.single"
|
||||
:pagination-hide="false"
|
||||
:defaultLoadPage="detailOptions.load"
|
||||
:doubleEdit="detailOptions.doubleEdit"
|
||||
:beginEdit="detailOptions.beginEdit"
|
||||
:endEditBefore="detailOptions.endEditBefore"
|
||||
:endEditAfter="detailOptions.endEditAfter"
|
||||
:summary="detailOptions.summary"
|
||||
:click-edit="detailOptions.clickEdit"
|
||||
:column-index="detailOptions.columnIndex"
|
||||
:ck="detailOptions.ck"
|
||||
:text-inline="detailOptions.textInline"
|
||||
:select2Count="select2Count"
|
||||
:selectable="detailSelectable"
|
||||
></mes-table>
|
||||
</div>
|
||||
<!--明细footer自定义组件-->
|
||||
<component
|
||||
:is="dynamicComponent.modelFooter"
|
||||
ref="modelFooter"
|
||||
@parentCall="parentCall"
|
||||
></component>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div style="text-align: center;" v-show="isBoxAudit">
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
plain
|
||||
@click="onGridModelClose(false)"
|
||||
>
|
||||
<i class="el-icon-close">关闭</i>
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
v-show="auditParam.showViewButton"
|
||||
@click="auditParam.model = true"
|
||||
>
|
||||
<i class="el-icon-view">审批</i>
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-show="!isBoxAudit">
|
||||
<el-button
|
||||
v-for="(btn, bIndex) in boxButtons"
|
||||
:key="bIndex"
|
||||
:type="btn.type"
|
||||
size="small"
|
||||
:plain="btn.plain"
|
||||
v-show="!(typeof btn.hidden == 'boolean' && btn.hidden)"
|
||||
:disabled="btn.hasOwnProperty('disabled') && !!btn.disabled"
|
||||
@click="onClick(btn.onClick)"
|
||||
>
|
||||
<i :class="btn.icon"> {{ btn.name }}</i>
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
plain
|
||||
@click="onGridModelClose(false)"
|
||||
>
|
||||
<i class="el-icon-close">关闭</i>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</mes-box>
|
||||
</div>
|
||||
<!--body自定义组件-->
|
||||
<div class="grid-body">
|
||||
<component
|
||||
:is="dynamicComponent.gridBody"
|
||||
ref="gridBody"
|
||||
@parentCall="parentCall"
|
||||
></component>
|
||||
</div>
|
||||
|
||||
<!--table表格-->
|
||||
<div class="grid-container">
|
||||
<!-- 2021.05.02增加树形结构 rowKey -->
|
||||
<mes-table
|
||||
ref="table"
|
||||
:single="single"
|
||||
:rowKey="rowKey"
|
||||
:loadTreeChildren="loadTreeTableChildren"
|
||||
@loadBefore="loadTableBefore"
|
||||
@loadAfter="loadTableAfter"
|
||||
@rowChange="rowOnChange"
|
||||
@rowClick="rowOnClick"
|
||||
@rowDbClick="rowOnDbClick"
|
||||
:tableData="[]"
|
||||
:linkView="linkData"
|
||||
:columns="columns"
|
||||
:pagination="pagination"
|
||||
:height="height"
|
||||
:max-height="tableMaxHeight"
|
||||
:pagination-hide="false"
|
||||
:url="url"
|
||||
:load-key="false"
|
||||
:defaultLoadPage="load"
|
||||
:summary="summary"
|
||||
:double-edit="doubleEdit"
|
||||
:index="doubleEdit"
|
||||
:beginEdit="tableBeginEdit"
|
||||
:endEditBefore="tableEndEditBefore"
|
||||
:click-edit="true"
|
||||
:column-index="columnIndex"
|
||||
:text-inline="textInline"
|
||||
:ck="ck"
|
||||
:select2Count="select2Count"
|
||||
:selectable="selectable"
|
||||
></mes-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--footer自定义组件-->
|
||||
<component
|
||||
:is="dynamicComponent.gridFooter"
|
||||
ref="gridFooter"
|
||||
@parentCall="parentCall"
|
||||
></component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const _const = {
|
||||
EDIT: 'update',
|
||||
ADD: 'Add',
|
||||
VIEW: 'view',
|
||||
PAGE: 'getPageData',
|
||||
AUDIT: 'audit',
|
||||
DEL: 'del',
|
||||
EXPORT: 'Export', //导出操作返回加密后的路径
|
||||
DOWNLOAD: 'DownLoadFile', //导出文件
|
||||
DOWNLOADTEMPLATE: 'DownLoadTemplate', //下载导入模板
|
||||
IMPORT: 'Import', //导入(导入表的Excel功能)
|
||||
UPLOAD: 'Upload' //上传文件
|
||||
};
|
||||
import Empty from '@/components/basic/Empty.vue';
|
||||
|
||||
import MesTable from '@/components/basic/MesTable.vue';
|
||||
import MesForm from '@/components/basic/MesForm.vue';
|
||||
import {
|
||||
defineAsyncComponent,
|
||||
defineComponent,
|
||||
ref,
|
||||
shallowRef,
|
||||
toRaw
|
||||
} from 'vue';
|
||||
var vueParam = {
|
||||
components: {
|
||||
'mes-form': MesForm,
|
||||
'mes-table': MesTable,
|
||||
MesBox: defineAsyncComponent(() => import('@/components/basic/MesBox.vue')),
|
||||
QuickSearch: defineAsyncComponent(() =>
|
||||
import('@/components/basic/QuickSearch.vue')
|
||||
),
|
||||
Audit: defineAsyncComponent(() => import('@/components/basic/Audit.vue')),
|
||||
UploadExcel: defineAsyncComponent(() =>
|
||||
import('@/components/basic/UploadExcel.vue')
|
||||
),
|
||||
'custom-column': defineAsyncComponent(() =>
|
||||
import('./ViewGridCustomColumn.vue')
|
||||
),
|
||||
'mes-header': defineAsyncComponent(() => import('./../MesHeader.vue')),
|
||||
ViewGridAudit: defineAsyncComponent(() => import('./ViewGridAudit.vue'))
|
||||
},
|
||||
props: {},
|
||||
setup(props) {
|
||||
//2021.07.17调整扩展组件组件
|
||||
const dynamicCom = {
|
||||
gridHeader: Empty,
|
||||
gridBody: Empty,
|
||||
gridFooter: Empty,
|
||||
modelHeader: Empty,
|
||||
modelBody: Empty,
|
||||
modelFooter: Empty
|
||||
};
|
||||
//合并扩展组件
|
||||
if (props.extend.components) {
|
||||
for (const key in props.extend.components) {
|
||||
if (props.extend.components[key]) {
|
||||
dynamicCom[key] = toRaw(props.extend.components[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
const dynamicComponent = shallowRef(dynamicCom);
|
||||
return { dynamicComponent };
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isBoxAudit: false,
|
||||
formFieldsType: [],
|
||||
workFlowSteps: [],
|
||||
//树形结构的主键字段,如果设置值默认会开启树形table;注意rowKey字段的值必须是唯一(2021.05.02)
|
||||
rowKey: undefined,
|
||||
fiexdSearchForm: false, //2020.09.011是否固定查询表单,true查询表单将固定显示在表单的最上面
|
||||
_inited: false,
|
||||
doubleEdit: false, //2021.03.19是否开启查询界面表格双击编辑
|
||||
single: false, //表是否单选
|
||||
const: _const, //增删改查导入导出等对应的action
|
||||
boxInit: false, //新建或编辑的弹出框初化状态,默认不做初始化,点击新建或编辑才初始化弹出框
|
||||
searchBoxShow: false, //高级查询(界面查询后的下拉框点击触发)
|
||||
singleSearch: {}, //快速查询字段
|
||||
exportHref: '',
|
||||
currentAction: _const.ADD, //当新建或编辑时,记录当前的状态:如当前操作是新建
|
||||
currentRow: {}, //当前编辑或查看数据的行
|
||||
closable: false,
|
||||
boxModel: false, //弹出新建、编辑框
|
||||
width: 700, //弹出框查看表数据结构
|
||||
labelWidth: 100, //高级查询的标签宽度
|
||||
viewModel: false, //查看表结构的弹出框
|
||||
viewColumns: [], //查看表结构的列数据
|
||||
viewColumnsClone: [],
|
||||
showCustom: true, //是否显示自定义配置列按钮2022.05.27
|
||||
// viewData: [], //查看表结构信息
|
||||
maxBtnLength: 6, //界面按钮最多显示的个数,超过的数量都显示在更多中
|
||||
buttons: [], //查询界面按钮 如需要其他操作按钮,可在表对应的.js中添加(如:Sys_User.js中buttons添加其他按钮)
|
||||
splitButtons: [],
|
||||
uploadfiled: [], //上传文件图片的字段
|
||||
boxButtons: [], //弹出框按钮 如需要其他操作按钮,可在表对应的.js中添加
|
||||
dicKeys: [], //当前界面所有的下拉框字典编号及数据源
|
||||
hasKeyField: [], //有字典数据源的字段
|
||||
keyValueType: { _dinit: false },
|
||||
url: '', //界面表查询的数据源的url
|
||||
hasDetail: false, //是否有从表(明细)表格数据
|
||||
initActivated: false,
|
||||
load: true, //是否默认加载表数据
|
||||
activatedLoad: false, //页面触发actived时是否刷新页面数据
|
||||
summary: false, //查询界面table是否显示合计
|
||||
//需要从远程绑定数据源的字典编号,如果字典数据源的查询结果较多,请在onInit中将字典编号添加进来
|
||||
//只对自定sql有效
|
||||
remoteKeys: [],
|
||||
columnIndex: false, //2020.11.01是否显示行号
|
||||
ck: true, //2020.11.01是否显示checkbox
|
||||
continueAdd: false, //2021.04.11新建时是否可以连续新建操作
|
||||
continueAddName: '保存后继续添加', //2021.04.11按钮名称
|
||||
// detailUrl: "",
|
||||
detailOptions: {
|
||||
//弹出框从表(明细)对象
|
||||
//从表配置
|
||||
buttons: [], //弹出框从表表格操作按钮,目前有删除行,添加行,刷新操作,如需要其他操作按钮,可在表对应的.js中添加
|
||||
cnName: '', //从表名称
|
||||
key: '', //从表主键名
|
||||
data: [], //数据源
|
||||
columns: [], //从表列信息
|
||||
edit: true, //明细是否可以编辑
|
||||
single: false, //明细表是否单选
|
||||
load: false, //
|
||||
delKeys: [], //当编辑时删除当前明细的行主键值
|
||||
url: '', //从表加载数据的url
|
||||
pagination: { total: 0, size: 100, sortName: '' }, //从表分页配置数据
|
||||
height: 0, //默认从表高度
|
||||
textInline: true, //明细表行内容显示在一行上,如果需要换行显示,请设置为false
|
||||
doubleEdit: true, //使用双击编辑
|
||||
clickEdit: false, //是否开启点击单元格编辑,点击其他行时结束编辑
|
||||
currentReadonly: false, //当前用户没有编辑或新建权限时,表单只读(可用于判断用户是否有编辑或新建权限)
|
||||
//开启编辑时
|
||||
beginEdit: (row, column, index) => {
|
||||
return true;
|
||||
},
|
||||
//结束编辑前
|
||||
endEditBefore: (row, column, index) => {
|
||||
return true;
|
||||
},
|
||||
//结束编辑后
|
||||
endEditAfter: (row, column, index) => {
|
||||
return true;
|
||||
},
|
||||
columnIndex: false, //2020.11.01明细是否显示行号
|
||||
ck: true //2020.11.01明细是否显示checkbox
|
||||
},
|
||||
auditParam: {
|
||||
//审核对象
|
||||
rows: 0, //当前选中审核的行数
|
||||
model: false, //审核弹出框
|
||||
value: -1, //审核结果
|
||||
status: -1,
|
||||
reason: '', //审核原因
|
||||
height: 500,
|
||||
showViewButton: true,
|
||||
auditHis: [],
|
||||
showAction: false, //是否显示审批操作(当前节点为用户审批时显示)
|
||||
//审核选项(可自行再添加)
|
||||
data: [
|
||||
{ text: '通过', value: 1 },
|
||||
{ text: '拒绝', value: 2 },
|
||||
{ text: '驳回', value: 3 }
|
||||
]
|
||||
},
|
||||
upload: {
|
||||
//导入上传excel对象
|
||||
excel: false, //导入的弹出框是否显示
|
||||
url: '', //导入的路径,如果没有值,则不渲染导入功能
|
||||
template: {
|
||||
//下载模板对象
|
||||
url: '', //下载模板路径
|
||||
fileName: '' //模板下载的中文名
|
||||
},
|
||||
init: false //是否有导入权限,有才渲染导入组件
|
||||
},
|
||||
height: 0, //表高度
|
||||
tableHeight: 0, //查询页面table的高度
|
||||
tableMaxHeight: 0, //查询页面table的最大高度
|
||||
textInline: true, //table内容超出后是否不换行2020.01.16
|
||||
pagination: { total: 0, size: 30, sortName: '' }, //从分页配置数据
|
||||
boxOptions: {
|
||||
title: '', //弹出框显示的标题2022.08.01
|
||||
saveClose: true,
|
||||
labelWidth: 100,
|
||||
height: 0,
|
||||
width: 0,
|
||||
summary: false, //弹出框明细table是否显示合计
|
||||
draggable: true, //2022.09.12弹出框拖动功能
|
||||
modal: true //2022.09.12弹出框背景遮罩层
|
||||
}, //saveClose新建或编辑成功后是否关闭弹出框//弹出框的标签宽度labelWidth
|
||||
editor: {
|
||||
uploadImgUrl: '', //上传路径
|
||||
upload: null //上传方法
|
||||
},
|
||||
numberFields: [],
|
||||
//2022.09.26增加自定义导出文件名
|
||||
downloadFileName: null,
|
||||
select2Count: 500 //超出500数量显示select2组件
|
||||
};
|
||||
},
|
||||
methods: {},
|
||||
activated() {
|
||||
this.initFlowQuery();
|
||||
//2020.06.25增加activated方法
|
||||
this.onActivated && this.onActivated();
|
||||
if (!this._inited) {
|
||||
this._inited = true;
|
||||
return;
|
||||
}
|
||||
if (this.activatedLoad) {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.mounted();
|
||||
// this.$refs.searchForm.forEach()
|
||||
},
|
||||
unmounted() {
|
||||
this.destroyed();
|
||||
},
|
||||
created: function() {
|
||||
//合并自定义业务扩展方法
|
||||
Object.assign(this, this.extend.methods);
|
||||
//如果没有指定排序字段,则用主键作为默认排序字段
|
||||
this.pagination.sortName = this.table.sortName || this.table.key;
|
||||
this.initBoxButtons(); //初始化弹出框与明细表格按钮
|
||||
this.initAuditColumn();
|
||||
this.onInit(); //初始化前,如果需要做其他处理在扩展方法中覆盖此方法
|
||||
this.getButtons();
|
||||
//初始化自定义表格列
|
||||
this.initViewColumns();
|
||||
//初始编辑框等数据
|
||||
this.initBoxHeightWidth();
|
||||
this.initDicKeys(); //初始下框数据源
|
||||
this.onInited(); //初始化后,如果需要做其他处理在扩展方法中覆盖此方法
|
||||
},
|
||||
beforeUpdate: function() {},
|
||||
updated: function() {}
|
||||
};
|
||||
|
||||
import props from './props.js';
|
||||
import methods from './methods.js';
|
||||
|
||||
//合并属性
|
||||
vueParam.props = Object.assign(vueParam.props, props);
|
||||
//合并方法
|
||||
vueParam.methods = Object.assign(
|
||||
vueParam.methods,
|
||||
methods,
|
||||
props.extend.methods
|
||||
);
|
||||
export default defineComponent(vueParam);
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import './ViewGrid.less';
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.btn-group ::v-deep(.ivu-select-dropdown) {
|
||||
padding: 0px !important;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.btn-group ::v-deep(.ivu-select-dropdown .ivu-dropdown-menu) {
|
||||
min-width: 100px;
|
||||
right: -2px;
|
||||
position: absolute;
|
||||
background: white;
|
||||
width: 130px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #e7e5e5;
|
||||
}
|
||||
|
||||
.vertical-center-modal ::v-deep(.srcoll-content) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.view-model-content {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.grid-detail ::v-deep(.v-table .el-table__header th) {
|
||||
height: 44px;
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.grid-search {
|
||||
position: relative;
|
||||
|
||||
.search-box {
|
||||
background: #fefefe;
|
||||
margin-top: 33px;
|
||||
border: 1px solid #eae8e8;
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
padding: 25px 20px;
|
||||
padding-bottom: 0;
|
||||
border-top: 0;
|
||||
box-shadow: 0 7px 18px -12px #bdc0bb;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
366
src/components/basic/ViewGrid/ViewGridAudit.vue
Normal file
@@ -0,0 +1,366 @@
|
||||
<template>
|
||||
<mes-box :footer="false" v-model="model" :height="height" :width="width" :padding="0" :lazy="true" title="审核">
|
||||
<div class="audit-model-content" :style="{ height: height - 70 + 'px' }">
|
||||
<el-radio-group v-show="hasFlow" style="padding-left: 15px;" v-model="activeName" class="ml-4">
|
||||
<el-radio label="audit" size="large">审核</el-radio>
|
||||
<el-radio label="log" size="large">审核记录</el-radio>
|
||||
</el-radio-group>
|
||||
<div v-show="activeName == 'audit' || !hasFlow" class="audit-content">
|
||||
<div class="fx-left" v-if="hasFlow">
|
||||
<div class="v-steps">
|
||||
<div v-for="(item, index) in workFlowSteps" :key="index">
|
||||
<div class="step-item" v-if="item.stepAttrType == 'start'">
|
||||
<div class="left-item">
|
||||
<div>流程开始</div>
|
||||
<div class="left-date">{{ item.createDate }}</div>
|
||||
</div>
|
||||
<div class="right-item">
|
||||
<div class="step-line"></div>
|
||||
<i class="step-circle"></i>
|
||||
<div class="step-title">
|
||||
{{ item.stepName }}
|
||||
</div>
|
||||
<div class="step-text">发起人:{{ item.creator }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step-item" v-else-if="item.stepAttrType == 'end'">
|
||||
<div class="left-item">
|
||||
<div>流程结束</div>
|
||||
</div>
|
||||
<div class="right-item">
|
||||
<div class="step-line"></div>
|
||||
<i class="step-circle"></i>
|
||||
<div class="step-title">
|
||||
{{ item.stepName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else :class="{ 'step-current': item.isCurrent }" class="step-item">
|
||||
<div class="left-item">
|
||||
<div>审批时间</div>
|
||||
<div class="left-date">{{ item.auditDate || '待审批' }}</div>
|
||||
</div>
|
||||
<div class="right-item">
|
||||
<div class="step-line"></div>
|
||||
<i class="step-circle"></i>
|
||||
<div class="step-title">
|
||||
{{ item.stepName }}
|
||||
</div>
|
||||
<div class="step-text">审批人:{{ item.auditor }}</div>
|
||||
<div class="step-text">
|
||||
状 态: {{ getAuditStatus(item.auditStatus) }}
|
||||
</div>
|
||||
<div class="step-text">备 注: {{ item.remark || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fx-right" :style="{ width: !hasFlow ? '100%' : '400px' }" v-if="isCurrentUser || !hasFlow">
|
||||
|
||||
<div v-if="!hasFlow">
|
||||
<el-alert :title="'当前选中【' +rowLen + '】条记录待审核..'" type="success" :closable="false"/>
|
||||
</div>
|
||||
<div class="rd">
|
||||
<span>审批:</span>
|
||||
<el-radio-group style="margin-left:15px" v-model="auditParam.value">
|
||||
<el-radio v-for="item in auditParam.data" :key="item.value" :label="item.value">
|
||||
<span>{{ item.text }}</span>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<el-input style="padding-top: 10px;" v-model="auditParam.reason" type="textarea"
|
||||
:autosize="{ minRows: 4, maxRows: 10 }" placeholder="请输入备注..."></el-input>
|
||||
<div class="btn">
|
||||
<el-button type="primary" @click="auditClick" icon="Check">审批</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="activeName == 'log'">
|
||||
<mes-table :tableData="tableData" :columns="columns" :height="370" :pagination-hide="true" :load-key="false"
|
||||
:text-inline="false" :ck="false"></mes-table>
|
||||
</div>
|
||||
</div>
|
||||
</mes-box>
|
||||
</template>
|
||||
<script>
|
||||
import MesTable from '@/components/basic/MesTable.vue';
|
||||
import MesBox from '@/components/basic/MesBox.vue';
|
||||
import http from '@/../src/api/http.js';
|
||||
import { defineComponent, ref, reactive, getCurrentInstance } from 'vue';
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MesTable,
|
||||
MesBox
|
||||
},
|
||||
props: {
|
||||
option: { //生成vue文件的table参数
|
||||
type: Object,
|
||||
default: {
|
||||
key: '',
|
||||
cnName: '',
|
||||
name: '',
|
||||
url: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const height = ref(500);
|
||||
const width = ref(820);
|
||||
const model = ref(false)
|
||||
const workFlowSteps = reactive([]);
|
||||
|
||||
const hasFlow = ref(false)
|
||||
|
||||
const auditParam = reactive({
|
||||
//审核对象
|
||||
rows: 0, //当前选中审核的行数
|
||||
model: false, //审核弹出框
|
||||
value: -1, //审核结果
|
||||
reason: '', //审核原因
|
||||
//审核选项(main.js里面可以添加其他选项)
|
||||
data: []
|
||||
})
|
||||
const { proxy } = getCurrentInstance();
|
||||
auditParam.data = proxy.$global.audit.data;
|
||||
const tableData = reactive([]);
|
||||
const columns = reactive([
|
||||
{ title: '节点', field: 'stepName', width: 100 },
|
||||
{ title: '审批人', field: 'auditor', width: 80 },
|
||||
{ title: '审批结果', field: 'auditStatus', width: 70, bind: { data: [] } },
|
||||
{ title: '审批时间', field: 'auditDate', width: 145 },
|
||||
{ title: '备注', field: 'remark', width: 120 }
|
||||
]);
|
||||
|
||||
const isCurrentUser = ref(null);
|
||||
const activeName = ref('audit')
|
||||
|
||||
const auditDic = reactive([]);
|
||||
const getAuditStatus = (key) => {
|
||||
return (auditDic.find(x => { return x.key === key + '' }) || { value: key }).value;
|
||||
}
|
||||
const rowLen=ref(0)
|
||||
let currentRows = []
|
||||
const getAuditInfo = () => {
|
||||
const table = props.option.url.replaceAll('/', '');
|
||||
const url = `api/Sys_WorkFlow/getSteps?tableName=${table}`
|
||||
let ids = currentRows.map(x => { return x[props.option.key] });
|
||||
// ['498043c1-fbd0-4a35-a870-523823912a9b']
|
||||
http.post(url, ids, true).then(result => {
|
||||
if (!result.status) {
|
||||
proxy.$message.error(result.message);
|
||||
return;
|
||||
}
|
||||
|
||||
hasFlow.value = !!(result.list || []).length;
|
||||
if (!hasFlow.value) {
|
||||
|
||||
let auditStatus = Object.keys(currentRows[0]).find(x => { return x.toLowerCase() === 'auditstatus' });
|
||||
|
||||
let checkStatus = currentRows.every((x) => {
|
||||
return proxy.$global.audit.status.some(c => { return c === x[auditStatus] || !x[auditStatus] })
|
||||
});
|
||||
if (!checkStatus) {
|
||||
proxy.$message.error('只能选择待审批或审核中的数据');
|
||||
return;
|
||||
}
|
||||
rowLen.value=currentRows.length;
|
||||
model.value = true;
|
||||
width.value = 430;
|
||||
height.value = 330;
|
||||
isCurrentUser.value = true;
|
||||
//没有审批流程的数据只显示
|
||||
return;
|
||||
}
|
||||
model.value = true;
|
||||
height.value = document.body.clientHeight*0.9;
|
||||
width.value = 820;
|
||||
if (!auditDic.length) {
|
||||
auditDic.push(...(result.auditDic || []))
|
||||
columns.forEach(item => {
|
||||
if (item.field == 'auditStatus') {
|
||||
item.bind.data = auditDic;
|
||||
}
|
||||
})
|
||||
}
|
||||
isCurrentUser.value = result.list.some(x => { return x.isCurrentUser })
|
||||
workFlowSteps.length = 0;
|
||||
workFlowSteps.push(...result.list);
|
||||
tableData.length = 0;
|
||||
tableData.push(...result.log)
|
||||
})
|
||||
}
|
||||
//
|
||||
|
||||
const auditClick = () => {
|
||||
if (auditParam.value == -1) {
|
||||
proxy.$message.error('请选择审批项');
|
||||
return;
|
||||
}
|
||||
emit("auditClick", auditParam, currentRows, (result) => {
|
||||
if (result.status) {
|
||||
model.value = false;
|
||||
tableData.length = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const open = (rows) => {
|
||||
currentRows = rows;
|
||||
activeName.value = 'audit'
|
||||
auditParam.reason = '';
|
||||
auditParam.value = -1;
|
||||
getAuditInfo();
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
height,
|
||||
width,
|
||||
model,
|
||||
workFlowSteps,
|
||||
getAuditInfo,
|
||||
getAuditStatus,
|
||||
activeName,
|
||||
reactive,
|
||||
tableData,
|
||||
auditParam,
|
||||
auditClick,
|
||||
open,
|
||||
isCurrentUser,
|
||||
hasFlow,
|
||||
rowLen
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.audit-model-content {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.step-item {
|
||||
background: #fff;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.left-item {
|
||||
min-width: 180px;
|
||||
text-align: right;
|
||||
padding-right: 25px;
|
||||
padding-top: 8px;
|
||||
|
||||
.left-date {
|
||||
font-size: 13px;
|
||||
padding-top: 7px;
|
||||
color: #6c6c6c;
|
||||
}
|
||||
}
|
||||
|
||||
.right-item {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
border-bottom: 1px solid #f3f3f3;
|
||||
padding: 5px 0 5px 5px;
|
||||
}
|
||||
|
||||
.left-item,
|
||||
.right-item {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.right-item:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.step-line {
|
||||
top: 16px;
|
||||
left: -10px;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
background-color: #ebedf0;
|
||||
}
|
||||
|
||||
.step-circle {
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
left: -9px;
|
||||
z-index: 2;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
background-color: #a1a1a1;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.right-item::before {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.step-content {
|
||||
padding-top: 2px;
|
||||
font-size: 14px;
|
||||
color: #828282;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-weight: bold;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
.step-text {
|
||||
font-size: 13px;
|
||||
color: #999999;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.step-current {
|
||||
* {
|
||||
color: #2f95ff !important;
|
||||
}
|
||||
|
||||
.step-circle {
|
||||
background: #2f95ff !important;
|
||||
}
|
||||
|
||||
// border-radius: 5px;
|
||||
// border: 1px solid #d6eaff;
|
||||
font-size: 13px;
|
||||
padding-top: 6px;
|
||||
// background-color: #eff7ffd9;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.audit-content {
|
||||
// background: #f9f9f9;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
|
||||
.fx-left {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
|
||||
.rd {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.fx-right {
|
||||
// width: 400px;
|
||||
|
||||
.btn {
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
145
src/components/basic/ViewGrid/ViewGridCustomColumn.js
Normal file
@@ -0,0 +1,145 @@
|
||||
export default {
|
||||
initViewColumns(isReset) {
|
||||
//初始化自定列配置
|
||||
if (isReset) {
|
||||
this.resetViewColumns();
|
||||
}
|
||||
if (!this.orginColumnFields) {
|
||||
this.orginColumnFields = this.columns.map((c) => {
|
||||
return c.field;
|
||||
});
|
||||
}
|
||||
this.viewColumns = this.columns
|
||||
.filter((c) => {
|
||||
return !c.hidden && !c.render;
|
||||
})
|
||||
.map((c) => {
|
||||
return { field: c.field, title: c.title, show: !c.hidden };
|
||||
});
|
||||
if (isReset) {
|
||||
return;
|
||||
}
|
||||
this.getCacheViewColumn();
|
||||
},
|
||||
getViewCacheKey(){
|
||||
return 'custom:column'+this.table.name;
|
||||
},
|
||||
getCacheViewColumn() {
|
||||
try {
|
||||
let columns = localStorage.getItem(this.getViewCacheKey());
|
||||
if (!columns) return;
|
||||
columns = JSON.parse(columns);
|
||||
let sortTableColumns = [];
|
||||
//弹出框的列
|
||||
let _viewColumns = [];
|
||||
columns.forEach((column) => {
|
||||
let _column = this.viewColumns.find((c) => {
|
||||
return c.field == column.field;
|
||||
});
|
||||
if (_column) {
|
||||
_column.show = column.show;
|
||||
_viewColumns.push(_column);
|
||||
}
|
||||
let tableColumn = this.columns.find((c) => {
|
||||
return c.field == column.field;
|
||||
});
|
||||
if (tableColumn) {
|
||||
tableColumn.hidden = !column.show;
|
||||
sortTableColumns.push(tableColumn);
|
||||
}
|
||||
});
|
||||
//重新排版弹出框自定义列
|
||||
let otherColumns = this.viewColumns.filter((c) => {
|
||||
return !_viewColumns.some((s) => {
|
||||
return c.field == s.field;
|
||||
});
|
||||
});
|
||||
//重新排版弹出框自定义列
|
||||
_viewColumns.push(...otherColumns);
|
||||
this.viewColumns.splice(0);
|
||||
this.viewColumns.push(..._viewColumns);
|
||||
|
||||
this.sortViewColumns(sortTableColumns);
|
||||
} catch (error) {
|
||||
console.log('设置默认自定义列异常:' + error.message);
|
||||
}
|
||||
},
|
||||
sortViewColumns(sortColumns) {
|
||||
if (sortColumns.length) {
|
||||
let hiddenColumns = this.columns.filter((c) => {
|
||||
return !sortColumns.some((s) => {
|
||||
return c.field == s.field;
|
||||
});
|
||||
});
|
||||
sortColumns.push(...hiddenColumns);
|
||||
this.columns.splice(0);
|
||||
this.columns.push(...sortColumns);
|
||||
}
|
||||
},
|
||||
resetViewColumns() {
|
||||
if (!this.orginColumnFields) {
|
||||
return;
|
||||
}
|
||||
let _columns = [];
|
||||
this.orginColumnFields.forEach((x) => {
|
||||
_columns.push(
|
||||
this.columns.find((c) => {
|
||||
return c.field == x;
|
||||
})
|
||||
);
|
||||
});
|
||||
let otherColumns = this.columns.filter((c) => {
|
||||
return !this.orginColumnFields.some((s) => {
|
||||
return c.field == s;
|
||||
});
|
||||
});
|
||||
_columns.push(...otherColumns);
|
||||
this.columns.splice(0);
|
||||
this.columns.push(..._columns);
|
||||
},
|
||||
showCustomModel() {
|
||||
if (!this.viewColumns.length) {
|
||||
this.initViewColumns();
|
||||
}
|
||||
this.viewColumnsClone = JSON.parse(JSON.stringify(this.viewColumns));
|
||||
this.viewModel = true;
|
||||
},
|
||||
closeCustomModel() {
|
||||
this.viewModel=false;
|
||||
if (this.checkColumnChanged()) {
|
||||
this.viewColumns = JSON.parse(JSON.stringify(this.viewColumnsClone));
|
||||
}
|
||||
},
|
||||
checkColumnChanged() {
|
||||
return (
|
||||
JSON.stringify(this.viewColumns) != JSON.stringify(this.viewColumnsClone)
|
||||
);
|
||||
},
|
||||
saveColumnConfig() {
|
||||
let hasShowColumn = this.viewColumns.some((x) => {
|
||||
return x.show;
|
||||
});
|
||||
if (!hasShowColumn) {
|
||||
return this.$message.error('至少选择一列显示');
|
||||
}
|
||||
this.viewModel = false;
|
||||
if (this.checkColumnChanged()) {
|
||||
let sortColumns = [];
|
||||
this.viewColumns.forEach((column) => {
|
||||
let _column = this.columns.find((c) => {
|
||||
return c.field == column.field;
|
||||
});
|
||||
if (_column) {
|
||||
_column.hidden = !column.show;
|
||||
sortColumns.push(_column);
|
||||
}
|
||||
});
|
||||
this.sortViewColumns(sortColumns);
|
||||
}
|
||||
try {
|
||||
localStorage.setItem(this.getViewCacheKey(), JSON.stringify(this.viewColumns));
|
||||
} catch (error) {
|
||||
console.log('获取自定义列异常:' + error.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
95
src/components/basic/ViewGrid/ViewGridCustomColumn.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<el-alert
|
||||
title="拖动列名可调整表格列显示顺序"
|
||||
type="success"
|
||||
:show-icon="false"
|
||||
>
|
||||
</el-alert>
|
||||
<div class="view-column view-column-title">
|
||||
<div class="view-column-index">#</div>
|
||||
<div class="view-column-left">列名</div>
|
||||
<div class="view-column-right">是否显示</div>
|
||||
</div>
|
||||
<draggable
|
||||
class="list-group"
|
||||
tag="transition-group"
|
||||
:component-data="componentData"
|
||||
:list="viewColumns"
|
||||
v-bind="dragOptions"
|
||||
item-key="order"
|
||||
>
|
||||
<transition-group class="drag-center-item">
|
||||
<div
|
||||
class="view-column"
|
||||
v-for="(column, index) in viewColumns"
|
||||
:key="index"
|
||||
>
|
||||
<div class="view-column-index">{{ index + 1 }}</div>
|
||||
<div class="view-column-left">{{ column.title }}</div>
|
||||
<div class="view-column-right">
|
||||
<el-checkbox v-model="column.show">
|
||||
<div style="height: 100%; width: 250px"></div
|
||||
></el-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</template>
|
||||
<script>
|
||||
import { VueDraggableNext } from 'vue-draggable-next';
|
||||
import { defineComponent, ref, reactive } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
viewColumns: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
draggable: VueDraggableNext
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
setup(props, context) {
|
||||
const dragOptions = reactive({
|
||||
animation: 200,
|
||||
group: 'description',
|
||||
disabled: false,
|
||||
ghostClass: 'ghost'
|
||||
});
|
||||
const componentData = reactive({
|
||||
tag: 'ul',
|
||||
type: 'transition-group'
|
||||
});
|
||||
return { dragOptions, componentData };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.view-column {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #f3f3f3;
|
||||
.view-column-index {
|
||||
width: 50px;
|
||||
}
|
||||
.view-column-left {
|
||||
width: 120px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.view-column-right {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.view-column-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
.view-column:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
97
src/components/basic/ViewGrid/detailMethods.js
Normal file
@@ -0,0 +1,97 @@
|
||||
//从表方法
|
||||
let detailMethods = {
|
||||
//查询从表前先做内部处理
|
||||
loadInternalDetailTableBefore(param, callBack) {
|
||||
//加载明细表数据之前,需要设定查询的主表的ID
|
||||
//每次只要加载明细表格数据就重置删除明细的值
|
||||
if (this.detailOptions.delKeys.length > 0) {
|
||||
this.detailOptions.delKeys = [];
|
||||
}
|
||||
let key = this.table.key;
|
||||
if (this.currentRow && this.currentRow.hasOwnProperty(key)) {
|
||||
param.value = this.currentRow[key];
|
||||
}
|
||||
return this.loadDetailTableBefore(param, callBack);
|
||||
},
|
||||
detailRowOnChange(row) {
|
||||
this.detailRowChange(row);
|
||||
},
|
||||
detailRowChange(row) {
|
||||
//checkbox选中行事件
|
||||
},
|
||||
detailRowOnClick({ row, column, event }) {
|
||||
//明细表点击行事件2020.11.07
|
||||
this.detailRowClick({ row, column, event });
|
||||
},
|
||||
detailRowClick({ row, column, event }) {},
|
||||
resetDetailTable(row) {
|
||||
//编辑和查看明细时重置从表数据
|
||||
if (!this.detailOptions.columns || this.detailOptions.columns.length == 0) {
|
||||
return;
|
||||
}
|
||||
let key = this.table.key;
|
||||
let query = { value: row ? row[key] : this.currentRow[key] };
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.detail) {
|
||||
this.$refs.detail.reset();
|
||||
this.$refs.detail.load(query);
|
||||
}
|
||||
});
|
||||
},
|
||||
//从后面加载从表数据
|
||||
refreshRow() {
|
||||
this.resetDetailTable();
|
||||
},
|
||||
addRow() {
|
||||
this.$refs.detail.addRow({});
|
||||
this.updateDetailTableSummaryTotal();
|
||||
},
|
||||
delRow() {
|
||||
let rows = this.$refs.detail.getSelected();
|
||||
if (!rows || rows.length == 0) {
|
||||
return this.$message.error('请选择要删除的行!');
|
||||
}
|
||||
if (!this.delDetailRow(rows)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let tigger = false;
|
||||
this.$confirm('确认要删除选择的数据吗?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
center: true
|
||||
}).then(() => {
|
||||
if (tigger) return;
|
||||
tigger = true;
|
||||
rows = this.$refs.detail.delRow();
|
||||
let key = this.detailOptions.key;
|
||||
//记录删除的行数据
|
||||
rows.forEach((x) => {
|
||||
if (x.hasOwnProperty(key) && x[key]) {
|
||||
this.detailOptions.delKeys.push(x[key]);
|
||||
}
|
||||
});
|
||||
this.updateDetailTableSummaryTotal();
|
||||
});
|
||||
},
|
||||
updateDetailTableSummaryTotal() {
|
||||
//2021.09.25增加明细表删除、修改时重新计算行数与汇总
|
||||
//2021.12.12增加明细表判断(强制刷新合计时会用到)
|
||||
if (!this.$refs.detail) {
|
||||
return;
|
||||
}
|
||||
//删除或新增行时重新设置显示的总行数
|
||||
this.$refs.detail.paginations.total = this.$refs.detail.rowData.length;
|
||||
//重新设置合计
|
||||
if (this.$refs.detail.summary) {
|
||||
this.$refs.detail.columns.forEach((column) => {
|
||||
if (column.summary) {
|
||||
this.$refs.detail.getInputSummaries(null, null, null, column);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default detailMethods;
|
||||
7
src/components/basic/ViewGrid/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import Grid from './ViewGrid.vue'
|
||||
const ViewGrid = {
|
||||
install: function (app) {
|
||||
app.component('ViewGrid', Grid)
|
||||
}
|
||||
}
|
||||
export default ViewGrid
|
||||
1683
src/components/basic/ViewGrid/methods.js
Normal file
55
src/components/basic/ViewGrid/props.js
Normal file
@@ -0,0 +1,55 @@
|
||||
let props = {
|
||||
columns: {//当前表的配置信息
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
detail: {//从表明细配置
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
columns: [],//从表列
|
||||
sortName: ""//从表排序字段
|
||||
};
|
||||
}
|
||||
},
|
||||
editFormFields: {//新建、编辑字段(key/value)
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
editFormOptions: {//新建、编辑配置信息
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
searchFormFields: {//查询字段(key/value)
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
searchFormOptions: {//查询配置信息(key/value)
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
table: {//表的配置信息:主键、排序等
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
extend: {//表的扩展方法与组件都合并到此属性中
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default props;
|
||||
106
src/components/basic/ViewGrid/serviceFilter.js
Normal file
@@ -0,0 +1,106 @@
|
||||
|
||||
|
||||
let serviceFilter = {
|
||||
onInit () { //对应created
|
||||
console.log('Create执行前')
|
||||
},
|
||||
onInited () { //对应created,在onInit与onInited中间会初始化界面数据对象
|
||||
console.log('Create执行后')
|
||||
},
|
||||
mounted () {
|
||||
console.log('mounted');
|
||||
},
|
||||
searchBefore (param) { //查询ViewGird表数据前,param查询参数
|
||||
// console.log('表' + this.table.cnName + '触发loadTableBefore');
|
||||
return true;
|
||||
},
|
||||
//2020.10.30增加查询后返回所有的查询信息
|
||||
searchAfter (param, result) { //查询ViewGird表数据后param查询参数,result回返查询的结果
|
||||
// console.log('表' + this.table.cnName + '触发loadTableAfter');
|
||||
return true;
|
||||
},
|
||||
searchDetailBefore (param) {//查询从表表数据前,param查询参数
|
||||
//console.log(this.detailOptions.cnName + '触发loadDetailTableBefore');
|
||||
return true;
|
||||
},
|
||||
searchDetailAfter (param, data) {//查询从表后param查询参数,result回返查询的结果
|
||||
// console.log(this.detailOptions.cnName + '触发loadDetailTableAfter');
|
||||
return true;
|
||||
},
|
||||
delBefore (ids, rows) { //查询界面的表删除前 ids为删除的id数组,,rows删除的行
|
||||
return true;
|
||||
},
|
||||
delAfter (result) {//查询界面的表删除后
|
||||
return true;
|
||||
},
|
||||
delDetailRow (rows) { //弹出框删除明细表的行数据(只是对table操作,并没有操作后台)
|
||||
return true;
|
||||
},
|
||||
addBefore (formData) { //新建保存前formData为对象,包括明细表
|
||||
return true;
|
||||
},
|
||||
async addBeforeAsync (formData) { //异步处理,功能同上(2020.12.06)
|
||||
return true;
|
||||
},
|
||||
addAfter (result) {//新建保存后result返回的状态及表单对象
|
||||
return true;
|
||||
},
|
||||
updateBefore (formData) { //编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
async updateBeforeAsync (formData) { //异步处理,功能同上(2020.12.06)
|
||||
return true;
|
||||
},
|
||||
updateAfter (result) {//编辑保存后result返回的状态及表单对象
|
||||
return true;
|
||||
},
|
||||
auditBefore (ids, rows) {//审核前
|
||||
return true;
|
||||
},
|
||||
auditAfter (result, rows) {// 审核后
|
||||
return true;
|
||||
},
|
||||
resetAddFormBefore () { //重置新建表单前的内容
|
||||
return true;
|
||||
},
|
||||
resetAddFormAfter () { //重置新建表单后的内容
|
||||
return true;
|
||||
},
|
||||
resetUpdateFormBefore () { //重置编辑表单前的内容
|
||||
return true;
|
||||
},
|
||||
resetUpdateFormAfter () { //重置编辑表单后的内容
|
||||
return true;
|
||||
},
|
||||
modelOpenBefore (row) { //点击编辑/新建按钮弹出框前,可以在此处写逻辑,如,从后台获取数据
|
||||
|
||||
},
|
||||
modelOpenAfter (row) { //点击编辑/新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
|
||||
},
|
||||
importAfter (data) { //导入excel后刷新table表格数据
|
||||
this.search();
|
||||
},
|
||||
//2020.10.31添加导入前的方法
|
||||
importExcelBefore (formData) { //导入excel导入前
|
||||
//往formData写一些其他参数提交到后台,
|
||||
// formData.append("val2", "xxx");
|
||||
//后台按下面方法获取请求的参数
|
||||
// Core.Utilities.HttpContext.Current.Request("val2");
|
||||
return true;
|
||||
},
|
||||
reloadDicSource () { //重新加载字典绑定的数据源
|
||||
this.initDicKeys();
|
||||
},
|
||||
exportBefore (param) { //2020.06.25增加导出前处理
|
||||
return true;
|
||||
},
|
||||
onModelClose(iconClick){
|
||||
//iconClick=true为点击左中上角X触发的关闭事件
|
||||
//如果返回 false不会关闭弹出框
|
||||
//return false;
|
||||
this.boxModel=false;
|
||||
}
|
||||
|
||||
}
|
||||
export default serviceFilter;
|
||||
13
src/components/editor/KindEditor.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
154
src/components/editor/MesWangEditor.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<div class="hello" ref="mesWangEditor"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import E from "wangeditor";
|
||||
export default {
|
||||
props: {
|
||||
url: {
|
||||
//上传图片的url
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
upload: {
|
||||
//上传方法
|
||||
type: Function,
|
||||
// (file, insertImgFn) => {}
|
||||
default: null,
|
||||
},
|
||||
uploadCount: {
|
||||
//最多可以上传(图片)的数量
|
||||
type: Number,
|
||||
default: 3,
|
||||
},
|
||||
modelValue: "",
|
||||
width: {
|
||||
type: String,
|
||||
default: "100%",
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 250,
|
||||
},
|
||||
minWidth: {
|
||||
type: Number,
|
||||
default: 650,
|
||||
},
|
||||
minHeight: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
},
|
||||
name: "wang-editor",
|
||||
data() {
|
||||
return {
|
||||
lastHtml: "",
|
||||
change: false,
|
||||
editor: null,
|
||||
init: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
modelValue(newVal, val) {
|
||||
if (
|
||||
(newVal !== val &&
|
||||
this.lastHtml !== "" &&
|
||||
val === this.lastHtml &&
|
||||
this.editor.txt.html() === this.lastHtml) ||
|
||||
this.editor.txt.html() === ""
|
||||
) {
|
||||
this.editor.txt.html(newVal);
|
||||
}
|
||||
this.lastHtml = newVal;
|
||||
},
|
||||
},
|
||||
destroyed() {
|
||||
this.editor = null;
|
||||
},
|
||||
mounted() {
|
||||
this.editor = null;
|
||||
let editor = new E(this.$refs.mesWangEditor);
|
||||
this.editor = editor;
|
||||
let $this = this;
|
||||
editor.config.zIndex = 500;
|
||||
editor.config.height = this.height;
|
||||
editor.config.onchange = (html) => {
|
||||
if (!this.init && this.lastHtml === "") {
|
||||
this.lastHtml = html;
|
||||
this.init = true;
|
||||
}
|
||||
this.$emit("update:modelValue", html);
|
||||
};
|
||||
// editor.config.uploadFileName = "fileInput";
|
||||
// //设置header
|
||||
// editor.config.uploadImgHeaders = {
|
||||
// Accept: "application/json",
|
||||
// Authorization: this.$store.getters.getToken(),
|
||||
// };
|
||||
//上传地址
|
||||
editor.config.uploadImgServer = this.http.ipAddress + this.url;
|
||||
// console.log(editor.config.uploadImgServer);
|
||||
editor.config.customUploadImg = function (resultFiles, insertImgFn) {
|
||||
// 自定义上传
|
||||
if ($this.upload) {
|
||||
console.log("调用自定义的上传方法");
|
||||
console.log(resultFiles);
|
||||
// resultFiles 是 input 中选中的文件列表
|
||||
// insertImgFn 是获取图片 url 后,插入到编辑器的方法
|
||||
//有可能会上传多张图片,上传多张图片就需要进行遍历
|
||||
resultFiles.map((item) => {
|
||||
// _this.getUploadImg(item, insertImgFn);
|
||||
$this.upload(item, insertImgFn);
|
||||
});
|
||||
} else {
|
||||
let formData = new FormData();
|
||||
let nameArr = [];
|
||||
resultFiles.forEach(function (file) {
|
||||
formData.append("fileInput", file, file.name);
|
||||
nameArr.push(file.name);
|
||||
});
|
||||
if (!$this.url) {
|
||||
$this.$message.error("未配置url");
|
||||
return;
|
||||
}
|
||||
$this.http.post($this.url, formData, true).then((x) => {
|
||||
if (!x.status) {
|
||||
return $this.$message.error(x.message);
|
||||
}
|
||||
nameArr.forEach(m=>{
|
||||
insertImgFn($this.http.ipAddress + x.data + m);
|
||||
})
|
||||
// let imgs = nameArr
|
||||
// .map((m) => {
|
||||
// return $this.http.ipAddress + x.data + m;
|
||||
// })
|
||||
// .join(",");
|
||||
// insertImgFn(imgs);
|
||||
});
|
||||
}
|
||||
};
|
||||
editor.create();
|
||||
editor.txt.html(this.modelValue);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
h1,
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
}
|
||||
a {
|
||||
color: #42b983;
|
||||
}
|
||||
</style>
|
||||
19
src/components/redirect/401.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div style="height: 100%">
|
||||
<redirect-error :text="text" message="请求确认是否配置权限" :errorNumber="errorNumber"></redirect-error>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import RedirectError from "./RedirectError";
|
||||
export default {
|
||||
components: {
|
||||
RedirectError,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
errorNumber: "401",
|
||||
text: "抱歉,您没有权限进行此操作~",
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
21
src/components/redirect/404.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<div style="height:100%;">
|
||||
<redirect-error :text="text" :errorNumber="errorNumber"></redirect-error>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import RedirectError from "./RedirectError";
|
||||
export default {
|
||||
components: {
|
||||
RedirectError
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
errorNumber:'404',
|
||||
text: "抱歉,页面好像去火星了~"
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
39
src/components/redirect/Message.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div class="middle-box">
|
||||
<div class="text-center animated fadeInDown">
|
||||
<i style="font-size: 50px;color: #67c23a;margin-top:40px;" class="el-icon-circle-check"></i>
|
||||
<div style="font-size: 20px;margin-top: 10px;" class="error-desc">{{ text }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
default: "操作成功!",
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
body {
|
||||
background-color: #fff;
|
||||
}
|
||||
.middle-box {
|
||||
text-align: center;
|
||||
padding-top: 80px;
|
||||
height: 100%;
|
||||
// background: #eee;
|
||||
h1 {
|
||||
font-size: 140px;
|
||||
font-weight: 100;
|
||||
}
|
||||
.back {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
59
src/components/redirect/RedirectError.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="middle-box">
|
||||
<div class="text-center animated fadeInDown">
|
||||
<h1>{{ errorNumber }}</h1>
|
||||
<h3 class="font-bold">{{message}}</h3>
|
||||
<slot></slot>
|
||||
<div class="error-desc">{{ text }}</div>
|
||||
<div class="back">
|
||||
<el-button type="primary" @click="backHome" icon="md-arrow-round-back"
|
||||
>返回首页</el-button >
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { Script } from "vm";
|
||||
export default {
|
||||
props: {
|
||||
errorNumber: {
|
||||
type: String,
|
||||
default: "500",
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
default: "页面未找到!",
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: "唉...好像出了点问题~",
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
backHome: function () {
|
||||
this.$router.push({
|
||||
path: "/home",
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
body {
|
||||
background-color: #fff;
|
||||
}
|
||||
.middle-box {
|
||||
text-align: center;
|
||||
padding-top: 80px;
|
||||
height: 100%;
|
||||
// background: #eee;
|
||||
h1 {
|
||||
font-size: 140px;
|
||||
font-weight: 100;
|
||||
}
|
||||
.back {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
25
src/components/redirect/coding.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div style="height:100%;">
|
||||
<redirect-error :text="text" :errorNumber="errorNumber">
|
||||
<div>
|
||||
<router-link to="SellOrder">
|
||||
<Button>点击查看[测试完整示例]</Button>
|
||||
</router-link>
|
||||
</div>
|
||||
</redirect-error>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import RedirectError from "./RedirectError";
|
||||
export default {
|
||||
components: {
|
||||
RedirectError
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
errorNumber: "用例正在整理中",
|
||||
text: "详细用例在正准备中,目前可参考[测试完整示例]的使用方法"
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
54
src/components/workflow/data_A.js
Normal file
@@ -0,0 +1,54 @@
|
||||
let dataA = {
|
||||
"name": "流程A",
|
||||
"nodeList": [
|
||||
{
|
||||
"id": "0",
|
||||
"name": "流程开始",
|
||||
"type": "start",
|
||||
"left": "346px",
|
||||
"top": "22px",
|
||||
"ico": "el-icon-user-solid"
|
||||
},
|
||||
{
|
||||
"id": "nodeA",
|
||||
"name": "流程A-节点A",
|
||||
"type": "node",
|
||||
"left": "346px",
|
||||
"top": "132px",
|
||||
"ico": "el-icon-user-solid"
|
||||
},
|
||||
// {
|
||||
// "id": "nodeB",
|
||||
// "name": "流程A-节点B",
|
||||
// "type": "node",
|
||||
// "left": "347px",
|
||||
// "top": "235px",
|
||||
// "ico": "el-icon-goods"
|
||||
// },
|
||||
// {
|
||||
// "id": "nodeC",
|
||||
// "name": "流程A-节点C",
|
||||
// "type": "node",
|
||||
// "left": "323px",
|
||||
// "top": "399px",
|
||||
// "ico": "el-icon-present"
|
||||
// }
|
||||
],
|
||||
"lineList": [
|
||||
{
|
||||
"from": "0",
|
||||
"to": "nodeA"
|
||||
},
|
||||
// {
|
||||
// "from": "nodeA",
|
||||
// "to": "nodeB"
|
||||
// },
|
||||
// {
|
||||
// "from": "nodeB",
|
||||
// "to": "nodeC"
|
||||
// }
|
||||
]
|
||||
}
|
||||
export function getDataA () {
|
||||
return dataA
|
||||
}
|
||||
182
src/components/workflow/force-directed.js
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* 感谢 https://github.com/chaangliu/ForceDirectedLayout/blob/master/javascript/force-directed.js
|
||||
* A force directed graph layout implementation by liuchang on 2018/05/10.
|
||||
*/
|
||||
const CANVAS_WIDTH = 1000
|
||||
const CANVAS_HEIGHT = 1000
|
||||
let k
|
||||
let mNodeList = []
|
||||
let mEdgeList = []
|
||||
let mDxMap = {}
|
||||
let mDyMap = {}
|
||||
let mNodeMap = {}
|
||||
|
||||
export function ForceDirected(data = {}) {
|
||||
// generate nodes and edges
|
||||
// for (let i = 0; i < 20; i++) {
|
||||
// mNodeList.push(new Node(i))
|
||||
// }
|
||||
k = 0
|
||||
mNodeList = []
|
||||
mEdgeList = []
|
||||
mDxMap = {}
|
||||
mDyMap = {}
|
||||
mNodeMap = {}
|
||||
|
||||
let nodeList = data.nodeList
|
||||
for (let i = 0; i < nodeList.length; i++) {
|
||||
let node = nodeList[i]
|
||||
mNodeList.push(node)
|
||||
}
|
||||
|
||||
// for (let i = 0; i < 20; i++) {
|
||||
// let edgeCount = Math.random() * 8 + 1
|
||||
// for (let j = 0; j < edgeCount; j++) {
|
||||
// let targetId = Math.floor(Math.random() * 20)
|
||||
// let edge = new Edge(i, targetId)
|
||||
// mEdgeList.push(edge)
|
||||
// }
|
||||
// }
|
||||
// line 转 edge
|
||||
let lineList = data.lineList
|
||||
for (let i = 0; i < lineList.length; i++) {
|
||||
let line = lineList[i]
|
||||
let edge = new Edge(line.from, line.to)
|
||||
mEdgeList.push(edge)
|
||||
}
|
||||
|
||||
if (mNodeList && mEdgeList) {
|
||||
k = Math.sqrt(CANVAS_WIDTH * CANVAS_HEIGHT / mNodeList.length)
|
||||
}
|
||||
for (let i = 0; i < mNodeList.length; i++) {
|
||||
let node = mNodeList[i]
|
||||
if (node) {
|
||||
mNodeMap[node.id] = node
|
||||
}
|
||||
}
|
||||
|
||||
// 随机生成坐标. Generate coordinates randomly.
|
||||
let initialX, initialY, initialSize = 40.0
|
||||
for (let i in mNodeList) {
|
||||
initialX = CANVAS_WIDTH * 0.5
|
||||
initialY = CANVAS_HEIGHT * 0.5
|
||||
mNodeList[i].x = initialX + initialSize * (Math.random() - 0.5)
|
||||
mNodeList[i].y = initialY + initialSize * (Math.random() - 0.5)
|
||||
}
|
||||
|
||||
// 迭代200次. Iterate 200 times.
|
||||
for (let i = 0; i < 200; i++) {
|
||||
calculateRepulsive()
|
||||
calculateTraction()
|
||||
updateCoordinates()
|
||||
}
|
||||
// console.log(JSON.stringify(new Result(mNodeList, mEdgeList)))
|
||||
// 坐标添加px
|
||||
for (let i = 0; i < mNodeList.length; i++) {
|
||||
let node = mNodeList[i]
|
||||
node.left = node.x + 'px'
|
||||
node.top = node.y + 'px'
|
||||
node.x = undefined
|
||||
node.y = undefined
|
||||
}
|
||||
|
||||
data.nodeList = mNodeList
|
||||
|
||||
// console.log(data)
|
||||
return data
|
||||
}
|
||||
|
||||
function Node(id = null) {
|
||||
this.id = id
|
||||
this.x = 22
|
||||
this.y = null
|
||||
}
|
||||
|
||||
function Edge(source = null, target = null) {
|
||||
this.source = source
|
||||
this.target = target
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个Node的斥力产生的单位位移。
|
||||
* Calculate the displacement generated by the repulsive force between two nodes.*
|
||||
*/
|
||||
function calculateRepulsive() {
|
||||
let ejectFactor = 6
|
||||
let distX, distY, dist
|
||||
for (let i = 0; i < mNodeList.length; i++) {
|
||||
mDxMap[mNodeList[i].id] = 0.0
|
||||
mDyMap[mNodeList[i].id] = 0.0
|
||||
for (let j = 0; j < mNodeList.length; j++) {
|
||||
if (i !== j) {
|
||||
distX = mNodeList[i].x - mNodeList[j].x
|
||||
distY = mNodeList[i].y - mNodeList[j].y
|
||||
dist = Math.sqrt(distX * distX + distY * distY)
|
||||
}
|
||||
if (dist < 30) {
|
||||
ejectFactor = 5
|
||||
}
|
||||
if (dist > 0 && dist < 250) {
|
||||
let id = mNodeList[i].id
|
||||
mDxMap[id] = mDxMap[id] + distX / dist * k * k / dist * ejectFactor
|
||||
mDyMap[id] = mDyMap[id] + distY / dist * k * k / dist * ejectFactor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算Edge的引力对两端Node产生的引力。
|
||||
* Calculate the traction force generated by the edge acted on the two nodes of its two ends.
|
||||
*/
|
||||
function calculateTraction() {
|
||||
let condenseFactor = 3
|
||||
let startNode, endNode
|
||||
for (let e = 0; e < mEdgeList.length; e++) {
|
||||
let eStartID = mEdgeList[e].source
|
||||
let eEndID = mEdgeList[e].target
|
||||
startNode = mNodeMap[eStartID]
|
||||
endNode = mNodeMap[eEndID]
|
||||
if (!startNode) {
|
||||
console.log('Cannot find start node id: ' + eStartID + ', please check it out.')
|
||||
return
|
||||
}
|
||||
if (!endNode) {
|
||||
console.log('Cannot find end node id: ' + eEndID + ', please check it out.')
|
||||
return
|
||||
}
|
||||
let distX, distY, dist
|
||||
distX = startNode.x - endNode.x
|
||||
distY = startNode.y - endNode.y
|
||||
dist = Math.sqrt(distX * distX + distY * distY)
|
||||
mDxMap[eStartID] = mDxMap[eStartID] - distX * dist / k * condenseFactor
|
||||
mDyMap[eStartID] = mDyMap[eStartID] - distY * dist / k * condenseFactor
|
||||
mDxMap[eEndID] = mDxMap[eEndID] + distX * dist / k * condenseFactor
|
||||
mDyMap[eEndID] = mDyMap[eEndID] + distY * dist / k * condenseFactor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新坐标。
|
||||
* update the coordinates.
|
||||
*/
|
||||
function updateCoordinates() {
|
||||
let maxt = 4, maxty = 3 // Additional coefficients.
|
||||
for (let v = 0; v < mNodeList.length; v++) {
|
||||
let node = mNodeList[v]
|
||||
let dx = Math.floor(mDxMap[node.id])
|
||||
let dy = Math.floor(mDyMap[node.id])
|
||||
|
||||
if (dx < -maxt) dx = -maxt
|
||||
if (dx > maxt) dx = maxt
|
||||
if (dy < -maxty) dy = -maxty
|
||||
if (dy > maxty) dy = maxty
|
||||
node.x = node.x + dx >= CANVAS_WIDTH || node.x + dx <= 0 ? node.x - dx : node.x + dx
|
||||
node.y = node.y + dy >= CANVAS_HEIGHT || node.y + dy <= 0 ? node.y - dy : node.y + dy
|
||||
}
|
||||
}
|
||||
|
||||
function Result(nodes = null, links = null) {
|
||||
this.nodes = nodes
|
||||
this.links = links
|
||||
}
|
||||
258
src/components/workflow/index.css
Normal file
@@ -0,0 +1,258 @@
|
||||
/*画布容器*/
|
||||
.efContainer {
|
||||
position: relative;
|
||||
overflow: scroll;
|
||||
flex: 1;
|
||||
}
|
||||
.tools {
|
||||
position: absolute;
|
||||
left: 220px;
|
||||
/* background: #fff; */
|
||||
/* border: 1px solid #d8d7d7; */
|
||||
/* border-radius: 5px; */
|
||||
padding: 5px 5px;
|
||||
display: flex;
|
||||
z-index: 99;
|
||||
background: #fcfcfc;
|
||||
}
|
||||
|
||||
/*顶部工具栏*/
|
||||
.ef-tooltar {
|
||||
padding-left: 10px;
|
||||
box-sizing: border-box;
|
||||
height: 42px;
|
||||
line-height: 42px;
|
||||
z-index: 3;
|
||||
border-bottom: 1px solid #dadce0;
|
||||
}
|
||||
|
||||
.jtk-overlay {
|
||||
cursor: pointer;
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
.ef-node-pmenu-item {
|
||||
padding: 10px;
|
||||
background: #f8f8f8;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 1px;
|
||||
border-top: 1px solid #eee;
|
||||
border-bottom: 1px solid #eee;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
/*节点菜单*/
|
||||
.ef-node-pmenu {
|
||||
cursor: pointer;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
width: 225px;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
color: #4a4a4a;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.ef-node-pmenu:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
.ef-node-menu-item {
|
||||
padding: 10px;
|
||||
}
|
||||
.ef-node-menu-li {
|
||||
cursor: move;
|
||||
border: 1px solid #eee;
|
||||
padding: 2px 13px;
|
||||
text-align: left;
|
||||
line-height: 28px;
|
||||
margin: 4px;
|
||||
border-radius: 3px;
|
||||
background: #f0f9eb;
|
||||
font-size: 12px;
|
||||
float: left;
|
||||
width: 98px;
|
||||
|
||||
}
|
||||
|
||||
.ef-node-menu-li > div:first-child{
|
||||
display: inline-block;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.ef-node-menu-li:hover {
|
||||
/* 设置移动样式*/
|
||||
cursor: move;
|
||||
border: 1px dashed #787be8;
|
||||
color: #787be8;
|
||||
/* background-color: #F0F7FF;
|
||||
border: 1px dashed #1879FF;
|
||||
border-left: 4px solid #1879FF;
|
||||
padding-left: 5px; */
|
||||
}
|
||||
|
||||
.ef-node-menu-ul {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/*节点的最外层容器*/
|
||||
.ef-node-container {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
width: 170px;
|
||||
height: 32px;
|
||||
border: 1px solid #e0e3e7;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.ef-node-container:hover {
|
||||
/* 设置移动样式*/
|
||||
cursor: move;
|
||||
background-color: #f0f7ff;
|
||||
/*box-shadow: #1879FF 0px 0px 12px 0px;*/
|
||||
background-color: #f0f7ff;
|
||||
border: 1px dashed #1879ff;
|
||||
}
|
||||
|
||||
/*节点激活样式*/
|
||||
.ef-node-active {
|
||||
background-color: #f0f7ff;
|
||||
/*box-shadow: #1879FF 0px 0px 12px 0px;*/
|
||||
background-color: #f0f7ff;
|
||||
border: 1px solid #1879ff;
|
||||
}
|
||||
|
||||
/*节点左侧的竖线*/
|
||||
.ef-node-left {
|
||||
width: 4px;
|
||||
background-color: #1879ff;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
/*节点左侧的图标*/
|
||||
.ef-node-left-ico {
|
||||
line-height: 32px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.ef-node-left-ico:hover {
|
||||
/* 设置拖拽的样式 */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
/*节点显示的文字*/
|
||||
.ef-node-text {
|
||||
color: #565758;
|
||||
font-size: 12px;
|
||||
line-height: 32px;
|
||||
margin-left: 8px;
|
||||
width: 100px;
|
||||
/* 设置超出宽度文本显示方式*/
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*节点右侧的图标*/
|
||||
.ef-node-right-ico {
|
||||
line-height: 32px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
color: #84cf65;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/*节点的几种状态样式*/
|
||||
.el-node-state-success {
|
||||
line-height: 32px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
color: #84cf65;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.el-node-state-error {
|
||||
line-height: 32px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
color: #f56c6c;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.el-node-state-warning {
|
||||
line-height: 32px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
color: #e6a23c;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.el-node-state-running {
|
||||
line-height: 32px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
color: #84cf65;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/*node-form*/
|
||||
.ef-node-form-header {
|
||||
height: 32px;
|
||||
border-top: 1px solid #dce3e8;
|
||||
border-bottom: 1px solid #dce3e8;
|
||||
background: #f1f3f4;
|
||||
color: #000;
|
||||
line-height: 32px;
|
||||
padding-left: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ef-node-form-body {
|
||||
margin-top: 10px;
|
||||
padding-right: 10px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 连线中的label 样式*/
|
||||
.jtk-overlay.flowLabel:not(.aLabel) {
|
||||
/* padding: 4px 10px; */
|
||||
padding: 1px 8px 2px 8px;
|
||||
background-color: white;
|
||||
color: #a9aaaa !important;
|
||||
border: 1px solid #e0e3e7;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* label 为空的样式 */
|
||||
.emptyFlowLabel {
|
||||
}
|
||||
|
||||
.ef-dot {
|
||||
background-color: #1879ff;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.ef-dot-hover {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.ef-rectangle {
|
||||
background-color: #1879ff;
|
||||
}
|
||||
|
||||
.ef-rectangle-hover {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.ef-img {
|
||||
}
|
||||
|
||||
.ef-img-hover {
|
||||
}
|
||||
|
||||
.ef-drop-hover {
|
||||
border: 1px dashed #1879ff;
|
||||
}
|
||||
15711
src/components/workflow/jsplumb.js
Normal file
157
src/components/workflow/mixins.js
Normal file
@@ -0,0 +1,157 @@
|
||||
export const easyFlowMixin = {
|
||||
data() {
|
||||
return {
|
||||
jsplumbSetting: {
|
||||
// 动态锚点、位置自适应
|
||||
Anchors: ['Top', 'TopCenter', 'TopRight', 'TopLeft', 'Right', 'RightMiddle', 'Bottom', 'BottomCenter', 'BottomRight', 'BottomLeft', 'Left', 'LeftMiddle'],
|
||||
// 容器ID
|
||||
Container: 'efContainer',
|
||||
// 连线的样式,直线或者曲线等,可选值: StateMachine、Flowchart,Bezier、Straight
|
||||
Connector: ['Bezier', {curviness: 100}],
|
||||
// Connector: ['Straight', {stub: 20, gap: 1}],
|
||||
// Connector: ['Flowchart', {stub: 30, gap: 1, alwaysRespectStubs: false, midpoint: 0.5, cornerRadius: 10}],
|
||||
// Connector: ['StateMachine', {margin: 5, curviness: 10, proximityLimit: 80}],
|
||||
// 鼠标不能拖动删除线
|
||||
ConnectionsDetachable: false,
|
||||
// 删除线的时候节点不删除
|
||||
DeleteEndpointsOnDetach: false,
|
||||
/**
|
||||
* 连线的两端端点类型:圆形
|
||||
* radius: 圆的半径,越大圆越大
|
||||
*/
|
||||
// Endpoint: ['Dot', {radius: 5, cssClass: 'ef-dot', hoverClass: 'ef-dot-hover'}],
|
||||
/**
|
||||
* 连线的两端端点类型:矩形
|
||||
* height: 矩形的高
|
||||
* width: 矩形的宽
|
||||
*/
|
||||
// Endpoint: ['Rectangle', {height: 20, width: 20, cssClass: 'ef-rectangle', hoverClass: 'ef-rectangle-hover'}],
|
||||
/**
|
||||
* 图像端点
|
||||
*/
|
||||
// Endpoint: ['Image', {src: 'https://www.easyicon.net/api/resizeApi.php?id=1181776&size=32', cssClass: 'ef-img', hoverClass: 'ef-img-hover'}],
|
||||
/**
|
||||
* 空白端点
|
||||
*/
|
||||
Endpoint: ['Blank', {Overlays: ''}],
|
||||
// Endpoints: [['Dot', {radius: 5, cssClass: 'ef-dot', hoverClass: 'ef-dot-hover'}], ['Rectangle', {height: 20, width: 20, cssClass: 'ef-rectangle', hoverClass: 'ef-rectangle-hover'}]],
|
||||
/**
|
||||
* 连线的两端端点样式
|
||||
* fill: 颜色值,如:#12aabb,为空不显示
|
||||
* outlineWidth: 外边线宽度
|
||||
*/
|
||||
EndpointStyle: {fill: '#1879ffa1', outlineWidth: 1},
|
||||
// 是否打开jsPlumb的内部日志记录
|
||||
LogEnabled: true,
|
||||
/**
|
||||
* 连线的样式
|
||||
*/
|
||||
PaintStyle: {
|
||||
// 线的颜色
|
||||
stroke: '#E0E3E7',
|
||||
// 线的粗细,值越大线越粗
|
||||
strokeWidth: 1,
|
||||
// 设置外边线的颜色,默认设置透明,这样别人就看不见了,点击线的时候可以不用精确点击,参考 https://blog.csdn.net/roymno2/article/details/72717101
|
||||
outlineStroke: 'transparent',
|
||||
// 线外边的宽,值越大,线的点击范围越大
|
||||
outlineWidth: 10
|
||||
},
|
||||
DragOptions: {cursor: 'pointer', zIndex: 2000},
|
||||
/**
|
||||
* 叠加 参考: https://www.jianshu.com/p/d9e9918fd928
|
||||
*/
|
||||
Overlays: [
|
||||
// 箭头叠加
|
||||
['Arrow', {
|
||||
width: 10, // 箭头尾部的宽度
|
||||
length: 8, // 从箭头的尾部到头部的距离
|
||||
location: 1, // 位置,建议使用0~1之间
|
||||
direction: 1, // 方向,默认值为1(表示向前),可选-1(表示向后)
|
||||
foldback: 0.623 // 折回,也就是尾翼的角度,默认0.623,当为1时,为正三角
|
||||
}],
|
||||
// ['Diamond', {
|
||||
// events: {
|
||||
// dblclick: function (diamondOverlay, originalEvent) {
|
||||
// console.log('double click on diamond overlay for : ' + diamondOverlay.component)
|
||||
// }
|
||||
// }
|
||||
// }],
|
||||
['Label', {
|
||||
label: '',
|
||||
location: 0.1,
|
||||
cssClass: 'aLabel'
|
||||
}]
|
||||
],
|
||||
// 绘制图的模式 svg、canvas
|
||||
RenderMode: 'svg',
|
||||
// 鼠标滑过线的样式
|
||||
HoverPaintStyle: {stroke: '#b0b2b5', strokeWidth: 1},
|
||||
// 滑过锚点效果
|
||||
// EndpointHoverStyle: {fill: 'red'}
|
||||
Scope: 'jsPlumb_DefaultScope' // 范围,具有相同scope的点才可连接
|
||||
},
|
||||
/**
|
||||
* 连线参数
|
||||
*/
|
||||
jsplumbConnectOptions: {
|
||||
isSource: true,
|
||||
isTarget: true,
|
||||
// 动态锚点、提供了4个方向 Continuous、AutoDefault
|
||||
anchor: 'Continuous',
|
||||
// 设置连线上面的label样式
|
||||
labelStyle: {
|
||||
cssClass: 'flowLabel'
|
||||
},
|
||||
// 修改了jsplumb 源码,支持label 为空传入自定义style
|
||||
emptyLabelStyle: {
|
||||
cssClass: 'emptyFlowLabel'
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 源点配置参数
|
||||
*/
|
||||
jsplumbSourceOptions: {
|
||||
// 设置可以拖拽的类名,只要鼠标移动到该类名上的DOM,就可以拖拽连线
|
||||
filter: '.flow-node-drag',
|
||||
filterExclude: false,
|
||||
anchor: 'Continuous',
|
||||
// 是否允许自己连接自己
|
||||
allowLoopback: true,
|
||||
maxConnections: -1,
|
||||
onMaxConnections: function (info, e) {
|
||||
console.log(`超过了最大值连线: ${info.maxConnections}`)
|
||||
}
|
||||
},
|
||||
// 参考 https://www.cnblogs.com/mq0036/p/7942139.html
|
||||
jsplumbSourceOptions2: {
|
||||
// 设置可以拖拽的类名,只要鼠标移动到该类名上的DOM,就可以拖拽连线
|
||||
filter: '.flow-node-drag',
|
||||
filterExclude: false,
|
||||
// anchor: 'Continuous',
|
||||
// 是否允许自己连接自己
|
||||
allowLoopback: true,
|
||||
connector: ['Flowchart', {curviness: 50}],
|
||||
connectorStyle: {
|
||||
// 线的颜色
|
||||
stroke: 'red',
|
||||
// 线的粗细,值越大线越粗
|
||||
strokeWidth: 1,
|
||||
// 设置外边线的颜色,默认设置透明,这样别人就看不见了,点击线的时候可以不用精确点击,参考 https://blog.csdn.net/roymno2/article/details/72717101
|
||||
outlineStroke: 'transparent',
|
||||
// 线外边的宽,值越大,线的点击范围越大
|
||||
outlineWidth: 10
|
||||
},
|
||||
connectorHoverStyle: {stroke: 'red', strokeWidth: 2}
|
||||
},
|
||||
jsplumbTargetOptions: {
|
||||
// 设置可以拖拽的类名,只要鼠标移动到该类名上的DOM,就可以拖拽连线
|
||||
filter: '.flow-node-drag',
|
||||
filterExclude: false,
|
||||
// 是否允许自己连接自己
|
||||
anchor: 'Continuous',
|
||||
allowLoopback: true,
|
||||
dropOptions: {hoverClass: 'ef-drop-hover'}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
94
src/components/workflow/node.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div ref="node" class="node-item" :style="nodeContainerStyle" @click="clickNode" @mouseup="changeNodeSite" :class="nodeContainerClass">
|
||||
<!-- 最左侧的那条竖线 -->
|
||||
<div class="ef-node-left"></div>
|
||||
<!-- 节点类型的图标 -->
|
||||
<div class="ef-node-left-ico flow-node-drag">
|
||||
<i :class="nodeIcoClass"></i>
|
||||
</div>
|
||||
<!-- 节点名称 -->
|
||||
<div class="ef-node-text" :show-overflow-tooltip="true">
|
||||
{{ node.name }}
|
||||
</div>
|
||||
<i @click.stop="delNode" v-if="node.type=='node'" style="display: none" class="el-icon-delete"></i>
|
||||
<!-- 节点状态图标 -->
|
||||
<div class="ef-node-right-ico">
|
||||
<i class="el-icon-circle-check el-node-state-success" v-show="node.state === 'success'"></i>
|
||||
<i class="el-icon-circle-close el-node-state-error" v-show="node.state === 'error'"></i>
|
||||
<i class="el-icon-warning-outline el-node-state-warning" v-show="node.state === 'warning'"></i>
|
||||
<i class="el-icon-loading el-node-state-running" v-show="node.state === 'running'"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
node: Object,
|
||||
activeElement: Object
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
nodeContainerClass() {
|
||||
return {
|
||||
'ef-node-container': true,
|
||||
'ef-node-active': this.activeElement.type == 'node' ? this.activeElement.nodeId === this.node.id : false
|
||||
}
|
||||
},
|
||||
// 节点容器样式
|
||||
nodeContainerStyle() {
|
||||
return {
|
||||
top: this.node.top,
|
||||
left: this.node.left
|
||||
}
|
||||
},
|
||||
nodeIcoClass() {
|
||||
var nodeIcoClass = {}
|
||||
nodeIcoClass[this.node.ico] = true
|
||||
// 添加该class可以推拽连线出来,viewOnly 可以控制节点是否运行编辑
|
||||
nodeIcoClass['flow-node-drag'] = this.node.viewOnly ? false : true
|
||||
return nodeIcoClass
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 点击节点
|
||||
clickNode() {
|
||||
this.$emit('clickNode', this.node.id)
|
||||
},
|
||||
// 鼠标移动后抬起
|
||||
changeNodeSite() {
|
||||
// 避免抖动
|
||||
if (this.node.left == this.$refs.node.style.left && this.node.top == this.$refs.node.style.top) {
|
||||
return;
|
||||
}
|
||||
this.$emit('changeNodeSite', {
|
||||
nodeId: this.node.id,
|
||||
left: this.$refs.node.style.left,
|
||||
top: this.$refs.node.style.top,
|
||||
})
|
||||
}, delNode() {
|
||||
this.$emit("delNode");
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
/* .node-item{
|
||||
position: relative;
|
||||
} */
|
||||
.node-item:hover .el-icon-delete {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
.el-icon-delete {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: -18px;
|
||||
padding-left: 5px;
|
||||
right: -16px;
|
||||
color: #f61313;
|
||||
height: 20px;
|
||||
}
|
||||
</style>
|
||||
198
src/components/workflow/node_filter.vue
Normal file
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div class="node-filter-container">
|
||||
<!-- <div class="add-btn">
|
||||
<span class="name">条件设置</span> <el-button @click="addItem" link><i>+</i>添加字段</el-button>
|
||||
</div> -->
|
||||
<!-- {{ $store.getters.data().flowTable.WorkTable }} -->
|
||||
<div class="ef-node-pmenu-item" style="display: flex;">
|
||||
<div style="flex:1;">
|
||||
<span class="name"><i class="el-icon-news"></i>条件设置</span>
|
||||
</div>
|
||||
<div><el-button link size="small" @click="addItem" type="primary">
|
||||
+ 添加字段</el-button></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<table>
|
||||
<tr>
|
||||
<td>字段</td>
|
||||
<td style="width:90px">条件</td>
|
||||
<td class="value">值</td>
|
||||
<td style="width: 40px;">操作</td>
|
||||
</tr>
|
||||
<tr v-for="(item, index) in filters" :key="index">
|
||||
|
||||
<td><el-select @change="(field) => { fieldChange(field, index) }" size="small" v-model="item.field"
|
||||
placeholder="请选择">
|
||||
<el-option v-for="data in fieldsOptions" :key="data.field" :label="data.name"
|
||||
:value="data.field" />
|
||||
</el-select></td>
|
||||
<td><el-select size="small" v-model="item.filterType" placeholder="请选择">
|
||||
<el-option v-for="data in filterType" :key="data.value" :label="data.name"
|
||||
:value="data.value" />
|
||||
</el-select></td>
|
||||
<td>
|
||||
<template v-if="item.data">
|
||||
<el-select v-if="item.data.length >= 300" multiple size="small" v-model="item.value"
|
||||
placeholder="请选择">
|
||||
<el-option v-for="data in item.data" :key="data.key" :label="data.value"
|
||||
:value="data.key" />
|
||||
</el-select>
|
||||
<el-select-v2 style="width: 100%;" v-else multiple size="small" :options="item.data"
|
||||
v-model="item.value" placeholder="请选择">
|
||||
|
||||
</el-select-v2>
|
||||
</template>
|
||||
<el-input v-else v-model="item.value" size="small"></el-input>
|
||||
</td>
|
||||
<td @click="delItem(index)" class="item-del"><i class="el-icon-delete"></i></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- <div>
|
||||
<label>自定义sql</label>
|
||||
<div><el-input type="textarea" v-model="customSql"></el-input></div>
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let _this = this;
|
||||
export default {
|
||||
props: {
|
||||
tableName: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
filters: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filter: this.$store.getters.data().flowTable,
|
||||
customSql: "",
|
||||
value: "",
|
||||
//{ field: "名称", value: "", filterType: "=" },
|
||||
// filters: [],
|
||||
fieldsOptions: [
|
||||
|
||||
],
|
||||
t: [],
|
||||
filterType: [{ name: "等于(=)", value: "=" },
|
||||
{ name: "不等于(!=)", value: "!=" },
|
||||
{ name: "大于(>)", value: ">" },
|
||||
{ name: "大于等于(>=)", value: ">=" },
|
||||
{ name: "小于(<)", value: "<" },
|
||||
{ name: "小于等于(<=)", value: "<=" },
|
||||
{ name: "包括(in)", value: "in" },
|
||||
// { name: "不包括(not in)", value: "notin" },
|
||||
{ name: "模糊匹配(like)", value: "like" },
|
||||
{ name: "或者(or)", value: "or" }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
delItem(index) {
|
||||
this.$confirm('确认要删除字配置条件配置吗?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
center: true
|
||||
}).then(() => {
|
||||
this.filters.splice(index, 1);
|
||||
});
|
||||
},
|
||||
addItem() {
|
||||
this.filters.push({ field: "", value: "", filterType: "", data: null })
|
||||
},
|
||||
fieldChange(field, index) {
|
||||
let option = this.fieldsOptions.find(x => { return x.field == field });
|
||||
this.filters[index].field = option.field;
|
||||
this.filters[index].value = option.data ? [] : null;
|
||||
this.filters[index].data = option.data;;
|
||||
},
|
||||
convertOptions(result) {
|
||||
|
||||
},
|
||||
getOptions(tableName) {
|
||||
const url = 'api/Sys_WorkFlow/getFields?table=' + tableName;
|
||||
this.http.post(url, {}, false).then(result => {
|
||||
result.forEach(c => {
|
||||
if (c.data && c.data.length < 300) {
|
||||
c.data = c.data.map(x => {
|
||||
return {
|
||||
value: x.key,
|
||||
label: x.value,
|
||||
key: x.key
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
_this.fieldsOptions = result;
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'filter.WorkTable': {
|
||||
handler(newvalue, oldvalue) {
|
||||
if (newvalue) {
|
||||
this.getOptions(newvalue);
|
||||
} else {
|
||||
// this.fieldsOptions.splice(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
// deep:true,
|
||||
// filter(newVal,oldVal){
|
||||
// alert(1)
|
||||
// }
|
||||
},
|
||||
created() {
|
||||
_this = this;
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.node-filter-container {
|
||||
margin-top: 15px;
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
padding-left: 6px;
|
||||
|
||||
td {
|
||||
font-size: 13px;
|
||||
padding: 5px;
|
||||
|
||||
}
|
||||
|
||||
tr:first-child {
|
||||
font-size: 12px;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.item-del {
|
||||
text-align: center;
|
||||
color: rgb(226, 4, 4);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.value {
|
||||
width: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.node-filter-item {}
|
||||
}</style>
|
||||
340
src/components/workflow/node_form.vue
Normal file
@@ -0,0 +1,340 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="ef-node-form">
|
||||
<div class="ef-node-pmenu-item">
|
||||
<div style="flex:1;">
|
||||
<span class="name"><i class="el-icon-news"></i>节点属性</span>
|
||||
<!-- <span @click="nameClick(1)" :class="{ active: index === 1 }" class="name">审批条件</span> -->
|
||||
</div>
|
||||
<!-- <div><el-button link size="small" type="primary" @click="save"><i class="el-icon-check"></i>
|
||||
保存配置</el-button></div> -->
|
||||
</div>
|
||||
<div class="ef-node-form-body">
|
||||
<div class="form-info">
|
||||
<MesForm ref="form" style="padding:0 10px;" :label-width="130" :loadKey="false" :formFields="node"
|
||||
:formRules="formRules">
|
||||
</MesForm>
|
||||
</div>
|
||||
<div>
|
||||
<node-filter :filters="node.filters" :tableName="tableName" ref="filter">
|
||||
</node-filter>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="el-node-form-tag"></div>-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { cloneDeep } from 'lodash'
|
||||
import MesForm from '@/components/basic/MesForm.vue';
|
||||
import nodeFilter from './node_filter.vue';
|
||||
export default {
|
||||
components: {
|
||||
MesForm,
|
||||
'node-filter': nodeFilter
|
||||
},
|
||||
props: {
|
||||
// node: {
|
||||
// type: Object,
|
||||
// default: () => {
|
||||
// return {
|
||||
// name: '',
|
||||
// auditType: 1,//审核类型
|
||||
// userId: null,
|
||||
// roleId: null,
|
||||
// deptId: null,
|
||||
// auditRefuse: null,//审核未通过
|
||||
// auditBack: null, //驳回
|
||||
// auditMethod: 0,//审批方式(会签)
|
||||
// stepValue: null,
|
||||
// sendMail: 0,
|
||||
// filters: [] //字段过滤条件
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
},
|
||||
created() {
|
||||
this.http.get('api/Sys_WorkFlow/getNodeDic').then((result) => {
|
||||
this.formRules.forEach((options) => {
|
||||
options.forEach((option) => {
|
||||
if (option.dataKey && !option.data.length) {
|
||||
option.data = result[option.dataKey] || [];
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableName:"",
|
||||
index: 1,
|
||||
visible: true,
|
||||
// node 或 line
|
||||
type: 'node',
|
||||
node: {},
|
||||
line: {},
|
||||
data: {},
|
||||
|
||||
node: {
|
||||
name: '',
|
||||
auditType: 1,//审核类型
|
||||
userId: null,
|
||||
roleId: null,
|
||||
deptId: null,
|
||||
auditRefuse: null,//审核未通过
|
||||
auditBack: null, //驳回
|
||||
auditMethod: 0,//审批方式(会签)
|
||||
// nodeValue: null,
|
||||
sendMail: 0,
|
||||
filters: []
|
||||
},
|
||||
formRules: [
|
||||
[
|
||||
{
|
||||
title: '节点名称',
|
||||
field: 'name',
|
||||
required: true,
|
||||
colSize: 12
|
||||
}],
|
||||
[
|
||||
{
|
||||
dataKey: '',
|
||||
title: '审批类型',
|
||||
required: true,
|
||||
hidden: false,
|
||||
field: 'auditType',
|
||||
data: [
|
||||
{ key: 1, value: '按用户审批' },
|
||||
{ key: 2, value: '按角色审批' },
|
||||
{ key: 3, value: '按部门审批' }
|
||||
],
|
||||
type: 'select',
|
||||
onChange: this.nodeTypeChange
|
||||
},
|
||||
{
|
||||
dataKey: 'users',
|
||||
hidden: false,
|
||||
title: '审批用户',
|
||||
required: true,
|
||||
field: 'userId',
|
||||
data: [],
|
||||
type: 'select'
|
||||
}
|
||||
,
|
||||
{
|
||||
dataKey: 'roles',
|
||||
hidden: true,
|
||||
title: '角色信息',
|
||||
required: true,
|
||||
field: 'roleId',
|
||||
|
||||
data: [],
|
||||
type: 'select'
|
||||
}
|
||||
,
|
||||
{
|
||||
dataKey: 'dept',
|
||||
hidden: true,
|
||||
title: '部门信息',
|
||||
required: true,
|
||||
field: 'deptId',
|
||||
data: [],
|
||||
type: 'select'
|
||||
}
|
||||
], [
|
||||
{
|
||||
dataKey: '',
|
||||
title: '审批未通过',
|
||||
required: false,
|
||||
field: 'auditRefuse',
|
||||
hidden: false,
|
||||
data: [
|
||||
{ key: 1, value: '返回上一节点' },
|
||||
{ key: 2, value: '流程重新开始' },
|
||||
{ key: 0, value: '流程结束' },
|
||||
],
|
||||
type: 'select',
|
||||
colSize: 6
|
||||
}
|
||||
,
|
||||
{
|
||||
dataKey: '',
|
||||
title: '审批驳回',
|
||||
required: false,
|
||||
hidden: false,
|
||||
field: 'auditBack',
|
||||
data: [
|
||||
{ key: 1, value: '返回上一节点' },
|
||||
{ key: 2, value: '流程重新开始' },
|
||||
{ key: 0, value: '流程结束' },
|
||||
],
|
||||
type: 'select',
|
||||
colSize: 6
|
||||
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
dataKey: '',
|
||||
title: '审核后发送邮件通知',
|
||||
required: false,
|
||||
hidden: false,
|
||||
field: 'sendMail',
|
||||
data: [
|
||||
{ key: 1, value: '是' },
|
||||
{ key: 0, value: '否' },
|
||||
],
|
||||
type: 'switch'
|
||||
},
|
||||
{
|
||||
dataKey: '',
|
||||
title: '启用会签',
|
||||
required: false,
|
||||
hidden: false,
|
||||
field: 'auditMethod',//审批方式
|
||||
data: [
|
||||
{ key: 1, value: '是' },
|
||||
{ key: 0, value: '否' }
|
||||
],
|
||||
type: 'radio'
|
||||
}
|
||||
],
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
nameClick(index) {
|
||||
this.index = index;
|
||||
},
|
||||
/**
|
||||
* 表单修改,这里可以根据传入的ID进行业务信息获取
|
||||
* @param data
|
||||
* @param id
|
||||
*/
|
||||
nodeInit(data, id,tableName) {
|
||||
this.tableName=tableName;
|
||||
this.type = 'node'
|
||||
this.data = data;
|
||||
// this.tableName=data.
|
||||
data.nodeList.filter((node) => {
|
||||
if (node.id === id) {
|
||||
this.formRules.forEach(options => {
|
||||
options.forEach(c => {
|
||||
if (c.field != 'name') {
|
||||
c.hidden = node.type == 'start' || node.type == 'end';
|
||||
}
|
||||
})
|
||||
})
|
||||
if (!node.filters) {
|
||||
node.filters=[];
|
||||
}
|
||||
this.node = node;// cloneDeep(node)
|
||||
if (node.type != 'start' && node.type != 'end') {
|
||||
this.nodeTypeChange(node.auditType);
|
||||
}
|
||||
}
|
||||
})
|
||||
// data.nodeList.filter((node) => {
|
||||
// if (node.id === id) {
|
||||
// let _node = cloneDeep(node);
|
||||
// _node.roleId = _node.roleId || null;
|
||||
// _node.userId = _node.userId || null;
|
||||
// _node.nodeType = (_node.nodeType || 1) * 1;
|
||||
// if (!node.filters) {
|
||||
// node.filters = [];
|
||||
// }
|
||||
// _node.filters = node.filters;
|
||||
// this.nodeTypeChange(_node.nodeType);
|
||||
// Object.assign(this.node, _node);
|
||||
// }
|
||||
// });
|
||||
},
|
||||
nodeTypeChange(value) {
|
||||
// { key: 1, value: '按用户审批' },
|
||||
// { key: 2, value: '按角色审批' },
|
||||
// { key: 3, value: '按部门审批' }
|
||||
this.formRules.forEach((options) => {
|
||||
options.forEach((option) => {
|
||||
if (option.field == 'userId') {
|
||||
option.hidden = value != 1;
|
||||
} else if (option.field == 'roleId') {
|
||||
option.hidden = value != 2;
|
||||
} else if (option.field == 'deptId') {
|
||||
option.hidden = value != 3;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
lineInit(line) {
|
||||
this.type = 'line'
|
||||
this.line = line
|
||||
},
|
||||
// 修改连线
|
||||
saveLine() {
|
||||
this.$emit('setLineLabel', this.line.from, this.line.to, this.line.label)
|
||||
},
|
||||
save() {
|
||||
this.data.nodeList.filter((node) => {
|
||||
if (node.id === this.node.id) {
|
||||
node.name = this.node.name;
|
||||
node.left = this.node.left;
|
||||
node.top = this.node.top;
|
||||
node.ico = this.node.ico;
|
||||
node.state = this.node.state;
|
||||
node.stepValue = this.node.stepValue;
|
||||
this.$emit('repaintEverything', this.node);
|
||||
}
|
||||
|
||||
});
|
||||
this.$message.success('保存成功')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.el-node-form-tag {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-left: -15px;
|
||||
height: 40px;
|
||||
width: 15px;
|
||||
background-color: #fbfbfb;
|
||||
border: 1px solid rgb(220, 227, 232);
|
||||
border-right: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.btns {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
|
||||
buttton {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.ef-node-pmenu-item {
|
||||
display: flex;
|
||||
|
||||
.name {
|
||||
cursor: pointer;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #0659e8;
|
||||
}
|
||||
}
|
||||
|
||||
.form-info ::v-deep(.mes-form-item) {
|
||||
display: flex;
|
||||
|
||||
.el-form-item:nth-child(2),
|
||||
.el-form-item:nth-child(3),
|
||||
.el-form-item:nth-child(4) {
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
126
src/components/workflow/node_menu.vue
Normal file
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div class="flow-menu" ref="tool">
|
||||
<div v-for="menu in menuList" :key="menu.id">
|
||||
<div class="ef-node-pmenu-item"><i class="el-icon-notebook-2"></i>节点配置</div>
|
||||
<ul v-show="menu.open" class="ef-node-menu-ul">
|
||||
<draggable @end="end" @start="move" v-model="menu.children" :options="draggableOptions">
|
||||
<li v-for="subMenu in menu.children" class="ef-node-menu-li" :key="subMenu.id" :type="subMenu.type">
|
||||
<i :class="subMenu.ico"></i> {{ subMenu.name }}
|
||||
</li>
|
||||
</draggable>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { VueDraggableNext as draggable } from "vue-draggable-next";
|
||||
|
||||
var mousePosition = {
|
||||
left: -1,
|
||||
top: -1
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
activeNames: '1',
|
||||
// draggable配置参数参考 https://www.cnblogs.com/weixin186/p/10108679.html
|
||||
draggableOptions: {
|
||||
preventOnFilter: false,
|
||||
sort: false,
|
||||
disabled: false,
|
||||
ghostClass: 'tt',
|
||||
// 不使用H5原生的配置
|
||||
forceFallback: true,
|
||||
// 拖拽的时候样式
|
||||
// fallbackClass: 'flow-node-draggable'
|
||||
},
|
||||
// 默认打开的左侧菜单的id
|
||||
defaultOpeneds: ['1', '2'],
|
||||
menuList: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'group',
|
||||
name: '开始节点',
|
||||
ico: 'el-icon-video-play',
|
||||
open: true,
|
||||
children: [
|
||||
{
|
||||
id: '0',
|
||||
type: 'start',
|
||||
name: '流程开始',
|
||||
ico: 'el-icon-time',
|
||||
// 自定义覆盖样式
|
||||
style: {}
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
type: 'end',
|
||||
name: '流程结束',
|
||||
ico: 'el-icon-switch-button',
|
||||
// 自定义覆盖样式
|
||||
style: {}
|
||||
}, {
|
||||
id: '2',
|
||||
type: 'node',
|
||||
name: '流程节点',
|
||||
ico: 'el-icon-news',
|
||||
// 自定义覆盖样式
|
||||
style: {}
|
||||
}
|
||||
]
|
||||
}],
|
||||
|
||||
nodeMenu: {}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
created() {
|
||||
/**
|
||||
* 以下是为了解决在火狐浏览器上推拽时弹出tab页到搜索问题
|
||||
* @param event
|
||||
*/
|
||||
if (this.isFirefox()) {
|
||||
document.body.ondrop = function (event) {
|
||||
// 解决火狐浏览器无法获取鼠标拖拽结束的坐标问题
|
||||
mousePosition.left = event.layerX
|
||||
mousePosition.top = event.clientY - 50
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 根据类型获取左侧菜单对象
|
||||
getMenuByType(type) {
|
||||
for (let i = 0; i < this.menuList.length; i++) {
|
||||
let children = this.menuList[i].children;
|
||||
for (let j = 0; j < children.length; j++) {
|
||||
if (children[j].type === type) {
|
||||
return children[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 拖拽开始时触发
|
||||
move(evt, a, b, c) {
|
||||
var type = evt.item.attributes.type.nodeValue
|
||||
this.nodeMenu = this.getMenuByType(type)
|
||||
},
|
||||
// 拖拽结束时触发
|
||||
end(evt, e) {
|
||||
this.$emit('addNode', evt, this.nodeMenu, mousePosition)
|
||||
},
|
||||
// 是否是火狐浏览器
|
||||
isFirefox() {
|
||||
var userAgent = navigator.userAgent
|
||||
if (userAgent.indexOf("Firefox") > -1) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
594
src/components/workflow/panel.vue
Normal file
@@ -0,0 +1,594 @@
|
||||
<!-- 审核流程插件基于https://gitee.com/xiaoka2017/easy-flow修改-->
|
||||
<!--感谢萌级小菜鸟 / easy-flow -->
|
||||
<template>
|
||||
<div v-if="easyFlowVisible" class="flow-panel">
|
||||
|
||||
<div style="display: flex;height: 100%;position: relative;">
|
||||
<el-scrollbar style="height: 100%;border-right: 1px solid rgb(220, 227, 232);">
|
||||
<div style="width: 220px;">
|
||||
<div class="ef-node-pmenu-item"><i class="el-icon-warning-outline"></i>基础信息</div>
|
||||
<MesForm ref="form" style="padding: 10px;" :label-width="180" :loadKey="true" :formFields="formFields"
|
||||
:formRules="formRules"></MesForm>
|
||||
<node-menu @addNode="addNode" ref="nodeMenu"></node-menu>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<div class="tools">
|
||||
<el-button circle @click="zoomAdd"><i class="el-icon-zoom-in"></i></el-button>
|
||||
<el-button circle @click="zoomSub"><i class="el-icon-zoom-out"></i></el-button>
|
||||
</div>
|
||||
<div style="flex: 1;" id="efContainer" ref="efContainer" class="container efContainer" v-flowDrag>
|
||||
|
||||
<template :key="node.id" v-for="node in data.nodeList">
|
||||
<flow-node :id="node.id" @delNode="deleteNode(node.id)" :node="node" :activeElement="activeElement"
|
||||
@changeNodeSite="changeNodeSite" @nodeRightMenu="nodeRightMenu" @clickNode="clickNode">
|
||||
</flow-node>
|
||||
</template>
|
||||
<!-- 给画布一个默认的宽度和高度 -->
|
||||
<div style="position:absolute;top: 3000px;left: 4000px;"> </div>
|
||||
</div>
|
||||
<!-- 右侧表单 -->
|
||||
<div style="width: 400px;border-left: 1px solid #dce3e8;background-color: #FBFBFB">
|
||||
<el-scrollbar style="height: 100%;padding-bottom: 10px;">
|
||||
<flow-node-form @delNode="deleteNode" ref="nodeForm" @setLineLabel="setLineLabel"
|
||||
@repaintEverything="repaintEverything"></flow-node-form>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { VueDraggableNext as draggable } from "vue-draggable-next";
|
||||
// import { jsPlumb } from 'jsplumb'
|
||||
// 使用修改后的jsplumb
|
||||
import './jsplumb'
|
||||
import { easyFlowMixin } from './mixins'
|
||||
import flowNode from './node'
|
||||
import nodeMenu from './node_menu'
|
||||
import FlowNodeForm from './node_form'
|
||||
import lodash from 'lodash'
|
||||
// import { getDataA } from './data_A'
|
||||
import MesForm from '@/components/basic/MesForm.vue';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
formFields: {
|
||||
WorkName: '',
|
||||
WorkTable: '',
|
||||
WorkTableName: '',
|
||||
Weight:1,
|
||||
AuditingEdit: 0,
|
||||
Remark: ''
|
||||
},
|
||||
formRules: [
|
||||
[
|
||||
{
|
||||
dataKey: '流程名称',
|
||||
title: '流程名称',
|
||||
field: 'WorkName',
|
||||
required: true
|
||||
}],
|
||||
[{
|
||||
dataKey: '',
|
||||
title: '流程实例',
|
||||
required: true,
|
||||
field: 'WorkTable',
|
||||
data: [],
|
||||
readonly: false,
|
||||
type: 'select',
|
||||
onChange: (value, item) => {
|
||||
this.formRules.forEach((options) => {
|
||||
options.forEach((option) => {
|
||||
if (option.field == 'WorkTable') {
|
||||
this.formFields.WorkTableName = option.data.find((x) => {
|
||||
return x.key == value;
|
||||
}).value;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}],
|
||||
[{
|
||||
title: '权重(相同条件权重大优先)',
|
||||
field: 'Weight',
|
||||
type: "number",
|
||||
}
|
||||
],
|
||||
|
||||
[{
|
||||
title: '审核中数据是否可以编辑',
|
||||
field: 'AuditingEdit',
|
||||
type: "switch",
|
||||
data: [{ key: 0, value: "否" }, { key: 1, value: "是" }]
|
||||
}
|
||||
],
|
||||
[{
|
||||
title: '备注',
|
||||
field: 'Remark'
|
||||
}
|
||||
]
|
||||
],
|
||||
// jsPlumb 实例
|
||||
jsPlumb: null,
|
||||
// 控制画布销毁
|
||||
easyFlowVisible: true,
|
||||
// 是否加载完毕标志位
|
||||
loadEasyFlowFinish: false,
|
||||
// 数据
|
||||
data: {},
|
||||
// 激活的元素、可能是节点、可能是连线
|
||||
activeElement: {
|
||||
// 可选值 node 、line
|
||||
type: undefined,
|
||||
// 节点ID
|
||||
nodeId: undefined,
|
||||
// 连线ID
|
||||
sourceId: undefined,
|
||||
targetId: undefined
|
||||
},
|
||||
zoom: 1
|
||||
}
|
||||
},
|
||||
// 一些基础配置移动该文件中
|
||||
mixins: [easyFlowMixin],
|
||||
components: {
|
||||
draggable, flowNode, nodeMenu, FlowNodeForm, MesForm
|
||||
},
|
||||
directives: {
|
||||
'flowDrag': {
|
||||
mounted(el, binding, vnode, oldNode) {
|
||||
if (!binding) {
|
||||
return
|
||||
}
|
||||
el.onmousedown = (e) => {
|
||||
if (e.button == 2) {
|
||||
// 右键不管
|
||||
return
|
||||
}
|
||||
// 鼠标按下,计算当前原始距离可视区的高度
|
||||
let disX = e.clientX
|
||||
let disY = e.clientY
|
||||
el.style.cursor = 'move'
|
||||
|
||||
document.onmousemove = function (e) {
|
||||
// 移动时禁止默认事件
|
||||
e.preventDefault()
|
||||
const left = e.clientX - disX
|
||||
disX = e.clientX
|
||||
el.scrollLeft += -left
|
||||
|
||||
const top = e.clientY - disY
|
||||
disY = e.clientY
|
||||
el.scrollTop += -top
|
||||
}
|
||||
|
||||
document.onmouseup = function (e) {
|
||||
el.style.cursor = 'auto'
|
||||
document.onmousemove = null
|
||||
document.onmouseup = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.jsPlumb = jsPlumb.getInstance()
|
||||
// this.$nextTick(() => {
|
||||
// // 默认加载流程A的数据、在这里可以根据具体的业务返回符合流程数据格式的数据即可
|
||||
// this.dataReload(getDataA())
|
||||
// })
|
||||
},
|
||||
created() {
|
||||
this.http.get('api/Sys_WorkFlow/getTableInfo').then((result) => {
|
||||
this.formRules.forEach((options) => {
|
||||
options.forEach((option) => {
|
||||
if (option.field == 'WorkTable') {
|
||||
option.data = result;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
this.$store.getters.data().flowTable = this.formFields;
|
||||
},
|
||||
methods: {
|
||||
// 返回唯一标识
|
||||
getUUID() {
|
||||
return Math.random().toString(36).substr(3, 10)
|
||||
},
|
||||
jsPlumbInit() {
|
||||
this.jsPlumb.ready(() => {
|
||||
// 导入默认配置
|
||||
this.jsPlumb.importDefaults(this.jsplumbSetting)
|
||||
// 会使整个jsPlumb立即重绘。
|
||||
this.jsPlumb.setSuspendDrawing(false, true);
|
||||
// 初始化节点
|
||||
this.loadEasyFlow()
|
||||
// 单点击了连接线, https://www.cnblogs.com/ysx215/p/7615677.html
|
||||
this.jsPlumb.bind('click', (conn, originalEvent) => {
|
||||
this.activeElement.type = 'line'
|
||||
this.activeElement.sourceId = conn.sourceId
|
||||
this.activeElement.targetId = conn.targetId
|
||||
this.$refs.nodeForm.lineInit({
|
||||
from: conn.sourceId,
|
||||
to: conn.targetId,
|
||||
label: conn.getLabel()
|
||||
})
|
||||
this.deleteElement();
|
||||
})
|
||||
// 连线
|
||||
this.jsPlumb.bind("connection", (evt) => {
|
||||
let from = evt.source.id
|
||||
let to = evt.target.id
|
||||
if (this.loadEasyFlowFinish) {
|
||||
this.data.lineList.push({ from: from, to: to })
|
||||
}
|
||||
})
|
||||
|
||||
// 删除连线回调
|
||||
this.jsPlumb.bind("connectionDetached", (evt) => {
|
||||
this.deleteLine(evt.sourceId, evt.targetId)
|
||||
})
|
||||
|
||||
// 改变线的连接节点
|
||||
this.jsPlumb.bind("connectionMoved", (evt) => {
|
||||
this.changeLine(evt.originalSourceId, evt.originalTargetId)
|
||||
})
|
||||
|
||||
// 连线右击
|
||||
this.jsPlumb.bind("contextmenu", (evt) => {
|
||||
console.log('contextmenu', evt)
|
||||
})
|
||||
|
||||
// 连线
|
||||
this.jsPlumb.bind("beforeDrop", (evt) => {
|
||||
let from = evt.sourceId
|
||||
let to = evt.targetId
|
||||
if (from === to) {
|
||||
this.$message.error('节点不支持连接自己')
|
||||
return false
|
||||
}
|
||||
if (this.hasLine(from, to)) {
|
||||
this.$message.error('该关系已存在,不允许重复创建')
|
||||
return false
|
||||
}
|
||||
if (this.hashOppositeLine(from, to)) {
|
||||
this.$message.error('不支持两个节点之间连线回环');
|
||||
return false
|
||||
}
|
||||
this.$message.success('连接成功')
|
||||
setTimeout(() => { this.setLineLabel(from, to, 'x') }, 50)
|
||||
return true
|
||||
})
|
||||
|
||||
// beforeDetach
|
||||
this.jsPlumb.bind("beforeDetach", (evt) => {
|
||||
console.log('beforeDetach', evt)
|
||||
})
|
||||
this.jsPlumb.setContainer(this.$refs.efContainer)
|
||||
})
|
||||
},
|
||||
// 加载流程图
|
||||
loadEasyFlow() {
|
||||
// 初始化节点
|
||||
for (var i = 0; i < this.data.nodeList.length; i++) {
|
||||
let node = this.data.nodeList[i]
|
||||
// 设置源点,可以拖出线连接其他节点
|
||||
this.jsPlumb.makeSource(node.id, lodash.merge(this.jsplumbSourceOptions, {}))
|
||||
// // 设置目标点,其他源点拖出的线可以连接该节点
|
||||
this.jsPlumb.makeTarget(node.id, this.jsplumbTargetOptions)
|
||||
if (!node.viewOnly) {
|
||||
this.jsPlumb.draggable(node.id, {
|
||||
containment: 'parent',
|
||||
stop: function (el) {
|
||||
// 拖拽节点结束后的对调
|
||||
console.log('拖拽结束: ', el)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// 初始化连线
|
||||
for (var i = 0; i < this.data.lineList.length; i++) {
|
||||
let line = this.data.lineList[i]
|
||||
var connParam = {
|
||||
source: line.from,
|
||||
target: line.to,
|
||||
label: line.label ? line.label : 'x',
|
||||
connector: line.connector ? line.connector : '',
|
||||
anchors: line.anchors ? line.anchors : undefined,
|
||||
|
||||
paintStyle: line.paintStyle ? line.paintStyle : undefined,
|
||||
}
|
||||
this.jsPlumb.connect(connParam, this.jsplumbConnectOptions)
|
||||
}
|
||||
this.$nextTick(function () {
|
||||
this.loadEasyFlowFinish = true
|
||||
})
|
||||
},
|
||||
// 设置连线条件
|
||||
setLineLabel(from, to, label) {
|
||||
var conn = this.jsPlumb.getConnections({
|
||||
source: from,
|
||||
target: to
|
||||
})[0]
|
||||
if (!label || label === '') {
|
||||
conn.removeClass('flowLabel ')
|
||||
conn.addClass('emptyFlowLabel')
|
||||
} else {
|
||||
conn.addClass('flowLabel')
|
||||
}
|
||||
conn.setLabel({
|
||||
label: 'x' //label,
|
||||
})
|
||||
this.data.lineList.forEach(function (line) {
|
||||
if (line.from == from && line.to == to) {
|
||||
line.label = 'x'// label
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
// 删除激活的元素
|
||||
deleteElement() {
|
||||
if (this.activeElement.type === 'node') {
|
||||
this.deleteNode(this.activeElement.nodeId)
|
||||
} else if (this.activeElement.type === 'line') {
|
||||
this.$confirm('确定删除所点击的线吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
var conn = this.jsPlumb.getConnections({
|
||||
source: this.activeElement.sourceId,
|
||||
target: this.activeElement.targetId
|
||||
})[0]
|
||||
this.jsPlumb.deleteConnection(conn)
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
},
|
||||
// 删除线
|
||||
deleteLine(from, to) {
|
||||
this.data.lineList = this.data.lineList.filter(function (line) {
|
||||
if (line.from == from && line.to == to) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
},
|
||||
// 改变连线
|
||||
changeLine(oldFrom, oldTo) {
|
||||
this.deleteLine(oldFrom, oldTo)
|
||||
},
|
||||
// 改变节点的位置
|
||||
changeNodeSite(data) {
|
||||
for (var i = 0; i < this.data.nodeList.length; i++) {
|
||||
let node = this.data.nodeList[i]
|
||||
if (node.id === data.nodeId) {
|
||||
node.left = data.left
|
||||
node.top = data.top
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 拖拽结束后添加新的节点
|
||||
* @param evt
|
||||
* @param nodeMenu 被添加的节点对象
|
||||
* @param mousePosition 鼠标拖拽结束的坐标
|
||||
*/
|
||||
addNode(evt, nodeMenu, mousePosition) {
|
||||
if (nodeMenu.type == 'start' && this.data.nodeList.some(x => { return x.type == 'start' })) {
|
||||
this.$message.error('【流程结束】节点已存在,只有选择一个流程开始节点');
|
||||
return
|
||||
}
|
||||
if (nodeMenu.type == 'end' && this.data.nodeList.some(x => { return x.type == 'end' })) {
|
||||
this.$message.error('【流程结束】节点已存在,只有选择一个流程开始节点');
|
||||
return
|
||||
}
|
||||
var screenX = evt.originalEvent.clientX, screenY = evt.originalEvent.clientY
|
||||
let efContainer = this.$refs.efContainer
|
||||
var containerRect = efContainer.getBoundingClientRect()
|
||||
var left = screenX, top = screenY
|
||||
// 计算是否拖入到容器中
|
||||
if (left < containerRect.x || left > containerRect.width + containerRect.x || top < containerRect.y || containerRect.y > containerRect.y + containerRect.height) {
|
||||
this.$message.error("请把节点拖入到画布中")
|
||||
return
|
||||
}
|
||||
left = left - containerRect.x + efContainer.scrollLeft
|
||||
top = top - containerRect.y + efContainer.scrollTop
|
||||
// 居中
|
||||
left -= 85
|
||||
top -= 16
|
||||
var nodeId = this.getUUID()
|
||||
// 动态生成名字
|
||||
var origName = nodeMenu.name
|
||||
var nodeName = origName
|
||||
var index = 1
|
||||
while (index < 10000) {
|
||||
var repeat = false
|
||||
for (var i = 0; i < this.data.nodeList.length; i++) {
|
||||
let node = this.data.nodeList[i]
|
||||
if (node.name === nodeName) {
|
||||
nodeName = origName + index
|
||||
repeat = true
|
||||
}
|
||||
}
|
||||
if (repeat) {
|
||||
index++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
var node = {
|
||||
id: nodeId,
|
||||
name: nodeName,
|
||||
type: nodeMenu.type,
|
||||
left: left + 'px',
|
||||
top: top + 'px',
|
||||
ico: nodeMenu.ico,
|
||||
state: 'success'
|
||||
}
|
||||
/**
|
||||
* 这里可以进行业务判断、是否能够添加该节点
|
||||
*/
|
||||
this.data.nodeList.push(node)
|
||||
this.$nextTick(function () {
|
||||
this.jsPlumb.makeSource(nodeId, this.jsplumbSourceOptions)
|
||||
this.jsPlumb.makeTarget(nodeId, this.jsplumbTargetOptions)
|
||||
this.jsPlumb.draggable(nodeId, {
|
||||
containment: 'parent',
|
||||
stop: function (el) {
|
||||
// 拖拽节点结束后的对调
|
||||
console.log('拖拽结束: ', el)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 删除节点
|
||||
* @param nodeId 被删除节点的ID
|
||||
*/
|
||||
deleteNode(nodeId) {
|
||||
this.$confirm('确定要删除节点' + nodeId + '?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
closeOnClickModal: false
|
||||
}).then(() => {
|
||||
/**
|
||||
* 这里需要进行业务判断,是否可以删除
|
||||
*/
|
||||
this.data.nodeList = this.data.nodeList.filter(function (node) {
|
||||
if (node.id === nodeId) {
|
||||
// 伪删除,将节点隐藏,否则会导致位置错位
|
||||
// node.show = false
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
this.$nextTick(function () {
|
||||
this.jsPlumb.removeAllEndpoints(nodeId);
|
||||
})
|
||||
}).catch(() => {
|
||||
})
|
||||
return true
|
||||
},
|
||||
clickNode(nodeId) {
|
||||
this.activeElement.type = 'node'
|
||||
this.activeElement.nodeId = nodeId
|
||||
this.$refs.nodeForm.nodeInit(this.data, nodeId, this.formFields.WorkTable)
|
||||
},
|
||||
// 是否具有该线
|
||||
hasLine(from, to) {
|
||||
for (var i = 0; i < this.data.lineList.length; i++) {
|
||||
var line = this.data.lineList[i]
|
||||
if (line.from === from && line.to === to) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
// 是否含有相反的线
|
||||
hashOppositeLine(from, to) {
|
||||
return this.hasLine(to, from)
|
||||
},
|
||||
nodeRightMenu(nodeId, evt) {
|
||||
this.menu.show = true
|
||||
this.menu.curNodeId = nodeId
|
||||
this.menu.left = evt.x + 'px'
|
||||
this.menu.top = evt.y + 'px'
|
||||
},
|
||||
repaintEverything(node) {
|
||||
let _node = this.data.nodeList.find((x) => {
|
||||
return x.id == node.id;
|
||||
});
|
||||
Object.assign(_node, node);
|
||||
console.log(_node);
|
||||
this.jsPlumb.repaint();
|
||||
},
|
||||
// 加载流程图
|
||||
dataReload(data, isAdd) {
|
||||
this.easyFlowVisible = false
|
||||
this.data.nodeList = []
|
||||
this.data.lineList = []
|
||||
this.$nextTick(() => {
|
||||
data = lodash.cloneDeep(data)
|
||||
this.easyFlowVisible = true
|
||||
this.data = data
|
||||
this.$nextTick(() => {
|
||||
this.jsPlumb = jsPlumb.getInstance()
|
||||
this.$nextTick(() => {
|
||||
this.jsPlumbInit()
|
||||
})
|
||||
})
|
||||
})
|
||||
this.formRules.forEach(options => {
|
||||
options.forEach(option => {
|
||||
if (option.field == "WorkTable") {
|
||||
option.readonly = !isAdd;
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
zoomAdd() {
|
||||
if (this.zoom >= 1) {
|
||||
return
|
||||
}
|
||||
this.zoom = this.zoom + 0.1
|
||||
this.$refs.efContainer.style.zoom = this.zoom;
|
||||
// this.jsPlumb.setZoom(this.zoom)
|
||||
},
|
||||
zoomSub() {
|
||||
if (this.zoom <= 0) {
|
||||
return
|
||||
}
|
||||
this.zoom = this.zoom - 0.1;
|
||||
if (this.zoom < 0.3) {
|
||||
this.zoom = 0.3;
|
||||
}
|
||||
this.$refs.efContainer.style.zoom = this.zoom;
|
||||
// this.jsPlumb.setZoom(this.zoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
@import './index.css';
|
||||
|
||||
.flow-panel {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.flow-panel ::v-deep(.el-form-item__label) {
|
||||
margin-bottom: -2px !important;
|
||||
text-align: left;
|
||||
padding: 0 !important;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.flow-panel ::v-deep(.el-form-item) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 7px !important;
|
||||
|
||||
}
|
||||
|
||||
.ef-node-menu-form {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 0px;
|
||||
background: #e0e3e7;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
</style>
|
||||
29
src/components/workflow/utils.js
Normal file
@@ -0,0 +1,29 @@
|
||||
// 是否具有该线
|
||||
export function hasLine(data, from, to) {
|
||||
for (let i = 0; i < data.lineList.length; i++) {
|
||||
let line = data.lineList[i]
|
||||
if (line.from === from && line.to === to) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 是否含有相反的线
|
||||
export function hashOppositeLine(data, from, to) {
|
||||
return hasLine(data, to, from)
|
||||
}
|
||||
|
||||
// 获取连线
|
||||
export function getConnector(jsp, from, to) {
|
||||
let connection = jsp.getConnections({
|
||||
source: from,
|
||||
target: to
|
||||
})[0]
|
||||
return connection
|
||||
}
|
||||
|
||||
// 获取唯一标识
|
||||
export function uuid() {
|
||||
return Math.random().toString(36).substr(3, 10)
|
||||
}
|
||||
73
src/extension/bi/bimanage/Bi_db_dim.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: '',
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
88
src/extension/bi/bimanage/Bi_db_set.js
Normal file
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: '',
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
this.buttons.splice(3,0,{ //也可以用push或者splice方法来修改buttons数组
|
||||
name: '设计', //按钮名称
|
||||
icon: 'el-icon-s-data', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
type: 'warning', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
onClick: function () {
|
||||
let selectRow = this.$refs.table.getSelected();
|
||||
if (selectRow.length == 0) {
|
||||
return this.$error('请选择要设计的行!');
|
||||
}
|
||||
if (selectRow.length != 1) {
|
||||
return this.$error('只能选择一行数据进行设计!');
|
||||
}
|
||||
window.open(this.http.ipAddress + 'BiManage/AppPage/DATABI/DSETEDIT.html?ID=' + selectRow[0].ID + "&token=" + this.$store.getters.getToken(),'_blank')
|
||||
}
|
||||
});
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
123
src/extension/bi/bimanage/Bi_db_source.js
Normal file
@@ -0,0 +1,123 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: '',
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: {
|
||||
view: [], box:
|
||||
[
|
||||
{
|
||||
name: "连接测试",
|
||||
icon: 'el-icon-question',
|
||||
value: 'Edit',
|
||||
class: '',
|
||||
type: 'success',
|
||||
index: 1,//显示的位置
|
||||
onClick: function () {
|
||||
//this.editFormFields.ID = 0;
|
||||
var param = {
|
||||
P1: JSON.stringify(this.editFormFields),
|
||||
Action: "DATABI_TESTBIDBSOURCE"
|
||||
};
|
||||
this.http.post("/api/Bll/ExeAction", param, "正在执行....").then((resultData) => {
|
||||
if (resultData.ErrorMsg == "" && resultData.Result == '1') {
|
||||
this.$Message.success('连接成功');
|
||||
}
|
||||
else {
|
||||
this.$Message.error(resultData.ErrorMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}], detail: []
|
||||
}, //扩展的按钮
|
||||
methods: {
|
||||
getFormOption(field) {
|
||||
let option;
|
||||
this.editFormOptions.forEach(x => {
|
||||
x.forEach(item => {
|
||||
if (item.field == field) {
|
||||
option = item;
|
||||
}
|
||||
})
|
||||
})
|
||||
return option;
|
||||
},
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
var dbType = this.getFormOption('DBType');
|
||||
this.boxOptions.labelWidth = 120;
|
||||
dbType.onChange = (val, item) => {
|
||||
if (val == "MYSQL") {
|
||||
this.editFormFields["Port"] = 3306;
|
||||
}
|
||||
else {
|
||||
this.editFormFields["Port"] = 1433;
|
||||
}
|
||||
};
|
||||
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
this.boxOptions.height = 500;
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
103
src/extension/bi/bimanage/Bi_db_ybp.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: '',
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
this.buttons.splice(3,0,{ //也可以用push或者splice方法来修改buttons数组
|
||||
name: '设计', //按钮名称
|
||||
icon: 'el-icon-s-data', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
type: 'success', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
onClick: function () {
|
||||
let selectRow = this.$refs.table.getSelected();
|
||||
if (selectRow.length == 0) {
|
||||
return this.$error('请选择要设计的行!');
|
||||
}
|
||||
if (selectRow.length != 1) {
|
||||
return this.$error('只能选择一行数据进行设计!');
|
||||
}
|
||||
window.open(this.http.ipAddress + 'BiManage/AppPage/DATABI/YBPBuild.html?id=' + selectRow[0].ID + "&token=" + this.$store.getters.getToken(),'_blank')
|
||||
}
|
||||
});
|
||||
this.buttons.splice(4,0,{ //也可以用push或者splice方法来修改buttons数组
|
||||
name: '预览', //按钮名称
|
||||
icon: 'el-icon-s-data', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
type: 'warning', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
onClick: function () {
|
||||
let selectRow = this.$refs.table.getSelected();
|
||||
if (selectRow.length == 0) {
|
||||
return this.$error('请选择要预览的行!');
|
||||
}
|
||||
if (selectRow.length != 1) {
|
||||
return this.$error('只能选择一行数据进行预览!');
|
||||
}
|
||||
window.open(this.http.ipAddress + 'BiManage/AppPage/DATABI/YBPVIEW.html?ID=' + selectRow[0].ID + "&token=" + this.$store.getters.getToken(),'_blank')
|
||||
}
|
||||
});
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
88
src/extension/bi/bimanage/Bi_desktop.js
Normal file
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: '',
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
let column = this.columns.find((x) => {
|
||||
return x.field == 'IsDefault';
|
||||
});
|
||||
column.edit = {
|
||||
type: 'switch',
|
||||
keep: true
|
||||
};
|
||||
//是否可用字段设置切换事件并保存到数据库
|
||||
column.onChange = (value, row, tableData) => {
|
||||
let url = `api/Bi_desktop/updateStatus?desktopId=${row.DesktopId}&statusFlag=${row.IsDefault}`;
|
||||
this.http.get(url, {}, true).then((result) => {
|
||||
this.search();
|
||||
this.$Message.success(result);
|
||||
});
|
||||
};
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
174
src/extension/calendar/calendar/Cal_Plan.js
Normal file
@@ -0,0 +1,174 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
import { h, resolveComponent, defineAsyncComponent } from 'vue';
|
||||
import modelBody from "./calendar/Cal_PlanModelBody.vue"
|
||||
import modelHeader from "./calendar/Cal_PlanModelHeader.vue"
|
||||
import modelFooter from "./calendar/Cal_PlanModelFooter.vue"
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: modelHeader,
|
||||
modelBody: modelBody,
|
||||
modelFooter: modelFooter
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
getFormOption(field) {
|
||||
let option;
|
||||
this.editFormOptions.forEach(x => {
|
||||
x.forEach(item => {
|
||||
if (item.field == field) {
|
||||
option = item;
|
||||
}
|
||||
})
|
||||
})
|
||||
return option;
|
||||
},
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
this.boxOptions.height = 450;
|
||||
this.height = this.height - 100;
|
||||
//自定义弹出框的高与宽
|
||||
this.boxOptions.height = document.body.clientHeight * 0.9;
|
||||
this.boxOptions.width = document.body.clientWidth * 0.8;
|
||||
var shiftType = this.getFormOption('ShiftType');
|
||||
shiftType.onChange = (value, option) => {
|
||||
if(value=="BB")
|
||||
{
|
||||
this.$refs.modelBody.$refs.table1.rowData = [
|
||||
{PlanShiftName: "白班",StartTime: "08:00", EndTime: "18:00"}
|
||||
]
|
||||
}
|
||||
else if(value=="LBD")
|
||||
{
|
||||
this.$refs.modelBody.$refs.table1.rowData = [
|
||||
{PlanShiftName: "白班",StartTime: "08:00", EndTime: "20:00"},
|
||||
{PlanShiftName: "夜班",StartTime: "20:00", EndTime: "08:00"}
|
||||
]
|
||||
}
|
||||
else
|
||||
{
|
||||
this.$refs.modelBody.$refs.table1.rowData = [
|
||||
{PlanShiftName: "白班",StartTime: "08:00", EndTime: "16:00"},
|
||||
{PlanShiftName: "中班",StartTime: "16:00", EndTime: "24:00"},
|
||||
{PlanShiftName: "夜班",StartTime: "00:00", EndTime: "08:00"}
|
||||
]
|
||||
}
|
||||
|
||||
};
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
this.setFormData(formData);
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
this.setFormData(formData);
|
||||
return true;
|
||||
},
|
||||
setFormData(formData) { //新建或编辑时,将从表1、2的数据提交到后台,见后台Equip_SpotMaintPlanService的新建方法
|
||||
//后台从对象里直接取extra的值
|
||||
let extra = {
|
||||
table1List: this.$refs.modelBody.$refs.table1.rowData,//获取从表1的行数据
|
||||
table2List: this.$refs.modelBody.$refs.table2.rowData//获取从表2的行数据
|
||||
}
|
||||
formData.extra = JSON.stringify(extra);
|
||||
},
|
||||
resetUpdateFormAfter() { //编辑弹出框时,点重置时,可自定义重置
|
||||
console.log('resetUpdateFormAfter')
|
||||
return true;
|
||||
},
|
||||
resetAddFormAfter() { //新建弹出框时,点重置时,可自定义重置
|
||||
console.log('resetAddFormAfter')
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
if (this.currentAction == 'Add') {
|
||||
this.editFormFields.Status = "1"
|
||||
}
|
||||
this.editFormFields.ChangeShiftType = "DAY"
|
||||
var _button = this.boxButtons.find((x) => {
|
||||
return x.value == 'save';
|
||||
});
|
||||
if(this.currentAction =="update" && row.Status == "2")
|
||||
{
|
||||
_button.disabled= true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_button.disabled= false;
|
||||
};
|
||||
this.editFormOptions.forEach(item => {
|
||||
item.forEach(x => {
|
||||
//如果是编辑设置为只读
|
||||
if (x.field == "PlanCode") {
|
||||
x.placeholder = "请输入,忽略将自动生成";
|
||||
}
|
||||
if (this.currentAction =="update" && row.Status == "2" && (x.field == 'PlanName' || x.field == 'PlanCode' ||x.field == 'TeamType' ||x.field == 'Status' ||x.field == 'StartDate' ||x.field == 'EndDate' ||x.field == 'ShiftType' ||x.field == 'ChangeShiftType' ||x.field == 'Remark') ) {
|
||||
x.readonly = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
x.readonly = false;
|
||||
}
|
||||
if (x.field == "ChangeShiftType") {
|
||||
x.readonly = true;
|
||||
}
|
||||
})
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
//这里没有给弹出框中的表格传参,如果需要参数可以通过 this.$emit("parentCall", 获取页面的参数
|
||||
//具体见自定义页面Equip_SpotMaintPlanModelBody.vue中的modelOpen方法的使用 this.$emit("parentCall", ($this) => {
|
||||
this.$refs.modelBody.modelOpen();
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
73
src/extension/calendar/calendar/Cal_PlanShift.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: '',
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
73
src/extension/calendar/calendar/Cal_PlanTeam.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: '',
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
102
src/extension/calendar/calendar/Cal_Team.js
Normal file
@@ -0,0 +1,102 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
import modelHeader from "./calendar/UserModelBody.vue"
|
||||
import gridFooter from './calendar/UserGridFooter.vue';
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: gridFooter,
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: modelHeader,
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.single = true;
|
||||
this.columnIndex = true;
|
||||
//点击单元格编辑与结束编辑(默认是点击单元格编辑,鼠标离开结束编辑)
|
||||
this.detailOptions.clickEdit = true;
|
||||
this.tableMaxHeight = (document.body.clientHeight - 260) / 2;
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
//明细表选择数据源操作
|
||||
//获取明细表备注列,给备注列添加选择数据操作
|
||||
this.detailOptions.buttons.unshift({
|
||||
name: '选择用户', //按钮名称
|
||||
icon: 'el-icon-plus', //按钮图标,参照iview图标
|
||||
hidden: false, //是否隐藏按钮(如果想要隐藏按钮,在onInited方法中遍历buttons,设置hidden=true)
|
||||
onClick: function () {
|
||||
//触发事件
|
||||
this.$refs.modelHeader.open();
|
||||
}
|
||||
});
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
this.$nextTick(() => {
|
||||
this.$refs.gridFooter.rowClick(result[0], "wareHouse");
|
||||
});
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
//调用Doc_Order1GridFooter.vue文件中(订单明细)的查询
|
||||
this.$refs.gridFooter.rowClick(row);
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
this.editFormOptions.forEach(item => {
|
||||
item.forEach(x => {
|
||||
//如果是编辑设置为只读
|
||||
if (x.field == "TeamCode") {
|
||||
x.placeholder = "请输入,忽略将自动生成";
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
73
src/extension/calendar/calendar/Cal_TeamMember.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: '',
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||
73
src/extension/calendar/calendar/Cal_TeamShift.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/*****************************************************************************************
|
||||
** Author:COCO 2022
|
||||
*****************************************************************************************/
|
||||
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
|
||||
|
||||
let extension = {
|
||||
components: {
|
||||
//查询界面扩展组件
|
||||
gridHeader: '',
|
||||
gridBody: '',
|
||||
gridFooter: '',
|
||||
//新建、编辑弹出框扩展组件
|
||||
modelHeader: '',
|
||||
modelBody: '',
|
||||
modelFooter: ''
|
||||
},
|
||||
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
|
||||
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
|
||||
methods: {
|
||||
//下面这些方法可以保留也可以删除
|
||||
onInit() { //框架初始化配置前,
|
||||
//示例:在按钮的最前面添加一个按钮
|
||||
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
|
||||
// name: '按钮', //按钮名称
|
||||
// icon: 'el-icon-document', //按钮图标vue2版本见iview文档icon,vue3版本见element ui文档icon(注意不是element puls文档)
|
||||
// type: 'primary', //按钮样式vue2版本见iview文档button,vue3版本见element ui文档button
|
||||
// onClick: function () {
|
||||
// this.$Message.success('点击了按钮');
|
||||
// }
|
||||
// });
|
||||
|
||||
//示例:设置修改新建、编辑弹出框字段标签的长度
|
||||
// this.boxOptions.labelWidth = 150;
|
||||
//显示序号(默认隐藏)
|
||||
this.columnIndex = true;
|
||||
},
|
||||
onInited() {
|
||||
//框架初始化配置后
|
||||
//如果要配置明细表,在此方法操作
|
||||
//this.detailOptions.columns.forEach(column=>{ });
|
||||
},
|
||||
searchBefore(param) {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
},
|
||||
searchAfter(result) {
|
||||
//查询后,result返回的查询数据,可以在显示到表格前处理表格的值
|
||||
return true;
|
||||
},
|
||||
addBefore(formData) {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
},
|
||||
updateBefore(formData) {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
},
|
||||
rowClick({ row, column, event }) {
|
||||
//查询界面点击行事件
|
||||
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
|
||||
},
|
||||
modelOpenAfter(row) {
|
||||
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
|
||||
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
|
||||
//(2)给弹出框设置默认值
|
||||
//(3)this.editFormFields.字段='xxx';
|
||||
//如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
|
||||
//看不懂就把输出看:console.log(this.editFormOptions)
|
||||
}
|
||||
}
|
||||
};
|
||||
export default extension;
|
||||