feat: 同步Saber3.0.1

saber
ssc 3 years ago
parent 2e66cd657c
commit ce05f87d2f
  1. BIN
      .git.zip
  2. 2
      package.json
  3. 9
      public/cdn/avue/2.9.12/avue.min.js
  4. 1
      public/cdn/avue/2.9.12/index.css
  5. 9
      public/cdn/avue/2.9.5/avue.min.js
  6. 1
      public/cdn/avue/2.9.5/index.css
  7. 4
      public/cdn/nutflow/wf-design-base/index.umd.min.js
  8. 4
      public/index.html
  9. 111
      src/api/tool/model.js
  10. 24
      src/api/user.js
  11. 4
      src/config/website.js
  12. 312
      src/const/tool/model.js
  13. 130
      src/lang/en.js
  14. 130
      src/lang/zh.js
  15. 17
      src/page/login/index.vue
  16. 8
      src/router/axios.js
  17. 25
      src/store/modules/user.js
  18. 12
      src/util/func.js
  19. 6
      src/views/authority/apiscope.vue
  20. 3
      src/views/system/menu.vue
  21. 2
      src/views/system/tenantpackage.vue
  22. 5
      src/views/system/user.vue
  23. 463
      src/views/tool/code.vue
  24. 349
      src/views/tool/model.vue
  25. 51
      src/views/wel/index.vue

Binary file not shown.

@ -1,6 +1,6 @@
{
"name": "saber-admin",
"version": "2.9.1",
"version": "3.0.1",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -15,7 +15,7 @@
<link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/index.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/avue/iconfont.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/saber/iconfont.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/avue/2.9.5/index.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/avue/2.9.12/index.css">
<script src="<%= BASE_URL %>cdn/xlsx/FileSaver.min.js"></script>
<script src="<%= BASE_URL %>cdn/xlsx/xlsx.full.min.js"></script>
<link rel="icon" href="<%= BASE_URL %>favicon.png">
@ -108,7 +108,7 @@
<script src="<%= BASE_URL %>cdn/vue-router/3.0.1/vue-router.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/axios/1.0.0/axios.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/element-ui/2.15.6/index.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/avue/2.9.5/avue.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/avue/2.9.12/avue.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/nutflow/wf-design-base/index.umd.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/avue-form-design/index.umd.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/wf-design/index.umd.min.js" charset="utf-8"></script>

@ -0,0 +1,111 @@
import request from '@/router/axios';
export const getList = (current, size, params) => {
return request({
url: '/api/blade-develop/model/list',
method: 'get',
params: {
...params,
current,
size,
}
})
}
export const getDetail = (id) => {
return request({
url: '/api/blade-develop/model/detail',
method: 'get',
params: {
id
}
})
}
export const remove = (ids) => {
return request({
url: '/api/blade-develop/model/remove',
method: 'post',
params: {
ids,
}
})
}
export const add = (row) => {
return request({
url: '/api/blade-develop/model/submit',
method: 'post',
data: row
})
}
export const update = (row) => {
return request({
url: '/api/blade-develop/model/submit',
method: 'post',
data: row
})
}
export const getTableList = (datasourceId) => {
return request({
url: '/api/blade-develop/model/table-list',
method: 'get',
params: {
datasourceId,
}
})
}
export const getTableInfo = (modelId, datasourceId) => {
return request({
url: '/api/blade-develop/model/table-info',
method: 'get',
params: {
modelId,
datasourceId,
}
})
}
export const getTableInfoByName = (tableName, datasourceId) => {
return request({
url: '/api/blade-develop/model/table-info',
method: 'get',
params: {
tableName,
datasourceId,
}
})
}
export const getModelPrototype = (modelId, datasourceId) => {
return request({
url: '/api/blade-develop/model/model-prototype',
method: 'get',
params: {
modelId,
datasourceId,
}
})
}
export const submitModelPrototype = (row) => {
return request({
url: '/api/blade-develop/model-prototype/submit-list',
method: 'post',
data: row
})
}
export const prototypeDetail = (modelId) => {
return request({
url: '/api/blade-develop/model-prototype/select',
method: 'get',
params: {
modelId,
}
})
}

@ -37,6 +37,21 @@ export const loginBySocial = (tenantId, source, code, state) => request({
}
})
export const loginBySso = (state, code) => request({
url: '/api/blade-auth/oauth/token',
method: 'post',
headers: {
'Tenant-Id': state
},
params: {
tenantId: state,
code,
grant_type: "authorization_code",
scope: "all",
redirect_uri: website.redirectUri,
}
})
export const refreshToken = (refresh_token, tenantId, deptId, roleId) => request({
url: '/api/blade-auth/oauth/token',
method: 'post',
@ -72,12 +87,14 @@ export const getButtons = () => request({
export const getCaptcha = () => request({
url: '/api/blade-auth/oauth/captcha',
method: 'get'
method: 'get',
authorization: false
});
export const logout = () => request({
url: '/api/blade-auth/oauth/logout',
method: 'get'
method: 'get',
authorization: false
});
export const getUserInfo = () => request({
@ -93,5 +110,6 @@ export const sendLogs = (list) => request({
export const clearCache = () => request({
url: '/api/blade-auth/oauth/clear-cache',
method: 'get'
method: 'get',
authorization: false
});

@ -44,4 +44,8 @@ export default {
authUrl: 'http://localhost/blade-auth/oauth/render',
// 报表设计器地址(cloud端口为8108,boot端口为80)
reportUrl: 'http://localhost:8108/ureport',
// 单点登录系统认证(blade-auth服务的地)
ssoUrl: 'http://localhost:8100/oauth/authorize?client_id=saber&response_type=code&redirect_uri=',
// 单点登录回调地址(Saber服务的地址)
redirectUri: 'http://localhost:1888',
}

@ -0,0 +1,312 @@
export const switchDic = [
{
label: "",
value: 0
},
{
label: "",
value: 1
}
];
export const entityDic = [
{
label: "String",
value: "java.lang.String"
},
{
label: "Integer",
value: "java.lang.Integer"
},
{
label: "Long",
value: "java.lang.Long"
},
{
label: "Double",
value: "java.lang.Double"
},
{
label: "BigDecimal",
value: "java.math.BigDecimal"
},
{
label: "Boolean",
value: "java.lang.Boolean"
},
{
label: "Date",
value: "java.util.Date"
}
];
export const componentDic = [
{
label: "单行文本",
value: "input"
},
{
label: "多行文本",
value: "textarea"
},
{
label: "下拉选项",
value: "select"
},
{
label: "树形下拉选项",
value: "tree"
},
{
label: "单选框",
value: "radio"
},
{
label: "多选框",
value: "checkbox"
},
{
label: "开关框",
value: "switch"
},
{
label: "日期框",
value: "date"
}
];
export const queryDic = [
{
label: "等于",
value: "equal"
},
{
label: "不等于",
value: "notequal"
},
{
label: "大于",
value: "gt"
},
{
label: "大于等于",
value: "ge"
},
{
label: "小于",
value: "lt"
},
{
label: "小于等于",
value: "le"
},
{
label: "区间",
value: "between"
},
{
label: "模糊",
value: "like"
},
{
label: "左模糊",
value: "likeleft"
},
{
label: "右模糊",
value: "likeright"
}
];
export const templateDic = [
{
label: "单表",
value: "crud"
},
{
label: "主子表",
value: "sub"
},
{
label: "树表",
value: "tree"
}
];
export const option = {
height: 'auto',
searchShow: true,
searchMenuSpan: 6,
tip: false,
border: true,
index: true,
viewBtn: true,
selection: true,
menuWidth: 250,
column: [
{
label: "数据源",
prop: "datasourceId",
search: true,
span: 24,
type: "select",
dicUrl: "/api/blade-develop/datasource/select",
props: {
label: "name",
value: "id"
},
rules: [{
required: true,
message: "请选择数据源",
trigger: "blur"
}]
},
{
label: "物理表名",
prop: "modelTable",
type: "tree",
slot: true,
dicData: [],
props: {
label: "comment",
value: "name"
},
rules: [{
required: true,
message: "请输入数据库表名",
trigger: "blur"
}]
},
{
label: "模型类名",
prop: "modelClass",
rules: [{
required: true,
message: "请输入模型类名",
trigger: "blur"
}]
},
{
label: "模型名称",
prop: "modelName",
search: true,
rules: [{
required: true,
message: "请输入模型名称",
trigger: "blur"
}]
},
{
label: "模型编号",
prop: "modelCode",
search: true,
rules: [{
required: true,
message: "请输入模型编号",
trigger: "blur"
}]
},
{
label: "模型备注",
prop: "modelRemark",
hide: true,
span: 24,
},
]
};
export const optionModel = {
border: true,
index: true,
addBtn: false,
editBtn: false,
addRowBtn: false,
cellBtn: false,
cancelBtn: false,
tip: false,
menu: false,
selection: true,
column: [{
label: '物理列名',
prop: 'jdbcName',
}, {
label: '物理类型',
prop: 'jdbcType',
}, {
label: '实体列名',
prop: 'propertyName',
cell: true,
}, {
label: '实体类型',
prop: 'propertyEntity',
type: "select",
dicData: entityDic,
cell: true,
}, {
label: '字段说明',
prop: 'comment',
cell: true,
}, {
label: '列表显示',
prop: 'isList',
type: 'switch',
dicData: switchDic,
align: 'center',
width: 80,
cell: true,
}, {
label: '表单显示',
prop: 'isForm',
type: 'switch',
dicData: switchDic,
align: 'center',
width: 80,
cell: true,
}, {
label: '独占一行',
prop: 'isRow',
type: 'switch',
dicData: switchDic,
align: 'center',
width: 80,
cell: true,
}, {
label: '必填',
prop: 'isRequired',
type: 'switch',
dicData: switchDic,
align: 'center',
width: 80,
cell: true,
}, {
label: '组件类型',
prop: 'componentType',
type: "select",
dicData: componentDic,
cell: true,
}, {
label: '字典编码',
prop: 'dictCode',
type: "select",
dicUrl: "/api/blade-system/dict/select",
props: {
label: "dictValue",
value: "code"
},
cell: true,
}, {
label: '查询配置',
prop: 'isQuery',
type: 'switch',
dicData: switchDic,
align: 'center',
width: 80,
cell: true,
}, {
label: '查询类型',
prop: 'queryType',
type: "select",
dicData: queryDic,
cell: true,
}]
};

@ -1,69 +1,80 @@
export default {
title: 'Avue is a framework',
tip: 'tip',
title: 'Saber Admin',
logoutTip: 'Exit the system, do you want to continue?',
submitText: 'submit',
cancelText: 'cancel',
search: 'Please input search content',
menuTip: 'none menu list',
wel: {
info: 'Good morning, Smallwei, Avuex is a framework',
dept: 'a certain technology department',
team: 'Team ranking',
project: 'Project access',
count: 'Item number',
data: {
subtitle: 'real time',
column1: 'Classified statistics',
column2: 'Annex statistics',
column3: 'Article statistics',
key1: 'C',
key2: 'A',
key3: 'A',
text1: 'Total Record Number of Classifications',
text2: 'Number of attachments Uploaded',
text3: 'Comment frequency'
},
data2: {
column1: 'Registration today',
column2: 'Login today',
column3: 'Subscription today',
column4: 'Todays review'
},
data3: {
column1: 'Conversion rate(Day 28%)',
column2: 'Attendance rate(Day 11%)',
column3: 'Attendance rate(Day 33%)'
common: {
condition: 'condition',
display: 'display',
hide: 'hide'
},
tip: {
select: 'Please select',
input: 'Please input'
},
upload: {
upload: 'upload',
tip: 'Drag files here,/'
},
date: {
start: 'Start date',
end: 'End date',
t: 'today',
y: 'yesterday',
n: 'nearly 7',
a: 'whole'
},
form: {
printBtn: 'print',
mockBtn: 'mock',
submitBtn: 'submit',
emptyBtn: 'empty'
},
crud: {
filter: {
addBtn: 'add',
clearBtn: 'clear',
resetBtn: 'reset',
cancelBtn: 'cancel',
submitBtn: 'submit'
},
data4: {
column1: 'Error log',
column2: 'Data display',
column3: 'Privilege management',
column4: 'user management'
column: {
name: 'name',
hide: 'hide',
fixed: 'fixed',
filters: 'filters',
sortable: 'sortable',
index: 'index',
width: 'width'
},
table: {
rw: 'Work Tasks',
nr: 'Work content',
sj: 'Working hours',
}
},
route: {
info: 'info',
website: 'website',
avuexwebsite: 'avuex',
dashboard: 'dashboard',
more: 'more',
tags: 'tags',
store: 'store',
permission: 'permission',
api: 'api',
logs: 'logs',
table: 'table',
form: 'form',
top: 'backtop',
data: 'data',
error: 'error',
test: 'test'
tipStartTitle: 'Currently selected',
tipEndTitle: 'items',
editTitle: 'edit',
copyTitle: 'copy',
addTitle: 'add',
viewTitle: 'view',
filterTitle: 'filter',
showTitle: 'showTitle',
menu: 'menu',
addBtn: 'add',
show: 'show',
hide: 'hide',
open: 'open',
shrink: 'shrink',
printBtn: 'print',
excelBtn: 'excel',
updateBtn: 'update',
cancelBtn: 'cancel',
searchBtn: 'search',
emptyBtn: 'empty',
menuBtn: 'menu',
saveBtn: 'save',
viewBtn: 'view',
editBtn: 'edit',
copyBtn: 'copy',
delBtn: 'delete'
},
login: {
title: 'Login ',
@ -81,6 +92,7 @@ export default {
userLogin: 'userLogin',
phoneLogin: 'phoneLogin',
thirdLogin: 'thirdLogin',
ssoLogin: 'ssoLogin',
msgText: 'send code',
msgSuccess: 'reissued code',
},
@ -107,4 +119,4 @@ export default {
closeOthers: 'Close Others',
closeAll: 'Close All'
}
}
};

@ -1,69 +1,80 @@
export default {
tip: '提示',
title: 'Saber企业平台',
title: 'Saber企业管理平台',
logoutTip: '退出系统, 是否继续?',
submitText: '确定',
cancelText: '取消',
search: '请输入搜索内容',
menuTip: '没有发现菜单',
wel: {
info: '早安,Smallwei,Avuex一款超乎你想象的框架!',
dept: '我是avue团队下的一个部门-哈皮部门-哈皮职位',
team: '团队内排名',
project: '项目访问',
count: '项目数',
data: {
subtitle: '实时',
column1: '分类统计',
column2: '附件统计',
column3: '文章统计',
key1: '分',
key2: '附',
key3: '评',
text1: '当前分类总记录数',
text2: '当前上传的附件数',
text3: '评论次数'
},
data2: {
column1: '今日注册',
column2: '今日登录',
column3: '今日订阅',
column4: '今日评论'
},
data3: {
column1: '转化率(日同比 28%)',
column2: '签到率(日同比 11%)',
column3: '签到率(日同比 11%)'
common: {
condition: '条件',
display: '显示',
hide: '隐藏'
},
tip: {
select: '请选择',
input: '请输入'
},
upload: {
upload: '点击上传',
tip: '将文件拖到此处,或'
},
date: {
start: '开始日期',
end: '结束日期',
t: '今日',
y: '昨日',
n: '近7天',
a: '全部'
},
form: {
printBtn: '打 印',
mockBtn: '模 拟',
submitBtn: '提 交',
emptyBtn: '清 空'
},
crud: {
filter: {
addBtn: '新增条件',
clearBtn: '清空数据',
resetBtn: '清空条件',
cancelBtn: '取 消',
submitBtn: '确 定'
},
data4: {
column1: '错误日志',
column2: '数据展示',
column3: '权限管理',
column4: '用户管理'
column: {
name: '列名',
hide: '隐藏',
fixed: '冻结',
filters: '过滤',
sortable: '排序',
index: '顺序',
width: '宽度'
},
table: {
rw: '工作任务',
nr: '工作内容',
sj: '工作时间'
}
},
route: {
info: '个人信息',
website: 'bladex官网',
avuexwebsite: 'avuex官网',
dashboard: '首页',
more: '更多',
tags: '标签',
store: '本地存储',
api: '全局函数',
logs: '日志监控',
table: '表格',
form: '表单',
top: '返回顶部',
data: '数据展示',
permission: '权限',
error: '异常页面',
test: '测试页面'
tipStartTitle: '当前表格已选择',
tipEndTitle: '项',
editTitle: '编 辑',
copyTitle: '复 制',
addTitle: '新 增',
viewTitle: '查 看',
filterTitle: '过滤条件',
showTitle: '列显隐',
menu: '操作',
addBtn: '新 增',
show: '显 示',
hide: '隐 藏',
open: '展 开',
shrink: '收 缩',
printBtn: '打 印',
excelBtn: '导 出',
updateBtn: '修 改',
cancelBtn: '取 消',
searchBtn: '搜 索',
emptyBtn: '清 空',
menuBtn: '功 能',
saveBtn: '保 存',
viewBtn: '查 看',
editBtn: '编 辑',
copyBtn: '复 制',
delBtn: '删 除'
},
login: {
title: '登录 ',
@ -81,6 +92,7 @@ export default {
userLogin: '账号密码登录',
phoneLogin: '手机号登录',
thirdLogin: '第三方系统登录',
ssoLogin: '单点系统登录',
msgText: '发送验证码',
msgSuccess: '秒后重发',
},
@ -106,4 +118,4 @@ export default {
closeOthers: '关闭其它',
closeAll: '关闭所有'
}
}
};

@ -45,6 +45,7 @@
<a href="#" @click.stop="activeName='user'">{{ $t('login.userLogin') }}</a>
<!--<a href="#" @click.stop="activeName='code'">{{ $t('login.phoneLogin') }}</a>-->
<a href="#" @click.stop="activeName='third'">{{ $t('login.thirdLogin') }}</a>
<a :href="website.ssoUrl + website.redirectUri">{{ $t('login.ssoLogin') }}</a>
</div>
</div>
@ -108,6 +109,7 @@
handleLogin() {
const topUrl = getTopUrl();
const redirectUrl = "/oauth/redirect/";
const ssoCode = "?code=";
this.socialForm.source = getQueryString("source");
this.socialForm.code = getQueryString("code");
this.socialForm.state = getQueryString("state");
@ -116,7 +118,7 @@
source = source.split(redirectUrl)[1];
this.socialForm.source = source;
}
if (!validatenull(this.socialForm.source) && !validatenull(this.socialForm.code) && !validatenull(this.socialForm.state)) {
if (topUrl.includes(redirectUrl) && !validatenull(this.socialForm.source) && !validatenull(this.socialForm.code) && !validatenull(this.socialForm.state)) {
const loading = this.$loading({
lock: true,
text: '第三方系统登录中,请稍后。。。',
@ -129,6 +131,19 @@
}).catch(() => {
loading.close();
});
} else if (!topUrl.includes(redirectUrl) && !validatenull(this.socialForm.code) && !validatenull(this.socialForm.state)) {
const loading = this.$loading({
lock: true,
text: '单点系统登录中,请稍后。。。',
spinner: "el-icon-loading"
});
this.$store.dispatch("LoginBySso", this.socialForm).then(() => {
window.location.href = topUrl.split(ssoCode)[0];
this.$router.push({path: this.tagWel.value});
loading.close();
}).catch(() => {
loading.close();
});
}
}
}

@ -32,10 +32,14 @@ NProgress.configure({
axios.interceptors.request.use(config => {
//开启 progress bar
NProgress.start();
//headers判断是否需要
const authorization = config.authorization === false;
if (!authorization) {
config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`;
}
//让每个请求携带token
const meta = (config.meta || {});
const isToken = meta.isToken === false;
config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`;
//让每个请求携带token
if (getToken() && !isToken) {
config.headers[website.tokenHeader] = 'bearer ' + getToken()
}

@ -4,7 +4,7 @@ import {setStore, getStore} from '@/util/store'
import {isURL, validatenull} from '@/util/validate'
import {deepClone} from '@/util/util'
import website from '@/config/website'
import {loginByUsername, loginBySocial, getUserInfo, logout, refreshToken, getButtons} from '@/api/user'
import {loginByUsername, loginBySocial, loginBySso, getUserInfo, logout, refreshToken, getButtons} from '@/api/user'
import {getTopMenu, getRoutes} from '@/api/system/menu'
import md5 from 'js-md5'
@ -95,6 +95,29 @@ const user = {
commit('SET_TOKEN', data.access_token);
commit('SET_REFRESH_TOKEN', data.refresh_token);
commit('SET_USER_INFO', data);
commit('SET_TENANT_ID', data.tenant_id);
commit('DEL_ALL_TAG');
commit('CLEAR_LOCK');
}
resolve();
})
})
},
//根据单点信息登录
LoginBySso({commit}, userInfo) {
return new Promise((resolve) => {
loginBySso(userInfo.state, userInfo.code).then(res => {
const data = res.data;
if (data.error_description) {
Message({
message: data.error_description,
type: 'error'
})
} else {
commit('SET_TOKEN', data.access_token);
commit('SET_REFRESH_TOKEN', data.refresh_token);
commit('SET_USER_INFO', data);
commit('SET_TENANT_ID', data.tenant_id);
commit('DEL_ALL_TAG');
commit('CLEAR_LOCK');
}

@ -90,4 +90,16 @@ export default class func {
static split(str) {
return str ? String(str).split(',') : '';
}
/**
* 转换空字符串
* @param str
* @returns {string|*}
*/
static toStr(str) {
if (typeof str === 'undefined' || str === null) {
return "";
}
return str;
}
}

@ -320,7 +320,7 @@
search: true,
rules: [{
required: true,
message: "请输入数据权限名称",
message: "请输入权限名称",
trigger: "blur"
}]
},
@ -331,7 +331,7 @@
width: 180,
rules: [{
required: true,
message: "请输入数据权限编号",
message: "请输入权限编号",
trigger: "blur"
}]
},
@ -341,7 +341,7 @@
width: 180,
rules: [{
required: true,
message: "请输入数据权限编号",
message: "请输入权限编号",
trigger: "blur"
}]
},

@ -190,6 +190,7 @@
prop: "isOpen",
type: "radio",
disabled: false,
display: false,
dicData: [
{
label: "否",
@ -213,8 +214,6 @@
label: "菜单排序",
prop: "sort",
type: "number",
row: true,
span: 24,
rules: [
{
required: true,

@ -146,7 +146,7 @@ export default {
done();
}, error => {
loading();
console.log(error);
window.console.log(error);
});
},
rowDel(row) {

@ -188,6 +188,7 @@
import {dateNow} from "@/util/date";
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import func from "@/util/func";
export default {
data() {
@ -902,13 +903,15 @@
done();
},
handleExport() {
const account = func.toStr(this.search.account);
const realName = func.toStr(this.search.realName);
this.$confirm("是否导出用户数据?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
NProgress.start();
exportBlob(`/api/blade-user/export-user?${this.website.tokenHeader}=${getToken()}&account=${this.search.account}&realName=${this.search.realName}`).then(res => {
exportBlob(`/api/blade-user/export-user?${this.website.tokenHeader}=${getToken()}&account=${account}&realName=${realName}`).then(res => {
downloadXls(res.data, `用户数据表${dateNow()}.xlsx`);
NProgress.done();
})

@ -48,6 +48,9 @@
<script>
import {getList, getCode, build, remove, add, update, copy} from "@/api/tool/code";
import {getDetail as modelDetail, prototypeDetail} from "@/api/tool/model";
import {templateDic} from "@/const/tool/model";
import {validatenull} from "@/util/validate";
import {mapGetters} from "vuex";
export default {
@ -76,144 +79,386 @@
menuWidth: 300,
viewBtn: true,
dialogClickModal: false,
tabs: true,
column: [
{
label: "数据源",
prop: "datasourceId",
search: true,
span: 24,
type: "select",
dicUrl: "/api/blade-develop/datasource/select",
props: {
label: "name",
value: "id"
},
rules: [{
required: true,
message: "请选择数据源",
trigger: "blur"
}]
},
{
label: "模块名",
prop: "codeName",
search: true,
rules: [{
required: true,
message: "请输入模块名",
trigger: "blur"
}]
display: false,
},
{
label: "服务名",
prop: "serviceName",
search: true,
rules: [{
required: true,
message: "请输入服务名",
trigger: "blur"
}]
label: '模版类型',
prop: 'templateType',
type: "select",
dicData: templateDic,
display: false,
},
{
label: "表名",
prop: "tableName",
rules: [{
required: true,
message: "请输入表名",
trigger: "blur"
}]
},
{
label: "表前缀",
prop: "tablePrefix",
hide: true,
rules: [{
required: true,
message: "请输入表前缀",
trigger: "blur"
}]
search: true,
display: false,
},
{
label: "主键名",
prop: "pkName",
hide: true,
rules: [{
required: true,
message: "请输入主键名",
trigger: "blur"
}]
label: "服务名",
prop: "serviceName",
search: true,
display: false,
},
{
label: "包名",
prop: "packageName",
overHidden: true,
rules: [{
required: true,
message: "请输入包名",
trigger: "blur"
}]
},
{
label: "基础业务",
prop: "baseMode",
type: 'radio',
dicUrl: "/api/blade-system/dict/dictionary?code=yes_no",
props: {
label: "dictValue",
value: "dictKey"
},
dataType: "number",
hide: true,
rules: [{
required: true,
message: "请选择基础业务",
trigger: "blur"
}]
display: false,
},
],
group: [
{
label: "包装器",
prop: "wrapMode",
type: 'radio',
dicUrl: "/api/blade-system/dict/dictionary?code=yes_no",
props: {
label: "dictValue",
value: "dictKey"
},
dataType: "number",
hide: true,
rules: [{
required: true,
message: "请选择包装器",
trigger: "blur"
}]
label: '模型配置',
prop: 'modelSetting',
icon: 'el-icon-tickets',
column: [
{
label: "数据模型",
prop: "modelId",
search: true,
span: 24,
type: "select",
dicUrl: "/api/blade-develop/model/select",
props: {
label: "modelName",
value: "id"
},
rules: [{
required: true,
message: "请选择数据模型",
trigger: "blur"
}]
},
{
label: "模块名",
prop: "codeName",
search: true,
rules: [{
required: true,
message: "请输入模块名",
trigger: "blur"
}]
},
{
label: "服务名",
prop: "serviceName",
search: true,
rules: [{
required: true,
message: "请输入服务名",
trigger: "blur"
}]
},
{
label: "表名",
prop: "tableName",
rules: [{
required: true,
message: "请输入表名",
trigger: "blur"
}]
},
{
label: "表前缀",
prop: "tablePrefix",
hide: true,
rules: [{
required: true,
message: "请输入表前缀",
trigger: "blur"
}]
},
{
label: "主键名",
prop: "pkName",
hide: true,
rules: [{
required: true,
message: "请输入主键名",
trigger: "blur"
}]
},
{
label: "包名",
prop: "packageName",
overHidden: true,
rules: [{
required: true,
message: "请输入包名",
trigger: "blur"
}]
},
]
},
{
label: "后端生成路径",
prop: "apiPath",
span: 24,
hide: true,
rules: [{
required: true,
message: "请输入后端生成路径",
trigger: "blur"
}]
label: '模版配置',
prop: 'templateSetting',
icon: 'el-icon-copy-document',
column: [
{
label: '模版类型',
prop: 'templateType',
type: "select",
dicData: templateDic,
value: "crud",
rules: [{
required: true,
message: "请选择模版类型",
trigger: "blur"
}]
},
{
label: "作者信息",
prop: "author",
value: "BladeX",
rules: [{
required: true,
message: "请输入作者",
trigger: "blur"
}]
},
{
label: "子表模型",
prop: "subModelId",
type: "select",
dicUrl: "/api/blade-develop/model/select",
props: {
label: "modelName",
value: "id"
},
display: false,
hide: true,
},
{
label: "子表外键",
prop: "subFkId",
display: false,
hide: true,
},
{
label: "树主键字段",
prop: "treeId",
type: "select",
dicData: [],
props: {
label: "comment",
value: "jdbcName"
},
display: false,
hide: true,
},
{
label: "树父主键字段",
prop: "treePid",
type: "select",
dicData: [],
props: {
label: "comment",
value: "jdbcName"
},
display: false,
hide: true,
},
{
label: "树名称字段",
prop: "treeName",
type: "select",
dicData: [],
props: {
label: "comment",
value: "jdbcName"
},
display: false,
hide: true,
},
]
},
{
label: "前端生成路径",
prop: "webPath",
span: 24,
hide: true,
rules: [{
required: true,
message: "请输入前端生成路径",
trigger: "blur"
}]
label: '生成配置',
prop: 'codingSetting',
icon: 'el-icon-printer',
column: [
{
label: "基础业务",
labelTip:'配置是否使用BladeX封装的BaseService解锁更多功能',
prop: "baseMode",
type: 'radio',
dicUrl: "/api/blade-system/dict/dictionary?code=yes_no",
props: {
label: "dictValue",
value: "dictKey"
},
value: 2,
dataType: "number",
hide: true,
rules: [{
required: true,
message: "请选择基础业务",
trigger: "blur"
}]
},
{
label: "包装器",
labelTip:'配置是否使用Wrapper包装器来拓展Controller返回列表的字段',
prop: "wrapMode",
type: 'radio',
dicUrl: "/api/blade-system/dict/dictionary?code=yes_no",
props: {
label: "dictValue",
value: "dictKey"
},
value: 2,
dataType: "number",
hide: true,
rules: [{
required: true,
message: "请选择包装器",
trigger: "blur"
}]
},
{
label: "远程调用",
labelTip:'配置是否使用Feign远程调用',
prop: "feignMode",
type: 'radio',
dicUrl: "/api/blade-system/dict/dictionary?code=yes_no",
props: {
label: "dictValue",
value: "dictKey"
},
value: 1,
dataType: "number",
hide: true,
rules: [{
required: true,
message: "请选择基础业务",
trigger: "blur"
}]
},
{
label: "代码风格",
labelTip:'选择不同底层实现的代码模版',
prop: "codeStyle",
type: 'radio',
dicData: [
{
label: "saber",
value: "saber"
},
{
label: "element",
value: "element"
}
],
value: "saber",
hide: true,
rules: [{
required: true,
message: "请选择代码风格",
trigger: "blur"
}]
},
{
label: "后端生成路径",
prop: "apiPath",
span: 24,
hide: true,
rules: [{
required: true,
message: "请输入后端生成路径",
trigger: "blur"
}]
},
{
label: "前端生成路径",
prop: "webPath",
span: 24,
hide: true,
rules: [{
required: true,
message: "请输入前端生成路径",
trigger: "blur"
}]
}
]
}
]
},
data: []
};
},
watch: {
'form.modelId'() {
if (!validatenull(this.form.modelId)) {
//
modelDetail(this.form.modelId).then(res => {
const result = res.data;
if (result.success) {
const {modelName, modelTable, modelCode} = result.data;
if (validatenull(this.form.tablePrefix)) {
this.form.tablePrefix = modelTable.split("_")[0] + "_";
}
if (validatenull(this.form.tableName)) {
this.form.tableName = modelTable;
}
if (validatenull(this.form.codeName)) {
this.form.codeName = modelName;
}
if (validatenull(this.form.serviceName)) {
this.form.serviceName = `blade-${modelCode}`;
}
if (validatenull(this.form.pkName)) {
this.form.pkName = "id";
}
if (validatenull(this.form.packageName)) {
this.form.packageName = `org.springblade.${modelCode}`;
}
if (validatenull(this.form.subFkId) && !validatenull(this.form.tablePrefix)) {
this.form.subFkId = modelTable.replace(this.form.tablePrefix, "") + "_id";
}
//
prototypeDetail(this.form.modelId).then(res => {
const result = res.data;
if (result.success) {
const columnTreeId = this.findObject(this.option.group, "treeId");
const columnTreePid = this.findObject(this.option.group, "treePid");
const columnTreeName = this.findObject(this.option.group, "treeName");
columnTreeId.dicData = result.data;
columnTreePid.dicData = result.data;
columnTreeName.dicData = result.data;
}
});
}
});
}
},
'form.templateType'() {
//
const type = this.form.templateType;
//
const columnSubModelId = this.findObject(this.option.group, "subModelId");
const columnSubFkId = this.findObject(this.option.group, "subFkId");
columnSubModelId.display = type === "sub";
columnSubFkId.display = type === "sub";
//
const columnTreeId = this.findObject(this.option.group, "treeId");
const columnTreePid = this.findObject(this.option.group, "treePid");
const columnTreeName = this.findObject(this.option.group, "treeName");
columnTreeId.display = type === "tree";
columnTreePid.display = type === "tree";
columnTreeName.display = type === "tree";
}
},
computed: {
...mapGetters(["permission"]),
permissionList() {

@ -0,0 +1,349 @@
<template>
<basic-container>
<avue-crud :option="option"
:table-loading="loading"
:data="data"
:page="page"
:permission="permissionList"
:before-open="beforeOpen"
v-model="form"
v-loading.fullscreen.lock="fullscreenLoading"
ref="crud"
@row-update="rowUpdate"
@row-save="rowSave"
@row-del="rowDel"
@search-change="searchChange"
@search-reset="searchReset"
@selection-change="selectionChange"
@current-change="currentChange"
@size-change="sizeChange"
@on-load="onLoad">
<template slot="menuLeft">
<el-button type="danger"
size="small"
icon="el-icon-delete"
plain
@click="handleDelete">
</el-button>
</template>
<template slot-scope="{row}" slot="menu">
<el-button type="text"
icon="el-icon-setting"
size="small"
plain
class="none-border"
@click.stop="handleModel(row)">模型配置
</el-button>
</template>
<template slot-scope="{row}" slot="modelTable">
<el-tag>{{ row.modelTable }}</el-tag>
</template>
</avue-crud>
<el-dialog title="数据库模型配置"
:visible.sync="modelBox"
:fullscreen="true"
append-to-body>
<avue-crud ref="crudModel" :option="optionModel" :table-loading="loading" :data="fields"></avue-crud>
<span slot="footer" class="dialog-footer">
<el-button type="danger" @click="modelBox = false"> </el-button>
<el-button type="primary" @click="handleSubmit"> </el-button>
</span>
</el-dialog>
</basic-container>
</template>
<script>
import {
getList,
getDetail,
add,
update,
remove,
getTableList,
getTableInfoByName,
getModelPrototype,
submitModelPrototype
} from "@/api/tool/model";
import {entityDic, option, optionModel} from "@/const/tool/model";
import {validatenull} from "@/util/validate";
import {mapGetters} from "vuex";
export default {
data() {
return {
form: {},
query: {},
loading: true,
loadingOption: {
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0)'
},
fullscreenLoading: false,
page: {
pageSize: 10,
currentPage: 1,
total: 0
},
selectionList: [],
modelBox: false,
modelId: 0,
datasourceId: 1,
tableInfo: {},
active: 0,
stepStart: 0,
stepEnd: 4,
data: [],
option: option,
optionModel: optionModel,
formStep: {},
fields: [],
selectionModelList: [],
};
},
watch: {
'form.datasourceId'() {
if (!validatenull(this.form.datasourceId)) {
const fullLoading = this.$loading(this.loadingOption);
getTableList(this.form.datasourceId).then(res => {
const column = this.findObject(this.option.column, "modelTable");
column.dicData = res.data.data;
fullLoading.close();
}).catch(() => {
fullLoading.close();
})
}
},
'form.modelTable'() {
if (!validatenull(this.form.modelTable)) {
const fullLoading = this.$loading(this.loadingOption);
getTableInfoByName(this.form.modelTable, this.form.datasourceId).then(res => {
const result = res.data;
if (result.success) {
const {comment, entityName} = result.data;
if (validatenull(this.form.modelClass)) {
this.form.modelClass = entityName;
}
if (validatenull(this.form.modelName)) {
this.form.modelName = comment;
}
if (validatenull(this.form.modelCode)) {
this.form.modelCode = entityName.replace(/^\S/, s => s.toLowerCase());
}
fullLoading.close();
}
});
}
}
},
computed: {
...mapGetters(["permission"]),
permissionList() {
return {
addBtn: true,
delBtn: true,
editBtn: true,
viewBtn: false
};
},
ids() {
let ids = [];
this.selectionList.forEach(ele => {
ids.push(ele.id);
});
return ids.join(",");
},
},
methods: {
rowSave(row, done, loading) {
add(row).then(() => {
done();
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
}, error => {
loading();
window.console.log(error);
});
},
rowUpdate(row, index, done, loading) {
update(row).then(() => {
done();
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
}, error => {
loading();
window.console.log(error);
});
},
rowDel(row) {
this.$confirm("确定将选择数据删除?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
return remove(row.id);
})
.then(() => {
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
});
},
handleDelete() {
if (this.selectionList.length === 0) {
this.$message.warning("请选择至少一条数据");
return;
}
this.$confirm("确定将选择数据删除?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
return remove(this.ids);
})
.then(() => {
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
this.$refs.crud.toggleSelection();
});
},
beforeOpen(done, type) {
if (["edit", "view"].includes(type)) {
getDetail(this.form.id).then(res => {
this.form = res.data.data;
});
}
done();
},
searchReset() {
this.query = {};
this.onLoad(this.page);
},
searchChange(params, done) {
this.query = params;
this.onLoad(this.page, params);
done();
},
selectionChange(list) {
this.selectionList = list;
},
selectionModelChange(list) {
this.selectionModelList = list;
},
selectionClear() {
this.selectionList = [];
this.$refs.crud.toggleSelection();
},
currentChange(currentPage) {
this.page.currentPage = currentPage;
},
sizeChange(pageSize) {
this.page.pageSize = pageSize;
},
onLoad(page, params = {}) {
this.loading = true;
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
const data = res.data.data;
this.page.total = data.total;
this.data = data.records;
this.loading = false;
this.selectionClear();
});
},
handleModel(row) {
this.fields = [];
this.modelBox = true;
this.loading = true;
this.modelId = row.id;
this.datasourceId = row.datasourceId;
getModelPrototype(this.modelId, this.datasourceId).then(res => {
const result = res.data;
if (result.success) {
this.fields = result.data;
this.fields.forEach(item => {
item.$cellEdit = true;
item.modelId = this.modelId;
//
if (validatenull(item.id)) {
item.isList = 1;
item.isForm = 1;
item.isRow = 0;
item.isRequired = 0;
item.isQuery = 0;
item.componentType = "input";
}
if (!validatenull(item.name)) {
item.jdbcName = item.name;
item.jdbcType = item.propertyType;
//
if (item.propertyType === "LocalDateTime") {
item.propertyType = "Date";
item.propertyEntity = "java.util.Date";
} else {
entityDic.forEach(d => {
if (d.label === item.propertyType) {
item.propertyType = d.label;
item.propertyEntity = d.value;
}
});
}
}
});
this.loading = false;
}
});
},
handleSubmit() {
console.log(this.fields);
this.$confirm("确定提交模型配置?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.fields.forEach(item => {
entityDic.forEach(d => {
if (d.value === item.propertyEntity) {
item.propertyType = d.label;
}
});
});
submitModelPrototype(this.fields).then(res => {
const result = res.data;
if (result.success) {
this.$message.success(result.msg);
this.modelBox = false;
} else {
this.$message.error(result.msg);
}
})
});
}
}
};
</script>
<style>
.none-border {
border: 0;
background-color: transparent !important;
}
.step-div {
margin-top: 30px;
}
</style>

@ -9,10 +9,10 @@
<el-col :span="24">
<basic-container>
<p style="text-align: center">
<img src="https://img.shields.io/badge/Release-V2.9.1-green.svg" alt="Downloads"/>
<img src="https://img.shields.io/badge/Release-V3.0.1-green.svg" alt="Downloads"/>
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" alt="Build Status"/>
<img src="https://img.shields.io/badge/Spring%20Cloud-Hoxton.SR12-blue.svg" alt="Coverage Status"/>
<img src="https://img.shields.io/badge/Spring%20Boot-2.3.12.RELEASE-blue.svg" alt="Downloads"/>
<img src="https://img.shields.io/badge/Spring%20Cloud-2021-blue.svg" alt="Coverage Status"/>
<img src="https://img.shields.io/badge/Spring%20Boot-2.7-blue.svg" alt="Downloads"/>
<a target="_blank" href="https://bladex.vip">
<img src="https://img.shields.io/badge/Saber%20Author-Small%20Chill-ff69b4.svg" alt="Downloads"/>
</a>
@ -44,7 +44,7 @@
</el-collapse-item>
<el-collapse-item title="为何需要BladeX" name="3">
<div>1.经历过较长的线上生产积累了很多企业痛点的解决方案</div>
<div>2.一套代码兼容MySqlOraclePostgreSQLSqlServer适应企业各种不同场景的需求</div>
<div>2.一套代码兼容MySqlOraclePostgreSQLSqlServer达梦适应企业各种不同场景的需求</div>
<div>3.集成了很多企业急切所需的例如多租户Oauth2授权认证工作流分布式事务等等功能</div>
<div>4.深度定制了Flowable工作流完美支持SpringCloud分布式服务的场景以远程调用的方式进行操作</div>
<div>5.升级了核心驱动新功能完全可以开箱即用而开源版需要自己再花时间进行集成需要花掉更多的时间成本</div>
@ -139,6 +139,47 @@
<el-row>
<basic-container>
<el-collapse v-model="logActiveNames" @change="handleChange">
<el-collapse-item title="3.0.1.RELEASE发布,代码生成功能全面升级" name="28">
<div>1.[新增]数据模型在线配置</div>
<div>2.[新增]代码生成表单组件在线配置</div>
<div>3.[新增]Saber风格的单表生成模版</div>
<div>4.[新增]Saber风格的主子表生成模版</div>
<div>5.[新增]Saber风格的树表生成模版</div>
<div>6.[新增]ElementUI风格的单表生成模版</div>
<div>7.[新增]ElementUI风格的主子表生成模版</div>
<div>8.[新增]ElementUI风格的树表生成模版</div>
</el-collapse-item>
<el-collapse-item title="3.0.0.RELEASE发布,系统架构升级至 SpringCloud 2021" name="27">
<div>1.[升级]SpringCloud 2021.0.3</div>
<div>2.[升级]SpringBoot 2.7.1</div>
<div>3.[升级]SpringBootAdmin 2.7.1</div>
<div>4.[升级]AlibabaCloud 2021.0.1.0</div>
<div>5.[升级]Mybatis-Plus 3.5.2</div>
<div>6.[升级]Mybatis-Plus-Generator 3.5.3</div>
<div>7.[升级]Nacos 2.1.0</div>
<div>8.[升级]Seata 1.5.2</div>
<div>9.[升级]Log4J 2.18.0</div>
<div>10.[升级]JackSon 2.13.3</div>
<div>11.[升级]FastJson 1.2.83</div>
<div>12.[升级]Avue 2.9.12</div>
<div>13.[新增]基于Oauth2的单点登录</div>
<div>14.[新增]灰度服务发布与调用</div>
<div>15.[新增]代码生成增加element和feign模版</div>
<div>16.[优化]自动装配模块采用新版@AutoConfiguration注解</div>
<div>17.[优化]TencentCosTemplate避免oom的情况</div>
<div>18.[优化]TreeNode类</div>
<div>19.[优化]Gateway鉴权逻辑</div>
<div>20.[修复]BladeRedis incr方法失效的问题</div>
<div>21.[修复]租户产品包更新后缓存未刷新的问题</div>
<div>22.[修复]绑定租户产品包后普通管理员权限配置丢失按钮选项的问题</div>
<div>23.[修复]流程设计器监听无法删除的问题</div>
<div>24.[修复]用户excel导出条件为空的判断逻辑</div>
<div>25.[删除]Hystrix接入以Sentinel取代</div>
<div>26.[删除]Ribbon接入以LoadBalancer取代</div>
<div>27.[删除]Zipkin接入</div>
<div>28.[删除]Turbine接入</div>
<div>29.[替代]后续版本将对接SkyWalking取代Zipkin与Turbine</div>
</el-collapse-item>
<el-collapse-item title="2.9.1.RELEASE发布,新增达梦数据库支持,集成NutFlow流程设计器" name="26">
<div>1.[升级]Mybatis-Plus 3.5.1</div>
<div>2.[升级]Mybatis-Plus-Generator 3.5.2</div>
@ -730,7 +771,7 @@
data() {
return {
activeNames: ['1', '2', '3', '5'],
logActiveNames: ['26']
logActiveNames: ['28']
};
},
computed: {

Loading…
Cancel
Save