Unverified Commit c384175d authored by zhu-mingye's avatar zhu-mingye Committed by GitHub

[Feature][admin,web] merge tenant to dev branch (#1093)

* add tenant implementation (#776)

* add tenant implement

* add tenant implement

* fix get tenants

* add tenants in the normal process

* update application.yml file mysql info

* fix tenant in normal process

* fix login

* add file agreement  and update dlink_history.sql

* fix application.yml file

* fix system init

* fix tenant bug

* fix tenant bug

* fix tenant bug

* fix tenant bug

* fix application.yml
Co-authored-by: 's avatartangxiuhong <tangxiuhong@cangshu.vip>
Co-authored-by: 's avataraiwenmo <32723967+aiwenmo@users.noreply.github.com>

* [Feature-812][admin,web] add FragmentVariable manager && resourcecenter page (#813)

* add FragmentVariable manager

* added resourcecenter

* fix sql file , mapper.xml

* added NameSpaceForm PasswordForm

* added NameSpaceForm PasswordForm (#820)

* Delete SqlParserTest.java

* Optimized for multi-tenant

* [optimization][admin] Optimized for multi-tenant (#834)

* Delete SqlParserTest.java

* Optimized for multi-tenant
Co-authored-by: 's avataraiwenmo <32723967+aiwenmo@users.noreply.github.com>

* Render multi tenant forms on login (#841)

* [Feature-823][web] Multi tenant front end implementation  (#847)

* Implementation of multi tenant login

* UserManager,RoleManager,TenantManager,NameSpaceManager implementation

* fix NameSpaceForm RoleForm

* optimize multi tenant (#848)

* fix get tenants by role id bug

* fix add tenant key no unique

* fix login get tenants interceptor

* optimize multi tenant

* optimize multi tenant
Co-authored-by: 's avatartangxiuhong <tangxiuhong@cangshu.vip>

* fix multi tenant add role and delete role (#865)

* fix multi tenant add role and delete role

* fix multi tenant add role and delete role
Co-authored-by: 's avatartangxiuhong <tangxiuhong@cangshu.vip>

* Optimization of multi tenant &&  Optimize form rendering  (#876)

* 优化多租户相关问题

* 优化用户赋权角色表单渲染

* 优化用户赋权角色表单渲染

* 优化资源中心左右表单渲染

* Optimization of multi tenant && Optimize form rendering 

Optimization of multi tenant && Optimize form rendering

* optimization multi tenant  of delete roles &&  optimization multi tenant web render (#887)

* 用户授权角色穿梭框优化

* 用户授权角色穿梭框删除handleSearch

* 优化角色删除及其关联命名空间删除的逻辑

* 修复角色选择命名空间回显问题

* 优化用户关联角色渲染 (#888)

* [Feature-890][admin] Implementation of user role management

* Realization of user empowerment role function(#893)

* merge dev to dev-tenant (#1006)

* Optimization StudioConsole's StudioProcess click show flinksql the div overflow (#802)

* [Document-793][doc] docs hotfix (#815)

* docs hotfix

* Fix Chinese README link error and add English README. (#817)

* Added ignore of logs folder in git ignore file. (#807)

* [Optimization-810][Common] Added Maven Wrapper (#811)

* add maven wrapper

* add maven-wrapper.jar

* update .gitignore

* Fix jobhistory bug (#805)

* jobHistory bug modify

* jobHistory bug modify

* jobHistory bug modify

* update roadmap (#822)
Co-authored-by: 's avatargodkaikai <32723967+godkaikai@users.noreply.github.com>

* Optimize cdc SQLSinkBuilder KafkaSinkBuilder, filter to process (#806)

* 优化 cdc SQLSinkBuilder KafkaSinkBuilder, filter to process

* change "_" to "."

* change "db" to config.getSchemaFieldName()

* change "tableMap key" to table.getSchemaTableName()

* [Fix-818][connector] fix when the data is flushed with an exception and no new data is entered subsequently (#824)

Co-authored-by: lucas.wu <1220671715>

* [Document-835][doc] Update the home page and basic information of the document (#836)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* remove sensitive info for more api. (#829)
Co-authored-by: 's avatardzygcc <avadar@qq.com>

* [fix 833] [dlink-client] Error with SQLSinkBuilder.buildRow (#833) (#842)
Co-authored-by: 's avatarqiaoyiming <wenpin@tianmagroup.com>

* [Optimization-819][dlink-client] CDCSOURCE with timestamp and timezone (#843)

change default timezone = UTC ,
set timezone with setting sink.timezone
(#819)
Co-authored-by: 's avatarqiaoyiming <wenpin@tianmagroup.com>

* [Optimization-849][client,executor] Replace sql separator and change default sql separator into ;\n (#850)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* fix execute error by flink 1.14.4 (#851)

* Optimize code style import order. (#853)

* fix SQLSinkBuilder.buildRow in flink-client-1.11 and flink-client-1.12 (#864)

change Row.withPositions() to new Row()

* 修复字符乱码和时区不正确以及增加datastream实现 (#845)

* fix: MYSQL CDC JsonDebeziumDeserializationSchema 字节转字符提定字符编码 UTF-8

* fix: MYSQL CDC SQLSinkBuilder 转换mysql 类型datetime时,时区不正确,应该设置UTC实区

* [Feature]:
   1:增加datastream-starrocks 实现,目前strrocks官网jar只到1.14对应的flink版本
   2:增加datastream-kafka-json 实现,主要实现抽像出必须的记录数据,增加扩展op、is_delete、schemaName,tableName,ts_ms等字段,方便业务使用

* [optimization]:优化调整重复代码

[optimization]:优化调整重复代码

* [Feature-794][*] Modify version into 0.6.7-SNAPSHOT (#866)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* Added  git file ignore (#867)

* 修改 dlink-conector-pulsar-1.14 (#871)

<!--新增 pulsar-client-api jar 解决找不到SubscriptionType报错-->

Co-authored-by: wzh8384 <wzh615961806>

* 使用dlink链接Flink1.14.4,SavePoint停止任务时会出现,这个问题我jackjson进行了升级就解决了,Flink1.14.4版本引用的是2.12.1 (#872)

* Using connection pooling to fix jdbc multi-connection problem (#873)
Co-authored-by: 's avatarliuxiaofeng <liuxiaofeng@xcxd.com>

* [Fix-803] [Client] Fix TypeConvert-ColumnType Enumeration usage error (#878)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* [bug and doc] Fix yarn per job resource release (#863)

* [文档]:
1. 补充部署细节。
2. 增加一些 flink sql 案例。

* [bug修复]:
修复 yarn per job 、 batch 模式下任务完成后,yarn 不自动释放 flink JM 角色资源的问题,任务以 detached 模式运行。

* [Fix-832][doc] add Practice Sharing of FlinkSQL Extending Redis (#879)
Co-authored-by: 's avatarhzymarine <marinehuang163@163.com>

* [Feature-868][Common] Added github workflow to check the checkstyle, test and build of each PR (#869)

* Added github workflow to check the checkstyle, test and build of each PR.

* Specify the checkstyle file.

* Added dlink-admin module code style (#889)

* [Optimization][Style]Added dlink-alert module code style. (#891)

* Added dlink-alert module code style.

* update alert plugin module code style

* Added dlink-common module code style. (#892)

* Added dlink-catalog module code style. (#895)

* Added dlink-app module code style. (#899)

* Optimized connection pooling and connection creation (#900)
Co-authored-by: 's avatarliuxiaofeng <liuxiaofeng@xcxd.com>

* feature 全局变量管理增删改查实现 (#906)

* [Feature-907][pom] Change Flink base version into 1.14 (#908)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* Added dlink-connectors module code style. (#913)

* [Feature-915][admin,core] Add global variables takes effect in flinksql (#916)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* Added dlink-daemon module code style. (#918)

* Added dlink-executor module code style. (#919)

* [Optimization][Style]  Added dlink-core module code style (#917)

* Added dlink-core module code style.

* fix AbstractTrans error

* Added dlink-client module code style. (#898)

* Added dlink-function and dlink-gateway module code style (#920)

* Add a license description to the pom file. (#922)

* Added dlink-metadata module code style. (#921)

* [Feature-923][*] Build column lineage base on flink logical plan (#924)

* [Feature-923][*] Build column lineage base on flink logical plan

* [Feature-923][*] Dynamic add getColumnOrigins method to class RelMdColumnOrigins by javassist
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* [Optimization-932][pom] Optimizate package and auto.sh by loading classpaths (#933)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* 'dlink-client-hadoop打包增加ServicesResourceTransformer' (#935)

* [Optimization-943][pom] Optimizate config and static dir packaging (#944)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* flinkSQL supports the posgresql CDC function and the full database synchronization function. (#925)

* 修改点:
1、dlink-flink1.14增加postgres cdc connector,支持flinksql开发。
2、整库同步增加支持postgres数据库。

* 修改点:
1、METADATA_TYPE与dlink-meta中保持一致,避免Driver找不到lib的情况;
2、url中/后改为databasename,原来代码中填schema名是不正确的。

* postgresCDCBuilder改为首字母大写。

* Modify checkstyle to be a required item. (#948)

* 支持sqlserver cdc功能,测试同步doris通过。 (#951)

* 增加sqlserver-cdc支持,可以通过手写finksql完成sqlservercdc同步,但是不支持cdcsource模式.

* 修改报名\类名为sqlserver

* 增加sqlserver-cdc支持,可以通过手写finksql完成sqlservercdc同步,但是不支持cdcsource模式.

* 优化trycatch异常日志打印代码

* 支持sqlservercdc功能
Co-authored-by: 's avatar金鑫 <jinyanhui@huansi.net>

* Fix cluster submission taskId is empty (#862)

* The bug that the cluster information cannot be obtained in the savepoint save list

* Add taskId in case dlink maintains sql

* format code

* enhance manage logic

* 1. fix taskId is 0
2. reformat code

* reformat code

* refactor imports

* [Optimization][Style] Configure global checkstyle validation. (#953)

* Configure global checkstyle validation.

* Configure global checkstyle validation.

* [Feature] Add swagger api doc (#954)

* Add swagger api doc

* update datasource config info in the application file

* [Fix-840] [web] fix registration document type filter condition error (#959)

* Sqlserver增加date类型数据转换规则 (#958)

* sqlserver增加date类型数据转换规则.

* sqlserver增加date类型数据转换规则.
Co-authored-by: 's avatar金鑫 <jinyanhui@huansi.net>

* [Fix][dlink-gateway]修复k8s Application、Yarn Application、Yarn PerJob提交任务时未指定集群配置MasterMemoryMB、TaskManagerMemoryMB、SlotsPerTaskManager (#970)

* [Fix][dlink-gateway]修复k8s Application、Yarn Application、Yarn PerJob提交任务时未指定集群配置MasterMemoryMB、TaskManagerMemoryMB、SlotsPerTaskManager

* cdcsource增加多目标库同步功能 (#969)

单目标使用 'sink.*'
多目标使用 'sink[N].*', N为0开始的index索引.
Co-authored-by: 's avatar金鑫 <jinyanhui@huansi.net>

* 修复问题: (#949)

解决KafkaSinkBuilder没有序列化会报错的问题。

* Create PostgreSqlQuery.java (#971)

优化PG库"schema_name"查询

* [Fix][dlink-gateway]修复k8s application模式提交失败,优化增加获取JobId等待时间 (#972)

* [Fix][dlink-gateway]修复k8s Application、Yarn Application、Yarn PerJob提交任务时未指定集群配置MasterMemoryMB、TaskManagerMemoryMB、SlotsPerTaskManager

* [Fix][dlink-gateway]修复k8s Application、Yarn Application、Yarn PerJob提交任务时未指定集群配置MasterMemoryMB、TaskManagerMemoryMB、SlotsPerTaskManager

* [Fix][dlink-gateway]修复k8s application模式提交失败,优化增加获取JobId等待时间,

* [Fix][dlink-common]扩展系统配置参数添加jobid的最大等待时间

* [Bug] fix the banner of dlink admin app (#977)

* [Bug] fix the banner of dlink admin app

* remove banners

* [Optimization-981][metadata] Doris support more syntax (#982)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* [Optimization-983][client] Optimizate Doris datastream sink (#984)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* Optimizing Deployment Documents (#980)

* [feature] [dlink-admin] File upload (#939)

* add a table, name: dlink_upload_file_record

* File upload implement

* Modify function name and javadoc

* [Feature-987][admin] ClusterConfig and jar add upload file (#988)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* optimization Some problems in front-end (#986)

* 修订TypeImformation原因,自定义隐函数不能在Flink 1.14.x 版本以上运行。 (#973)

1.引入泛型,以自适应多种数据类型;
2.直接返回Map<K,V>,避免数据转换

* [Feature-989][metadata] Add StarRocks datasource (#990)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* [Optimization-882][web] Collapse all directories by default on datastudio's directory panel (#991)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* [Feature-946][alarm] Alarm after task monitoring retry (#992)

* [Feature-946][alarm] Alarm after task monitoring retry

* Format code
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* [Optimization-881][datastudio] Optimizate FlinkSql explain exception message (#993)
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>

* fix code checkstyle

* 渲染用户选择租户菜单

* 优化注册全局变量时被拦截的问题

* 优化用户选择租户菜单

* 优化一些代码
Co-authored-by: 's avatarKerwin <37063904+zhuangchong@users.noreply.github.com>
Co-authored-by: 's avatarmydq <42607771+mydq@users.noreply.github.com>
Co-authored-by: 's avataraiwenmo <32723967+aiwenmo@users.noreply.github.com>
Co-authored-by: 's avatargodkaikai <32723967+godkaikai@users.noreply.github.com>
Co-authored-by: 's avatarZackYoung <42713096+zackyoungh@users.noreply.github.com>
Co-authored-by: 's avatarlucas.wu <1220671715@qq.com>
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>
Co-authored-by: 's avatardzygcc <dzygcc@gmail.com>
Co-authored-by: 's avatardzygcc <avadar@qq.com>
Co-authored-by: 's avatarchrofram <32118314+chrofram@users.noreply.github.com>
Co-authored-by: 's avatarqiaoyiming <wenpin@tianmagroup.com>
Co-authored-by: 's avatarwindWheel <1817802738@qq.com>
Co-authored-by: 's avatarzhongjingq <51869301+zhongjingq@users.noreply.github.com>
Co-authored-by: 's avatarzhonggui.wang <17490539+wangzhonggui@users.noreply.github.com>
Co-authored-by: 's avatarsunyanqing01 <43230630+sunyanqing01@users.noreply.github.com>
Co-authored-by: 's avatarxiaofeng <46049797+XiaoF-Liu@users.noreply.github.com>
Co-authored-by: 's avatarliuxiaofeng <liuxiaofeng@xcxd.com>
Co-authored-by: 's avatar第一片心意 <107013241+ziqiang-wang@users.noreply.github.com>
Co-authored-by: 's avatarhzymarine <50948904+hzymarine@users.noreply.github.com>
Co-authored-by: 's avatarhzymarine <marinehuang163@163.com>
Co-authored-by: 's avatarlnnlab <35280765+lnnlab@users.noreply.github.com>
Co-authored-by: 's avatarmengyejiang <403905717@qq.com>
Co-authored-by: 's avatar金鑫 <jinxincoding@gmail.com>
Co-authored-by: 's avatar金鑫 <jinyanhui@huansi.net>
Co-authored-by: 's avatarrafael <46079067+rafaelxie@users.noreply.github.com>
Co-authored-by: 's avatarcong <274902531@qq.com>
Co-authored-by: 's avatarzhujunjieit <42972147+zhujunjieit@users.noreply.github.com>
Co-authored-by: 's avatarleo65535 <leo65535@163.com>
Co-authored-by: 's avatarbyd-android-2017 <17773406760@189.cn>

* fix tenant bug (#1010)

* optimization choose tenant

* [optimization][*] optimization tenant code checkstyles (#1037)

* optimizer tenant,add user and tenant relation. (#1070)

* Implementation of tenant assignment user function and related code optimization (#1071)

* [Fix][web] Fix tenant assignment user function code (#1073)

* Implementation of tenant assignment user function and related code optimization

* fix tenant assignment user function code

* fix tenant assignment user function code

* [Optimize][web,admin] Optimize tenant selection (#1081)

* Implementation of tenant assignment user function and related code optimization

* fix tenant assignment user function code

* fix tenant assignment user function code

* Optimize tenant selection

* [Optimize][web] change resource center to authentication center (#1082)

* [optimization][web] Tips for optimizing batch deletion (#1085)

* Fix merged problems

* Fix merged sql file problems

* Fix merged sql file problems

* Fix merged init bug

* Fix merged user info bug

* Fix merged web bug

* Optimize internationalization

* Optimize internationalization

* reduction readme.md

* reduction readme.md

* reduction  readme.md
Co-authored-by: 's avatarXiuhongTang <t_spider@aliyun.com>
Co-authored-by: 's avatartangxiuhong <tangxiuhong@cangshu.vip>
Co-authored-by: 's avataraiwenmo <32723967+aiwenmo@users.noreply.github.com>
Co-authored-by: 's avatarwenmo <32723967+wenmo@users.noreply.github.com>
Co-authored-by: 's avatarKerwin <37063904+zhuangchong@users.noreply.github.com>
Co-authored-by: 's avatarmydq <42607771+mydq@users.noreply.github.com>
Co-authored-by: 's avatargodkaikai <32723967+godkaikai@users.noreply.github.com>
Co-authored-by: 's avatarZackYoung <42713096+zackyoungh@users.noreply.github.com>
Co-authored-by: 's avatarlucas.wu <1220671715@qq.com>
Co-authored-by: 's avatardzygcc <dzygcc@gmail.com>
Co-authored-by: 's avatardzygcc <avadar@qq.com>
Co-authored-by: 's avatarchrofram <32118314+chrofram@users.noreply.github.com>
Co-authored-by: 's avatarqiaoyiming <wenpin@tianmagroup.com>
Co-authored-by: 's avatarwindWheel <1817802738@qq.com>
Co-authored-by: 's avatarzhongjingq <51869301+zhongjingq@users.noreply.github.com>
Co-authored-by: 's avatarzhonggui.wang <17490539+wangzhonggui@users.noreply.github.com>
Co-authored-by: 's avatarsunyanqing01 <43230630+sunyanqing01@users.noreply.github.com>
Co-authored-by: 's avatarxiaofeng <46049797+XiaoF-Liu@users.noreply.github.com>
Co-authored-by: 's avatarliuxiaofeng <liuxiaofeng@xcxd.com>
Co-authored-by: 's avatar第一片心意 <107013241+ziqiang-wang@users.noreply.github.com>
Co-authored-by: 's avatarhzymarine <50948904+hzymarine@users.noreply.github.com>
Co-authored-by: 's avatarhzymarine <marinehuang163@163.com>
Co-authored-by: 's avatarlnnlab <35280765+lnnlab@users.noreply.github.com>
Co-authored-by: 's avatarmengyejiang <403905717@qq.com>
Co-authored-by: 's avatar金鑫 <jinxincoding@gmail.com>
Co-authored-by: 's avatar金鑫 <jinyanhui@huansi.net>
Co-authored-by: 's avatarrafael <46079067+rafaelxie@users.noreply.github.com>
Co-authored-by: 's avatarcong <274902531@qq.com>
Co-authored-by: 's avatarzhujunjieit <42972147+zhujunjieit@users.noreply.github.com>
Co-authored-by: 's avatarleo65535 <leo65535@163.com>
Co-authored-by: 's avatarbyd-android-2017 <17773406760@189.cn>
parent 6222f508
......@@ -16,7 +16,7 @@ Dinky 是一个 `开箱即用` 、`易扩展` ,以 `Apache Flink` 为基础,
其主要功能如下:
- 沉浸式 FlinkSQL 数据开发:自动提示补全、语法高亮、语句美化、在线调试、语法校验、执行计划、MetaStore、血缘分析、版本对比等
- 支持 FlinkSQL 多版本开发及多种执行模式:Local、Standalone、Yarn/Kubernetes Session、Yarn Per-Job、Yarn/Kubernetes Application
- 支持 FlinkSQL 多版本开发及多种执行模式:Local、Standalone、Yarn/Kubernetes Session、Yarn Per-Job、Yarn/Kubernetes Application
- 支持 Apache Flink 生态:Connector、FlinkCDC、Table Store 等
- 支持 FlinkSQL 语法增强:表值聚合函数、全局变量、执行环境、语句合并、整库同步、共享会话等
- 支持 FlinkCDC 整库实时入仓入湖、多库输出、自动建表
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.configure;
import com.dlink.context.RequestContext;
import java.util.List;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.NullValue;
/**
* mybatisPlus config class
*/
@Configuration
@MapperScan("com.dlink.mapper")
@Slf4j
public class MybatisPlusConfig {
private static final List<String> IGNORE_TABLE_NAMES = Lists.newArrayList(
"dlink_namespace"
, "dlink_alert_group"
, "dlink_alert_history"
, "dlink_alert_instance"
, "dlink_catalogue"
, "dlink_cluster"
, "dlink_cluster_configuration"
, "dlink_database"
//,"dlink_fragment"
, "dlink_history"
, "dlink_jar"
, "dlink_job_history"
, "dlink_job_instance"
,"dlink_role"
, "dlink_savepoints"
, "dlink_task"
, "dlink_task_statement"
, "dlink_task_version"
);
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
log.info("mybatis plus interceptor execute");
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
@Override
public Expression getTenantId() {
Integer tenantId = (Integer) RequestContext.get();
if (tenantId == null) {
log.warn("request context tenant id is null");
return new NullValue();
}
return new LongValue(tenantId);
}
@Override
public boolean ignoreTable(String tableName) {
return !IGNORE_TABLE_NAMES.contains(tableName);
}
}));
return interceptor;
}
}
\ No newline at end of file
......@@ -19,6 +19,8 @@
package com.dlink.configure;
import com.dlink.interceptor.TenantInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
......@@ -40,7 +42,25 @@ public class SaTokenConfigure implements WebMvcConfigurer {
registry.addInterceptor(new SaRouteInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login")
.excludePathPatterns("/api/geTenants")
.excludePathPatterns("/openapi/**");
registry.addInterceptor(new TenantInterceptor())
.addPathPatterns("/api/alertGroup/**")
.addPathPatterns("/api/alertHistory/**")
.addPathPatterns("/api/alertInstance/**")
.addPathPatterns("/api/catalogue/**")
.addPathPatterns("/api/clusterConfiguration/**")
.addPathPatterns("/api/cluster/**")
.addPathPatterns("/api/database/**")
.addPathPatterns("/api/history/**")
.addPathPatterns("/api/jobInstance/**")
.addPathPatterns("/api/namespace/**")
.addPathPatterns("/api/savepoints/**")
.addPathPatterns("/api/statement/**")
.addPathPatterns("/api/task/**")
.addPathPatterns("/api/role/**")
//.addPathPatterns("/api/fragment/**")
.addPathPatterns("/api/jar/*");
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.context;
/**
* request context
*/
public class RequestContext {
private static final ThreadLocal<Object> threadLocal = new ThreadLocal<>();
public static void set(Object value) {
threadLocal.set(value);
}
public static Object get() {
return threadLocal.get();
}
public static void remove() {
threadLocal.remove();
}
}
\ No newline at end of file
......@@ -30,6 +30,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import cn.dev33.satoken.stp.StpUtil;
......@@ -57,7 +58,7 @@ public class AdminController {
if (Asserts.isNull(loginUTO.isAutoLogin())) {
loginUTO.setAutoLogin(false);
}
return userService.loginUser(loginUTO.getUsername(), loginUTO.getPassword(), loginUTO.isAutoLogin());
return userService.loginUser(loginUTO);
}
/**
......@@ -80,4 +81,12 @@ public class AdminController {
return Result.failed("获取失败");
}
}
/**
* get tenant
*/
@RequestMapping("/geTenants")
public Result getTenants(@RequestParam("username") String username) {
return userService.getTenants(username);
}
}
......@@ -60,12 +60,13 @@ public class ClusterConfigurationController {
*/
@PutMapping
public Result saveOrUpdate(@RequestBody ClusterConfiguration clusterConfiguration) {
Integer id = clusterConfiguration.getId();
TestResult testResult = clusterConfigurationService.testGateway(clusterConfiguration);
clusterConfiguration.setIsAvailable(testResult.isAvailable());
if (clusterConfigurationService.saveOrUpdate(clusterConfiguration)) {
return Result.succeed(Asserts.isNotNull(clusterConfiguration.getId()) ? "修改成功" : "新增成功");
return Result.succeed(Asserts.isNotNull(id) ? "修改成功" : "新增成功");
} else {
return Result.failed(Asserts.isNotNull(clusterConfiguration.getId()) ? "修改失败" : "新增失败");
return Result.failed(Asserts.isNotNull(id) ? "修改失败" : "新增失败");
}
}
......
......@@ -60,8 +60,9 @@ public class ClusterController {
@PutMapping
public Result saveOrUpdate(@RequestBody Cluster cluster) throws Exception {
cluster.setAutoRegisters(false);
Integer id = cluster.getId();
clusterService.registersCluster(cluster);
return Result.succeed(Asserts.isNotNull(cluster.getId()) ? "修改成功" : "新增成功");
return Result.succeed(Asserts.isNotNull(id) ? "修改成功" : "新增成功");
}
/**
......
......@@ -130,7 +130,7 @@ public class JarController {
List<String> udfCodes = allUDF.stream().map(Task::getStatement).collect(Collectors.toList());
Map<String, List<String>> resultMap = UDFUtil.buildJar(udfCodes);
String msg = StrUtil.format("udf jar生成成功,jar文件在{};\n本次成功 class:{}。\n失败 class:{}"
, PathConstant.UDF_JAR_TMP_PATH, resultMap.get("success"), resultMap.get("failed"));
, PathConstant.UDF_JAR_TMP_PATH, resultMap.get("success"), resultMap.get("failed"));
return Result.succeed(resultMap, msg);
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.controller;
import com.dlink.assertion.Asserts;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.model.Namespace;
import com.dlink.service.NamespaceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/api/namespace")
public class NamespaceController {
@Autowired
private NamespaceService namespaceService;
/**
* create or update namespace
*
* @return delete result code
*/
@PutMapping
public Result saveOrUpdate(@RequestBody Namespace namespace) {
Integer id = namespace.getId();
if (namespaceService.saveOrUpdate(namespace)) {
return Result.succeed(Asserts.isNotNull(id) ? "修改成功" : "新增成功");
} else {
return Result.failed(Asserts.isNotNull(id) ? "修改失败" : "新增失败");
}
}
/**
* delete namespace by id
*
* @return delete result code
*/
@DeleteMapping()
public Result deleteNamespaceById(@RequestBody JsonNode para) {
return namespaceService.deleteNamespaceById(para);
}
/**
* query namespace list
*/
@PostMapping
public ProTableResult<Namespace> listNamespaces(@RequestBody JsonNode para) {
return namespaceService.selectForProTable(para);
}
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.controller;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.model.Role;
import com.dlink.model.UserRole;
import com.dlink.service.RoleService;
import com.dlink.service.UserRoleService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/api/role")
public class RoleController {
@Autowired
private RoleService roleService;
@Autowired
private UserRoleService userRoleService;
/**
* create or update role
*
* @return delete result code
*/
@PutMapping
public Result saveOrUpdateRole(@RequestBody Role role) {
return roleService.saveOrUpdateRole(role);
}
/**
* delete tenant by id
*
* @return delete result code
*/
@DeleteMapping
public Result deleteMul(@RequestBody JsonNode para) {
return roleService.deleteRoles(para);
}
/**
* query role list
*/
@PostMapping
public ProTableResult<Role> listRoles(@RequestBody JsonNode para) {
return roleService.selectForProTable(para, true);
}
/**
* 获取所有的角色列表以及当前用户的角色 ids
*/
@GetMapping(value = "/getRolesAndIdsByUserId")
public Result getRolesAndIdsByUserId(@RequestParam Integer id) {
List<Role> roleList = roleService.list();
Map result = new HashMap();
result.put("roles", roleList);
List<UserRole> userRoleList = userRoleService.getUserRoleByUserId(id);
List<Integer> userRoleIds = new ArrayList<>();
for (UserRole userRole : userRoleList) {
userRoleIds.add(userRole.getRoleId());
}
result.put("roleIds", userRoleIds);
return Result.succeed(result, "获取成功");
}
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.controller;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.model.Tenant;
import com.dlink.service.TenantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/api/tenant")
public class TenantController {
@Autowired
private TenantService tenantService;
/**
* create or update tenant
*
* @return delete result code
*/
@PutMapping
public Result saveOrUpdate(@RequestBody Tenant tenant) {
return tenantService.saveOrUpdateTenant(tenant);
}
/**
* delete tenant by id
*
* @return delete result code
*/
@DeleteMapping()
public Result deleteTenantById(@RequestBody JsonNode para) {
return tenantService.deleteTenantById(para);
}
/**
* query tenant list
*/
@PostMapping
public ProTableResult<Tenant> listTenants(@RequestBody JsonNode para) {
return tenantService.selectForProTable(para, true);
}
/**
* give tenant grant user
*
* @return
*/
@PutMapping(value = "/grantTenantToUser")
public Result distributeUser(@RequestBody JsonNode para) {
return tenantService.distributeUsers(para);
}
@PostMapping(value = "/switchTenant")
public Result switchTenant(@RequestBody JsonNode para) {
return tenantService.switchTenant(para);
}
}
\ No newline at end of file
......@@ -24,19 +24,26 @@ import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.dto.ModifyPasswordDTO;
import com.dlink.model.User;
import com.dlink.model.UserTenant;
import com.dlink.service.UserService;
import com.dlink.service.UserTenantService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
......@@ -54,6 +61,9 @@ public class UserController {
@Autowired
private UserService userService;
@Autowired
private UserTenantService userTenantService;
/**
* 新增或者更新
*/
......@@ -122,6 +132,30 @@ public class UserController {
@PostMapping("/modifyPassword")
public Result modifyPassword(@RequestBody ModifyPasswordDTO modifyPasswordDTO) {
return userService.modifyPassword(modifyPasswordDTO.getUsername(), modifyPasswordDTO.getPassword(),
modifyPasswordDTO.getNewPassword());
modifyPasswordDTO.getNewPassword());
}
/**
* give user grant role
*
* @return
*/
@PutMapping(value = "/grantRole")
public Result grantRole(@RequestBody JsonNode para) {
return userService.grantRole(para);
}
@GetMapping("/getUserListByTenantId")
public Result getUserListByTenantId(@RequestParam("id") Integer id) {
List<User> userList = userService.list();
Map result = new HashMap();
result.put("users", userList);
List<UserTenant> userTenants = userTenantService.getBaseMapper().selectList(new QueryWrapper<UserTenant>().eq("tenant_id", id));
List<Integer> userIds = new ArrayList<>();
for (UserTenant userTenant : userTenants) {
userIds.add(userTenant.getUserId());
}
result.put("userIds", userIds);
return Result.succeed(result, "获取成功");
}
}
......@@ -34,6 +34,7 @@ import lombok.Setter;
@Setter
public class CatalogueTaskDTO {
private Integer id;
private Integer tenantId;
private Integer parentId;
private boolean isLeaf;
private String name;
......
......@@ -33,5 +33,6 @@ import lombok.Setter;
public class LoginUTO {
private String username;
private String password;
private Integer tenantId;
private boolean autoLogin;
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.dto;
import com.dlink.model.Role;
import com.dlink.model.Tenant;
import com.dlink.model.User;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO {
private User user;
private List<Role> roleList;
private List<Tenant> tenantList;
private Tenant currentTenant;
}
......@@ -69,7 +69,7 @@ public class WebExceptionHandler {
return Result.notLogin("该用户未登录!");
}
@ResponseStatus(HttpStatus.BAD_REQUEST) //设置状态码为 400
@ResponseStatus(HttpStatus.BAD_REQUEST) // 设置状态码为 400
@ExceptionHandler({MethodArgumentNotValidException.class})
public Result<String> paramExceptionHandler(MethodArgumentNotValidException e) {
BindingResult exceptions = e.getBindingResult();
......@@ -93,5 +93,4 @@ public class WebExceptionHandler {
logger.error("ERROR:", e);
return Result.failed(e.getMessage());
}
}
......@@ -20,10 +20,12 @@
package com.dlink.init;
import com.dlink.assertion.Asserts;
import com.dlink.context.RequestContext;
import com.dlink.daemon.task.DaemonFactory;
import com.dlink.daemon.task.DaemonTaskConfig;
import com.dlink.job.FlinkJobTask;
import com.dlink.model.JobInstance;
import com.dlink.model.Tenant;
import com.dlink.scheduler.client.ProjectClient;
import com.dlink.scheduler.config.DolphinSchedulerProperties;
import com.dlink.scheduler.exception.SchedulerException;
......@@ -31,6 +33,7 @@ import com.dlink.scheduler.model.Project;
import com.dlink.service.JobInstanceService;
import com.dlink.service.SysConfigService;
import com.dlink.service.TaskService;
import com.dlink.service.TenantService;
import java.util.ArrayList;
import java.util.List;
......@@ -63,13 +66,19 @@ public class SystemInit implements ApplicationRunner {
@Autowired
private TaskService taskService;
@Autowired
private TenantService tenantService;
@Autowired
private DolphinSchedulerProperties dolphinSchedulerProperties;
private static Project project;
@Override
public void run(ApplicationArguments args) throws Exception {
List<Tenant> tenants = tenantService.list();
sysConfigService.initSysConfig();
taskService.initDefaultFlinkSQLEnv();
for (Tenant tenant : tenants) {
RequestContext.set(tenant.getId());
taskService.initDefaultFlinkSQLEnv(tenant.getId());
}
initTaskMonitor();
initDolphinScheduler();
}
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.interceptor;
import com.dlink.context.RequestContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import com.mysql.cj.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
/**
* tenant interceptor
*/
@Slf4j
public class TenantInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String tenantId = request.getHeader("tenantId");
log.info("tenant interceptor preHandle execute ; current tenant id: 【" + tenantId + "】");
if (!StringUtils.isNullOrEmpty(tenantId)) {
RequestContext.set(Integer.valueOf(tenantId));
}
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.mapper;
import com.dlink.db.mapper.SuperMapper;
import com.dlink.model.Namespace;
import org.apache.ibatis.annotations.Mapper;
/**
* namespace mapper interface
*/
@Mapper
public interface NamespaceMapper extends SuperMapper<Namespace> {
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.mapper;
import com.dlink.db.mapper.SuperMapper;
import com.dlink.model.Role;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
* role mapper interface
*/
@Mapper
public interface RoleMapper extends SuperMapper<Role> {
List<Role> getRoleByIds(@Param("roleIds") Set<Integer> roleIds);
List<Role> getRoleByTenantIdAndIds(@Param("tenantId") String tenantId, @Param("roleIds") Set<Integer> roleIds);
int deleteByIds(@Param("ids") List<Integer> ids);
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.mapper;
import com.dlink.db.mapper.SuperMapper;
import com.dlink.model.RoleNamespace;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* role namespace mapper interface
*/
@Mapper
public interface RoleNamespaceMapper extends SuperMapper<RoleNamespace> {
/**
* delete user role relation by role id
*
* @param roleIds role id
* @return
*/
int deleteByRoleIds(@Param("roleIds") List<Integer> roleIds);
}
\ No newline at end of file
......@@ -33,6 +33,4 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface StatementMapper extends SuperMapper<Statement> {
int insert(Statement statement);
}
......@@ -41,4 +41,6 @@ public interface TaskMapper extends SuperMapper<Task> {
List<Task> queryOnLineTaskByDoneStatus(@Param("parentIds") List<Integer> parentIds
, @Param("stepIds") List<Integer> stepIds, @Param("includeNull") boolean includeNull
, @Param("jobStatuses") List<String> jobStatuses);
Task getTaskByNameAndTenantId(@Param("name") String name, @Param("tenantId") Integer tenantId);
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.mapper;
import com.dlink.db.mapper.SuperMapper;
import com.dlink.model.Tenant;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
* tenant mapper interface
*/
@Mapper
public interface TenantMapper extends SuperMapper<Tenant> {
List<Tenant> getTenantByIds(@Param("tenantIds") Set<Integer> tenantIds);
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.mapper;
import com.dlink.db.mapper.SuperMapper;
import com.dlink.model.UserRole;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* user role mapper interface
*/
@Mapper
public interface UserRoleMapper extends SuperMapper<UserRole> {
/**
* @param userId userId
* @return user role relation
*/
List<UserRole> getUserRoleByUserId(@Param("userId") int userId);
/**
* delete user role relation
*
* @param userRoleList list
* @return int
*/
int deleteBathRelation(@Param("userRoleList") List<UserRole> userRoleList);
/**
* delete user role relation by role id
*
* @param roleIds role id
* @return delete status
*/
int deleteByRoleIds(@Param("roleIds") List<Integer> roleIds);
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.mapper;
import com.dlink.db.mapper.SuperMapper;
import com.dlink.model.UserTenant;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface UserTenantMapper extends SuperMapper<UserTenant> {
/**
* @param userId userId
* @return user role tenant
*/
List<UserTenant> getUserTenantByUserId(@Param("userId") int userId);
}
......@@ -42,6 +42,8 @@ public class AlertGroup extends SuperEntity {
private static final long serialVersionUID = 7027411164191682344L;
private Integer tenantId;
private String alertInstanceIds;
private String note;
......
......@@ -47,6 +47,8 @@ public class AlertHistory implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer tenantId;
private Integer alertGroupId;
private Integer jobInstanceId;
......
......@@ -38,6 +38,8 @@ import lombok.EqualsAndHashCode;
public class AlertInstance extends SuperEntity {
private static final long serialVersionUID = -3435401513220527001L;
private Integer tenantId;
private String type;
private String params;
......
......@@ -39,6 +39,8 @@ public class Catalogue extends SuperEntity {
private static final long serialVersionUID = 4659379420249868394L;
private Integer tenantId;
private Integer taskId;
private String type;
......
......@@ -41,6 +41,8 @@ public class Cluster extends SuperEntity {
private static final long serialVersionUID = 3104721227014487321L;
private Integer tenantId;
@TableField(fill = FieldFill.INSERT)
private String alias;
......
......@@ -47,6 +47,8 @@ public class ClusterConfiguration extends SuperEntity {
private static final long serialVersionUID = 5830130188542066241L;
private Integer tenantId;
@TableField(fill = FieldFill.INSERT)
private String alias;
......
......@@ -44,6 +44,8 @@ public class DataBase extends SuperEntity {
private static final long serialVersionUID = -5002272138861566408L;
private Integer tenantId;
@TableField(fill = FieldFill.INSERT)
private String alias;
......
......@@ -43,28 +43,48 @@ public class History implements Serializable {
private static final long serialVersionUID = 4058280957630503072L;
private Integer id;
private Integer tenantId;
private Integer clusterId;
private Integer clusterConfigurationId;
private String session;
private String jobId;
private String jobName;
private String jobManagerAddress;
private Integer status;
private String statement;
private String type;
private String error;
private String result;
@TableField(exist = false)
private ObjectNode config;
private String configJson;
private LocalDateTime startTime;
private LocalDateTime endTime;
private Integer taskId;
@TableField(exist = false)
private String statusText;
@TableField(exist = false)
private String clusterAlias;
@TableField(exist = false)
private String taskAlias;
......
......@@ -44,6 +44,8 @@ public class Jar extends SuperEntity {
@TableField(fill = FieldFill.INSERT)
private String alias;
private Integer tenantId;
private String type;
private String path;
......
......@@ -45,6 +45,8 @@ public class JobHistory implements Serializable {
private Integer id;
private Integer tenantId;
@TableField(exist = false)
private ObjectNode job;
......
......@@ -48,6 +48,8 @@ public class JobInstance implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer tenantId;
private String name;
private Integer taskId;
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.model;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* namespace used to control permissions
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("dlink_namespace")
public class Namespace implements Serializable {
private static final long serialVersionUID = -5960332046748903443L;
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* tenant id
*/
private Integer tenantId;
/**
* namespace code
*/
private String namespaceCode;
/**
* is enabled
*/
private Boolean enabled;
/**
* note
*/
private String note;
/**
* create time
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* update time
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
/**
* tenant
*/
@TableField(exist = false)
private Tenant tenant;
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.model;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* role
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("dlink_role")
public class Role implements Serializable {
private static final long serialVersionUID = 6877230738922824958L;
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* tenant id
*/
private Integer tenantId;
/**
* role code
*/
private String roleCode;
/**
* role name
*/
private String roleName;
/**
* is delete
*/
private Boolean isDelete;
/**
* note
*/
private String note;
/**
* create time
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* update time
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
/**
* namespace list
*/
@TableField(exist = false)
private List<Namespace> namespaces;
/**
* namespace namespaceIds
*/
@TableField(exist = false)
private String namespaceIds;
/**
* tenant
*/
@TableField(exist = false)
private Tenant tenant;
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.model;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("dlink_role_namespace")
public class RoleNamespace implements Serializable {
private static final long serialVersionUID = 304808291890721691L;
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* role id
*/
private Integer roleId;
/**
* namespace id
*/
private Integer namespaceId;
/**
* create time
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* update time
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
\ No newline at end of file
......@@ -50,6 +50,8 @@ public class Savepoints implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private Integer tenantId;
@NotNull(message = "作业ID不能为空", groups = {Save.class})
private Integer taskId;
......
......@@ -41,5 +41,7 @@ public class Statement implements Serializable {
private Integer id;
private Integer tenantId;
private String statement;
}
......@@ -52,11 +52,14 @@ public class Task extends SuperEntity {
private static final long serialVersionUID = 5988972129893667154L;
@TableField(fill = FieldFill.INSERT)
private String alias;
private String dialect;
private Integer tenantId;
private String type;
private Integer checkPoint;
......@@ -152,7 +155,7 @@ public class Task extends SuperEntity {
boolean fg = Asserts.isNull(fragment) ? false : fragment;
boolean sts = Asserts.isNull(statementSet) ? false : statementSet;
return new JobConfig(type, step, false, false, useRemote, clusterId, clusterConfigurationId,jid, getId(),
alias, fg, sts, batchModel, checkPoint, parallelism, savePointStrategy, savePointPath, map);
alias, fg, sts, batchModel, checkPoint, parallelism, savePointStrategy, savePointPath, map);
}
public JsonNode parseJsonNode() {
......
......@@ -51,6 +51,11 @@ public class TaskVersion implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* tenant id
*/
private Integer tenantId;
/**
* 作业ID
*/
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.model;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* tenant use to isolate data
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("dlink_tenant")
public class Tenant implements Serializable {
private static final long serialVersionUID = -7782313413034278131L;
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* code
*/
private String tenantCode;
/**
* note
*/
private String note;
/**
* is delete
*/
private Boolean isDelete;
/**
* create time
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* update time
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.model;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("dlink_user_role")
public class UserRole implements Serializable {
private static final long serialVersionUID = -6123386787317880485L;
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* user id
*/
private Integer userId;
/**
* role id
*/
private Integer roleId;
/**
* create time
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* update time
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
\ No newline at end of file
package com.dlink.model;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import java.io.Serializable;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("dlink_user_tenant")
public class UserTenant implements Serializable {
private static final long serialVersionUID = -6123386787317880405L;
/**
* id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* user id
*/
private Integer userId;
/**
* tenant id
*/
private Integer tenantId;
/**
* create time
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* update time
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.db.service.ISuperService;
import com.dlink.model.Namespace;
import com.fasterxml.jackson.databind.JsonNode;
public interface NamespaceService extends ISuperService<Namespace> {
/**
* delete namespace by id
*
* @param para namespace id
* @return delete result code
*/
Result deleteNamespaceById(JsonNode para);
@Override
ProTableResult<Namespace> selectForProTable(JsonNode para);
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service;
import com.dlink.db.service.ISuperService;
import com.dlink.model.RoleNamespace;
import java.util.List;
public interface RoleNamespaceService extends ISuperService<RoleNamespace> {
/**
* delete user role relation by role id
*
* @param roleIds role id
* @return
*/
boolean deleteByRoleIds(List<Integer> roleIds);
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.db.service.ISuperService;
import com.dlink.model.Role;
import java.util.List;
import java.util.Set;
import com.fasterxml.jackson.databind.JsonNode;
public interface RoleService extends ISuperService<Role> {
/**
* delete role
*
* @param para role id
* @return delete result code
*/
Result deleteRoles(JsonNode para);
Result saveOrUpdateRole(Role role);
List<Role> getRoleByIds(Set<Integer> roleIds);
List<Role> getRoleByTenantIdAndIds(String tenantId, Set<Integer> roleIds);
boolean deleteByIds(List<Integer> ids);
@Override
ProTableResult<Role> selectForProTable(JsonNode para);
}
\ No newline at end of file
......@@ -59,7 +59,7 @@ public interface TaskService extends ISuperService<Task> {
List<Task> listFlinkSQLEnv();
Task initDefaultFlinkSQLEnv();
Task initDefaultFlinkSQLEnv(Integer tenantId);
String exportSql(Integer id);
......@@ -110,4 +110,6 @@ public interface TaskService extends ISuperService<Task> {
void selectSavepointOffLineTask(TaskOperatingResult taskOperatingResult);
Task getTaskByNameAndTenantId(String name, Integer tenantId);
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service;
import com.dlink.common.result.Result;
import com.dlink.db.service.ISuperService;
import com.dlink.model.Tenant;
import java.util.List;
import java.util.Set;
import com.fasterxml.jackson.databind.JsonNode;
public interface TenantService extends ISuperService<Tenant> {
/**
* delete tenant by id
*
* @param para tenant id
* @return delete result code
*/
Result deleteTenantById(JsonNode para);
/**
* add or update tenant
*
* @param tenant tenant info
* @return add or update code
*/
Result saveOrUpdateTenant(Tenant tenant);
/**
* @param tenantCode tenant code
* @return Tenant
*/
Tenant getTenantByTenantCode(String tenantCode);
/**
* @param tenant tenant info
* @return modify code
*/
boolean modifyTenant(Tenant tenant);
List<Tenant> getTenantByIds(Set<Integer> tenantIds);
Result distributeUsers(JsonNode para);
Result switchTenant(JsonNode para);
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service;
import com.dlink.db.service.ISuperService;
import com.dlink.model.UserRole;
import java.util.List;
public interface UserRoleService extends ISuperService<UserRole> {
/**
* delete user role relation by user id
*
* @param userId user id
* @return delete row num
*/
int delete(int userId);
/**
* query user role relation by userId
*
* @param userId user id
* @return delete row num
*/
List<UserRole> getUserRoleByUserId(int userId);
/**
* delete user role relation by userId and roleId
*
* @param userRoleList
* @return
*/
int deleteBathRelation(List<UserRole> userRoleList);
/**
* delete user role relation by role id
*
* @param roleIds role id
* @return
*/
boolean deleteByRoleIds(List<Integer> roleIds);
}
......@@ -21,8 +21,11 @@ package com.dlink.service;
import com.dlink.common.result.Result;
import com.dlink.db.service.ISuperService;
import com.dlink.dto.LoginUTO;
import com.dlink.model.User;
import com.fasterxml.jackson.databind.JsonNode;
/**
* UserService
*
......@@ -39,7 +42,11 @@ public interface UserService extends ISuperService<User> {
boolean removeUser(Integer id);
Result loginUser(String username, String password, boolean isRemember);
Result loginUser(LoginUTO loginUTO);
User getUserByUsername(String username);
Result grantRole(JsonNode para);
Result getTenants(String username);
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service;
import com.dlink.db.service.ISuperService;
import com.dlink.model.UserTenant;
import java.util.List;
public interface UserTenantService extends ISuperService<UserTenant> {
/**
* @param userId userId
* @return user role tenant
*/
List<UserTenant> getUserTenantByUserId(int userId);
}
......@@ -85,6 +85,7 @@ public class CatalogueServiceImpl extends SuperServiceImpl<CatalogueMapper, Cata
task.setDialect(catalogueTaskDTO.getDialect());
taskService.saveOrUpdateTask(task);
Catalogue catalogue = new Catalogue();
catalogue.setTenantId(catalogueTaskDTO.getTenantId());
catalogue.setName(catalogueTaskDTO.getAlias());
catalogue.setIsLeaf(true);
catalogue.setTaskId(task.getId());
......@@ -189,8 +190,8 @@ public class CatalogueServiceImpl extends SuperServiceImpl<CatalogueMapper, Cata
Statement statementServiceById = statementService.getById(catalogue.getTaskId());
//新建作业的sql语句
Statement statement = new Statement();
statement.setStatement(statementServiceById.getStatement());
statement.setId(newTask.getId());
statement.setStatement(statementServiceById.getStatement());
statementService.save(statement);
Catalogue one = this.getOne(new LambdaQueryWrapper<Catalogue>().eq(Catalogue::getTaskId, catalogue.getTaskId()));
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service.impl;
import com.dlink.assertion.Asserts;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.db.service.impl.SuperServiceImpl;
import com.dlink.mapper.NamespaceMapper;
import com.dlink.model.Namespace;
import com.dlink.model.RoleNamespace;
import com.dlink.model.Tenant;
import com.dlink.service.NamespaceService;
import com.dlink.service.RoleNamespaceService;
import com.dlink.service.TenantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
@Service
public class NamespaceServiceImpl extends SuperServiceImpl<NamespaceMapper, Namespace> implements NamespaceService {
@Autowired
private RoleNamespaceService roleNamespaceService;
@Autowired
private TenantService tenantService;
@Override
public ProTableResult<Namespace> selectForProTable(JsonNode para) {
ProTableResult<Namespace> namespaceProTableResult = super.selectForProTable(para);
namespaceProTableResult.getData().forEach(namespace -> {
Tenant tenant = tenantService.getBaseMapper().selectById(namespace.getTenantId());
namespace.setTenant(tenant);
});
return namespaceProTableResult;
}
@Transactional(rollbackFor = Exception.class)
@Override
public Result deleteNamespaceById(JsonNode para) {
for (JsonNode item : para) {
Integer id = item.asInt();
Namespace namespace = getById(id);
if (Asserts.isNull(namespace)) {
return Result.failed("名称空间不存在");
}
Long roleNamespaceCount = roleNamespaceService.getBaseMapper().selectCount(new QueryWrapper<RoleNamespace>().eq("namespace_id", id));
if (roleNamespaceCount > 0) {
return Result.failed("删除名称空间失败,该名称空间被角色绑定");
}
boolean result = removeById(id);
if (result) {
return Result.succeed("删除名称空间成功");
} else {
return Result.failed("删除名称空间失败");
}
}
return Result.failed("名称空间不存在");
}
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service.impl;
import com.dlink.db.service.impl.SuperServiceImpl;
import com.dlink.mapper.RoleNamespaceMapper;
import com.dlink.model.RoleNamespace;
import com.dlink.service.RoleNamespaceService;
import java.util.List;
import org.springframework.stereotype.Service;
@Service
public class RoleNamespaceServiceImpl extends SuperServiceImpl<RoleNamespaceMapper, RoleNamespace> implements RoleNamespaceService {
@Override
public boolean deleteByRoleIds(List<Integer> roleIds) {
return baseMapper.deleteByRoleIds(roleIds) > 0;
}
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service.impl;
import com.dlink.assertion.Asserts;
import com.dlink.common.result.ProTableResult;
import com.dlink.common.result.Result;
import com.dlink.db.service.impl.SuperServiceImpl;
import com.dlink.mapper.RoleMapper;
import com.dlink.model.Namespace;
import com.dlink.model.Role;
import com.dlink.model.RoleNamespace;
import com.dlink.model.Tenant;
import com.dlink.model.UserRole;
import com.dlink.service.NamespaceService;
import com.dlink.service.RoleNamespaceService;
import com.dlink.service.RoleService;
import com.dlink.service.TenantService;
import com.dlink.service.UserRoleService;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
/**
* role service impl
*/
@Service
public class RoleServiceImpl extends SuperServiceImpl<RoleMapper, Role> implements RoleService {
private static final Logger LOG = LoggerFactory.getLogger(RoleServiceImpl.class);
@Autowired
private RoleNamespaceService roleNamespaceService;
@Autowired
private UserRoleService userRoleService;
@Autowired
private RoleService roleService;
@Autowired
private TenantService tenantService;
@Autowired
private NamespaceService namespaceService;
@Transactional(rollbackFor = Exception.class)
@Override
public Result saveOrUpdateRole(Role role) {
if (Asserts.isNull(role.getId())) {
Role roleCode = roleService.getOne(new QueryWrapper<Role>().eq("role_code", role.getRoleCode()));
if (Asserts.isNotNull(roleCode)) {
return Result.failed("角色编号:【" + role.getRoleCode() + "】已存在");
}
}
boolean roleSaveOrUpdate = saveOrUpdate(role);
boolean roleNamespaceSaveOrUpdate = false;
if (roleSaveOrUpdate) {
List<RoleNamespace> roleNamespaceList = roleNamespaceService.getBaseMapper().selectList(new QueryWrapper<RoleNamespace>().eq("role_id", role.getId()));
roleNamespaceService.removeByIds(roleNamespaceList.stream().map(RoleNamespace::getId).collect(Collectors.toList()));
List<RoleNamespace> arrayListRoleNamespace = new ArrayList<>();
String[] idsList = role.getNamespaceIds().split(",");
for (String namespaceId : idsList) {
RoleNamespace roleNamespace = new RoleNamespace();
roleNamespace.setRoleId(role.getId());
roleNamespace.setNamespaceId(Integer.valueOf(namespaceId));
arrayListRoleNamespace.add(roleNamespace);
}
roleNamespaceSaveOrUpdate = roleNamespaceService.saveBatch(arrayListRoleNamespace);
}
if (roleSaveOrUpdate && roleNamespaceSaveOrUpdate) {
return Result.succeed("保存成功");
} else {
return Result.failed("保存失败");
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public Result deleteRoles(JsonNode para) {
if (para.size() > 0) {
List<Integer> error = new ArrayList<>();
for (final JsonNode item : para) {
Integer id = item.asInt();
boolean roleNameSpaceRemove = roleNamespaceService.remove(new QueryWrapper<RoleNamespace>().eq("role_id", id));
boolean userRoleRemove = userRoleService.remove(new QueryWrapper<UserRole>().eq("role_id", id));
Role role = getById(id);
role.setIsDelete(true);
boolean removeById = roleService.updateById(role);
if (!removeById && !roleNameSpaceRemove && !userRoleRemove) {
error.add(id);
}
}
if (error.size() == 0) {
return Result.succeed("删除成功");
} else {
return Result.succeed("删除部分成功,但" + error.toString() + "删除失败,共" + error.size() + "次失败。");
}
} else {
return Result.failed("请选择要删除的记录");
}
}
@Override
public List<Role> getRoleByIds(Set<Integer> roleIds) {
return baseMapper.getRoleByIds(roleIds);
}
@Override
public List<Role> getRoleByTenantIdAndIds(String tenantId, Set<Integer> roleIds) {
return baseMapper.getRoleByTenantIdAndIds(tenantId, roleIds);
}
@Override
public boolean deleteByIds(List<Integer> ids) {
return baseMapper.deleteByIds(ids) > 0;
}
@Override
public ProTableResult<Role> selectForProTable(JsonNode para, boolean isDelete) {
ProTableResult<Role> roleProTableResult = super.selectForProTable(para, isDelete);
roleProTableResult.getData().forEach(role -> {
List<Namespace> namespaceArrayList = new ArrayList<>();
List<Integer> idsList = new ArrayList<>();
Tenant tenant = tenantService.getBaseMapper().selectById(role.getTenantId());
roleNamespaceService.list(new QueryWrapper<RoleNamespace>().eq("role_id", role.getId())).forEach(roleNamespace -> {
Namespace namespaceServiceById = namespaceService.getById(roleNamespace.getNamespaceId());
namespaceArrayList.add(namespaceServiceById);
idsList.add(roleNamespace.getNamespaceId());
});
role.setTenant(tenant);
role.setNamespaces(namespaceArrayList);
String result = idsList.stream().map(Object::toString).collect(Collectors.joining(","));
role.setNamespaceIds(result);
});
return roleProTableResult;
}
}
\ No newline at end of file
......@@ -401,12 +401,17 @@ public class TaskServiceImpl extends SuperServiceImpl<TaskMapper, Task> implemen
}
@Override
public Task initDefaultFlinkSQLEnv() {
public Task initDefaultFlinkSQLEnv(Integer tenantId) {
String separator = SystemConfiguration.getInstances().getSqlSeparator();
separator = separator.replace("\\r", "\r").replace("\\n", "\n");
Task defaultFlinkSQLEnvTask = new Task();
defaultFlinkSQLEnvTask.setId(1);
defaultFlinkSQLEnvTask.setName("dlink_default_catalog");
String name = "dlink_default_catalog";
Task defaultFlinkSQLEnvTask = getTaskByNameAndTenantId(name, tenantId);
if (null == defaultFlinkSQLEnvTask) {
defaultFlinkSQLEnvTask = new Task();
}
// defaultFlinkSQLEnvTask.setId(1);
defaultFlinkSQLEnvTask.setName(name);
defaultFlinkSQLEnvTask.setAlias("DefaultCatalog");
defaultFlinkSQLEnvTask.setDialect(Dialect.FLINKSQLENV.getValue());
StringBuilder sb = new StringBuilder();
......@@ -427,15 +432,25 @@ public class TaskServiceImpl extends SuperServiceImpl<TaskMapper, Task> implemen
sb.append(separator);
defaultFlinkSQLEnvTask.setStatement(sb.toString());
defaultFlinkSQLEnvTask.setFragment(true);
defaultFlinkSQLEnvTask.setTenantId(tenantId);
defaultFlinkSQLEnvTask.setEnabled(true);
saveOrUpdate(defaultFlinkSQLEnvTask);
Statement statement = new Statement();
statement.setId(1);
statement.setId(defaultFlinkSQLEnvTask.getId());
statement.setTenantId(tenantId);
statement.setStatement(sb.toString());
statementService.saveOrUpdate(statement);
return defaultFlinkSQLEnvTask;
}
@Override
public Task getTaskByNameAndTenantId(String name, Integer tenantId) {
Task task = baseMapper.getTaskByNameAndTenantId(name, tenantId);
return task;
}
@Override
public String exportSql(Integer id) {
Task task = getTaskInfoById(id);
......@@ -474,7 +489,7 @@ public class TaskServiceImpl extends SuperServiceImpl<TaskMapper, Task> implemen
Task task = getTaskInfoById(id);
Assert.check(task);
if (JobLifeCycle.DEVELOP.equalsValue(task.getStep())) {
//KubernetesApplaction is not sql, skip sqlExplain verify
// KubernetesApplaction is not sql, skip sqlExplain verify
if (!Dialect.KUBERNETES_APPLICATION.equalsVal(task.getDialect())) {
List<SqlExplainResult> sqlExplainResults = explainTask(id);
for (SqlExplainResult sqlExplainResult : sqlExplainResults) {
......@@ -684,7 +699,7 @@ public class TaskServiceImpl extends SuperServiceImpl<TaskMapper, Task> implemen
if (GatewayType.KUBERNETES_APPLICATION.equalsValue(cluster.getType())) {
Statement statement = statementService.getById(cluster.getTaskId());
Map<String, Object> gatewayConfig = JSONUtil.toMap(statement.getStatement(),String.class,Object.class);
Map<String, Object> gatewayConfig = JSONUtil.toMap(statement.getStatement(), String.class, Object.class);
jobConfig.buildGatewayConfig(gatewayConfig);
jobConfig.getGatewayConfig().getClusterConfig().setAppId(cluster.getName());
useGateway = true;
......@@ -726,7 +741,7 @@ public class TaskServiceImpl extends SuperServiceImpl<TaskMapper, Task> implemen
private JobConfig buildJobConfig(Task task) {
boolean isJarTask = Dialect.FLINKJAR.equalsVal(task.getDialect())
|| Dialect.KUBERNETES_APPLICATION.equalsVal(task.getDialect());
|| Dialect.KUBERNETES_APPLICATION.equalsVal(task.getDialect());
if (!isJarTask && Asserts.isNotNull(task.getFragment()) ? task.getFragment() : false) {
String flinkWithSql = dataBaseService.getEnabledFlinkWithSql();
if (Asserts.isNotNullString(flinkWithSql)) {
......@@ -744,14 +759,14 @@ public class TaskServiceImpl extends SuperServiceImpl<TaskMapper, Task> implemen
if (!JobManager.useGateway(config.getType())) {
config.setAddress(clusterService.buildEnvironmentAddress(config.isUseRemote(), task.getClusterId()));
}
//support custom K8s app submit, rather than clusterConfiguration
// support custom K8s app submit, rather than clusterConfiguration
else if (Dialect.KUBERNETES_APPLICATION.equalsVal(task.getDialect())
&& GatewayType.KUBERNETES_APPLICATION.equalsValue(config.getType())) {
Map<String, Object> gatewayConfig = JSONUtil.toMap(task.getStatement(),String.class,Object.class);
&& GatewayType.KUBERNETES_APPLICATION.equalsValue(config.getType())) {
Map<String, Object> gatewayConfig = JSONUtil.toMap(task.getStatement(), String.class, Object.class);
config.buildGatewayConfig(gatewayConfig);
} else {
Map<String, Object> gatewayConfig = clusterConfigurationService.getGatewayConfig(task.getClusterConfigurationId());
//submit application type with clusterConfiguration
// submit application type with clusterConfiguration
if (GatewayType.YARN_APPLICATION.equalsValue(config.getType()) || GatewayType.KUBERNETES_APPLICATION.equalsValue(config.getType())) {
if (!isJarTask) {
SystemConfiguration systemConfiguration = SystemConfiguration.getInstances();
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service.impl;
import com.dlink.assertion.Asserts;
import com.dlink.common.result.Result;
import com.dlink.context.RequestContext;
import com.dlink.db.service.impl.SuperServiceImpl;
import com.dlink.mapper.TenantMapper;
import com.dlink.model.Namespace;
import com.dlink.model.Role;
import com.dlink.model.Tenant;
import com.dlink.model.UserTenant;
import com.dlink.service.NamespaceService;
import com.dlink.service.RoleService;
import com.dlink.service.TenantService;
import com.dlink.service.UserTenantService;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
@Service
public class TenantServiceImpl extends SuperServiceImpl<TenantMapper, Tenant> implements TenantService {
@Autowired
private RoleService roleService;
@Autowired
private NamespaceService namespaceService;
@Autowired
private UserTenantService userTenantService;
@Override
public Result saveOrUpdateTenant(Tenant tenant) {
Integer tenantId = tenant.getId();
if (Asserts.isNull(tenantId)) {
Tenant tenantByTenantCode = getTenantByTenantCode(tenant.getTenantCode());
if (Asserts.isNotNull(tenantByTenantCode)) {
return Result.failed("该租户已存在");
}
tenant.setIsDelete(false);
if (save(tenant)) {
RequestContext.set(tenant.getId());
return Result.succeed("新增成功");
}
return Result.failed("新增失败");
} else {
if (modifyTenant(tenant)) {
return Result.failed("修改成功");
}
return Result.failed("新增失败");
}
}
@Override
public Tenant getTenantByTenantCode(String tenantCode) {
return getOne(new QueryWrapper<Tenant>().eq("tenant_code", tenantCode).eq("is_delete", 0));
}
@Override
public boolean modifyTenant(Tenant tenant) {
if (Asserts.isNull(tenant.getId())) {
return false;
}
return updateById(tenant);
}
@Transactional(rollbackFor = Exception.class)
@Override
public Result<String> deleteTenantById(JsonNode para) {
for (JsonNode item : para) {
Integer id = item.asInt();
Tenant tenant = getById(id);
if (Asserts.isNull(tenant)) {
return Result.failed("租户不存在");
}
Long tenantRoleCount = roleService.getBaseMapper().selectCount(new QueryWrapper<Role>().eq("tenant_id", id));
if (tenantRoleCount > 0) {
return Result.failed("删除租户失败,该租户已绑定角色");
}
Long tenantNamespaceCount = namespaceService.getBaseMapper().selectCount(new QueryWrapper<Namespace>().eq("tenant_id", id));
if (tenantNamespaceCount > 0) {
return Result.failed("删除租户失败,该租户已绑定名称空间");
}
tenant.setIsDelete(true);
boolean result = updateById(tenant);
if (result) {
return Result.succeed("删除成功");
} else {
return Result.failed("删除失败");
}
}
return Result.failed("删除租户不存在");
}
@Override
public List<Tenant> getTenantByIds(Set<Integer> tenantIds) {
return baseMapper.getTenantByIds(tenantIds);
}
/**
* Assign users to specified tenants
*
* @param para
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Result distributeUsers(JsonNode para) {
if (para.size() > 0) {
List<UserTenant> tenantUserList = new ArrayList<>();
Integer tenantId = para.get("tenantId").asInt();
userTenantService.remove(new QueryWrapper<UserTenant>().eq("tenant_id", tenantId));
JsonNode tenantUserJsonNode = para.get("users");
for (JsonNode ids : tenantUserJsonNode) {
UserTenant userTenant = new UserTenant();
userTenant.setTenantId(tenantId);
userTenant.setUserId(ids.asInt());
tenantUserList.add(userTenant);
}
// save or update user role
boolean result = userTenantService.saveOrUpdateBatch(tenantUserList, 1000);
if (result) {
return Result.succeed("分配用户成功");
} else {
return Result.failed("分配用户失败");
}
} else {
return Result.failed("请选择要分配的用户");
}
}
@Override
public Result switchTenant(JsonNode para) {
if (para.size() > 0) {
Integer tenantId = para.get("tenantId").asInt();
RequestContext.remove();
RequestContext.set(tenantId);
return Result.succeed("切换租户成功");
} else {
return Result.failed("无法切换租户,获取不到租户信息");
}
}
}
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service.impl;
import com.dlink.db.service.impl.SuperServiceImpl;
import com.dlink.mapper.UserRoleMapper;
import com.dlink.model.UserRole;
import com.dlink.service.UserRoleService;
import java.util.List;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@Service
public class UserRoleServiceImpl extends SuperServiceImpl<UserRoleMapper, UserRole> implements UserRoleService {
@Override
public int delete(int userId) {
LambdaQueryWrapper<UserRole> wrapper = Wrappers.lambdaQuery();
wrapper.eq(UserRole::getUserId, userId);
return baseMapper.delete(wrapper);
}
@Override
public List<UserRole> getUserRoleByUserId(int userId) {
return baseMapper.getUserRoleByUserId(userId);
}
@Override
public int deleteBathRelation(List<UserRole> userRoleList) {
return baseMapper.deleteBathRelation(userRoleList);
}
@Override
public boolean deleteByRoleIds(List<Integer> roleIds) {
return baseMapper.deleteByRoleIds(roleIds) > 0;
}
}
\ No newline at end of file
......@@ -21,14 +21,34 @@ package com.dlink.service.impl;
import com.dlink.assertion.Asserts;
import com.dlink.common.result.Result;
import com.dlink.context.RequestContext;
import com.dlink.db.service.impl.SuperServiceImpl;
import com.dlink.dto.LoginUTO;
import com.dlink.dto.UserDTO;
import com.dlink.mapper.UserMapper;
import com.dlink.model.Role;
import com.dlink.model.Tenant;
import com.dlink.model.User;
import com.dlink.model.UserRole;
import com.dlink.model.UserTenant;
import com.dlink.service.RoleService;
import com.dlink.service.TenantService;
import com.dlink.service.UserRoleService;
import com.dlink.service.UserService;
import com.dlink.service.UserTenantService;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
......@@ -44,6 +64,18 @@ public class UserServiceImpl extends SuperServiceImpl<UserMapper, User> implemen
private static final String DEFAULT_PASSWORD = "123456";
@Autowired
private UserRoleService userRoleService;
@Autowired
private UserTenantService userTenantService;
@Autowired
private RoleService roleService;
@Autowired
private TenantService tenantService;
@Override
public Result registerUser(User user) {
User userByUsername = getUserByUsername(user.getUsername());
......@@ -96,30 +128,68 @@ public class UserServiceImpl extends SuperServiceImpl<UserMapper, User> implemen
}
@Override
public Result loginUser(String username, String password, boolean isRemember) {
User user = getUserByUsername(username);
public Result loginUser(LoginUTO loginUTO) {
User user = getUserByUsername(loginUTO.getUsername());
if (Asserts.isNull(user)) {
return Result.failed("账号或密码错误");
}
String userPassword = user.getPassword();
if (Asserts.isNullString(password)) {
if (Asserts.isNullString(loginUTO.getPassword())) {
return Result.failed("密码不能为空");
}
if (Asserts.isEquals(SaSecureUtil.md5(password), userPassword)) {
if (Asserts.isEquals(SaSecureUtil.md5(loginUTO.getPassword()), userPassword)) {
if (user.getIsDelete()) {
return Result.failed("账号不存在");
}
if (!user.getEnabled()) {
return Result.failed("账号已被禁用");
}
StpUtil.login(user.getId(), isRemember);
StpUtil.getSession().set("user", user);
return Result.succeed(user, "登录成功");
// 将前端入参 租户id 放入上下文
RequestContext.set(loginUTO.getTenantId());
// get user tenants and roles
UserDTO userDTO = getUserALLBaseInfo(loginUTO, user);
StpUtil.login(user.getId(), loginUTO.isAutoLogin());
StpUtil.getSession().set("user", userDTO);
return Result.succeed(userDTO, "登录成功");
} else {
return Result.failed("账号或密码错误");
}
}
private UserDTO getUserALLBaseInfo(LoginUTO loginUTO, User user) {
UserDTO userDTO = new UserDTO();
List<Role> roleList = new LinkedList<>();
List<Tenant> tenantList = new LinkedList<>();
List<UserRole> userRoles = userRoleService.getUserRoleByUserId(user.getId());
List<UserTenant> userTenants = userTenantService.getUserTenantByUserId(user.getId());
Tenant currentTenant = tenantService.getBaseMapper().selectById(loginUTO.getTenantId());
userRoles.forEach(userRole -> {
Role role = roleService.getBaseMapper().selectById(userRole.getRoleId());
if (Asserts.isNotNull(role)) {
roleList.add(role);
}
});
userTenants.forEach(userTenant -> {
Tenant tenant = tenantService.getBaseMapper().selectOne(new QueryWrapper<Tenant>().eq("id", userTenant.getTenantId()));
if (Asserts.isNotNull(tenant)) {
tenantList.add(tenant);
}
});
userDTO.setUser(user);
userDTO.setRoleList(roleList);
userDTO.setTenantList(tenantList);
userDTO.setCurrentTenant(currentTenant);
return userDTO;
}
@Override
public User getUserByUsername(String username) {
User user = getOne(new QueryWrapper<User>().eq("username", username));
......@@ -128,4 +198,49 @@ public class UserServiceImpl extends SuperServiceImpl<UserMapper, User> implemen
}
return user;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Result grantRole(JsonNode para) {
if (para.size() > 0) {
List<UserRole> userRoleList = new ArrayList<>();
Integer userId = para.get("userId").asInt();
userRoleService.remove(new QueryWrapper<UserRole>().eq("user_id", userId));
JsonNode userRoleJsonNode = para.get("roles");
for (JsonNode ids : userRoleJsonNode) {
UserRole userRole = new UserRole();
userRole.setUserId(userId);
userRole.setRoleId(ids.asInt());
userRoleList.add(userRole);
}
// save or update user role
boolean result = userRoleService.saveOrUpdateBatch(userRoleList, 1000);
if (result) {
return Result.succeed("用户授权角色成功");
} else {
return Result.failed("用户授权角色失败");
}
} else {
return Result.failed("请选择要授权的角色");
}
}
@Override
public Result getTenants(String username) {
User user = getUserByUsername(username);
if (Asserts.isNull(user)) {
return Result.failed("该账号不存在,获取租户失败");
}
List<UserTenant> userTenants = userTenantService.getUserTenantByUserId(user.getId());
if (userTenants.size() == 0) {
return Result.failed("用户未绑定租户,获取租户失败");
}
Set<Integer> tenantIds = new HashSet<>();
userTenants.forEach(userTenant -> tenantIds.add(userTenant.getTenantId()));
List<Tenant> tenants = tenantService.getTenantByIds(tenantIds);
return Result.succeed(tenants, "获取成功");
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.dlink.service.impl;
import com.dlink.db.service.impl.SuperServiceImpl;
import com.dlink.mapper.UserTenantMapper;
import com.dlink.model.UserTenant;
import com.dlink.service.UserTenantService;
import java.util.List;
import org.springframework.stereotype.Service;
@Service
public class UserTenantServiceImpl extends SuperServiceImpl<UserTenantMapper, UserTenant> implements UserTenantService {
@Override
public List<UserTenant> getUserTenantByUserId(int userId) {
return baseMapper.getUserTenantByUserId(userId);
}
}
:: Spring Boot :: ${spring-boot.formatted-version}
______ _ __
|_ _ `. (_) [ | _
| | `. \ __ _ .--. | | / ] _ __
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dlink.mapper.NamespaceMapper">
<sql id="baseSql">
id,tenant_id,namespace_code,enabled,note,create_time,update_time
</sql>
<select id="selectForProTable" resultType="com.dlink.model.Namespace">
select
<include refid="baseSql"/>
from
dlink_namespace a
<where>
1=1
<if test='param.tenantId!=null and param.tenantId!=""'>
and tenant_id = #{param.tenantId}
</if>
<if test='param.namespaceCode!=null and param.namespaceCode!=""'>
and namespace_code like "%${param.namespaceCode}%"
</if>
<if test='param.createTime!=null and param.createTime!=""'>
and create_time <![CDATA[>=]]> str_to_date( #{param.createTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='param.updateTime!=null and param.updateTime!=""'>
and update_time <![CDATA[>=]]> str_to_date( #{param.updateTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!="" and !ew.sqlSegment.startsWith(" ORDER BY")'>
and
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!=""'>
${ew.sqlSegment}
</if>
</where>
</select>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dlink.mapper.RoleMapper">
<resultMap id="roleResultMap" type="com.dlink.model.Role">
<id property="id" column="id"/>
<result property="tenantId" column="tenant_id"/>
<result property="roleCode" column="role_code"/>
<result property="roleName" column="role_name"/>
<result property="isDelete" column="is_delete"/>
<result property="note" column="note"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<collection property="namespaces" ofType="com.dlink.model.Namespace"
resultMap="namespaceResultMap"></collection>
</resultMap>
<resultMap id="namespaceResultMap" type="com.dlink.model.Namespace">
<id property="id" column="id"/>
<result property="tenantId" column="tenant_id"/>
<result property="namespaceCode" column="namespace_code"/>
<result property="enabled" column="enabled"/>
<result property="note" column="note"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<sql id="role">
select dr.id
, dr.tenant_id
, dr.role_code
, dr.role_name
, dr.note
, dr.create_time
, dr.update_time
, dn.id as dn_id
, dn.namespace_code
, dn.enabled
, dn.note dn_note
, dn.create_time as dn_create_time
, dn.update_time dn_update_time
from dlink_role dr
join dlink_role_namespace drn
on dr.id = drn.role_id
join dlink_namespace dn
on drn.namespace_id = dn.id
</sql>
<select id="selectForProTable" resultType="com.dlink.model.Role">
select
a.*
from dlink_role a
<where>
1=1
<if test='param.tenantId!=null and param.tenantId!=""'>
and tenant_id = '${param.tenantId}'
</if>
<if test='param.roleCode!=null and param.roleCode!=""'>
and role_code = '${param.roleCode}'
</if>
<if test='param.roleName!=null and param.roleName!=""'>
and role_name like "%${param.roleName}%"
</if>
<if test='param.createTime!=null and param.createTime!=""'>
and create_time <![CDATA[>=]]> str_to_date( #{param.createTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='param.updateTime!=null and param.updateTime!=""'>
and update_time <![CDATA[>=]]> str_to_date( #{param.updateTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!="" and !ew.sqlSegment.startsWith(" ORDER BY")'>
and
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!=""'>
${ew.sqlSegment}
</if>
</where>
</select>
<select id="getRoleByIds" resultType="com.dlink.model.Role">
select id
,tenant_id
,role_code
,role_name
,is_delete
,note
,create_time
,update_time
from dlink_role
where id in
<foreach collection="roleIds" item="id" separator="," open="(" close=")" index="">
#{id}
</foreach>
</select>
<select id="getRoleByTenantIdAndIds" resultType="com.dlink.model.Role">
select id
,tenant_id
,role_code
,role_name
,is_delete
,note
,create_time
,update_time
from dlink_role
<where>
1=1
<if test='tenantId!=null and tenantId!=""'>
and tenant_id = '${tenantId}'
</if>
and id in
<foreach collection="roleIds" item="id" separator="," open="(" close=")" index="">
#{id}
</foreach>
</where>
</select>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dlink.mapper.RoleNamespaceMapper">
<sql id="baseSql">
id,role_id,namespace_id
</sql>
<select id="selectForProTable" resultType="com.dlink.model.RoleNamespace">
select
<include refid="baseSql"/>
from
dlink_role_namespace
<where>
1=1
<if test='param.roleId!=null and param.roleId!=""'>
and role_id = #{param.roleId}
</if>
<if test='param.namespaceId!=null and param.namespaceId!=""'>
and namespace_id = #{param.namespaceId}
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!="" and !ew.sqlSegment.startsWith(" ORDER BY")'>
and
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!=""'>
${ew.sqlSegment}
</if>
</where>
</select>
<delete id="deleteByRoleIds" parameterType="java.util.List">
DELETE FROM dlink_role_namespace
WHERE role_id IN
<foreach collection="roleIds" item="item" open="(" separator="," close=")">
${item}
</foreach>
</delete>
</mapper>
\ No newline at end of file
......@@ -11,10 +11,6 @@
id,statement
</sql>
<insert id="insert">
insert into dlink_task_statement (id,statement) values (#{id},#{statement})
</insert>
<select id="selectForProTable" resultType="com.dlink.model.Task">
select
a.*
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
~
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You under the Apache License, Version 2.0
~ (the "License"); you may not use this file except in compliance with
~ the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dlink.mapper.TaskMapper">
<select id="selectForProTable" resultType="com.dlink.model.Task">
select
a.*
......@@ -37,23 +55,42 @@
where `name` REGEXP '${name}_[0-9]$'
</select>
<select id="getTaskByNameAndTenantId" resultType="com.dlink.model.Task">
select *
from dlink_task
where 1 = 1
and name = "${name}"
and tenant_id = ${tenantId}
</select>
<select id="queryOnLineTaskByDoneStatus" resultType="com.dlink.model.Task">
select t.id as id, t.name as name
from dlink_task t
left join dlink_catalogue c on c.task_id = t.id
left join dlink_job_instance i on i.id = t.job_instance_id
where
c.parent_id in <foreach collection="parentIds" item="parentId" open="(" close=")" separator=","> #{parentId} </foreach>
and c.task_id is not null
and c.is_leaf = 1
and t.step in <foreach collection="stepIds" item="stepId" open="(" close=")" separator=","> #{stepId} </foreach>
and t.enabled = 1
c.parent_id in
<foreach collection="parentIds" item="parentId" open="(" close=")" separator=",">
#{parentId}
</foreach>
and c.task_id is not null
and c.is_leaf = 1
and t.step in
<foreach collection="stepIds" item="stepId" open="(" close=")" separator=",">
#{stepId}
</foreach>
and t.enabled = 1
<if test="includeNull == true">
and ((i.status is null) or (i.status in <foreach collection="jobStatuses" item="jobStatus" open="(" close=")" separator=","> #{jobStatus} </foreach>))
and ((i.status is null) or (i.status in <foreach collection="jobStatuses" item="jobStatus" open="("
close=")" separator=",">
#{jobStatus}
</foreach>))
</if>
<if test="includeNull != true">
and i.status in <foreach collection="jobStatuses" item="jobStatus" open="(" close=")" separator=","> #{jobStatus} </foreach>
and i.status in
<foreach collection="jobStatuses" item="jobStatus" open="(" close=")" separator=",">
#{jobStatus}
</foreach>
</if>
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dlink.mapper.TenantMapper">
<sql id="baseSql">
id,tenant_code,is_delete,note,create_time,update_time
</sql>
<select id="selectForProTable" resultType="com.dlink.model.Tenant">
select
<include refid="baseSql"/>
from
dlink_tenant a
<where>
1=1
<if test='param.tenantCode!=null and param.tenantCode!=""'>
and tenant_code like "%${param.tenantCode}%"
</if>
<if test='param.createTime!=null and param.createTime!=""'>
and create_time <![CDATA[>=]]> str_to_date( #{param.createTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='param.updateTime!=null and param.updateTime!=""'>
and update_time <![CDATA[>=]]> str_to_date( #{param.updateTime},'%Y-%m-%d %H:%i:%s')
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!="" and !ew.sqlSegment.startsWith(" ORDER BY")'>
and
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!=""'>
${ew.sqlSegment}
</if>
</where>
</select>
<select id="getTenantByIds" resultType="com.dlink.model.Tenant">
select id
,tenant_code
,is_delete
,note
,create_time
,update_time
from dlink_tenant a
where 1=1
and id in
<foreach collection="tenantIds" item="id" separator="," open="(" close=")" index="">
#{id}
</foreach>
</select>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dlink.mapper.UserRoleMapper">
<sql id="baseSql">
id,user_id,role_id
</sql>
<select id="selectForProTable" resultType="com.dlink.model.UserRole">
select
<include refid="baseSql"/>
from
dlink_user_role
<where>
1=1
<if test='param.userId!=null and param.userId!=""'>
and user_id = #{param.userId}
</if>
<if test='param.roleId!=null and param.roleId!=""'>
and role_id = #{param.roleId}
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!="" and !ew.sqlSegment.startsWith(" ORDER BY")'>
and
</if>
<if test='ew.sqlSegment!=null and ew.sqlSegment!=""'>
${ew.sqlSegment}
</if>
</where>
</select>
<select id="getUserRoleByUserId" resultType="com.dlink.model.UserRole">
select
<include refid="baseSql"/>
from
dlink_user_role
where user_id = (#{userId})
</select>
<delete id="deleteBathRelation" parameterType="java.util.List">
delete from dlink_user_role
where (user_id,role_id) in
<foreach item="item" index="index" collection="userRoleList" open="(" separator="," close=")">
(#{item.userId},#{item.roleId})
</foreach>
</delete>
<delete id="deleteByRoleIds" parameterType="java.util.List">
DELETE FROM dlink_user_role
WHERE role_id IN
<foreach collection="roleIds" item="item" open="(" separator="," close=")">
${item}
</foreach>
</delete>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dlink.mapper.UserTenantMapper">
<sql id="baseSql">
id
,user_id,tenant_id
</sql>
<select id="getUserTenantByUserId" resultType="com.dlink.model.UserTenant">
select
<include refid="baseSql"/>
from
dlink_user_tenant
where user_id = (#{userId})
</select>
</mapper>
\ No newline at end of file
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
Navicat Premium Data Transfer
......@@ -655,6 +673,277 @@ CREATE TABLE `dlink_upload_file_record` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='上传文件记录';
-- ----------------------------
-- Table structure for metadata_database
-- ----------------------------
drop table if exists `metadata_database`;
create table if not exists `metadata_database` (
`id` int(11) not null AUTO_INCREMENT COMMENT '主键',
`database_name` varchar(255) NOT NULL COMMENT '名称',
`description` varchar(255) null comment'描述',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='元数据对象信息';
-- ----------------------------
-- Table structure for metadata_table
-- ----------------------------
drop table if exists `metadata_table`;
create table if not exists `metadata_table` (
`id` int(11) not null AUTO_INCREMENT COMMENT '主键',
`table_name` varchar(255) NOT NULL COMMENT '名称',
`table_type` varchar(255) NOT null comment '对象类型,分为:database 和 table view',
`database_id` int(11) not null COMMENT '数据库主键',
`description` varchar(255) null comment'描述',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='元数据对象信息';
-- ----------------------------
-- Table structure for metadata_database_property
-- ----------------------------
drop table if exists `metadata_database_property`;
create table if not exists `metadata_database_property` (
`key` varchar(255) NOT NULL COMMENT '属性key',
`value` varchar(255) NULL COMMENT '属性value',
`database_id` int(11) not null COMMENT '数据库主键',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`key`, `database_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='元数据属性信息';
-- ----------------------------
-- Table structure for metadata_table_property
-- ----------------------------
drop table if exists `metadata_table_property`;
create table if not exists `metadata_table_property` (
`key` varchar(255) NOT NULL COMMENT '属性key',
`value` varchar(255) NULL COMMENT '属性value',
`table_id` int(11) not null COMMENT '数据表名称',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`key`, `table_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='元数据属性信息';
-- ----------------------------
-- Table structure for metadata_column
-- ----------------------------
drop table if exists metadata_column;
create table if not exists `metadata_column` (
`column_name` varchar(255) NOT NULL COMMENT '列名',
`column_type` varchar(255) NOT NULL COMMENT '列类型, 有Physical Metadata Computed WATERMARK ',
`data_type` varchar(255) NOT NULL COMMENT '数据类型',
`expr` varchar(255) NULL COMMENT '表达式',
`description` varchar(255) NOT NULL COMMENT '字段描述',
`table_id` int(11) not null COMMENT '数据表名称',
`primary` bit null comment '主键',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`table_id`,`column_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据列信息';
-- ----------------------------
-- Table structure for metadata_function
-- ----------------------------
drop table if exists `metadata_function`;
create table if not exists `metadata_function` (
`id` int(11) not null AUTO_INCREMENT COMMENT '主键',
`function_name` varchar(255) NOT NULL COMMENT '名称',
`class_name` varchar(255) NOT null comment '类名',
`database_id` int(11) not null COMMENT '数据库主键',
`function_language` varchar(255) null comment'UDF语言',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='UDF信息';
-- ----------------------------
-- Table structure for dlink_tenant
-- ----------------------------
drop table if exists `dlink_tenant`;
CREATE TABLE IF NOT EXISTS dlink_tenant
(
id int auto_increment comment 'ID',
tenant_code varchar(64) not null comment '租户编码',
is_delete tinyint(1) default 0 not null comment '是否被删除',
note varchar(255) null comment '注释',
create_time datetime null comment '创建时间',
update_time datetime null comment '最近修改时间',
PRIMARY KEY (id) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT '租户' ;
-- ----------------------------
-- Records of dlink_tenant
-- ----------------------------
INSERT INTO `dlink_tenant`(`id`, `tenant_code`, `is_delete`, `note`, `create_time`, `update_time`) VALUES (1, 'DefaultTenant', 0, 'DefaultTenant', current_time, current_time);
-- ----------------------------
-- Table structure for dlink_role
-- ----------------------------
drop table if exists `dlink_role`;
CREATE TABLE IF NOT EXISTS dlink_role
(
id int auto_increment comment 'ID',
tenant_id int not null comment '租户ID',
role_code varchar(64) not null comment '角色编码',
role_name varchar(64) not null comment '角色名称',
is_delete tinyint(1) default 0 not null comment '是否被删除',
note varchar(255) null comment '注释',
create_time datetime null comment '创建时间',
update_time datetime null comment '更新时间',
PRIMARY KEY (id) USING BTREE,
UNIQUE KEY `dlink_role_un` (`role_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC comment '角色' ;
-- ----------------------------
-- Records of dlink_role
-- ----------------------------
INSERT INTO `dlink_role`(`id`, `tenant_id`, `role_code`, `role_name`, `is_delete`, `note`, `create_time`, `update_time`) VALUES (1, 1, 'SuperAdmin', '超级管理员', 0, '超级管理员角色', current_time, current_time);
-- ----------------------------
-- Table structure for dlink_namespace
-- ----------------------------
drop table if exists `dlink_namespace`;
CREATE TABLE IF NOT EXISTS dlink_namespace
(
id int auto_increment comment 'ID',
tenant_id int not null comment '租户ID',
namespace_code varchar(64) not null comment '命名空间编码',
enabled tinyint(1) default 1 not null comment '是否启用',
note varchar(255) null comment '注释',
create_time datetime null comment '创建时间',
update_time datetime null comment '更新时间',
PRIMARY KEY (id) USING BTREE,
UNIQUE KEY `dlink_namespace_un` (`namespace_code`,`tenant_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC comment '命名空间';
-- ----------------------------
-- Records of dlink_namespace
-- ----------------------------
INSERT INTO `dlink_namespace`(`id`, `tenant_id`, `namespace_code`, `enabled`, `note`, `create_time`, `update_time`) VALUES (1, 1, 'DefaultNameSpace', 1, '默认命名空间', current_time, current_time);
-- ----------------------------
-- Table structure for dlink_role_namespace
-- ----------------------------
drop table if exists `dlink_role_namespace`;
CREATE TABLE IF NOT EXISTS dlink_role_namespace
(
id int auto_increment comment 'ID',
role_id int not null comment '用户ID',
namespace_id int not null comment '名称空间ID',
create_time datetime null comment '创建时间',
update_time datetime null comment '更新时间',
PRIMARY KEY (id) USING BTREE,
UNIQUE KEY `dlink_role_namespace_un` (role_id, namespace_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC comment '角色与名称空间关系';
-- ----------------------------
-- Records of dlink_role_namespace
-- ----------------------------
INSERT INTO `dlink_role_namespace`(`id`, `role_id`, `namespace_id`, `create_time`, `update_time`) VALUES (1, 1, 1, current_time, current_time);
-- ----------------------------
-- Table structure for dlink_user_role
-- ----------------------------
drop table if exists `dlink_user_role`;
CREATE TABLE IF NOT EXISTS dlink_user_role
(
id int auto_increment comment 'ID',
user_id int not null comment '用户ID',
role_id int not null comment '角色ID',
create_time datetime null comment '创建时间',
update_time datetime null comment '更新时间',
PRIMARY KEY (id) USING BTREE,
UNIQUE KEY `dlink_user_role_un` (user_id, role_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC comment '用户与角色关系';
-- ----------------------------
-- Records of dlink_user_role
-- ----------------------------
INSERT INTO `dlink_user_role`(`id`, `user_id`, `role_id`, `create_time`, `update_time`) VALUES (1, 1, 1, current_time, current_time);
-- ----------------------------
-- Table structure for dlink_user_tenant
-- ----------------------------
drop table if exists `dlink_user_tenant`;
CREATE TABLE `dlink_user_tenant` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` int NOT NULL COMMENT '用户ID',
`tenant_id` int NOT NULL COMMENT '租户ID',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `dlink_user_role_un` (`user_id`,`tenant_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='用户与租户关系';
-- ----------------------------
-- Records of dlink_user_tenant
-- ----------------------------
INSERT INTO `dlink_user_tenant`(`id`, `user_id`, `tenant_id`, `create_time`, `update_time`) VALUES (1, 1, 1, current_time, current_time);
alter table dlink_catalogue add column tenant_id int not null comment '租户ID' after id;
alter table dlink_catalogue drop index `idx_name`;
alter table dlink_catalogue add unique key `dlink_catalogue_un` (`name`, `parent_id`,`tenant_id`);
alter table dlink_cluster add column tenant_id int not null comment '租户ID' after id;
alter table dlink_cluster drop index `idx_name`;
alter table dlink_cluster add unique key `dlink_cluster_un` (`name`, `tenant_id`);
alter table dlink_task add column tenant_id int not null comment '租户ID' after name;
alter table dlink_task drop index `idx_name`;
alter table dlink_task add unique key `dlink_task_un` (`name`, `tenant_id`);
alter table dlink_task_statement add column tenant_id int not null comment '租户ID' after id;
alter table dlink_task_statement add unique key `dlink_task_statement_un` (`tenant_id`,`id`);
alter table dlink_database add column tenant_id int not null comment '租户ID' after id;
alter table dlink_database drop index `db_index`;
alter table dlink_database add unique key `dlink_database_un` (`name`,`tenant_id`);
alter table dlink_cluster_configuration add column tenant_id int not null comment '租户ID' after id;
alter table dlink_cluster_configuration add unique key `dlink_cluster_configuration_un` (`name`,`tenant_id`);
alter table dlink_jar add column tenant_id int not null comment '租户ID' after id;
alter table dlink_jar add unique key `dlink_jar_un` (`tenant_id`,`name`);
alter table dlink_savepoints add column tenant_id int not null comment '租户ID' after task_id;
alter table dlink_job_instance add column tenant_id int not null comment '租户ID' after name;
alter table dlink_job_instance add unique key `dlink_job_instance_un` (`tenant_id`,`name`,`task_id`,`history_id`);
alter table dlink_alert_instance add column tenant_id int not null comment '租户ID' after name;
alter table dlink_alert_instance add unique key `dlink_alert_instance_un` (`name`,`tenant_id`);
alter table dlink_alert_group add column tenant_id int not null comment '租户ID' after name;
alter table dlink_alert_group add unique key `dlink_alert_instance_un` (`name`,`tenant_id`);
alter table dlink_alert_history add column tenant_id int not null comment '租户ID' after id;
alter table dlink_task_version add column tenant_id int not null comment '租户ID' after task_id;
alter table dlink_task_version add unique key `dlink_task_version_un` (`task_id`,`tenant_id`,`version_id`);
alter table dlink_history add column tenant_id int not null comment '租户ID' after id;
alter table dlink_job_history add column tenant_id int not null comment '租户ID' after id;
-- 修改历史表的租户编号为默认租户
UPDATE `dlink_alert_group` SET `tenant_id` = 1 ;
UPDATE `dlink_alert_history` SET `tenant_id` = 1;
UPDATE `dlink_alert_instance` SET `tenant_id` = 1;
UPDATE `dlink_catalogue` SET `tenant_id` = 1;
UPDATE `dlink_cluster` SET `tenant_id` = 1;
UPDATE `dlink_cluster_configuration` SET `tenant_id` = 1 ;
UPDATE `dlink_database` SET `tenant_id` = 1 ;
UPDATE `dlink_history` SET `tenant_id` = 1;
UPDATE `dlink_jar` SET `tenant_id` = 1 ;
UPDATE `dlink_job_instance` SET `tenant_id` = 1 ;
UPDATE `dlink_savepoints` SET `tenant_id` = 1;
UPDATE `dlink_task` SET `tenant_id` = 1 ;
UPDATE `dlink_task_statement` SET `tenant_id` = 1;
UPDATE `dlink_task_version` SET `tenant_id` = 1;
UPDATE `dlink_job_history` SET `tenant_id` = 1;
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
Navicat Premium Data Transfer
......@@ -20,7 +39,6 @@ SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for dlink_catalogue
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_catalogue`;
CREATE TABLE if not exists `dlink_catalogue` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`task_id` int(11) NULL DEFAULT NULL COMMENT '任务ID',
......@@ -38,7 +56,6 @@ CREATE TABLE if not exists `dlink_catalogue` (
-- ----------------------------
-- Table structure for dlink_cluster
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_cluster`;
CREATE TABLE if not exists `dlink_cluster` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '名称',
......@@ -58,7 +75,6 @@ CREATE TABLE if not exists `dlink_cluster` (
-- ----------------------------
-- Table structure for dlink_task
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_task`;
CREATE TABLE if not exists `dlink_task` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '名称',
......@@ -80,7 +96,6 @@ CREATE TABLE if not exists `dlink_task` (
-- ----------------------------
-- Table structure for dlink_task_statement
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_task_statement`;
CREATE TABLE if not exists `dlink_task_statement` (
`id` int(11) NOT NULL COMMENT 'ID',
`statement` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '语句',
......@@ -90,7 +105,6 @@ CREATE TABLE if not exists `dlink_task_statement` (
-- ----------------------------
-- Table structure for dlink_flink_document
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_flink_document`;
CREATE TABLE if not exists `dlink_flink_document` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`category` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文档类型',
......@@ -337,7 +351,6 @@ INSERT INTO `dlink_flink_document` VALUES (217, 'Function', 'UDF', '表值聚合
-- ----------------------------
-- Table structure for dlink_history
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_history`;
CREATE TABLE if not exists `dlink_history` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`cluster_id` int(11) NOT NULL DEFAULT 0 COMMENT '集群ID',
......@@ -365,7 +378,6 @@ ALTER TABLE `dlink_task`
-- ----------------------------
-- Table structure for dlink_database
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_database`;
CREATE TABLE if not exists `dlink_database` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '数据源名',
......@@ -469,13 +481,13 @@ ALTER TABLE `dlink_task`
ADD COLUMN `save_point_strategy` int(1) NULL COMMENT 'SavePoint策略' AFTER `check_point`;
-- ----------------------------
-- 0.4.0-SNAPSHOT 2021-11-24
-- 0.4.0 2021-11-24
-- ----------------------------
ALTER TABLE `dlink_task`
ADD COLUMN `jar_id` int(11) NULL COMMENT 'JarID' AFTER `cluster_configuration_id`;
-- ----------------------------
-- 0.4.0-SNAPSHOT 2021-11-28
-- 0.4.0 2021-11-28
-- ----------------------------
CREATE TABLE if not exists `dlink_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
......@@ -500,7 +512,7 @@ ALTER TABLE `dlink_task`
CHANGE COLUMN `config` `config_json` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '配置JSON' AFTER `jar_id`;
-- ----------------------------
-- 0.5.0-SNAPSHOT 2021-12-13
-- 0.5.0 2021-12-13
-- ----------------------------
ALTER TABLE `dlink_task`
ADD COLUMN `dialect` varchar(50) NULL COMMENT '方言' AFTER `alias`;
......@@ -508,24 +520,23 @@ ALTER TABLE `dlink_task`
ADD COLUMN `database_id` int(11) NULL COMMENT '数据源ID' AFTER `cluster_configuration_id`;
-- ----------------------------
-- 0.5.0-SNAPSHOT 2021-12-29
-- 0.5.0 2021-12-29
-- ----------------------------
ALTER TABLE `dlink_task`
ADD COLUMN `env_id` int(11) NULL COMMENT '环境ID' AFTER `jar_id`;
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-01-28
-- 0.6.0 2022-01-28
-- ----------------------------
ALTER TABLE `dlink_database`
ADD COLUMN `flink_config` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT 'Flink配置' AFTER `note`;
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-02-02
-- 0.6.0 2022-02-02
-- ----------------------------
-- ----------------------------
-- Table structure for dlink_job_instance
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_job_instance`;
CREATE TABLE if not exists `dlink_job_instance` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '作业实例名',
......@@ -547,31 +558,30 @@ ALTER TABLE `dlink_task`
ADD COLUMN `step` int(11) NULL COMMENT '作业生命周期' AFTER `note`;
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-02-03
-- 0.6.0 2022-02-03
-- ----------------------------
update dlink_task set dialect = 'FlinkJar' where jar_id is not null;
update dlink_catalogue set type = 'FlinkJar' where task_id in (select id as task_id from dlink_task where jar_id is not null);
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-02-07
-- 0.6.0 2022-02-07
-- ----------------------------
ALTER TABLE `dlink_task`
ADD COLUMN `batch_model` tinyint(1) NULL DEFAULT 0 COMMENT '使用批模式' AFTER `statement_set`;
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-02-18
-- 0.6.0 2022-02-18
-- ----------------------------
ALTER TABLE `dlink_database`
ADD COLUMN `flink_template` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT 'Flink模板' AFTER `flink_config`;
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-02-22
-- 0.6.0 2022-02-22
-- ----------------------------
ALTER TABLE `dlink_job_instance` MODIFY COLUMN status varchar(50) NULL COMMENT '实例状态';
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-02-24
-- 0.6.0 2022-02-24
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_alert_instance`;
CREATE TABLE if not exists `dlink_alert_instance` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称',
......@@ -584,7 +594,6 @@ CREATE TABLE if not exists `dlink_alert_instance` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='Alert实例';
-- DROP TABLE IF EXISTS `dlink_alert_group`;
CREATE TABLE if not exists `dlink_alert_group` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称',
......@@ -597,7 +606,6 @@ CREATE TABLE if not exists `dlink_alert_group` (
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='Alert组';
-- DROP TABLE IF EXISTS `dlink_alert_history`;
CREATE TABLE if not exists `dlink_alert_history` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`alert_group_id` int DEFAULT NULL COMMENT 'Alert组ID',
......@@ -612,17 +620,17 @@ CREATE TABLE if not exists `dlink_alert_history` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='Alert历史';
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-02-25
-- 0.6.0 2022-02-25
-- ----------------------------
ALTER TABLE `dlink_job_instance` MODIFY COLUMN name varchar(255) NULL COMMENT '作业实例名';
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-02-28
-- 0.6.0 2022-02-28
-- ----------------------------
ALTER TABLE `dlink_job_instance`
ADD COLUMN `duration` BIGINT NULL COMMENT '耗时' AFTER `finish_time`;
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-03-01
-- 0.6.0 2022-03-01
-- ----------------------------
-- DROP TABLE IF EXISTS `dlink_job_history`;
CREATE TABLE if not exists `dlink_job_history` (
......@@ -641,7 +649,7 @@ CREATE TABLE if not exists `dlink_job_history` (
-- ----------------------------
-- 0.6.0-SNAPSHOT 2021-03-02
-- 0.6.0 2021-03-02
-- ----------------------------
ALTER TABLE `dlink_history`
CHANGE COLUMN `config` `config_json` json NULL COMMENT '配置JSON' AFTER `result`;
......@@ -653,7 +661,7 @@ ALTER TABLE `dlink_task`
ALTER TABLE `dlink_task`
ADD COLUMN `alert_group_id` BIGINT NULL COMMENT '报警组ID' AFTER `env_id`;
-- ----------------------------
-- 0.6.0-SNAPSHOT 2022-03-13
-- 0.6.0 2022-03-13
-- ----------------------------
ALTER TABLE `dlink_job_instance`
ADD COLUMN `step` INT NULL COMMENT '生命周期' AFTER `task_id`;
......@@ -663,7 +671,7 @@ ALTER TABLE `dlink_job_instance`
CREATE INDEX dlink_job_instance_task_id_IDX USING BTREE ON dlink_job_instance (task_id);
SET FOREIGN_KEY_CHECKS = 1;
-- 0.6.2-SNAPSHOT 2022-04-17
-- 0.6.2 2022-04-17
-- ----------------------------
alter table dlink_task alter column fragment set default 0;
alter table dlink_task alter column statement_set set default 0;
......@@ -671,7 +679,7 @@ alter table dlink_cluster_configuration modify column is_available tinyint(1) N
-- 0.6.5-SNAPSHOT 2022-06-28
-- 0.6.5 2022-06-28
-- ----------------------------
alter table dlink_task
ADD COLUMN `version_id` INT NULL COMMENT '版本号ID' ;
......@@ -692,9 +700,8 @@ CREATE TABLE `dlink_task_version` (
-- 0.6.7-SNAPSHOT 2022-08-02
-- 0.6.7 2022-08-02
-- -----------------------
-- DROP TABLE IF EXISTS `dlink_fragment`;
CREATE TABLE `dlink_fragment` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '实例主键',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '唯一名称',
......@@ -709,9 +716,8 @@ CREATE TABLE `dlink_fragment` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='全局变量';
-- 0.6.7-SNAPSHOT 2022-09-02
-- 0.6.7 2022-09-02
-- -----------------------
-- DROP TABLE IF EXISTS `dlink_upload_file_record`;
CREATE TABLE `dlink_upload_file_record` (
`id` tinyint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '上传文件的类型名称,目前有:hadoop-conf(1)、flink-conf(2)、flink-lib(3)、user-jar(4)、dlink-jar(5)',
......@@ -725,4 +731,170 @@ CREATE TABLE `dlink_upload_file_record` (
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='上传文件记录';
\ No newline at end of file
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='上传文件记录';
-- 0.6.8 2022-10-13
-- ----------------------------
CREATE TABLE IF NOT EXISTS dlink_tenant
(
id int auto_increment comment 'ID',
tenant_code varchar(64) not null comment '租户编码',
is_delete tinyint(1) default 0 not null comment '是否被删除',
note varchar(255) null comment '注释',
create_time datetime null comment '创建时间',
update_time datetime null comment '最近修改时间',
PRIMARY KEY (id) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT '租户' ;
-- ----------------------------
-- Records of dlink_tenant
-- ----------------------------
INSERT INTO `dlink_tenant`(`id`, `tenant_code`, `is_delete`, `note`, `create_time`, `update_time`) VALUES (1, 'DefaultTenant', 0, 'DefaultTenant', current_time, current_time);
CREATE TABLE IF NOT EXISTS dlink_role
(
id int auto_increment comment 'ID',
tenant_id int not null comment '租户ID',
role_code varchar(64) not null comment '角色编码',
role_name varchar(64) not null comment '角色名称',
is_delete tinyint(1) default 0 not null comment '是否被删除',
note varchar(255) null comment '注释',
create_time datetime null comment '创建时间',
update_time datetime null comment '更新时间',
PRIMARY KEY (id) USING BTREE,
UNIQUE KEY `dlink_role_un` (`role_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC comment '角色' ;
-- ----------------------------
-- Records of dlink_role
-- ----------------------------
INSERT INTO `dlink_role`(`id`, `tenant_id`, `role_code`, `role_name`, `is_delete`, `note`, `create_time`, `update_time`) VALUES (1, 1, 'SuperAdmin', '超级管理员', 0, '超级管理员角色', current_time, current_time);
CREATE TABLE IF NOT EXISTS dlink_namespace
(
id int auto_increment comment 'ID',
tenant_id int not null comment '租户ID',
namespace_code varchar(64) not null comment '命名空间编码',
enabled tinyint(1) default 1 not null comment '是否启用',
note varchar(255) null comment '注释',
create_time datetime null comment '创建时间',
update_time datetime null comment '更新时间',
PRIMARY KEY (id) USING BTREE,
UNIQUE KEY `dlink_namespace_un` (`namespace_code`,`tenant_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC comment '命名空间';
-- ----------------------------
-- Records of dlink_namespace
-- ----------------------------
INSERT INTO `dlink_namespace`(`id`, `tenant_id`, `namespace_code`, `enabled`, `note`, `create_time`, `update_time`) VALUES (1, 1, 'DefaultNameSpace', 1, '默认命名空间', current_time, current_time);
CREATE TABLE IF NOT EXISTS dlink_role_namespace
(
id int auto_increment comment 'ID',
role_id int not null comment '用户ID',
namespace_id int not null comment '名称空间ID',
create_time datetime null comment '创建时间',
update_time datetime null comment '更新时间',
PRIMARY KEY (id) USING BTREE,
UNIQUE KEY `dlink_role_namespace_un` (role_id, namespace_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC comment '角色与名称空间关系';
-- ----------------------------
-- Records of dlink_role_namespace
-- ----------------------------
INSERT INTO `dlink_role_namespace`(`id`, `role_id`, `namespace_id`, `create_time`, `update_time`) VALUES (1, 1, 1, current_time, current_time);
CREATE TABLE IF NOT EXISTS dlink_user_role
(
id int auto_increment comment 'ID',
user_id int not null comment '用户ID',
role_id int not null comment '角色ID',
create_time datetime null comment '创建时间',
update_time datetime null comment '更新时间',
PRIMARY KEY (id) USING BTREE,
UNIQUE KEY `dlink_user_role_un` (user_id, role_id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC comment '用户与角色关系';
-- ----------------------------
-- Records of dlink_user_role
-- ----------------------------
INSERT INTO `dlink_user_role`(`id`, `user_id`, `role_id`, `create_time`, `update_time`) VALUES (1, 1, 1, current_time, current_time);
CREATE TABLE `dlink_user_tenant` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` int NOT NULL COMMENT '用户ID',
`tenant_id` int NOT NULL COMMENT '租户ID',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `dlink_user_role_un` (`user_id`,`tenant_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='用户与租户关系';
-- ----------------------------
-- Records of dlink_user_tenant
-- ----------------------------
INSERT INTO `dlink_user_tenant`(`id`, `user_id`, `tenant_id`, `create_time`, `update_time`) VALUES (1, 1, 1, current_time, current_time);
alter table dlink_catalogue add column tenant_id int not null comment '租户ID' after id;
alter table dlink_catalogue drop index `idx_name`;
alter table dlink_catalogue add unique key `dlink_catalogue_un` (`name`, `parent_id`,`tenant_id`);
alter table dlink_cluster add column tenant_id int not null comment '租户ID' after id;
alter table dlink_cluster drop index `idx_name`;
alter table dlink_cluster add unique key `dlink_cluster_un` (`name`, `tenant_id`);
alter table dlink_task add column tenant_id int not null comment '租户ID' after name;
alter table dlink_task drop index `idx_name`;
alter table dlink_task add unique key `dlink_task_un` (`name`, `tenant_id`);
alter table dlink_task_statement add column tenant_id int not null comment '租户ID' after id;
alter table dlink_task_statement add unique key `dlink_task_statement_un` (`tenant_id`,`id`);
alter table dlink_database add column tenant_id int not null comment '租户ID' after id;
alter table dlink_database drop index `db_index`;
alter table dlink_database add unique key `dlink_database_un` (`name`,`tenant_id`);
alter table dlink_cluster_configuration add column tenant_id int not null comment '租户ID' after id;
alter table dlink_cluster_configuration add unique key `dlink_cluster_configuration_un` (`name`,`tenant_id`);
alter table dlink_jar add column tenant_id int not null comment '租户ID' after id;
alter table dlink_jar add unique key `dlink_jar_un` (`tenant_id`,`name`);
alter table dlink_savepoints add column tenant_id int not null comment '租户ID' after task_id;
alter table dlink_job_instance add column tenant_id int not null comment '租户ID' after name;
alter table dlink_job_instance add unique key `dlink_job_instance_un` (`tenant_id`,`name`,`task_id`,`history_id`);
alter table dlink_alert_instance add column tenant_id int not null comment '租户ID' after name;
alter table dlink_alert_instance add unique key `dlink_alert_instance_un` (`name`,`tenant_id`);
alter table dlink_alert_group add column tenant_id int not null comment '租户ID' after name;
alter table dlink_alert_group add unique key `dlink_alert_instance_un` (`name`,`tenant_id`);
alter table dlink_alert_history add column tenant_id int not null comment '租户ID' after id;
alter table dlink_task_version add column tenant_id int not null comment '租户ID' after task_id;
alter table dlink_task_version add unique key `dlink_task_version_un` (`task_id`,`tenant_id`,`version_id`);
alter table dlink_history add column tenant_id int not null comment '租户ID' after id;
alter table dlink_job_history add column tenant_id int not null comment '租户ID' after id;
-- 修改历史表的租户编号为默认租户
UPDATE `dlink_alert_group` SET `tenant_id` = 1 ;
UPDATE `dlink_alert_history` SET `tenant_id` = 1;
UPDATE `dlink_alert_instance` SET `tenant_id` = 1;
UPDATE `dlink_catalogue` SET `tenant_id` = 1;
UPDATE `dlink_cluster` SET `tenant_id` = 1;
UPDATE `dlink_cluster_configuration` SET `tenant_id` = 1 ;
UPDATE `dlink_database` SET `tenant_id` = 1 ;
UPDATE `dlink_history` SET `tenant_id` = 1;
UPDATE `dlink_jar` SET `tenant_id` = 1 ;
UPDATE `dlink_job_instance` SET `tenant_id` = 1 ;
UPDATE `dlink_savepoints` SET `tenant_id` = 1;
UPDATE `dlink_task` SET `tenant_id` = 1 ;
UPDATE `dlink_task_statement` SET `tenant_id` = 1;
UPDATE `dlink_task_version` SET `tenant_id` = 1;
UPDATE `dlink_job_history` SET `tenant_id` = 1;
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -462,7 +462,7 @@ public abstract class AbstractJdbcDriver extends AbstractDriver {
return sb.toString();
}
//todu impl by subclass
// todu impl by subclass
@Override
public String generateCreateTableSql(Table table) {
StringBuilder sb = new StringBuilder();
......@@ -473,7 +473,7 @@ public abstract class AbstractJdbcDriver extends AbstractDriver {
public boolean execute(String sql) throws Exception {
Asserts.checkNullString(sql, "Sql 语句为空");
try (Statement statement = conn.get().createStatement()) {
//logger.info("执行sql的连接id:" + ((DruidPooledConnection) conn).getTransactionInfo().getId());
// logger.info("执行sql的连接id:" + ((DruidPooledConnection) conn).getTransactionInfo().getId());
statement.execute(sql);
}
return true;
......@@ -503,10 +503,10 @@ public abstract class AbstractJdbcDriver extends AbstractDriver {
String limitEnd = queryData.getOption().getLimitEnd();
StringBuilder optionBuilder = new StringBuilder()
.append("select * from ")
.append(queryData.getSchemaName())
.append(".")
.append(queryData.getTableName());
.append("select * from ")
.append(queryData.getSchemaName())
.append(".")
.append(queryData.getTableName());
if (where != null && !where.equals("")) {
optionBuilder.append(" where ").append(where);
......@@ -522,9 +522,9 @@ public abstract class AbstractJdbcDriver extends AbstractDriver {
limitEnd = "100";
}
optionBuilder.append(" limit ")
.append(limitStart)
.append(",")
.append(limitEnd);
.append(limitStart)
.append(",")
.append(limitEnd);
return optionBuilder;
}
......
......@@ -17,7 +17,6 @@
*
*/
export default [
{
path: '/user',
......@@ -118,7 +117,7 @@ export default [
component: './AlertGroup',
},
],
},{
}, {
path: '/registration/document',
name: 'document',
icon: 'container',
......@@ -128,6 +127,37 @@ export default [
name: 'fragment',
icon: "cloud",
component: './FragmentVariable',
}
],
},
{
name: 'authenticationcenter',
icon: 'SafetyCertificateOutlined',
path: '/authenticationcenter',
routes: [
{
path: '/authenticationcenter/usermanager',
name: 'usermanager',
icon: 'UserOutlined',
component: './AuthenticationCenter/UserManager',
},
{
path: '/authenticationcenter/rolemanager',
name: 'rolemanager',
icon: 'TeamOutlined',
component: './AuthenticationCenter/RoleManager',
},
{
path: '/authenticationcenter/namespacemanager',
name: 'namespacemanager',
icon: 'BulbOutlined',
component: './AuthenticationCenter/NamespaceManager',
},
{
path: '/authenticationcenter/tenantmanager',
name: 'tenantmanager',
icon: 'SecurityScanOutlined',
component: './AuthenticationCenter/TenantManager',
},
],
},
......@@ -138,8 +168,15 @@ export default [
{
name: 'settings',
icon: 'setting',
path: '/settings',
component: './Settings',
path: '/settingcenter',
routes: [
{
path: '/settingcenter/flinksettings',
name: 'flinkConfig',
icon: 'setting',
component: './SettingCenter/FlinkSettings',
},
],
},
{
path: '/about',
......
......@@ -57,6 +57,7 @@
"@ant-design/charts": "^1.3.4",
"@ant-design/icons": "^4.5.0",
"@ant-design/plots": "^1.0.7",
"@ant-design/pro-components": "^1.1.23",
"@ant-design/pro-descriptions": "^1.6.8",
"@ant-design/pro-form": "^1.18.3",
"@ant-design/pro-layout": "^6.18.0",
......
......@@ -22,8 +22,8 @@
* @see https://umijs.org/zh-CN/plugins/plugin-access
* */
export default function access(initialState: { currentUser?: API.CurrentUser | undefined }) {
const { currentUser } = initialState || {};
const {currentUser} = initialState || {};
return {
canAdmin: currentUser && currentUser.access === 'admin',
canAdmin: currentUser && currentUser.isAdmin ? 'admin' : '',
};
}
......@@ -28,14 +28,13 @@ import Footer from '@/components/Footer';
import type {ResponseError} from 'umi-request';
import {currentUser as queryCurrentUser} from './services/ant-design-pro/api';
import {BookOutlined, LinkOutlined} from '@ant-design/icons';
import {useIntl} from "@@/plugin-locale/localeExports";
const isDev = process.env.NODE_ENV === 'development';
const loginPath = '/user/login';
/** 获取用户信息比较慢的时候会展示一个 loading */
export const initialStateConfig = {
loading: <PageLoading />,
loading: <PageLoading/>,
};
/**
......@@ -47,20 +46,24 @@ export async function getInitialState(): Promise<{
fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
}> {
const fetchUserInfo = async () => {
try {
const result = await queryCurrentUser();
const currentUser: API.CurrentUser = {
name: result.datas.nickname || result.datas.username,
avatar: result.datas.avatar?result.datas.avatar:'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
userid: result.datas.username,
notifyCount: 0,
unreadCount: 0,
access: result.datas.isAdmin?'admin':'',
phone: result.datas.mobile,
isAdmin:result.datas.isAdmin,
worknum:result.datas.worknum,
id: result.datas.user.id,
username: result.datas.user.username,
password: result.datas.user.password,
nickname: result.datas.user.nickname,
worknum: result.datas.user.worknum,
avatar: result.datas.user.avatar ? result.datas.user.avatar : 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
mobile: result.datas.user.mobile,
enabled: result.datas.user.enabled,
isDelete: result.datas.user.isDelete,
createTime: result.datas.user.createTime,
updateTime: result.datas.user.updateTime,
isAdmin: result.datas.user.isAdmin,
roleList: result.datas.roleList,
tenantList: result.datas.tenantList,
currentTenant: result.datas.currentTenant,
};
return currentUser;
} catch (error) {
......@@ -107,48 +110,48 @@ export async function getInitialState(): Promise<{
*/
export const request: RequestConfig = {
errorHandler: (error: ResponseError) => {
const { messages } = getIntl(getLocale());
const { request,response } = error;
const {messages} = getIntl(getLocale());
const {request, response} = error;
const writeUrl = ['/api/current'];
if(writeUrl.indexOf(request.originUrl)>-1){
return;
}else {
if (response && response.status) {
const {status, statusText, url} = response;
const requestErrorMessage = messages['app.request.error'];
const errorMessage = `${requestErrorMessage} ${status}: ${url}`;
const errorDescription = messages[`app.request.${status}`] || statusText;
notification.error({
message: errorMessage,
description: errorDescription,
});
}
if (writeUrl.indexOf(request.originUrl) > -1) {
return;
} else {
if (response && response.status) {
const {status, statusText, url} = response;
const requestErrorMessage = messages['app.request.error'];
const errorMessage = `${requestErrorMessage} ${status}: ${url}`;
const errorDescription = messages[`app.request.${status}`] || statusText;
notification.error({
message: errorMessage,
description: errorDescription,
});
}
if (!response) {
notification.error({
description: '您的网络发生异常,无法连接服务器',
message: '网络异常',
});
if (!response) {
notification.error({
description: '您的网络发生异常,无法连接服务器',
message: '网络异常',
});
}
throw error;
}
throw error;
}
},
};
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState }) => {
export const layout: RunTimeLayoutConfig = ({initialState}) => {
return {
rightContentRender: () => <RightContent />,
rightContentRender: () => <RightContent/>,
disableContentMargin: false,
/*waterMarkProps: {
content: initialState?.currentUser?.name,
},*/
footerRender: () => <Footer />,
footerRender: () => <Footer/>,
onPageChange: () => {
const { location } = history;
const {location} = history;
// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== loginPath) {
history.push(loginPath);
......@@ -156,15 +159,15 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => {
},
links: isDev
? [
<Link to="/umi/plugin/openapi" target="_blank">
<LinkOutlined />
<span>openAPI Document</span>
</Link>,
<Link to="/~docs">
<BookOutlined />
<span>Business Component Document</span>
</Link>,
]
<Link to="/umi/plugin/openapi" target="_blank">
<LinkOutlined/>
<span>openAPI Document</span>
</Link>,
<Link to="/~docs">
<BookOutlined/>
<span>Business Component Document</span>
</Link>,
]
: [],
menuHeaderRender: undefined,
// 自定义 403 页面
......
......@@ -18,9 +18,19 @@
*/
import request from "umi-request";
import {extend} from "umi-request";
import {TableListParams} from "@/components/Common/data";
import {message, Modal} from "antd";
import {message} from "antd";
export const request2 = extend(
{ headers: { tenantId: localStorage.getItem('dlink-tenantId') || ''} }
);
export const getStorageTenantId = () => {
return localStorage.getItem('dlink-tenantId') || '';
}
export const CODE = {
SUCCESS: 0,
......@@ -28,7 +38,7 @@ export const CODE = {
};
export async function queryData(url:string,params?: TableListParams) {
return request(url, {
return request2(url, {
method: 'POST',
data: {
...params,
......@@ -37,7 +47,7 @@ export async function queryData(url:string,params?: TableListParams) {
}
export async function getData(url:string,params?: any) {
return request(url, {
return request2(url, {
method: 'GET',
params: {
...params,
......@@ -46,7 +56,7 @@ export async function getData(url:string,params?: any) {
}
export async function removeData(url:string,params: any[]) {
return request(url, {
return request2(url, {
method: 'DELETE',
data: {
...params,
......@@ -55,7 +65,7 @@ export async function removeData(url:string,params: any[]) {
}
export async function addOrUpdateData(url:string,params: any) {
return request(url, {
return request2(url, {
method: 'PUT',
data: {
...params,
......@@ -64,7 +74,7 @@ export async function addOrUpdateData(url:string,params: any) {
}
export async function postDataArray(url:string,params: number[]) {
return request(url, {
return request2(url, {
method: 'POST',
data: {
...params,
......@@ -73,7 +83,7 @@ export async function postDataArray(url:string,params: number[]) {
}
export async function postAll(url:string,params?: any) {
return request(url, {
return request2(url, {
method: 'POST',
data: {
...params,
......@@ -82,7 +92,7 @@ export async function postAll(url:string,params?: any) {
}
export async function getInfoById(url:string,id:number) {
return request(url, {
return request2(url, {
method: 'GET',
params: {
id:id,
......
......@@ -18,14 +18,22 @@
*/
import React, {useCallback} from 'react';
import {LogoutOutlined, SettingOutlined, UserOutlined} from '@ant-design/icons';
import {Avatar, Menu, Spin} from 'antd';
import React, {useCallback, useRef} from 'react';
import {
LogoutOutlined,
SafetyOutlined,
SecurityScanOutlined,
SettingOutlined,
UserSwitchOutlined
} from '@ant-design/icons';
import {Avatar, Menu, Modal, Spin} from 'antd';
import {history, useModel} from 'umi';
import {stringify} from 'querystring';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
import {outLogin} from '@/services/ant-design-pro/api';
import {ActionType} from "@ant-design/pro-table";
import {useIntl} from "@@/plugin-locale/localeExports";
export type GlobalHeaderRightProps = {
menu?: boolean;
......@@ -36,8 +44,8 @@ export type GlobalHeaderRightProps = {
*/
const loginOut = async () => {
await outLogin();
const { query = {}, pathname } = history.location;
const { redirect } = query;
const {query = {}, pathname} = history.location;
const {redirect} = query;
// Note: There may be security issues, please note
if (window.location.pathname !== '/user/login' && !redirect) {
history.replace({
......@@ -49,8 +57,14 @@ const loginOut = async () => {
}
};
const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
const { initialState, setInitialState } = useModel('@@initialState');
const requestUrl = '/api/tenant/switchTenant';
const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({menu}) => {
const {initialState, setInitialState} = useModel('@@initialState');
const actionRef = useRef<ActionType>();
const intl = useIntl();
const onMenuClick = useCallback(
(event: {
......@@ -59,9 +73,9 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
item: React.ReactInstance;
domEvent: React.MouseEvent<HTMLElement>;
}) => {
const { key } = event;
const {key} = event;
if (key === 'logout' && initialState) {
setInitialState({ ...initialState, currentUser: undefined });
setInitialState({...initialState, currentUser: undefined});
loginOut();
return;
}
......@@ -86,39 +100,97 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
return loading;
}
const { currentUser } = initialState;
const {currentUser} = initialState;
if (!currentUser || !currentUser.name) {
if (!currentUser || !currentUser.username) {
return loading;
}
const getChooseTenantListForm = () => {
let chooseTenantList: JSX.Element[] = [];
currentUser.tenantList?.map((item) => {
chooseTenantList.push(
<>
<Menu.Item
// If the current key (tenant id) is equal to the tenant the current user chooses to log in, this item is not optional
disabled={item.id === currentUser.currentTenant?.id}
key={item.id}
title={item.tenantCode}
icon={<SecurityScanOutlined/>}
onClick={(e) => {
console.log(e)
// get choose tenant title
let title = e.domEvent.target.textContent;
// get choose tenantId
let tenantInfoId = e.key;
Modal.confirm({
title: intl.formatMessage({id: 'menu.account.checkTenant'}),
content: '确定切换【' + title + '】租户吗?',
okText: intl.formatMessage({id: 'button.confirm'}),
cancelText: intl.formatMessage({id: 'button.cancel'}),
onOk: async () => {
// 目前先直接退出登录 重新选择租户登录
loginOut();
// todo 切换租户需要将租户id 传入后端 以及本地存储中
// const {code, msg} = await postAll(requestUrl, {tenantId: tenantInfoId});
// localStorage.clear() // clear local storage
// localStorage.setItem('dlink-tenantId',tenantInfoId) // set tenant to localStorage
// code == 0 ? message.success(msg) : message.error(msg);
// todo
// 1.切换租户后 需要重新调用 /api/current接口获取用户的信息 (目前此接口从cookie直接取数 ,达不到预期效果)
// 2.同步刷新所有页面 获取该租户id下的数据
//actionRef.current?.reload()
// actionRef.current?.reloadAndRest?.();
}
});
}}
>
{item.tenantCode}
</Menu.Item>
</>
)
})
return <>
<Menu.SubMenu
key="chooseTenantList"
title={intl.formatMessage({id: 'menu.account.checkTenant'})}
icon={<UserSwitchOutlined/>}
>
{chooseTenantList}
</Menu.SubMenu>
</>;
}
const menuHeaderDropdown = (
<Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
{menu && (
<Menu.Item key="center">
<UserOutlined />
个人中心
getChooseTenantListForm()
)}
{menu && (
<Menu.Item key="personSettings" disabled>
<SettingOutlined/>
{intl.formatMessage({id: 'menu.account.settings'})}
</Menu.Item>
)}
{menu && (
<Menu.Item key="settings">
<SettingOutlined />
个人设置
<Menu.Item key="changePassWord" disabled>
<SafetyOutlined/>
{intl.formatMessage({id: 'menu.account.changePassword'})}
</Menu.Item>
)}
{menu && <Menu.Divider />}
{menu && <Menu.Divider/>}
<Menu.Item key="logout">
<LogoutOutlined />
退出登录
<LogoutOutlined/>
{intl.formatMessage({id: 'menu.account.logout'})}
</Menu.Item>
</Menu>
);
return (
<HeaderDropdown overlay={menuHeaderDropdown}>
<span className={`${styles.action} ${styles.account}`}>
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
<span className={`${styles.name} anticon`}>{currentUser.name}</span>
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar"/>
<span className={`${styles.name} anticon`}>{currentUser.username}</span>
</span>
</HeaderDropdown>
);
......
......@@ -18,12 +18,11 @@
*/
import { Tag, Space } from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons';
import {GlobalOutlined} from '@ant-design/icons';
import {Space} from 'antd';
import React from 'react';
import { useModel, SelectLang } from 'umi';
import {SelectLang, useModel} from 'umi';
import Avatar from './AvatarDropdown';
import HeaderSearch from '../HeaderSearch';
import styles from './index.less';
export type SiderTheme = 'light' | 'dark';
......@@ -35,13 +34,13 @@ const ENVTagColor = {
};
const GlobalHeaderRight: React.FC = () => {
const { initialState } = useModel('@@initialState');
const {initialState} = useModel('@@initialState');
if (!initialState || !initialState.settings) {
return null;
}
const { navTheme, layout } = initialState.settings;
const {navTheme, layout} = initialState.settings;
let className = styles.right;
if ((navTheme === 'dark' && layout === 'top') || layout === 'mix') {
......@@ -49,44 +48,13 @@ const GlobalHeaderRight: React.FC = () => {
}
return (
<Space className={className}>
<HeaderSearch
className={`${styles.action} ${styles.search}`}
placeholder="站内搜索"
defaultValue="umi ui"
options={[
{ label: <a href="https://umijs.org/zh/guide/umi-ui.html">umi ui</a>, value: 'umi ui' },
{
label: <a href="next.ant.design">Ant Design</a>,
value: 'Ant Design',
},
{
label: <a href="https://protable.ant.design/">Pro Table</a>,
value: 'Pro Table',
},
{
label: <a href="https://prolayout.ant.design/">Pro Layout</a>,
value: 'Pro Layout',
},
]}
// onSearch={value => {
// console.log('input', value);
// }}
/>
<span
className={styles.action}
onClick={() => {
window.open('https://pro.ant.design/docs/getting-started');
}}
>
<QuestionCircleOutlined />
</span>
<Avatar />
{REACT_APP_ENV && (
<span>
<Tag color={ENVTagColor[REACT_APP_ENV]}>{REACT_APP_ENV}</Tag>
</span>
)}
<SelectLang className={styles.action} />
<Avatar menu={true}/>
{/*{REACT_APP_ENV && (*/}
{/* <span>*/}
{/* <Tag color={ENVTagColor[REACT_APP_ENV]}>{REACT_APP_ENV}</Tag>*/}
{/* </span>*/}
{/*)}*/}
<SelectLang icon={<GlobalOutlined/>} className={styles.action}/>
</Space>
);
};
......
......@@ -40,7 +40,7 @@ export function convertToTreeData(data:TreeDataNode[], pid:number,path?:string[]
!path&&(path=[]);
const result:TreeDataNode[] = [];
let temp:TreeDataNode[] = [];
for (let i = 0; i < data.length; i++) {
for (let i = 0; i < data?.length; i++) {
if (data[i].parentId === pid) {
let obj = data[i];
obj.title = obj.name;
......
......@@ -18,25 +18,31 @@
*/
import React, {useEffect, useRef, useState, useCallback} from "react";
import React, {useCallback, useEffect, useState} from "react";
import {connect} from "umi";
import styles from './index.less';
import {} from "@ant-design/icons";
import StudioMenu from "./StudioMenu";
import {Row, Col, Card, Form} from "antd";
import {Card, Col, Form, Row} from "antd";
import StudioTabs from "./StudioTabs";
import StudioHome from "./StudioHome";
import {StateType} from "@/pages/DataStudio/model";
import StudioConsole from "./StudioConsole";
import StudioLeftTool from "./StudioLeftTool";
import StudioRightTool from "./StudioRightTool";
import {
listSession, showCluster, showDataBase, getFillAllByVersion,
showClusterConfiguration, showSessionCluster, showJars, showEnv, showAlertInstance, showAlertGroup
getFillAllByVersion,
listSession,
showAlertGroup,
showAlertInstance,
showCluster,
showClusterConfiguration,
showDataBase,
showEnv,
showJars,
showSessionCluster
} from "@/components/Studio/StudioEvent/DDL";
import {loadSettings} from "@/pages/Settings/function";
import DraggleLayout from "@/components/DraggleLayout";
import DraggleVerticalLayout from "@/components/DraggleLayout/DraggleVerticalLayout";
import {loadSettings} from "@/pages/SettingCenter/FlinkSettings/function";
const Studio = (props: any) => {
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import component from './en-US/component';
import globalHeader from './en-US/globalHeader';
import menu from './en-US/menu';
......@@ -6,6 +25,7 @@ import pwa from './en-US/pwa';
import request from './en-US/request';
import settingDrawer from './en-US/settingDrawer';
import settings from './en-US/settings';
import button from './en-US/button';
export default {
'navBar.lang': 'Languages',
......@@ -24,4 +44,5 @@ export default {
...component,
...pages,
...request,
...button,
};
......@@ -17,24 +17,9 @@
*
*/
export type UserTableListItem = {
id?: number;
enabled?: boolean;
isDelete?: string;
createTime?: Date;
updateTime?: Date;
username?: string;
nickname?: string;
password?: string;
avatar?: string;
worknum?: string;
mobile?: string;
};
export type PasswordItem = {
username: string;
password?: string;
newPassword?: string;
newPasswordCheck?: string;
export default {
'button.create': 'Create',
'button.close': 'Close',
'button.confirm': 'Confirm',
'button.cancel': 'Cancel',
};
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'component.tagSelect.expand': 'Expand',
'component.tagSelect.collapse': 'Collapse',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'component.globalHeader.search': 'Search',
'component.globalHeader.search.example1': 'Search example 1',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'menu.welcome': 'Welcome',
'menu.more-blocks': 'More Blocks',
......@@ -45,25 +64,41 @@ export default {
'menu.account.settings': 'Account Settings',
'menu.account.trigger': 'Trigger Error',
'menu.account.logout': 'Logout',
'menu.account.checkTenant': 'Check Tenant',
'menu.account.changePassword': 'Change Password',
'menu.editor': 'Graphic Editor',
'menu.editor.flow': 'Flow Editor',
'menu.editor.mind': 'Mind Editor',
'menu.editor.koni': 'Koni Editor',
'menu.datastudio': 'Data Studio',
'menu.devops': 'Devops',
'menu.job': 'Job Instance',
'menu.datacenter': 'Mate Data Center',
'menu.datacenter.metadata': 'Mate Data',
'menu.registration': 'Regist Center',
'menu.registration.cluster': 'Cluster Management',
'menu.registration.cluster.clusterInstance': 'Cluster Instance',
'menu.registration.cluster.clusterConfiguration': 'Cluster Config',
'menu.registration.jar': 'Jar Management',
'menu.registration.database': 'Data Source Management',
'menu.registration.alert': 'Alarm Management',
'menu.registration.alert.alertInstance': 'Alarm Instance Management',
'menu.registration.alert.alertGroup': 'Alarm Group Management',
'menu.registration.jar': 'Jar Management',
'menu.registration.document': 'Document Management',
'menu.registration.fragment': 'Global Variable Management',
'menu.datastudio': 'Data Studio',
'menu.settings': 'System Setting',
'menu.devops': 'Devops',
'menu.authenticationcenter': 'Authentication Center',
'menu.authenticationcenter.usermanager': 'User Management',
'menu.authenticationcenter.namespacemanager': 'NameSpace Management',
'menu.authenticationcenter.rolemanager': 'Role Management',
'menu.authenticationcenter.tenantmanager': 'Tenant Management',
'menu.settings': 'Setting Center',
'menu.settings.flinkConfig': 'Flink Settings',
'menu.about': 'About',
};
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'pages.layouts.userLayout.title': 'Dinky Real-time Computing Platform',
......@@ -5,6 +24,7 @@ export default {
'pages.login.accountLogin.errorMessage': 'Incorrect UserName/Password(admin/ant.design)',
'pages.login.failure': 'Login Failed, Please Try Again!',
'pages.login.success': 'Login Success!',
'pages.login.chooseTenant': 'Please Choose Tenant',
'pages.login.username.placeholder': 'Username: Admin Or User',
'pages.login.username.required': 'Please Input Your UserName!',
'pages.login.password.placeholder': 'Password: ant.design',
......@@ -68,83 +88,82 @@ export default {
'pages.searchTable.batchDeletion': 'Bacth Deletion',
'pages.searchTable.batchApproval': 'Batch Approval',
'pages.devops.jobstatus.CREATED' : 'Created',
'pages.devops.jobstatus.INITIALIZING' : 'Initialize',
'pages.devops.jobstatus.RUNNING' : 'Running',
'pages.devops.jobstatus.FINISHED' : 'Finished',
'pages.devops.jobstatus.FAILING' : 'Abnormal',
'pages.devops.jobstatus.FAILED' : 'Failed',
'pages.devops.jobstatus.SUSPENDED' : 'Paused',
'pages.devops.jobstatus.CANCELLING' : 'Canceling',
'pages.devops.jobstatus.CANCELED' : 'Canceled',
'pages.devops.jobstatus.RESTARTING' : 'Restarting',
'pages.devops.jobstatus.UNKNOWN' : 'Unknown',
'pages.devops.LastUpdateTime' : 'LastUpdateTime',
'pages.devops.jobstatus.CREATED': 'Created',
'pages.devops.jobstatus.INITIALIZING': 'Initialize',
'pages.devops.jobstatus.RUNNING': 'Running',
'pages.devops.jobstatus.FINISHED': 'Finished',
'pages.devops.jobstatus.FAILING': 'Abnormal',
'pages.devops.jobstatus.FAILED': 'Failed',
'pages.devops.jobstatus.SUSPENDED': 'Paused',
'pages.devops.jobstatus.CANCELLING': 'Canceling',
'pages.devops.jobstatus.CANCELED': 'Canceled',
'pages.devops.jobstatus.RESTARTING': 'Restarting',
'pages.devops.jobstatus.UNKNOWN': 'Unknown',
'pages.settings.UserManagement' : 'User Management',
'pages.settings.Flink' : 'Flink Setting',
'pages.settings.FlinkURL' : 'Submit the Jar file path to FlinkSQL',
'pages.devops.LastUpdateTime': 'LastUpdateTime',
'pages.settings.FlinkSQLJarMainParameter' : 'Submit The Main Class entry To the Jar For FlinkSQL',
'pages.settings.FlinkSQLJarMainClass' : 'The Main Class Of The Jar That Submitted FlinkSQL',
'pages.settings.FlinkRestAPI' : 'Using Rest API',
'pages.settings.FlinkURLSplit' : 'FlinkSQL Statement Separator',
'pages.settings.FlinkSQLLogic' : 'Calculate Consanguinity Using A Logical Plan',
'pages.settings.FlinkJobID' : 'Maximum Waiting Time For Getting A Job ID (seconds)',
'pages.settings.FlinkNoSetting' : 'Not Setting',
'pages.settings.FlinkNoUseSetting' : 'After The Flink Task Is Enabled, Operations Such As Savepoint And Stop Are Performed Through The RestAPI Of JobManager',
'pages.settings.FlinkLogic' : 'Whether The Calculation Of Field Consanguinity Analysis For Flink Tasks Is Based On A Logical Plan Is Supported Only In Version 1.14',
'pages.settings.UserManagement': 'User Management',
'pages.settings.Flink': 'Flink Setting',
'pages.settings.FlinkURL': 'Submit the Jar file path to FlinkSQL',
'pages.settings.FlinkUpdate' : 'Update',
'pages.settings.FlinkSave' : 'Save',
'pages.settings.FlinkCancel' : 'Cancel',
'pages.settings.FlinkUse' : 'In Use',
'pages.settings.FlinkNotUse' : 'Not Use',
'pages.settings.FlinkSQLJarMainParameter': 'Submit The Main Class entry To the Jar For FlinkSQL',
'pages.settings.FlinkSQLJarMainClass': 'The Main Class Of The Jar That Submitted FlinkSQL',
'pages.settings.FlinkRestAPI': 'Using Rest API',
'pages.settings.FlinkURLSplit': 'FlinkSQL Statement Separator',
'pages.settings.FlinkSQLLogic': 'Calculate Consanguinity Using A Logical Plan',
'pages.settings.FlinkJobID': 'Maximum Waiting Time For Getting A Job ID (seconds)',
'pages.settings.FlinkNoSetting': 'Not Setting',
'pages.settings.FlinkNoUseSetting': 'After The Flink Task Is Enabled, Operations Such As Savepoint And Stop Are Performed Through The RestAPI Of JobManager',
'pages.settings.FlinkLogic': 'Whether The Calculation Of Field Consanguinity Analysis For Flink Tasks Is Based On A Logical Plan Is Supported Only In Version 1.14',
'pages.user.UserEdit' : 'Edit',
'pages.user.UserDelete' : 'Delete',
'pages.user.UserChangePassword' : 'Update Password',
'pages.user.UserConfig' : 'Config',
'pages.user.UserMore' : 'More',
'pages.settings.FlinkUpdate': 'Update',
'pages.settings.FlinkSave': 'Save',
'pages.settings.FlinkCancel': 'Cancel',
'pages.settings.FlinkUse': 'In Use',
'pages.settings.FlinkNotUse': 'Not Use',
'pages.user.UserCreate' : 'Create',
'pages.user.UserManger' : 'User Management',
'pages.user.UserName' : 'User Name',//用户名
'pages.user.UserJobNumber' : 'Job Number',//工号
'pages.user.UserPhoneNumber' : 'Phone Number',//手机号
'pages.user.UserNickName' : 'Nick Name',//昵称
'pages.user.UserIsUse' : 'Is Use',//是否启用
'pages.user.UserUpdateTime' : 'Update Time',//最近更新时间
'pages.user.UserOperate' : 'Operate',//操作
'pages.user.UserInUse' : 'In Use',//已启用
'pages.user.UserNotUse' : 'Not Use',//已禁用
'pages.user.UserCreateTime' : 'Create Time',//创建时间
'pages.user.UserEdit': 'Edit',
'pages.user.UserDelete': 'Delete',
'pages.user.UserChangePassword': 'Update Password',
'pages.user.UserConfig': 'Config',
'pages.user.UserMore': 'More',
'pages.user.UserComplete' : 'Complete',
'pages.user.UserConfirm' : 'Confirm',
'pages.user.UserCancel' : 'Cancel',
'pages.user.UserDeleteUser' : 'Delete User',
'pages.user.UserCreateUser' : 'Create User',
'pages.user.UserUpdateUser' : 'Update User',
'pages.user.UserEnterUserName' : 'Please enter user name',
'pages.user.UserEnterUniqueUserName' : 'Please enter unique user name',
'pages.user.UserEnterJobNumber' : 'Please enter job number',
'pages.user.UserEnterNickName' : 'Please enter nickname',
'pages.user.UserEnterPhoneNumber' : 'Please enter phone number',
'pages.user.UserOldPassword' : 'Old Password',
'pages.user.UserNewPassword' : 'New Password',
'pages.user.UserRepeatNewPassword' : 'Repeat New Password',
'pages.user.UserEnterOldPassword' : 'Please enter old password',
'pages.user.UserEnterNewPassword' : 'Please enter new password',
'pages.user.UserEnterRepeatNewPassword' : 'Please enter repeat new password',
'pages.user.UserNewPasswordNotMatch' : 'The new passwords do not match',
'pages.user.UserUpdatePassword' : 'Update Password',
'pages.user.UserCreate': 'Create',
'pages.user.UserManger': 'User Management',
'pages.user.UserName': 'User Name',//用户名
'pages.user.UserJobNumber': 'Job Number',//工号
'pages.user.UserPhoneNumber': 'Phone Number',//手机号
'pages.user.UserNickName': 'Nick Name',//昵称
'pages.user.UserIsUse': 'Is Use',//是否启用
'pages.user.UserUpdateTime': 'Update Time',//最近更新时间
'pages.user.UserOperate': 'Operate',//操作
'pages.user.UserInUse': 'In Use',//已启用
'pages.user.UserNotUse': 'Not Use',//已禁用
'pages.user.UserCreateTime': 'Create Time',//创建时间
'pages.user.UserComplete': 'Complete',
'pages.user.UserConfirm': 'Confirm',
'pages.user.UserCancel': 'Cancel',
'pages.user.UserDeleteUser': 'Delete User',
'pages.user.UserCreateUser': 'Create User',
'pages.user.UserUpdateUser': 'Update User',
'pages.user.UserEnterUserName': 'Please enter user name',
'pages.user.UserEnterUniqueUserName': 'Please enter unique user name',
'pages.user.UserEnterJobNumber': 'Please enter job number',
'pages.user.UserEnterNickName': 'Please enter nickname',
'pages.user.UserEnterPhoneNumber': 'Please enter phone number',
'pages.user.UserOldPassword': 'Old Password',
'pages.user.UserNewPassword': 'New Password',
'pages.user.UserRepeatNewPassword': 'Repeat New Password',
'pages.user.UserEnterOldPassword': 'Please enter old password',
'pages.user.UserEnterNewPassword': 'Please enter new password',
'pages.user.UserEnterRepeatNewPassword': 'Please enter repeat new password',
'pages.user.UserNewPasswordNotMatch': 'The new passwords do not match',
'pages.user.UserUpdatePassword': 'Update Password',
'pages.regist.openAPI' : 'openAPI Document',
'pages.regist.BusinessComponent' : 'Business Component Document',
'pages.regist.openAPI': 'openAPI Document',
'pages.regist.BusinessComponent': 'Business Component Document',
};
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'app.pwa.offline': 'You are offline now',
'app.pwa.serviceworker.updated': 'New content is available',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'app.request.error': 'Request error',
'app.request.200': 'The server successfully returned the requested data. ',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'app.setting.pagestyle': 'Page style setting',
'app.setting.pagestyle.dark': 'Dark style',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'app.settings.menuMap.basic': 'Basic Settings',
'app.settings.menuMap.security': 'Security Settings',
......
import component from './fa-IR/component';
import globalHeader from './fa-IR/globalHeader';
import menu from './fa-IR/menu';
import pwa from './fa-IR/pwa';
import settingDrawer from './fa-IR/settingDrawer';
import settings from './fa-IR/settings';
import pages from './fa-IR/pages';
export default {
'navBar.lang': 'زبان ها ',
'layout.user.link.help': 'کمک',
'layout.user.link.privacy': 'حریم خصوصی',
'layout.user.link.terms': 'مقررات',
'app.preview.down.block': 'این صفحه را در پروژه محلی خود بارگیری کنید',
'app.welcome.link.fetch-blocks': 'دریافت تمام بلوک',
'app.welcome.link.block-list': 'به سرعت صفحات استاندارد مبتنی بر توسعه "بلوک" را بسازید',
...globalHeader,
...menu,
...settingDrawer,
...settings,
...pwa,
...component,
...pages,
};
export default {
'component.tagSelect.expand': 'باز',
'component.tagSelect.collapse': 'بسته ',
'component.tagSelect.all': 'همه',
};
export default {
'component.globalHeader.search': 'جستجو ',
'component.globalHeader.search.example1': 'مثال 1 را جستجو کنید',
'component.globalHeader.search.example2': 'مثال 2 را جستجو کنید',
'component.globalHeader.search.example3': 'مثال 3 را جستجو کنید',
'component.globalHeader.help': 'کمک',
'component.globalHeader.notification': 'اعلان',
'component.globalHeader.notification.empty': 'شما همه اعلان ها را مشاهده کرده اید.',
'component.globalHeader.message': 'پیام',
'component.globalHeader.message.empty': 'شما همه پیام ها را مشاهده کرده اید.',
'component.globalHeader.event': 'رویداد',
'component.globalHeader.event.empty': 'شما همه رویدادها را مشاهده کرده اید.',
'component.noticeIcon.clear': 'پاک کردن',
'component.noticeIcon.cleared': 'پاک شد',
'component.noticeIcon.empty': 'بدون اعلان',
'component.noticeIcon.view-more': 'نمایش بیشتر',
};
export default {
'menu.welcome': 'خوش آمدید',
'menu.more-blocks': 'بلوک های بیشتر',
'menu.home': 'خانه',
'menu.admin': 'مدیر',
'menu.admin.sub-page': 'زیر صفحه',
'menu.login': 'ورود',
'menu.register': 'ثبت نام',
'menu.register.result': 'ثبت نام نتیجه',
'menu.dashboard': 'داشبورد',
'menu.dashboard.analysis': 'تحلیل و بررسی',
'menu.dashboard.monitor': 'نظارت',
'menu.dashboard.workplace': 'محل کار',
'menu.exception.403': '403',
'menu.exception.404': '404',
'menu.exception.500': '500',
'menu.form': 'فرم',
'menu.form.basic-form': 'فرم اساسی',
'menu.form.step-form': 'فرم مرحله',
'menu.form.step-form.info': 'فرم مرحله (نوشتن اطلاعات انتقال)',
'menu.form.step-form.confirm': 'فرم مرحله (تأیید اطلاعات انتقال)',
'menu.form.step-form.result': 'فرم مرحله (تمام شده)',
'menu.form.advanced-form': 'فرم پیشرفته',
'menu.list': 'لیست',
'menu.list.table-list': 'جدول جستجو',
'menu.list.basic-list': 'لیست اصلی',
'menu.list.card-list': 'لیست کارت',
'menu.list.search-list': 'لیست جستجو',
'menu.list.search-list.articles': 'لیست جستجو (مقالات)',
'menu.list.search-list.projects': 'لیست جستجو (پروژه ها)',
'menu.list.search-list.applications': 'لیست جستجو (برنامه ها)',
'menu.profile': 'مشخصات',
'menu.profile.basic': 'مشخصات عمومی',
'menu.profile.advanced': 'مشخصات پیشرفته',
'menu.result': 'نتیجه',
'menu.result.success': 'موفق',
'menu.result.fail': 'ناموفق',
'menu.exception': 'استثنا',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': 'راه اندازی',
'menu.account': 'حساب',
'menu.account.center': 'مرکز حساب',
'menu.account.settings': 'تنظیمات حساب',
'menu.account.trigger': 'خطای راه اندازی',
'menu.account.logout': 'خروج',
'menu.editor': 'ویرایشگر گرافیک',
'menu.editor.flow': 'ویرایشگر جریان',
'menu.editor.mind': 'ویرایشگر ذهن',
'menu.editor.koni': 'ویرایشگر Koni',
};
export default {
'pages.layouts.userLayout.title': 'طراحی مورچه تأثیرگذارترین مشخصات طراحی وب در منطقه Xihu است',
'pages.login.accountLogin.tab': 'ورود به حساب کاربری',
'pages.login.accountLogin.errorMessage': 'نام کاربری / رمزعبور نادرست (مدیر / ant.design)',
'pages.login.username.placeholder': 'نام کاربری: مدیر یا کاربر',
'pages.login.username.required': 'لطفا نام کاربری خود را وارد کنید!',
'pages.login.password.placeholder': 'رمز عبور: ant.design',
'pages.login.password.required': 'لطفاً رمز ورود خود را وارد کنید!',
'pages.login.phoneLogin.tab': 'ورود به سیستم تلفن',
'pages.login.phoneLogin.errorMessage': 'خطای کد تأیید',
'pages.login.phoneNumber.placeholder': 'شماره تلفن',
'pages.login.phoneNumber.required': 'لطفاً شماره تلفن خود را وارد کنید!',
'pages.login.phoneNumber.invalid': 'شماره تلفن نامعتبر است!',
'pages.login.captcha.placeholder': 'کد تایید',
'pages.login.captcha.required': 'لطفا کد تأیید را وارد کنید!',
'pages.login.phoneLogin.getVerificationCode': 'دریافت کد',
'pages.getCaptchaSecondText': 'ثانیه',
'pages.login.rememberMe': 'مرا به خاطر بسپار',
'pages.login.forgotPassword': 'رمز عبور را فراموش کرده اید ?',
'pages.login.submit': 'ارسال',
'pages.login.loginWith': 'وارد شوید با :',
'pages.login.registerAccount': 'ثبت نام',
'pages.welcome.advancedComponent': 'مولفه پیشرفته',
'pages.welcome.link': 'خوش آمدید',
'pages.welcome.advancedLayout': 'چیدمان پیشرفته',
'pages.welcome.alertMessage': 'اجزای سنگین تر سریعتر و قوی تر آزاد شده اند.',
'pages.admin.subPage.title': 'این صفحه فقط توسط مدیر قابل مشاهده است',
'pages.admin.subPage.alertMessage':
'رابط کاربری Umi اکنون منتشر شده است ، برای شروع تجربه استفاده از npm run ui خوش آمدید.',
'pages.searchTable.createForm.newRule': 'قانون جدید',
'pages.searchTable.updateForm.ruleConfig': 'پیکربندی قانون',
'pages.searchTable.updateForm.basicConfig': 'اطلاعات اولیه',
'pages.searchTable.updateForm.ruleName.nameLabel': ' نام قانون',
'pages.searchTable.updateForm.ruleName.nameRules': 'لطفاً نام قانون را وارد کنید!',
'pages.searchTable.updateForm.ruleDesc.descLabel': 'شرح قانون',
'pages.searchTable.updateForm.ruleDesc.descPlaceholder': 'لطفاً حداقل پنج حرف وارد کنید',
'pages.searchTable.updateForm.ruleDesc.descRules':
'لطفاً حداقل یک قانون حاوی پنج کاراکتر شرح دهید!',
'pages.searchTable.updateForm.ruleProps.title': 'پیکربندی خصوصیات',
'pages.searchTable.updateForm.object': 'نظارت بر شی',
'pages.searchTable.updateForm.ruleProps.templateLabel': 'الگوی قانون',
'pages.searchTable.updateForm.ruleProps.typeLabel': 'نوع قانون',
'pages.searchTable.updateForm.schedulingPeriod.title': 'تنظیم دوره زمان بندی',
'pages.searchTable.updateForm.schedulingPeriod.timeLabel': 'زمان شروع',
'pages.searchTable.updateForm.schedulingPeriod.timeRules': 'لطفاً زمان شروع را انتخاب کنید!',
'pages.searchTable.titleDesc': 'شرح',
'pages.searchTable.ruleName': 'نام قانون لازم است',
'pages.searchTable.titleCallNo': 'تعداد تماس های خدماتی',
'pages.searchTable.titleStatus': 'وضعیت',
'pages.searchTable.nameStatus.default': 'پیش فرض',
'pages.searchTable.nameStatus.running': 'در حال دویدن',
'pages.searchTable.nameStatus.online': 'برخط',
'pages.searchTable.nameStatus.abnormal': 'غیرطبیعی',
'pages.searchTable.titleUpdatedAt': 'آخرین برنامه ریزی در',
'pages.searchTable.exception': 'لطفا دلیل استثنا را وارد کنید!',
'pages.searchTable.titleOption': 'گزینه',
'pages.searchTable.config': 'پیکربندی',
'pages.searchTable.subscribeAlert': 'مشترک شدن در هشدارها',
'pages.searchTable.title': 'فرم درخواست',
'pages.searchTable.new': 'جدید',
'pages.searchTable.chosen': 'انتخاب شده',
'pages.searchTable.item': 'مورد',
'pages.searchTable.totalServiceCalls': 'تعداد کل تماس های خدماتی',
'pages.searchTable.tenThousand': '0000',
'pages.searchTable.batchDeletion': 'حذف دسته ای',
'pages.searchTable.batchApproval': 'تصویب دسته ای',
};
export default {
'app.pwa.offline': 'شما اکنون آفلاین هستید',
'app.pwa.serviceworker.updated': 'مطالب جدید در دسترس است',
'app.pwa.serviceworker.updated.hint':
'لطفاً برای بارگیری مجدد صفحه فعلی ، دکمه "تازه سازی" را فشار دهید',
'app.pwa.serviceworker.updated.ok': 'تازه سازی',
};
export default {
'app.setting.pagestyle': 'تنظیم نوع صفحه',
'app.setting.pagestyle.dark': 'سبک تیره',
'app.setting.pagestyle.light': 'سبک سبک',
'app.setting.content-width': 'عرض محتوا',
'app.setting.content-width.fixed': 'ثابت',
'app.setting.content-width.fluid': 'شناور',
'app.setting.themecolor': 'رنگ تم',
'app.setting.themecolor.dust': 'گرد و غبار قرمز',
'app.setting.themecolor.volcano': 'آتشفشان',
'app.setting.themecolor.sunset': 'غروب نارنجی',
'app.setting.themecolor.cyan': 'فیروزه ای',
'app.setting.themecolor.green': 'سبز قطبی',
'app.setting.themecolor.daybreak': 'آبی روشن(پیشفرض)',
'app.setting.themecolor.geekblue': 'چسب گیک',
'app.setting.themecolor.purple': 'بنفش طلایی',
'app.setting.navigationmode': 'حالت پیمایش',
'app.setting.sidemenu': 'طرح منوی کناری',
'app.setting.topmenu': 'طرح منوی بالایی',
'app.setting.fixedheader': 'سرصفحه ثابت',
'app.setting.fixedsidebar': 'نوار کناری ثابت',
'app.setting.fixedsidebar.hint': 'کار بر روی منوی کناری',
'app.setting.hideheader': 'هدر پنهان هنگام پیمایش',
'app.setting.hideheader.hint': 'وقتی Hidden Header فعال باشد کار می کند',
'app.setting.othersettings': 'تنظیمات دیگر',
'app.setting.weakmode': 'حالت ضعیف',
'app.setting.copy': 'تنظیمات کپی',
'app.setting.copyinfo':
'موفقیت در کپی کردن , لطفا defaultSettings را در src / models / setting.js جایگزین کنید',
'app.setting.production.hint':
'صفحه تنظیم فقط در محیط توسعه نمایش داده می شود ، لطفاً دستی تغییر دهید',
};
export default {
'app.settings.menuMap.basic': 'تنظیمات پایه ',
'app.settings.menuMap.security': 'تنظیمات امنیتی',
'app.settings.menuMap.binding': 'صحافی حساب',
'app.settings.menuMap.notification': 'اعلان پیام جدید',
'app.settings.basic.avatar': 'آواتار',
'app.settings.basic.change-avatar': 'آواتار را تغییر دهید',
'app.settings.basic.email': 'ایمیل',
'app.settings.basic.email-message': 'لطفا ایمیل خود را وارد کنید!',
'app.settings.basic.nickname': 'نام مستعار',
'app.settings.basic.nickname-message': 'لطفاً نام مستعار خود را وارد کنید!',
'app.settings.basic.profile': 'پروفایل شخصی',
'app.settings.basic.profile-message': 'لطفاً مشخصات شخصی خود را وارد کنید!',
'app.settings.basic.profile-placeholder': 'معرفی مختصر خودتان',
'app.settings.basic.country': 'کشور / منطقه',
'app.settings.basic.country-message': 'لطفاً کشور خود را وارد کنید!',
'app.settings.basic.geographic': 'استان یا شهر',
'app.settings.basic.geographic-message': 'لطفاً اطلاعات جغرافیایی خود را وارد کنید!',
'app.settings.basic.address': 'آدرس خیابان',
'app.settings.basic.address-message': 'لطفا آدرس خود را وارد کنید!',
'app.settings.basic.phone': 'شماره تلفن',
'app.settings.basic.phone-message': 'لطفاً تلفن خود را وارد کنید!',
'app.settings.basic.update': 'به روز رسانی اطلاعات',
'app.settings.security.strong': 'قوی',
'app.settings.security.medium': 'متوسط',
'app.settings.security.weak': 'ضعیف',
'app.settings.security.password': 'رمز عبور حساب کاربری',
'app.settings.security.password-description': 'قدرت رمز عبور فعلی',
'app.settings.security.phone': 'تلفن امنیتی',
'app.settings.security.phone-description': 'تلفن مقید',
'app.settings.security.question': 'سوال امنیتی',
'app.settings.security.question-description':
'سوال امنیتی تنظیم نشده است و سیاست امنیتی می تواند به طور موثر از امنیت حساب محافظت کند',
'app.settings.security.email': 'ایمیل پشتیبان',
'app.settings.security.email-description': 'ایمیل مقید',
'app.settings.security.mfa': 'دستگاه MFA',
'app.settings.security.mfa-description':
'دستگاه MFA بسته نشده ، پس از اتصال ، می تواند دو بار تأیید شود',
'app.settings.security.modify': 'تغییر',
'app.settings.security.set': 'تنظیم',
'app.settings.security.bind': 'بستن',
'app.settings.binding.taobao': 'اتصال Taobao',
'app.settings.binding.taobao-description': 'حساب Taobao در حال حاضر بسته نشده است',
'app.settings.binding.alipay': 'اتصال Alipay',
'app.settings.binding.alipay-description': 'حساب Alipay در حال حاضر بسته نشده است',
'app.settings.binding.dingding': 'اتصال DingTalk',
'app.settings.binding.dingding-description': 'حساب DingTalk در حال حاضر محدود نشده است',
'app.settings.binding.bind': 'بستن',
'app.settings.notification.password': 'رمز عبور حساب کاربری',
'app.settings.notification.password-description':
'پیام های سایر کاربران در قالب یک نامه ایستگاهی اعلام خواهد شد',
'app.settings.notification.messages': 'پیام های سیستم',
'app.settings.notification.messages-description':
'پیام های سیستم به صورت نامه ایستگاه مطلع می شوند',
'app.settings.notification.todo': 'اعلان کارها',
'app.settings.notification.todo-description':
'لیست کارها به صورت نامه ای از ایستگاه اطلاع داده می شود',
'app.settings.open': 'باز کن',
'app.settings.close': 'بستن',
};
import component from './id-ID/component';
import globalHeader from './id-ID/globalHeader';
import menu from './id-ID/menu';
import pwa from './id-ID/pwa';
import settingDrawer from './id-ID/settingDrawer';
import settings from './id-ID/settings';
import pages from './id-ID/pages';
export default {
'navbar.lang': 'Bahasa',
'layout.user.link.help': 'Bantuan',
'layout.user.link.privacy': 'Privasi',
'layout.user.link.terms': 'Ketentuan',
'app.preview.down.block': 'Unduh halaman ini dalam projek lokal anda',
'app.welcome.link.fetch-blocks': 'Dapatkan semua blok',
'app.welcome.link.block-list':
'Buat standar dengan cepat, halaman-halaman berdasarkan pengembangan `block`',
...globalHeader,
...menu,
...settingDrawer,
...settings,
...pwa,
...component,
...pages,
};
export default {
'component.tagSelect.expand': 'Perluas',
'component.tagSelect.collapse': 'Lipat',
'component.tagSelect.all': 'Semua',
};
export default {
'component.globalHeader.search': 'Pencarian',
'component.globalHeader.search.example1': 'Contoh 1 Pencarian',
'component.globalHeader.search.example2': 'Contoh 2 Pencarian',
'component.globalHeader.search.example3': 'Contoh 3 Pencarian',
'component.globalHeader.help': 'Bantuan',
'component.globalHeader.notification': 'Notifikasi',
'component.globalHeader.notification.empty': 'Anda telah membaca semua notifikasi',
'component.globalHeader.message': 'Pesan',
'component.globalHeader.message.empty': 'Anda telah membaca semua pesan.',
'component.globalHeader.event': 'Acara',
'component.globalHeader.event.empty': 'Anda telah melihat semua acara.',
'component.noticeIcon.clear': 'Kosongkan',
'component.noticeIcon.cleared': 'Berhasil dikosongkan',
'component.noticeIcon.empty': 'Tidak ada pemberitahuan',
'component.noticeIcon.view-more': 'Melihat lebih',
};
export default {
'menu.welcome': 'Selamat Datang',
'menu.more-blocks': 'Blocks Lainnya',
'menu.home': 'Halaman Awal',
'menu.admin': 'Admin',
'menu.admin.sub-page': 'Sub-Halaman',
'menu.login': 'Masuk',
'menu.register': 'Pendaftaran',
'menu.register.result': 'Hasil Pendaftaran',
'menu.dashboard': 'Dasbor',
'menu.dashboard.analysis': 'Analisis',
'menu.dashboard.monitor': 'Monitor',
'menu.dashboard.workplace': 'Workplace',
'menu.exception.403': '403',
'menu.exception.404': '404',
'menu.exception.500': '500',
'menu.form': 'Form',
'menu.form.basic-form': 'Form Dasar',
'menu.form.step-form': 'Form Bertahap',
'menu.form.step-form.info': 'Form Bertahap(menulis informasi yang dibagikan)',
'menu.form.step-form.confirm': 'Form Bertahap(konfirmasi informasi yang dibagikan)',
'menu.form.step-form.result': 'Form Bertahap(selesai)',
'menu.form.advanced-form': 'Form Lanjutan',
'menu.list': 'Daftar',
'menu.list.table-list': 'Tabel Pencarian',
'menu.list.basic-list': 'Daftar Dasar',
'menu.list.card-list': 'Daftar Kartu',
'menu.list.search-list': 'Daftar Pencarian',
'menu.list.search-list.articles': 'Daftar Pencarian(artikel)',
'menu.list.search-list.projects': 'Daftar Pencarian(projek)',
'menu.list.search-list.applications': 'Daftar Pencarian(aplikasi)',
'menu.profile': 'Profil',
'menu.profile.basic': 'Profil Dasar',
'menu.profile.advanced': 'Profile Lanjutan',
'menu.result': 'Hasil',
'menu.result.success': 'Sukses',
'menu.result.fail': 'Gagal',
'menu.exception': 'Pengecualian',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': 'Jalankan',
'menu.account': 'Akun',
'menu.account.center': 'Detail Akun',
'menu.account.settings': 'Pengaturan Akun',
'menu.account.trigger': 'Mengaktivasi Error',
'menu.account.logout': 'Keluar',
'menu.editor': 'Penyusun Grafis',
'menu.editor.flow': 'Penyusun Alur',
'menu.editor.mind': 'Penyusun Mind',
'menu.editor.koni': 'Penyusun Koni',
};
export default {
'pages.layouts.userLayout.title':
'Ant Design adalah spesifikasi desain Web yang paling berpengaruh di Kabupaten Xihu',
'pages.login.accountLogin.tab': 'Login dengan akun',
'pages.login.accountLogin.errorMessage': 'Nama pengguna dan kata sandi salah(admin/ant.design)',
'pages.login.username.placeholder': 'nama pengguna: admin atau user',
'pages.login.username.required': 'Nama pengguna harus diisi!',
'pages.login.password.placeholder': 'kata sandi: ant.design',
'pages.login.password.required': 'Kata sandi harus diisi!',
'pages.login.phoneLogin.tab': 'Login dengan ponsel',
'pages.login.phoneLogin.errorMessage': 'Kesalahan kode verifikasi',
'pages.login.phoneNumber.placeholder': 'masukkan nomor telepon',
'pages.login.phoneNumber.required': 'Nomor ponsel harus diisi!',
'pages.login.phoneNumber.invalid': 'Nomor ponsel tidak valid!',
'pages.login.captcha.placeholder': 'kode verifikasi',
'pages.login.captcha.required': 'Kode verifikasi diperlukan!',
'pages.login.phoneLogin.getVerificationCode': 'Dapatkan kode',
'pages.getCaptchaSecondText': 'detik tersisa',
'pages.login.rememberMe': 'Ingat saya',
'pages.login.forgotPassword': 'Lupa Kata Sandi?',
'pages.login.submit': 'Masuk',
'pages.login.loginWith': 'Masuk dengan :',
'pages.login.registerAccount': 'Daftar Akun',
'pages.welcome.advancedComponent': 'Formulir Lanjutan',
'pages.welcome.link': 'Selamat datang',
'pages.welcome.advancedLayout': 'Tata letak Lanjutan',
'pages.welcome.alertMessage':
'Komponen heavy-duty yang lebih cepat dan lebih kuat telah dirilis.',
'pages.admin.subPage.title': 'Halaman ini hanya dapat dilihat oleh admin',
'pages.admin.subPage.alertMessage':
'umi ui telah dirilis, silahkan gunakan npm run ui untuk memulai pengalaman.',
'pages.searchTable.createForm.newRule': 'Aturan baru',
'pages.searchTable.updateForm.ruleConfig': 'Konfigurasi aturan',
'pages.searchTable.updateForm.basicConfig': 'Informasi dasar',
'pages.searchTable.updateForm.ruleName.nameLabel': 'Nama aturan',
'pages.searchTable.updateForm.ruleName.nameRules': 'Harap masukkan nama aturan!',
'pages.searchTable.updateForm.ruleDesc.descLabel': 'Deskripsi aturan',
'pages.searchTable.updateForm.ruleDesc.descPlaceholder':
'Harap masukkan setidaknya lima karakter',
'pages.searchTable.updateForm.ruleDesc.descRules':
'Harap masukkan deskripsi aturan setidaknya lima karakter!',
'pages.searchTable.updateForm.ruleProps.title': 'Properti aturan',
'pages.searchTable.updateForm.object': 'Objek pemantauan',
'pages.searchTable.updateForm.ruleProps.templateLabel': 'Template aturan',
'pages.searchTable.updateForm.ruleProps.typeLabel': 'Jenis aturan',
'pages.searchTable.updateForm.schedulingPeriod.title': 'Periode penjadwalan',
'pages.searchTable.updateForm.schedulingPeriod.timeLabel': 'Waktu mulai',
'pages.searchTable.updateForm.schedulingPeriod.timeRules': 'Pilih waktu mulai!',
'pages.searchTable.titleDesc': 'deskripsi',
'pages.searchTable.ruleName': 'Nama aturan wajib diisi',
'pages.searchTable.titleCallNo': 'Jumlah panggilan',
'pages.searchTable.titleStatus': 'Status',
'pages.searchTable.nameStatus.default': 'default',
'pages.searchTable.nameStatus.running': 'menyala',
'pages.searchTable.nameStatus.online': 'online',
'pages.searchTable.nameStatus.abnormal': 'abnormal',
'pages.searchTable.titleUpdatedAt': 'Waktu terjadwal',
'pages.searchTable.exception': 'Harap masukkan alasan pengecualian!',
'pages.searchTable.titleOption': 'Pengoperasian',
'pages.searchTable.config': 'Konfigurasi',
'pages.searchTable.subscribeAlert': 'Berlangganan notifikasi',
'pages.searchTable.title': 'Formulir pertanyaan',
'pages.searchTable.new': 'Baru',
'pages.searchTable.chosen': 'Terpilih',
'pages.searchTable.item': 'item',
'pages.searchTable.totalServiceCalls': 'Jumlah total panggilan layanan',
'pages.searchTable.tenThousand': '0000',
'pages.searchTable.batchDeletion': 'Penghapusan batch',
'pages.searchTable.batchApproval': 'Persetujuan batch',
};
export default {
'app.pwa.offline': 'Koneksi anda terputus',
'app.pwa.serviceworker.updated': 'Konten baru sudah tersedia',
'app.pwa.serviceworker.updated.hint':
'Silahkan klik tombol "Refresh" untuk memuat ulang halaman ini',
'app.pwa.serviceworker.updated.ok': 'Memuat ulang',
};
export default {
'app.setting.pagestyle': 'Pengaturan style Halaman',
'app.setting.pagestyle.dark': 'Style Gelap',
'app.setting.pagestyle.light': 'Style Cerah',
'app.setting.content-width': 'Lebar Konten',
'app.setting.content-width.fixed': 'Tetap',
'app.setting.content-width.fluid': 'Fluid',
'app.setting.themecolor': 'Theme Color',
'app.setting.themecolor.dust': 'Dust Red',
'app.setting.themecolor.volcano': 'Volcano',
'app.setting.themecolor.sunset': 'Sunset Orange',
'app.setting.themecolor.cyan': 'Cyan',
'app.setting.themecolor.green': 'Polar Green',
'app.setting.themecolor.daybreak': 'Daybreak Blue (bawaan)',
'app.setting.themecolor.geekblue': 'Geek Glue',
'app.setting.themecolor.purple': 'Golden Purple',
'app.setting.navigationmode': 'Mode Navigasi',
'app.setting.sidemenu': 'Susunan Menu Samping',
'app.setting.topmenu': 'Susunan Menu Atas',
'app.setting.fixedheader': 'Header Tetap',
'app.setting.fixedsidebar': 'Sidebar Tetap',
'app.setting.fixedsidebar.hint': 'Berjalan pada Susunan Menu Samping',
'app.setting.hideheader': 'Sembunyikan Header ketika gulir ke bawah',
'app.setting.hideheader.hint': 'Bekerja ketika Header tersembunyi dimunculkan',
'app.setting.othersettings': 'Pengaturan Lainnya',
'app.setting.weakmode': 'Mode Lemah',
'app.setting.copy': 'Salin Pengaturan',
'app.setting.copyinfo':
'Berhasil disalin,tolong ubah defaultSettings pada src/models/setting.js',
'app.setting.production.hint':
'Panel pengaturan hanya muncul pada lingkungan pengembangan, silahkan modifikasi secara menual',
};
export default {
'app.settings.menuMap.basic': 'Pengaturan Dasar',
'app.settings.menuMap.security': 'Pengaturan Keamanan',
'app.settings.menuMap.binding': 'Pengikatan Akun',
'app.settings.menuMap.notification': 'Notifikasi Pesan Baru',
'app.settings.basic.avatar': 'Avatar',
'app.settings.basic.change-avatar': 'Ubah avatar',
'app.settings.basic.email': 'Email',
'app.settings.basic.email-message': 'Tolong masukkan email!',
'app.settings.basic.nickname': 'Nickname',
'app.settings.basic.nickname-message': 'Tolong masukkan Nickname!',
'app.settings.basic.profile': 'Profil Personal',
'app.settings.basic.profile-message': 'Tolong masukkan profil personal!',
'app.settings.basic.profile-placeholder': 'Perkenalan Singkat tentang Diri Anda',
'app.settings.basic.country': 'Negara/Wilayah',
'app.settings.basic.country-message': 'Tolong masukkan negara anda!',
'app.settings.basic.geographic': 'Provinsi atau kota',
'app.settings.basic.geographic-message': 'Tolong masukkan info geografis anda!',
'app.settings.basic.address': 'Alamat Jalan',
'app.settings.basic.address-message': 'Tolong masukkan Alamat Jalan anda!',
'app.settings.basic.phone': 'Nomor Ponsel',
'app.settings.basic.phone-message': 'Tolong masukkan Nomor Ponsel anda!',
'app.settings.basic.update': 'Perbarui Informasi',
'app.settings.security.strong': 'Kuat',
'app.settings.security.medium': 'Sedang',
'app.settings.security.weak': 'Lemah',
'app.settings.security.password': 'Kata Sandi Akun',
'app.settings.security.password-description': 'Kekuatan Kata Sandi saat ini',
'app.settings.security.phone': 'Keamanan Ponsel',
'app.settings.security.phone-description': 'Mengikat Ponsel',
'app.settings.security.question': 'Pertanyaan Keamanan',
'app.settings.security.question-description':
'Pertanyaan Keamanan belum diatur, dan kebijakan keamanan dapat melindungi akun secara efektif',
'app.settings.security.email': 'Email Cadangan',
'app.settings.security.email-description': 'Mengikat Email',
'app.settings.security.mfa': 'Perangka MFA',
'app.settings.security.mfa-description':
'Tidak mengikat Perangkat MFA, setelah diikat, dapat dikonfirmasi dua kali',
'app.settings.security.modify': 'Modifikasi',
'app.settings.security.set': 'Setel',
'app.settings.security.bind': 'Ikat',
'app.settings.binding.taobao': 'Mengikat Taobao',
'app.settings.binding.taobao-description': 'Tidak mengikat akun Taobao saat ini',
'app.settings.binding.alipay': 'Mengikat Alipay',
'app.settings.binding.alipay-description': 'Tidak mengikat akun Alipay saat ini',
'app.settings.binding.dingding': 'Mengikat DingTalk',
'app.settings.binding.dingding-description': 'Tidak mengikat akun DingTalk',
'app.settings.binding.bind': 'Ikat',
'app.settings.notification.password': 'Kata Sandi Akun',
'app.settings.notification.password-description':
'Pesan dari pengguna lain akan diberitahu dalam bentuk surat',
'app.settings.notification.messages': 'Pesan Sistem',
'app.settings.notification.messages-description':
'Pesan sistem akan diberitahu dalam bentuk surat',
'app.settings.notification.todo': 'Notifikasi daftar To-do',
'app.settings.notification.todo-description':
'Daftar to-do akan diberitahukan dalam bentuk surat dari stasiun',
'app.settings.open': 'Buka',
'app.settings.close': 'Tutup',
};
import globalHeader from './ja-JP/globalHeader';
import menu from './ja-JP/menu';
import settingDrawer from './ja-JP/settingDrawer';
import settings from './ja-JP/settings';
import pwa from './ja-JP/pwa';
import component from './ja-JP/component';
import pages from './ja-JP/pages';
export default {
'navBar.lang': '言語',
'layout.user.link.help': 'ヘルプ',
'layout.user.link.privacy': 'プライバシー',
'layout.user.link.terms': '利用規約',
'app.preview.down.block': 'このページをローカルプロジェクトにダウンロードしてください',
'app.welcome.link.fetch-blocks': '',
'app.welcome.link.block-list': '',
...globalHeader,
...menu,
...settingDrawer,
...settings,
...pwa,
...component,
...pages,
};
export default {
'component.tagSelect.expand': '展開',
'component.tagSelect.collapse': '折りたたむ',
'component.tagSelect.all': 'すべて',
};
export default {
'component.globalHeader.search': '検索',
'component.globalHeader.search.example1': '検索例1',
'component.globalHeader.search.example2': '検索例2',
'component.globalHeader.search.example3': '検索例3',
'component.globalHeader.help': 'ヘルプ',
'component.globalHeader.notification': '通知',
'component.globalHeader.notification.empty': 'すべての通知を表示しました。',
'component.globalHeader.message': 'メッセージ',
'component.globalHeader.message.empty': 'すべてのメッセージを表示しました。',
'component.globalHeader.event': 'イベント',
'component.globalHeader.event.empty': 'すべてのイベントを表示しました。',
'component.noticeIcon.clear': 'クリア',
'component.noticeIcon.cleared': 'クリア済み',
'component.noticeIcon.empty': '通知なし',
'component.noticeIcon.view-more': 'もっと見る',
};
export default {
'menu.welcome': 'ようこそ',
'menu.more-blocks': 'その他のブロック',
'menu.home': 'ホーム',
'menu.admin': '管理者',
'menu.admin.sub-page': 'サブページ',
'menu.login': 'ログイン',
'menu.register': '登録',
'menu.register.result': '登録結果',
'menu.dashboard': 'ダッシュボード',
'menu.dashboard.analysis': '分析',
'menu.dashboard.monitor': 'モニター',
'menu.dashboard.workplace': '職場',
'menu.exception.403': '403',
'menu.exception.404': '404',
'menu.exception.500': '500',
'menu.form': 'フォーム',
'menu.form.basic-form': '基本フォーム',
'menu.form.step-form': 'ステップフォーム',
'menu.form.step-form.info': 'ステップフォーム(転送情報の書き込み)',
'menu.form.step-form.confirm': 'ステップフォーム(転送情報の確認)',
'menu.form.step-form.result': 'ステップフォーム(完成)',
'menu.form.advanced-form': '高度なフォーム',
'menu.list': 'リスト',
'menu.list.table-list': '検索テーブル',
'menu.list.basic-list': '基本リスト',
'menu.list.card-list': 'カードリスト',
'menu.list.search-list': '検索リスト',
'menu.list.search-list.articles': '検索リスト(記事)',
'menu.list.search-list.projects': '検索リスト(プロジェクト)',
'menu.list.search-list.applications': '検索リスト(アプリ)',
'menu.profile': 'プロフィール',
'menu.profile.basic': '基本プロフィール',
'menu.profile.advanced': '高度なプロフィール',
'menu.result': '結果',
'menu.result.success': '成功',
'menu.result.fail': '失敗',
'menu.exception': '例外',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': 'トリガー',
'menu.account': 'アカウント',
'menu.account.center': 'アカウントセンター',
'menu.account.settings': 'アカウント設定',
'menu.account.trigger': 'トリガーエラー',
'menu.account.logout': 'ログアウト',
'menu.editor': 'グラフィックエディタ',
'menu.editor.flow': 'フローエディタ',
'menu.editor.mind': 'マインドエディター',
'menu.editor.koni': 'コニエディター',
};
export default {
'pages.layouts.userLayout.title': 'Ant Designは、西湖区で最も影響力のあるWebデザイン仕様です。',
'pages.login.accountLogin.tab': 'アカウントログイン',
'pages.login.accountLogin.errorMessage':
'ユーザー名/パスワードが正しくありません(admin/ant.design)',
'pages.login.username.placeholder': 'ユーザー名:adminまたはuser',
'pages.login.username.required': 'ユーザー名を入力してください!',
'pages.login.password.placeholder': 'パスワード:ant.design',
'pages.login.password.required': 'パスワードを入力してください!',
'pages.login.phoneLogin.tab': '電話ログイン',
'pages.login.phoneLogin.errorMessage': '検証コードエラー',
'pages.login.phoneNumber.placeholder': '電話番号',
'pages.login.phoneNumber.required': '電話番号を入力してください!',
'pages.login.phoneNumber.invalid': '電話番号が無効です!',
'pages.login.captcha.placeholder': '確認コード',
'pages.login.captcha.required': '確認コードを入力してください!',
'pages.login.phoneLogin.getVerificationCode': '確認コードを取得',
'pages.getCaptchaSecondText': '秒',
'pages.login.rememberMe': 'Remember me',
'pages.login.forgotPassword': 'パスワードをお忘れですか?',
'pages.login.submit': 'ログイン',
'pages.login.loginWith': 'その他のログイン方法:',
'pages.login.registerAccount': 'アカウント登録',
'pages.welcome.advancedComponent': '高度なコンポーネント',
'pages.welcome.link': 'ようこそ',
'pages.welcome.advancedLayout': '高度なレイアウト',
'pages.welcome.alertMessage': 'より高速で強力な頑丈なコンポーネントがリリースされました。',
'pages.admin.subPage.title': 'このページは管理者のみが表示できます',
'pages.admin.subPage.alertMessage':
'Umi uiがリリースされました。npm run uiを使用して体験してください。',
'pages.searchTable.createForm.newRule': '新しいルール',
'pages.searchTable.updateForm.ruleConfig': 'ルール構成',
'pages.searchTable.updateForm.basicConfig': '基本情報',
'pages.searchTable.updateForm.ruleName.nameLabel': 'ルール名',
'pages.searchTable.updateForm.ruleName.nameRules': 'ルール名を入力してください!',
'pages.searchTable.updateForm.ruleDesc.descLabel': 'ルールの説明',
'pages.searchTable.updateForm.ruleDesc.descPlaceholder': '5文字以上入力してください',
'pages.searchTable.updateForm.ruleDesc.descRules': '5文字以上のルールの説明を入力してください!',
'pages.searchTable.updateForm.ruleProps.title': 'プロパティの構成',
'pages.searchTable.updateForm.object': '監視対象',
'pages.searchTable.updateForm.ruleProps.templateLabel': 'ルールテンプレート',
'pages.searchTable.updateForm.ruleProps.typeLabel': 'ルールタイプ',
'pages.searchTable.updateForm.schedulingPeriod.title': 'スケジュール期間の設定',
'pages.searchTable.updateForm.schedulingPeriod.timeLabel': '開始時間',
'pages.searchTable.updateForm.schedulingPeriod.timeRules': '開始時間を選択してください!',
'pages.searchTable.titleDesc': '説明',
'pages.searchTable.ruleName': 'ルール名が必要です',
'pages.searchTable.titleCallNo': 'サービスコール数',
'pages.searchTable.titleStatus': 'ステータス',
'pages.searchTable.nameStatus.default': 'デフォルト',
'pages.searchTable.nameStatus.running': '起動中',
'pages.searchTable.nameStatus.online': 'オンライン',
'pages.searchTable.nameStatus.abnormal': '異常',
'pages.searchTable.titleUpdatedAt': '最終スケジュール',
'pages.searchTable.exception': '例外の理由を入力してください!',
'pages.searchTable.titleOption': 'オプション',
'pages.searchTable.config': '構成',
'pages.searchTable.subscribeAlert': 'アラートを購読する',
'pages.searchTable.title': 'お問い合わせフォーム',
'pages.searchTable.new': '新しい',
'pages.searchTable.chosen': '選んだ項目',
'pages.searchTable.item': '項目',
'pages.searchTable.totalServiceCalls': 'サービスコールの総数',
'pages.searchTable.tenThousand': '万',
'pages.searchTable.batchDeletion': 'バッチ削除',
'pages.searchTable.batchApproval': 'バッチ承認',
};
export default {
'app.pwa.offline': 'あなたは今オフラインです',
'app.pwa.serviceworker.updated': '新しいコンテンツが利用可能です',
'app.pwa.serviceworker.updated.hint':
'現在のページをリロードするには、「更新」ボタンを押してください',
'app.pwa.serviceworker.updated.ok': 'リフレッシュ',
};
export default {
'app.setting.pagestyle': 'ページスタイル設定',
'app.setting.pagestyle.dark': 'ダークスタイル',
'app.setting.pagestyle.light': 'ライトスタイル',
'app.setting.content-width': 'コンテンツの幅',
'app.setting.content-width.fixed': '固定',
'app.setting.content-width.fluid': '流体',
'app.setting.themecolor': 'テーマカラー',
'app.setting.themecolor.dust': 'ダストレッド',
'app.setting.themecolor.volcano': 'ボルケ-ノ',
'app.setting.themecolor.sunset': 'サンセットオレンジ',
'app.setting.themecolor.cyan': 'シアン',
'app.setting.themecolor.green': 'ポーラーグリーン',
'app.setting.themecolor.daybreak': '夜明けの青(デフォルト)',
'app.setting.themecolor.geekblue': 'ギーク ブルー',
'app.setting.themecolor.purple': 'ゴールデンパープル',
'app.setting.navigationmode': 'ナビゲーションモード',
'app.setting.sidemenu': 'サイドメニューのレイアウト',
'app.setting.topmenu': 'トップメニューのレイアウト',
'app.setting.fixedheader': '固定ヘッダー',
'app.setting.fixedsidebar': '固定サイドバー',
'app.setting.fixedsidebar.hint': 'サイドメニューのレイアウトで動作します',
'app.setting.hideheader': 'スクロール時の非表示ヘッダー',
'app.setting.hideheader.hint': '非表示ヘッダーが有効になっている場合に機能します',
'app.setting.othersettings': 'その他の設定',
'app.setting.weakmode': 'ウィークモード',
'app.setting.copy': 'コピー設定',
'app.setting.copyinfo':
'コピーが成功しました。src/models/setting.jsのdefaultSettingsを置き換えてください',
'app.setting.production.hint': '設定パネルは開発環境でのみ表示されます。手動で変更してください',
};
export default {
'app.settings.menuMap.basic': '基本設定',
'app.settings.menuMap.security': 'セキュリティ設定',
'app.settings.menuMap.binding': 'アカウントのバインド',
'app.settings.menuMap.notification': '新しいメッセージの通知',
'app.settings.basic.avatar': 'アバター',
'app.settings.basic.change-avatar': 'アバターを変更する',
'app.settings.basic.email': 'メール',
'app.settings.basic.email-message': 'メールアドレスを入力してください!',
'app.settings.basic.nickname': 'ニックネーム',
'app.settings.basic.nickname-message': 'ニックネームを入力してください!',
'app.settings.basic.profile': '個人プロフィール',
'app.settings.basic.profile-message': '個人プロフィールを入力してください!',
'app.settings.basic.profile-placeholder': '自己紹介',
'app.settings.basic.country': '国/地域',
'app.settings.basic.country-message': 'あなたの国を入力してください!',
'app.settings.basic.geographic': '州または市',
'app.settings.basic.geographic-message': '地理情報を入力してください!',
'app.settings.basic.address': '住所',
'app.settings.basic.address-message': '住所を入力してください!',
'app.settings.basic.phone': '電話番号',
'app.settings.basic.phone-message': '電話番号を入力してください!',
'app.settings.basic.update': '更新情報',
'app.settings.security.strong': '強い',
'app.settings.security.medium': 'ミディアム',
'app.settings.security.weak': '弱い',
'app.settings.security.password': 'アカウントパスワード',
'app.settings.security.password-description': '現在のパスワードの強度',
'app.settings.security.phone': 'セキュリティ電話番号',
'app.settings.security.phone-description': 'バインドされた電話番号',
'app.settings.security.question': '秘密の質問',
'app.settings.security.question-description':
'セキュリティの質問が設定されてません。セキュリティポリシーはアカウントのセキュリティを効果的に保護できます',
'app.settings.security.email': 'バックアップメール',
'app.settings.security.email-description': 'バインドされたメール',
'app.settings.security.mfa': '多要素認証デバイス',
'app.settings.security.mfa-description':
'バインドされていない多要素認証デバイスは、バインド後、2回確認できます',
'app.settings.security.modify': '変更する',
'app.settings.security.set': 'セットする',
'app.settings.security.bind': 'バインド',
'app.settings.binding.taobao': 'タオバオをバインドする',
'app.settings.binding.taobao-description': '現在バインドされていないタオバオアカウント',
'app.settings.binding.alipay': 'アリペイをバインドする',
'app.settings.binding.alipay-description': '現在バインドされていないアリペイアカウント',
'app.settings.binding.dingding': 'ディントークをバインドする',
'app.settings.binding.dingding-description': '現在バインドされていないディントークアカウント',
'app.settings.binding.bind': 'バインド',
'app.settings.notification.password': 'アカウントパスワード',
'app.settings.notification.password-description':
'他のユーザーからのメッセージは、ステーションレターの形式で通知されます',
'app.settings.notification.messages': 'システムメッセージ',
'app.settings.notification.messages-description':
'システムメッセージは、ステーションレターの形式で通知されます',
'app.settings.notification.todo': 'To Do(用事) 通知',
'app.settings.notification.todo-description': 'To Doタスクは、内部レターの形式で通知されます',
'app.settings.open': '開く',
'app.settings.close': '閉じる',
};
import component from './pt-BR/component';
import globalHeader from './pt-BR/globalHeader';
import menu from './pt-BR/menu';
import pwa from './pt-BR/pwa';
import settingDrawer from './pt-BR/settingDrawer';
import settings from './pt-BR/settings';
import pages from './pt-BR/pages';
export default {
'navBar.lang': 'Idiomas',
'layout.user.link.help': 'ajuda',
'layout.user.link.privacy': 'política de privacidade',
'layout.user.link.terms': 'termos de serviços',
'app.preview.down.block': 'Download this page to your local project',
...globalHeader,
...menu,
...settingDrawer,
...settings,
...pwa,
...component,
...pages,
};
export default {
'component.tagSelect.expand': 'Expandir',
'component.tagSelect.collapse': 'Diminuir',
'component.tagSelect.all': 'Todas',
};
export default {
'component.globalHeader.search': 'Busca',
'component.globalHeader.search.example1': 'Exemplo de busca 1',
'component.globalHeader.search.example2': 'Exemplo de busca 2',
'component.globalHeader.search.example3': 'Exemplo de busca 3',
'component.globalHeader.help': 'Ajuda',
'component.globalHeader.notification': 'Notificação',
'component.globalHeader.notification.empty': 'Você visualizou todas as notificações.',
'component.globalHeader.message': 'Mensagem',
'component.globalHeader.message.empty': 'Você visualizou todas as mensagens.',
'component.globalHeader.event': 'Evento',
'component.globalHeader.event.empty': 'Você visualizou todos os eventos.',
'component.noticeIcon.clear': 'Limpar',
'component.noticeIcon.cleared': 'Limpo',
'component.noticeIcon.empty': 'Sem notificações',
'component.noticeIcon.loaded': 'Carregado',
'component.noticeIcon.view-more': 'Veja mais',
};
export default {
'menu.welcome': 'Welcome',
'menu.more-blocks': 'More Blocks',
'menu.home': 'Início',
'menu.login': 'Login',
'menu.admin': 'Admin',
'menu.admin.sub-page': 'Sub-Page',
'menu.register': 'Registro',
'menu.register.result': 'Resultado de registro',
'menu.dashboard': 'Dashboard',
'menu.dashboard.analysis': 'Análise',
'menu.dashboard.monitor': 'Monitor',
'menu.dashboard.workplace': 'Ambiente de Trabalho',
'menu.exception.403': '403',
'menu.exception.404': '404',
'menu.exception.500': '500',
'menu.form': 'Formulário',
'menu.form.basic-form': 'Formulário Básico',
'menu.form.step-form': 'Formulário Assistido',
'menu.form.step-form.info': 'Formulário Assistido(gravar informações de transferência)',
'menu.form.step-form.confirm': 'Formulário Assistido(confirmar informações de transferência)',
'menu.form.step-form.result': 'Formulário Assistido(finalizado)',
'menu.form.advanced-form': 'Formulário Avançado',
'menu.list': 'Lista',
'menu.list.table-list': 'Tabela de Busca',
'menu.list.basic-list': 'Lista Básica',
'menu.list.card-list': 'Lista de Card',
'menu.list.search-list': 'Lista de Busca',
'menu.list.search-list.articles': 'Lista de Busca(artigos)',
'menu.list.search-list.projects': 'Lista de Busca(projetos)',
'menu.list.search-list.applications': 'Lista de Busca(aplicações)',
'menu.profile': 'Perfil',
'menu.profile.basic': 'Perfil Básico',
'menu.profile.advanced': 'Perfil Avançado',
'menu.result': 'Resultado',
'menu.result.success': 'Sucesso',
'menu.result.fail': 'Falha',
'menu.exception': 'Exceção',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': 'Disparar',
'menu.account': 'Conta',
'menu.account.center': 'Central da Conta',
'menu.account.settings': 'Configurar Conta',
'menu.account.trigger': 'Disparar Erro',
'menu.account.logout': 'Sair',
'menu.editor': 'Graphic Editor',
'menu.editor.flow': 'Flow Editor',
'menu.editor.mind': 'Mind Editor',
'menu.editor.koni': 'Koni Editor',
};
export default {
'pages.layouts.userLayout.title':
'Ant Design é a especificação de web design mais influente no distrito de Xihu',
'pages.login.accountLogin.tab': 'Login da conta',
'pages.login.accountLogin.errorMessage': 'usuário/senha incorreto(admin/ant.design)',
'pages.login.username.placeholder': 'Usuário: admin or user',
'pages.login.username.required': 'Por favor insira seu usuário!',
'pages.login.password.placeholder': 'Senha: ant.design',
'pages.login.password.required': 'Por favor insira sua senha!',
'pages.login.phoneLogin.tab': 'Login com Telefone',
'pages.login.phoneLogin.errorMessage': 'Erro de Código de Verificação',
'pages.login.phoneNumber.placeholder': 'Telefone',
'pages.login.phoneNumber.required': 'Por favor entre com seu telefone!',
'pages.login.phoneNumber.invalid': 'Telefone é inválido!',
'pages.login.captcha.placeholder': 'Código de Verificação',
'pages.login.captcha.required': 'Por favor entre com o código de verificação!',
'pages.login.phoneLogin.getVerificationCode': 'Obter Código',
'pages.getCaptchaSecondText': 'seg(s)',
'pages.login.rememberMe': 'Lembre-me',
'pages.login.forgotPassword': 'Perdeu a Senha ?',
'pages.login.submit': 'Enviar',
'pages.login.loginWith': 'Login com :',
'pages.login.registerAccount': 'Registra Conta',
'pages.welcome.advancedComponent': 'Componente Avançado',
'pages.welcome.link': 'Bem-vindo',
'pages.welcome.advancedLayout': 'Layout Avançado',
'pages.welcome.alertMessage': 'Componentes pesados mais rápidos e mais fortes foram lançados.',
'pages.admin.subPage.title': 'Esta página só pode ser vista pelo Admin',
'pages.admin.subPage.alertMessage':
'O Umi ui foi lançado, bem-vindo ao usar o npm run ui para iniciar a experiência.',
'pages.searchTable.createForm.newRule': 'Neva Regra',
'pages.searchTable.updateForm.ruleConfig': 'Configuração de Regra',
'pages.searchTable.updateForm.basicConfig': 'Informação básica',
'pages.searchTable.updateForm.ruleName.nameLabel': 'Nome da Regra',
'pages.searchTable.updateForm.ruleName.nameRules': 'Por favor entre com o nome da regra!',
'pages.searchTable.updateForm.ruleDesc.descLabel': 'Descrição da Regra',
'pages.searchTable.updateForm.ruleDesc.descPlaceholder':
'Por favor insira ao menos cinco caracteres',
'pages.searchTable.updateForm.ruleDesc.descRules':
'Insira uma descrição de regra de pelo menos cinco caracteres!',
'pages.searchTable.updateForm.ruleProps.title': 'Configurar Propriedades',
'pages.searchTable.updateForm.object': 'Objeto de Monitoramento',
'pages.searchTable.updateForm.ruleProps.templateLabel': 'Modelo de Regra',
'pages.searchTable.updateForm.ruleProps.typeLabel': 'Tipo de Regra',
'pages.searchTable.updateForm.schedulingPeriod.title': 'Definir Período de Agendamento',
'pages.searchTable.updateForm.schedulingPeriod.timeLabel': 'Hora de Início',
'pages.searchTable.updateForm.schedulingPeriod.timeRules':
'Por favor selecione um horáriod e início!',
'pages.searchTable.titleDesc': 'Descrição',
'pages.searchTable.ruleName': 'O nome da regra é obrigatório',
'pages.searchTable.titleCallNo': 'Número de chamadas de serviço',
'pages.searchTable.titleStatus': 'Status',
'pages.searchTable.nameStatus.default': 'padrão',
'pages.searchTable.nameStatus.running': 'executando',
'pages.searchTable.nameStatus.online': 'online',
'pages.searchTable.nameStatus.abnormal': 'anormal',
'pages.searchTable.titleUpdatedAt': 'Última programação em',
'pages.searchTable.exception': 'Por favor, indique o motivo da exceção!',
'pages.searchTable.titleOption': 'Opção',
'pages.searchTable.config': 'Configuração',
'pages.searchTable.subscribeAlert': 'Inscreva-se para receber alertas',
'pages.searchTable.title': 'Formulário de Consulta',
'pages.searchTable.new': 'Novo',
'pages.searchTable.chosen': 'selecionado',
'pages.searchTable.item': 'item',
'pages.searchTable.totalServiceCalls': 'Número total de chamadas de serviço',
'pages.searchTable.tenThousand': '0000',
'pages.searchTable.batchDeletion': 'deleção em lote',
'pages.searchTable.batchApproval': 'aprovação em lote',
};
export default {
'app.pwa.offline': 'Você está offline agora',
'app.pwa.serviceworker.updated': 'Novo conteúdo está disponível',
'app.pwa.serviceworker.updated.hint':
'Por favor, pressione o botão "Atualizar" para recarregar a página atual',
'app.pwa.serviceworker.updated.ok': 'Atualizar',
};
export default {
'app.setting.pagestyle': 'Configuração de estilo da página',
'app.setting.pagestyle.dark': 'Dark style',
'app.setting.pagestyle.light': 'Light style',
'app.setting.content-width': 'Largura do conteúdo',
'app.setting.content-width.fixed': 'Fixo',
'app.setting.content-width.fluid': 'Fluido',
'app.setting.themecolor': 'Cor do Tema',
'app.setting.themecolor.dust': 'Dust Red',
'app.setting.themecolor.volcano': 'Volcano',
'app.setting.themecolor.sunset': 'Sunset Orange',
'app.setting.themecolor.cyan': 'Cyan',
'app.setting.themecolor.green': 'Polar Green',
'app.setting.themecolor.daybreak': 'Daybreak Blue (default)',
'app.setting.themecolor.geekblue': 'Geek Glue',
'app.setting.themecolor.purple': 'Golden Purple',
'app.setting.navigationmode': 'Modo de Navegação',
'app.setting.sidemenu': 'Layout do Menu Lateral',
'app.setting.topmenu': 'Layout do Menu Superior',
'app.setting.fixedheader': 'Cabeçalho fixo',
'app.setting.fixedsidebar': 'Barra lateral fixa',
'app.setting.fixedsidebar.hint': 'Funciona no layout do menu lateral',
'app.setting.hideheader': 'Esconder o cabeçalho quando rolar',
'app.setting.hideheader.hint': 'Funciona quando o esconder cabeçalho está abilitado',
'app.setting.othersettings': 'Outras configurações',
'app.setting.weakmode': 'Weak Mode',
'app.setting.copy': 'Copiar Configuração',
'app.setting.copyinfo':
'copiado com sucesso,por favor trocar o defaultSettings em src/models/setting.js',
'app.setting.production.hint':
'O painel de configuração apenas é exibido no ambiente de desenvolvimento, por favor modifique manualmente o',
};
export default {
'app.settings.menuMap.basic': 'Configurações Básicas',
'app.settings.menuMap.security': 'Configurações de Segurança',
'app.settings.menuMap.binding': 'Vinculação de Conta',
'app.settings.menuMap.notification': 'Mensagens de Notificação',
'app.settings.basic.avatar': 'Avatar',
'app.settings.basic.change-avatar': 'Alterar avatar',
'app.settings.basic.email': 'Email',
'app.settings.basic.email-message': 'Por favor insira seu email!',
'app.settings.basic.nickname': 'Nome de usuário',
'app.settings.basic.nickname-message': 'Por favor insira seu nome de usuário!',
'app.settings.basic.profile': 'Perfil pessoal',
'app.settings.basic.profile-message': 'Por favor insira seu perfil pessoal!',
'app.settings.basic.profile-placeholder': 'Breve introdução sua',
'app.settings.basic.country': 'País/Região',
'app.settings.basic.country-message': 'Por favor insira país!',
'app.settings.basic.geographic': 'Província, estado ou cidade',
'app.settings.basic.geographic-message': 'Por favor insira suas informações geográficas!',
'app.settings.basic.address': 'Endereço',
'app.settings.basic.address-message': 'Por favor insira seu endereço!',
'app.settings.basic.phone': 'Número de telefone',
'app.settings.basic.phone-message': 'Por favor insira seu número de telefone!',
'app.settings.basic.update': 'Atualizar Informações',
'app.settings.security.strong': 'Forte',
'app.settings.security.medium': 'Média',
'app.settings.security.weak': 'Fraca',
'app.settings.security.password': 'Senha da Conta',
'app.settings.security.password-description': 'Força da senha',
'app.settings.security.phone': 'Telefone de Seguraça',
'app.settings.security.phone-description': 'Telefone vinculado',
'app.settings.security.question': 'Pergunta de Segurança',
'app.settings.security.question-description':
'A pergunta de segurança não está definida e a política de segurança pode proteger efetivamente a segurança da conta',
'app.settings.security.email': 'Email de Backup',
'app.settings.security.email-description': 'Email vinculado',
'app.settings.security.mfa': 'Dispositivo MFA',
'app.settings.security.mfa-description':
'O dispositivo MFA não vinculado, após a vinculação, pode ser confirmado duas vezes',
'app.settings.security.modify': 'Modificar',
'app.settings.security.set': 'Atribuir',
'app.settings.security.bind': 'Vincular',
'app.settings.binding.taobao': 'Vincular Taobao',
'app.settings.binding.taobao-description': 'Atualmente não vinculado à conta Taobao',
'app.settings.binding.alipay': 'Vincular Alipay',
'app.settings.binding.alipay-description': 'Atualmente não vinculado à conta Alipay',
'app.settings.binding.dingding': 'Vincular DingTalk',
'app.settings.binding.dingding-description': 'Atualmente não vinculado à conta DingTalk',
'app.settings.binding.bind': 'Vincular',
'app.settings.notification.password': 'Senha da Conta',
'app.settings.notification.password-description':
'Mensagens de outros usuários serão notificadas na forma de uma estação de letra',
'app.settings.notification.messages': 'Mensagens de Sistema',
'app.settings.notification.messages-description':
'Mensagens de sistema serão notificadas na forma de uma estação de letra',
'app.settings.notification.todo': 'Notificação de To-do',
'app.settings.notification.todo-description':
'A lista de to-do será notificada na forma de uma estação de letra',
'app.settings.open': 'Aberto',
'app.settings.close': 'Fechado',
};
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import component from './zh-CN/component';
import globalHeader from './zh-CN/globalHeader';
import menu from './zh-CN/menu';
......@@ -6,6 +25,7 @@ import request from './zh-CN/request';
import settingDrawer from './zh-CN/settingDrawer';
import settings from './zh-CN/settings';
import pages from './zh-CN/pages';
import button from './zh-CN/button';
export default {
'navBar.lang': '语言',
......@@ -24,4 +44,5 @@ export default {
...pwa,
...component,
...request,
...button,
};
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'button.create': '新建',
'button.close': '关闭',
'button.confirm': '确定',
'button.cancel': '取消',
};
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'component.tagSelect.expand': '展开',
'component.tagSelect.collapse': '收起',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'component.globalHeader.search': '站内搜索',
'component.globalHeader.search.example1': '搜索提示一',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'menu.welcome': '欢迎',
'menu.more-blocks': '更多区块',
'menu.about': '关于',
'menu.admin': '管理页',
'menu.admin.sub-page': '二级管理页',
'menu.login': '登录',
......@@ -45,34 +64,50 @@ export default {
'menu.account.settings': '个人设置',
'menu.account.trigger': '触发报错',
'menu.account.logout': '退出登录',
'menu.account.changePassword': '修改密码',
'menu.account.checkTenant': '切换租户',
'menu.editor': '图形编辑器',
'menu.editor.flow': '流程编辑器',
'menu.editor.mind': '脑图编辑器',
'menu.editor.koni': '拓扑编辑器',
'menu.demo': 'Demo 开发模板',
'menu.dev.flink': 'Flink 计算框架',
'menu.dev.flink.docs': '官方文档',
'menu.dev.ant-design': 'Ant Design UI框架',
'menu.dev.ant-design.docs': '官方文档',
'menu.dev.ant-design.preview': '官方预览',
'menu.datastudio': '数据开发',
'menu.devops': '运维中心',
'menu.job': '作业实例',
'menu.datacenter': '元数据中心',
'menu.datacenter.metadata': '元数据',
'menu.registration': '注册中心',
'menu.registration.cluster': '集群管理',
'menu.registration.cluster.clusterInstance': '集群实例管理',
'menu.registration.cluster.clusterConfiguration': '集群配置管理',
'menu.registration.jar': 'Jar 管理',
'menu.registration.database': '数据源管理',
'menu.registration.alert': '报警管理',
'menu.registration.alert.alertInstance': '报警实例管理',
'menu.registration.alert.alertGroup': '报警组管理',
'menu.registration.jar': 'Jar 管理',
'menu.registration.document': '文档管理',
'menu.registration.fragment': '全局变量管理',
'menu.datastudio': '数据开发',
'menu.devops': '运维中心',
'menu.job': '作业实例',
'menu.settings': '系统设置',
'menu.dev.flink': 'Flink 计算框架',
'menu.dev.flink.docs': '官方文档',
'menu.dev.ant-design': 'Ant Design UI框架',
'menu.dev.ant-design.docs': '官方文档',
'menu.dev.ant-design.preview': '官方预览',
'menu.datacenter': '元数据中心',
'menu.datacenter.metadata': '元数据',
'menu.authenticationcenter': '认证中心',
'menu.authenticationcenter.usermanager': '用户管理',
'menu.authenticationcenter.namespacemanager': '命名空间管理',
'menu.authenticationcenter.rolemanager': '角色管理',
'menu.authenticationcenter.tenantmanager': '租户管理',
'menu.settings': '配置中心',
'menu.settings.flinkConfig': 'Flink 配置',
'menu.about': '关于',
};
......@@ -23,6 +23,7 @@ export default {
'pages.login.accountLogin.errorMessage': '错误的用户名和密码(admin/admin)',
'pages.login.failure': '登录失败,请重试!',
'pages.login.success': '登录成功!',
'pages.login.chooseTenant': '请选择租户',
'pages.login.username.placeholder': '用户名: admin',
'pages.login.username.required': '用户名是必填项!',
'pages.login.password.placeholder': '密码: admin',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'app.pwa.offline': '当前处于离线状态',
'app.pwa.serviceworker.updated': '有新内容',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'app.request.error': '请求错误',
'app.request.200': '服务器成功返回请求的数据。',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'app.setting.pagestyle': '整体风格设置',
'app.setting.pagestyle.dark': '暗色菜单风格',
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export default {
'app.settings.menuMap.basic': '基本设置',
'app.settings.menuMap.security': '安全设置',
......
import component from './zh-TW/component';
import globalHeader from './zh-TW/globalHeader';
import menu from './zh-TW/menu';
import pwa from './zh-TW/pwa';
import settingDrawer from './zh-TW/settingDrawer';
import settings from './zh-TW/settings';
export default {
'navBar.lang': '語言',
'layout.user.link.help': '幫助',
'layout.user.link.privacy': '隱私',
'layout.user.link.terms': '條款',
'app.preview.down.block': '下載此頁面到本地項目',
...globalHeader,
...menu,
...settingDrawer,
...settings,
...pwa,
...component,
};
export default {
'component.tagSelect.expand': '展開',
'component.tagSelect.collapse': '收起',
'component.tagSelect.all': '全部',
};
export default {
'component.globalHeader.search': '站內搜索',
'component.globalHeader.search.example1': '搜索提示壹',
'component.globalHeader.search.example2': '搜索提示二',
'component.globalHeader.search.example3': '搜索提示三',
'component.globalHeader.help': '使用手冊',
'component.globalHeader.notification': '通知',
'component.globalHeader.notification.empty': '妳已查看所有通知',
'component.globalHeader.message': '消息',
'component.globalHeader.message.empty': '您已讀完所有消息',
'component.globalHeader.event': '待辦',
'component.globalHeader.event.empty': '妳已完成所有待辦',
'component.noticeIcon.clear': '清空',
'component.noticeIcon.cleared': '清空了',
'component.noticeIcon.empty': '暫無資料',
'component.noticeIcon.view-more': '查看更多',
};
export default {
'menu.welcome': '歡迎',
'menu.more-blocks': '更多區塊',
'menu.home': '首頁',
'menu.login': '登錄',
'menu.admin': '权限',
'menu.admin.sub-page': '二级管理页',
'menu.exception.403': '403',
'menu.exception.404': '404',
'menu.exception.500': '500',
'menu.register': '註冊',
'menu.register.result': '註冊結果',
'menu.dashboard': 'Dashboard',
'menu.dashboard.analysis': '分析頁',
'menu.dashboard.monitor': '監控頁',
'menu.dashboard.workplace': '工作臺',
'menu.form': '表單頁',
'menu.form.basic-form': '基礎表單',
'menu.form.step-form': '分步表單',
'menu.form.step-form.info': '分步表單(填寫轉賬信息)',
'menu.form.step-form.confirm': '分步表單(確認轉賬信息)',
'menu.form.step-form.result': '分步表單(完成)',
'menu.form.advanced-form': '高級表單',
'menu.list': '列表頁',
'menu.list.table-list': '查詢表格',
'menu.list.basic-list': '標淮列表',
'menu.list.card-list': '卡片列表',
'menu.list.search-list': '搜索列表',
'menu.list.search-list.articles': '搜索列表(文章)',
'menu.list.search-list.projects': '搜索列表(項目)',
'menu.list.search-list.applications': '搜索列表(應用)',
'menu.profile': '詳情頁',
'menu.profile.basic': '基礎詳情頁',
'menu.profile.advanced': '高級詳情頁',
'menu.result': '結果頁',
'menu.result.success': '成功頁',
'menu.result.fail': '失敗頁',
'menu.account': '個人頁',
'menu.account.center': '個人中心',
'menu.account.settings': '個人設置',
'menu.account.trigger': '觸發報錯',
'menu.account.logout': '退出登錄',
'menu.exception': '异常页',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': '触发错误',
'menu.editor': '圖形編輯器',
'menu.editor.flow': '流程編輯器',
'menu.editor.mind': '腦圖編輯器',
'menu.editor.koni': '拓撲編輯器',
'menu.demo': 'Demo 開發模板',
'menu.clusters': '集群中心',
'menu.clusters.cluster': '集群實例',
'menu.clusters.clusterConfiguration': '集群配製',
'menu.database': '數據源中心',
'menu.studio': 'FlinkSql IDE',
'menu.flinksqlstudio': 'FlinkSql Studio',
'menu.taskcenter': '作業中心',
'menu.taskcenter.task': '作業管理',
'menu.taskcenter.jar': 'Jar 管理',
'menu.document': '文檔中心',
'menu.settings': '系統設置',
'menu.dev.flink': 'Flink 計算框架',
'menu.dev.flink.docs': '官方文檔',
'menu.dev.ant-design': 'Ant Design UI框架',
'menu.dev.ant-design.docs': '官方文檔',
'menu.dev.ant-design.preview': '官方預覽',
};
export default {
'app.pwa.offline': '當前處於離線狀態',
'app.pwa.serviceworker.updated': '有新內容',
'app.pwa.serviceworker.updated.hint': '請點擊“刷新”按鈕或者手動刷新頁面',
'app.pwa.serviceworker.updated.ok': '刷新',
};
export default {
'app.setting.pagestyle': '整體風格設置',
'app.setting.pagestyle.dark': '暗色菜單風格',
'app.setting.pagestyle.light': '亮色菜單風格',
'app.setting.content-width': '內容區域寬度',
'app.setting.content-width.fixed': '定寬',
'app.setting.content-width.fluid': '流式',
'app.setting.themecolor': '主題色',
'app.setting.themecolor.dust': '薄暮',
'app.setting.themecolor.volcano': '火山',
'app.setting.themecolor.sunset': '日暮',
'app.setting.themecolor.cyan': '明青',
'app.setting.themecolor.green': '極光綠',
'app.setting.themecolor.daybreak': '拂曉藍(默認)',
'app.setting.themecolor.geekblue': '極客藍',
'app.setting.themecolor.purple': '醬紫',
'app.setting.navigationmode': '導航模式',
'app.setting.sidemenu': '側邊菜單布局',
'app.setting.topmenu': '頂部菜單布局',
'app.setting.fixedheader': '固定 Header',
'app.setting.fixedsidebar': '固定側邊菜單',
'app.setting.fixedsidebar.hint': '側邊菜單布局時可配置',
'app.setting.hideheader': '下滑時隱藏 Header',
'app.setting.hideheader.hint': '固定 Header 時可配置',
'app.setting.othersettings': '其他設置',
'app.setting.weakmode': '色弱模式',
'app.setting.copy': '拷貝設置',
'app.setting.copyinfo': '拷貝成功,請到 src/defaultSettings.js 中替換默認配置',
'app.setting.production.hint':
'配置欄只在開發環境用於預覽,生產環境不會展現,請拷貝後手動修改配置文件',
};
export default {
'app.settings.menuMap.basic': '基本設置',
'app.settings.menuMap.security': '安全設置',
'app.settings.menuMap.binding': '賬號綁定',
'app.settings.menuMap.notification': '新消息通知',
'app.settings.basic.avatar': '頭像',
'app.settings.basic.change-avatar': '更換頭像',
'app.settings.basic.email': '郵箱',
'app.settings.basic.email-message': '請輸入您的郵箱!',
'app.settings.basic.nickname': '昵稱',
'app.settings.basic.nickname-message': '請輸入您的昵稱!',
'app.settings.basic.profile': '個人簡介',
'app.settings.basic.profile-message': '請輸入個人簡介!',
'app.settings.basic.profile-placeholder': '個人簡介',
'app.settings.basic.country': '國家/地區',
'app.settings.basic.country-message': '請輸入您的國家或地區!',
'app.settings.basic.geographic': '所在省市',
'app.settings.basic.geographic-message': '請輸入您的所在省市!',
'app.settings.basic.address': '街道地址',
'app.settings.basic.address-message': '請輸入您的街道地址!',
'app.settings.basic.phone': '聯系電話',
'app.settings.basic.phone-message': '請輸入您的聯系電話!',
'app.settings.basic.update': '更新基本信息',
'app.settings.security.strong': '強',
'app.settings.security.medium': '中',
'app.settings.security.weak': '弱',
'app.settings.security.password': '賬戶密碼',
'app.settings.security.password-description': '當前密碼強度',
'app.settings.security.phone': '密保手機',
'app.settings.security.phone-description': '已綁定手機',
'app.settings.security.question': '密保問題',
'app.settings.security.question-description': '未設置密保問題,密保問題可有效保護賬戶安全',
'app.settings.security.email': '備用郵箱',
'app.settings.security.email-description': '已綁定郵箱',
'app.settings.security.mfa': 'MFA 設備',
'app.settings.security.mfa-description': '未綁定 MFA 設備,綁定後,可以進行二次確認',
'app.settings.security.modify': '修改',
'app.settings.security.set': '設置',
'app.settings.security.bind': '綁定',
'app.settings.binding.taobao': '綁定淘寶',
'app.settings.binding.taobao-description': '當前未綁定淘寶賬號',
'app.settings.binding.alipay': '綁定支付寶',
'app.settings.binding.alipay-description': '當前未綁定支付寶賬號',
'app.settings.binding.dingding': '綁定釘釘',
'app.settings.binding.dingding-description': '當前未綁定釘釘賬號',
'app.settings.binding.bind': '綁定',
'app.settings.notification.password': '賬戶密碼',
'app.settings.notification.password-description': '其他用戶的消息將以站內信的形式通知',
'app.settings.notification.messages': '系統消息',
'app.settings.notification.messages-description': '系統消息將以站內信的形式通知',
'app.settings.notification.todo': '待辦任務',
'app.settings.notification.todo-description': '待辦任務將以站內信的形式通知',
'app.settings.open': '開',
'app.settings.close': '關',
};
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, {useState} from 'react';
import {Button, Form, Input, Modal, Switch} from 'antd';
import {NameSpaceTableListItem} from "@/pages/AuthenticationCenter/data.d";
import {getStorageTenantId} from "@/components/Common/crud";
export type TenantFormProps = {
onCancel: (flag?: boolean) => void;
onSubmit: (values: Partial<NameSpaceTableListItem>) => void;
modalVisible: boolean;
values: Partial<NameSpaceTableListItem>;
};
const formLayout = {
labelCol: {span: 7},
wrapperCol: {span: 13},
};
const NameSpaceForm: React.FC<TenantFormProps> = (props) => {
const [form] = Form.useForm();
const [formVals, setFormVals] = useState<Partial<NameSpaceTableListItem>>({
id: props.values?.id,
tenantId: props.values?.tenantId,
namespaceCode: props.values?.namespaceCode,
enabled: props.values?.enabled,
note: props.values?.note,
createTime: props.values?.createTime,
updateTime: props.values?.updateTime,
});
const {
onSubmit: handleSubmit,
onCancel: handleModalVisible,
modalVisible,
} = props;
const submitForm = async () => {
const fieldsValue = await form.validateFields();
fieldsValue.id = formVals.id;
setFormVals({...formVals,...fieldsValue});
handleSubmit({...formVals,...fieldsValue});
};
const renderContent = (formValsPara: Partial<NameSpaceTableListItem>) => {
return (
<>
<Form.Item
name="namespaceCode"
label="命名空间编号"
rules={[{required: true, message: '请输入命名空间唯一编码!'}]}>
<Input placeholder="请输入命名空间唯一编码"/>
</Form.Item>
<Form.Item
hidden={true}
name="tenantId"
label="所属租户"
>
<Input disabled defaultValue={getStorageTenantId()}/>
</Form.Item>
<Form.Item
name="note"
label="注释"
>
<Input.TextArea placeholder="请输入描述信息" allowClear
autoSize={{minRows: 3, maxRows: 10}}/>
</Form.Item>
<Form.Item
name="enabled"
label="是否启用">
<Switch checkedChildren="启用" unCheckedChildren="禁用"
defaultChecked={formValsPara.enabled}/>
</Form.Item>
</>
);
};
const renderFooter = () => {
return (
<>
<Button onClick={() => handleModalVisible(false)}>取消</Button>
<Button type="primary" onClick={() => submitForm()}>
完成
</Button>
</>
);
};
return (
<Modal
width={640}
bodyStyle={{padding: '32px 40px 48px'}}
destroyOnClose
title={formVals.id ? "修改命名空间" : "创建命名空间"}
visible={modalVisible}
footer={renderFooter()}
onCancel={() => handleModalVisible()}
>
<Form
{...formLayout}
form={form}
initialValues={formVals}
>
{renderContent(formVals)}
</Form>
</Modal>
);
};
export default NameSpaceForm;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, {useRef, useState} from "react";
import {DownOutlined, PlusOutlined} from '@ant-design/icons';
import ProTable, {ActionType, ProColumns} from "@ant-design/pro-table";
import {Button, Drawer, Dropdown, Menu, Modal} from 'antd';
import {FooterToolbar, PageContainer} from '@ant-design/pro-layout';
import ProDescriptions from '@ant-design/pro-descriptions';
import {handleAddOrUpdate, handleRemove, queryData, updateEnabled} from "@/components/Common/crud";
import {NameSpaceTableListItem} from "@/pages/AuthenticationCenter/data.d";
import NameSpaceForm from "@/pages/AuthenticationCenter/NamespaceManager/components/NameSpaceForm";
const url = '/api/namespace';
const NameSpaceFormList: React.FC<{}> = (props: any) => {
const [row, setRow] = useState<NameSpaceTableListItem>();
const [formValues, setFormValues] = useState<NameSpaceTableListItem>();
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const [modalVisible, handleModalVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [selectedRowsState, setSelectedRows] = useState<NameSpaceTableListItem[]>([]);
const editAndDelete = (key: string | number, currentItem: NameSpaceTableListItem) => {
if (key === 'edit') {
handleUpdateModalVisible(true);
setFormValues(currentItem);
} else if (key === 'delete') {
Modal.confirm({
title: '删除命名空间',
content: '确定删除该命名空间吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, [currentItem]);
actionRef.current?.reloadAndRest?.();
}
});
}
};
const MoreBtn: React.FC<{
item: NameSpaceTableListItem;
}> = ({item}) => (
<Dropdown
overlay={
<Menu onClick={({key}) => editAndDelete(key, item)}>
<Menu.Item key="edit">编辑</Menu.Item>
<Menu.Item key="delete">删除</Menu.Item>
</Menu>
}
>
<a>
更多 <DownOutlined/>
</a>
</Dropdown>
);
const columns: ProColumns<NameSpaceTableListItem>[] = [
{
title: 'ID',
dataIndex: 'id',
hideInTable: true,
hideInSearch: true,
sorter: true,
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
{
title: '命名空间编码',
dataIndex: 'namespaceCode',
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
{
title: '所属租户',
hideInSearch: true,
render: (dom, entity) => {
return entity.tenant.tenantCode;
},
},
{
title: '是否启用',
dataIndex: 'enabled',
hideInTable: false,
hideInSearch: true,
filters: [
{
text: '已启用',
value: 1,
},
{
text: '未启用',
value: 0,
},
],
filterMultiple: false,
valueEnum: {
true: {text: '已启用', status: 'Success'},
false: {text: '未启用', status: 'Error'},
},
},
{
title: '备注',
dataIndex: 'note',
hideInSearch: true,
ellipsis: true,
},
{
title: '创建时间',
dataIndex: 'createTime',
sorter: true,
valueType: 'dateTime',
},
{
title: '最近更新时间',
dataIndex: 'updateTime',
sorter: true,
valueType: 'dateTime',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<a
onClick={() => {
handleUpdateModalVisible(true);
setFormValues(record);
}}
>
配置
</a>,
<MoreBtn key="more" item={record}/>,
],
},
];
return (
<PageContainer>
<ProTable<NameSpaceTableListItem>
headerTitle="命名空间管理"
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button type="primary" onClick={() => handleModalVisible(true)}>
<PlusOutlined/> 新建
</Button>,
]}
request={(params, sorter, filter) => queryData(url, {...params, sorter, filter})}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
已选择 <a style={{fontWeight: 600}}>{selectedRowsState.length}</a>&nbsp;&nbsp;
<span>
被禁用的命名空间共 {selectedRowsState.length - selectedRowsState.reduce((pre, item) => pre + (item.enabled ? 1 : 0), 0)}
</span>
</div>
}
>
<Button type="primary" danger
onClick={() => {
Modal.confirm({
title: '删除命名空间',
content: '确定删除选中的命名空间吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>
批量删除
</Button>
<Button type="primary"
onClick={() => {
Modal.confirm({
title: '启用命名空间',
content: '确定启用选中的命名空间吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, true);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量启用</Button>
<Button danger
onClick={() => {
Modal.confirm({
title: '禁用命名空间',
content: '确定禁用选中的命名空间吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, false);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量禁用</Button>
</FooterToolbar>
)}
<NameSpaceForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate(url, value);
if (success) {
handleModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleModalVisible(false);
}}
modalVisible={modalVisible}
values={{}}
/>
{
formValues && Object.keys(formValues).length ? (
<NameSpaceForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate(url, value);
if (success) {
handleUpdateModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
setFormValues({});
}}
modalVisible={updateModalVisible}
values={formValues}
/>
) : undefined
}
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.id && (
<ProDescriptions<NameSpaceTableListItem>
column={2}
title={row?.namespaceCode}
request={async () => ({
data: row || {},
})}
params={{
id: row?.id,
}}
columns={columns}
/>
)}
</Drawer>
</PageContainer>
);
};
export default NameSpaceFormList;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, {useState} from 'react';
import {Button, Form, Input, Modal, Select, Tag} from 'antd';
import {NameSpaceTableListItem, RoleTableListItem} from "@/pages/AuthenticationCenter/data.d";
import {getStorageTenantId} from "@/components/Common/crud";
import {connect} from "umi";
import {NameSpaceStateType} from "@/pages/AuthenticationCenter/RoleManager/model";
import {buildFormData, getFormData} from "@/pages/AuthenticationCenter/function";
export type TenantFormProps = {
onCancel: (flag?: boolean) => void;
onSubmit: (values: Partial<RoleTableListItem>) => void;
modalVisible: boolean;
values: Partial<RoleTableListItem>;
nameSpaces: NameSpaceTableListItem[];
};
const formLayout = {
labelCol: {span: 7},
wrapperCol: {span: 13},
};
const Option = Select.Option;
const RoleForm: React.FC<TenantFormProps> = (props) => {
const [form] = Form.useForm();
const [formVals, setFormVals] = useState<Partial<RoleTableListItem>>({
id: props.values?.id,
tenantId: props.values?.tenantId,
roleCode: props.values?.roleCode,
namespaceIds: props.values?.namespaceIds,
roleName: props.values?.roleName,
isDelete: props.values?.isDelete,
note: props.values?.note,
createTime: props.values?.createTime,
updateTime: props.values?.updateTime,
});
const {
onSubmit: handleSubmit,
onCancel: handleModalVisible,
modalVisible,
nameSpaces,
} = props;
const getNameSpaceOptions = () => {
const itemList: JSX.Element[] = [];
for (const item of nameSpaces) {
const tag = (
<>
<Tag color="processing">
{item.namespaceCode}
</Tag>
{/*{item.namespaceCode}*/}
</>);
itemList.push(<Option key={item.namespaceCode} value={item.id?.toString()} label={tag}>
{tag}
</Option>)
}
return itemList;
};
const submitForm = async () => {
const fieldsValue = await form.validateFields();
// fieldsValue.id = formVals.id;
fieldsValue.tenantId = getStorageTenantId();
setFormVals(buildFormData(formVals, fieldsValue));
handleSubmit(buildFormData(formVals, fieldsValue));
};
const renderContent = (formVals) => {
return (
<>
<Form.Item
name="roleCode"
label="角色编号"
rules={[{required: true, message: '请输入角色唯一编码!'}]}>
<Input placeholder="请输入角色唯一编码"/>
</Form.Item>
<Form.Item
name="roleName"
label="角色名称"
rules={[{required: true, message: '请输入角色名称!'}]}>
<Input placeholder="请输入角色名称"/>
</Form.Item>
<Form.Item
name="namespaceIds"
label="命名空间"
rules={[{required: true, message: '请选择命名空间!'}]}
>
<Select
mode="multiple"
style={{width: '100%'}}
placeholder="请选择命名空间"
optionLabelProp="label"
>
{getNameSpaceOptions()}
</Select>
</Form.Item>
<Form.Item
name="note"
label="注释"
>
<Input.TextArea placeholder="请输入文本注释" allowClear
autoSize={{minRows: 3, maxRows: 10}}/>
</Form.Item>
</>
);
};
const renderFooter = () => {
return (
<>
<Button onClick={() => handleModalVisible(false)}>取消</Button>
<Button type="primary" onClick={() => submitForm()}>
完成
</Button>
</>
);
};
return (
<Modal
width={1000}
bodyStyle={{padding: '32px 40px 48px'}}
destroyOnClose
title={formVals.id ? "修改角色" : "创建角色"}
visible={modalVisible}
footer={renderFooter()}
onCancel={() => handleModalVisible()}
>
<Form
{...formLayout}
form={form}
initialValues={getFormData(formVals)}
>
{renderContent(getFormData(formVals))}
</Form>
</Modal>
);
};
export default connect(({NameSpace}: { NameSpace: NameSpaceStateType }) => ({
nameSpaces: NameSpace.nameSpaces,
}))(RoleForm);
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, {useEffect, useRef, useState} from "react";
import {DownOutlined, PlusOutlined} from '@ant-design/icons';
import ProTable, {ActionType, ProColumns} from "@ant-design/pro-table";
import {Button, Drawer, Dropdown, Menu, Modal} from 'antd';
import {FooterToolbar, PageContainer} from '@ant-design/pro-layout';
import ProDescriptions from '@ant-design/pro-descriptions';
import {getStorageTenantId, handleAddOrUpdate, handleRemove, queryData} from "@/components/Common/crud";
import {RoleTableListItem} from "@/pages/AuthenticationCenter/data.d";
import RoleForm from "@/pages/AuthenticationCenter/RoleManager/components/RoleForm";
import {getNameSpaceList} from "@/pages/AuthenticationCenter/service";
import {connect} from "umi";
const url = '/api/role';
const RoleFormList: React.FC<{}> = (props: any) => {
const {dispatch} = props;
const [row, setRow] = useState<RoleTableListItem>();
const [formValues, setFormValues] = useState<RoleTableListItem>();
const [modalVisible, handleModalVisible] = useState<boolean>(false);
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [selectedRowsState, setSelectedRows] = useState<RoleTableListItem[]>([]);
useEffect(() => {
getNameSpaceList(dispatch);
}, []);
const editAndDelete = (key: string | number, currentItem: RoleTableListItem) => {
if (key === 'edit') {
setFormValues(currentItem);
handleUpdateModalVisible(true);
} else if (key === 'delete') {
Modal.confirm({
title: '删除角色',
content: '确定删除该角色吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, [currentItem]);
actionRef.current?.reloadAndRest?.();
}
});
}
};
const MoreBtn: React.FC<{
item: RoleTableListItem;
}> = ({item}) => (
<Dropdown
overlay={
<Menu onClick={({key}) => editAndDelete(key, item)}>
<Menu.Item key="edit">编辑</Menu.Item>
<Menu.Item key="delete">删除</Menu.Item>
</Menu>
}
>
<a>
更多 <DownOutlined/>
</a>
</Dropdown>
);
const columns: ProColumns<RoleTableListItem>[] = [
{
title: 'ID',
dataIndex: 'id',
hideInTable: true,
hideInSearch: true,
sorter: true,
},
{
title: '角色编码',
dataIndex: 'roleCode',
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
{
title: '角色名称',
dataIndex: 'roleName',
},
{
title: '所属租户',
hideInSearch: true,
render: (dom, entity) => {
return entity?.tenant?.tenantCode || '';
},
},
// {
// title: '是否删除',
// dataIndex: 'isDelete',
// hideInForm: true,
// hideInSearch: true,
// hideInTable: false,
// filters: [
// {
// text: '未删除',
// value: 0,
// },
// {
// text: '已删除',
// value: 1,
// },
// ],
// filterMultiple: false,
// valueEnum: {
// true: {text: '已删除', status: 'Error'},
// false: {text: '未删除', status: 'Success'},
// },
// },
{
title: '备注',
dataIndex: 'note',
hideInSearch: true,
ellipsis: true,
},
{
title: '创建时间',
dataIndex: 'createTime',
sorter: true,
valueType: 'dateTime',
},
{
title: '最近更新时间',
dataIndex: 'updateTime',
sorter: true,
valueType: 'dateTime',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<Button type={"link"}
onClick={() => {
handleUpdateModalVisible(true);
setFormValues(record);
}}
>
配置
</Button>,
<MoreBtn key="more" item={record}/>,
],
},
];
return (
<PageContainer>
<ProTable<RoleTableListItem>
headerTitle="角色管理"
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button type="primary" onClick={() => handleModalVisible(true)}>
<PlusOutlined/> 新建
</Button>,
]}
request={(params, sorter, filter) => queryData(url, {tenantId: getStorageTenantId(), sorter, filter})}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
已选择 <a style={{fontWeight: 600}}>{selectedRowsState.length}</a>
</div>
}
>
<Button type="primary" danger
onClick={() => {
Modal.confirm({
title: '删除角色',
content: '确定删除选中的角色吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>
批量删除
</Button>
</FooterToolbar>
)}
<RoleForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate(url, value);
if (success) {
handleModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleModalVisible(false);
}}
modalVisible={modalVisible}
values={{}}
/>
{
formValues && Object.keys(formValues).length ? (
<RoleForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate(url, value);
if (success) {
handleUpdateModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
setFormValues({});
}}
modalVisible={updateModalVisible}
values={formValues}
/>
) : undefined
}
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.id && (
<ProDescriptions<RoleTableListItem>
column={2}
title={row?.roleName}
request={async () => ({
data: row || {},
})}
params={{
id: row?.id,
}}
columns={columns}
/>
)}
</Drawer>
</PageContainer>
);
};
export default connect()(RoleFormList);
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import {NameSpaceTableListItem, RoleTableListItem} from "@/pages/AuthenticationCenter/data.d";
import {Reducer} from "@@/plugin-dva/connect";
export type NameSpaceStateType = {
role:RoleTableListItem[],
nameSpaces: NameSpaceTableListItem[],
};
export type NameSpaceModelType = {
namespace: string;
state: NameSpaceStateType;
effects: {
};
reducers: {
saveRole: Reducer<NameSpaceStateType>;
saveNameSpace: Reducer<NameSpaceStateType>;
};
};
const NameSpaceModel: NameSpaceModelType = {
namespace: 'NameSpace',
state: {
role:[],
nameSpaces:[],
},
effects: {
},
reducers: {
saveRole(state, {payload}) {
return {
...state,
role: payload,
};
},
saveNameSpace(state, {payload}) {
return {
...state,
nameSpaces: payload,
};
},
},
};
export default NameSpaceModel;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import {Table, Transfer} from 'antd';
import type {ColumnsType, TableRowSelection} from 'antd/es/table/interface';
import type {TransferProps} from 'antd/es/transfer';
import difference from 'lodash/difference';
import React, {useEffect, useState} from 'react';
import {getData} from "@/components/Common/crud";
import {Scrollbars} from 'react-custom-scrollbars';
import { TenantTableListItem, UserTableListItem} from "@/pages/AuthenticationCenter/data.d";
interface TableTransferProps extends TransferProps<UserTableListItem> {
dataSource: UserTableListItem[];
leftColumns: ColumnsType<UserTableListItem>;
rightColumns: ColumnsType<UserTableListItem>;
}
// Customize Table Transfer
const GrantTenantTransfer = ({leftColumns, rightColumns, ...restProps}: TableTransferProps) => (
<Transfer
titles={['未选', '已选']}
locale={{
itemUnit: "项",
itemsUnit: "项",
searchPlaceholder: "请输入用户名搜索",
}}
showSelectAll={false}
showSearch={true}
{...restProps}>
{({
direction,
filteredItems,
onItemSelectAll,
onItemSelect,
selectedKeys: listSelectedKeys,
disabled: enabled,
}) => {
const columns = direction === 'left' ? leftColumns : rightColumns;
const rowSelection: TableRowSelection<UserTableListItem> = {
getCheckboxProps: item => ({disabled: enabled || !item.enabled}),
onSelectAll: function (selected, selectedRows) {
const treeSelectedKeys = selectedRows
.filter(item => item.enabled)
.map(({id}) => id);
const diffKeys = selected
? difference(treeSelectedKeys, listSelectedKeys)
: difference(listSelectedKeys, treeSelectedKeys);
onItemSelectAll(diffKeys as string[], selected);
},
onSelect({id}, selected) {
onItemSelect(id as unknown as string, selected);
},
selectedRowKeys: listSelectedKeys,
};
return (<>
<Scrollbars style={{height: '520px', width: '100%'}}>
<Table
rowSelection={rowSelection}
columns={columns}
pagination={{
pageSize: 7,
}}
dataSource={filteredItems}
size="large"
rowKey='id'
style={{
height: '350px',
pointerEvents: enabled ? 'none' : undefined
}}
onRow={({id, enabled: itemDisabled}) => ({
onClick: (e) => {
if (itemDisabled || !enabled){
onItemSelect(id, listSelectedKeys.includes(id));
} else {
return;
}
},
})}
/>
</Scrollbars>
</>
);
}}
</Transfer>
);
export type TableTransferFromProps = {
tenant: Partial<TenantTableListItem>;
onChange: (values: string[]) => void;
};
const GrantTenantToUserTableTransferFrom = (props: TableTransferFromProps) => {
const {tenant, onChange: handleChange} = props;
const [targetKeys, setTargetKeys] = useState<string[]>([]);
const [userTableList, setUserTableList] = useState<UserTableListItem[]>([]);
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
const onSelectChange = (
sourceSelectedKeys: string[],
targetSelectedKeys: string[],
) => {
const newSelectedKeys = [...sourceSelectedKeys, ...targetSelectedKeys];
setSelectedKeys(newSelectedKeys);
};
useEffect(() => {
getData('/api/user/getUserListByTenantId', {id: tenant.id}).then(result => {
setUserTableList(result.datas.users);
setTargetKeys(result.datas.userIds);
handleChange(result.datas.userIds);
});
}, []);
const leftTableColumns: ColumnsType<UserTableListItem> = [
{
title: '用户名',
dataIndex: 'username',
},
{
title: '昵称',
dataIndex: 'nickname',
},
{
title: '工号',
dataIndex: 'worknum',
},
];
const rightTableColumns: ColumnsType<UserTableListItem> = [
{
title: '用户名',
dataIndex: 'username',
},
{
title: '昵称',
dataIndex: 'nickname',
},
{
title: '工号',
dataIndex: 'worknum',
},
];
const onChange = (nextTargetKeys: string[]) => {
setTargetKeys(nextTargetKeys);
handleChange(nextTargetKeys);
};
return (<>
<GrantTenantTransfer
dataSource={userTableList}
targetKeys={targetKeys}
selectedKeys={selectedKeys}
rowKey={item => item.id}
onChange={onChange}
onSelectChange={onSelectChange}
filterOption={(inputValue, item) =>
item.username!.indexOf(inputValue) !== -1
|| item.nickname!.indexOf(inputValue) !== -1
|| item.worknum!.indexOf(inputValue) !== -1
}
leftColumns={leftTableColumns}
rightColumns={rightTableColumns}
/>
</>
);
};
export default GrantTenantToUserTableTransferFrom;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, {useState} from 'react';
import {Button, Form, Input, Modal} from 'antd';
import {TenantTableListItem} from "@/pages/AuthenticationCenter/data.d";
export type TenantFormProps = {
onCancel: (flag?: boolean) => void;
onSubmit: (values: Partial<TenantTableListItem>) => void;
modalVisible: boolean;
values: Partial<TenantTableListItem>;
};
const formLayout = {
labelCol: {span: 7},
wrapperCol: {span: 13},
};
const FormItem = Form.Item;
const TenantForm: React.FC<TenantFormProps> = (props) => {
const [form] = Form.useForm();
const [formVals, setFormVals] = useState<Partial<TenantTableListItem>>({
id: props.values.id,
tenantCode: props.values.tenantCode,
isDelete: props.values.isDelete,
note: props.values.note,
createTime: props.values.createTime,
updateTime: props.values.updateTime,
});
const {
onSubmit: handleSubmit,
onCancel: handleModalVisible,
modalVisible,
} = props;
const submitForm = async () => {
const fieldsValue = await form.validateFields();
fieldsValue.id = formVals.id;
setFormVals({...formVals,...fieldsValue});
handleSubmit({...formVals,...fieldsValue});
};
const renderContent = (formVals: Partial<TenantTableListItem>) => {
return (
<>
<FormItem
name="tenantCode"
label="唯一编码"
rules={[{required: true, message: '请输入租户唯一编码!'}]}>
<Input allowClear placeholder="请输入租户唯一编码"/>
</FormItem>
<FormItem
name="note"
label="注释"
rules={[{required: true, message: '请输入租户注释/描述信息!'}]}
>
<Input.TextArea placeholder="请输入租户注释/描述信息" allowClear
autoSize={{minRows: 3, maxRows: 10}}/>
</FormItem>
</>
);
};
const renderFooter = () => {
return (
<>
<Button onClick={() => handleModalVisible(false)}>取消</Button>
<Button type="primary" onClick={() => submitForm()}>
完成
</Button>
</>
);
};
return (
<Modal
width={640}
bodyStyle={{padding: '32px 40px 48px'}}
destroyOnClose
title={formVals.id ? "修改租户" : "创建租户"}
visible={modalVisible}
footer={renderFooter()}
onCancel={() => handleModalVisible()}
>
<Form
{...formLayout}
form={form}
initialValues={formVals}
>
{renderContent(formVals)}
</Form>
</Modal>
);
};
export default TenantForm;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, {useRef, useState} from "react";
import {DownOutlined, PlusOutlined} from '@ant-design/icons';
import ProTable, {ActionType, ProColumns} from "@ant-design/pro-table";
import {Button, Drawer, Dropdown, Menu, Modal} from 'antd';
import {FooterToolbar, PageContainer} from '@ant-design/pro-layout';
import ProDescriptions from '@ant-design/pro-descriptions';
import {handleAddOrUpdate, handleRemove, queryData} from "@/components/Common/crud";
import {TenantTableListItem} from "@/pages/AuthenticationCenter/data.d";
import TenantForm from "@/pages/AuthenticationCenter/TenantManager/components/TenantForm";
import GrantTenantTransfer from "@/pages/AuthenticationCenter/TenantManager/components/GrantTenantTransfer";
const url = '/api/tenant';
const TenantFormList: React.FC<{}> = (props: any) => {
const [row, setRow] = useState<TenantTableListItem>();
const [handleGrantTenant, setHandleGrantTenant] = useState<boolean>(false);
const [tenantRelFormValues, setTenantRelFormValues] = useState({});
const [modalVisible, handleModalVisible] = useState<boolean>(false);
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const actionRef = useRef<ActionType>();
const [selectedRowsState, setSelectedRows] = useState<TenantTableListItem[]>([]);
const [formValues, setFormValues] = useState({});
const editAndDelete = (key: string | number, currentItem: TenantTableListItem) => {
if (key === 'edit') {
handleUpdateModalVisible(true);
setFormValues(currentItem);
} else if (key === 'delete') {
Modal.confirm({
title: '删除租户',
content: '确定删除该租户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, [currentItem]);
actionRef.current?.reloadAndRest?.();
}
});
}
};
const MoreBtn: React.FC<{
item: TenantTableListItem;
}> = ({item}) => (
<Dropdown
overlay={
<Menu onClick={({key}) => editAndDelete(key, item)}>
<Menu.Item key="edit">编辑</Menu.Item>
<Menu.Item key="delete">删除</Menu.Item>
</Menu>
}
>
<a>
更多 <DownOutlined/>
</a>
</Dropdown>
);
const handleGrantTenantForm = () => {
return (
<Modal title="分配用户" visible={handleGrantTenant} destroyOnClose={true} width={"1500px"}
onCancel={() => {
setHandleGrantTenant(false);
}}
footer={[
<Button key="back" onClick={() => {
setHandleGrantTenant(false);
}}>
关闭
</Button>,
<Button type="primary" onClick={async () => {
// to save
const success = await handleAddOrUpdate(url+ "/grantTenantToUser", {
tenantId: formValues.id,
users: tenantRelFormValues
});
if (success) {
setHandleGrantTenant(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
>
确认
</Button>,
]}>
<GrantTenantTransfer tenant={formValues} onChange={(value) => {
setTenantRelFormValues(value);
}}/>
</Modal>
)
}
const columns: ProColumns<TenantTableListItem>[] = [
{
title: 'ID',
dataIndex: 'id',
hideInTable: true,
hideInSearch: true,
sorter: true,
},
{
title: '租户编码',
tip: '编码是唯一的',
dataIndex: 'tenantCode',
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
// {
// title: '是否删除',
// dataIndex: 'isDelete',
// hideInForm: true,
// hideInSearch: true,
// hideInTable: false,
// filters: [
// {
// text: '未删除',
// value: 0,
// },
// {
// text: '已删除',
// value: 1,
// },
// ],
// filterMultiple: false,
// valueEnum: {
// true: {text: '已删除', status: 'Error'},
// false: {text: '未删除', status: 'Success'},
// },
// },
{
title: '备注',
dataIndex: 'note',
hideInSearch: true,
ellipsis: true,
},
{
title: '创建时间',
dataIndex: 'createTime',
valueType: 'dateTime',
},
{
title: '最近更新时间',
dataIndex: 'updateTime',
valueType: 'dateTime',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record:TenantTableListItem) => [
<a
onClick={() => {
handleUpdateModalVisible(true);
setFormValues(record);
}}
>
配置
</a>,
<a
onClick={() => {
setHandleGrantTenant(true);
setFormValues(record);
}}
>
分配用户
</a>,
<MoreBtn key="more" item={record}/>,
],
},
];
return (
<PageContainer>
<ProTable<TenantTableListItem>
headerTitle="租户管理"
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button type="primary" onClick={() => handleModalVisible(true)}>
<PlusOutlined/> 新建
</Button>,
]}
request={(params, sorter, filter) => queryData(url, {...params, sorter, filter})}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
已选择 <a style={{fontWeight: 600}}>{selectedRowsState.length}</a>
</div>
}
>
<Button type="primary" danger
onClick={() => {
Modal.confirm({
title: '删除租户',
content: '确定删除选中的租户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>
批量删除
</Button>
</FooterToolbar>
)}
<TenantForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate(url, value);
if (success) {
handleModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleModalVisible(false);
}}
modalVisible={modalVisible}
values={{}}
/>
{
formValues && Object.keys(formValues).length ? (
<TenantForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate(url, value);
if (success) {
handleUpdateModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
setFormValues({});
}}
modalVisible={updateModalVisible}
values={formValues}
/>
) : undefined
}
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.tenantCode && (
<ProDescriptions<TenantTableListItem>
column={2}
title={row?.tenantCode}
request={async () => ({
data: row || {},
})}
params={{
id: row?.id,
}}
columns={columns}
/>
)}
</Drawer>
{handleGrantTenantForm()}
</PageContainer>
);
};
export default TenantFormList;
......@@ -19,8 +19,8 @@
import React, {useState} from 'react';
import {Form, Button, Input, Modal} from 'antd';
import {PasswordItem} from "@/pages/user/data";
import {Button, Form, Input, Modal} from 'antd';
import {PasswordItem} from "@/pages/AuthenticationCenter/data.d";
import { useIntl, Link, history, FormattedMessage, SelectLang} from 'umi';
export type PasswordFormProps = {
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import {Table, Transfer} from 'antd';
import type {ColumnsType, TableRowSelection} from 'antd/es/table/interface';
import type {TransferProps} from 'antd/es/transfer';
import difference from 'lodash/difference';
import {useEffect, useState} from 'react';
import {getData} from "@/components/Common/crud";
import {Scrollbars} from 'react-custom-scrollbars';
import {RoleTableListItem, UserTableListItem} from "@/pages/AuthenticationCenter/data.d";
interface TableTransferProps extends TransferProps<RoleTableListItem> {
dataSource: RoleTableListItem[];
leftColumns: ColumnsType<RoleTableListItem>;
rightColumns: ColumnsType<RoleTableListItem>;
}
// Customize Table Transfer
const TableTransfer = ({leftColumns, rightColumns, ...restProps}: TableTransferProps) => (
<Transfer
titles={['未选', '已选']}
locale={{
itemUnit: "项",
itemsUnit: "项",
searchPlaceholder: "请输入角色名称搜索",
}}
showSelectAll={false}
showSearch={true}
{...restProps}>
{({
direction,
filteredItems,
onItemSelectAll,
onItemSelect,
selectedKeys: listSelectedKeys,
disabled: isDelete,
}) => {
const columns = direction === 'left' ? leftColumns : rightColumns;
const rowSelection: TableRowSelection<RoleTableListItem> = {
getCheckboxProps: item => ({disabled: isDelete || item.isDelete}),
onSelectAll: function (selected, selectedRows) {
const treeSelectedKeys = selectedRows
.filter(item => !item.isDelete)
.map(({id}) => id);
const diffKeys = selected
? difference(treeSelectedKeys, listSelectedKeys)
: difference(listSelectedKeys, treeSelectedKeys);
onItemSelectAll(diffKeys as string[], selected);
},
onSelect({id}, selected) {
onItemSelect(id as unknown as string, selected);
},
selectedRowKeys: listSelectedKeys,
};
return (<>
<Scrollbars style={{height: '520px', width: '100%'}}>
<Table
rowSelection={rowSelection}
columns={columns}
pagination={{
pageSize: 7,
}}
dataSource={filteredItems}
size="large"
rowKey='id'
style={{
height: '350px',
pointerEvents: isDelete ? 'none' : undefined
}}
onRow={({id, isDelete: itemDisabled}) => ({
onClick: () => {
if (itemDisabled || isDelete) return;
onItemSelect(id, !listSelectedKeys.includes(id));
},
})}
/>
</Scrollbars>
</>
);
}}
</Transfer>
);
export type TableTransferFromProps = {
user: Partial<UserTableListItem>;
onChange: (values: string[]) => void;
};
const TableTransferFrom = (props: TableTransferFromProps) => {
const {user, onChange: handleChange} = props;
const [targetKeys, setTargetKeys] = useState<string[]>([]);
const [roleTableList, setRoleTableList] = useState<RoleTableListItem[]>([]);
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
const onSelectChange = (
sourceSelectedKeys: string[],
targetSelectedKeys: string[],
) => {
const newSelectedKeys = [...sourceSelectedKeys, ...targetSelectedKeys];
setSelectedKeys(newSelectedKeys);
};
useEffect(() => {
getData('/api/role/getRolesAndIdsByUserId', {id: user.id}).then(result => {
setRoleTableList(result.datas.roles);
setTargetKeys(result.datas.roleIds);
handleChange(result.datas.roleIds);
});
}, []);
const leftTableColumns: ColumnsType<RoleTableListItem> = [
{
dataIndex: 'roleCode',
title: '角色编码',
},
{
dataIndex: 'roleName',
title: '角色名称',
},
{
dataIndex: 'note',
title: '描述',
ellipsis: true,
},
];
const rightTableColumns: ColumnsType<RoleTableListItem> = [
{
dataIndex: 'roleCode',
title: '角色编码',
},
{
dataIndex: 'roleName',
title: '角色名称',
},
{
dataIndex: 'note',
title: '描述',
ellipsis: true,
},
];
const onChange = (nextTargetKeys: string[]) => {
setTargetKeys(nextTargetKeys);
handleChange(nextTargetKeys);
};
return (<>
<TableTransfer
dataSource={roleTableList}
targetKeys={targetKeys}
selectedKeys={selectedKeys}
rowKey={item => item.id}
onChange={onChange}
onSelectChange={onSelectChange}
filterOption={(inputValue, item) =>
item.roleCode!.indexOf(inputValue) !== -1 || item.roleName!.indexOf(inputValue) !== -1
}
leftColumns={leftTableColumns}
rightColumns={rightTableColumns}
/>
</>
);
};
export default TableTransferFrom;
......@@ -19,8 +19,8 @@
import React, {useState} from 'react';
import {Form, Button, Input, Modal, Switch} from 'antd';
import {UserTableListItem} from "@/pages/user/data";
import {Button, Form, Input, Modal, Switch} from 'antd';
import {UserTableListItem} from "@/pages/AuthenticationCenter/data.d";
import { useIntl, Link, history, FormattedMessage, SelectLang} from 'umi';
export type UserFormProps = {
......@@ -64,7 +64,7 @@ const UserForm: React.FC<UserFormProps> = (props) => {
handleSubmit({ ...formVals, ...fieldsValue });
};
const renderContent = (formVals) => {
const renderContent = (formVals: Partial<UserTableListItem>) => {
return (
<>
<Form.Item
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, {useRef, useState} from "react";
import {DownOutlined, PlusOutlined} from '@ant-design/icons';
import ProTable, {ActionType, ProColumns} from "@ant-design/pro-table";
import {Button, Drawer, Dropdown, Menu, Modal} from 'antd';
import {FooterToolbar, PageContainer} from '@ant-design/pro-layout';
import ProDescriptions from '@ant-design/pro-descriptions';
import {handleAddOrUpdate, handleOption, handleRemove, queryData, updateEnabled} from "@/components/Common/crud";
import {UserTableListItem} from "@/pages/AuthenticationCenter/data.d";
import UserForm from "@/pages/AuthenticationCenter/UserManager/components/UserForm";
import PasswordForm from "@/pages/AuthenticationCenter/UserManager/components/PasswordForm";
import TableTransferFrom from "@/pages/AuthenticationCenter/UserManager/components/TableTransfer";
const url = '/api/user';
const UserTableList: React.FC<{}> = (props: any) => {
const {dispatch} = props;
const [row, setRow] = useState<UserTableListItem>();
const [modalVisible, handleModalVisible] = useState<boolean>(false);
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const [handleGrantRole, setHandleGrantRole] = useState<boolean>(false);
const [passwordModalVisible, handlePasswordModalVisible] = useState<boolean>(false);
const [formValues, setFormValues] = useState({});
const [roleRelFormValues, setRoleRelFormValues] = useState({});
const actionRef = useRef<ActionType>();
const [selectedRowsState, setSelectedRows] = useState<UserTableListItem[]>([]);
const editAndDelete = (key: string | number, currentItem: UserTableListItem) => {
if (key === 'edit') {
setFormValues(currentItem);
handleUpdateModalVisible(true);
} else if (key === 'password') {
setFormValues(currentItem);
handlePasswordModalVisible(true);
} else if (key === 'delete') {
Modal.confirm({
title: '删除用户',
content: '确定删除该用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, [currentItem]);
actionRef.current?.reloadAndRest?.();
}
});
}
};
const MoreBtn: React.FC<{
item: UserTableListItem;
}> = ({item}) => (
<Dropdown
overlay={
<Menu onClick={({key}) => editAndDelete(key, item)}>
<Menu.Item key="edit">编辑</Menu.Item>
<Menu.Item key="password">修改密码</Menu.Item>
{item.username == 'admin' ? '' : (<Menu.Item key="delete">删除</Menu.Item>)}
</Menu>
}
>
<a>
更多 <DownOutlined/>
</a>
</Dropdown>
);
const handleGrantRoleForm = () => {
return (
<Modal title="添加角色" visible={handleGrantRole} destroyOnClose={true} width={"1500px"}
onCancel={() => {
setHandleGrantRole(false);
}}
footer={[
<Button key="back" onClick={() => {
setHandleGrantRole(false);
}}>
关闭
</Button>,
<Button type="primary" onClick={async () => {
// to save
const success = await handleAddOrUpdate("api/user/grantRole", {
userId: formValues.id,
roles: roleRelFormValues
});
if (success) {
setHandleGrantRole(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
>
确认
</Button>,
]}>
<TableTransferFrom user={formValues} onChange={(value) => {
setRoleRelFormValues(value);
}}/>
</Modal>
)
}
const columns: ProColumns<UserTableListItem>[] = [
{
title: '用户名',
dataIndex: 'username',
sorter: true,
render: (dom, entity) => {
return <a onClick={() => setRow(entity)}>{dom}</a>;
},
},
{
title: '用户ID',
dataIndex: 'id',
hideInTable: true,
hideInForm: true,
hideInSearch: true,
},
{
title: '昵称',
sorter: true,
dataIndex: 'nickname',
hideInTable: false,
},
{
title: '工号',
sorter: true,
dataIndex: 'worknum',
hideInTable: false,
},
{
title: '手机号',
sorter: true,
dataIndex: 'mobile',
hideInTable: false,
},
{
title: '是否启用',
dataIndex: 'enabled',
hideInForm: true,
hideInSearch: true,
hideInTable: false,
filters: [
{
text: '已启用',
value: 1,
},
{
text: '已禁用',
value: 0,
},
],
filterMultiple: false,
valueEnum: {
true: {text: '已启用', status: 'Success'},
false: {text: '已禁用', status: 'Error'},
},
},
{
title: '创建时间',
dataIndex: 'createTime',
sorter: true,
valueType: 'dateTime',
hideInTable: true,
},
{
title: '最近更新时间',
dataIndex: 'updateTime',
sorter: true,
valueType: 'dateTime',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
render: (_, record) => [
<a
onClick={() => {
handleUpdateModalVisible(true);
setFormValues(record);
}}
>
配置
</a>,
<a
onClick={() => {
setHandleGrantRole(true);
setFormValues(record);
}}
>
关联角色
</a>,
<MoreBtn key="more" item={record}/>,
],
},
];
return (
<>
<PageContainer>
<ProTable<UserTableListItem>
headerTitle="用户管理"
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button type="primary" onClick={() => handleModalVisible(true)}>
<PlusOutlined/> 新建
</Button>,
]}
request={(params, sorter, filter) => queryData(url, {...params, sorter, filter})}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
已选择 <a style={{fontWeight: 600}}>{selectedRowsState.length}</a>&nbsp;&nbsp;
<span>
被禁用的用户共 {selectedRowsState.length - selectedRowsState.reduce((pre, item) => pre + (item.enabled ? 1 : 0), 0)}
</span>
</div>
}
>
<Button type="primary" danger
onClick={() => {
Modal.confirm({
title: '删除用户',
content: '确定删除选中的用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>
批量删除
</Button>
<Button type="primary"
onClick={() => {
Modal.confirm({
title: '启用用户',
content: '确定启用选中的用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, true);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量启用</Button>
<Button danger
onClick={() => {
Modal.confirm({
title: '禁用用户',
content: '确定禁用选中的用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, false);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量禁用</Button>
</FooterToolbar>
)}
<UserForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate("api/user", value);
if (success) {
handleModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleModalVisible(false);
}}
modalVisible={modalVisible}
values={{}}
/>
{formValues && Object.keys(formValues).length ? (
<>
<PasswordForm
onSubmit={async (value) => {
const success = await handleOption(url + "/modifyPassword", '修改密码', value);
if (success) {
handlePasswordModalVisible(false);
setFormValues({});
}
}}
onCancel={() => {
handlePasswordModalVisible(false);
}}
modalVisible={passwordModalVisible}
values={formValues}
/>
<UserForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate("api/user", value);
if (success) {
handleUpdateModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
setFormValues({});
}}
modalVisible={updateModalVisible}
values={formValues}
/></>
) : null}
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.username && (
<ProDescriptions<UserTableListItem>
column={2}
title={row?.username}
request={async () => ({
data: row || {},
})}
params={{
id: row?.username,
}}
columns={columns}
/>
)}
</Drawer>
{handleGrantRoleForm()}
</PageContainer>
</>
);
};
export default UserTableList;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
export type UserTableListItem = {
id?: number;
enabled?: boolean;
isDelete?: string;
createTime?: Date;
updateTime?: Date;
username?: string;
nickname?: string;
password?: string;
avatar?: string;
worknum?: string;
mobile?: string;
};
export type PasswordItem = {
username: string;
password?: string;
newPassword?: string;
newPasswordCheck?: string;
};
export type TenantTableListItem = {
id?: number;
tenantCode?: string;
isDelete?: boolean;
note?: string;
createTime?: Date;
updateTime?: Date;
};
export type RoleTableListItem = {
id?: number;
tenantId?: number;
tenant: TenantTableListItem;
roleCode?: string;
roleName?: string;
namespaceIds?: string;
namespaces?: NameSpaceTableListItem[];
isDelete?: boolean;
note?: string;
createTime?: Date;
updateTime?: Date;
};
export type NameSpaceTableListItem = {
id?: number;
tenantId?: number;
tenant: TenantTableListItem;
namespaceCode?: string;
enabled?: boolean;
note?: string;
createTime?: Date;
updateTime?: Date;
};
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import {RoleTableListItem} from "@/pages/AuthenticationCenter/data.d";
export const getFormData = (values: RoleTableListItem) => {
let namespaceIds:string [] = [];
if(values&&values.namespaceIds && values.namespaceIds!=''){
namespaceIds = values.namespaceIds.split(',');
}
return {...values,namespaceIds:namespaceIds};
}
export const buildFormData = (values: RoleTableListItem,params: any) => {
let newValue = values;
if(params.namespaceIds){
newValue.namespaceIds = params.namespaceIds.join(',');
delete params.namespaceIds;
}
return {...newValue,...params};
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import {queryData} from "@/components/Common/crud";
/*--- 刷新 NameSpace ---*/
export function getNameSpaceList(dispatch: any) {
const res = queryData('/api/namespace');
res.then((result) => {
result.data && dispatch && dispatch({
type: "NameSpace/saveNameSpace",
payload: result.data,
});
});
}
/*--- 获取角色 ---*/
export function getRoleList(dispatch: any) {
const res = queryData('/api/role');
res.then((result) => {
result.data && dispatch && dispatch({
type: "Role/getRoleList",
payload: result.data,
});
});
}
......@@ -18,8 +18,9 @@
*/
import request from 'umi-request';
import {CAParam, StudioMetaStoreParam, StudioParam} from "@/components/Studio/StudioEdit/data";
import {request2} from "@/components/Common/crud";
import {request} from "umi";
export async function executeSql(params: StudioParam) {
return request<API.Result>('/api/studio/executeSql', {
......@@ -76,7 +77,7 @@ export async function getJobData(jobId: string) {
}
export async function getCatalogueTreeData(params?: StudioParam) {
return request<API.Result>('/api/catalogue/getCatalogueTreeData', {
return request2<API.Result>('/api/catalogue/getCatalogueTreeData', {
method: 'POST',
data: {
...params,
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import ProTable, {ActionType, ProColumns} from "@ant-design/pro-table";
import {TaskVersion} from "@/pages/DevOps/data";
import {useRef, useState,} from "react";
import {queryData} from "@/components/Common/crud";
import {getIcon} from "@/components/Studio/icon";
import {Button, Modal, Tag} from "antd";
import {FullscreenOutlined} from "@ant-design/icons";
import CodeShow from "@/components/Common/CodeShow";
const url = '/api/task/version';
const VersionList = (props: any) => {
const {job} = props;
const actionRef = useRef<ActionType>();
const [row, setRow] = useState<TaskVersion>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const cancelHandle = () => {
setRow(undefined);
setModalVisible(false);
}
const handleShowStatement = (item: any) =>{
return (
<div style={{width: "1100px"}}>
<Modal title="作业执行 SQL" visible={modalVisible} destroyOnClose={true} width={"60%"}
onCancel={()=>{
cancelHandle();
}}
footer={[
<Button key="back" onClick={() => {
cancelHandle();
}}>
关闭
</Button>,
]}>
<CodeShow language={"sql"} code={item?.statement} height={'600px'} />
</Modal>
</div>
)
}
const columns: ProColumns<TaskVersion>[] = [
{
title: '作业ID',
align: 'center',
dataIndex: 'taskId',
hideInSearch: true,
},
{
title: '作业名称',
align: 'center',
sorter: true,
dataIndex: 'name',
},
{
title: '作业别名',
align: 'center',
sorter: true,
dataIndex: 'alias',
},
{
title: '作业方言',
align: 'center',
render: (dom, entity) => {
return <>
{getIcon(entity.dialect) }
{
<Tag color="blue">
{entity.dialect}
</Tag>
}
</>;
},
},
{
title: '作业类型',
align: 'center',
render: (dom, entity) => {
return <>
{
<Tag color="blue">
{entity.type}
</Tag>
}
</>;
},
},
{
title: '版本号',
align: 'center',
sorter: true,
dataIndex: 'versionId',
},
{
title: '作业内容',
align: 'center',
ellipsis: true,
hideInSearch: true,
render: (dom, entity) => {
return <>
{<>
<a onClick={()=>{
setRow(entity)
setModalVisible(true);
}}>
<Tag color="green">
<FullscreenOutlined title={"查看作业详情"} />
</Tag> 查看作业详情
</a>
</>
}
</>
;
},
},
{
title: '创建时间',
align: 'center',
sorter: true,
valueType: 'dateTime',
dataIndex: 'createTime',
},
// {
// title: '操作',
// align: 'center',
// render: (dom, entity) => {
// return <>
// {<>
// <Button type={"link"} onClick={()=>{
// setRow(entity)
// setModalVisible(true);
// }}>
// 版本对比
// </Button>
// </>
// }
// </>
// ;
// },
// },
];
return (
<>
<ProTable<TaskVersion>
columns={columns}
style={{width: '100%'}}
request={(params, sorter, filter) => queryData(url, {taskId: job?.instance.taskId, ...params, sorter, filter})}
actionRef={actionRef}
rowKey="id"
pagination={{
pageSize: 10,
}}
bordered
search={false}
size="small"
/>
{handleShowStatement(row)}
</>
)
};
export default VersionList;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, {useEffect, useState,} from "react";
import {BackTop, Button, Card, Radio, RadioChangeEvent, Timeline} from "antd";
import {queryData} from "@/components/Common/crud";
import moment from "moment";
import {TaskVersion} from "@/pages/DevOps/data";
import {CheckCircleOutlined, SyncOutlined} from "@ant-design/icons";
// import {Scrollbars} from "react-custom-scrollbars";
const url = '/api/task/version';
const VersionTimeLineList = (props: any) => {
const {job} = props;
const [mode, setMode] = useState<'left' | 'alternate' | 'right'>('alternate');
const [reverse, setReverse] = useState(false);
const onChange = (e: RadioChangeEvent) => {
setMode(e.target.value);
};
const [taskVersionData, setTaskVersionData] = useState<TaskVersion>();
let taskId =job.instance.taskId;
const getVersionData = () => {
setTaskVersionData(undefined);
const res = queryData(url, {taskId, sorter: {versionId: 'descend'}});
res.then((result) => {
setTaskVersionData(result.data);
});
};
useEffect(() => {
getVersionData();
}, []);
const handleClick = () => {
setReverse(!reverse);
};
const style: React.CSSProperties = {
height: 40,
width: 40,
lineHeight: '40px',
borderRadius: 4,
backgroundColor: '#1088e9',
color: '#fff',
textAlign: 'center',
fontSize: 14,
};
const getTimelineForm = () => {
let formList = [];
let tempData = taskVersionData
for (let key in tempData) {
formList.push(
<Timeline.Item dot={(<CheckCircleOutlined/>)} label={moment(tempData[key].createTime).format("YYYY-MM-DD HH:mm:ss")} color="green">
<p>{tempData[key].name}: Create Version 【{tempData[key].versionId}
{/*site 【{ moment(tempData[key].createTime).format("YYYY-MM-DD HH:mm:ss")}】*/}
</p>
<p>Execute Mode: 【{tempData[key].type}</p>
</Timeline.Item>
)
}
return formList
}
function refresh() {
getVersionData()
}
return (
<div style={{
marginTop: "20px",
}}>
<Button type="primary" style={{ margin:"5px" }} onClick={handleClick}>
{reverse? "倒序": "正序"}
</Button>
<Button type="primary" style={{ margin:"5px" }} onClick={refresh}>
刷新
</Button>
<Radio.Group
onChange={onChange}
value={mode}
>
<Radio value="left">Left</Radio>
<Radio value="right">Right</Radio>
<Radio value="alternate">Alternate</Radio>
</Radio.Group>
<Card size="small" style={{ width: "auto" }}>
{/*<Scrollbars style={{height: "450px"}} >*/}
<br/><br/>
<Timeline mode={mode} pending={moment().format("YYYY-MM-DD HH:mm:ss")+" Developing..."} reverse={reverse} pendingDot={<SyncOutlined spin/>}>
{getTimelineForm()}
</Timeline>
<BackTop>
<div style={style}>Top</div>
</BackTop>
{/*</Scrollbars>*/}
</Card>
</div>
)
};
export default VersionTimeLineList;
import ProTable, {ActionType, ProColumns} from "@ant-design/pro-table";
import {TaskVersion} from "@/pages/DevOps/data";
import React, {useRef, useState,} from "react";
import {queryData} from "@/components/Common/crud";
import {getIcon} from "@/components/Studio/icon";
import {Button, Modal, Tag} from "antd";
import {FullscreenOutlined} from "@ant-design/icons";
import CodeShow from "@/components/Common/CodeShow";
const url = '/api/task/version';
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import {Tabs} from "antd";
import VersionList from "@/pages/DevOps/JobInfo/Version/VersionList";
import VersionTimeLineList from "@/pages/DevOps/JobInfo/Version/VersionTimeLineList";
const {TabPane} = Tabs;
const TaskVersionInfo = (props: any) => {
const {job} = props;
const actionRef = useRef<ActionType>();
const [row, setRow] = useState<TaskVersion>();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const cancelHandle = () => {
setRow(undefined);
setModalVisible(false);
}
const handleShowStatement = (statement: string) =>{
return (
<div style={{width: "1100px"}}>
<Modal title="作业执行 SQL" visible={modalVisible} destroyOnClose={true} width={"60%"}
onCancel={()=>{
cancelHandle();
}}
footer={[
<Button key="back" onClick={() => {
cancelHandle();
}}>
关闭
</Button>,
]}>
<CodeShow language={"sql"} code={statement} height={'600px'} />
</Modal>
</div>
)
}
return (<>
<Tabs defaultActiveKey="overview" size="small" tabPosition="top" style={{
border: "1px solid #f0f0f0",
}}>
<TabPane tab={<span>&nbsp; 版本列表 &nbsp;</span>} key="versionlist">
<VersionList job={job}/>
</TabPane>
const columns: ProColumns<TaskVersion>[] = [
{
title: '作业ID',
align: 'center',
dataIndex: 'taskId',
hideInSearch: true,
},
{
title: '作业名称',
align: 'center',
sorter: true,
dataIndex: 'name',
},
{
title: '作业别名',
align: 'center',
sorter: true,
dataIndex: 'alias',
},
{
title: '作业方言',
align: 'center',
render: (dom, entity) => {
return <>
{getIcon(entity.dialect) }
{
<Tag color="blue">
{entity.dialect}
</Tag>
}
</>;
},
},
{
title: '作业类型',
align: 'center',
render: (dom, entity) => {
return <>
{
<Tag color="blue">
{entity.type}
</Tag>
}
</>;
},
},
{
title: '版本号',
align: 'center',
sorter: true,
dataIndex: 'versionId',
},
{
title: '作业内容',
align: 'center',
ellipsis: true,
hideInSearch: true,
render: (dom, entity) => {
return <>
{<>
<a onClick={()=>{
setRow(entity)
setModalVisible(true);
}}>
<Tag color="green">
<FullscreenOutlined title={"查看作业详情"} />
</Tag> 查看作业详情
</a>
{handleShowStatement(entity.statement)}
</>
}
</>
;
},
},
{
title: '创建时间',
align: 'center',
sorter: true,
valueType: 'dateTime',
dataIndex: 'createTime',
},
];
<TabPane tab={<span>&nbsp; TimeLine &nbsp;</span>} key="timeline">
<VersionTimeLineList job={job}/>
</TabPane>
return (
<>
<ProTable<TaskVersion>
columns={columns}
style={{width: '100%'}}
request={(params, sorter, filter) => queryData(url, {taskId: job?.instance.taskId, ...params, sorter, filter})}
actionRef={actionRef}
rowKey="id"
pagination={{
pageSize: 15,
}}
bordered
search={false}
size="small"
/>
</>
)
</Tabs>
</>)
};
export default TaskVersionInfo;
......@@ -218,9 +218,9 @@ const DocumentForm: React.FC<DocumentFormProps> = (props) => {
<Form
{...formLayout}
form={form}
initialValues={getDocumentFormData(formVals)}
initialValues={getDocumentFormData(formVals as DocumentTableListItem)}
>
{renderContent(getDocumentFormData(formVals))}
{renderContent(getDocumentFormData(formVals as DocumentTableListItem))}
</Form>
</Modal>
);
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import {FragmentVariableTableListItem} from "@/pages/FragmentVariable/data";
export const getFragmentVariableTableListItem = (values: FragmentVariableTableListItem) => {
return values;
}
......@@ -19,10 +19,9 @@
import React, {useEffect, useState} from 'react';
import {Form, Input, List, Switch} from 'antd';
import {connect} from "umi";
import {SettingsStateType} from "@/pages/Settings/model";
import {saveSettings} from "@/pages/Settings/function";
import { useIntl, Link, history, FormattedMessage, SelectLang} from 'umi';
import {connect, useIntl} from "umi";
import {SettingsStateType} from "@/pages/SettingCenter/FlinkSettings/model";
import {saveSettings} from "@/pages/SettingCenter/FlinkSettings/function";
type FlinkConfigProps = {
sqlSubmitJarPath: SettingsStateType['sqlSubmitJarPath'];
......@@ -63,73 +62,137 @@ const FlinkConfigView: React.FC<FlinkConfigProps> = (props) => {
title: intl.formatMessage({id: 'pages.settings.FlinkURL', defaultMessage: '提交FlinkSQL的Jar文件路径',}),
description: (
editName != 'sqlSubmitJarPath' ?
(sqlSubmitJarPath ? sqlSubmitJarPath : intl.formatMessage({id: 'pages.settings.FlinkNoSetting', defaultMessage: intl.formatMessage({id: 'pages.settings.FlinkNoSetting', defaultMessage: '未设置',}),})) : (
(sqlSubmitJarPath ? sqlSubmitJarPath : intl.formatMessage({
id: 'pages.settings.FlinkNoSetting',
defaultMessage: intl.formatMessage({id: 'pages.settings.FlinkNoSetting', defaultMessage: '未设置',}),
})) : (
<Input
id='sqlSubmitJarPath'
defaultValue={sqlSubmitJarPath}
onChange={onChange}
placeholder="hdfs:///dlink/jar/dlink-app.jar"/>)),
actions: editName != 'sqlSubmitJarPath' ? [<a onClick={({}) => handleEditClick('sqlSubmitJarPath')}>{intl.formatMessage({id: 'pages.settings.FlinkUpdate', defaultMessage: '修改',})}</a>] :
[<a onClick={({}) => handleSaveClick('sqlSubmitJarPath')}>{intl.formatMessage({id: 'pages.settings.FlinkSave', defaultMessage: '保存',})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({id: 'pages.settings.FlinkCancel', defaultMessage: '取消',})}</a>],
actions: editName != 'sqlSubmitJarPath' ? [<a
onClick={({}) => handleEditClick('sqlSubmitJarPath')}>{intl.formatMessage({
id: 'pages.settings.FlinkUpdate',
defaultMessage: '修改',
})}</a>] :
[<a onClick={({}) => handleSaveClick('sqlSubmitJarPath')}>{intl.formatMessage({
id: 'pages.settings.FlinkSave',
defaultMessage: '保存',
})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({
id: 'pages.settings.FlinkCancel',
defaultMessage: '取消',
})}</a>],
},
{
title: intl.formatMessage({id: 'pages.settings.FlinkSQLJarMainParameter', defaultMessage: '提交FlinkSQL的Jar的主类入参',}),
title: intl.formatMessage({
id: 'pages.settings.FlinkSQLJarMainParameter',
defaultMessage: '提交FlinkSQL的Jar的主类入参',
}),
description: (
editName != 'sqlSubmitJarParas' ?
(sqlSubmitJarParas ? sqlSubmitJarParas : intl.formatMessage({id: 'pages.settings.FlinkNoSetting', defaultMessage: '未设置',})) : (<Input
(sqlSubmitJarParas ? sqlSubmitJarParas : intl.formatMessage({
id: 'pages.settings.FlinkNoSetting',
defaultMessage: '未设置',
})) : (<Input
id='sqlSubmitJarParas'
defaultValue={sqlSubmitJarParas}
onChange={onChange}
placeholder=""/>)),
actions: editName != 'sqlSubmitJarParas' ? [<a onClick={({}) => handleEditClick('sqlSubmitJarParas')}>{intl.formatMessage({id: 'pages.settings.FlinkUpdate', defaultMessage: '修改',})}</a>] :
[<a onClick={({}) => handleSaveClick('sqlSubmitJarParas')}>{intl.formatMessage({id: 'pages.settings.FlinkSave', defaultMessage: '保存',})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({id: 'pages.settings.FlinkCancel', defaultMessage: '取消',})}</a>],
actions: editName != 'sqlSubmitJarParas' ? [<a
onClick={({}) => handleEditClick('sqlSubmitJarParas')}>{intl.formatMessage({
id: 'pages.settings.FlinkUpdate',
defaultMessage: '修改',
})}</a>] :
[<a onClick={({}) => handleSaveClick('sqlSubmitJarParas')}>{intl.formatMessage({
id: 'pages.settings.FlinkSave',
defaultMessage: '保存',
})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({
id: 'pages.settings.FlinkCancel',
defaultMessage: '取消',
})}</a>],
},
{
title: intl.formatMessage({id: 'pages.settings.FlinkSQLJarMainClass', defaultMessage: '提交FlinkSQL的Jar的主类',}),
title: intl.formatMessage({
id: 'pages.settings.FlinkSQLJarMainClass',
defaultMessage: '提交FlinkSQL的Jar的主类',
}),
description: (
editName != 'sqlSubmitJarMainAppClass' ?
(sqlSubmitJarMainAppClass ? sqlSubmitJarMainAppClass : intl.formatMessage({id: 'pages.settings.FlinkNoSetting', defaultMessage: '未设置',})) : (<Input
(sqlSubmitJarMainAppClass ? sqlSubmitJarMainAppClass : intl.formatMessage({
id: 'pages.settings.FlinkNoSetting',
defaultMessage: '未设置',
})) : (<Input
id='sqlSubmitJarMainAppClass'
defaultValue={sqlSubmitJarMainAppClass}
onChange={onChange}
placeholder="com.dlink.app.MainApp"/>)),
actions: editName != 'sqlSubmitJarMainAppClass' ? [<a
onClick={({}) => handleEditClick('sqlSubmitJarMainAppClass')}>{intl.formatMessage({id: 'pages.settings.FlinkUpdate', defaultMessage: '修改',})}</a>] :
[<a onClick={({}) => handleSaveClick('sqlSubmitJarMainAppClass')}>{intl.formatMessage({id: 'pages.settings.FlinkSave', defaultMessage: '保存',})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({id: 'pages.settings.FlinkCancel', defaultMessage: '取消',})}</a>],
onClick={({}) => handleEditClick('sqlSubmitJarMainAppClass')}>{intl.formatMessage({
id: 'pages.settings.FlinkUpdate',
defaultMessage: '修改',
})}</a>] :
[<a onClick={({}) => handleSaveClick('sqlSubmitJarMainAppClass')}>{intl.formatMessage({
id: 'pages.settings.FlinkSave',
defaultMessage: '保存',
})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({
id: 'pages.settings.FlinkCancel',
defaultMessage: '取消',
})}</a>],
}, {
title: intl.formatMessage({id: 'pages.settings.FlinkRestAPI', defaultMessage: '使用 RestAPI',}),
description: intl.formatMessage({id: 'pages.settings.FlinkNoUseSetting', defaultMessage: '启用后,Flink 任务的 savepoint、停止等操作将通过 JobManager 的 RestAPI 进行',}),
description: intl.formatMessage({
id: 'pages.settings.FlinkNoUseSetting',
defaultMessage: '启用后,Flink 任务的 savepoint、停止等操作将通过 JobManager 的 RestAPI 进行',
}),
actions: [
<Form.Item
name="useRestAPI" valuePropName="checked"
>
<Switch checkedChildren={intl.formatMessage({id: 'pages.settings.FlinkUse', defaultMessage: '启用',})} unCheckedChildren={intl.formatMessage({id: 'pages.settings.FlinkNotUse', defaultMessage: '禁用',})}
<Switch checkedChildren={intl.formatMessage({id: 'pages.settings.FlinkUse', defaultMessage: '启用',})}
unCheckedChildren={intl.formatMessage({id: 'pages.settings.FlinkNotUse', defaultMessage: '禁用',})}
checked={useRestAPI}
/></Form.Item>],
}, {
title: intl.formatMessage({id: 'pages.settings.FlinkURLSplit', defaultMessage: 'FlinkSQL语句分割符',}),
description: (
editName != 'sqlSeparator' ?
(sqlSeparator ? sqlSeparator : intl.formatMessage({id: 'pages.settings.FlinkNoSetting', defaultMessage: '未设置',})) : (<Input
(sqlSeparator ? sqlSeparator : intl.formatMessage({
id: 'pages.settings.FlinkNoSetting',
defaultMessage: '未设置',
})) : (<Input
id='sqlSeparator'
defaultValue={sqlSeparator}
onChange={onChange}
placeholder=";"/>)),
actions: editName != 'sqlSeparator' ? [<a onClick={({}) => handleEditClick('sqlSeparator')}>{intl.formatMessage({id: 'pages.settings.FlinkUpdate', defaultMessage: '修改',})}</a>] :
[<a onClick={({}) => handleSaveClick('sqlSeparator')}>{intl.formatMessage({id: 'pages.settings.FlinkSave', defaultMessage: '保存',})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({id: 'pages.settings.FlinkCancel', defaultMessage: '取消',})}</a>],
actions: editName != 'sqlSeparator' ? [<a onClick={({}) => handleEditClick('sqlSeparator')}>{intl.formatMessage({
id: 'pages.settings.FlinkUpdate',
defaultMessage: '修改',
})}</a>] :
[<a onClick={({}) => handleSaveClick('sqlSeparator')}>{intl.formatMessage({
id: 'pages.settings.FlinkSave',
defaultMessage: '保存',
})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({
id: 'pages.settings.FlinkCancel',
defaultMessage: '取消',
})}</a>],
},
{
title: intl.formatMessage({id: 'pages.settings.FlinkSQLLogic', defaultMessage: '使用逻辑计划计算血缘',}),
description: intl.formatMessage({id: 'pages.settings.FlinkNoUseSetting', defaultMessage: '在计算 Flink 任务的字段血缘分析时是否基于逻辑计划进行,只支持 1.14 版本',}),
description: intl.formatMessage({
id: 'pages.settings.FlinkNoUseSetting',
defaultMessage: '在计算 Flink 任务的字段血缘分析时是否基于逻辑计划进行,只支持 1.14 版本',
}),
actions: [
<Form.Item
name="useLogicalPlan" valuePropName="checked"
>
<Switch checkedChildren={intl.formatMessage({id: 'pages.settings.FlinkUse', defaultMessage: '启用',})} unCheckedChildren={intl.formatMessage({id: 'pages.settings.FlinkNotUse', defaultMessage: '禁用',})}
<Switch checkedChildren={intl.formatMessage({id: 'pages.settings.FlinkUse', defaultMessage: '启用',})}
unCheckedChildren={intl.formatMessage({id: 'pages.settings.FlinkNotUse', defaultMessage: '禁用',})}
checked={useLogicalPlan}
/></Form.Item>],
},
......@@ -143,9 +206,18 @@ const FlinkConfigView: React.FC<FlinkConfigProps> = (props) => {
defaultValue={jobIdWait}
onChange={onChange}
placeholder="30"/>)),
actions: editName != 'jobIdWait' ? [<a onClick={({}) => handleEditClick('jobIdWait')}>{intl.formatMessage({id: 'pages.settings.FlinkUpdate', defaultMessage: '修改',})}</a>] :
[<a onClick={({}) => handleSaveClick('jobIdWait')}>{intl.formatMessage({id: 'pages.settings.FlinkSave', defaultMessage: '保存',})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({id: 'pages.settings.FlinkCancel', defaultMessage: '取消',})}</a>],
actions: editName != 'jobIdWait' ? [<a onClick={({}) => handleEditClick('jobIdWait')}>{intl.formatMessage({
id: 'pages.settings.FlinkUpdate',
defaultMessage: '修改',
})}</a>] :
[<a onClick={({}) => handleSaveClick('jobIdWait')}>{intl.formatMessage({
id: 'pages.settings.FlinkSave',
defaultMessage: '保存',
})}</a>,
<a onClick={({}) => handleCancelClick()}>{intl.formatMessage({
id: 'pages.settings.FlinkCancel',
defaultMessage: '取消',
})}</a>],
},
];
......
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React from 'react';
import FlinkConfigView from './components/flinkConfig';
import {connect} from "umi";
import {PageContainer} from "@ant-design/pro-layout";
import {SettingsStateType} from "@/pages/SettingCenter/FlinkSettings/model";
import {loadSettings} from "@/pages/SettingCenter/FlinkSettings/function";
type SettingsProps = {
dispatch:any;
};
const Settings: React.FC<SettingsProps> = (props) => {
const {dispatch} = props;
loadSettings(dispatch);
return (
<PageContainer>
<FlinkConfigView />
</PageContainer>
);
};
export default connect(({Settings}: { Settings: SettingsStateType }) => ({
sqlSubmitJarPath: Settings.sqlSubmitJarPath,
sqlSubmitJarParas: Settings.sqlSubmitJarParas,
sqlSubmitJarMainAppClass: Settings.sqlSubmitJarMainAppClass,
}))(Settings);
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import React, { useState,useEffect, useRef, useLayoutEffect } from 'react';
import { GridContent } from '@ant-design/pro-layout';
import { Menu } from 'antd';
import FlinkConfigView from './components/flinkConfig';
import styles from './style.less';
import {loadSettings} from "@/pages/Settings/function";
import {SettingsStateType} from "@/pages/Settings/model";
import {connect,useModel} from "umi";
import UserTableList from '../user';
import { useIntl, Link, history, FormattedMessage, SelectLang} from 'umi';
const { Item } = Menu;
type SettingsStateKeys = 'userManager' |'flinkConfig' | 'sysConfig';
type SettingsState = {
mode: 'inline' | 'horizontal';
selectKey: SettingsStateKeys;
};
type SettingsProps = {
dispatch:any;
};
const Settings: React.FC<SettingsProps> = (props) => {
const intl = useIntl();
const { initialState, setInitialState } = useModel('@@initialState');
const menuMapAdmin: Record<string, React.ReactNode> = {
userManager: intl.formatMessage({id: 'pages.settings.UserManagement', defaultMessage: '用户管理',}),
flinkConfig: intl.formatMessage({id: 'pages.settings.Flink', defaultMessage: 'Flink 设置',}),
};
const menuMapUser: Record<string, React.ReactNode> = {
flinkConfig: intl.formatMessage({id: 'pages.settings.Flink', defaultMessage: 'Flink 设置',}),
};
const menuMap: Record<string, React.ReactNode> = (initialState?.currentUser?.isAdmin)?menuMapAdmin:menuMapUser;
const {dispatch} = props;
const [initConfig, setInitConfig] = useState<SettingsState>({
mode: 'inline',
selectKey: 'flinkConfig',
});
const dom = useRef<HTMLDivElement>();
loadSettings(dispatch);
const resize = () => {
requestAnimationFrame(() => {
if (!dom.current) {
return;
}
let mode: 'inline' | 'horizontal' = 'inline';
const { offsetWidth } = dom.current;
if (dom.current.offsetWidth < 641 && offsetWidth > 400) {
mode = 'horizontal';
}
if (window.innerWidth < 768 && offsetWidth > 400) {
mode = 'horizontal';
}
setInitConfig({ ...initConfig, mode: mode as SettingsState['mode'] });
});
};
useLayoutEffect(() => {
if (dom.current) {
window.addEventListener('resize', resize);
resize();
}
return () => {
window.removeEventListener('resize', resize);
};
}, [dom.current]);
const getMenu = () => {
console.log(menuMap);
return Object.keys(menuMap).map((item) => <Item key={item}>{menuMap[item]}</Item>);
};
const renderChildren = () => {
const { selectKey } = initConfig;
switch (selectKey) {
case 'userManager':
return <UserTableList />;
case 'flinkConfig':
return <FlinkConfigView />;
default:
return null;
}
};
return (
<GridContent>
<div
className={styles.main}
ref={(ref) => {
if (ref) {
dom.current = ref;
}
}}
>
<div className={styles.leftMenu}>
<Menu
mode={initConfig.mode}
selectedKeys={[initConfig.selectKey]}
onClick={({ key }) => {
setInitConfig({
...initConfig,
selectKey: key as SettingsStateKeys,
});
}}
>
{getMenu()}
</Menu>
</div>
<div className={styles.right}>
<div className={styles.title}>{menuMap[initConfig.selectKey]}</div>
{renderChildren()}
</div>
</div>
</GridContent>
);
};
export default connect(({Settings}: { Settings: SettingsStateType }) => ({
sqlSubmitJarPath: Settings.sqlSubmitJarPath,
sqlSubmitJarParas: Settings.sqlSubmitJarParas,
sqlSubmitJarMainAppClass: Settings.sqlSubmitJarMainAppClass,
}))(Settings);
......@@ -17,44 +17,26 @@
*
*/
import {
AlipayCircleOutlined,
LockOutlined,
MobileOutlined,
TaobaoCircleOutlined,
UserOutlined,
WeiboCircleOutlined,
} from '@ant-design/icons';
import { Alert, Space, message, Tabs } from 'antd';
import React, { useState } from 'react';
import ProForm, { ProFormCaptcha, ProFormCheckbox, ProFormText } from '@ant-design/pro-form';
import { useIntl, Link, history, FormattedMessage, SelectLang, useModel } from 'umi';
import {LockOutlined, UserOutlined,} from '@ant-design/icons';
import {Button, message, Modal} from 'antd';
import React, {useEffect, useState} from 'react';
import ProForm, {ProFormCheckbox, ProFormText} from '@ant-design/pro-form';
import {FormattedMessage, history, Link, SelectLang, useIntl, useModel} from 'umi';
import Footer from '@/components/Footer';
import { login } from '@/services/ant-design-pro/api';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
import {login} from '@/services/ant-design-pro/api';
import {CheckCard} from '@ant-design/pro-components';
import styles from './index.less';
import {getData} from "@/components/Common/crud";
import {TenantTableListItem} from "@/pages/AuthenticationCenter/data.d";
const LoginMessage: React.FC<{
content: string;
}> = ({ content }) => (
<Alert
style={{
marginBottom: 24,
}}
message={content}
type="error"
showIcon
/>
);
/** 此方法会跳转到 redirect 参数所在的位置 */
const goto = () => {
if (!history) return;
setTimeout(() => {
const { query } = history.location;
const { redirect } = query as { redirect: string };
const {query} = history.location;
const {redirect} = query as { redirect: string };
history.push(redirect || '/');
}, 10);
};
......@@ -62,10 +44,15 @@ const goto = () => {
const Login: React.FC = () => {
const [submitting, setSubmitting] = useState(false);
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({});
const [userParamsState, setUserParamsState] = useState<API.LoginParams>({});
const [type, setType] = useState<string>('password');
const { initialState, setInitialState } = useModel('@@initialState');
const {initialState, setInitialState} = useModel('@@initialState');
const [isLogin, setIsLogin] = useState<boolean>(true);
const [chooseTenant, setChooseTenant] = useState<boolean>(false);
const [tenantId, setTenantId] = useState<number>();
const [tenant, setTenant] = useState<TenantTableListItem[]>([]);
const [checkDisabled, setCheckDisabled] = useState<boolean>(true);
const intl = useIntl();
const fetchUserInfo = async () => {
......@@ -78,15 +65,34 @@ const Login: React.FC = () => {
}
};
useEffect(() => {
// 调用接口
const {username} = userParamsState
if (!username) {
return
}
getData("/api/geTenants", {username}).then(result => {
setTenant(result?.datas);
})
}, [
userParamsState?.username
])
const handleSubmit = async (values: API.LoginParams) => {
if(!isLogin) {return;}
if (!isLogin) {
return;
}
setIsLogin(false);
setTimeout(()=>{setIsLogin(true)},200);
setTimeout(() => {
setIsLogin(true)
}, 200);
setSubmitting(true);
try {
// 登录
const msg = await login({ ...values, type });
if (msg.code === 0 && msg.datas!=undefined ) {
const msg = await login({...values, type});
if (msg.code === 0 && msg.datas != undefined) {
const defaultloginSuccessMessage = intl.formatMessage({
id: 'pages.login.success',
defaultMessage: '登录成功!',
......@@ -95,7 +101,7 @@ const Login: React.FC = () => {
await fetchUserInfo();
goto();
return;
}else{
} else {
const defaultloginFailureMessage = intl.formatMessage({
id: msg.msg,
defaultMessage: msg.msg,
......@@ -116,19 +122,73 @@ const Login: React.FC = () => {
};
//const {code } = userLoginState;
const handleShowTenant = (item: API.LoginParams) => {
return <>
<Modal title={intl.formatMessage({id: 'pages.login.chooseTenant'})} visible={chooseTenant} destroyOnClose={true}
width={"60%"}
onCancel={() => {
setChooseTenant(false);
}}
footer={[
<Button key="back" onClick={() => {
setChooseTenant(false);
}}>
{intl.formatMessage({id: 'button.close'})}
</Button>,
<Button disabled={checkDisabled} type="primary" key="submit" loading={submitting}
onClick={async () => {
userParamsState.tenantId = tenantId;
localStorage.setItem("dlink-tenantId", tenantId.toString());
await handleSubmit(userParamsState);
}}>
{intl.formatMessage({id: 'button.confirm'})}
</Button>
]}>
<CheckCard.Group
multiple={false}
onChange={(value) => {
if (value) {
setCheckDisabled(false)
setTenantId(value as number)
userParamsState.tenantId = value as number;
} else {
setCheckDisabled(true)
}
}}
>
{tenant?.map((item: any) => {
return <>
<CheckCard
size={"default"}
key={item?.id}
avatar="https://gw.alipayobjects.com/zos/bmw-prod/f601048d-61c2-44d0-bf57-ca1afe7fd92e.svg"
title={item?.tenantCode}
value={item?.id}
description={item?.note}
/>
</>
})}
</CheckCard.Group>
</Modal>
</>
}
return (
<div className={styles.container}>
<div className={styles.lang}>{SelectLang && <SelectLang />}</div>
<div className={styles.lang}>{SelectLang && <SelectLang/>}</div>
<div className={styles.content}>
<div className={styles.top}>
<div className={styles.header}>
<Link to="/">
<img alt="logo" className={styles.logo} src="/dinky.svg" />
<img alt="logo" className={styles.logo} src="/dinky.svg"/>
<span className={styles.title}>Dinky</span>
</Link>
</div>
<div className={styles.desc}>
{intl.formatMessage({ id: 'pages.layouts.userLayout.title' })}
{intl.formatMessage({id: 'pages.layouts.userLayout.title'})}
</div>
</div>
......@@ -151,12 +211,14 @@ const Login: React.FC = () => {
style: {
width: '100%',
},
htmlType:'submit',
htmlType: 'submit',
},
}}
onFinish={async (values) => {
values.grant_type = 'password';
handleSubmit(values as API.LoginParams);
setUserLoginState(values);
setUserParamsState(values);
setChooseTenant(true)
}}
>
{type === 'password' && (
......@@ -165,7 +227,7 @@ const Login: React.FC = () => {
name="username"
fieldProps={{
size: 'large',
prefix: <UserOutlined className={styles.prefixIcon} />,
prefix: <UserOutlined className={styles.prefixIcon}/>,
}}
placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder',
......@@ -187,7 +249,7 @@ const Login: React.FC = () => {
name="password"
fieldProps={{
size: 'large',
prefix: <LockOutlined className={styles.prefixIcon} />,
prefix: <LockOutlined className={styles.prefixIcon}/>,
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
......@@ -215,21 +277,23 @@ const Login: React.FC = () => {
}}
>
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage id="pages.login.rememberMe" defaultMessage="自动登录" />
<FormattedMessage id="pages.login.rememberMe" defaultMessage="自动登录"/>
</ProFormCheckbox>
<a
style={{
float: 'right',
}}
>
<FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码" />
<FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码"/>
</a>
</div>
</ProForm>
</div>
</div>
<Footer />
<Footer/>
{handleShowTenant(userParamsState)}
</div>
);
};
......
......@@ -20,16 +20,15 @@
import React, {useRef, useState} from "react";
import {DownOutlined, PlusOutlined} from '@ant-design/icons';
import {ActionType, ProColumns} from "@ant-design/pro-table";
import {Button, Drawer, Modal, Dropdown, Menu} from 'antd';
import ProTable, {ActionType, ProColumns} from "@ant-design/pro-table";
import {Button, Drawer, Dropdown, Menu, Modal} from 'antd';
import {FooterToolbar} from '@ant-design/pro-layout';
import ProTable from '@ant-design/pro-table';
import ProDescriptions from '@ant-design/pro-descriptions';
import {UserTableListItem} from "@/pages/user/data";
import {handleAddOrUpdate, handleOption, handleRemove, queryData, updateEnabled} from "@/components/Common/crud";
import UserForm from "@/pages/user/components/UserForm";
import PasswordForm from "@/pages/user/components/PasswordForm";
import { useIntl, Link, history, FormattedMessage, SelectLang} from 'umi';
import {useIntl} from 'umi';
import UserForm from "@/pages/AuthenticationCenter/UserManager/components/UserForm";
import PasswordForm from "@/pages/AuthenticationCenter/UserManager/components/PasswordForm";
import {UserTableListItem} from "@/pages/AuthenticationCenter/data.d";
const url = '/api/user';
const UserTableList: React.FC<{}> = (props: any) => {
......@@ -73,8 +72,14 @@ const UserTableList: React.FC<{}> = (props: any) => {
overlay={
<Menu onClick={({key}) => editAndDelete(key, item)}>
<Menu.Item key="edit">{intl.formatMessage({id: 'pages.user.UserEdit', defaultMessage: '编辑',})}</Menu.Item>
<Menu.Item key="password">{intl.formatMessage({id: 'pages.user.UserChangePassword', defaultMessage: '修改密码',})}</Menu.Item>
{item.username=='admin'?'':(<Menu.Item key="delete">{intl.formatMessage({id: 'pages.user.UserDelete', defaultMessage: '删除',})}</Menu.Item>)}
<Menu.Item key="password">{intl.formatMessage({
id: 'pages.user.UserChangePassword',
defaultMessage: '修改密码',
})}</Menu.Item>
{item.username == 'admin' ? '' : (<Menu.Item key="delete">{intl.formatMessage({
id: 'pages.user.UserDelete',
defaultMessage: '删除',
})}</Menu.Item>)}
</Menu>
}
>
......@@ -164,7 +169,10 @@ const UserTableList: React.FC<{}> = (props: any) => {
setFormValues(record);
}}
>
{intl.formatMessage({id: 'pages.user.UserConfig', defaultMessage: intl.formatMessage({id: 'pages.user.UserConfig', defaultMessage: '配置',}),})}
{intl.formatMessage({
id: 'pages.user.UserConfig',
defaultMessage: intl.formatMessage({id: 'pages.user.UserConfig', defaultMessage: '配置',}),
})}
</a>,
<MoreBtn key="more" item={record}/>,
],
......@@ -178,155 +186,155 @@ const UserTableList: React.FC<{}> = (props: any) => {
actionRef={actionRef}
rowKey="id"
search={{
labelWidth: 120,
}}
labelWidth: 120,
}}
toolBarRender={() => [
<Button type="primary" onClick={() => handleModalVisible(true)}>
<PlusOutlined/> {intl.formatMessage({id: 'pages.user.UserCreate', defaultMessage: '新建',})}
</Button>,
]}
<Button type="primary" onClick={() => handleModalVisible(true)}>
<PlusOutlined/> {intl.formatMessage({id: 'pages.user.UserCreate', defaultMessage: '新建',})}
</Button>,
]}
request={(params, sorter, filter) => queryData(url, {...params, sorter, filter})}
columns={columns}
rowSelection={{
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
已选择 <a style={{fontWeight: 600}}>{selectedRowsState.length}</a>&nbsp;&nbsp;
<span>
onChange: (_, selectedRows) => setSelectedRows(selectedRows),
}}
/>
{selectedRowsState?.length > 0 && (
<FooterToolbar
extra={
<div>
已选择 <a style={{fontWeight: 600}}>{selectedRowsState.length}</a>&nbsp;&nbsp;
<span>
被禁用的用户共 {selectedRowsState.length - selectedRowsState.reduce((pre, item) => pre + (item.enabled ? 1 : 0), 0)}
</span>
</div>
}
</div>
}
>
<Button type="primary" danger
onClick={() => {
Modal.confirm({
title: '删除用户',
content: '确定删除选中的用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>
<Button type="primary" danger
onClick={() => {
Modal.confirm({
title: '删除用户',
content: '确定删除选中的用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await handleRemove(url, selectedRowsState);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>
批量删除
</Button>
<Button type="primary"
onClick={() => {
Modal.confirm({
title: '启用用户',
content: '确定启用选中的用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, true);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量启用</Button>
<Button danger
onClick={() => {
Modal.confirm({
title: '禁用用户',
content: '确定禁用选中的用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, false);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量禁用</Button>
</FooterToolbar>
)}
<UserForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate("api/user", value);
if (success) {
handleModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
批量删除
</Button>
<Button type="primary"
onClick={() => {
Modal.confirm({
title: '启用用户',
content: '确定启用选中的用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, true);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量启用</Button>
<Button danger
onClick={() => {
Modal.confirm({
title: '禁用用户',
content: '确定禁用选中的用户吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
await updateEnabled(url, selectedRowsState, false);
setSelectedRows([]);
actionRef.current?.reloadAndRest?.();
}
});
}}
>批量禁用</Button>
</FooterToolbar>
)}
<UserForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate("api/user", value);
if (success) {
handleModalVisible(false);
}}
modalVisible={modalVisible}
values={{}}
/>
{formValues && Object.keys(formValues).length ? (
<>
<PasswordForm
onSubmit={async (value) => {
const success = await handleOption(url +"/modifyPassword",'修改密码', value);
if (success) {
handlePasswordModalVisible(false);
setFormValues({});
}
}}
onCancel={() => {
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleModalVisible(false);
}}
modalVisible={modalVisible}
values={{}}
/>
{formValues && Object.keys(formValues).length ? (
<>
<PasswordForm
onSubmit={async (value) => {
const success = await handleOption(url + "/modifyPassword", '修改密码', value);
if (success) {
handlePasswordModalVisible(false);
}}
modalVisible={passwordModalVisible}
values={formValues}
/>
<UserForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate("api/user", value);
if (success) {
setFormValues({});
}
}}
onCancel={() => {
handlePasswordModalVisible(false);
}}
modalVisible={passwordModalVisible}
values={formValues}
/>
<UserForm
onSubmit={async (value) => {
const success = await handleAddOrUpdate("api/user", value);
if (success) {
handleUpdateModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
setFormValues({});
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
setFormValues({});
}}
modalVisible={updateModalVisible}
values={formValues}
/></>
): null}
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.username && (
<ProDescriptions<UserTableListItem>
column={2}
title={row?.username}
request={async () => ({
}}
modalVisible={updateModalVisible}
values={formValues}
/></>
) : null}
<Drawer
width={600}
visible={!!row}
onClose={() => {
setRow(undefined);
}}
closable={false}
>
{row?.username && (
<ProDescriptions<UserTableListItem>
column={2}
title={row?.username}
request={async () => ({
data: row || {},
})}
params={{
params={{
id: row?.username,
}}
columns={columns}
/>
)}
</Drawer>
columns={columns}
/>
)}
</Drawer>
</>
);
);
};
export default UserTableList;
......@@ -20,12 +20,14 @@
// @ts-ignore
/* eslint-disable */
import {request} from 'umi';
import {request2} from "@/components/Common/crud";
import {request} from "umi";
/** 获取当前的用户 GET /api/currentUser */
export async function currentUser(options?: { [key: string]: any }) {
return request<API.Result>('/api/current', {
return request2<API.Result>('/api/current', {
method: 'GET',
...(options || {}),
});
......@@ -33,7 +35,7 @@ export async function currentUser(options?: { [key: string]: any }) {
/** 退出登录接口 POST /api-uaa/oauth/remove/token?token= */
export async function outLogin(options?: { [key: string]: any }) {
return request<Record<string, any>>('/api/outLogin', {
return request2<Record<string, any>>('/api/outLogin', {
method: 'DELETE',
...(options || {}),
});
......@@ -41,16 +43,24 @@ export async function outLogin(options?: { [key: string]: any }) {
/** 登录接口 POST /api-uaa/oauth/token */
export async function login(body: API.LoginParams, options?: { [key: string]: any }) {
const tenantId = localStorage.getItem('dlink-tenantId') || '';
const authHeader = { tenantId };
return request<API.Result>('/api/login', {
method: 'POST',
data: body,
...(options || {}),
requestInterceptors:[
{
tenantId
}
],
...authHeader,
...(options || {}),
});
}
/** 此处后端没有提供注释 GET /api/notices */
export async function getNotices(options?: { [key: string]: any }) {
return request<API.NoticeIconList>('/api/notices', {
return request2<API.NoticeIconList>('/api/notices', {
method: 'GET',
...(options || {}),
});
......
......@@ -17,10 +17,6 @@
*
*/
// @ts-ignore
/* eslint-disable */
declare namespace API {
type Result = {
code: number;
......@@ -29,28 +25,44 @@ declare namespace API {
};
type CurrentUser = {
name?: string;
id?: number;
username?: string;
password?: string;
nickname?: string;
worknum?: string;
avatar?: string;
userid?: string;
email?: string;
signature?: string;
title?: string;
group?: string;
tags?: { key?: string; label?: string }[];
notifyCount?: number;
unreadCount?: number;
country?: string;
access?: string;
geographic?: {
province?: { label?: string; key?: string };
city?: { label?: string; key?: string };
};
address?: string;
phone?: string;
isAdmin?:boolean;
worknum?:string;
mobile?: string;
enabled?: boolean;
isDelete?: boolean;
isAdmin?: boolean;
createTime?: Date;
updateTime?: Date;
roleList?: Role[];
tenantList?: Tenant[];
currentTenant?: Tenant;
};
type Role = {
id?: number;
tenantId?: number;
roleCode?: string;
roleName?: string;
note?: string;
isDelete?: boolean;
createTime?: Date;
updateTime?: Date;
tenant?: Tenant;
};
type Tenant = {
id?: number;
tenantCode?: string;
note?: string;
isDelete?: boolean;
createTime?: Date;
updateTime?: Date;
};
/*type LoginResult = {
code?: number;
datas?: {
......@@ -107,6 +119,7 @@ declare namespace API {
username?: string;
password?: string;
autoLogin?: boolean;
tenantId?: number;
type?: string;
grant_type?: string;
};
......
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