Commit 9e046a07 by zhangdaiscott

Jeecg-Boot 2.2.0 版本发布 | 重磅升级

parent 046831e7
......@@ -7,12 +7,12 @@
Jeecg-Boot 快速开发平台(前后端分离版本)
===============
当前最新版本: 2.1.4(发布日期:2020-02-24
当前最新版本: 2.2.0(发布日期:2020-05-06
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
[![](https://img.shields.io/badge/Author-JEECG团队-orange.svg)](http://www.jeecg.com)
[![](https://img.shields.io/badge/version-2.1.4-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
[![](https://img.shields.io/badge/version-2.2.0-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)
......
Ant Design Jeecg Vue
====
当前最新版本: 2.1.4(发布日期:2020-02-24
当前最新版本: 2.2.0(发布日期:2020-05-06
Overview
----
......
......@@ -20,5 +20,5 @@ module.exports = {
'@router': resolve('src/router'),
'@store': resolve('src/store')
}
}
},
}
\ No newline at end of file
{
"name": "vue-antd-jeecg",
"version": "2.1.4",
"version": "2.2.0",
"private": true,
"scripts": {
"pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ",
"pre": "yarn --registry https://registry.npm.taobao.org || cnpm install || npm install --registry https://registry.npm.taobao.org ",
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@antv/data-set": "^0.10.2",
"@jeecg/antd-online-214": "^2.1.41",
"@antv/data-set": "^0.11.2",
"@jeecg/antd-online-beta220": "^1.0.1",
"@tinymce/tinymce-vue": "^2.0.0",
"ant-design-vue": "^1.4.11",
"apexcharts": "^3.6.5",
"ant-design-vue": "^1.5.2",
"area-data": "^5.0.6",
"axios": "^0.18.0",
"clipboard": "^2.0.4",
"codemirror": "^5.46.0",
......@@ -25,22 +25,20 @@
"md5": "^2.2.1",
"nprogress": "^0.2.0",
"tinymce": "^5.1.4",
"tui-editor": "^1.4.10",
"viser-vue": "^2.4.4",
"vue": "^2.6.10",
"vue-apexcharts": "^1.3.2",
"vue-class-component": "^6.0.0",
"vue-area-linkage": "^5.1.0",
"vue-cropper": "^0.4.8",
"vue-i18n": "^8.7.0",
"vue-loader": "^15.7.0",
"vue-ls": "^3.2.0",
"vue-photo-preview": "^1.1.3",
"vue-print-nb-jeecg": "^1.0.9",
"vue-property-decorator": "^7.3.0",
"vue-router": "^3.0.1",
"vue-splitpane": "^1.0.4",
"vuedraggable": "^2.20.0",
"vuex": "^3.0.1",
"vuex-class": "^0.3.1"
"vuex": "^3.1.0"
},
"devDependencies": {
"@babel/polyfill": "^7.2.5",
......@@ -49,9 +47,10 @@
"@vue/cli-service": "^3.3.0",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.0.1",
"compression-webpack-plugin": "^3.1.0",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.1.0",
"html-webpack-plugin": "^4.0.0-beta.11",
"html-webpack-plugin": "^4.2.0",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"vue-template-compiler": "^2.6.10"
......
......@@ -7679,3 +7679,23 @@ font.medium {
font.weak {
color: #f5222d;
}
// begin -------- JAreaLinkage 三级联动样式 --------------
.cascader-menu-list .cascader-menu-option.hover,
.cascader-menu-list .cascader-menu-option:hover {
background-color: color(~`colorPalette("@{primary-color}", 1)`);
}
.area-selectable-list .area-select-option.hover {
background-color: color(~`colorPalette("@{primary-color}", 1)`);
}
.area-select:hover {
border-color: @primary-color;
}
.area-select:active {
box-shadow: 0 0 0 2px color(~`colorPalette("@{primary-color}", 1)`);
}
// end -------- JAreaLinkage 三级联动样式 --------------
\ No newline at end of file
import Vue from 'vue'
/**
* 将一个请求分组
*
* @param getPromise 传入一个可以获取到Promise对象的方法
* @param groupId 分组ID,如果不传或者为空则不分组
* @param expire 过期时间,默认 半分钟
*/
export function httpGroupRequest(getPromise, groupId, expire = 1000 * 30) {
if (groupId == null || groupId === '') {
console.log("--------popup----------getFrom DB-------with---no--groupId ")
return getPromise()
}
if (Vue.ls.get(groupId)) {
console.log("---------popup--------getFrom Cache--------groupId = " + groupId)
return Promise.resolve(Vue.ls.get(groupId));
} else {
console.log("--------popup----------getFrom DB---------groupId = " + groupId)
}
// 还没有发出请求,就发出第一次的请求
return getPromise().then(res => {
Vue.ls.set(groupId, res, expire);
return Promise.resolve(res);
})
}
import { getAction,deleteAction,putAction,postAction} from '@/api/manage'
import { getAction, deleteAction, putAction, postAction, httpAction } from '@/api/manage'
import Vue from 'vue'
import {UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types"
////根路径
// const doMian = "/jeecg-boot/";
////图片预览请求地址
// const imgView = "http://localhost:8080/jeecg-boot/sys/common/view/";
//角色管理
const addRole = (params)=>postAction("/sys/role/add",params);
const editRole = (params)=>putAction("/sys/role/edit",params);
// const getRoleList = (params)=>getAction("/sys/role/list",params);
// const deleteRole = (params)=>deleteAction("/sys/role/delete",params);
// const deleteRoleList = (params)=>deleteAction("/sys/role/deleteBatch",params);
const checkRoleCode = (params)=>getAction("/sys/role/checkRoleCode",params);
const queryall = (params)=>getAction("/sys/role/queryall",params);
......@@ -19,8 +14,6 @@ const addUser = (params)=>postAction("/sys/user/add",params);
const editUser = (params)=>putAction("/sys/user/edit",params);
const queryUserRole = (params)=>getAction("/sys/user/queryUserRole",params);
const getUserList = (params)=>getAction("/sys/user/list",params);
// const deleteUser = (params)=>deleteAction("/sys/user/delete",params);
// const deleteUserList = (params)=>deleteAction("/sys/user/deleteBatch",params);
const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
//验证用户是否存在
const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
......@@ -31,20 +24,15 @@ const changePassword = (params)=>putAction("/sys/user/changePassword",params);
const addPermission= (params)=>postAction("/sys/permission/add",params);
const editPermission= (params)=>putAction("/sys/permission/edit",params);
const getPermissionList = (params)=>getAction("/sys/permission/list",params);
/*update_begin author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params);
const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params);
const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params)
/*update_end author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
// const deletePermission = (params)=>deleteAction("/sys/permission/delete",params);
// const deletePermissionList = (params)=>deleteAction("/sys/permission/deleteBatch",params);
const queryTreeList = (params)=>getAction("/sys/permission/queryTreeList",params);
const queryTreeListForRole = (params)=>getAction("/sys/role/queryTreeList",params);
const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params);
const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params);
const saveRolePermission = (params)=>postAction("/sys/permission/saveRolePermission",params);
//const queryPermissionsByUser = (params)=>getAction("/sys/permission/queryByUser",params);
const queryPermissionsByUser = (params)=>getAction("/sys/permission/getUserPermissionByToken",params);
const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params);
const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleListByPermId",params);
......@@ -66,24 +54,26 @@ const saveDeptRolePermission = (params)=>postAction("/sys/sysDepartPermission/sa
const queryMyDepartTreeList = (params)=>getAction("/sys/sysDepart/queryMyDeptTreeList",params);
//日志管理
//const getLogList = (params)=>getAction("/sys/log/list",params);
const deleteLog = (params)=>deleteAction("/sys/log/delete",params);
const deleteLogList = (params)=>deleteAction("/sys/log/deleteBatch",params);
//数据字典
const addDict = (params)=>postAction("/sys/dict/add",params);
const editDict = (params)=>putAction("/sys/dict/edit",params);
//const getDictList = (params)=>getAction("/sys/dict/list",params);
const treeList = (params)=>getAction("/sys/dict/treeList",params);
// const delDict = (params)=>deleteAction("/sys/dict/delete",params);
//const getDictItemList = (params)=>getAction("/sys/dictItem/list",params);
const addDictItem = (params)=>postAction("/sys/dictItem/add",params);
const editDictItem = (params)=>putAction("/sys/dictItem/edit",params);
//const delDictItem = (params)=>deleteAction("/sys/dictItem/delete",params);
//const delDictItemList = (params)=>deleteAction("/sys/dictItem/deleteBatch",params);
//字典标签专用(通过code获取字典数组)
export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItems/${code}`,params);
//从缓存中获取字典配置
function getDictItemsFromCache(dictCode) {
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode]) {
let dictItems = Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode];
console.log("-----------getDictItemsFromCache----------dictCode="+dictCode+"---- dictItems=",dictItems)
return dictItems;
}
}
//系统通告
const doReleaseData = (params)=>getAction("/sys/annountCement/doReleaseData",params);
......@@ -91,23 +81,18 @@ const doReovkeData = (params)=>getAction("/sys/annountCement/doReovkeData",param
//获取系统访问量
const getLoginfo = (params)=>getAction("/sys/loginfo",params);
const getVisitInfo = (params)=>getAction("/sys/visitInfo",params);
//数据日志访问
// const getDataLogList = (params)=>getAction("/sys/dataLog/list",params);
// 根据部门主键查询用户信息
const queryUserByDepId = (params)=>getAction("/sys/user/queryUserByDepId",params);
// 查询用户角色表里的所有信息
const queryUserRoleMap = (params)=>getAction("/sys/user/queryUserRoleMap",params);
// 重复校验
const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
// 加载分类字典
const loadCategoryData = (params)=>getAction("/sys/category/loadAllData",params);
const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
//我的通告
const getUserNoticeInfo= (params)=>getAction("/sys/sysAnnouncementSend/getMyAnnouncementSend",params);
export {
// imgView,
// doMian,
addRole,
editRole,
checkRoleCode,
......@@ -147,7 +132,6 @@ export {
getLoginfo,
getVisitInfo,
queryUserByDepId,
queryUserRoleMap,
duplicateCheck,
queryTreeListForRole,
getSystemMenuList,
......@@ -160,7 +144,9 @@ export {
queryTreeListForDeptRole,
queryDeptRolePermission,
saveDeptRolePermission,
queryMyDepartTreeList
queryMyDepartTreeList,
getUserNoticeInfo,
getDictItemsFromCache
}
......
......@@ -56,3 +56,18 @@ export function logout(logoutToken) {
}
})
}
/**
* 第三方登录
* @param token
* @returns {*}
*/
export function thirdLogin(token) {
return axios({
url: `/thirdLogin/getLoginUser/${token}`,
method: 'get',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
}
\ No newline at end of file
import Vue from 'vue'
import { axios } from '@/utils/request'
const api = {
......@@ -113,16 +114,64 @@ export function downFile(url,parameter){
}
/**
* 获取文件访问路径
* 下载文件
* @param url 文件路径
* @param fileName 文件名
* @param parameter
* @returns {*}
*/
export function downloadFile(url, fileName, parameter) {
return downFile(url, parameter).then((data) => {
if (!data || data.size === 0) {
Vue.prototype['$message'].warning('文件下载失败')
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), fileName)
} else {
let url = window.URL.createObjectURL(new Blob([data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) //下载完成移除元素
window.URL.revokeObjectURL(url) //释放掉blob对象
}
})
}
/**
* 文件上传 用于富文本上传图片
* @param url
* @param parameter
* @returns {*}
*/
export function uploadAction(url,parameter){
return axios({
url: url,
data: parameter,
method:'post' ,
headers: {
'Content-Type': 'multipart/form-data', // 文件上传
},
})
}
/**
* 获取文件服务访问路径
* @param avatar
* @param imgerver
* @param str
* @param subStr
* @returns {*}
*/
export function getFileAccessHttpUrl(avatar,imgerver,subStr) {
if(avatar && avatar.indexOf(subStr) != -1 ){
export function getFileAccessHttpUrl(avatar,subStr) {
if(!subStr) subStr = 'http'
if(avatar && avatar.startsWith(subStr)){
return avatar;
}else{
return imgerver + "/" + avatar;
if(avatar && avatar.length>0 && avatar.indexOf('[')==-1){
return window._CONFIG['staticDomainURL'] + "/" + avatar;
}
}
}
.area-zoom-in-top-enter-active,
.area-zoom-in-top-leave-active {
opacity: 1;
transform: scaleY(1);
}
.area-zoom-in-top-enter,
.area-zoom-in-top-leave-active {
opacity: 0;
transform: scaleY(0);
}
.area-select {
box-sizing: border-box;
margin: 0;
padding: 0;
color: rgba(0, 0, 0, 0.65);
font-size: 14px;
font-variant: tabular-nums;
line-height: 1.5;
list-style: none;
font-feature-settings: 'tnum';
position: relative;
outline: 0;
display: block;
background-color: #fff;
border: 1px solid #d9d9d9;
border-top-width: 1.02px;
border-radius: 4px;
outline: none;
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.area-select-wrap .area-select {
display: inline-block;
}
.area-select * {
box-sizing: border-box;
}
.area-select:hover {
border-color: #40a9ff;
border-right-width: 1px !important;
outline: 0;
}
.area-select:active {
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
.area-select.small {
width: 126px;
}
.area-select.medium {
width: 160px;
}
.area-select.large {
width: 194px;
}
.area-select.is-disabled {
background: #eceff5;
cursor: not-allowed;
}
.area-select.is-disabled:hover {
border-color: #e1e2e6;
}
.area-select.is-disabled .area-selected-trigger {
cursor: not-allowed;
}
.area-select .area-selected-trigger {
position: relative;
display: block;
font-size: 14px;
cursor: pointer;
margin: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
height: 100%;
padding: 8px 20px 7px 12px;
}
.area-select .area-select-icon {
position: absolute;
top: 50%;
margin-top: -2px;
right: 6px;
content: "";
width: 0;
height: 0;
border: 6px solid transparent;
border-top-color: rgba(0, 0, 0, 0.25);
transition: all .3s linear;
transform-origin: center;
}
.area-select .area-select-icon.active {
margin-top: -8px;
transform: rotate(180deg);
}
.area-selectable-list-wrap {
position: absolute;
width: 100%;
max-height: 275px;
z-index: 15000;
background-color: #fff;
box-sizing: border-box;
overflow-x: auto;
margin: 2px 0;
border-radius: 4px;
outline: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: opacity 0.15s, transform 0.3s !important;
transform-origin: center top !important;
}
.area-selectable-list {
position: relative;
margin: 0;
padding: 6px 0;
width: 100%;
font-size: 14px;
color: #565656;
list-style: none;
}
.area-selectable-list .area-select-option {
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
padding: 0 15px 0 10px;
height: 32px;
line-height: 32px;
}
.area-selectable-list .area-select-option.hover {
background-color: #e6f7ff;
}
.area-selectable-list .area-select-option.selected {
color: rgba(0, 0, 0, 0.65);
font-weight: 600;
background-color: #efefef;
}
.cascader-menu-list-wrap {
position: absolute;
white-space: nowrap;
z-index: 15000;
background-color: #fff;
box-sizing: border-box;
overflow: hidden;
font-size: 0;
margin: 2px 0;
border-radius: 4px;
outline: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: opacity 0.15s, transform 0.3s !important;
transform-origin: center top !important;
}
.cascader-menu-list {
position: relative;
margin: 0;
font-size: 14px;
color: #565656;
padding: 6px 0;
list-style: none;
display: inline-block;
height: 204px;
overflow-x: hidden;
overflow-y: auto;
min-width: 160px;
vertical-align: top;
background-color: #fff;
border-right: 1px solid #e4e7ed;
}
.cascader-menu-list:last-child {
border-right: none;
}
.cascader-menu-list .cascader-menu-option {
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
padding: 0 15px 0 10px;
height: 32px;
line-height: 32px;
}
.cascader-menu-list .cascader-menu-option.hover,
.cascader-menu-list .cascader-menu-option:hover {
background-color: #e6f7ff;
}
.cascader-menu-list .cascader-menu-option.selected {
color: rgba(0, 0, 0, 0.65);
font-weight: 600;
background-color: #efefef;
}
.cascader-menu-list .cascader-menu-option.cascader-menu-extensible:after {
position: absolute;
top: 50%;
margin-top: -4px;
right: 5px;
content: "";
width: 0;
height: 0;
border: 4px solid transparent;
border-left-color: #a1a4ad;
}
.cascader-menu-list::-webkit-scrollbar,
.area-selectable-list-wrap::-webkit-scrollbar {
width: 8px;
background: transparent;
}
.area-selectable-list-wrap::-webkit-scrollbar-button:vertical:decremen,
.area-selectable-list-wrap::-webkit-scrollbar-button:vertical:end:decrement,
.area-selectable-list-wrap::-webkit-scrollbar-button:vertical:increment,
.area-selectable-list-wrap::-webkit-scrollbar-button:vertical:start:increment,
.cascader-menu-list::-webkit-scrollbar-button:vertical:decremen,
.cascader-menu-list::-webkit-scrollbar-button:vertical:end:decrement,
.cascader-menu-list::-webkit-scrollbar-button:vertical:increment,
.cascader-menu-list::-webkit-scrollbar-button:vertical:start:increment {
display: none;
}
.cascader-menu-list::-webkit-scrollbar-thumb:vertical,
.area-selectable-list-wrap::-webkit-scrollbar-thumb:vertical {
background-color: #b8b8b8;
border-radius: 4px;
}
.cascader-menu-list::-webkit-scrollbar-thumb:vertical:hover,
.area-selectable-list-wrap::-webkit-scrollbar-thumb:vertical:hover {
background-color: #777;
}
\ No newline at end of file
/** [表格主题样式一] 表格强制列不换行 */
.j-table-force-nowrap {
td, th {
white-space: nowrap;
}
.ant-table-selection-column {
padding: 12px 22px !important;
}
/** 列自适应,弊端会导致列宽失效 */
&.ant-table-wrapper .ant-table-content {
overflow-x: auto;
}
}
/*列表上方操作按钮区域*/
.ant-card-body .table-operator {
margin-bottom: 18px;
margin-bottom: 8px;
}
/** Button按钮间距 */
.table-operator .ant-btn {
margin: 8px 8px 0 0;
margin: 0 8px 8px 0;
}
.table-operator .ant-btn-group .ant-btn {
margin: 0;
}
.table-operator .ant-btn-group .ant-btn:last-child {
margin: 0 8px 8px 0;
}
/*列表td的padding设置 可以控制列表大小*/
.ant-table-tbody .ant-table-row td {
......@@ -45,3 +52,7 @@
/*erp风格子表外框padding设置*/
.ant-card-wider-padding.cust-erp-sub-tab>.ant-card-body{padding:5px 12px}
/* 内嵌子表背景颜色 */
.j-inner-table-wrapper /deep/ .ant-table-expanded-row .ant-table-wrapper .ant-table-tbody .ant-table-row {
background-color: #FFFFFF;
}
\ No newline at end of file
......@@ -8,14 +8,14 @@ const init = (callback) => {
console.log("-------单点登录开始-------");
let token = Vue.ls.get(ACCESS_TOKEN);
let st = getUrlParam("ticket");
var sevice = "http://"+window.location.host+"/";
let sevice = "http://"+window.location.host+"/";
if(token){
loginSuccess(callback);
}else{
if(st){
validateSt(st,sevice,callback);
}else{
var serviceUrl = encodeURIComponent(sevice);
let serviceUrl = encodeURIComponent(sevice);
window.location.href = window._CONFIG['casPrefixUrl']+"/login?service="+serviceUrl;
}
}
......@@ -26,14 +26,14 @@ const SSO = {
};
function getUrlParam(paraName) {
var url = document.location.toString();
var arrObj = url.split("?");
let url = document.location.toString();
let arrObj = url.split("?");
if (arrObj.length > 1) {
var arrPara = arrObj[1].split("&");
var arr;
let arrPara = arrObj[1].split("&");
let arr;
for (var i = 0; i < arrPara.length; i++) {
for (let i = 0; i < arrPara.length; i++) {
arr = arrPara[i].split("=");
if (arr != null && arr[0] == paraName) {
......@@ -57,8 +57,8 @@ function validateSt(ticket,service,callback){
if(res.success){
loginSuccess(callback);
}else{
var sevice = "http://"+window.location.host+"/";
var serviceUrl = encodeURIComponent(sevice);
let sevice = "http://"+window.location.host+"/";
let serviceUrl = encodeURIComponent(sevice);
window.location.href = window._CONFIG['casPrefixUrl']+"/login?service="+serviceUrl;
}
}).catch((err) => {
......
<script>
import Tooltip from 'ant-design-vue/es/tooltip'
import { cutStrByFullLength, getStrFullLength } from '@/components/_util/StringUtil'
/*
const isSupportLineClamp = document.body.style.webkitLineClamp !== undefined;
const TooltipOverlayStyle = {
overflowWrap: 'break-word',
wordWrap: 'break-word',
};
*/
export default {
name: 'Ellipsis',
components: {
Tooltip
},
props: {
prefixCls: {
type: String,
default: 'ant-pro-ellipsis'
},
tooltip: {
type: Boolean
type: Boolean,
default: true,
},
length: {
type: Number,
required: true
default: 25,
},
lines: {
type: Number,
......@@ -36,28 +25,25 @@
default: false
}
},
methods: {
getStrDom (str) {
return (
<span>{ cutStrByFullLength(str, this.length) + '...' }</span>
)
},
getTooltip ( fullStr) {
return (
<Tooltip>
<template slot="title">{ fullStr }</template>
{ this.getStrDom(fullStr) }
</Tooltip>
)
}
},
render () {
methods: {},
render() {
const { tooltip, length } = this.$props
let str = this.$slots.default.map(vNode => vNode.text).join("")
const strDom = tooltip && getStrFullLength(str) > length ? this.getTooltip(str) : this.getStrDom(str);
let text = ''
// 处理没有default插槽时的特殊情况
if (this.$slots.default) {
text = this.$slots.default.map(vNode => vNode.text).join('')
}
// 判断是否显示 tooltip
if (tooltip && getStrFullLength(text) > length) {
return (
strDom
<a-tooltip>
<template slot="title">{text}</template>
<span>{cutStrByFullLength(text, this.length) + '…'}</span>
</a-tooltip>
)
} else {
return (<span>{text}</span>)
}
}
}
</script>
\ No newline at end of file
import { pcaa } from 'area-data'
/**
* 省市区
*/
export default class Area {
/**
* 构造器
* @param express
*/
constructor() {
let arr = []
const province = pcaa['86']
Object.keys(province).map(key=>{
arr.push({id:key, text:province[key], pid:'86'});
const city = pcaa[key];
Object.keys(city).map(key2=>{
arr.push({id:key2, text:city[key2], pid:key});
const qu = pcaa[key2];
Object.keys(qu).map(key3=>{
arr.push({id:key3, text:qu[key3], pid:key2});
})
})
})
this.all = arr;
}
get pca(){
return this.all;
}
getCode(text){
if(!text || text.length==0){
return ''
}
for(let item of this.all){
if(item.text === text){
return item.id;
}
}
}
getText(code){
if(!code || code.length==0){
return ''
}
let arr = []
this.getAreaBycode(code,arr);
return arr.join('/')
}
getRealCode(code){
let arr = []
this.getPcode(code, arr)
return arr;
}
getPcode(id, arr){
for(let item of this.all){
if(item.id === id){
arr.unshift(id)
if(item.pid != '86'){
this.getPcode(item.pid,arr)
}
}
}
}
getAreaBycode(code,arr){
//console.log("this.all.length",this.all)
for(let item of this.all){
if(item.id === code){
arr.unshift(item.text);
this.getAreaBycode(item.pid,arr)
}
}
}
}
\ No newline at end of file
<template>
<div>
<v-chart :forceFit="true" :height="height" :data="data">
<v-coord type="rect" direction="LB" />
<v-tooltip />
<v-legend />
<v-axis dataKey="State" :label="label" />
<v-stack-bar position="State*流程数量" color="流程状态" />
</v-chart>
</div>
</template>
<script>
const DataSet = require('@antv/data-set');
export default {
name: 'StackBar',
props: {
dataSource: {
type: Array,
required: true,
default: () => [
{ 'State': '请假', '流转中': 25, '已归档': 18 },
{ 'State': '出差', '流转中': 30, '已归档': 20 },
{ 'State': '加班', '流转中': 38, '已归档': 42},
{ 'State': '用车', '流转中': 51, '已归档': 67}
]
},
height: {
type: Number,
default: 254
}
},
data() {
return {
label: { offset: 12 }
}
},
computed: {
data() {
const dv = new DataSet.View().source(this.dataSource);
dv.transform({
type: 'fold',
fields: ['流转中', '已归档'],
key: '流程状态',
value: '流程数量',
retains: ['State'],
});
return dv.rows;
}
}
}
</script>
\ No newline at end of file
......@@ -3,6 +3,10 @@
<a-radio v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio>
</a-radio-group>
<a-radio-group v-else-if="tagType=='radioButton'" buttonStyle="solid" @change="handleInput" :value="getValueSting" :disabled="disabled">
<a-radio-button v-for="(item, key) in dictOptions" :key="key" :value="item.value">{{ item.text }}</a-radio-button>
</a-radio-group>
<a-select v-else-if="tagType=='select'" :getPopupContainer = "(target) => target.parentNode" :placeholder="placeholder" :disabled="disabled" :value="getValueSting" @change="handleInput">
<a-select-option :value="undefined">请选择</a-select-option>
<a-select-option v-for="(item, key) in dictOptions" :key="key" :value="item.value">
......@@ -14,7 +18,7 @@
</template>
<script>
import {ajaxGetDictItems} from '@/api/api'
import {ajaxGetDictItems,getDictItemsFromCache} from '@/api/api'
export default {
name: "JDictSelectTag",
......@@ -52,11 +56,17 @@
},
computed: {
getValueSting(){
return this.value ? this.value.toString() : null;
return this.value != null ? this.value.toString() : null;
},
},
methods: {
initDictData() {
//优先从缓存中读取字典配置
if(getDictItemsFromCache(this.dictCode)){
this.dictOptions = getDictItemsFromCache(this.dictCode);
return
}
//根据字典Code, 初始化字典数组
ajaxGetDictItems(this.dictCode, null).then((res) => {
if (res.success) {
......
......@@ -4,7 +4,7 @@
* date: 20190109
*/
import {ajaxGetDictItems} from '@/api/api'
import {ajaxGetDictItems,getDictItemsFromCache} from '@/api/api'
import {getAction} from '@/api/manage'
/**
......@@ -16,6 +16,13 @@ export async function initDictOptions(dictCode) {
if (!dictCode) {
return '字典Code不能为空!';
}
//优先从缓存中读取字典配置
if(getDictItemsFromCache(dictCode)){
let res = {}
res.result = getDictItemsFromCache(dictCode);
res.success = true;
return res;
}
//获取字典数组
let res = await ajaxGetDictItems(dictCode);
return res;
......@@ -28,16 +35,25 @@ export async function initDictOptions(dictCode) {
* @return String
*/
export function filterDictText(dictOptions, text) {
//--update-begin----author:sunjianlei---date:20191025------for:修复字典替换方法在字典没有加载完成之前报错的问题、修复没有找到字典时返回空值的问题---
if (dictOptions instanceof Array) {
// --update-begin----author:sunjianlei---date:20200323------for: 字典翻译 text 允许逗号分隔 ---
if (text != null && dictOptions instanceof Array) {
let result = []
// 允许多个逗号分隔
let splitText = text.toString().trim().split(',')
for (let txt of splitText) {
let dictText = txt
for (let dictItem of dictOptions) {
if (text === dictItem.value) {
return dictItem.text
if (txt === dictItem.value.toString()) {
dictText = dictItem.text
break
}
}
result.push(dictText)
}
return result.join(',')
}
return text
//--update-end----author:sunjianlei---date:20191025------for:修复字典替换方法在字典没有加载完成之前报错的问题、修复没有找到字典时返回空值的问题---
// --update-end----author:sunjianlei---date:20200323------for: 字典翻译 text 允许逗号分隔 ---
}
/**
......@@ -49,26 +65,30 @@ export function filterDictText(dictOptions, text) {
export function filterMultiDictText(dictOptions, text) {
//js “!text” 认为0为空,所以做提前处理
if(text === 0 || text === '0'){
if(dictOptions){
for (let dictItem of dictOptions) {
if (text == dictItem.value) {
return dictItem.text
}
}
}
}
if(!text || !dictOptions || dictOptions.length==0){
if(!text || text=='null' || !dictOptions || dictOptions.length==0){
return ""
}
let re = "";
text = text.toString()
let arr = text.split(",")
dictOptions.forEach(function (option) {
if(option){
for(let i=0;i<arr.length;i++){
if (arr[i] === option.value) {
re += option.text+",";
break;
}
}
}
});
if(re==""){
return text;
......@@ -81,20 +101,42 @@ export function filterMultiDictText(dictOptions, text) {
* @param children
* @returns string
*/
export async function ajaxFilterDictText(dictCode, key) {
export function filterDictTextByCache(dictCode, key) {
if(key==null ||key.length==0){
return;
}
if (!dictCode) {
return '字典Code不能为空!';
}
//console.log(`key : ${key}`);
if (!key) {
return '';
//优先从缓存中读取字典配置
if(getDictItemsFromCache(dictCode)){
let item = getDictItemsFromCache(dictCode).filter(t => t["value"] == key)
if(item && item.length>0){
return item[0]["text"]
}
}
}
/** 通过code获取字典数组 */
export async function getDictItems(dictCode, params) {
//优先从缓存中读取字典配置
if(getDictItemsFromCache(dictCode)){
let desformDictItems = getDictItemsFromCache(dictCode).map(item => ({...item, label: item.text}))
return desformDictItems;
}
//通过请求读取字典文本
let res = await getAction(`/sys/dict/getDictText/${dictCode}/${key}`);
if (res.success) {
// console.log('restult: '+ res.result);
return res.result;
//缓存中没有,就请求后台
return await ajaxGetDictItems(dictCode, params).then(({success, result}) => {
if (success) {
let res = result.map(item => ({...item, label: item.text}))
console.log('------- 从DB中获取到了字典-------dictCode : ', dictCode, res)
return Promise.resolve(res)
} else {
return '';
console.error('getDictItems error: : ', res)
return Promise.resolve([])
}
}).catch((res) => {
console.error('getDictItems error: ', res)
return Promise.resolve([])
})
}
\ No newline at end of file
......@@ -10,6 +10,7 @@
:disabled="disabled"
mode="multiple"
:placeholder="placeholder"
:getPopupContainer="(node) => node.parentNode"
allowClear>
<a-select-option
v-for="(item,index) in dictOptions"
......@@ -24,7 +25,7 @@
</template>
<script>
import {ajaxGetDictItems} from '@/api/api'
import {ajaxGetDictItems,getDictItemsFromCache} from '@/api/api'
export default {
name: 'JMultiSelectTag',
props: {
......@@ -49,12 +50,18 @@
this.tagType = this.type
}
//获取字典数据
this.initDictData();
//this.initDictData();
},
watch:{
options: function(val){
this.setCurrentDictOptions(val);
},
dictCode:{
immediate:true,
handler() {
this.initDictData()
},
},
value (val) {
if(!val){
this.arrayValue = []
......@@ -68,6 +75,11 @@
if(this.options && this.options.length>0){
this.dictOptions = [...this.options]
}else{
//优先从缓存中读取字典配置
if(getDictItemsFromCache(this.dictCode)){
this.dictOptions = getDictItemsFromCache(this.dictCode);
return
}
//根据字典Code, 初始化字典数组
ajaxGetDictItems(this.dictCode, null).then((res) => {
if (res.success) {
......
......@@ -4,6 +4,8 @@
v-if="async"
showSearch
labelInValue
:disabled="disabled"
:getPopupContainer="(node) => node.parentNode"
@search="loadData"
:placeholder="placeholder"
v-model="selectedAsyncValue"
......@@ -19,7 +21,9 @@
<a-select
v-else
:getPopupContainer="(node) => node.parentNode"
showSearch
:disabled="disabled"
:placeholder="placeholder"
optionFilterProp="children"
style="width: 100%"
......@@ -35,7 +39,7 @@
</template>
<script>
import { ajaxGetDictItems } from '@/api/api'
import { ajaxGetDictItems,getDictItemsFromCache } from '@/api/api'
import debounce from 'lodash/debounce';
import { getAction } from '../../api/manage'
......@@ -43,7 +47,7 @@
name: 'JSearchSelectTag',
props:{
disabled: Boolean,
value: String,
value: [String, Number],
dict: String,
dictOptions: Array,
async: Boolean,
......@@ -71,8 +75,12 @@
immediate:true,
handler(val){
if(!val){
if(val==0){
this.initSelectValue()
}else{
this.selectedValue=[]
this.selectedAsyncValue=[]
}
}else{
this.initSelectValue()
}
......@@ -100,7 +108,7 @@
})
}
}else{
this.selectedValue = this.value
this.selectedValue = this.value.toString()
}
},
loadData(value){
......@@ -132,13 +140,30 @@
this.options = [...this.dictOptions]
}else{
//根据字典Code, 初始化字典数组
ajaxGetDictItems(this.dict, null).then((res) => {
let dictStr = ''
if(this.dict){
let arr = this.dict.split(',')
if(arr[0].indexOf('where')>0){
let tbInfo = arr[0].split('where')
dictStr = tbInfo[0].trim()+','+arr[1]+','+arr[2]+','+encodeURIComponent(tbInfo[1])
}else{
dictStr = this.dict
}
if (this.dict.indexOf(",") == -1) {
//优先从缓存中读取字典配置
if (getDictItemsFromCache(this.dictCode)) {
this.options = getDictItemsFromCache(this.dictCode);
return
}
}
ajaxGetDictItems(dictStr, null).then((res) => {
if (res.success) {
this.options = res.result;
}
})
}
}
}
},
filterOption(input, option) {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
......
<template>
<div v-if="!reloading" class="j-area-linkage">
<area-cascader
v-if="_type === enums.type[0]"
:value="innerValue"
:data="pcaa"
:level="1"
:style="{width}"
v-bind="$attrs"
v-on="_listeners"
@change="handleChange"
/>
<area-select
v-else-if="_type === enums.type[1]"
:value="innerValue"
:data="pcaa"
:level="2"
v-bind="$attrs"
v-on="_listeners"
@change="handleChange"
/>
<div v-else>
<span style="color:red;"> Bad type value: {{_type}}</span>
</div>
</div>
</template>
<script>
import { pcaa } from 'area-data'
import Area from '@/components/_util/Area'
export default {
name: 'JAreaLinkage',
props: {
value: {
type: String,
required:false
},
// 组件的类型,可选值:
// select 下拉样式
// cascader 级联样式(默认)
type: {
type: String,
default: 'cascader'
},
width: {
type: String,
default: '100%'
}
},
data() {
return {
pcaa,
innerValue: [],
usedListeners: ['change'],
enums: {
type: ['cascader', 'select']
},
reloading: false,
areaData:''
}
},
computed: {
_listeners() {
let listeners = { ...this.$listeners }
// 去掉已使用的事件,防止冲突
this.usedListeners.forEach(key => {
delete listeners[key]
})
return listeners
},
_type() {
if (this.enums.type.includes(this.type)) {
return this.type
} else {
console.error(`JAreaLinkage的type属性只能接收指定的值(${this.enums.type.join('|')})`)
return this.enums.type[0]
}
},
},
watch: {
value: {
immediate: true,
handler() {
this.loadDataByValue(this.value)
}
},
},
created() {
this.initAreaData();
},
methods: {
/** 通过 value 反推 options */
loadDataByValue(value) {
if(!value || value.length==0){
this.innerValue = []
this.reloading = true;
setTimeout(()=>{
this.reloading = false
},100)
}else{
this.initAreaData();
let arr = this.areaData.getRealCode(value);
this.innerValue = arr
}
},
/** 通过地区code获取子级 */
loadDataByCode(value) {
let options = []
let data = pcaa[value]
if (data) {
for (let key in data) {
if (data.hasOwnProperty(key)) {
options.push({ value: key, label: data[key], })
}
}
return options
} else {
return []
}
},
/** 判断是否有子节点 */
hasChildren(options) {
options.forEach(option => {
let data = this.loadDataByCode(option.value)
option.isLeaf = data.length === 0
})
},
handleChange(values) {
let value = values[values.length - 1]
this.$emit('change', value)
},
initAreaData(){
if(!this.areaData){
this.areaData = new Area();
}
},
},
model: { prop: 'value', event: 'change' },
}
</script>
<style lang="less" scoped>
.j-area-linkage {
height:40px;
/deep/ .area-cascader-wrap .area-select {
width: 100%;
}
/deep/ .area-select .area-selected-trigger {
line-height: 1.15;
}
}
</style>
\ No newline at end of file
......@@ -96,7 +96,7 @@
loadRoot(){
let param = {
pid:this.pid,
pcode:this.pcode,
pcode:!this.pcode?'0':this.pcode,
condition:this.condition
}
getAction(this.url,param).then(res=>{
......@@ -122,8 +122,6 @@
this.treeValue = []
}else{
getAction(this.view,{ids:this.value}).then(res=>{
console.log(124345)
console.log(124345,res)
if(res.success){
let values = this.value.split(',')
this.treeValue = res.result.map((item, index) => ({
......
<template>
<div v-bind="fullScreenParentProps">
<a-icon v-if="fullScreen" class="full-screen-icon" type="fullscreen" @click="()=>fullCoder=!fullCoder"/>
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
<div class="code-editor-cust full-screen-child">
<textarea ref="textarea"></textarea>
......@@ -91,6 +91,7 @@
return {
// 内部真实的内容
code: '',
iconType: 'fullscreen',
hasCode:false,
// 默认的语法类型
mode: 'javascript',
......@@ -155,6 +156,15 @@
}
},
watch: {
fullCoder:{
handler(value) {
if(value){
this.iconType="fullscreen-exit"
}else{
this.iconType="fullscreen"
}
}
},
// value: {
// immediate: false,
// handler(value) {
......@@ -408,6 +418,7 @@
.full-screen-child {
min-height: 120px;
max-height: 320px;
overflow:hidden;
}
}
......
......@@ -51,7 +51,7 @@
},
getCalendarContainer: {
type: Function,
default: () => document.body
default: (node) => node.parentNode
}
},
data () {
......
......@@ -23,6 +23,7 @@
import 'tinymce/plugins/colorpicker'
import 'tinymce/plugins/textcolor'
import 'tinymce/plugins/fullscreen'
import { uploadAction,getFileAccessHttpUrl } from '@/api/manage'
export default {
components: {
Editor
......@@ -65,8 +66,21 @@
menubar: false,
toolbar_drawer: false,
images_upload_handler: (blobInfo, success) => {
let formData = new FormData()
formData.append('file', blobInfo.blob(), blobInfo.filename());
formData.append('biz', "jeditor");
formData.append("jeditor","1");
uploadAction(window._CONFIG['domianURL']+"/sys/common/upload", formData).then((res) => {
if (res.success) {
if(res.message == 'local'){
const img = 'data:image/jpeg;base64,' + blobInfo.base64()
success(img)
}else{
let img = getFileAccessHttpUrl(res.message)
success(img)
}
}
})
}
},
myValue: this.value
......
<template>
<div :class="disabled?'jeecg-form-container-disabled':''">
<fieldset disabled>
<fieldset :disabled="disabled">
<slot name="detail"></slot>
</fieldset>
<slot name="edit"></slot>
......@@ -46,4 +46,16 @@
-ms-pointer-events: none;
pointer-events: none;
}
.jeecg-form-container-disabled .ant-upload-select{display:none}
.jeecg-form-container-disabled .ant-upload-list{cursor:grabbing}
.jeecg-form-container-disabled fieldset[disabled] .ant-upload-list{
-ms-pointer-events: auto !important;
pointer-events: auto !important;
}
.jeecg-form-container-disabled .ant-upload-list-item-actions .anticon-delete,
.jeecg-form-container-disabled .ant-upload-list-item .anticon-close{
display: none;
}
</style>
\ No newline at end of file
<template>
<div class="gc-canvas" @click="reloadPic">
<canvas id="gc-canvas" :width="contentWidth" :height="contentHeight"></canvas>
</div>
</template>
<script>
import { getAction } from '@/api/manage'
export default {
name: 'JGraphicCode',
props: {
length:{
type: Number,
default: 4
},
fontSizeMin: {
type: Number,
default: 20
},
fontSizeMax: {
type: Number,
default: 45
},
backgroundColorMin: {
type: Number,
default: 180
},
backgroundColorMax: {
type: Number,
default: 240
},
colorMin: {
type: Number,
default: 50
},
colorMax: {
type: Number,
default: 160
},
lineColorMin: {
type: Number,
default: 40
},
lineColorMax: {
type: Number,
default: 180
},
dotColorMin: {
type: Number,
default: 0
},
dotColorMax: {
type: Number,
default: 255
},
contentWidth: {
type: Number,
default:136
},
contentHeight: {
type: Number,
default: 38
},
remote:{
type:Boolean,
default:false,
required:false
}
},
methods: {
// 生成一个随机数
randomNum (min, max) {
return Math.floor(Math.random() * (max - min) + min)
},
// 生成一个随机的颜色
randomColor (min, max) {
let r = this.randomNum(min, max)
let g = this.randomNum(min, max)
let b = this.randomNum(min, max)
return 'rgb(' + r + ',' + g + ',' + b + ')'
},
drawPic () {
this.randomCode().then(()=>{
let canvas = document.getElementById('gc-canvas')
let ctx = canvas.getContext('2d')
ctx.textBaseline = 'bottom'
// 绘制背景
ctx.fillStyle = this.randomColor(this.backgroundColorMin, this.backgroundColorMax)
ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)
// 绘制文字
for (let i = 0; i < this.code.length; i++) {
this.drawText(ctx, this.code[i], i)
}
this.drawLine(ctx)
this.drawDot(ctx)
this.$emit("success",this.code)
})
},
drawText (ctx, txt, i) {
ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
let fontSize = this.randomNum(this.fontSizeMin, this.fontSizeMax)
ctx.font = fontSize + 'px SimHei'
let padding = 10;
let offset = (this.contentWidth-40)/(this.code.length-1)
let x=padding;
if(i>0){
x = padding+(i*offset)
}
//let x = (i + 1) * (this.contentWidth / (this.code.length + 1))
let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)
if(fontSize>40){
y=40
}
var deg = this.randomNum(-10,10)
// 修改坐标原点和旋转角度
ctx.translate(x, y)
ctx.rotate(deg * Math.PI / 180)
ctx.fillText(txt, 0, 0)
// 恢复坐标原点和旋转角度
ctx.rotate(-deg * Math.PI / 180)
ctx.translate(-x, -y)
},
drawLine (ctx) {
// 绘制干扰线
for (let i = 0; i <1; i++) {
ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax)
ctx.beginPath()
ctx.moveTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
ctx.lineTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
ctx.stroke()
}
},
drawDot (ctx) {
// 绘制干扰点
for (let i = 0; i < 100; i++) {
ctx.fillStyle = this.randomColor(0, 255)
ctx.beginPath()
ctx.arc(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight), 1, 0, 2 * Math.PI)
ctx.fill()
}
},
reloadPic(){
this.drawPic()
},
randomCode(){
return new Promise((resolve)=>{
if(this.remote==true){
getAction("/sys/getCheckCode").then(res=>{
console.log("aaaaa",res)
if(res.success){
this.checkKey = res.result.key
this.code = window.atob(res.result.code)
resolve();
}else{
this.$message.error("生成验证码错误,请联系系统管理员")
this.code = 'BUG'
resolve();
}
}).catch(()=>{
console.log("生成验证码连接服务器异常")
this.code = 'BUG'
resolve();
})
}else{
this.randomLocalCode();
resolve();
}
})
},
randomLocalCode(){
let random = ''
//去掉了I l i o O
let str = "QWERTYUPLKJHGFDSAZXCVBNMqwertyupkjhgfdsazxcvbnm1234567890"
for(let i = 0; i < this.length; i++) {
let index = Math.floor(Math.random()*57);
random += str[index];
}
this.code = random
},
getLoginParam(){
return {
checkCode:this.code,
checkKey:this.checkKey
}
}
},
mounted () {
this.drawPic()
},
data(){
return {
code:"",
checkKey:""
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -44,7 +44,6 @@
data(){
return {
uploadAction:window._CONFIG['domianURL']+"/sys/common/upload",
urlView:window._CONFIG['staticDomainURL'],
uploadLoading:false,
picUrl:false,
headers:{},
......@@ -103,7 +102,7 @@
let fileList = [];
let arr = paths.split(",")
for(var a=0;a<arr.length;a++){
let url = getFileAccessHttpUrl(arr[a],this.urlView,"http");
let url = getFileAccessHttpUrl(arr[a]);
fileList.push({
uid: uidGenerator(),
name: getFileName(arr[a]),
......@@ -156,7 +155,7 @@
getAvatarView(){
if(this.fileList.length>0){
let url = this.fileList[0].url
return getFileAccessHttpUrl(url,this.urlView,"http")
return getFileAccessHttpUrl(url)
}
},
handlePathChange(){
......
......@@ -32,7 +32,12 @@
handler:function(){
this.initVal();
}
}
},
// update-begin author:sunjianlei date:20200225 for:当 type 变化的时候重新计算值 ------
type() {
this.backValue({ target: { value: this.inputVal } })
},
// update-end author:sunjianlei date:20200225 for:当 type 变化的时候重新计算值 ------
},
model: {
prop: 'value',
......
export default {
minHeight: '200px',
previewStyle: 'vertical',
useCommandShortcut: true,
useDefaultHTMLSanitizer: true,
usageStatistics: false,
hideModeSwitch: false,
toolbarItems: [
'heading',
'bold',
'italic',
'strike',
'divider',
'hr',
'quote',
'divider',
'ul',
'ol',
'task',
'indent',
'outdent',
'divider',
'table',
'image',
'link',
'divider',
'code',
'codeblock'
]
}
<template>
<div :id="id" />
</template>
<script>
import 'codemirror/lib/codemirror.css'
import 'tui-editor/dist/tui-editor.css'
import 'tui-editor/dist/tui-editor-contents.css'
import Editor from 'tui-editor'
import defaultOptions from './default-options'
export default {
name: 'JMarkdownEditor',
props: {
value: {
type: String,
default: ''
},
id: {
type: String,
required: false,
default() {
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
}
},
options: {
type: Object,
default() {
return defaultOptions
}
},
mode: {
type: String,
default: 'markdown'
},
height: {
type: String,
required: false,
default: '300px'
},
language: {
type: String,
required: false,
default: 'en_US'
}
},
data() {
return {
editor: null
}
},
computed: {
editorOptions() {
const options = Object.assign({}, defaultOptions, this.options)
options.initialEditType = this.mode
options.height = this.height
options.language = this.language
return options
}
},
watch: {
value(newValue, preValue) {
if (newValue !== preValue && newValue !== this.editor.getValue()) {
this.editor.setValue(newValue)
}
},
language(val) {
this.destroyEditor()
this.initEditor()
},
height(newValue) {
this.editor.height(newValue)
},
mode(newValue) {
this.editor.changeMode(newValue)
}
},
mounted() {
this.initEditor()
},
destroyed() {
this.destroyEditor()
},
methods: {
initEditor() {
this.editor = new Editor({
el: document.getElementById(this.id),
...this.editorOptions
})
if (this.value) {
this.editor.setValue(this.value)
}
this.editor.on('change', () => {
this.$emit('change', this.editor.getValue())
})
},
destroyEditor() {
if (!this.editor) return
this.editor.off('change')
this.editor.remove()
},
setValue(value) {
this.editor.setValue(value)
},
getValue() {
return this.editor.getValue()
},
setHtml(value) {
this.editor.setHtml(value)
},
getHtml() {
return this.editor.getHtml()
}
},
model: {
prop: 'value',
event: 'change'
}
}
</script>
<template>
<a-modal
ref="modal"
class="j-modal-box"
:class="{'fullscreen':innerFullscreen,'no-title':isNoTitle,'no-footer':isNoFooter,}"
:class="getClass(modalClass)"
:style="getStyle(modalStyle)"
:visible="visible"
v-bind="_attrs"
v-on="$listeners"
......@@ -38,6 +38,8 @@
<script>
import { getClass, getStyle } from '@/utils/props-util'
export default {
name: 'JModal',
props: {
......@@ -47,13 +49,18 @@
// 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
fullscreen: {
type: Boolean,
default: true
default: false
},
// 是否允许切换全屏(允许后右上角会出现一个按钮)
switchFullscreen: {
type: Boolean,
default: false
},
// 点击确定按钮的时候是否关闭弹窗
okClose: {
type: Boolean,
default: true
},
},
data() {
return {
......@@ -73,6 +80,22 @@
}
return attrs
},
modalClass() {
return {
'j-modal-box': true,
'fullscreen': this.innerFullscreen,
'no-title': this.isNoTitle,
'no-footer': this.isNoFooter,
}
},
modalStyle() {
let style = {}
// 如果全屏就将top设为 0
if (this.innerFullscreen) {
style['top'] = '0'
}
return style
},
isNoTitle() {
return !this.title && !this.allSlotsKeys.includes('title')
},
......@@ -90,7 +113,7 @@
},
// 切换全屏的按钮图标
fullscreenButtonIcon() {
return this.innerFullscreen ? 'fullscreen' : 'fullscreen-exit'
return this.innerFullscreen ? 'fullscreen-exit' : 'fullscreen'
},
},
watch: {
......@@ -105,12 +128,21 @@
},
methods: {
getClass(clazz) {
return { ...getClass(this), ...clazz }
},
getStyle(style) {
return { ...getStyle(this), ...style }
},
close() {
this.$emit('update:visible', false)
},
handleOk() {
if (this.okClose) {
this.close()
}
},
handleCancel() {
this.close()
......@@ -167,6 +199,7 @@
.right {
width: 56px;
position: inherit;
.ant-modal-close {
right: 56px;
......@@ -180,5 +213,13 @@
}
}
}
@media (max-width: 767px) {
.j-modal-box.fullscreen {
margin: 0;
max-width: 100vw;
}
}
</style>
\ No newline at end of file
<template>
<a-switch v-model="checkStatus" :disabled="disabled" @change="handleChange"/>
</template>
<script>
export default {
name: 'JSwitch',
props: {
value:{
type: String,
required: false
},
disabled:{
type: Boolean,
required: false,
default: false
},
options:{
type:Array,
required:false,
default:()=>['Y','N']
}
},
data () {
return {
checkStatus: false
}
},
watch: {
value:{
immediate: true,
handler(val){
if(!val){
this.checkStatus = false
this.$emit('change', this.options[1]);
}else{
if(this.options[0]==val){
this.checkStatus = true
}else{
this.checkStatus = false
}
}
}
}
},
methods: {
handleChange(checked){
let flag = checked===false?this.options[1]:this.options[0];
this.$emit('change', flag);
}
},
model: {
prop: 'value',
event: 'change'
}
}
</script>
......@@ -180,7 +180,11 @@
},
onChange(value){
console.log(value)
if(!value){
this.$emit('change', '');
}else{
this.$emit('change', value.value);
}
this.treeValue = value
},
onSearch(value){
......
......@@ -2,6 +2,7 @@
<a-tree-select
allowClear
labelInValue
:getPopupContainer="(node) => node.parentNode"
style="width: 100%"
:disabled="disabled"
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
......
<template>
<div>
<a-modal
title="文件上传"
:width="width"
:visible="visible"
@ok="ok"
cancelText="取消"
@cancel="close">
<!--style="top: 20px;"-->
<j-upload :file-type="fileType" :value="filePath" @change="handleChange" :disabled="disabled"></j-upload>
</a-modal>
</div>
</template>
<script>
import JUpload from '@/components/jeecg/JUpload'
import { getFileAccessHttpUrl } from '@/api/manage';
const getFileName=(path)=>{
if(path.lastIndexOf("\\")>=0){
let reg=new RegExp("\\\\","g");
path = path.replace(reg,"/");
}
return path.substring(path.lastIndexOf("/")+1);
}
export default {
name: 'JFilePop',
components: { JUpload },
props:{
title:{
type:String,
default:'',
required:false
},
position:{
type:String,
default:'right',
required:false
},
height:{
type:Number,
default:200,
required:false
},
width:{
type:Number,
default:520,
required:false
},
popContainer:{
type:String,
default:'',
required:false
},
disabled:{
type:Boolean,
default:false,
required:false
}
},
data(){
return {
visible:false,
filePath:'',
id:'',
fileType:'file'
}
},
methods:{
handleChange(value){
this.filePath = value;
},
show(id,value,flag){
this.id = id;
this.filePath = value;
this.visible=true
if(flag === 'img'){
this.fileType = 'image'
}else{
this.fileType = 'file'
}
},
ok(){
if(!this.filePath){
this.$message.error("未上传任何文件")
return false;
}
let arr = this.filePath.split(",")
let obj = {
name:getFileName(arr[0]),
url:getFileAccessHttpUrl(arr[0]),
path:this.filePath,
status: 'done',
id:this.id
}
this.$emit('ok',obj)
this.visible=false
},
close(){
this.visible=false
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<a-popover trigger="contextmenu" v-model="visible" :placement="position">
<!--"(node) => node.parentNode.parentNode"-->
<div slot="title">
<span>{{ title }}</span>
<span style="float: right" title="关闭">
<a-icon type="close" @click="visible=false"/>
</span>
</div>
<a-input :value="inputContent" @change="handleInputChange">
<a-icon slot="suffix" type="fullscreen" @click.stop="pop" />
</a-input>
<div slot="content">
<textarea :value="inputContent" @input="handleInputChange" :style="{ height: height + 'px', width: width + 'px' }"></textarea>
</div>
</a-popover>
</template>
<script>
export default {
name: 'JInputPop',
props:{
title:{
type:String,
default:'',
required:false
},
position:{
type:String,
default:'right',
required:false
},
height:{
type:Number,
default:200,
required:false
},
width:{
type:Number,
default:150,
required:false
},
value:{
type:String,
required:false
},
popContainer:{
type:String,
default:'',
required:false
}
},
data(){
return {
visible:false,
inputContent:''
}
},
watch:{
value:{
immediate:true,
handler:function(){
if(this.value && this.value.length>0){
this.inputContent = this.value;
}
}
},
},
model: {
prop: 'value',
event: 'change'
},
methods:{
handleInputChange(event){
this.inputContent = event.target.value
this.$emit('change',this.inputContent)
},
pop(){
this.visible=true
},
getPopupContainer(node){
if(!this.popContainer){
return node.parentNode
}else{
return document.getElementById(this.popContainer)
}
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -63,12 +63,14 @@
<script>
import { getAction } from '@/api/manage'
import Ellipsis from '@/components/Ellipsis'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import { cloneObject, pushIfNotExist } from '@/utils/util'
export default {
name: 'JSelectBizComponentModal',
mixins: [JeecgListMixin],
components: { Ellipsis },
props: {
value: {
type: Array,
......@@ -128,12 +130,15 @@
type: String,
default: 'id'
},
// 过长裁剪长度,设置为 -1 代表不裁剪
ellipsisLength: {
type: Number,
default: 12
},
},
data() {
return {
innerValue: [],
// 表头
innerColumns: this.columns,
// 已选择列表
selectedTable: {
pagination: false,
......@@ -147,6 +152,7 @@
],
dataSource: [],
},
renderEllipsis: (value) => (<ellipsis length={this.ellipsisLength}>{value}</ellipsis>),
url: { list: this.listUrl },
/* 分页参数 */
ipagination: {
......@@ -164,6 +170,19 @@
dataSourceMap: {},
}
},
computed: {
// 表头
innerColumns() {
let columns = cloneObject(this.columns)
columns.forEach(column => {
// 给所有的列加上过长裁剪
if (this.ellipsisLength !== -1) {
column.customRender = (text) => this.renderEllipsis(text)
}
})
return columns
},
},
watch: {
value: {
deep: true,
......
......@@ -29,7 +29,7 @@ export default {
| selectButtonText | String | | "选择" | 选择按钮的文字 |
| queryParamText | String | | null | 查询条件显示文字,不传则使用 `name` |
| columns | Array | 是 | | 列配置项,与antd的table的配置完全一致。列的第一项会被配置成右侧已选择的列表上 |
| columns[0].widthRight | Array | | null | 仅列的第一项可以应用此配置,表示右侧已选择列表的宽度,建议 `70%`,不传则应用`width` |
| columns[0].widthRight | String | | null | 仅列的第一项可以应用此配置,表示右侧已选择列表的宽度,建议 `70%`,不传则应用`width` |
| placeholder | String | | "请选择" | 占位符 |
| disabled | Boolean | | false | 是否禁用 |
| multiple | Boolean | | false | 是否可多选 |
......
......@@ -9,8 +9,9 @@
:options="selectOptions"
allowClear
:disabled="disabled"
:open="false"
:open="selectOpen"
style="width: 100%;"
@dropdownVisibleChange="handleDropdownVisibleChange"
@click.native="visible=(buttons?visible:true)"
/>
</slot>
......@@ -85,7 +86,8 @@
selectValue: [],
selectOptions: [],
dataSourceMap: {},
visible: false
visible: false,
selectOpen: false,
}
},
computed: {
......@@ -128,6 +130,13 @@
this.selectOptions = options
this.dataSourceMap = dataSourceMap
},
handleDropdownVisibleChange() {
// 解决antdv自己的bug —— open 设置为 false 了,点击后还是添加了 open 样式,导致点击事件失效
this.selectOpen = true
this.$nextTick(() => {
this.selectOpen = false
})
},
}
}
</script>
......@@ -142,7 +151,7 @@
}
.right {
width: @width ;
width: @width;
}
.full {
......
......@@ -2,6 +2,7 @@
<!-- 定义在这里的参数都是不可在外部覆盖的,防止出现问题 -->
<j-select-biz-component
:value="value"
:ellipsisLength="25"
:listUrl="url.list"
:columns="columns"
v-on="$listeners"
......@@ -20,15 +21,15 @@
return {
url: { list: '/sys/user/list' },
columns: [
{ title: '姓名', align: 'center', width: '20%', widthRight: '70%', dataIndex: 'realname' },
{ title: '账号', align: 'center', width: '20%', dataIndex: 'username' },
{ title: '电话', align: 'center', width: '23%', dataIndex: 'phone' },
{ title: '出生日期', align: 'center', width: '23%', dataIndex: 'birthday' }
{ title: '姓名', align: 'center', width: '25%', widthRight: '70%', dataIndex: 'realname' },
{ title: '账号', align: 'center', width: '25%', dataIndex: 'username' },
{ title: '电话', align: 'center', width: '20%', dataIndex: 'phone' },
{ title: '出生日期', align: 'center', width: '20%', dataIndex: 'birthday' }
],
// 定义在这里的参数都是可以在外部传递覆盖的,可以更灵活的定制化使用的组件
default: {
name: '用户',
width: 1000,
width: 1200,
displayKey: 'realname',
returnKeys: ['id', 'username'],
queryParamText: '账号',
......
......@@ -3,7 +3,8 @@
<a-input-search
v-model="userNames"
placeholder="请先选择用户"
disabled
readOnly
unselectable="on"
@search="onSearchDepUser">
<a-button slot="enterButton" :disabled="disabled">选择用户</a-button>
</a-input-search>
......
......@@ -93,6 +93,8 @@
this.linkList.push(this.$route.fullPath)
this.activePage = this.$route.fullPath
},
mounted() {
},
watch: {
'$route': function(newRoute) {
//console.log("新的路由",newRoute)
......@@ -192,6 +194,7 @@
this.$message.warning('这是最后一页,不能再关闭了啦')
return
}
console.log("this.pageList ",this.pageList );
this.pageList = this.pageList.filter(item => item.fullPath !== key)
let index = this.linkList.indexOf(key)
this.linkList = this.linkList.filter(item => item !== key)
......
......@@ -43,7 +43,7 @@ export default {
},
methods: {
closeMenu (e) {
if (['menuitemicon', 'menuitem'].indexOf(e.target.getAttribute('role')) < 0) {
if (this.visible === true && ['menuitemicon', 'menuitem'].indexOf(e.target.getAttribute('role')) < 0) {
this.$emit('update:visible', false)
}
},
......
......@@ -149,8 +149,11 @@ export default {
this.selectedRows = []
},
onClearSelected() {
// 【TESTA-262】页面清空后还能才做所选行,增加 this.$emit('clearAll')
this.selectedRowKeys = []
this.selectedRows = []
this.updateSelect([], [])
this.$emit('clearAll')
},
renderMsg(h) {
const _vm = this
......
......@@ -26,7 +26,7 @@ export default {
console.log('this.$route.matched', this.$route.matched)
this.breadList = []
this.breadList.push({ name: 'dashboard', path: '/dashboard/', meta: { title: '首页' } })
this.breadList.push({ name: 'dashboard-analysis', path: '/dashboard/analysis', meta: { title: '首页' } })
this.name = this.$route.name
this.$route.matched.forEach((item) => {
......
......@@ -121,7 +121,7 @@
this.loadData();
//this.timerFun();
this.initWebSocket();
this.heartCheckFun();
// this.heartCheckFun();
},
destroyed: function () { // 离开页面生命周期函数
this.websocketclose();
......@@ -212,7 +212,7 @@
websocketOnopen: function () {
console.log("WebSocket连接成功");
//心跳检测重置
this.heartCheck.reset().start();
//this.heartCheck.reset().start();
},
websocketOnerror: function (e) {
console.log("WebSocket连接发生错误");
......@@ -229,7 +229,7 @@
this.loadData();
}
//心跳检测重置
this.heartCheck.reset().start();
//this.heartCheck.reset().start();
},
websocketOnclose: function (e) {
console.log("connection closed (" + e.code + ")");
......
<template>
<a-modal
class="announcementCustomModal"
<j-modal
:title="title"
:width="modelStyle.width"
:visible="visible"
:bodyStyle ="bodyStyle"
:switchFullscreen="switchFullscreen"
@cancel="handleCancel"
destroyOnClose>
<template slot="title">
<a-button icon="fullscreen" class="custom-btn" @click="handleClickToggleFullScreen"/>
</template>
>
<template slot="footer">
<a-button key="back" @click="handleCancel">关闭</a-button>
<a-button v-if="record.openType==='url'&&record.readFlag!=='1'" type="primary" @click="toHandle">去处理</a-button>
<a-button v-if="record.openType==='url'" type="primary" @click="toHandle">去处理</a-button>
</template>
<a-card class="daily-article" :loading="loading">
<a-card-meta
......@@ -21,7 +19,7 @@
<a-divider />
<span v-html="record.msgContent" class="article-content"></span>
</a-card>
</a-modal>
</j-modal>
</template>
<script>
......@@ -42,6 +40,7 @@
sm: { span: 16 },
},
visible: false,
switchFullscreen: true,
loading: false,
bodyStyle:{
padding: "0",
......@@ -79,7 +78,7 @@
this.modelStyle.fullScreen = mode
},
toHandle(){
if(this.record.openType==='url'&&this.record.readFlag!== '1'){
if(this.record.openType==='url'){
this.visible = false;
//链接跳转
this.$router.push({path: this.record.openPage})
......
......@@ -94,6 +94,7 @@
import DepartSelect from './DepartSelect'
import { mapActions, mapGetters,mapState } from 'vuex'
import { mixinDevice } from '@/utils/mixin.js'
import { getFileAccessHttpUrl } from "@/api/manage"
export default {
name: "UserMenu",
......@@ -157,8 +158,7 @@
...mapActions(["Logout"]),
...mapGetters(["nickname", "avatar","userInfo"]),
getAvatar(){
console.log('url = '+ window._CONFIG['staticDomainURL']+"/"+this.avatar())
return window._CONFIG['staticDomainURL']+"/"+this.avatar()
return getFileAccessHttpUrl(this.avatar())
},
handleLogout() {
const that = this
......
......@@ -11,7 +11,7 @@ export const asyncRouterMap = [
name: 'dashboard',
component: TabLayout,
meta: { title: '首页' },
redirect: '/dashboard/workplace',
redirect: '/dashboard/analysis',
children: [
// // dashboard
......
......@@ -14,13 +14,11 @@ import '@/permission' // permission control
import '@/utils/filter' // base filter
import Print from 'vue-print-nb-jeecg'
/*import '@babel/polyfill'*/
import VueApexCharts from 'vue-apexcharts'
import preview from 'vue-photo-preview'
import 'vue-photo-preview/dist/skin.css'
require('@jeecg/antd-online-214')
require('@jeecg/antd-online-214/dist/OnlineForm.css')
require('@jeecg/antd-online-beta220')
require('@jeecg/antd-online-beta220/dist/OnlineForm.css')
import {
ACCESS_TOKEN,
......@@ -41,6 +39,8 @@ import JDictSelectTag from './components/dict/index.js'
import hasPermission from '@/utils/hasPermission'
import vueBus from '@/utils/vueBus';
import JeecgComponents from '@/components/jeecg/index'
import '@/assets/less/JAreaLinkage.less'
import VueAreaLinkage from 'vue-area-linkage'
Vue.config.productionTip = false
Vue.use(Storage, config.storageOptions)
......@@ -50,11 +50,10 @@ Vue.use(Viser)
Vue.use(hasPermission)
Vue.use(JDictSelectTag)
Vue.use(Print)
Vue.use(VueApexCharts)
Vue.component('apexchart', VueApexCharts)
Vue.use(preview)
Vue.use(vueBus);
Vue.use(JeecgComponents);
Vue.use(VueAreaLinkage);
new Vue({
router,
......
......@@ -83,7 +83,16 @@ export const JEditableTableMixin = {
requestSubTableData(url, params, tab, success) {
tab.loading = true
getAction(url, params).then(res => {
tab.dataSource = res.result || []
let { result } = res
let dataSource = []
if (result) {
if (Array.isArray(result)) {
dataSource = result
} else if (Array.isArray(result.records)) {
dataSource = result.records
}
}
tab.dataSource = dataSource
typeof success === 'function' ? success(res) : ''
}).finally(() => {
tab.loading = false
......
......@@ -4,7 +4,7 @@
* data中url定义 list为查询列表 delete为删除单条记录 deleteBatch为批量删除
*/
import { filterObj } from '@/utils/util';
import { deleteAction, getAction,downFile } from '@/api/manage'
import { deleteAction, getAction,downFile,getFileAccessHttpUrl } from '@/api/manage'
import Vue from 'vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
......@@ -47,7 +47,9 @@ export const JeecgListMixin = {
/* 高级查询条件生效状态 */
superQueryFlag:false,
/* 高级查询条件 */
superQueryParams:""
superQueryParams: '',
/** 高级查询拼接方式 */
superQueryMatchType: 'and',
}
},
created() {
......@@ -84,22 +86,24 @@ export const JeecgListMixin = {
initDictConfig(){
console.log("--这是一个假的方法!")
},
handleSuperQuery(arg) {
handleSuperQuery(params, matchType) {
//高级查询方法
if(!arg){
if(!params){
this.superQueryParams=''
this.superQueryFlag = false
}else{
this.superQueryFlag = true
this.superQueryParams=JSON.stringify(arg)
this.superQueryParams=JSON.stringify(params)
this.superQueryMatchType = matchType
}
this.loadData()
this.loadData(1)
},
getQueryParams() {
//获取查询条件
let sqp = {}
if(this.superQueryParams){
sqp['superQueryParams']=encodeURI(this.superQueryParams)
sqp['superQueryMatchType'] = this.superQueryMatchType
}
var param = Object.assign(sqp, this.queryParam, this.isorter ,this.filters);
param.field = this.getQueryField();
......@@ -206,6 +210,10 @@ export const JeecgListMixin = {
handleToggleSearch(){
this.toggleSearchStatus = !this.toggleSearchStatus;
},
// 给popup查询使用(查询区域不支持回填多个字段,限制只返回一个字段)
getPopupField(fields){
return fields.split(',')[0]
},
modalFormOk() {
// 新增/修改 成功时,重载列表
this.loadData();
......@@ -286,7 +294,7 @@ export const JeecgListMixin = {
if(text && text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
return window._CONFIG['staticDomainURL']+"/"+text
return getFileAccessHttpUrl(text)
},
/* 文件下载 */
uploadFile(text){
......@@ -297,7 +305,8 @@ export const JeecgListMixin = {
if(text.indexOf(",")>0){
text = text.substring(0,text.indexOf(","))
}
window.open(window._CONFIG['staticDomainURL']+ "/"+text);
let url = getFileAccessHttpUrl(text)
window.open(url);
},
}
......
export const HrefJump = {
data() {
return {
fieldHrefSlots: [],
hrefComponent: {
model: {
title: '',
width: '100%',
visible: false,
destroyOnClose: true,
style: {
top: 0,
left: 0,
height: '100%',
margin: 0,
padding: 0
},
bodyStyle: { padding: '8px', height: 'calc(100vh - 108px)', overflow: 'auto', overflowX: 'hidden' },
// 隐藏掉取消按钮
cancelButtonProps: { style: { display: 'none' } },
afterClose: () => {
// 恢复body的滚动
document.body.style.overflow = null
}
},
on: {
ok: () => this.hrefComponent.model.visible = false,
cancel: () => this.hrefComponent.model.visible = false
},
is: null,
params: {},
}
}
},
methods: {
//支持链接href跳转
handleClickFieldHref(field, record) {
let href = field.href
let urlPattern = /(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&amp;%\$#_]*)?/
let compPattern = /\.vue(\?.*)?$/
if (typeof href === 'string') {
href = href.trim().replace(/\${([^}]+)?}/g, (s1, s2) => record[s2])
if (urlPattern.test(href)) {
window.open(href, '_blank')
} else if (compPattern.test(href)) {
this.openHrefCompModal(href)
} else {
this.$router.push(href)
}
}
},
openHrefCompModal(href) {
// 解析 href 参数
let index = href.indexOf('?')
let path = href
if (index !== -1) {
path = href.substring(0, index)
let paramString = href.substring(index + 1, href.length)
let paramArray = paramString.split('&')
let params = {}
paramArray.forEach(paramObject => {
let paramItem = paramObject.split('=')
params[paramItem[0]] = paramItem[1]
})
this.hrefComponent.params = params
} else {
this.hrefComponent.params = {}
}
this.hrefComponent.model.visible = true
this.hrefComponent.model.title = '@/views/' + path
this.hrefComponent.is = () => import('@/views/' + (path.startsWith('/')?path.slice(1):path))
// 禁止body滚动,防止滚动穿透
setTimeout(() => {
document.body.style.overflow = 'hidden'
}, 300)
},
}
}
\ No newline at end of file
import { formatDate } from '@/utils/util'
import Area from '@/components/_util/Area'
const onlUtil = {
data(){
return {
mixin_pca:''
}
},
created(){
this.mixin_pca = new Area()
},
methods:{
simpleDateFormat(millisecond, format){
return formatDate(millisecond, format)
},
getPcaText(code){
return this.mixin_pca.getText(code);
},
getPcaCode(text){
return this.mixin_pca.getCode(text)
}
}
}
export { onlUtil }
\ No newline at end of file
......@@ -4,7 +4,7 @@ import store from './store'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import notification from 'ant-design-vue/es/notification'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import { ACCESS_TOKEN,INDEX_MAIN_PAGE_PATH } from '@/store/mutation-types'
import { generateIndexRouter } from "@/utils/util"
NProgress.configure({ showSpinner: false }) // NProgress Configuration
......@@ -17,7 +17,7 @@ router.beforeEach((to, from, next) => {
if (Vue.ls.get(ACCESS_TOKEN)) {
/* has token */
if (to.path === '/user/login') {
next({ path: '/dashboard/workplace' })
next({ path: INDEX_MAIN_PAGE_PATH })
NProgress.done()
} else {
if (store.getters.permissionList.length === 0) {
......
import Vue from 'vue'
import { USER_INFO} from "@/store/mutation-types"
import { USER_INFO, ENHANCE_PRE } from "@/store/mutation-types"
const getters = {
device: state => state.app.device,
theme: state => state.app.theme,
......@@ -11,7 +11,12 @@ const getters = {
welcome: state => state.user.welcome,
permissionList: state => state.user.permissionList,
userInfo: state => {state.user.info = Vue.ls.get(USER_INFO); return state.user.info},
addRouters: state => state.permission.addRouters
addRouters: state => state.permission.addRouters,
enhanceJs:(state) => (code) => {
state.enhance.enhanceJs[code] = Vue.ls.get(ENHANCE_PRE+code);
return state.enhance.enhanceJs[code]
}
}
export default getters
\ No newline at end of file
......@@ -4,6 +4,7 @@ import Vuex from 'vuex'
import app from './modules/app'
import user from './modules/user'
import permission from './modules/permission'
import enhance from './modules/enhance'
import getters from './getters'
Vue.use(Vuex)
......@@ -12,7 +13,8 @@ export default new Vuex.Store({
modules: {
app,
user,
permission
permission,
enhance
},
state: {
......
import Vue from 'vue'
const enhance = {
state: {
enhanceJs:{
}
},
mutations: {
ADD_TABLE_ENHANCE: (state, record) => {
if(!state.enhanceJs){
let obj = {}
let arr = []
arr.push({...record})
obj[record.code] = arr
state.enhanceJs = obj
}else{
if(!state.enhanceJs[record.code]){
let arr = []
arr.push({...record})
state.enhanceJs[record.code] = arr
}
state.enhanceJs[record.code].push({...record})
}
let arr = state.enhanceJs[record.code]
while(arr.length>16){
arr.shift()
}
Vue.ls.set('enhance_'+record['code'], arr)
}
},
actions: {
addEhanceRecord({ commit }, record) {
commit('ADD_TABLE_ENHANCE', record)
}
}
}
export default enhance
\ No newline at end of file
import Vue from 'vue'
import { login, logout, phoneLogin } from "@/api/login"
import { ACCESS_TOKEN, USER_NAME,USER_INFO,USER_AUTH,SYS_BUTTON_AUTH } from "@/store/mutation-types"
import { login, logout, phoneLogin, thirdLogin } from "@/api/login"
import { ACCESS_TOKEN, USER_NAME,USER_INFO,USER_AUTH,SYS_BUTTON_AUTH,UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types"
import { welcome } from "@/utils/util"
import { queryPermissionsByUser } from '@/api/api'
import { getAction } from '@/api/manage'
......@@ -71,6 +71,7 @@ const user = {
Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(USER_NAME, userInfo.username, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(UI_CACHE_DB_DICT_DATA, result.sysAllDictItems, 7 * 24 * 60 * 60 * 1000)
commit('SET_TOKEN', result.token)
commit('SET_INFO', userInfo)
commit('SET_NAME', { username: userInfo.username,realname: userInfo.realname, welcome: welcome() })
......@@ -94,6 +95,7 @@ const user = {
Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(USER_NAME, userInfo.username, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(UI_CACHE_DB_DICT_DATA, result.sysAllDictItems, 7 * 24 * 60 * 60 * 1000)
commit('SET_TOKEN', result.token)
commit('SET_INFO', userInfo)
commit('SET_NAME', { username: userInfo.username,realname: userInfo.realname, welcome: welcome() })
......@@ -151,10 +153,11 @@ const user = {
commit('SET_TOKEN', '')
commit('SET_PERMISSIONLIST', [])
Vue.ls.remove(ACCESS_TOKEN)
Vue.ls.remove(UI_CACHE_DB_DICT_DATA)
//console.log('logoutToken: '+ logoutToken)
logout(logoutToken).then(() => {
//var sevice = "http://"+window.location.host+"/";
//var serviceUrl = encodeURIComponent(sevice);
//let sevice = "http://"+window.location.host+"/";
//let serviceUrl = encodeURIComponent(sevice);
//window.location.href = window._CONFIG['casPrefixUrl']+"/logout?service="+serviceUrl;
resolve()
}).catch(() => {
......@@ -162,6 +165,29 @@ const user = {
})
})
},
// 第三方登录
ThirdLogin({ commit }, token) {
return new Promise((resolve, reject) => {
thirdLogin(token).then(response => {
if(response.code =='200'){
const result = response.result
const userInfo = result.userInfo
Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(USER_NAME, userInfo.username, 7 * 24 * 60 * 60 * 1000)
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
commit('SET_TOKEN', result.token)
commit('SET_INFO', userInfo)
commit('SET_NAME', { username: userInfo.username,realname: userInfo.realname, welcome: welcome() })
commit('SET_AVATAR', userInfo.avatar)
resolve(response)
}else{
reject(response)
}
}).catch(error => {
reject(error)
})
})
},
}
}
......
......@@ -14,6 +14,9 @@ export const USER_INFO = 'Login_Userinfo'
export const USER_AUTH = 'LOGIN_USER_BUTTON_AUTH'
export const SYS_BUTTON_AUTH = 'SYS_BUTTON_AUTH'
export const ENCRYPTED_STRING = 'ENCRYPTED_STRING'
export const ENHANCE_PRE = 'enhance_'
export const UI_CACHE_DB_DICT_DATA = 'UI_CACHE_DB_DICT_DATA'
export const INDEX_MAIN_PAGE_PATH = "/dashboard/analysis"
export const CONTENT_WIDTH_TYPE = {
Fluid: 'Fluid',
......
......@@ -14,6 +14,7 @@ const FormTypes = {
sel_search:"sel_search",
radio:'radio',
checkbox_meta:"checkbox_meta",
input_pop:'input_pop',
slot: 'slot',
hidden: 'hidden'
......@@ -77,18 +78,22 @@ export function validateFormAndTables(form, cases) {
/**
* 验证并获取一个或多个表格的所有值
* @param cases 接收一个数组,每项都是一个JEditableTable实例
* @param deleteTempId 是否删除临时ID,如果设为true,行编辑就不返回新增行的ID,ID需要后台生成
* @author sunjianlei
*/
export function validateTables(cases) {
export function validateTables(cases, deleteTempId) {
if (!(cases instanceof Array)) {
throw `'validateTables'函数的'cases'参数需要的是一个数组,而传入的却是${typeof cases}`
}
return new Promise((resolve, reject) => {
let tables = []
let index = 0;
if(!cases || cases.length==0){
resolve()
}
(function next() {
let vm = cases[index]
vm.getAll(true).then(all => {
vm.getAll(true, deleteTempId).then(all => {
tables[index] = all
// 判断校验是否全部完成,完成返回成功,否则继续进行下一步校验
if (++index === cases.length) {
......
......@@ -9,9 +9,10 @@ export function disabledAuthFilter(code,formData) {
}
function nodeDisabledAuth(code,formData){
console.log("页面权限禁用--NODE--开始");
let permissionList = [];
try {
//console.log("页面权限禁用--NODE--开始",obj);
console.log("页面权限禁用--NODE--开始",formData);
if (formData) {
let bpmList = formData.permissionList;
permissionList = bpmList.filter(item=>item.type=='2')
......@@ -52,10 +53,10 @@ function nodeDisabledAuth(code,formData){
}
function globalDisabledAuth(code){
//console.log("全局页面禁用权限--Global--开始");
console.log("全局页面禁用权限--Global--开始");
var permissionList = [];
var allPermissionList = [];
let permissionList = [];
let allPermissionList = [];
//let authList = Vue.ls.get(USER_AUTH);
let authList = JSON.parse(sessionStorage.getItem(USER_AUTH) || "[]");
......@@ -72,8 +73,8 @@ function globalDisabledAuth(code){
}
}
//设置全局配置是否有命中
var gFlag = false;//禁用命中
var invalidFlag = false;//无效命中
let gFlag = false;//禁用命中
let invalidFlag = false;//无效命中
if(allPermissionList != null && allPermissionList != "" && allPermissionList != undefined && allPermissionList.length > 0){
for (let itemG of allPermissionList) {
if(code === itemG.action){
......@@ -116,7 +117,7 @@ function globalDisabledAuth(code){
export function colAuthFilter(columns,pre) {
var authList = getNoAuthCols(pre);
let authList = getNoAuthCols(pre);
const cols = columns.filter(item => {
if (hasColoum(item,authList)) {
return true
......@@ -126,6 +127,44 @@ export function colAuthFilter(columns,pre) {
return cols
}
/**
* 【子表行编辑】实现两个功能:
* 1、隐藏JEditableTable无权限的字段
* 2、禁用JEditableTable无权限的字段
* @param columns
* @param pre
* @returns {*}
*/
export function colAuthFilterJEditableTable(columns,pre) {
let authList = getAllShowAndDisabledAuthCols(pre);
const cols = columns.filter(item => {
let oneAuth = authList.find(auth => {
return auth.action === pre + item.key;
});
if(!oneAuth){
return true
}
//代码严谨处理,防止一个授权标识,配置多次
if(oneAuth instanceof Array){
oneAuth = oneAuth[0]
}
//禁用逻辑
if (oneAuth.type == '2' && !oneAuth.isAuth) {
item["disabled"] = true
return true
}
//隐藏逻辑逻辑
if (oneAuth.type == '1' && !oneAuth.isAuth) {
return false
}
return true
})
return cols
}
function hasColoum(item,authList){
if (authList.includes(item.dataIndex)) {
return false
......@@ -164,6 +203,32 @@ function getNoAuthCols(pre){
return cols;
}
/**
* 额外增加方法【用于行编辑组件】
* date: 2020-04-05
* author: scott
* @param pre
* @returns {*[]}
*/
function getAllShowAndDisabledAuthCols(pre){
//用户拥有的权限
let userAuthList = JSON.parse(sessionStorage.getItem(USER_AUTH) || "[]");
//全部权限配置
let allAuthList = JSON.parse(sessionStorage.getItem(SYS_BUTTON_AUTH) || "[]");
let newAllAuthList = allAuthList.map(function (item, index) {
let hasAuthArray = userAuthList.filter(u => u.action===item.action );
if (hasAuthArray && hasAuthArray.length>0) {
item["isAuth"] = true
}
return item;
})
return newAllAuthList;
}
function startWith(str,pre) {
if (pre == null || pre == "" || str==null|| str==""|| str.length == 0 || pre.length > str.length)
return false;
......
import { getFileAccessHttpUrl } from '@/api/manage'
const getFileName=(path)=>{
if(path.lastIndexOf("\\")>=0){
let reg=new RegExp("\\\\","g");
......@@ -15,7 +16,7 @@ const getFilePaths=(uploadFiles)=>{
if(!uploadFiles){
return ""
}
for(var a=0;a<uploadFiles.length;a++){
for(let a=0;a<uploadFiles.length;a++){
arr.push(uploadFiles[a].response.message)
}
if(arr && arr.length>0){
......@@ -30,7 +31,7 @@ const getUploadFileList=(paths)=>{
}
let fileList = [];
let arr = paths.split(",")
for(var a=0;a<arr.length;a++){
for(let a=0;a<arr.length;a++){
if(!arr[a]){
continue
}else{
......@@ -38,7 +39,7 @@ const getUploadFileList=(paths)=>{
uid:uidGenerator(),
name:getFileName(arr[a]),
status: 'done',
url: window._CONFIG['staticDomainURL']+"/"+arr[a],
url: getFileAccessHttpUrl(arr[a]),
response:{
status:"history",
message:arr[a]
......
/*
*
* 这里填写用户自定义的表达式
* 可用在Online表单的默认值表达式中使用
* 需要外部使用的变量或方法一定要 export,否则无法识别
* 示例:
* export const name = '张三'; // const 是常量
* export let age = 17; // 看情况 export const 还是 let ,两者都可正常使用
* export function content(arg) { // export 方法,可传参数,使用时要加括号,值一定要return回去,可以返回Promise
* return 'content' + arg;
* }
* export const address = (arg) => content(arg) + ' | 北京市'; // export 箭头函数也可以
*
*/
/** 字段默认值官方示例:获取地址 */
export function demoFieldDefVal_getAddress(arg) {
if (!arg) {
arg = '朝阳区'
}
return `北京市 ${arg}`
}
\ No newline at end of file
......@@ -2,16 +2,16 @@ import { USER_AUTH,SYS_BUTTON_AUTH } from "@/store/mutation-types"
const hasPermission = {
install (Vue, options) {
//console.log(options);
console.log(options);
Vue.directive('has', {
inserted: (el, binding, vnode)=>{
//console.log("页面权限控制----");
console.time()
console.log("页面权限控制----");
//console.time()
//节点权限处理,如果命中则不进行全局权限处理
if(!filterNodePermission(el, binding, vnode)){
filterGlobalPermission(el, binding, vnode);
}
console.timeEnd() //计时结束并输出时长
//console.timeEnd() //计时结束并输出时长
}
});
}
......
/**
* 该文件截取自 "ant-design-vue/es/_util/props-util.js" 文件,并对其做出特殊修改
*/
function classNames() {
let classes = []
for (let i = 0; i < arguments.length; i++) {
let arg = arguments[i]
if (!arg) continue
let argType = typeof arg
if (argType === 'string' || argType === 'number') {
classes.push(arg)
} else if (Array.isArray(arg) && arg.length) {
let inner = classNames.apply(null, arg)
if (inner) {
classes.push(inner)
}
} else if (argType === 'object') {
for (let key in arg) {
if (arg.hasOwnProperty(key) && arg[key]) {
classes.push(key)
}
}
}
}
return classes.join(' ')
}
const camelizeRE = /-(\w)/g
function camelize(str) {
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''))
}
function objectCamelize(obj) {
let res = {}
Object.keys(obj).forEach(k => (res[camelize(k)] = obj[k]))
return res
}
function parseStyleText(cssText = '', camel) {
const res = {}
const listDelimiter = /;(?![^(]*\))/g
const propertyDelimiter = /:(.+)/
cssText.split(listDelimiter).forEach(function (item) {
if (item) {
const tmp = item.split(propertyDelimiter)
if (tmp.length > 1) {
const k = camel ? camelize(tmp[0].trim()) : tmp[0].trim()
res[k] = tmp[1].trim()
}
}
})
return res
}
export function getClass(ele) {
let data = {}
if (ele.data) {
data = ele.data
} else if (ele.$vnode && ele.$vnode.data) {
data = ele.$vnode.data
}
const tempCls = data.class || {}
const staticClass = data.staticClass
let cls = {}
staticClass &&
staticClass.split(' ').forEach(c => {
cls[c.trim()] = true
})
if (typeof tempCls === 'string') {
tempCls.split(' ').forEach(c => {
cls[c.trim()] = true
})
} else if (Array.isArray(tempCls)) {
classNames(tempCls)
.split(' ')
.forEach(c => {
cls[c.trim()] = true
})
} else {
cls = { ...cls, ...tempCls }
}
return cls
}
export function getStyle(ele, camel) {
getClass(ele)
let data = {}
if (ele.data) {
data = ele.data
} else if (ele.$vnode && ele.$vnode.data) {
data = ele.$vnode.data
}
// update-begin-author:sunjianlei date:20200303 for: style 和 staticStyle 可以共存
let style = data.style || {}
let staticStyle = data.staticStyle
staticStyle = staticStyle ? objectCamelize(data.staticStyle) : {}
// update-end-author:sunjianlei date:20200303 for: style 和 staticStyle 可以共存
if (typeof style === 'string') {
style = parseStyleText(style, camel)
} else if (camel && style) {
// 驼峰化
style = objectCamelize(style)
}
return { ...staticStyle, ...style }
}
......@@ -5,16 +5,18 @@ import { VueAxios } from './axios'
import {Modal, notification} from 'ant-design-vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
//自动设置后台服务 baseURL (也可以手工指定写死项目名字)
let baseDomain = window._CONFIG['domianURL'];
let baseProject = baseDomain.substring(baseDomain.lastIndexOf("/"));
console.log("baseDomain= ",baseDomain)
console.log("baseProject= ",baseProject)
/**
* 【指定 axios的 baseURL】
* 如果手工指定 baseURL: '/jeecg-boot'
* 则映射后端域名,通过 vue.config.js
* @type {*|string}
*/
let apiBaseUrl = window._CONFIG['domianURL'] || "/jeecg-boot";
console.log("apiBaseUrl= ",apiBaseUrl)
// 创建 axios 实例
const service = axios.create({
//baseURL: '/jeecg-boot',
baseURL: baseProject, // api base_url
baseURL: apiBaseUrl, // api base_url
timeout: 9000 // 请求超时时间
})
......
import * as api from '@/api/api'
import { isURL } from '@/utils/validate'
import onlineCommons from '@jeecg/antd-online-beta220'
export function timeFix() {
const time = new Date()
......@@ -33,7 +34,7 @@ export function filterObj(obj) {
return;
}
for ( var key in obj) {
for ( let key in obj) {
if (obj.hasOwnProperty(key)
&& (obj[key] == null || obj[key] == undefined || obj[key] === '')) {
delete obj[key];
......@@ -49,7 +50,7 @@ export function filterObj(obj) {
* @returns {*}
*/
export function formatDate(value, fmt) {
var regPos = /^\d+(\.\d+)?$/;
let regPos = /^\d+(\.\d+)?$/;
if(regPos.test(value)){
//如果是数字
let getDate = new Date(value);
......@@ -100,7 +101,7 @@ let indexRouter = [{
function generateChildRouters (data) {
const routers = [];
for (var item of data) {
for (let item of data) {
let component = "";
if(item.component.indexOf("layouts")>=0){
component = "components/"+item.component;
......@@ -114,11 +115,33 @@ function generateChildRouters (data) {
item.meta.url = URL;
}
//online菜单路由加载逻辑
let componentPath
if(item.component=="modules/online/cgform/OnlCgformHeadList"){
componentPath = onlineCommons.OnlCgformHeadList
}else if(item.component=="modules/online/cgform/OnlCgformCopyList"){
componentPath = onlineCommons.OnlCgformCopyList
}else if(item.component=="modules/online/cgform/auto/OnlCgformAutoList"){
componentPath = onlineCommons.OnlCgformAutoList
}else if(item.component=="modules/online/cgform/auto/OnlCgformTreeList"){
componentPath = onlineCommons.OnlCgformTreeList
}else if(item.component=="modules/online/cgform/auto/erp/OnlCgformErpList"){
componentPath = onlineCommons.OnlCgformErpList
}else if(item.component=="modules/online/cgform/auto/innerTable/OnlCgformInnerTableList"){
componentPath = onlineCommons.OnlCgformInnerTableList
}else if(item.component=="modules/online/cgreport/OnlCgreportHeadList"){
componentPath = onlineCommons.OnlCgreportHeadList
}else if(item.component=="modules/online/cgreport/auto/OnlCgreportAutoList"){
componentPath = onlineCommons.OnlCgreportAutoList
}else{
componentPath = resolve => require(['@/' + component+'.vue'], resolve)
}
let menu = {
path: item.path,
name: item.name,
redirect:item.redirect,
component: resolve => require(['@/' + component+'.vue'], resolve),
component: componentPath,
hidden:item.hidden,
//component:()=> import(`@/views/${item.component}.vue`),
meta: {
......@@ -415,3 +438,43 @@ export function alwaysResolve(promise) {
}
})
}
/**
* 简单实现防抖方法
*
* 防抖(debounce)函数在第一次触发给定的函数时,不立即执行函数,而是给出一个期限值(delay),比如100ms。
* 如果100ms内再次执行函数,就重新开始计时,直到计时结束后再真正执行函数。
* 这样做的好处是如果短时间内大量触发同一事件,只会执行一次函数。
*
* @param fn 要防抖的函数
* @param delay 防抖的毫秒数
* @returns {Function}
*/
export function simpleDebounce(fn, delay = 100) {
let timer = null
return function () {
let args = arguments
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(null, args)
}, delay)
}
}
/**
* 不用正则的方式替换所有值
* @param text 被替换的字符串
* @param checker 替换前的内容
* @param replacer 替换后的内容
* @returns {String} 替换后的字符串
*/
export function replaceAll(text, checker, replacer) {
let lastText = text
text = text.replace(checker, replacer)
if (lastText !== text) {
return replaceAll(text, checker, replacer)
}
return text
}
......@@ -94,6 +94,7 @@
import RouteView from "@/components/layouts/RouteView"
import { AppPage, ArticlePage, ProjectPage } from './page'
import { mapGetters } from 'vuex'
import { getFileAccessHttpUrl } from '@/api/manage';
export default {
components: {
......@@ -133,7 +134,7 @@
methods: {
...mapGetters(["nickname", "avatar"]),
getAvatar(){
return window._CONFIG['staticDomainURL']+"/"+this.avatar();
return getFileAccessHttpUrl(this.avatar());
},
getTeams() {
this.$http.get('/api/workplace/teams')
......
......@@ -116,7 +116,7 @@
import PageLayout from '@/components/page/PageLayout'
import HeadInfo from '@/components/tools/HeadInfo'
import Radar from '@/components/chart/Radar'
import { getRoleList, getServiceList } from "@/api/manage"
import { getRoleList, getServiceList, getFileAccessHttpUrl } from "@/api/manage"
const DataSet = require('@antv/data-set')
......@@ -185,7 +185,7 @@
},
created() {
this.user = this.userInfo
this.avatar = window._CONFIG['staticDomainURL'] +"/"+ this.userInfo.avatar
this.avatar = getFileAccessHttpUrl(this.userInfo.avatar)
console.log('this.avatar :'+ this.avatar)
getRoleList().then(res => {
......
......@@ -65,37 +65,33 @@
},
data() {
return {
description: '电子档补扫页面',
description: '图片预览页面',
spinning:false,
//数据集
dataSource: [{
key:0,
fileDetails:[
{
imgUrl:"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2735633715,2749454924&fm=27&gp=0.jpg"
imgUrl:"https://static.jeecg.com/upload/test/3a4490d5d1cd495b826e528537a47cc1.jpg"
},
{
imgUrl:"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3967239004,1951414302&fm=27&gp=0.jpg"
},
{
imgUrl:"https://ss0.bdstatic.com/6Ox1bjeh1BF3odCf/it/u=3660968530,985748925&fm=191&app=48&size=h300&n=0&g=4n&f=JPEG?sec=1853310920&t=5e64af964be378c6c2a3b0acc65dfe24"
imgUrl:"https://static.jeecg.com/upload/test/8f22cd945be44388bacbf0b88cf86cfa.png"
}
]
},{
key:1,
fileDetails:[
{
imgUrl:"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=889120611,3801177793&fm=27&gp=0.jpg"
imgUrl:"https://static.jeecg.com/upload/test/u27356337152749454924fm27gp0_1588149731821.jpg"
},
{
imgUrl:"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2445468140,2491956848&fm=27&gp=0.jpg"
imgUrl:"https://static.jeecg.com/upload/test/1_1588149743473.jpg"
}
]
},
}
],
url: {
},
}
}
},
created() {
......
......@@ -42,11 +42,11 @@
spinning: false,
//数据集
dataSource: [
{id:'000',sort: 0,filePath: 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2735633715,2749454924&fm=27&gp=0.jpg'},
{id:'111',sort: 1,filePath: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3967239004,1951414302&fm=27&gp=0.jpg'},
{id:'222',sort: 2,filePath: 'https://ss0.bdstatic.com/6Ox1bjeh1BF3odCf/it/u=3660968530,985748925&fm=191&app=48&size=h300&n=0&g=4n&f=JPEG?sec=1853310920&t=5e64af964be378c6c2a3b0acc65dfe24'},
{id:'333',sort: 3,filePath: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=889120611,3801177793&fm=27&gp=0.jpg'},
{id:'444',sort: 4,filePath: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2445468140,2491956848&fm=27&gp=0.jpg'}
{id:'000',sort: 0,filePath: 'https://static.jeecg.com/upload/test/1_1588149743473.jpg'},
{id:'111',sort: 1,filePath: 'https://static.jeecg.com/upload/test/u27356337152749454924fm27gp0_1588149731821.jpg'},
{id:'222',sort: 2,filePath: 'https://static.jeecg.com/upload/test/u24454681402491956848fm27gp0_1588149712663.jpg'},
{id:'333',sort: 3,filePath: 'https://static.jeecg.com/upload/test/8f22cd945be44388bacbf0b88cf86cfa.png'},
{id:'444',sort: 4,filePath: 'https://static.jeecg.com/upload/test/u8891206113801177793fm27gp0_1588149704459.jpg'}
],
oldDateSource:[],
newDateSource:[],
......
......@@ -50,11 +50,11 @@
children: [{
title: '1页',
key: '0-0-0',
imgUrl:'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2735633715,2749454924&fm=27&gp=0.jpg'
imgUrl:'https://static.jeecg.com/upload/test/1_1588149743473.jpg'
}, {
title: '2页',
key: '0-0-1',
imgUrl:'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3967239004,1951414302&fm=27&gp=0.jpg'
imgUrl:'https://static.jeecg.com/upload/test/u27356337152749454924fm27gp0_1588149731821.jpg'
}]
},{
title: '第二页',
......@@ -62,11 +62,11 @@
children: [{
title: '1页',
key: '0-1-0',
imgUrl:'https://ss0.bdstatic.com/6Ox1bjeh1BF3odCf/it/u=3660968530,985748925&fm=191&app=48&size=h300&n=0&g=4n&f=JPEG?sec=1853310920&t=5e64af964be378c6c2a3b0acc65dfe24'
imgUrl:'https://static.jeecg.com/upload/test/u24454681402491956848fm27gp0_1588149712663.jpg'
}, {
title: '2页',
key: '0-1-1',
imgUrl:'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=889120611,3801177793&fm=27&gp=0.jpg'
imgUrl:'https://static.jeecg.com/upload/test/u8891206113801177793fm27gp0_1588149704459.jpg'
}]
},{
title: '第三页',
......@@ -74,7 +74,7 @@
children: [{
title: '1页',
key: '0-2-0',
imgUrl:'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2445468140,2491956848&fm=27&gp=0.jpg'
imgUrl:'https://static.jeecg.com/upload/test/1374962_1587621329085.jpg'
}]
}],
selectedKeys:[],
......
......@@ -26,7 +26,7 @@
<a-tabs defaultActiveKey="1">
<a-tab-pane tab="response" key="1">
<textarea style="width:100%;font-size: 16px;font-weight:500" :rows="10" v-html="resultJson" readonly>
<textarea style="width:100%;font-size: 16px;font-weight:500" :rows="10" v-html="resultJson" readOnly>
</textarea>
</a-tab-pane>
</a-tabs>
......
......@@ -6,12 +6,12 @@
<a-form layout="inline" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<a-col :md="6" :sm="8">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="用户名">
<j-input placeholder="请输入名称模糊查询" v-model="queryParam.name"></j-input>
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="年龄">
<!-- <a-input placeholder="请输入名称查询" v-model="queryParam.age"></a-input>-->
<a-input placeholder="最小年龄" type="ge" v-model="queryParam.age_begin" style="width:calc(50% - 15px);"></a-input>
......@@ -20,7 +20,7 @@
</a-form-item>
</a-col>
<template v-if="toggleSearchStatus">
<a-col :md="6" :sm="8">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="生日">
<a-range-picker v-model="queryParam.birthdayRange"
format="YYYY-MM-DD"
......@@ -28,56 +28,42 @@
@change="onBirthdayChange" />
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="性别">
<j-dict-select-tag v-model="queryParam.sex" placeholder="请选择性别" dictCode="sex"/>
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="选择用户">
<j-dict-select-tag v-model="queryParam.id" placeholder="请选择用户" dictCode="demo,name,id"/>
</a-form-item>
</a-col>
</template>
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-col :md="6" :sm="24">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
</a-col>
</span>
<a-col :md="6" :sm="24">
<!-- <template v-if="superQueryFlag">
<a-tooltip title="已有高级查询条件生效!">
<button :disabled="false" class="ant-btn ant-btn-primary" @click="superQuery">
<a-icon type="appstore" theme="twoTone" spin="true"></a-icon>
<span>高级查询</span>
</button>
</a-tooltip>
</template>
<a-button v-else type="primary" @click="superQuery" icon="filter">高级查询</a-button>
-->
<!-- 高级查询区域 -->
<j-super-query :fieldList="fieldList" ref="superQueryModal" @handleSuperQuery="handleSuperQuery"></j-super-query>
<a @click="handleToggleSearch" style="margin-left: 8px">
{{ toggleSearchStatus ? '收起' : '展开' }}
<a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
</a>
</a-col>
</span>
</a-row>
</a-form>
</div>
<!-- 操作按钮区域 -->
<div class="table-operator" style="margin-top: 5px">
<div class="table-operator">
<a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
<a-button type="primary" icon="plus" @click="jump">创建单据</a-button>
<a-button type="primary" icon="plus" @click="onetomany">一对多</a-button>
<a-button type="primary" icon="download" @click="handleExportXls('demo')">导出</a-button>
<a-button type="primary" icon="download" @click="handleExportXls('单表示例')">导出</a-button>
<a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
<a-button type="primary" icon="import">导入</a-button>
</a-upload>
<!-- 高级查询区域 -->
<j-super-query :fieldList="fieldList" ref="superQueryModal" @handleSuperQuery="handleSuperQuery"></j-super-query>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay">
<a-menu-item key="1" @click="batchDel">
......@@ -112,7 +98,7 @@
</a-row>
</a-checkbox-group>
</template>
<a><a-icon type="setting" />自定义列</a>
<a><a-icon type="setting" />设置</a>
</a-popover>
</span>
</div>
......@@ -178,25 +164,27 @@
import JSuperQuery from '@/components/jeecg/JSuperQuery.vue';
import JInput from '@/components/jeecg/JInput.vue';
import JeecgDemoTabsModal from './modules/JeecgDemoTabsModal'
import {initDictOptions, filterDictText} from '@/components/dict/JDictSelectUtil'
import {initDictOptions, filterDictText,filterDictTextByCache} from '@/components/dict/JDictSelectUtil'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import Vue from 'vue'
import { filterObj } from '@/utils/util';
//高级查询modal需要参数
const superQueryFieldList=[{
type:"date",
value:"birthday",
text:"生日"
},{
type:"string",
value:"name",
text:"用户名"
},{
type:"int",
value:"age",
text:"年龄"
}]
const superQueryFieldList=[
{
type: "string",
value: "name",
text: "用户名"
}, {
type: "int",
value: "age",
text: "年龄"
}, {
type: "date",
value: "birthday",
text: "生日"
}
]
export default {
name: "JeecgDemoList",
mixins:[JeecgListMixin],
......@@ -208,7 +196,7 @@
},
data() {
return {
description: '用户管理页面',
description: '单表示例列表',
//字典数组缓存
sexDictOptions: [],
importExcelUrl:`${window._CONFIG['domianURL']}/test/jeecgDemo/importExcel`,
......@@ -249,7 +237,7 @@
dataIndex: 'sex',
customRender: (text) => {
//字典值替换通用方法
return filterDictText(this.sexDictOptions, text);
return filterDictTextByCache('sex', text);
}
},
{
......@@ -293,12 +281,11 @@
},
methods: {
getQueryParams(){
console.log(this.queryParam.birthdayRange)
//高级查询器
let sqp = {}
if(this.superQueryParams){
sqp['superQueryParams']=encodeURI(this.superQueryParams)
sqp['superQueryMatchType'] = this.superQueryMatchType
}
var param = Object.assign(sqp, this.queryParam, this.isorter ,this.filters);
......@@ -380,38 +367,5 @@
}
</script>
<style scoped>
.ant-card-body .table-operator {
margin-bottom: 18px;
}
.ant-table-tbody .ant-table-row td {
padding-top: 15px;
padding-bottom: 15px;
}
.anty-row-operator button {
margin: 0 5px
}
.ant-btn-danger {
background-color: #ffffff
}
.ant-modal-cust-warp {
height: 100%
}
.ant-modal-cust-warp .ant-modal-body {
height: calc(100% - 110px) !important;
overflow-y: auto
}
.ant-modal-cust-warp .ant-modal-content {
height: 90% !important;
overflow-y: hidden
}
/** Button按钮间距 */
.ant-btn {
margin-left: 3px
}
@import '~@assets/less/common.less';
</style>
\ No newline at end of file
......@@ -28,7 +28,7 @@
</div>
</template>
<template v-else>
(暂无材料,点击右侧"选择文件"或"扫描上传"上传文件)
(暂无材料,点击"选择文件"或"扫描上传"上传文件)
</template>
</a-col>
</a-row>
......
......@@ -33,6 +33,7 @@
<script>
import { getAction } from '@/api/manage'
export default {
props: ['sex','name'],
data () {
return {
formLayout: 'horizontal',
......@@ -63,11 +64,25 @@
},
},
created (){
console.log('============= online href common props ============= ');
console.log('props sex: ',this.sex);
console.log('props name: ',this.name);
getAction('/api/area').then((res) => {
console.log("------------")
console.log(res)
this.areaOptions = res;
})
},
watch: {
$route: {
immediate: true,
handler() {
console.log('============= online href $route props ============= ');
let sex = this.$route.query.sex
console.log('$route sex: ', sex);
}
}
},
}
</script>
\ No newline at end of file
......@@ -25,7 +25,7 @@
@selectRowChange="handleSelectRowChange">
<template v-slot:action="props">
<a @click="handleDelete(props)">{{ props.text }}</a>
<a @click="handleDelete(props)">删除</a>
</template>
</j-editable-table>
......@@ -154,6 +154,8 @@
type: FormTypes.inputNumber,
defaultValue: 32,
placeholder: '${title}',
// 是否是统计列,只有 inputNumber 才能设置统计列
statistics: true,
validateRules: [{ required: true, message: '请输入${title}' }]
},
{
......@@ -167,6 +169,15 @@
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '数字',
key: 'money',
width: '320px',
type: FormTypes.inputNumber,
defaultValue: '100.32',
placeholder: '请选择${title}',
validateRules: [{ required: true, message: '请选择${title}' }]
},
{
title: '可以为空',
key: 'isNull',
// width: '8%',
......@@ -176,13 +187,22 @@
defaultChecked: false
},
{
type: FormTypes.popup,
key: 'popup',
title: 'JPopup',
width: '180px',
popupCode: 'demo',
field: 'name',
orgFields: 'name',
destFields: 'name'
},
{
title: '操作',
key: 'action',
// width: '8%',
width: '100px',
type: FormTypes.slot,
slotName: 'action',
defaultValue: '删除'
}
],
......
......@@ -624,7 +624,7 @@
}
},
callback (key) {
console.log(key)
//console.log(key)
}
}
}
......
......@@ -160,7 +160,6 @@
add: "/test/order/addCustomer",
edit: "/test/order/editCustomer",
fileUpload: window._CONFIG['domianURL'] + "/sys/common/upload",
imgerver: window._CONFIG['staticDomainURL'],
getOrderCustomerList: "/test/order/listOrderCustomerByMainId",
},
validatorRules: {
......@@ -246,7 +245,11 @@
let formData = Object.assign(this.model, values);
console.log(formData);
formData.orderId = this.orderId;
if(this.fileList != '') {
formData.idcardPic = this.fileList;
}else{
formData.idcardPic = '';
}
httpAction(httpurl, formData, method).then((res) => {
if (res.success) {
that.$message.success(res.message);
......@@ -278,36 +281,6 @@
callback("您的身份证号码格式不正确!");
}
},
handleChange(info) {
this.fileList = info.fileList;
if (info.file.status === 'uploading') {
return
}
if (info.file.status === 'done') {
var response = info.file.response;
if (!response.success) {
this.$message.warning(response.message);
}
}
},
handlePicCancel() {
this.previewVisible = false
this.previewImage=''
},
handlePicView(url){
this.previewImage = this.url.imgerver + "/" + url
this.previewVisible = true
},
handlePreview(file) {
this.previewImage = file.url || file.thumbUrl
this.previewVisible = true
},
getIdCardView(url) {
// let pics = this.model.idcardPic.split(",");
//let pics_len = pics.length;
// 显示上传的最后一个图片
return this.url.imgerver + "/" + url
}
}
}
</script>
......
/**
* online 自定义按钮表达式处理类
*/
export default class ButtonExpHandler {
/**
* 构造器
* @param express
*/
constructor(express,record) {
this._express = express;
this._record = record;
}
get show() {
if(!this._express || this._express==''){
return true;
}
let arr = this._express.split('#');
//获取字段值
let fieldValue = this._record[arr[0]];
//获取表达式
let exp = arr[1].toLowerCase();
//判断表达式
if(exp === 'eq'){
return fieldValue == arr[2];
}else if(exp === 'ne'){
return !(fieldValue == arr[2]);
}else if(exp === 'empty'){
if(arr[2]==='true' || arr[2]===true){
return !fieldValue || fieldValue=='';
}else{
return fieldValue && fieldValue.length>0
}
}else if(exp === 'in'){
let arr2 = arr[2].split(',');
return arr2.indexOf(String(fieldValue))>=0;
}
return false;
}
}
\ No newline at end of file
<template>
<a-card :bordered="false" style="height: 100%">
<online-common-list
:ref="'onl_'+mainModel.currentTableName"
:code="code"
:model="mainModel"
@seleted="onSelected">
</online-common-list>
<a-tabs defaultActiveKey="0">
<a-tab-pane v-for="(item,index) in subList" :tab="item.description" :key="index+''" :forceRender="true" >
<online-common-list
:ref="item.currentTableName"
:code="item.code"
:model="item"
:main="selectedRow">
</online-common-list>
</a-tab-pane>
</a-tabs>
</a-card>
</template>
<script>
import { getAction } from '@/api/manage'
export default {
name: 'OnlCgformErpList',
components:{
},
data(){
return {
code:'',
url: {
getColumns: '/online/cgform/api/getErpColumns/',
},
mainModel:{},
subList:[],
mainId:'',
selectedRow:{}
}
},
watch: {
'$route'() {
// 刷新参数放到这里去触发,就可以刷新相同界面了
this.initColumnConfig()
}
},
created() {
this.initColumnConfig();
},
methods:{
getSubIndex(index){
return index+1 + ''
},
getSubRef(item){
let ref = item.currentTableName
console.log("ref string",ref)
return ref;
},
initColumnConfig(){
if(!this.$route.params.code){
return false
}
this.code = this.$route.params.code
getAction(`${this.url.getColumns}${this.code}`).then((res)=>{
console.log("erp表单配置",res)
if(res.success){
this.mainModel = res.result.main
this.subList = res.result.subList
this.$nextTick(()=>{
this.$refs['onl_'+this.mainModel.currentTableName].initListByModel();
if(this.subList && this.subList.length>0){
for(let item of this.subList){
this.$refs[item.currentTableName][0].initListByModel();
}
}
});
}
})
},
onSelected(row){
console.log("onSelected",row)
this.selectedRow = row;
}
}
}
</script>
<style>
.ant-card-body .table-operator{
margin-bottom: 18px;
}
.ant-table-tbody .ant-table-row td{
padding-top:15px;
padding-bottom:15px;
}
.anty-row-operator button{margin: 0 5px}
.ant-btn-danger{background-color: #ffffff}
.anty-img-wrap{height:25px;position: relative;}
.anty-img-wrap > img{max-height:100%;}
.ant-modal-cust-warp{height: 100%}
.ant-modal-cust-warp .ant-modal-body{height:calc(100% - 110px) !important;overflow-y: auto}
.ant-modal-cust-warp .ant-modal-content{height:90% !important;overflow-y: hidden}
</style>
\ No newline at end of file
/**
* 同步列表,可以同步新增、修改、删除
* @author sunjianlei
* */
export async function syncAllTable(vm, table1) {
vm.$refs.editableTable.resetScrollTop()
let deleteIds = table1.$refs.editableTable.getDeleteIds()
let table1Value
await table1.$refs.editableTable.getValuesPromise(false).then((values) => {
table1Value = values
return vm.$refs.editableTable.getValuesPromise(false)
}).then((values) => {
table1Value.forEach(value => {
let flag = false
values.forEach((thisValue) => {
if (value.id === thisValue.id) {
// 判断是否修改了值
let dbFieldName = thisValue['dbFieldName']
let dbFieldTxt = thisValue['dbFieldTxt']
// return
if (value.dbFieldName !== dbFieldName
|| value.dbFieldTxt !== dbFieldTxt) {
// 修改了
vm.$refs.editableTable.setValues([{
rowKey: thisValue.id,
values: {
dbFieldName: value.dbFieldName,
dbFieldTxt: value.dbFieldTxt
}
}])
}
flag = true
} else {
// id不匹配则有可能是新增也有可能是删除了的
// 遍历传进来的 deleteIds 进行对比
deleteIds.forEach(delId => {
// 对比成功,则删除该条数据
if (delId === thisValue.id) {
vm.$refs.editableTable.removeRows(vm.$refs.editableTable.caseId + delId)
flag = true
}
})
}
})
// return
// 判断是否操作了该条数据,若没有操作则代表要执行新增操作
if (!flag) {
let record = Object.assign({}, value)
vm.columns.forEach(column => {
if (
column.dataIndex !== 'dbFieldName' &&
column.dataIndex !== 'dbFieldTxt'
) {
record[column.dataIndex] = column.defaultValue
}
})
vm.$refs.editableTable.push(record)
}
})
})
}
/**
* 将数据分类并Set进dataSource
* @author sunjianlei
**/
export function setDataSource(vm, queryData) {
let dataSource = []
// 遍历查询出来的数据
queryData.forEach(value => {
let data = { id: value['id'] }
vm.columns.forEach(column => {
let key = column.key
if (key) {
data[key] = value[key]
// 由于多选下拉框返回的是一个数组,所以需要改成 [1,2,3] 数组的形式,否则组件不识别
// if (key === 'indexField') {
// data[key] = value[key].split(',')
// }
}
})
dataSource.push(data)
})
vm.dataSource = dataSource
}
/** 获取主表的初始化数据 */
export function getMasterTableInitialData() {
return [
{
dbFieldName: 'id',
dbFieldTxt: '主键',
dbLength: 36,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '1',
dbIsNull: '0',
// table2
isShowForm: '0',
isShowList: '0',
isReadOnly: '1',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 1
},
{
dbFieldName: 'create_by',
dbFieldTxt: '创建人',
dbLength: 50,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 2
},
{
dbFieldName: 'create_time',
dbFieldTxt: '创建日期',
dbLength: 20,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'Date',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'datetime',
fieldLength: '120',
queryMode: 'single',
orderNum: 3
},
{
dbFieldName: 'update_by',
dbFieldTxt: '更新人',
dbLength: 50,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 4
},
{
dbFieldName: 'update_time',
dbFieldTxt: '更新日期',
dbLength: 20,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'Date',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'datetime',
fieldLength: '120',
queryMode: 'single',
orderNum: 5
},{
dbFieldName: 'sys_org_code',
dbFieldTxt: '所属部门',
dbLength: 64,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 6
}
// {
// dbFieldName: 'sys_org_code',
// dbFieldTxt: '所属部门',
// dbLength: 50,
// dbPointLength: 0,
// dbDefaultVal: '',
// dbType: 'string',
// dbIsKey: false,
// dbIsNull: true
// }, {
// dbFieldName: 'sys_company_code',
// dbFieldTxt: '所属公司',
// dbLength: 50,
// dbPointLength: 0,
// dbDefaultVal: '',
// dbType: 'string',
// dbIsKey: false,
// dbIsNull: true
// }, {
// dbFieldName: 'bpm_status',
// dbFieldTxt: '流程状态',
// dbLength: 32,
// dbPointLength: 0,
// dbDefaultVal: '',
// dbType: 'string',
// dbIsKey: false,
// dbIsNull: true
// }
]
}
/** 获取树的初始化数据 */
export function getTreeNeedFields() {
return [{
dbFieldName: 'pid',
dbFieldTxt: '父级节点',
dbLength: 32,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '1',
isShowList: '0',
fieldShowType: 'text',
fieldLength: '120',
queryMode: 'single',
orderNum: 7
},{
dbFieldName: 'has_child',
dbFieldTxt: '是否有子节点',
dbLength: 3,
dbPointLength: 0,
dbDefaultVal: '',
dbType: 'string',
dbIsKey: '0',
dbIsNull: '1',
// table2
isShowForm: '0',
isShowList: '0',
fieldShowType: 'list',
fieldLength: '120',
queryMode: 'single',
orderNum: 8,
// table3
dictField:"yn"
}]
}
\ No newline at end of file
<template>
<a-card :bordered="false">
<!-- 查询区域 -->
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="24">
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="报表编码">
<a-input placeholder="请输入报表编码" v-model="queryParam.code"></a-input>
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<a-form-item label="报表名字">
<a-input placeholder="请输入报表名字" v-model="queryParam.name"></a-input>
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!-- 操作按钮区域 -->
<div class="table-operator">
<a-button @click="handleAdd" type="primary" icon="plus">录入</a-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<a-menu slot="overlay">
<a-menu-item key="1" @click="batchDel">
<a-icon type="delete"/>
删除
</a-menu-item>
</a-menu>
<a-button style="margin-left: 8px"> 批量操作
<a-icon type="down"/>
</a-button>
</a-dropdown>
</div>
<!-- table区域-begin -->
<div>
<div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
<i class="anticon anticon-info-circle ant-alert-icon"></i>
已选择
<a style="font-weight: 600">
{{ selectedRowKeys.length }}
</a>
<a style="margin-left: 24px" @click="onClearSelected">清空</a>
</div>
<a-table
ref="table"
size="middle"
bordered
rowKey="id"
:columns="columns"
:dataSource="dataSource"
:pagination="ipagination"
:loading="loading"
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
@change="handleTableChange">
<span slot="action" slot-scope="text, record">
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical"/>
<a-dropdown>
<a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
<a-menu slot="overlay">
<a-menu-item @click="popReportURL(record.id)">
配置地址
</a-menu-item>
<a-menu-item>
<a @click="goPageOnline(record.id)">功能测试</a>
</a-menu-item>
<a-menu-item>
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
<a>删除</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown>
</span>
</a-table>
</div>
<!-- table区域-end -->
<!-- 表单区域 -->
<onlCgreportHead-modal ref="modalForm" @ok="modalFormOk"></onlCgreportHead-modal>
<!-- 提示online报表链接 -->
<a-modal
title="报表访问链接"
:visible="visible"
@cancel="handleCancel">
<template slot="footer">
<a-button @click="handleCancel">关闭</a-button>
<a-button type="primary" class="copy-this-text" :data-clipboard-text="reportUrlText" @click="onCopyUrl">复制</a-button>
</template>
<p>{{ reportUrlText }}</p>
</a-modal>
</a-card>
</template>
<script>
import {JeecgListMixin} from '@/mixins/JeecgListMixin'
import Clipboard from 'clipboard'
import { getAction } from '@/api/manage'
export default {
name: 'OnlCgreportHeadList',
mixins: [JeecgListMixin],
components: {
Clipboard
},
data() {
return {
description: '在线报表配置管理页面',
visible:false,
reportUrlText:'',
// 表头
columns: [
{
title: '报表名称',
align: 'center',
dataIndex: 'name'
},
{
title: '编码',
align: 'center',
dataIndex: 'code'
},
{
title: '查询SQL',
align: 'center',
dataIndex: 'cgrSql'
},
{
title: '数据源',
align: 'center',
dataIndex: 'dbSource'
},
{
title: '创建时间',
align: 'center',
dataIndex: 'createTime'
},
{
title: '描述',
align: 'center',
dataIndex: 'content'
},
{
title: '操作',
dataIndex: 'action',
align: 'center',
scopedSlots: { customRender: 'action' }
}
],
url: {
list: '/online/cgreport/head/list',
delete: '/online/cgreport/head/delete',
deleteBatch: '/online/cgreport/head/deleteBatch',
getParamsInfo:'/online/cgreport/api/getParamsInfo/'
}
}
},
methods: {
initReportUrlText(id){
getAction(this.url.getParamsInfo+id).then((res) => {
let textUrl = ""
if (res.success) {
if(res.result && res.result.length>0){
for(let i of res.result){
textUrl+=i.paramName+"=${"+i.paramName+"}&"
}
}
} else {
this.$message.warning(res.message)
}
if(textUrl.length>0){
textUrl = textUrl.substring(0,textUrl.length-1)
this.reportUrlText = `/online/cgreport/${id}?${textUrl}`
}else{
this.reportUrlText = `/online/cgreport/${id}`
}
})
},
goPageOnline(id){
this.$router.push({path: '/online/cgreport/'+id})
},
popReportURL(id){
this.visible = true;
this.initReportUrlText(id)
},
handleCancel(){
this.visible = false
this.reportUrlText = '';
},
onCopyUrl(){
var clipboard = new Clipboard('.copy-this-text')
clipboard.on('success', () => {
clipboard.destroy()
this.$message.success('复制成功')
this.handleCancel()
})
clipboard.on('error', () => {
this.$message.error('该浏览器不支持自动复制')
clipboard.destroy()
})
}
}
}
</script>
<style lang="less" scoped>
.ant-card-body .table-operator {
margin-bottom: 18px;
}
.ant-table-tbody .ant-table-row td {
padding-top: 15px;
padding-bottom: 15px;
}
.anty-row-operator button {
margin: 0 5px
}
.ant-btn-danger {
background-color: #ffffff
}
.ant-modal-cust-warp {
height: 100%
}
.ant-modal-cust-warp .ant-modal-body {
height: calc(100% - 110px) !important;
overflow-y: auto
}
.ant-modal-cust-warp .ant-modal-content {
height: 90% !important;
overflow-y: hidden
}
</style>
\ No newline at end of file
......@@ -14,6 +14,12 @@
<a-input placeholder="请输入文件地址" v-model="queryParam.url"></a-input>
</a-form-item>
</a-col>
<a-col :md="6" :sm="8">
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
</span>
</a-col>
</a-row>
</a-form>
</div>
......
......@@ -79,26 +79,30 @@
{
title: '表名',
align: 'center',
dataIndex: 'dataTable'
dataIndex: 'dataTable',
width: "120"
}, {
title: '数据ID',
align: 'center',
dataIndex: 'dataId'
dataIndex: 'dataId',
width: "120"
}, {
title: '版本号',
align: 'center',
dataIndex: 'dataVersion'
dataIndex: 'dataVersion',
width: "50"
}, {
title: '数据内容',
align: 'center',
dataIndex: 'dataContent',
width: "120px",
width: "150",
scopedSlots: {customRender: 'dataContent'},
}, {
title: '创建人',
align: 'center',
dataIndex: 'createBy'
}
dataIndex: 'createBy',
width: "100"
},
],
url: {
list: "/sys/dataLog/list",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment