mirror of https://github.com/jeecgboot/jeecg-boot
zhangdaiscott
4 years ago
614 changed files with 206292 additions and 29220 deletions
@ -0,0 +1,3 @@
|
||||
NODE_ENV=production |
||||
VUE_APP_PLATFORM_NAME=Jeecg-Boot 企业级快速开发平台 |
||||
VUE_APP_SSO=false |
@ -0,0 +1,4 @@
|
||||
NODE_ENV=development |
||||
VUE_APP_API_BASE_URL=http://localhost:8080/jeecg-boot |
||||
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas |
||||
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview |
@ -0,0 +1,4 @@
|
||||
NODE_ENV=production |
||||
VUE_APP_API_BASE_URL=http://boot.jeecg.com:8080/jeecg-boot |
||||
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas |
||||
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview |
@ -0,0 +1,4 @@
|
||||
NODE_ENV=production |
||||
VUE_APP_API_BASE_URL=https://bootapi.jeecg.com |
||||
VUE_APP_CAS_BASE_URL=http://localhost:8888/cas |
||||
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview |
@ -1,7 +1,11 @@
|
||||
import T from './JDictSelectTag.vue' |
||||
const JDictSelectTag = { |
||||
import JDictSelectTag from './JDictSelectTag.vue' |
||||
import JMultiSelectTag from './JMultiSelectTag.vue' |
||||
import JSearchSelectTag from './JSearchSelectTag.vue' |
||||
|
||||
export default { |
||||
install: function (Vue) { |
||||
Vue.component('JDictSelectTag',T); |
||||
Vue.component('JDictSelectTag',JDictSelectTag); |
||||
Vue.component('JMultiSelectTag',JMultiSelectTag); |
||||
Vue.component('JSearchSelectTag',JSearchSelectTag); |
||||
} |
||||
} |
||||
export default JDictSelectTag; |
||||
} |
@ -1,11 +1,41 @@
|
||||
import JModal from './JModal' |
||||
import JFormContainer from './JFormContainer.vue' |
||||
import JPopup from './JPopup.vue' |
||||
import JMarkdownEditor from './JMarkdownEditor' |
||||
import JCodeEditor from './JCodeEditor.vue' |
||||
import JEditor from './JEditor.vue' |
||||
import JEditableTable from './JEditableTable.vue' |
||||
import JAreaLinkage from './JAreaLinkage.vue' |
||||
import JSuperQuery from './JSuperQuery.vue' |
||||
import JUpload from './JUpload.vue' |
||||
import JTreeSelect from './JTreeSelect.vue' |
||||
import JCategorySelect from './JCategorySelect.vue' |
||||
import JImageUpload from './JImageUpload.vue' |
||||
import JTreeDict from './JTreeDict.vue' |
||||
import JCheckbox from './JCheckbox.vue' |
||||
import JCron from './JCron.vue' |
||||
import JSelectMultiple from './JSelectMultiple.vue' |
||||
import JPopupOnlReport from './modal/JPopupOnlReport.vue' |
||||
|
||||
export default { |
||||
install(Vue) { |
||||
Vue.component('JFormContainer', JFormContainer) |
||||
Vue.component('JPopup', JPopup) |
||||
Vue.component(JModal.name, JModal) |
||||
Vue.component('JMarkdownEditor', JMarkdownEditor) |
||||
Vue.component('JEditor', JEditor) |
||||
Vue.component('JCodeEditor', JCodeEditor) |
||||
Vue.component('JEditableTable', JEditableTable) |
||||
Vue.component('JAreaLinkage', JAreaLinkage) |
||||
Vue.component('JSuperQuery', JSuperQuery) |
||||
Vue.component('JUpload', JUpload) |
||||
Vue.component('JTreeSelect', JTreeSelect) |
||||
Vue.component('JCategorySelect', JCategorySelect) |
||||
Vue.component('JImageUpload', JImageUpload) |
||||
Vue.component('JTreeDict', JTreeDict) |
||||
Vue.component('JCheckbox', JCheckbox) |
||||
Vue.component('JCron', JCron) |
||||
Vue.component('JPopupOnlReport', JPopupOnlReport) |
||||
Vue.component('JSelectMultiple', JSelectMultiple) |
||||
} |
||||
} |
@ -0,0 +1,10 @@
|
||||
/** init domain config */ |
||||
import Vue from 'vue' |
||||
//设置全局API_BASE_URL
|
||||
Vue.prototype.API_BASE_URL = process.env.VUE_APP_API_BASE_URL |
||||
window._CONFIG['domianURL'] = Vue.prototype.API_BASE_URL |
||||
//单点登录地址
|
||||
window._CONFIG['casPrefixUrl'] = process.env.VUE_APP_CAS_BASE_URL |
||||
window._CONFIG['onlinePreviewDomainURL'] = process.env.VUE_APP_ONLINE_BASE_URL |
||||
window._CONFIG['staticDomainURL'] = Vue.prototype.API_BASE_URL + '/sys/common/static' |
||||
window._CONFIG['pdfDomainURL'] = Vue.prototype.API_BASE_URL+ '/sys/common/pdf/pdfPreviewIframe' |
@ -1,116 +0,0 @@
|
||||
import { filterMultiDictText } from '@/components/dict/JDictSelectUtil' |
||||
|
||||
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' } } |
||||
}, |
||||
on: { |
||||
ok: () => this.hrefComponent.model.visible = false, |
||||
cancel: () => this.hrefComponent.model.visible = false |
||||
}, |
||||
is: null, |
||||
params: {}, |
||||
} |
||||
} |
||||
}, |
||||
methods: { |
||||
// 处理接收href参数
|
||||
handleAcceptHrefParams(){ |
||||
this.acceptHrefParams={} |
||||
let hrefparam = this.$route.query; |
||||
if(hrefparam){ |
||||
this.acceptHrefParams = {...hrefparam} |
||||
} |
||||
}, |
||||
//支持链接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\-\.\?\,\'\/\\\+&%\$#_]*)?/ |
||||
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 = '操作' |
||||
this.hrefComponent.is = () => import('@/views/' + (path.startsWith('/') ? path.slice(1) : path)) |
||||
}, |
||||
/** 处理列中的 href 跳转和 dict 字典,使两者可以兼容存在 */ |
||||
handleColumnHrefAndDict(column = {}, fieldHrefSlotKeysMap = {}) { |
||||
let { customRender, hrefSlotName } = column |
||||
if (!hrefSlotName && (column.scopedSlots && column.scopedSlots.customRender)) { |
||||
//hrefSlotName = column.scopedSlots.customRender
|
||||
} |
||||
// 如果 customRender 有值则代表使用了字典
|
||||
// 如果 hrefSlotName 有值则代表使用了href跳转
|
||||
// 两者可以兼容。兼容的具体思路为:先获取到字典替换的值,再添加href链接跳转
|
||||
if (customRender || hrefSlotName) { |
||||
let dictCode = customRender |
||||
let replaceFlag = '_replace_text_' |
||||
column.customRender = (text, record) => { |
||||
let value = text |
||||
// 如果 dictCode 有值,就进行字典转换
|
||||
if (dictCode) { |
||||
if (dictCode.startsWith(replaceFlag)) { |
||||
let textFieldName = dictCode.replace(replaceFlag, '') |
||||
value = record[textFieldName] |
||||
} else { |
||||
value = filterMultiDictText(this.dictOptions[dictCode], text) |
||||
} |
||||
} |
||||
// 如果 hrefSlotName 有值,就生成一个 a 标签,包裹住字典替换后(或原生)的值
|
||||
if (hrefSlotName) { |
||||
let field = fieldHrefSlotKeysMap[hrefSlotName] |
||||
if (field) { |
||||
// 此处为 JSX 语法
|
||||
return (<a onClick={() => this.handleClickFieldHref(field, record)}>{value}</a>) |
||||
} |
||||
} |
||||
return value |
||||
} |
||||
} |
||||
}, |
||||
|
||||
} |
||||
} |
@ -1,60 +0,0 @@
|
||||
import router from '@/router' |
||||
import { getAction } from '@api/manage' |
||||
|
||||
/** 表单设计器路由类型 */ |
||||
export const DESFORM_ROUTE_TYPE = { |
||||
/** 跳转到表单 */ |
||||
form: '1', |
||||
/** 跳转到菜单 */ |
||||
menu: '2', |
||||
/** 跳转到外部链接 */ |
||||
href: '3', |
||||
} |
||||
/** 表单设计器路由跳转带过来的ID名字 */ |
||||
export const DESFORM_ROUTE_DATA_ID = 'routeDataId' |
||||
|
||||
/** |
||||
* 获取当前路由或指定路由的 routeDataId |
||||
* |
||||
* @param $route 路由对象,默认为当前路由 |
||||
*/ |
||||
export function getDesformRouteDataId($route) { |
||||
if (arguments.length === 0) { |
||||
$route = router.currentRoute |
||||
} |
||||
if ($route) { |
||||
return $route.query[DESFORM_ROUTE_DATA_ID] |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* 根据路由跳转带过来的ID来获取表单设计器的数据 |
||||
* @param param 表单设计器路由跳转带过来的ID(可以直接传id字符串,也可以传 this.$route,自动从$route里获取id,如果不传就获取当前路由的参数) |
||||
* @returns {Promise<void>} |
||||
*/ |
||||
export async function getDesformDataByRouteDataId(param) { |
||||
if (!param) { |
||||
param = router.currentRoute |
||||
} |
||||
let id |
||||
if (typeof param == 'string') { |
||||
id = param |
||||
} else if (typeof param.query === 'object') { |
||||
id = getDesformRouteDataId(param) |
||||
if (!id) { |
||||
// 当前$route.query里没有带表单设计器路由ID,直接返回null
|
||||
return null |
||||
} |
||||
} else { |
||||
throw new Error('传递的参数不能识别,可以直接传id字符串,也可以传 this.$route,自动从$route里获取id,如果不传就获取当前路由的参数') |
||||
} |
||||
let url = `/desform/data/queryById?id=${id}` |
||||
let { success, result, message } = await getAction(url) |
||||
if (success) { |
||||
result.desformDataJson = JSON.parse(result.desformDataJson) |
||||
return result |
||||
} else { |
||||
throw new Error('表单设计器路由数据获取失败:' + message) |
||||
} |
||||
} |
@ -1,185 +0,0 @@
|
||||
/* |
||||
* 省市区联动组件通用工具类。 |
||||
* 列表翻译、组件反推、表单设计器组件反推等功能都可以用该工具类实现。 |
||||
* |
||||
* 1. leafName字段的意义: |
||||
* AntdvUI和ElementUI的叶级节点名字是不一样的, |
||||
* AntdvUI的名字是 isLeaf,ElementUI是 leaf, |
||||
* 默认是AntdvUI的名字,在表单设计器那边需要手动 setLeafName |
||||
*/ |
||||
|
||||
import { pcaa } from 'area-data' |
||||
|
||||
export { pcaa } |
||||
|
||||
/** 根节点Code = 86 */ |
||||
export const ROOT_CODE = '86' |
||||
|
||||
/** 叶级节点的名字 */ |
||||
let leafName = 'isLeaf' |
||||
|
||||
/** |
||||
* set leafName |
||||
* @param $leafName |
||||
*/ |
||||
export function setLeafName($leafName = 'isLeaf') { |
||||
leafName = $leafName |
||||
} |
||||
|
||||
/** |
||||
* 将地区数据转换成下拉框等组件可识别的Options数组 |
||||
* @param data 地区data |
||||
* @param labelName label标签名字 |
||||
* @return |
||||
*/ |
||||
export function transToOptions(data, labelName = 'label') { |
||||
if (data) { |
||||
return Object.keys(data).map(key => ({ value: key, [labelName]: data[key] })) |
||||
} else { |
||||
return [] |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取子级Data对象 |
||||
* |
||||
* @param code 父级地区Code |
||||
*/ |
||||
export function getChildrenDataByCode(code) { |
||||
return pcaa[code] |
||||
} |
||||
|
||||
/** |
||||
* 获取子级Options对象 |
||||
* |
||||
* @param code 父级地区Code |
||||
* @return {Array} 返回的值一定是一个数组,如果数组length===0,则代表没有子级 |
||||
*/ |
||||
export function getChildrenOptionsByCode(code) { |
||||
let options = [] |
||||
let data = getChildrenDataByCode(code) |
||||
if (data) { |
||||
for (let key in data) { |
||||
if (data.hasOwnProperty(key)) { |
||||
options.push({ value: key, label: data[key], }) |
||||
} |
||||
} |
||||
return options |
||||
} else { |
||||
return [] |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取兄弟Data对象 |
||||
* |
||||
* @param code 地区Code |
||||
*/ |
||||
export function getSiblingsDataByCode(code) { |
||||
if (typeof code === 'string' && code.length === 6) { |
||||
// 父级节点Code
|
||||
let parentCode = `${code.substring(0, 4)}00` |
||||
return getChildrenDataByCode(parentCode) |
||||
} else { |
||||
console.warn('[getSiblingsByCode]: code不合法') |
||||
return null |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取对应的 Label |
||||
* |
||||
* @param code 地区Code |
||||
*/ |
||||
export function getLabelByCode(code) { |
||||
if (code) { |
||||
// 获取当前code所有的兄弟节点
|
||||
let siblingsData = getSiblingsDataByCode(code) |
||||
// 然后取出自己的值
|
||||
return siblingsData[code] |
||||
} else { |
||||
return code |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取所有的 Label,包括自身和所有父级 |
||||
* |
||||
* @param code 地区Code |
||||
* @param joinText 合并文本 |
||||
*/ |
||||
export function getAllLabelByCode(code, joinText = ' / ') { |
||||
if (code) { |
||||
let { labels } = getAllParentByCode(code) |
||||
return labels.join(joinText) |
||||
} else { |
||||
return code |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 通过子级 code 反推所有父级的 code |
||||
* |
||||
* @param code 子级地区Code |
||||
* @returns {Object} options: 所有父级的选项;codes: 所有父级的code;labels: 所有父级的显示名 |
||||
*/ |
||||
export function getAllParentByCode(code) { |
||||
code = (typeof code === 'string' ? code : '').trim() |
||||
if (code.length === 0) { |
||||
return { options: [], codes: [], labels: [] } |
||||
} |
||||
// 获取第一级数据
|
||||
let rootOptions = getChildrenOptionsByCode(ROOT_CODE) |
||||
hasChildren(rootOptions) |
||||
// 父级code数组,code长度
|
||||
let parentCodes = [code], length = code.length |
||||
// 父级label数组
|
||||
let parentLabels = [getLabelByCode(code)] |
||||
// 级别,位数,是否继续循环
|
||||
let level = 1, num = 2, flag = true |
||||
|
||||
let options = rootOptions |
||||
do { |
||||
let endIndex = num * level++ |
||||
// 末尾补零个数
|
||||
let zeroPadding = [...new Array(length - endIndex)].map(i => '0').join('') |
||||
// 裁剪并补零(获取上级的方式就是将当前code的后两位变成 00)
|
||||
let parentCode = code.substring(0, endIndex) + zeroPadding |
||||
// 是否找到在选项中的位置
|
||||
let findIt = false |
||||
for (let option of options) { |
||||
if (option.value === parentCode) { |
||||
if (option[leafName]) { |
||||
flag = false |
||||
} else { |
||||
let children = getChildrenOptionsByCode(option.value) |
||||
hasChildren(children) |
||||
option.children = children |
||||
options = children |
||||
parentCodes.splice(parentCodes.length - 1, 0, option.value) |
||||
parentLabels.splice(parentLabels.length - 1, 0, option.label) |
||||
} |
||||
findIt = true |
||||
break |
||||
} |
||||
} |
||||
|
||||
if (findIt) { |
||||
findIt = false |
||||
} else { |
||||
flag = false |
||||
} |
||||
} while (flag) |
||||
return { options: rootOptions, codes: parentCodes, labels: parentLabels } |
||||
} |
||||
|
||||
/** |
||||
* 判断所有的项是否有子节点 |
||||
* |
||||
* @param options |
||||
*/ |
||||
export function hasChildren(options) { |
||||
options.forEach(option => { |
||||
option[leafName] = getChildrenOptionsByCode(option.value).length === 0 |
||||
}) |
||||
} |
@ -1,15 +0,0 @@
|
||||
<template> |
||||
<div> |
||||
404 page |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
name: "404" |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
|
||||
</style> |
@ -1,101 +1,111 @@
|
||||
<template> |
||||
<a-card :bordered="false" style="height: 100%"> |
||||
<div style="padding-bottom: 2px"> |
||||
<a-alert type="warning" show-icon> |
||||
<div slot="message" style="width: 100%"> |
||||
<span>路由配置请慎重</span> |
||||
<span style="display:inline-block;float:right;padding-right: 5px"> |
||||
<a @click="clearRedis"><a-icon type="reload" />清除缓存</a> |
||||
</span> |
||||
</div> |
||||
</a-alert> |
||||
<a-card :bordered="false"> |
||||
<!-- 操作按钮区域 --> |
||||
<div class="table-operator"> |
||||
<a-button @click="showModal(null)" type="primary" icon="plus">新增</a-button> |
||||
</div> |
||||
<div :id="eleId" :style="{ height: editorHeight + 'px', width: '100%' }"></div> |
||||
<div style="text-align: center;padding-top:10px"> |
||||
<a-button type="primary" @click="submitForm" style="width:160px">保存</a-button> |
||||
<div> |
||||
<a-table |
||||
ref="table" |
||||
size="middle" |
||||
:scroll="{x:true}" |
||||
bordered |
||||
rowKey="id" |
||||
:columns="columns" |
||||
:dataSource="dataSource" |
||||
:pagination="false" |
||||
:loading="loading" |
||||
class="j-table-force-nowrap" |
||||
@change="handleTableChange"> |
||||
<span slot="status" slot-scope="text, record, index"> |
||||
<a-tag color="pink" v-if="text==0">禁用</a-tag> |
||||
<a-tag color="#87d068" v-if="text==1" >正常</a-tag> |
||||
</span> |
||||
<span slot="action" slot-scope="text, record"> |
||||
<a @click="showModal(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> |
||||
<a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)"> |
||||
<a>删除</a> |
||||
</a-popconfirm> |
||||
</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown> |
||||
</span> |
||||
|
||||
</a-table> |
||||
</div> |
||||
<gate-way-route-modal ref="modalForm" @ok="modalFormOk"></gate-way-route-modal> |
||||
</a-card> |
||||
</template> |
||||
|
||||
<script> |
||||
import JsonEditor from 'jsoneditor' |
||||
import 'jsoneditor/dist/jsoneditor.min.css' |
||||
import { getAction, postAction } from '@/api/manage' |
||||
|
||||
import '@/assets/less/TableExpand.less' |
||||
import { mixinDevice } from '@/utils/mixin' |
||||
import { JeecgListMixin } from '@/mixins/JeecgListMixin' |
||||
import GateWayRouteModal from './modules/GateWayRouteModal' |
||||
|
||||
export default { |
||||
name: "SysGatewayRouteList", |
||||
data () { |
||||
name: 'TenantList', |
||||
mixins: [JeecgListMixin, mixinDevice], |
||||
components: { |
||||
GateWayRouteModal |
||||
}, |
||||
data() { |
||||
return { |
||||
eleId:'jsoneditor', |
||||
description: 'gateway路由管理管理页面', |
||||
editor: null, |
||||
editorWidth:400, |
||||
editorHeight:500, |
||||
url:{ |
||||
description: 'adad管理页面', |
||||
// 表头
|
||||
columns: [ |
||||
{ |
||||
title: '路由ID', |
||||
align: 'center', |
||||
dataIndex: 'routerId' |
||||
}, { |
||||
title: '路由名称', |
||||
align: 'center', |
||||
dataIndex: 'name' |
||||
}, |
||||
{ |
||||
title: '路由URI', |
||||
align: 'center', |
||||
dataIndex: 'uri' |
||||
}, |
||||
{ |
||||
title: '状态', |
||||
align: 'center', |
||||
dataIndex: 'status', |
||||
scopedSlots: { customRender: 'status' } |
||||
}, |
||||
{ |
||||
title: '操作', |
||||
dataIndex: 'action', |
||||
align: 'center', |
||||
fixed: 'right', |
||||
width: 147, |
||||
scopedSlots: { customRender: 'action' } |
||||
} |
||||
], |
||||
url: { |
||||
list: '/sys/gatewayRoute/list', |
||||
update: '/sys/gatewayRoute/updateAll', |
||||
clear: '/sys/gatewayRoute/clearRedis' |
||||
delete: '/sys/gatewayRoute/delete' |
||||
}, |
||||
|
||||
dictOptions: {} |
||||
} |
||||
}, |
||||
created() { |
||||
let winWidth = window.innerWidth; |
||||
console.log("页面宽度",winWidth) |
||||
this.editorWidth = winWidth |
||||
|
||||
}, |
||||
mounted(){ |
||||
this.initJsonEditor(); |
||||
}, |
||||
methods: { |
||||
initJsonEditor() { |
||||
let container = document.getElementById(this.eleId); |
||||
let options = { |
||||
modes: ['text', 'code', 'tree', 'form', 'view'], |
||||
mode: 'tree', |
||||
ace: ace, |
||||
sortObjectKeys: 'code', |
||||
mainMenuBar:['format'] |
||||
}; |
||||
this.editor = new JsonEditor(container, options); |
||||
this.initRouteData(); |
||||
}, |
||||
initRouteData(){ |
||||
getAction(this.url.list).then(res=>{ |
||||
if(res.success){ |
||||
let array = res.result |
||||
console.log('当前路由配置信息为', array) |
||||
this.editor.set(array) |
||||
} |
||||
}) |
||||
}, |
||||
// 获取json
|
||||
submitForm() { |
||||
let text = this.editor.getText() |
||||
console.log("保存的json数据",text) |
||||
if(!text || text.length<=0 || text=='{}' || text=='[]'){ |
||||
this.$message.warning('未录入任何信息') |
||||
return ; |
||||
} |
||||
postAction(this.url.update,{ |
||||
routes:text |
||||
}).then(res=>{ |
||||
if(res.success){ |
||||
this.$message.success(res.message) |
||||
}else{ |
||||
this.$message.error(res.message) |
||||
} |
||||
}) |
||||
}, |
||||
clearRedis(){ |
||||
getAction(this.url.clear).then(res=>{ |
||||
if(res.success){ |
||||
this.$message.success(res.message) |
||||
} |
||||
}) |
||||
showModal(record) { |
||||
this.$refs['modalForm'].show(record) |
||||
} |
||||
|
||||
} |
||||
} |
||||
</script> |
||||
<style scoped> |
||||
@import '~@assets/less/common.less'; |
||||
</style> |
@ -0,0 +1,101 @@
|
||||
<!--<template>--> |
||||
<!-- <a-card :bordered="false" style="height: 100%">--> |
||||
<!-- <div style="padding-bottom: 2px">--> |
||||
<!-- <a-alert type="warning" show-icon>--> |
||||
<!-- <div slot="message" style="width: 100%">--> |
||||
<!-- <span>路由配置请慎重</span>--> |
||||
<!-- <span style="display:inline-block;float:right;padding-right: 5px">--> |
||||
<!-- <a @click="clearRedis"><a-icon type="reload" />清除缓存</a>--> |
||||
<!-- </span>--> |
||||
<!-- </div>--> |
||||
<!-- </a-alert>--> |
||||
<!-- </div>--> |
||||
<!-- <div :id="eleId" :style="{ height: editorHeight + 'px', width: '100%' }"></div>--> |
||||
<!-- <div style="text-align: center;padding-top:10px">--> |
||||
<!-- <a-button type="primary" @click="submitForm" style="width:160px">保存</a-button>--> |
||||
<!-- </div>--> |
||||
<!-- </a-card>--> |
||||
<!--</template>--> |
||||
|
||||
<!--<script>--> |
||||
<!-- import JsonEditor from 'jsoneditor'--> |
||||
<!-- import 'jsoneditor/dist/jsoneditor.min.css'--> |
||||
<!-- import { getAction, postAction } from '@/api/manage'--> |
||||
|
||||
<!-- export default {--> |
||||
<!-- name: "SysGatewayRouteList",--> |
||||
<!-- data () {--> |
||||
<!-- return {--> |
||||
<!-- eleId:'jsoneditor',--> |
||||
<!-- description: 'gateway路由管理管理页面',--> |
||||
<!-- editor: null,--> |
||||
<!-- editorWidth:400,--> |
||||
<!-- editorHeight:500,--> |
||||
<!-- url:{--> |
||||
<!-- list: '/sys/gatewayRoute/list',--> |
||||
<!-- update: '/sys/gatewayRoute/updateAll',--> |
||||
<!-- clear: '/sys/gatewayRoute/clearRedis'--> |
||||
<!-- },--> |
||||
|
||||
<!-- }--> |
||||
<!-- },--> |
||||
<!-- created() {--> |
||||
<!-- let winWidth = window.innerWidth;--> |
||||
<!-- console.log("页面宽度",winWidth)--> |
||||
<!-- this.editorWidth = winWidth--> |
||||
|
||||
<!-- },--> |
||||
<!-- mounted(){--> |
||||
<!-- this.initJsonEditor();--> |
||||
<!-- },--> |
||||
<!-- methods: {--> |
||||
<!-- initJsonEditor() {--> |
||||
<!-- let container = document.getElementById(this.eleId);--> |
||||
<!-- let options = {--> |
||||
<!-- modes: ['text', 'code', 'tree', 'form', 'view'],--> |
||||
<!-- mode: 'tree',--> |
||||
<!-- ace: ace,--> |
||||
<!-- sortObjectKeys: 'code',--> |
||||
<!-- mainMenuBar:['format']--> |
||||
<!-- };--> |
||||
<!-- this.editor = new JsonEditor(container, options);--> |
||||
<!-- this.initRouteData();--> |
||||
<!-- },--> |
||||
<!-- initRouteData(){--> |
||||
<!-- getAction(this.url.list).then(res=>{--> |
||||
<!-- if(res.success){--> |
||||
<!-- let array = res.result--> |
||||
<!-- console.log('当前路由配置信息为', array)--> |
||||
<!-- this.editor.set(array)--> |
||||
<!-- }--> |
||||
<!-- })--> |
||||
<!-- },--> |
||||
<!-- // 获取json-->
|
||||
<!-- submitForm() {--> |
||||
<!-- let text = this.editor.getText()--> |
||||
<!-- console.log("保存的json数据",text)--> |
||||
<!-- if(!text || text.length<=0 || text=='{}' || text=='[]'){--> |
||||
<!-- this.$message.warning('未录入任何信息')--> |
||||
<!-- return ;--> |
||||
<!-- }--> |
||||
<!-- postAction(this.url.update,{--> |
||||
<!-- routes:text--> |
||||
<!-- }).then(res=>{--> |
||||
<!-- if(res.success){--> |
||||
<!-- this.$message.success(res.message)--> |
||||
<!-- }else{--> |
||||
<!-- this.$message.error(res.message)--> |
||||
<!-- }--> |
||||
<!-- })--> |
||||
<!-- },--> |
||||
<!-- clearRedis(){--> |
||||
<!-- getAction(this.url.clear).then(res=>{--> |
||||
<!-- if(res.success){--> |
||||
<!-- this.$message.success(res.message)--> |
||||
<!-- }--> |
||||
<!-- })--> |
||||
<!-- }--> |
||||
|
||||
<!-- }--> |
||||
<!-- }--> |
||||
<!--</script>--> |
@ -0,0 +1,306 @@
|
||||
<template> |
||||
<a-drawer |
||||
:title="title" |
||||
:maskClosable="true" |
||||
width="45%" |
||||
placement="right" |
||||
v-if="visible" |
||||
:closable="true" |
||||
@close="handleCancel" |
||||
:visible="visible" |
||||
style="overflow: auto;padding-bottom: 53px;"> |
||||
<a-form-model ref="form" :layout="layout" :label-col="labelCol" :wrapper-col="wrapperCol" :model="router"> |
||||
<a-form-model-item label="路由ID"> |
||||
<a-input v-model="router.routerId" placeholder="路由唯一ID"/> |
||||
</a-form-model-item> |
||||
<a-form-model-item label="路由名称"> |
||||
<a-input v-model="router.name" placeholder="路由名称"/> |
||||
</a-form-model-item> |
||||
<a-form-model-item label="路由URI"> |
||||
<a-input v-model="router.uri" placeholder="路由URL"/> |
||||
</a-form-model-item> |
||||
<a-form-model-item label="路由状态" prop="status"> |
||||
<a-switch default-checked v-model="router.status"/> |
||||
</a-form-model-item> |
||||
|
||||
<a-form-model-item prop="predicates" label="路由条件"> |
||||
<div v-for="(item,index) in router.predicates"> |
||||
<a-divider>{{item.name}} |
||||
<a-icon type="delete" size="22" @click="removePredicate(router,index)"/> |
||||
</a-divider> |
||||
<div> |
||||
<template v-for="(tag, index) in item.args"> |
||||
<a-input v-if="index==currentTagIndex" ref="input" type="text" size="small" |
||||
:style="{ width: '190px' }" |
||||
:value="tag" |
||||
@change="handleInputChange" @blur="handleInputEditConfirm(item,tag,index)" |
||||
@keyup.enter="handleInputEditConfirm(item,tag,index)"/> |
||||
<a-tag v-else :key="tag" :closable="true" @close="() => removeTag(item,tag)" @click="editTag(tag,index)"> |
||||
{{ tag }} |
||||
</a-tag> |
||||
</template> |
||||
<a-input v-if="inputVisible&&index==currentNameIndex" ref="input" type="text" size="small" |
||||
:style="{ width: '100px' }" |
||||
:value="inputValue" |
||||
@change="handleInputChange" @blur="handleInputConfirm(item)" |
||||
@keyup.enter="handleInputConfirm(item)"/> |
||||
<a-tag v-else style="background: #fff; borderStyle: dashed;" @click="showInput(item,index)"> |
||||
<a-icon type="plus"/> |
||||
新建{{item.name}} |
||||
</a-tag> |
||||
</div> |
||||
</div> |
||||
<p class="btn" style="padding-top: 10px"> |
||||
<a-dropdown> |
||||
<a-menu slot="overlay" @click="predicatesHandleMenuClick"> |
||||
<a-menu-item :key="item" v-for="item in tagArray">{{item}}</a-menu-item> |
||||
</a-menu> |
||||
<a-button type="dashed" style="margin-left: 8px;width:100%"> 添加路由条件 |
||||
<a-icon type="down"/> |
||||
</a-button> |
||||
</a-dropdown> |
||||
</p> |
||||
</a-form-model-item> |
||||
<a-form-model-item prop="predicates" label="过滤器"> |
||||
<div v-for="(item,index) in router.filters"> |
||||
<a-divider>{{item.name}} |
||||
<a-icon type="delete" size="22" @click="removeFilter(router,index)"/> |
||||
</a-divider> |
||||
<div v-for="(tag, index) in item.args" :key="tag.key"> |
||||
<a-input v-model="tag.key" placeholder="参数键" style="width: 45%; margin-right: 8px"/> |
||||
<a-input v-model="tag.value" placeholder="参数值" style="width: 40%; margin-right: 8px"/> |
||||
<a-icon class="dynamic-delete-button" type="minus-circle-o" @click="removeFilterParams(item,index)"/> |
||||
</div> |
||||
<a-button type="dashed" style="margin-left:28%;width: 30%" size="small" @click="addFilterParams(item)"> |
||||
<a-icon type="plus"/> |
||||
添加参数 |
||||
</a-button> |
||||
</div> |
||||
<p class="btn" style="padding-top: 10px"> |
||||
<a-dropdown> |
||||
<a-menu slot="overlay" @click="filterHandleMenuClick"> |
||||
<a-menu-item :key="item.key" :name="item.name" v-for="item in filterArray">{{item.name}}</a-menu-item> |
||||
</a-menu> |
||||
<a-button type="dashed" style="margin-left: 8px;width:100%"> 添加过滤器 |
||||
<a-icon type="down"/> |
||||
</a-button> |
||||
</a-dropdown> |
||||
</p> |
||||
</a-form-model-item> |
||||
<a-row :style="{textAlign:'right'}" class="drawer-bootom-button"> |
||||
<a-button :style="{marginRight: '8px'}" @click="handleCancel"> |
||||
关闭 |
||||
</a-button> |
||||
<a-button @click="handleSubmit" type="primary">确定</a-button> |
||||
</a-row> |
||||
</a-form-model> |
||||
|
||||
</a-drawer> |
||||
|
||||
</template> |
||||
<script> |
||||
|
||||
import { postAction } from '@/api/manage' |
||||
|
||||
export default { |
||||
name: 'GateWayRouteModal', |
||||
components: {}, |
||||
data() { |
||||
return { |
||||
layout: 'horizontal', |
||||
labelCol: { span: 3 }, |
||||
wrapperCol: { span: 14 }, |
||||
currentNameIndex: 0, |
||||
currentTagIndex:-1, |
||||
predicates: {}, |
||||
filterArray: [{ key: 0, name: '熔断器' }, { key: 1, name: '限流过滤器' }], |
||||
tagArray: ['Path', 'Host', 'Cookie', 'Header', 'Method', 'Query', 'After', 'Before', 'Between', 'RemoteAddr'], |
||||
inputVisible: false, |
||||
inputValue: '', |
||||
url: { |
||||
update: '/sys/gatewayRoute/updateAll', |
||||
clear: '/sys/gatewayRoute/clearRedis' |
||||
}, |
||||
router: this.getRouter(), |
||||
title: '路由编辑', |
||||
visible: false, |
||||
loading: false |
||||
} |
||||
}, |
||||
methods: { |
||||
getRouter() { |
||||
return { |
||||
routerId: '', |
||||
name: '', |
||||
uri: '', |
||||
predicates: [], |
||||
filters: [] |
||||
} |
||||
}, |
||||
show(router) { |
||||
if (router) { |
||||
router.status=Boolean(router.status) |
||||
this.router = router |
||||
} else { |
||||
this.router = this.getRouter() |
||||
this.inputValue='' |
||||
} |
||||
this.visible = true |
||||
this.currentTagIndex=-1 |
||||
this.currentNameIndex=-1 |
||||
}, |
||||
close() { |
||||
this.reset() |
||||
this.$emit('close') |
||||
this.$refs['form'].resetFields() |
||||
this.visible = false |
||||
}, |
||||
//删除路由条件配置项
|
||||
removeTag(item, removedTag) { |
||||
const tags = item.args.filter(tag => tag !== removedTag) |
||||
item.args = tags |
||||
}, |
||||
//添加路由选项
|
||||
predicatesHandleMenuClick(e) { |
||||
this.router.predicates.push({ |
||||
args: [], |
||||
name: e.key |
||||
}) |
||||
}, |
||||
editTag(tag,index){ |
||||
this.currentTagIndex=index |
||||
}, |
||||
//显示输入框
|
||||
showInput(item, index) { |
||||
this.inputVisible = true |
||||
this.currentNameIndex = index |
||||
this.$nextTick(function() { |
||||
this.$refs.input.focus() |
||||
}) |
||||
}, |
||||
//路由选项输入框失去焦点事件
|
||||
handleInputChange(e) { |
||||
this.inputValue = e.target.value |
||||
}, |
||||
//删除路由条件
|
||||
removePredicate(item, index) { |
||||
item.predicates.splice(index, 1) |
||||
}, |
||||
//删除过滤器参数
|
||||
removeFilterParams(item, index) { |
||||
item.args.splice(index, 1) |
||||
}, |
||||
//删除过滤器
|
||||
removeFilter(item, index) { |
||||
item.filters.splice(index, 1) |
||||
}, |
||||
//添加过滤器参数
|
||||
addFilterParams(item) { |
||||
item.args.push({ |
||||
key: 'key' + item.args.length + 1, |
||||
value: '' |
||||
}) |
||||
}, |
||||
//过滤器添加事件
|
||||
filterHandleMenuClick(e) { |
||||
if (e.key == 0) { |
||||
this.router.filters.push({ |
||||
args: [ { |
||||
key: 'name', |
||||
value: 'default' |
||||
},{ |
||||
key: 'fallbackUri', |
||||
value: 'forward:/fallback' |
||||
}], |
||||
name:'Hystrix', |
||||
title: this.filterArray[0].name |
||||
}) |
||||
} |
||||
if (e.key == 1) { |
||||
this.router.filters.push({ |
||||
args: [ { |
||||
key: 'key-resolver', |
||||
value: '#{@ipKeyResolver}' |
||||
}, { |
||||
key: 'redis-rate-limiter.replenishRate', |
||||
value: 20 |
||||
}, { |
||||
key: 'redis-rate-limiter.burstCapacity', |
||||
value: 20 |
||||
}], |
||||
name:"RequestRateLimiter", |
||||
title: this.filterArray[1].name |
||||
}) |
||||
} |
||||
}, |
||||
//输入框确认
|
||||
handleInputConfirm(item) { |
||||
const inputValue = this.inputValue |
||||
let tags = item.args |
||||
if (inputValue && tags.indexOf(inputValue) === -1) { |
||||
item.args = [...tags, inputValue] |
||||
} |
||||
console.log(tags) |
||||
Object.assign(this, { |
||||
tags, |
||||
inputVisible: false, |
||||
inputValue: '' |
||||
}) |
||||
this.currentTagIndex=-1 |
||||
}, |
||||
//输入框确认
|
||||
handleInputEditConfirm(item,tag,index) { |
||||
if(this.inputValue) |
||||
{ |
||||
const inputValue = this.inputValue |
||||
item.args[index]=inputValue |
||||
} |
||||
this.currentTagIndex=-1 |
||||
|
||||
}, |
||||
reset() { |
||||
this.expandedKeysss = [] |
||||
this.checkedKeys = [] |
||||
this.defaultCheckedKeys = [] |
||||
this.loading = false |
||||
}, |
||||
//关闭弹窗
|
||||
handleCancel() { |
||||
this.close() |
||||
}, |
||||
//提交路由
|
||||
handleSubmit() { |
||||
let { predicates, filters, ...other } = this.router |
||||
let router = other |
||||
router.predicates = JSON.stringify(this.router.predicates) |
||||
router.filters = JSON.stringify(this.router.filters) |
||||
postAction(this.url.update, { |
||||
router |
||||
}).then(res => { |
||||
if (res.success) { |
||||
this.close() |
||||
this.$emit('ok') |
||||
this.$message.success(res.message) |
||||
} else { |
||||
this.$message.error(res.message) |
||||
} |
||||
}) |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
</script> |
||||
<style lang="less" scoped> |
||||
.drawer-bootom-button { |
||||
position: absolute; |
||||
bottom: 0; |
||||
width: 100%; |
||||
border-top: 1px solid #e8e8e8; |
||||
padding: 10px 16px; |
||||
text-align: right; |
||||
left: 0; |
||||
background: #fff; |
||||
border-radius: 0 0 2px 2px; |
||||
} |
||||
</style> |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue