168 changed files with 5732 additions and 1178 deletions
@ -0,0 +1,223 @@ |
|||||
|
########################################################################## |
||||
|
#(100) excluded auto configuration - io.sc.platform.core |
||||
|
########################################################################## |
||||
|
spring.autoconfigure.exclude = |
||||
|
|
||||
|
########################################################################## |
||||
|
#(150) application configuration - io.sc.platform.core |
||||
|
########################################################################## |
||||
|
# - io.sc.platform.core |
||||
|
application.audit-log-mode = none |
||||
|
#application.audit-log-mode = none |
||||
|
#application.audit-log-mode = log |
||||
|
#application.audit-log-mode = database |
||||
|
# - io.sc.platform.installer |
||||
|
application.installer.enabled = true |
||||
|
# - io.sc.platform.jdbc.liquibase |
||||
|
application.updater.enabled = true |
||||
|
# - io.sc.platform.security |
||||
|
application.default-password = password |
||||
|
|
||||
|
########################################################################## |
||||
|
#(200) spring.main configuration - io.sc.platform.core |
||||
|
########################################################################## |
||||
|
spring.main.allow-bean-definition-overriding = false |
||||
|
spring.main.banner-mode = console |
||||
|
spring.main.lazy-initialization = false |
||||
|
spring.main.log-startup-info = true |
||||
|
spring.main.register-shutdown-hook = true |
||||
|
|
||||
|
########################################################################## |
||||
|
#(210) jasypt encryptor configuration - io.sc.platform.core |
||||
|
########################################################################## |
||||
|
jasypt.encryptor.bean = platformJasyptStringEncryptor |
||||
|
|
||||
|
########################################################################## |
||||
|
#(300) web server configuration - io.sc.platform.mvc |
||||
|
########################################################################## |
||||
|
#server.address = 127.0.0.1 |
||||
|
server.port = 8080 |
||||
|
server.servlet.context-path = / |
||||
|
server.servlet.session.timeout = 30m |
||||
|
server.error.path = /error |
||||
|
server.error.whitelabel.enabled = true |
||||
|
server.error.include-exception = true |
||||
|
server.error.include-binding-errors = always |
||||
|
server.error.include-message = always |
||||
|
server.error.include-stacktrace = always |
||||
|
|
||||
|
########################################################################## |
||||
|
#(1000) dataSource configuration - io.sc.platform.jdbc |
||||
|
########################################################################## |
||||
|
spring.datasource.items[primary].driver-class-name = org.h2.Driver |
||||
|
spring.datasource.items[primary].url = jdbc:h2:mem:DB_PLATFORM;DB_CLOSE_DELAY=-1 |
||||
|
spring.datasource.items[primary].username = platform |
||||
|
spring.datasource.items[primary].password = platform |
||||
|
|
||||
|
########################################################################## |
||||
|
#(1100) jpa configuration - io.sc.platform.orm.jpa |
||||
|
########################################################################## |
||||
|
spring.jpa.open-in-view = false |
||||
|
spring.jpa.show-sql = false |
||||
|
spring.jpa.generate-ddl = false |
||||
|
spring.jpa.hibernate.ddl-auto = none |
||||
|
spring.jpa.hibernate.jdbc.batch_size = 25 |
||||
|
spring.jpa.properties.hibernate.enable_lazy_load_no_trans =true |
||||
|
spring.jpa.properties.hibernate.dialect =org.hibernate.dialect.H2Dialect |
||||
|
|
||||
|
########################################################################## |
||||
|
#(1500) hikari configuration - io.sc.platform.jdbc |
||||
|
########################################################################## |
||||
|
#spring.datasource.items[primary].hikari.autoCommit = true |
||||
|
#spring.datasource.items[primary].hikari.connectionTimeout = 10000 |
||||
|
#spring.datasource.items[primary].hikari.idleTimeout = 600000 |
||||
|
#spring.datasource.items[primary].hikari.maxLifetime = 1800000 |
||||
|
#spring.datasource.items[primary].hikari.minimumIdle = 10 |
||||
|
#spring.datasource.items[primary].hikari.maximumPoolSize = 10 |
||||
|
#spring.datasource.items[primary].hikari.metricRegistry = |
||||
|
#spring.datasource.items[primary].hikari.healthCheckRegistry = |
||||
|
#spring.datasource.items[primary].hikari.poolName = |
||||
|
#spring.datasource.items[primary].hikari.initializationFailTimeout = 1 |
||||
|
#spring.datasource.items[primary].hikari.isolateInternalQueries = false |
||||
|
#spring.datasource.items[primary].hikari.allowPoolSuspension = false |
||||
|
#spring.datasource.items[primary].hikari.readOnly = false |
||||
|
#spring.datasource.items[primary].hikari.registerMbeans = false |
||||
|
#spring.datasource.items[primary].hikari.catalog = |
||||
|
#spring.datasource.items[primary].hikari.connectionInitSql = |
||||
|
#spring.datasource.items[primary].hikari.driverClassName = |
||||
|
#spring.datasource.items[primary].hikari.transactionIsolation = |
||||
|
#spring.datasource.items[primary].hikari.validationTimeout = 5000 |
||||
|
#spring.datasource.items[primary].hikari.leakDetectionThreshold = 0 |
||||
|
#spring.datasource.items[primary].hikari.dataSource = |
||||
|
#spring.datasource.items[primary].hikari.schema = |
||||
|
#spring.datasource.items[primary].hikari.threadFactory = |
||||
|
#spring.datasource.items[primary].hikari.scheduledExecutor = |
||||
|
|
||||
|
########################################################################## |
||||
|
#(2100) spring.session configuration - io.sc.platform.mvc |
||||
|
########################################################################## |
||||
|
spring.session.store-type = none |
||||
|
#spring.session.store-type = jdbc |
||||
|
#spring.session.store-type = redis |
||||
|
spring.session.jdbc.initializer.enabled = false |
||||
|
spring.session.jdbc.cleanup-cron = 0 */5 * * * * |
||||
|
spring.session.redis.namespace = spring:session |
||||
|
spring.session.redis.cleanupCron = 0 */5 * * * * |
||||
|
|
||||
|
########################################################################## |
||||
|
#(2200) spring web configuration (WebProperties) - io.sc.platform.mvc |
||||
|
########################################################################## |
||||
|
spring.web.resources.add-mappings = true |
||||
|
spring.web.resources.cache.cachecontrol.cache-public = true |
||||
|
spring.web.resources.cache.cachecontrol.must-revalidate = true |
||||
|
spring.web.resources.chain.cache = true |
||||
|
spring.web.resources.chain.compressed = true |
||||
|
|
||||
|
########################################################################## |
||||
|
#(2300) management http server configuration - io.sc.platform.mvc |
||||
|
########################################################################## |
||||
|
management.endpoints.enabled-by-default = true |
||||
|
management.endpoints.web.exposure.include = * |
||||
|
management.context-path = /actuator |
||||
|
management.security.enabled = false |
||||
|
|
||||
|
########################################################################## |
||||
|
#(2400) thymeleaf configuration - io.sc.platform.mvc |
||||
|
########################################################################## |
||||
|
spring.thymeleaf.enabled = true |
||||
|
spring.thymeleaf.cache = false |
||||
|
spring.thymeleaf.encoding = UTF-8 |
||||
|
spring.thymeleaf.mode = HTML |
||||
|
spring.thymeleaf.prefix = classpath:/templates/ |
||||
|
spring.thymeleaf.check-template = false |
||||
|
spring.thymeleaf.check-template-location = false |
||||
|
spring.thymeleaf.servlet.content-type = text/html |
||||
|
|
||||
|
########################################################################## |
||||
|
#(2500) jackson configuration - io.sc.platform.mvc |
||||
|
########################################################################## |
||||
|
spring.jackson.time-zone = Asia/Shanghai |
||||
|
spring.jackson.date-format = yyyy-MM-dd HH:mm:ss |
||||
|
spring.jackson.serialization.indent_output = true |
||||
|
spring.jackson.serialization.fail_on_empty_beans = false |
||||
|
spring.jackson.deserialization.fail_on_ignored_properties = false |
||||
|
spring.jackson.parser.allow_comments = true |
||||
|
spring.jackson.parser.allow_single_quotes = true |
||||
|
spring.jackson.parser.allow_trailing_comma = true |
||||
|
spring.jackson.parser.allow_unquoted_field_names = true |
||||
|
spring.jackson.parser.ignore_undefined = true |
||||
|
spring.jackson.parser.allow_unquoted_control_chars = true |
||||
|
|
||||
|
########################################################################## |
||||
|
#(2600) i18n message source configuration - io.sc.platform.mvc |
||||
|
########################################################################## |
||||
|
spring.messages.alwaysUseMessageFormat = false |
||||
|
spring.messages.cacheDuration = -1 |
||||
|
spring.messages.encoding = UTF-8 |
||||
|
spring.messages.fallbackToSystemLocale = false |
||||
|
spring.messages.useCodeAsDefaultMessage = true |
||||
|
|
||||
|
########################################################################## |
||||
|
#(3000) platform security configuration - io.sc.platform.security.loginform |
||||
|
########################################################################## |
||||
|
spring.security.formLogin.loginPage = /login |
||||
|
spring.security.formLogin.loginProcessingUrl = /login |
||||
|
spring.security.formLogin.failureUrl = /login-error |
||||
|
spring.security.logout.logoutUrl = /logout |
||||
|
spring.security.logout.logoutSuccessUrl = / |
||||
|
|
||||
|
########################################################################## |
||||
|
#(4000) email configuration - io.sc.platform.communication |
||||
|
########################################################################## |
||||
|
spring.mail.host=zzz.xxx.yyy |
||||
|
spring.mail.port=25 |
||||
|
spring.mail.protocol=smtp |
||||
|
spring.mail.test-connection=false |
||||
|
spring.mail.default-encoding=UTF-8 |
||||
|
spring.mail.properties.mail.smtp.auth=true |
||||
|
spring.mail.username=xxx |
||||
|
spring.mail.password=yyy |
||||
|
|
||||
|
########################################################################## |
||||
|
#(5000) flowable bpm configuration - io.sc.platform.flowable |
||||
|
########################################################################## |
||||
|
# core |
||||
|
flowable.asyncExecutorActivate =false |
||||
|
flowable.asyncHistoryExecutorActivate = false |
||||
|
flowable.check-process-definitions=false |
||||
|
flowable.custom-mybatis-mappers= |
||||
|
flowable.custom-mybatis-x-m-l-mappers= |
||||
|
flowable.database-schema= |
||||
|
flowable.database-schema-update=true |
||||
|
flowable.db-history-used=true |
||||
|
flowable.deployment-name=SpringBootAutoDeployment |
||||
|
flowable.history-level= |
||||
|
flowable.process-definition-location-prefix=classpath*:/processes/ |
||||
|
flowable.process-definition-location-suffixes=**.bpmn20.xml,**.bpmn |
||||
|
# process |
||||
|
flowable.process.definition-cache-limit=-1 |
||||
|
flowable.process.enable-safe-xml=true |
||||
|
flowable.process.servlet.load-on-startup=-1 |
||||
|
flowable.process.servlet.name=Flowable BPMN Rest API |
||||
|
flowable.process.servlet.path=/process-api |
||||
|
# cmmn |
||||
|
flowable.cmmn.enabled=false |
||||
|
# content |
||||
|
flowable.content.enabled=false |
||||
|
# dmn |
||||
|
flowable.dmn.enabled=false |
||||
|
# form |
||||
|
flowable.form.enabled=false |
||||
|
# idm |
||||
|
flowable.idm.enabled=false |
||||
|
|
||||
|
########################################################################## |
||||
|
#(8000) cxf configuration - io.sc.platform.ws.cxf |
||||
|
########################################################################## |
||||
|
cxf.path = /webservices |
||||
|
|
||||
|
########################################################################## |
||||
|
#(9000) p6spy configuration - io.sc.platform.jdbc |
||||
|
########################################################################## |
||||
|
p6spy.enabled = true |
||||
|
p6spy.ignorePattern = false |
@ -0,0 +1,48 @@ |
|||||
|
************************************************************************************** |
||||
|
Name: app.platform |
||||
|
Version: ${application.version} |
||||
|
Base on Spring Boot ${spring-boot.version} |
||||
|
************************************************************************************** |
||||
|
System.environment: |
||||
|
-------------------------------------------------------------------------------------- |
||||
|
java.specification.version = 1.8 |
||||
|
java.specification.vendor = Oracle Corporation |
||||
|
java.specification.name = Java Platform API Specification |
||||
|
java.vm.specification.version = 1.8 |
||||
|
java.vm.specification.vendor = Oracle Corporation |
||||
|
java.vm.specification.name = Java Virtual Machine Specification |
||||
|
java.home = /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre |
||||
|
java.version = 1.8.0_332 |
||||
|
java.vendor = Azul Systems, Inc. |
||||
|
java.vendor.url = http://www.azul.com/ |
||||
|
java.vm.version = 25.332-b09 |
||||
|
java.vm.vendor = Azul Systems, Inc. |
||||
|
java.vm.name = OpenJDK 64-Bit Server VM |
||||
|
java.class.version = 52.0 |
||||
|
java.class.path = ${java.class.path2} |
||||
|
java.library.path = /Users/wangshaoping/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:. |
||||
|
java.io.tmpdir = /var/folders/82/6m96_g610hj1v1tcpvhtjysr0000gn/T/ |
||||
|
java.ext.dirs = /Users/wangshaoping/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java |
||||
|
os.name = Mac OS X |
||||
|
os.arch = aarch64 |
||||
|
os.version = 13.5.1 |
||||
|
user.name = wangshaoping |
||||
|
user.home = /Users/wangshaoping |
||||
|
user.dir = /Users/wangshaoping/wspsc/workspace/wangshaoping/v8/platform |
||||
|
|
||||
|
Application.environment |
||||
|
-------------------------------------------------------------------------------------- |
||||
|
application.name = app.platform |
||||
|
application.is-running-in-development = false |
||||
|
application.is-running-in-web-container = false |
||||
|
|
||||
|
application.home.dir = /Users/wangshaoping/wspsc/workspace/wangshaoping/v8/platform |
||||
|
application.installer.enabled = ${application.installer.enabled} |
||||
|
application.updater.enabled = ${application.updater.enabled} |
||||
|
application.audit-log-mode = ${application.audit-log-mode} |
||||
|
spring.config.location = file:/Users/wangshaoping/wspsc/workspace/wangshaoping/v8/platform/config/application.properties |
||||
|
spring.banner.location = file:/Users/wangshaoping/wspsc/workspace/wangshaoping/v8/platform/config/banner.txt |
||||
|
logging.config = file:/Users/wangshaoping/wspsc/workspace/wangshaoping/v8/platform/config/logback-spring.xml |
||||
|
p6spy.enabled = ${p6spy.enabled} |
||||
|
p6spy.ignorePattern = ${p6spy.ignorePattern} |
||||
|
************************************************************************************** |
@ -0,0 +1,216 @@ |
|||||
|
Apache License |
||||
|
Version 2.0, January 2004 |
||||
|
https://www.apache.org/licenses/ |
||||
|
|
||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||
|
|
||||
|
1. Definitions. |
||||
|
|
||||
|
"License" shall mean the terms and conditions for use, reproduction, |
||||
|
and distribution as defined by Sections 1 through 9 of this document. |
||||
|
|
||||
|
"Licensor" shall mean the copyright owner or entity authorized by |
||||
|
the copyright owner that is granting the License. |
||||
|
|
||||
|
"Legal Entity" shall mean the union of the acting entity and all |
||||
|
other entities that control, are controlled by, or are under common |
||||
|
control with that entity. For the purposes of this definition, |
||||
|
"control" means (i) the power, direct or indirect, to cause the |
||||
|
direction or management of such entity, whether by contract or |
||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||
|
outstanding shares, or (iii) beneficial ownership of such entity. |
||||
|
|
||||
|
"You" (or "Your") shall mean an individual or Legal Entity |
||||
|
exercising permissions granted by this License. |
||||
|
|
||||
|
"Source" form shall mean the preferred form for making modifications, |
||||
|
including but not limited to software source code, documentation |
||||
|
source, and configuration files. |
||||
|
|
||||
|
"Object" form shall mean any form resulting from mechanical |
||||
|
transformation or translation of a Source form, including but |
||||
|
not limited to compiled object code, generated documentation, |
||||
|
and conversions to other media types. |
||||
|
|
||||
|
"Work" shall mean the work of authorship, whether in Source or |
||||
|
Object form, made available under the License, as indicated by a |
||||
|
copyright notice that is included in or attached to the work |
||||
|
(an example is provided in the Appendix below). |
||||
|
|
||||
|
"Derivative Works" shall mean any work, whether in Source or Object |
||||
|
form, that is based on (or derived from) the Work and for which the |
||||
|
editorial revisions, annotations, elaborations, or other modifications |
||||
|
represent, as a whole, an original work of authorship. For the purposes |
||||
|
of this License, Derivative Works shall not include works that remain |
||||
|
separable from, or merely link (or bind by name) to the interfaces of, |
||||
|
the Work and Derivative Works thereof. |
||||
|
|
||||
|
"Contribution" shall mean any work of authorship, including |
||||
|
the original version of the Work and any modifications or additions |
||||
|
to that Work or Derivative Works thereof, that is intentionally |
||||
|
submitted to Licensor for inclusion in the Work by the copyright owner |
||||
|
or by an individual or Legal Entity authorized to submit on behalf of |
||||
|
the copyright owner. For the purposes of this definition, "submitted" |
||||
|
means any form of electronic, verbal, or written communication sent |
||||
|
to the Licensor or its representatives, including but not limited to |
||||
|
communication on electronic mailing lists, source code control systems, |
||||
|
and issue tracking systems that are managed by, or on behalf of, the |
||||
|
Licensor for the purpose of discussing and improving the Work, but |
||||
|
excluding communication that is conspicuously marked or otherwise |
||||
|
designated in writing by the copyright owner as "Not a Contribution." |
||||
|
|
||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||
|
on behalf of whom a Contribution has been received by Licensor and |
||||
|
subsequently incorporated within the Work. |
||||
|
|
||||
|
2. Grant of Copyright License. Subject to the terms and conditions of |
||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
|
copyright license to reproduce, prepare Derivative Works of, |
||||
|
publicly display, publicly perform, sublicense, and distribute the |
||||
|
Work and such Derivative Works in Source or Object form. |
||||
|
|
||||
|
3. Grant of Patent License. Subject to the terms and conditions of |
||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
|
(except as stated in this section) patent license to make, have made, |
||||
|
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||
|
where such license applies only to those patent claims licensable |
||||
|
by such Contributor that are necessarily infringed by their |
||||
|
Contribution(s) alone or by combination of their Contribution(s) |
||||
|
with the Work to which such Contribution(s) was submitted. If You |
||||
|
institute patent litigation against any entity (including a |
||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||
|
or a Contribution incorporated within the Work constitutes direct |
||||
|
or contributory patent infringement, then any patent licenses |
||||
|
granted to You under this License for that Work shall terminate |
||||
|
as of the date such litigation is filed. |
||||
|
|
||||
|
4. Redistribution. You may reproduce and distribute copies of the |
||||
|
Work or Derivative Works thereof in any medium, with or without |
||||
|
modifications, and in Source or Object form, provided that You |
||||
|
meet the following conditions: |
||||
|
|
||||
|
(a) You must give any other recipients of the Work or |
||||
|
Derivative Works a copy of this License; and |
||||
|
|
||||
|
(b) You must cause any modified files to carry prominent notices |
||||
|
stating that You changed the files; and |
||||
|
|
||||
|
(c) You must retain, in the Source form of any Derivative Works |
||||
|
that You distribute, all copyright, patent, trademark, and |
||||
|
attribution notices from the Source form of the Work, |
||||
|
excluding those notices that do not pertain to any part of |
||||
|
the Derivative Works; and |
||||
|
|
||||
|
(d) If the Work includes a "NOTICE" text file as part of its |
||||
|
distribution, then any Derivative Works that You distribute must |
||||
|
include a readable copy of the attribution notices contained |
||||
|
within such NOTICE file, excluding those notices that do not |
||||
|
pertain to any part of the Derivative Works, in at least one |
||||
|
of the following places: within a NOTICE text file distributed |
||||
|
as part of the Derivative Works; within the Source form or |
||||
|
documentation, if provided along with the Derivative Works; or, |
||||
|
within a display generated by the Derivative Works, if and |
||||
|
wherever such third-party notices normally appear. The contents |
||||
|
of the NOTICE file are for informational purposes only and |
||||
|
do not modify the License. You may add Your own attribution |
||||
|
notices within Derivative Works that You distribute, alongside |
||||
|
or as an addendum to the NOTICE text from the Work, provided |
||||
|
that such additional attribution notices cannot be construed |
||||
|
as modifying the License. |
||||
|
|
||||
|
You may add Your own copyright statement to Your modifications and |
||||
|
may provide additional or different license terms and conditions |
||||
|
for use, reproduction, or distribution of Your modifications, or |
||||
|
for any such Derivative Works as a whole, provided Your use, |
||||
|
reproduction, and distribution of the Work otherwise complies with |
||||
|
the conditions stated in this License. |
||||
|
|
||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||
|
any Contribution intentionally submitted for inclusion in the Work |
||||
|
by You to the Licensor shall be under the terms and conditions of |
||||
|
this License, without any additional terms or conditions. |
||||
|
Notwithstanding the above, nothing herein shall supersede or modify |
||||
|
the terms of any separate license agreement you may have executed |
||||
|
with Licensor regarding such Contributions. |
||||
|
|
||||
|
6. Trademarks. This License does not grant permission to use the trade |
||||
|
names, trademarks, service marks, or product names of the Licensor, |
||||
|
except as required for reasonable and customary use in describing the |
||||
|
origin of the Work and reproducing the content of the NOTICE file. |
||||
|
|
||||
|
7. Disclaimer of Warranty. Unless required by applicable law or |
||||
|
agreed to in writing, Licensor provides the Work (and each |
||||
|
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||
|
implied, including, without limitation, any warranties or conditions |
||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||
|
appropriateness of using or redistributing the Work and assume any |
||||
|
risks associated with Your exercise of permissions under this License. |
||||
|
|
||||
|
8. Limitation of Liability. In no event and under no legal theory, |
||||
|
whether in tort (including negligence), contract, or otherwise, |
||||
|
unless required by applicable law (such as deliberate and grossly |
||||
|
negligent acts) or agreed to in writing, shall any Contributor be |
||||
|
liable to You for damages, including any direct, indirect, special, |
||||
|
incidental, or consequential damages of any character arising as a |
||||
|
result of this License or out of the use or inability to use the |
||||
|
Work (including but not limited to damages for loss of goodwill, |
||||
|
work stoppage, computer failure or malfunction, or any and all |
||||
|
other commercial damages or losses), even if such Contributor |
||||
|
has been advised of the possibility of such damages. |
||||
|
|
||||
|
9. Accepting Warranty or Additional Liability. While redistributing |
||||
|
the Work or Derivative Works thereof, You may choose to offer, |
||||
|
and charge a fee for, acceptance of support, warranty, indemnity, |
||||
|
or other liability obligations and/or rights consistent with this |
||||
|
License. However, in accepting such obligations, You may act only |
||||
|
on Your own behalf and on Your sole responsibility, not on behalf |
||||
|
of any other Contributor, and only if You agree to indemnify, |
||||
|
defend, and hold each Contributor harmless for any liability |
||||
|
incurred by, or claims asserted against, such Contributor by reason |
||||
|
of your accepting any such warranty or additional liability. |
||||
|
|
||||
|
END OF TERMS AND CONDITIONS |
||||
|
|
||||
|
APPENDIX: How to apply the Apache License to your work. |
||||
|
|
||||
|
To apply the Apache License to your work, attach the following |
||||
|
boilerplate notice, with the fields enclosed by brackets "[]" |
||||
|
replaced with your own identifying information. (Don't include |
||||
|
the brackets!) The text should be enclosed in the appropriate |
||||
|
comment syntax for the file format. We also recommend that a |
||||
|
file or class name and description of purpose be included on the |
||||
|
same "printed page" as the copyright notice for easier |
||||
|
identification within third-party archives. |
||||
|
|
||||
|
Copyright [yyyy] [name of copyright owner] |
||||
|
|
||||
|
Licensed 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 |
||||
|
|
||||
|
https://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. |
||||
|
|
||||
|
======================================================================= |
||||
|
|
||||
|
To the extent any open source subcomponents are licensed under the EPL and/or other |
||||
|
similar licenses that require the source code and/or modifications to |
||||
|
source code to be made available (as would be noted above), you may obtain a |
||||
|
copy of the source code corresponding to the binaries for such open source |
||||
|
components and modifications thereto, if any, (the "Source Files"), by |
||||
|
downloading the Source Files from https://www.springsource.org/download, |
||||
|
or by sending a request, with your name and address to: VMware, Inc., 3401 Hillview |
||||
|
Avenue, Palo Alto, CA 94304, United States of America or email info@vmware.com. All |
||||
|
such requests should clearly specify: OPEN SOURCE FILES REQUEST, Attention General |
||||
|
Counsel. VMware shall mail a copy of the Source Files to you on a CD or equivalent |
||||
|
physical medium. This offer to obtain a copy of the Source Files is valid for three |
||||
|
years from the date you acquired this Software product. |
@ -0,0 +1,66 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!-- 自动扫描本文件,如果发生变化,则重新初始化日志系统,并设置每隔5秒钟扫描一次 --> |
||||
|
<configuration debug="false" scan="true" scanPeriod="5 seconds"> |
||||
|
<!-- |
||||
|
以下为 logback 的 spring 扩展支持的功能,即支持从 application.properties 文件中获取属性,并在此文件中采用 ${} 方式使用。 |
||||
|
要使用此功能,必须使用 logback-ext-spring 扩展 jar 包,以 gradle 构建系统,则需要加入以下依赖 |
||||
|
dependencies { |
||||
|
compile( |
||||
|
"org.logback-extensions:logback-ext-spring:0.1.2" |
||||
|
) |
||||
|
} |
||||
|
--> |
||||
|
<property name="homedir" value="/Users/wangshaoping/wspsc/workspace/wangshaoping/v8/platform"/> |
||||
|
<property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n"/> |
||||
|
|
||||
|
<!-- 在控制台中输出日志 --> |
||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
||||
|
<encoder><pattern>${pattern}</pattern></encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<!-- 在磁盘文件中输出日志 --> |
||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
|
<encoder><pattern>${pattern}</pattern></encoder> |
||||
|
<file>${homedir}/logs/log.log</file> |
||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
||||
|
<fileNamePattern>${homedir}/logs/log.%d.log</fileNamePattern> |
||||
|
<maxHistory>30</maxHistory> |
||||
|
</rollingPolicy> |
||||
|
</appender> |
||||
|
|
||||
|
<root level="info"> |
||||
|
<appender-ref ref="STDOUT" /> |
||||
|
<appender-ref ref="FILE" /> |
||||
|
</root> |
||||
|
|
||||
|
<logger name="org.wsp.engine.model.core.code" level="info" additivity="false"/> |
||||
|
|
||||
|
<logger name="org.wsp.engine.rule.core.code" level="debug" additivity="false"> |
||||
|
<appender-ref ref="STDOUT" /> |
||||
|
<appender-ref ref="FILE" /> |
||||
|
</logger> |
||||
|
|
||||
|
<logger name="org.springframework.security" level="info" additivity="false"> |
||||
|
<appender-ref ref="STDOUT" /> |
||||
|
<appender-ref ref="FILE" /> |
||||
|
</logger> |
||||
|
|
||||
|
|
||||
|
<!-- 可对不同的日志写入不同的文件示例 --> |
||||
|
<!-- |
||||
|
<appender name="RULE_ENGINE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
||||
|
<encoder><pattern>${pattern}</pattern></encoder> |
||||
|
<file>${homedir}/logs/rule-engine.log</file> |
||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
||||
|
<fileNamePattern>${homedir}/logs/rule-engine.%d.log</fileNamePattern> |
||||
|
<maxHistory>30</maxHistory> |
||||
|
</rollingPolicy> |
||||
|
</appender> |
||||
|
|
||||
|
<logger name="org.wsp.engine.rule.core.code" level="debug" additivity="false"> |
||||
|
<appender-ref ref="STDOUT" /> |
||||
|
<appender-ref ref="FILE" /> |
||||
|
<appender-ref ref="RULE_ENGINE_FILE" /> |
||||
|
</logger> |
||||
|
--> |
||||
|
</configuration> |
@ -0,0 +1,167 @@ |
|||||
|
import { laBell } from '@quasar/extras/line-awesome'; import { mergeProps } from 'vue'; import { pushScopeId } from 'vue'; import { clear } from 'console'; |
||||
|
<template> |
||||
|
<div> |
||||
|
<div class="flex justify-between"> |
||||
|
<div class="text-h6">{{ title }}</div> |
||||
|
<div class="flex justify-end gap-4"> |
||||
|
<template v-for="(btn, index) in actions as any" :key="index"> |
||||
|
<q-btn v-if="typeof btn === 'object'" :loading="btn.loading ? btn.loading : false" :label="btn.label" :icon="btn.icon" outline @click="btn.click()"> |
||||
|
</q-btn> |
||||
|
</template> |
||||
|
</div> |
||||
|
</div> |
||||
|
<q-tree |
||||
|
ref="tree" |
||||
|
v-bind="attrs" |
||||
|
v-model:selected="selectedRef" |
||||
|
v-model:ticked="tickedRef" |
||||
|
v-model:expanded="expandedRef" |
||||
|
class="w-full" |
||||
|
:nodes="nodesRef" |
||||
|
node-key="id" |
||||
|
label-key="i18nLabel" |
||||
|
/> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, useAttrs, toRaw } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { TreeBuilder } from '@/platform'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
const props = defineProps({ |
||||
|
title: { type: String, default: '' }, |
||||
|
labelI18n: { type: Boolean, default: false }, |
||||
|
labelEmpty: { type: String, default: '' }, |
||||
|
actions: { type: Array, default: () => [] }, |
||||
|
}); |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const tree = ref(); |
||||
|
|
||||
|
const nodesCache = new Map<string, object>(); |
||||
|
const nodesRef = ref(TreeBuilder.build(attrs.nodes)); |
||||
|
const selectedRef = ref([]); |
||||
|
const tickedRef = ref([]); |
||||
|
const expandedRef = ref([]); |
||||
|
|
||||
|
const getNodeById = (id: string) => { |
||||
|
return nodesCache.get(id); |
||||
|
}; |
||||
|
|
||||
|
const setNodes = (nodes) => { |
||||
|
nodesCache.clear(); |
||||
|
const tickeds = []; |
||||
|
if (nodes && nodes.length > 0) { |
||||
|
const labelKey = attrs['label-key']; |
||||
|
for (const node of nodes) { |
||||
|
const label = node[labelKey]; |
||||
|
if (props.labelI18n) { |
||||
|
if (label) { |
||||
|
node.i18nLabel = t(label); |
||||
|
} else { |
||||
|
if (props.labelEmpty) { |
||||
|
node.i18nLabel = t(props.labelEmpty); |
||||
|
} else { |
||||
|
node.i18nLabel = label; |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
node.i18nLabel = label; |
||||
|
} |
||||
|
nodesCache.set(node.id, node); |
||||
|
if (node.selected) { |
||||
|
tickeds.push(node.id); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
nodesRef.value = TreeBuilder.build(nodes); |
||||
|
tickedRef.value = tickeds; |
||||
|
}; |
||||
|
|
||||
|
const getSelectedNode = () => { |
||||
|
return nodesCache.get(selectedRef.value); |
||||
|
}; |
||||
|
|
||||
|
const getSelected = () => { |
||||
|
return selectedRef.value; |
||||
|
}; |
||||
|
|
||||
|
const setSelected = (selected) => { |
||||
|
selectedRef.value = selected; |
||||
|
}; |
||||
|
|
||||
|
const setTicked = (ticked) => { |
||||
|
tickedRef.value = ticked; |
||||
|
}; |
||||
|
|
||||
|
const getTicked = () => { |
||||
|
const result = new Set<string>(); |
||||
|
const tickeds = toRaw(tickedRef.value); |
||||
|
if (tickeds && tickeds.length > 0) { |
||||
|
for (const ticked of tickeds) { |
||||
|
result.add(ticked); |
||||
|
} |
||||
|
for (const ticked of tickeds) { |
||||
|
getAllParentIds(nodesCache.get(ticked).parentId, result); |
||||
|
} |
||||
|
} |
||||
|
return [...result]; |
||||
|
}; |
||||
|
|
||||
|
const getAllParentIds = (parentId, result) => { |
||||
|
if (parentId) { |
||||
|
const parent = nodesCache.get(parentId); |
||||
|
if (parent) { |
||||
|
result.add(parent.id); |
||||
|
getAllParentIds(parent.parentId, result); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const getCascadeParentIds = (id) => { |
||||
|
const result = []; |
||||
|
let node = nodesCache.get(id); |
||||
|
if (node) { |
||||
|
result.push(id); |
||||
|
while (node.parentId) { |
||||
|
result.push(node.parentId); |
||||
|
node = nodesCache.get(node.parentId); |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
}; |
||||
|
|
||||
|
const getCascadeChildrenIds = (id) => { |
||||
|
const result = []; |
||||
|
let node = nodesCache.get(id); |
||||
|
if (node) { |
||||
|
if (node.children && node.children.length > 0) { |
||||
|
for (const child of node.children) { |
||||
|
result.push(child.id); |
||||
|
const childResult = getCascadeChildrenIds(child.id); |
||||
|
if (childResult && childResult.length > 0) { |
||||
|
result.push(...childResult); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
}; |
||||
|
|
||||
|
defineExpose({ |
||||
|
getNodeById, |
||||
|
setNodes, |
||||
|
|
||||
|
getTicked, |
||||
|
setTicked, |
||||
|
|
||||
|
getSelectedNode, |
||||
|
getSelected, |
||||
|
setSelected, |
||||
|
|
||||
|
getCascadeParentIds, |
||||
|
getCascadeChildrenIds, |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,58 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<w-tree-grid |
||||
|
ref="treeGrid" |
||||
|
title="机构树" |
||||
|
:nodes="nodes" |
||||
|
label-key="titleI18nKey" |
||||
|
label-i18n |
||||
|
label-empty="--------------------" |
||||
|
:actions="actions" |
||||
|
tick-strategy="leaf" |
||||
|
/> |
||||
|
<q-btn label="ok" @click="ok"></q-btn> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, toRaw, onMounted } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { Environment, axios, BackendTools } from '@/platform'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const treeGrid = ref(); |
||||
|
const nodes = ref([]); |
||||
|
const selected = []; |
||||
|
const ticked = []; |
||||
|
const expanded = []; |
||||
|
const actions = [ |
||||
|
{ |
||||
|
name: 'refresh', |
||||
|
label: '刷新', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'expandAll', |
||||
|
label: '全部展开', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'selectAll', |
||||
|
label: '全部选择', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'save', |
||||
|
label: '保存', |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
axios.get(Environment.apiContextPath('/api/system/menu?pageable=false')).then((response) => { |
||||
|
treeGrid.value.setNodes(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
const ok = () => { |
||||
|
console.log(treeGrid.value.getCascadeParentIds(treeGrid.value.getSelected())); |
||||
|
console.log(treeGrid.value.getCascadeChildrenIds(treeGrid.value.getSelected())); |
||||
|
console.log(treeGrid.value.getSelectedNode(treeGrid.value.getSelected())); |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,58 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<w-tree-grid |
||||
|
ref="treeGrid" |
||||
|
title="机构树" |
||||
|
:nodes="nodes" |
||||
|
label-key="titleI18nKey" |
||||
|
label-i18n |
||||
|
label-empty="--------------------" |
||||
|
:actions="actions" |
||||
|
tick-strategy="leaf" |
||||
|
/> |
||||
|
<q-btn label="ok" @click="ok"></q-btn> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, toRaw, onMounted } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { Environment, axios, BackendTools } from '@/platform'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const treeGrid = ref(); |
||||
|
const nodes = ref([]); |
||||
|
const selected = []; |
||||
|
const ticked = []; |
||||
|
const expanded = []; |
||||
|
const actions = [ |
||||
|
{ |
||||
|
name: 'refresh', |
||||
|
label: '刷新', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'expandAll', |
||||
|
label: '全部展开', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'selectAll', |
||||
|
label: '全部选择', |
||||
|
}, |
||||
|
{ |
||||
|
name: 'save', |
||||
|
label: '保存', |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
axios.get(Environment.apiContextPath('/api/system/menu?pageable=false')).then((response) => { |
||||
|
treeGrid.value.setNodes(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
const ok = () => { |
||||
|
console.log(treeGrid.value.getCascadeParentIds(treeGrid.value.getSelected())); |
||||
|
console.log(treeGrid.value.getCascadeChildrenIds(treeGrid.value.getSelected())); |
||||
|
console.log(treeGrid.value.getSelectedNode(treeGrid.value.getSelected())); |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,11 @@ |
|||||
|
{ |
||||
|
"name": "app.platform", |
||||
|
"components": [ |
||||
|
], |
||||
|
"resources": [ |
||||
|
"/public/configure.js", |
||||
|
"/public/favicon.svg", |
||||
|
"/public/login-bg.jpg", |
||||
|
"/public/logo.svg" |
||||
|
] |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
//ext['oracle-database.version'] = '12.2.0.1' |
||||
|
|
||||
|
dependencies { |
||||
|
api( |
||||
|
"oracle:oracle:12.2.0.1", |
||||
|
) |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
{ |
||||
|
"installerEnable" : true, |
||||
|
"type" : "Oracle", |
||||
|
"version" : "12.2", |
||||
|
"driver" : "oracle.jdbc.OracleDriver", |
||||
|
"url" : "jdbc:oracle:thin:@${host}:${port}:${sid}", |
||||
|
"urlSample" : "jdbc:oracle:thin:@localhost:1521:EE", |
||||
|
"hibernateDialect" : "org.hibernate.dialect.Oracle10gDialect", |
||||
|
"validationQuery" : "select 1 from dual" |
||||
|
} |
@ -1,6 +1,7 @@ |
|||||
|
//ext['oracle-database.version'] = '12.2.0.1' |
||||
|
|
||||
dependencies { |
dependencies { |
||||
api( |
api( |
||||
"com.oracle.database.jdbc:ojdbc8", |
"oracle:oracle:12.2.0.1", |
||||
"com.oracle.database.nls:orai18n" |
|
||||
) |
) |
||||
} |
} |
@ -0,0 +1,12 @@ |
|||||
|
dependencies { |
||||
|
api( |
||||
|
project(":io.sc.platform.jdbc"), |
||||
|
|
||||
|
"us.fatehi:schemacrawler:${schemacrawler_version}", |
||||
|
"us.fatehi:schemacrawler-mysql:${schemacrawler_version}", |
||||
|
"us.fatehi:schemacrawler-oracle:${schemacrawler_version}", |
||||
|
"us.fatehi:schemacrawler-db2:${schemacrawler_version}", |
||||
|
"us.fatehi:schemacrawler-postgresql:${schemacrawler_version}", |
||||
|
"us.fatehi:schemacrawler-sqlite:${schemacrawler_version}", |
||||
|
) |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
|
@ -0,0 +1,218 @@ |
|||||
|
package io.sc.platform.jdbc.schemacrawler; |
||||
|
|
||||
|
import io.sc.platform.jdbc.DatabaseType; |
||||
|
import io.sc.platform.jdbc.meta.MetaDataLoader; |
||||
|
import io.sc.platform.jdbc.meta.support.*; |
||||
|
import org.springframework.jdbc.datasource.DataSourceUtils; |
||||
|
import schemacrawler.schema.Catalog; |
||||
|
import schemacrawler.schema.TableRelationshipType; |
||||
|
import schemacrawler.schemacrawler.*; |
||||
|
import schemacrawler.utility.SchemaCrawlerUtility; |
||||
|
|
||||
|
import javax.sql.DataSource; |
||||
|
import java.sql.Connection; |
||||
|
import java.sql.SQLException; |
||||
|
import java.util.*; |
||||
|
|
||||
|
public class MetaDataLoaderImpl implements MetaDataLoader { |
||||
|
private Map<DataSource, Catalog> catalogs =new HashMap<DataSource,Catalog>(); |
||||
|
private Object lock =new Object(); |
||||
|
|
||||
|
public void crawler(DataSource dataSource) throws SQLException { |
||||
|
crawler(dataSource,getDefaultOptions(dataSource)); |
||||
|
} |
||||
|
|
||||
|
public void crawler(DataSource dataSource, SchemaCrawlerOptions options) throws SQLException { |
||||
|
//catalogs.clear();
|
||||
|
Connection connection = null; |
||||
|
try { |
||||
|
connection = DataSourceUtils.getConnection(dataSource); |
||||
|
synchronized (lock) { |
||||
|
catalogs.put(dataSource, SchemaCrawlerUtility.getCatalog(connection,getDefaultOptions(dataSource))); |
||||
|
} |
||||
|
}catch (SchemaCrawlerException e) { |
||||
|
throw new SQLException(e); |
||||
|
}finally { |
||||
|
DataSourceUtils.releaseConnection(connection, dataSource); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public Catalog getCatalog(DataSource dataSource) throws SQLException{ |
||||
|
return getCatalog(dataSource,getDefaultOptions(dataSource)); |
||||
|
} |
||||
|
|
||||
|
public Catalog getCatalog(DataSource dataSource, SchemaCrawlerOptions options) throws SQLException{ |
||||
|
synchronized (lock) { |
||||
|
if(!catalogs.containsKey(dataSource)) { |
||||
|
crawler(dataSource,options); |
||||
|
} |
||||
|
return catalogs.get(dataSource); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<Schema> getSchemas(DataSource dataSource) throws MetaDataAccessException { |
||||
|
Catalog catalog = null; |
||||
|
try { |
||||
|
catalog = getCatalog(dataSource); |
||||
|
} catch (SQLException e) { |
||||
|
throw new MetaDataAccessException(e); |
||||
|
} |
||||
|
if(catalog!=null) { |
||||
|
Collection<schemacrawler.schema.Schema> schemas =catalog.getSchemas(); |
||||
|
if(schemas!=null && schemas.size()>0) { |
||||
|
List<Schema> result =new ArrayList<>(); |
||||
|
for(schemacrawler.schema.Schema schema : schemas){ |
||||
|
result.add(from(schema)); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<TableSummary> getTableSummary(DataSource dataSource, String schemaName) throws MetaDataAccessException { |
||||
|
List<Table> tables =getTables(dataSource,schemaName); |
||||
|
List<TableSummary> result =new ArrayList<>(); |
||||
|
for(Table table : tables){ |
||||
|
TableSummary summary =new TableSummary(); |
||||
|
summary.setName(table.getName()); |
||||
|
summary.setRemarks(table.getRemarks()); |
||||
|
result.add(summary); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<TableSummary> getTableSummary(DataSource dataSource, String schemaName, boolean isCount) throws MetaDataAccessException { |
||||
|
return getTableSummary(dataSource,schemaName,false); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<Table> getTables(DataSource dataSource, String schemaName, String... tableNames) throws MetaDataAccessException { |
||||
|
Catalog catalog = null; |
||||
|
try { |
||||
|
catalog = getCatalog(dataSource); |
||||
|
} catch (SQLException e) { |
||||
|
throw new MetaDataAccessException(e); |
||||
|
} |
||||
|
if(catalog!=null) { |
||||
|
schemacrawler.schema.Schema schema =findSchema(catalog,schemaName); |
||||
|
if(schema!=null) { |
||||
|
Collection<schemacrawler.schema.Table> tables =catalog.getTables(schema); |
||||
|
if(tables!=null && tables.size()>0) { |
||||
|
List<Table> result =new ArrayList<Table>(); |
||||
|
for(schemacrawler.schema.Table table : tables){ |
||||
|
result.add(from(table)); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public boolean isSelfReference(schemacrawler.schema.Table table) { |
||||
|
Collection<schemacrawler.schema.Table> parentTables =table.getRelatedTables(TableRelationshipType.parent); |
||||
|
if(parentTables!=null && !parentTables.isEmpty()) { |
||||
|
for(schemacrawler.schema.Table parentTable : parentTables) { |
||||
|
if(parentTable.equals(table)) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
private Schema from(schemacrawler.schema.Schema schema){ |
||||
|
Schema result =new Schema(); |
||||
|
result.setName(schema.getName()==null?schema.getCatalogName():schema.getName()); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
private Table from(schemacrawler.schema.Table table){ |
||||
|
Table result =new Table(); |
||||
|
result.setName(table.getName()); |
||||
|
result.setRemarks(table.getRemarks()); |
||||
|
// 处理列
|
||||
|
for(schemacrawler.schema.Column column : table.getColumns()) { |
||||
|
result.getColumns().add(from(column)); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
private Column from(schemacrawler.schema.Column column){ |
||||
|
Column result =new Column(); |
||||
|
result.setName(column.getName()); |
||||
|
result.setRemarks(column.getRemarks()); |
||||
|
result.setJavaType(column.getType().getTypeMappedClass()); |
||||
|
result.setSqlType(column.getColumnDataType().getJavaSqlType().getName()); |
||||
|
result.setVendorTypeNumber(column.getColumnDataType().getJavaSqlType().getVendorTypeNumber()); |
||||
|
result.setNullable(column.isNullable()); |
||||
|
result.setDefaultValue(column.getDefaultValue()); |
||||
|
result.setGenerated(column.isGenerated()); |
||||
|
result.setHidden(column.isHidden()); |
||||
|
result.setAutoIncremented(column.isAutoIncremented()); |
||||
|
result.setPartOfIndex(column.isPartOfIndex()); |
||||
|
result.setPartOfUniqueIndex(column.isPartOfUniqueIndex()); |
||||
|
result.setPartOfPrimaryKey(column.isPartOfPrimaryKey()); |
||||
|
result.setSize(column.getSize()); |
||||
|
result.setWidth(column.getWidth()); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
private SchemaCrawlerOptions getDefaultOptions(DataSource dataSource) { |
||||
|
final SchemaCrawlerOptions options = new SchemaCrawlerOptions(); |
||||
|
options.setSchemaInfoLevel(SchemaInfoLevelBuilder.standard()); |
||||
|
options.setRoutineInclusionRule(new ExcludeAll()); |
||||
|
options.setTableInclusionRule(new IncludeAll()); |
||||
|
|
||||
|
|
||||
|
options.setSchemaInclusionRule(new RegularExpressionInclusionRule("I9")); |
||||
|
//options.setSchemaInclusionRule(new RegularExpressionInclusionRule("FRAMEWORK"));
|
||||
|
|
||||
|
|
||||
|
DatabaseType type =null; |
||||
|
try { |
||||
|
type = DatabaseType.fromMetaData(dataSource); |
||||
|
} catch (org.springframework.jdbc.support.MetaDataAccessException e) { |
||||
|
throw new RuntimeException(e); |
||||
|
} |
||||
|
switch(type) { |
||||
|
case DB2: |
||||
|
options.setSchemaInclusionRule(new RegularExpressionExclusionRule("NULLID|SQLJ|SYSCAT|SYSFUN|SYSIBM|SYSIBMADM|SYSIBMINTERNAL|SYSIBMTS|SYSPROC|SYSPUBLIC|SYSSTAT|SYSTOOLS")); |
||||
|
break; |
||||
|
case ORACLE: |
||||
|
options.setSchemaInclusionRule(new RegularExpressionExclusionRule("ANONYMOUS|APEX_PUBLIC_USER|APPQOSSYS|BI|CTXSYS|DBSNMP|DIP|EXFSYS|FLOWS_30000|FLOWS_FILES|GSMADMIN_INTERNAL|HR|IX|LBACSYS|MDDATA|MDSYS|MGMT_VIEW|OE|OLAPSYS|ORACLE_OCM|ORDDATA|ORDPLUGINS|ORDSYS|OUTLN|OWBSYS|OWBSYS_AUDIT|PM|RDSADMIN|SCOTT|SH|SI_INFORMTN_SCHEMA|SPATIAL_CSW_ADMIN_USR|SPATIAL_WFS_ADMIN_USR|SYS|SYSMAN|\\\"SYSTEM\\\"|TSMSYS|WKPROXY|WKSYS|WK_TEST|WMSYS|XDB|APEX_[0-9]{6}|FLOWS_[0-9]{5,6}|XS\\$NULL|\\\"XS\\$NULL\\\"")); |
||||
|
break; |
||||
|
case MYSQL: |
||||
|
options.setSchemaInclusionRule(new RegularExpressionExclusionRule("sys|mysql|performance_schema|information_schema")); |
||||
|
break; |
||||
|
case POSTGRESQL: |
||||
|
options.setSchemaInclusionRule(new RegularExpressionExclusionRule("pg_catalog|information_schema")); |
||||
|
break; |
||||
|
default: |
||||
|
} |
||||
|
return options; |
||||
|
} |
||||
|
|
||||
|
private schemacrawler.schema.Schema findSchema(Catalog catalog,String schemaName) { |
||||
|
Collection<schemacrawler.schema.Schema> schemas =catalog.getSchemas(); |
||||
|
if(schemas!=null && schemas.size()>0) { |
||||
|
for(schemacrawler.schema.Schema schema : schemas) { |
||||
|
DatabaseType type =DatabaseType.fromProductName(catalog.getDatabaseInfo().getProductName()); |
||||
|
if(DatabaseType.MYSQL.equals(type)) {//mysql 没有 schema,只有 catalog
|
||||
|
if(schema.getCatalogName().equalsIgnoreCase(schemaName)) { |
||||
|
return schema; |
||||
|
} |
||||
|
}else { |
||||
|
if(schema.getName().equalsIgnoreCase(schemaName)) { |
||||
|
return schema; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
package io.sc.platform.jdbc.schemacrawler; |
||||
|
|
||||
|
import schemacrawler.schema.Table; |
||||
|
import schemacrawler.schema.TableRelationshipType; |
||||
|
|
||||
|
import java.util.Collection; |
||||
|
import java.util.Comparator; |
||||
|
|
||||
|
public class ParentAndChildrenTableComparator implements Comparator<Table> { |
||||
|
@Override |
||||
|
public int compare(Table o1, Table o2) { |
||||
|
Collection<Table> parentTables =o1.getRelatedTables(TableRelationshipType.parent); |
||||
|
Collection<schemacrawler.schema.Table> childrenTables =o1.getRelatedTables(TableRelationshipType.child); |
||||
|
if(parentTables!=null && !parentTables.isEmpty() && parentTables.contains(o2)) { |
||||
|
return 1; |
||||
|
}else if(childrenTables!=null && !childrenTables.isEmpty() && childrenTables.contains(o2)) { |
||||
|
return -1; |
||||
|
}else { |
||||
|
return o1.getName().compareTo(o2.getName()); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
io.sc.platform.jdbc.schemacrawler.MetaDataLoaderImpl |
@ -0,0 +1,22 @@ |
|||||
|
package io.sc.platform.mvc.support; |
||||
|
|
||||
|
public class OrderItem<ID,ORDER> { |
||||
|
private ID id; |
||||
|
private ORDER order; |
||||
|
|
||||
|
public ID getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(ID id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public ORDER getOrder() { |
||||
|
return order; |
||||
|
} |
||||
|
|
||||
|
public void setOrder(ORDER order) { |
||||
|
this.order = order; |
||||
|
} |
||||
|
} |
@ -1,12 +1,12 @@ |
|||||
[ |
[ |
||||
/*系统*/ |
/*系统*/ |
||||
{"id":"parameter.system","order":0}, |
{"id":"parameter.system","order":0}, |
||||
/*系统/首页 Thymeleaf 视图模板*/ |
/*系统/首页路由*/ |
||||
{ |
{ |
||||
"id" : "parameter.system.indexPageTemplate", |
"id" : "parameter.system.homePage", |
||||
"parentId" : "parameter.system", |
"parentId" : "parameter.system", |
||||
"code" : "parameter.system.indexPageTemplate", |
"code" : "parameter.system.homePage", |
||||
"defaultValue" : "io.sc.platform.mvc.frontend.html", |
"defaultValue" : "/home", |
||||
"order" : 100 |
"order" : 100 |
||||
} |
} |
||||
] |
] |
@ -0,0 +1,44 @@ |
|||||
|
package io.sc.platform.system.api.announcement; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonPropertyOrder; |
||||
|
import io.sc.platform.orm.api.vo.AuditorVo; |
||||
|
|
||||
|
|
||||
|
@JsonPropertyOrder({ |
||||
|
"id", |
||||
|
"title", |
||||
|
"content", |
||||
|
"creator", |
||||
|
"createDate", |
||||
|
"lastModifier", |
||||
|
"lastModifyDate" |
||||
|
}) |
||||
|
public class AnnouncementVo extends AuditorVo { |
||||
|
private String id; |
||||
|
private String title; |
||||
|
private String content; |
||||
|
|
||||
|
public String getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(String id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getTitle() { |
||||
|
return title; |
||||
|
} |
||||
|
|
||||
|
public void setTitle(String title) { |
||||
|
this.title = title; |
||||
|
} |
||||
|
|
||||
|
public String getContent() { |
||||
|
return content; |
||||
|
} |
||||
|
|
||||
|
public void setContent(String content) { |
||||
|
this.content = content; |
||||
|
} |
||||
|
} |
@ -1,4 +0,0 @@ |
|||||
package io.sc.platform.system.api.parameter; |
|
||||
|
|
||||
public class Parameter { |
|
||||
} |
|
@ -0,0 +1,40 @@ |
|||||
|
package io.sc.platform.system.api.parameter; |
||||
|
|
||||
|
public class ParameterVo { |
||||
|
private String id; |
||||
|
private String code; |
||||
|
private String value; |
||||
|
private String parentId; |
||||
|
|
||||
|
public String getId() { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
public void setId(String id) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
|
||||
|
public String getCode() { |
||||
|
return code; |
||||
|
} |
||||
|
|
||||
|
public void setCode(String code) { |
||||
|
this.code = code; |
||||
|
} |
||||
|
|
||||
|
public String getValue() { |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
public void setValue(String value) { |
||||
|
this.value = value; |
||||
|
} |
||||
|
|
||||
|
public String getParentId() { |
||||
|
return parentId; |
||||
|
} |
||||
|
|
||||
|
public void setParentId(String parentId) { |
||||
|
this.parentId = parentId; |
||||
|
} |
||||
|
} |
@ -1,4 +0,0 @@ |
|||||
<template> |
|
||||
<div>Corporation</div> |
|
||||
</template> |
|
||||
<script setup lang="ts"></script> |
|
@ -1,4 +0,0 @@ |
|||||
<template> |
|
||||
<div>Dictionary</div> |
|
||||
</template> |
|
||||
<script setup lang="ts"></script> |
|
@ -1,4 +0,0 @@ |
|||||
<template> |
|
||||
<div>Parameter</div> |
|
||||
</template> |
|
||||
<script setup lang="ts"></script> |
|
@ -0,0 +1,70 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<platform-grid |
||||
|
ref="announcementGridRef" |
||||
|
:table-props="{ borderded: false, flat: true }" |
||||
|
:query-form-cols-number="announcementConfigure.queryFormColsNumber" |
||||
|
:query-form-cols-auto="announcementConfigure.queryFormColsAuto" |
||||
|
:table-title="announcementConfigure.tableTitle" |
||||
|
:table-row-key="announcementConfigure.tableRowKey" |
||||
|
:table-init-load-data="announcementConfigure.tableInitLoadData" |
||||
|
:table-data-url="announcementConfigure.tableDataUrl" |
||||
|
:table-show-sort-no="false" |
||||
|
:table-columns="announcementConfigure.tableColumns" |
||||
|
:table-left-column-sticky-number="announcementConfigure.tableLeftColumnStickyNumber" |
||||
|
:table-buttons="announcementConfigure.tableButtons" |
||||
|
:query-form-fields="announcementConfigure.queryFormFields" |
||||
|
:table-pagination="announcementConfigure.tablePagination" |
||||
|
:add-form-props="announcementConfigure.addFormProps" |
||||
|
:table-dense="false" |
||||
|
@row-click="announcementConfigure.rowClickFun" |
||||
|
> |
||||
|
</platform-grid> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { Environment, axios } from 'platform-core'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const announcementConfigure = { |
||||
|
queryFormColsNumber: 4, |
||||
|
queryFormColsAuto: false, |
||||
|
hideBottom: false, |
||||
|
tableInitLoadData: true, |
||||
|
tableLeftColumnStickyNumber: 0, |
||||
|
tableTitle: t('system.announcement.gridTitle'), |
||||
|
tableRowKey: 'id', |
||||
|
tableDataUrl: Environment.apiContextPath('/api/system/announcement'), |
||||
|
tablePagination: { |
||||
|
sortBy: 'lastModifyDate', |
||||
|
descending: true, |
||||
|
reqPageStart: 0, |
||||
|
rowsPerPage: 10, |
||||
|
}, |
||||
|
queryFormFields: [ |
||||
|
{ width: 100, name: 'title', label: t('title') }, |
||||
|
{ width: 110, name: 'lastModifier', label: t('lastModifier') }, |
||||
|
{ width: 115, name: 'lastModifyDate', label: t('lastModifyDate') }, |
||||
|
], |
||||
|
tableButtons: ['add', 'edit', 'delete', 'separator', 'view', 'inFullscreen'], |
||||
|
tableColumns: [ |
||||
|
{ width: 100, name: 'title', label: t('title') }, |
||||
|
{ width: 100, name: 'content', label: t('content') }, |
||||
|
{ width: 110, name: 'lastModifier', label: t('lastModifier') }, |
||||
|
{ width: 115, name: 'lastModifyDate', label: t('lastModifyDate') }, |
||||
|
], |
||||
|
addFormProps: { |
||||
|
dialogInitWidth: '50%', |
||||
|
dialogInitHeight: '90%', |
||||
|
formColsNumber: 1, |
||||
|
formColsAuto: false, |
||||
|
formFields: [ |
||||
|
{ modelName: 'title', label: t('title'), type: 'text', required: true }, |
||||
|
{ modelName: 'content', label: t('content'), type: 'textarea', required: true }, |
||||
|
], |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,51 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<w-tree-grid ref="corporationTreeGridRef" title="法人树" label-key="name" :actions="corporationConfigure.actions" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, onMounted } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { Environment, axios } from 'platform-core'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const corporationTreeGridRef = ref(); |
||||
|
|
||||
|
const corporationConfigure = { |
||||
|
actions: [ |
||||
|
{ |
||||
|
name: 'refresh', |
||||
|
label: t('refresh'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
name: 'addRoot', |
||||
|
label: t('system.corporation.action.addTop'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'addChild', |
||||
|
label: t('system.corporation.action.addChild'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'edit', |
||||
|
label: t('edit'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'delete', |
||||
|
label: t('delete'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
axios.get(Environment.apiContextPath('/api/system/corporation?pageable=false&sortBy=name')).then((response) => { |
||||
|
corporationTreeGridRef.value.setNodes(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,70 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<platform-grid |
||||
|
ref="dictionaryGridRef" |
||||
|
:table-props="{ borderded: false, flat: true }" |
||||
|
:table-title="dictionaryConfigure.tableTitle" |
||||
|
:table-init-load-data="dictionaryConfigure.tableInitLoadData" |
||||
|
:table-row-key="dictionaryConfigure.tableRowKey" |
||||
|
:table-data-url="dictionaryConfigure.tableDataUrl" |
||||
|
:table-columns="dictionaryConfigure.tableColumns" |
||||
|
:table-buttons="dictionaryConfigure.tableButtons" |
||||
|
:add-form-props="dictionaryConfigure.addFormProps" |
||||
|
:table-show-sort-no="false" |
||||
|
:table-dense="true" |
||||
|
:table-row-drag="true" |
||||
|
:table-pagination="dictionaryConfigure.tablePagination" |
||||
|
@row-drag-drop-after="rowDragDropAfter" |
||||
|
> |
||||
|
</platform-grid> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { onMounted, ref } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { Environment, axios } from 'platform-core'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const dictionaryGridRef = ref(); |
||||
|
const dictionaryConfigure = { |
||||
|
tableTitle: '数据字典列表', |
||||
|
tableInitLoadData: true, |
||||
|
tableRowKey: 'id', |
||||
|
tableDataUrl: Environment.apiContextPath('/api/system/dictionary'), |
||||
|
tablePagination: { |
||||
|
sortBy: 'order', |
||||
|
descending: false, |
||||
|
reqPageStart: 0, |
||||
|
rowsPerPage: 0, |
||||
|
}, |
||||
|
tableColumns: [ |
||||
|
{ name: 'code', label: t('code') }, |
||||
|
{ name: 'value', label: t('value') }, |
||||
|
{ name: 'value', label: t('displayValue'), format: (value) => t(value) }, |
||||
|
{ name: 'order', label: t('order') }, |
||||
|
], |
||||
|
tableButtons: ['refresh', 'add', 'edit', 'delete'], |
||||
|
addFormProps: { |
||||
|
dialogInitWidth: '50%', |
||||
|
dialogInitHeight: '90%', |
||||
|
formColsNumber: 1, |
||||
|
formColsAuto: false, |
||||
|
formFields: [ |
||||
|
{ modelName: 'code', label: t('code'), type: 'text', required: true }, |
||||
|
{ modelName: 'value', label: t('value'), type: 'text', required: true }, |
||||
|
{ modelName: 'order', label: t('order'), type: 'text', required: true }, |
||||
|
], |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
const rowDragDropAfter = () => { |
||||
|
const rows = dictionaryGridRef.value.getRowsFun(); |
||||
|
for (let i = 0; i < rows.length; i++) { |
||||
|
rows[i].order = i; |
||||
|
} |
||||
|
axios.post(Environment.apiContextPath('/api/system/dictionary/updateDictionariesOrder'), rows).then(() => { |
||||
|
//dictionaryGridRef.value.refreshTable(); |
||||
|
}); |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,70 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<platform-grid |
||||
|
ref="i18nGridRef" |
||||
|
:table-props="{ borderded: false, flat: true }" |
||||
|
:table-title="i18nConfigure.tableTitle" |
||||
|
:table-init-load-data="i18nConfigure.tableInitLoadData" |
||||
|
:table-row-key="i18nConfigure.tableRowKey" |
||||
|
:table-data-url="i18nConfigure.tableDataUrl" |
||||
|
:table-columns="i18nConfigure.tableColumns" |
||||
|
:table-buttons="i18nConfigure.tableButtons" |
||||
|
:add-form-props="i18nConfigure.addFormProps" |
||||
|
:table-show-sort-no="false" |
||||
|
:table-dense="true" |
||||
|
:table-row-drag="true" |
||||
|
:table-pagination="i18nConfigure.tablePagination" |
||||
|
> |
||||
|
</platform-grid> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { onMounted, ref } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { Environment, axios } from 'platform-core'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const Language = { |
||||
|
en: '英文', |
||||
|
zh_CN: '简体中文', |
||||
|
tw_CN: '繁体中文', |
||||
|
}; |
||||
|
|
||||
|
const LanguageOptions = [ |
||||
|
{ label: '英文', value: 'en' }, |
||||
|
{ label: '简体中文', value: 'zh_CN' }, |
||||
|
{ label: '繁体中文', value: 'tw_CN' }, |
||||
|
]; |
||||
|
|
||||
|
const i18nGridRef = ref(); |
||||
|
const i18nConfigure = { |
||||
|
tableTitle: '多语言消息列表', |
||||
|
tableInitLoadData: true, |
||||
|
tableRowKey: 'id', |
||||
|
tableDataUrl: Environment.apiContextPath('/api/system/i18n'), |
||||
|
tablePagination: { |
||||
|
sortBy: 'code', |
||||
|
descending: false, |
||||
|
reqPageStart: 0, |
||||
|
rowsPerPage: 20, |
||||
|
}, |
||||
|
tableColumns: [ |
||||
|
{ name: 'code', label: t('code') }, |
||||
|
{ name: 'lang', label: t('lang'), format: (value) => Language[value] }, |
||||
|
{ name: 'message', label: t('message') }, |
||||
|
], |
||||
|
tableButtons: ['refresh', 'add', 'edit', 'delete'], |
||||
|
addFormProps: { |
||||
|
dialogInitWidth: '50%', |
||||
|
dialogInitHeight: '90%', |
||||
|
formColsNumber: 1, |
||||
|
formColsAuto: false, |
||||
|
formFields: [ |
||||
|
{ modelName: 'code', label: t('code'), type: 'text', required: true }, |
||||
|
{ modelName: 'lang', label: t('lang'), type: 'select', required: true, options: LanguageOptions }, |
||||
|
{ modelName: 'message', label: t('message'), type: 'text', required: true }, |
||||
|
], |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,248 @@ |
|||||
|
<template> |
||||
|
<q-splitter :model-value="70" class="w-full h-full"> |
||||
|
<template #before> |
||||
|
<w-tree-grid |
||||
|
ref="menuTreeGridRef" |
||||
|
title="菜单树" |
||||
|
label-key="titleI18nKey" |
||||
|
label-i18n |
||||
|
label-empty="--------------------" |
||||
|
:actions="menuConfigure.actions" |
||||
|
tick-strategy="none" |
||||
|
@update:selected="menuSelected" |
||||
|
/> |
||||
|
</template> |
||||
|
<template #after> |
||||
|
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0"> |
||||
|
<q-tab name="role" icon="bi-diagram-3" :label="$t('role')" /> |
||||
|
<q-tab name="org" icon="bi-people" :label="$t('org')" /> |
||||
|
</q-tabs> |
||||
|
|
||||
|
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive> |
||||
|
<q-tab-panel name="user"> |
||||
|
<platform-grid |
||||
|
ref="roleGridRef" |
||||
|
:table-props="{ borderded: false, flat: true }" |
||||
|
:query-form-cols-number="roleConfigure.queryFormColsNumber" |
||||
|
:hide-bottom="roleConfigure.hideBottom" |
||||
|
:query-form-cols-auto="roleConfigure.queryFormColsAuto" |
||||
|
:table-title="roleConfigure.tableTitle" |
||||
|
:table-row-key="roleConfigure.tableRowKey" |
||||
|
:table-init-load-data="roleConfigure.tableInitLoadData" |
||||
|
:table-data-url="roleConfigure.tableDataUrl" |
||||
|
:table-show-sort-no="false" |
||||
|
:table-columns="roleConfigure.tableColumns" |
||||
|
:table-left-column-sticky-number="roleConfigure.tableLeftColumnStickyNumber" |
||||
|
:table-buttons="roleConfigure.tableButtons" |
||||
|
:query-form-fields="roleConfigure.queryFormFields" |
||||
|
:table-pagination="roleConfigure.tablePagination" |
||||
|
table-selection="multiple" |
||||
|
:table-dense="false" |
||||
|
> |
||||
|
</platform-grid> |
||||
|
</q-tab-panel> |
||||
|
|
||||
|
<q-tab-panel name="org"> |
||||
|
<w-tree-grid |
||||
|
ref="orgTreeGridRef" |
||||
|
title="机构树" |
||||
|
label-key="titleI18nKey" |
||||
|
label-i18n |
||||
|
label-empty="--------------------" |
||||
|
:actions="orgConfigure.actions" |
||||
|
/> |
||||
|
</q-tab-panel> |
||||
|
</q-tab-panels> |
||||
|
</template> |
||||
|
<SelectRoleDialog ref="selectRoleDialog" title="可选角色列表" :maximized="false" width="50%" height="500px"></SelectRoleDialog> |
||||
|
</q-splitter> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { ref, onMounted } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { Environment, axios } from 'platform-core'; |
||||
|
import SelectRoleDialog from './SelectRoleDialog.vue'; |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const menuTreeGridRef = ref(); |
||||
|
const roleGridRef = ref(); |
||||
|
const orgTreeGridRef = ref(); |
||||
|
|
||||
|
const selectRoleDialog = ref(); |
||||
|
const selectedTabRef = ref('user'); |
||||
|
let selectedMenuId = ''; |
||||
|
|
||||
|
const roleConfigure = { |
||||
|
queryFormColsNumber: 4, |
||||
|
queryFormColsAuto: false, |
||||
|
queryFormFields: [], |
||||
|
hideBottom: true, |
||||
|
tableInitLoadData: false, |
||||
|
tableLeftColumnStickyNumber: 0, |
||||
|
tableTitle: t('system.role.gridTitle'), |
||||
|
tableRowKey: 'id', |
||||
|
tableDataUrl: '', |
||||
|
tablePagination: { |
||||
|
sortBy: 'lastModifyDate', |
||||
|
descending: true, |
||||
|
reqPageStart: 0, |
||||
|
rowsPerPage: 0, |
||||
|
}, |
||||
|
tableButtons: [ |
||||
|
'refresh', |
||||
|
'inFullscreen', |
||||
|
{ |
||||
|
name: 'addRole', |
||||
|
label: t('system.role.action.addRole'), |
||||
|
icon: '', |
||||
|
enable: () => {}, |
||||
|
click: () => { |
||||
|
selectRoleDialog.value.show({ roleGridRef: roleGridRef, menuTreeGridRef: menuTreeGridRef }); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'addAllRole', |
||||
|
label: t('system.role.action.addAllRole'), |
||||
|
icon: '', |
||||
|
enable: () => {}, |
||||
|
click: () => { |
||||
|
const menuId = menuTreeGridRef.value.getSelected(); |
||||
|
axios |
||||
|
.post(Environment.apiContextPath('/api/system/menu/addAllRoles'), { |
||||
|
source: menuId, |
||||
|
sourceParents: menuTreeGridRef.value.getCascadeParentIds(menuId), |
||||
|
sourceChildren: menuTreeGridRef.value.getCascadeChildrenIds(menuId), |
||||
|
targets: [], |
||||
|
}) |
||||
|
.then((response) => { |
||||
|
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByMenu?menuId=') + menuId).then((response) => { |
||||
|
roleGridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'removeRole', |
||||
|
label: t('system.role.action.removeRole'), |
||||
|
icon: '', |
||||
|
enable: () => {}, |
||||
|
click: () => { |
||||
|
const menuId = menuTreeGridRef.value.getSelected(); |
||||
|
const roleIds = []; |
||||
|
for (const role of roleGridRef.value.getSelectedRows()) { |
||||
|
roleIds.push(role.id); |
||||
|
} |
||||
|
axios |
||||
|
.post(Environment.apiContextPath('/api/system/menu/removeRoles'), { |
||||
|
source: menuId, |
||||
|
sourceParents: menuTreeGridRef.value.getCascadeParentIds(menuId), |
||||
|
sourceChildren: menuTreeGridRef.value.getCascadeChildrenIds(menuId), |
||||
|
targets: roleIds, |
||||
|
}) |
||||
|
.then((response) => { |
||||
|
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByMenu?menuId=') + menuId).then((response) => { |
||||
|
roleGridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'removeAllRole', |
||||
|
label: t('system.role.action.removeAllRole'), |
||||
|
icon: '', |
||||
|
enable: () => {}, |
||||
|
click: () => { |
||||
|
const menuId = menuTreeGridRef.value.getSelected(); |
||||
|
axios |
||||
|
.post(Environment.apiContextPath('/api/system/menu/removeAllRoles'), { |
||||
|
source: menuId, |
||||
|
sourceParents: menuTreeGridRef.value.getCascadeParentIds(menuId), |
||||
|
sourceChildren: menuTreeGridRef.value.getCascadeChildrenIds(menuId), |
||||
|
targets: [], |
||||
|
}) |
||||
|
.then((response) => { |
||||
|
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByMenu?menuId=') + menuId).then((response) => { |
||||
|
roleGridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
tableColumns: [ |
||||
|
{ width: 100, name: 'code', label: t('code') }, |
||||
|
{ width: 100, name: 'name', label: t('name') }, |
||||
|
{ width: 80, name: 'enable', label: t('isEnable'), format: (value) => (value ? t('yes') : t('no')) }, |
||||
|
], |
||||
|
}; |
||||
|
|
||||
|
const menuConfigure = { |
||||
|
actions: [ |
||||
|
{ |
||||
|
name: 'refresh', |
||||
|
label: t('refresh'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
name: 'addRoot', |
||||
|
label: t('system.menu.action.addTop'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'addChild', |
||||
|
label: t('system.menu.action.addChild'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'edit', |
||||
|
label: t('edit'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
{ |
||||
|
name: 'delete', |
||||
|
label: t('delete'), |
||||
|
click: () => {}, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
|
||||
|
const orgConfigure = { |
||||
|
actions: [ |
||||
|
{ |
||||
|
name: 'save', |
||||
|
label: '保存', |
||||
|
click: () => { |
||||
|
const orgId = menuTreeGridRef.value.getSelected()[0]; |
||||
|
axios |
||||
|
.post(Environment.apiContextPath('/api/system/menu/updateOrgs'), { |
||||
|
one: orgId, |
||||
|
many: menuTreeGridRef.value.getTicked(), |
||||
|
}) |
||||
|
.then((response) => {}); |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
|
||||
|
const menuSelected = (target) => { |
||||
|
selectedMenuId = target; |
||||
|
if (roleGridRef.value) { |
||||
|
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByMenu?menuId=') + selectedMenuId).then((response) => { |
||||
|
roleGridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// if (orgTreeGridRef.value) { |
||||
|
// axios.get(Environment.apiContextPath('/api/system/org/listAllOrgsWithSelectedStatusByMenu?menuId=') + selectedMenuId).then((response) => { |
||||
|
// orgTreeGridRef.value.setNodes(response.data); |
||||
|
// }); |
||||
|
// } |
||||
|
}; |
||||
|
|
||||
|
onMounted(() => { |
||||
|
axios.get(Environment.apiContextPath('/api/system/menu?pageable=false&sortBy=order')).then((response) => { |
||||
|
menuTreeGridRef.value.setNodes(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
</script> |
@ -0,0 +1,155 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<q-dialog ref="dialogRef" allow-focus-outside v-bind="attrs"> |
||||
|
<q-card |
||||
|
:style="{ |
||||
|
width: attrs.maximized ? '100vw' : width, |
||||
|
'max-width': '100vw', |
||||
|
height: attrs.maximized ? '100vh' : height, |
||||
|
'max-height': '100vh', |
||||
|
}" |
||||
|
> |
||||
|
<q-card-section :style="headerStyle"> |
||||
|
<div class="flex justify-between"> |
||||
|
<div class="text-h6">{{ title }}</div> |
||||
|
<div class="flex justify-end q-gutter-md"> |
||||
|
<q-btn :label="$t('confirm')" dense color="primary" style="width: 100px" @click="addRoles" /> |
||||
|
<q-btn v-close-popup dense flat icon="close" :title="$t('close')"> </q-btn> |
||||
|
</div> |
||||
|
</div> |
||||
|
</q-card-section> |
||||
|
<q-card-section class="q-pt-none" :style="bodyStyle"> |
||||
|
<platform-grid |
||||
|
ref="gridRef" |
||||
|
:table-props="{ borderded: false, flat: true }" |
||||
|
:query-form-cols-number="roleConfigure.queryFormColsNumber" |
||||
|
:hide-bottom="roleConfigure.hideBottom" |
||||
|
:query-form-cols-auto="roleConfigure.queryFormColsAuto" |
||||
|
:table-title="roleConfigure.tableTitle" |
||||
|
:table-row-key="roleConfigure.tableRowKey" |
||||
|
:table-init-load-data="roleConfigure.tableInitLoadData" |
||||
|
:table-data-url="roleConfigure.tableDataUrl" |
||||
|
:table-show-sort-no="false" |
||||
|
:table-columns="roleConfigure.tableColumns" |
||||
|
:table-left-column-sticky-number="roleConfigure.tableLeftColumnStickyNumber" |
||||
|
:table-buttons="roleConfigure.tableButtons" |
||||
|
:query-form-fields="roleConfigure.queryFormFields" |
||||
|
:table-pagination="roleConfigure.tablePagination" |
||||
|
table-selection="multiple" |
||||
|
:table-dense="false" |
||||
|
> |
||||
|
</platform-grid> |
||||
|
</q-card-section> |
||||
|
</q-card> |
||||
|
</q-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup lang="ts"> |
||||
|
import { useAttrs, ref, onMounted, nextTick } from 'vue'; |
||||
|
import { useI18n } from 'vue-i18n'; |
||||
|
import { axios, Environment } from 'platform-core'; |
||||
|
|
||||
|
const attrs = useAttrs(); |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
headerStyle: { type: String, default: 'width:100%;padding: 16px 8px 4px 16px' }, |
||||
|
bodyStyle: { type: String, default: 'padding: 0px 8px 0px 8px;height:calc(100%)' }, |
||||
|
title: { type: String, default: '' }, |
||||
|
width: { type: String, default: '70%' }, |
||||
|
height: { type: String, default: '70%' }, |
||||
|
}); |
||||
|
|
||||
|
const { t } = useI18n(); |
||||
|
|
||||
|
const dialogRef = ref(); |
||||
|
const gridRef = ref(); |
||||
|
let menuTreeGridRef, roleGridRef; |
||||
|
|
||||
|
const roleConfigure = { |
||||
|
queryFormColsNumber: 4, |
||||
|
queryFormColsAuto: false, |
||||
|
hideBottom: true, |
||||
|
tableInitLoadData: false, |
||||
|
tableLeftColumnStickyNumber: 0, |
||||
|
tableTitle: '', |
||||
|
tableRowKey: 'id', |
||||
|
tableDataUrl: '', |
||||
|
tablePagination: { |
||||
|
sortBy: 'lastModifyDate', |
||||
|
descending: true, |
||||
|
reqPageStart: 0, |
||||
|
rowsPerPage: 0, |
||||
|
}, |
||||
|
tableButtons: ['query', 'refresh'], |
||||
|
queryFormFields: [ |
||||
|
{ label: t('code'), modelName: 'code', type: 'text' }, |
||||
|
{ label: t('name'), modelName: 'name', type: 'text' }, |
||||
|
{ |
||||
|
label: t('enable'), |
||||
|
modelName: 'enable', |
||||
|
type: 'select', |
||||
|
options: [ |
||||
|
{ value: true, label: '是' }, |
||||
|
{ value: false, label: '否' }, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
label: t('dataComeFrom'), |
||||
|
modelName: 'dataComeFrom', |
||||
|
type: 'select', |
||||
|
options: [ |
||||
|
{ value: 'MANUAL', label: t('io.sc.platform.orm.api.enums.DataComeFrom.MANUAL') }, |
||||
|
{ value: 'AUTO', label: t('io.sc.platform.orm.api.enums.DataComeFrom.AUTO') }, |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
tableColumns: [ |
||||
|
{ width: 100, name: 'code', label: t('code') }, |
||||
|
{ width: 100, name: 'name', label: t('name') }, |
||||
|
{ width: 80, name: 'enable', label: t('isEnable'), format: (value) => (value ? t('yes') : t('no')) }, |
||||
|
], |
||||
|
}; |
||||
|
|
||||
|
const addRoles = () => { |
||||
|
const menuId = menuTreeGridRef.value.getSelected(); |
||||
|
const roleIds = []; |
||||
|
for (const role of gridRef.value.getSelectedRows()) { |
||||
|
roleIds.push(role.id); |
||||
|
} |
||||
|
axios |
||||
|
.post(Environment.apiContextPath('/api/system/menu/addRoles'), { |
||||
|
source: menuId, |
||||
|
sourceParents: menuTreeGridRef.value.getCascadeParentIds(menuId), |
||||
|
sourceChildren: menuTreeGridRef.value.getCascadeChildrenIds(menuId), |
||||
|
targets: roleIds, |
||||
|
}) |
||||
|
.then((response) => { |
||||
|
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByMenu?menuId=') + menuId).then((response) => { |
||||
|
roleGridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
dialogRef.value.hide(); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const show = (param: object) => { |
||||
|
menuTreeGridRef = param.menuTreeGridRef; |
||||
|
roleGridRef = param.roleGridRef; |
||||
|
const currentMenuId = menuTreeGridRef.value.getSelected()[0]; |
||||
|
|
||||
|
dialogRef.value.show(); |
||||
|
nextTick(() => { |
||||
|
axios.get(Environment.apiContextPath('/api/system/role/queryOtherRolesByMenu?menuId=') + currentMenuId).then((response) => { |
||||
|
gridRef.value.replaceRowsFun(response.data.content); |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
const hide = () => { |
||||
|
dialogRef.value.hide(); |
||||
|
}; |
||||
|
|
||||
|
defineExpose({ |
||||
|
show, |
||||
|
hide, |
||||
|
}); |
||||
|
</script> |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue