Browse Source

update frontend

main
wangshaoping 1 year ago
parent
commit
03f6c82021
  1. 1
      build.gradle
  2. 3
      gradle.properties
  3. 12
      io.sc.platform.app/build.gradle
  4. 7
      io.sc.platform.communication/build.gradle
  5. 45
      io.sc.platform.communication/src/main/java/io/sc/platform/communication/service/MailSenderService.java
  6. 66
      io.sc.platform.communication/src/main/java/io/sc/platform/communication/service/impl/MailSenderServiceImpl.java
  7. 17
      io.sc.platform.communication/src/main/resources/META-INF/platform/plugins/application-properties.json
  8. 5
      io.sc.platform.communication/src/main/resources/META-INF/platform/plugins/components.json
  9. 22
      io.sc.platform.communication/src/main/resources/META-INF/platform/plugins/restart-properties.json
  10. 4
      io.sc.platform.components.frontend/package.json
  11. 2
      io.sc.platform.components.frontend/src/App.vue
  12. 2
      io.sc.platform.components.frontend/webpack.config.mf.cjs
  13. 9
      io.sc.platform.core.frontend/package.json
  14. 9
      io.sc.platform.core.frontend/src/App.vue
  15. 0
      io.sc.platform.core.frontend/src/platform/components/app/WPlatformPage.vue
  16. 118
      io.sc.platform.core.frontend/src/platform/components/dialog/PlatformDialog.vue
  17. 107
      io.sc.platform.core.frontend/src/platform/components/dialog/WDialog.vue
  18. 103
      io.sc.platform.core.frontend/src/platform/components/drawer/PlatformDrawer.vue
  19. 528
      io.sc.platform.core.frontend/src/platform/components/form/PlatformForm.vue
  20. 2322
      io.sc.platform.core.frontend/src/platform/components/grid/PlatformGrid.vue
  21. 30
      io.sc.platform.core.frontend/src/platform/components/grid/PlatformGridTdDrag.vue
  22. 0
      io.sc.platform.core.frontend/src/platform/components/icon/WIconEmpty.vue
  23. 26
      io.sc.platform.core.frontend/src/platform/components/index.ts
  24. 0
      io.sc.platform.core.frontend/src/platform/components/layout/WHScreenDiv.vue
  25. 0
      io.sc.platform.core.frontend/src/platform/components/layout/WVExpandDiv.vue
  26. 85
      io.sc.platform.core.frontend/src/platform/components/panel/PlatformInfo.vue
  27. 0
      io.sc.platform.core.frontend/src/platform/components/svg/WSvgEditor.vue
  28. 186
      io.sc.platform.core.frontend/src/platform/components/utils/commUtil.ts
  29. 332
      io.sc.platform.core.frontend/src/platform/components/utils/componentComm.ts
  30. 19
      io.sc.platform.core.frontend/src/platform/components/utils/index.ts
  31. 0
      io.sc.platform.core.frontend/src/platform/components/widget/color/WColorInput.vue
  32. 0
      io.sc.platform.core.frontend/src/platform/components/widget/color/WColorInputPalette.vue
  33. 0
      io.sc.platform.core.frontend/src/platform/components/widget/position/WPosition.vue
  34. 48
      io.sc.platform.core.frontend/src/platform/enums/IconEnum.ts
  35. 1
      io.sc.platform.core.frontend/src/platform/enums/index.ts
  36. 38
      io.sc.platform.core.frontend/src/platform/index.ts
  37. 32
      io.sc.platform.core.frontend/src/platform/mock/api/lcdp/configure/getActiveConfigure.json
  38. 4
      io.sc.platform.core.frontend/src/platform/mock/index.ts
  39. 20
      io.sc.platform.core.frontend/src/platform/utils/Tools.ts
  40. 38
      io.sc.platform.core.frontend/src/views/View1.vue
  41. 8
      io.sc.platform.core.frontend/template-project/package.json
  42. 5
      io.sc.platform.core.frontend/template-project/src/App.vue
  43. 38
      io.sc.platform.core.frontend/template-project/src/views/View1.vue
  44. 2
      io.sc.platform.core.frontend/template-project/webpack.config.mf.cjs
  45. 2
      io.sc.platform.core.frontend/webpack.config.mf.cjs
  46. 3
      io.sc.platform.core/src/main/java/io/sc/platform/core/i18n/PlatformResourceBundleMessageSource.java
  47. 4
      io.sc.platform.core/src/main/java/io/sc/platform/core/service/impl/RuntimeServiceImpl.java
  48. 19
      io.sc.platform.core/src/main/java/io/sc/platform/core/util/BeanUtil.java
  49. 1
      io.sc.platform.developer.doc/asciidoc/9999-appendix/docker-compose/docker-compose.adoc
  50. 2
      io.sc.platform.developer.doc/asciidoc/9999-appendix/docker/mysql/mysql.adoc
  51. 5
      io.sc.platform.developer.frontend/package.json
  52. 2
      io.sc.platform.developer.frontend/webpack.config.mf.cjs
  53. 1
      io.sc.platform.flowable/build.gradle
  54. 2
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/AgentWebController.java
  55. 27
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/FlowableModelerEditorWebController.java
  56. 12
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/ProcessEntityWebController.java
  57. 10
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/ProcessOperationWebController.java
  58. 12
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/ProcessQueryWebController.java
  59. 4
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/support/ProcessProperties.java
  60. 18
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/extension/listener/VariableSetterListener.java
  61. 14
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/extension/listener/task/SendMailListener.java
  62. 24
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/jpa/entity/Agent.java
  63. 26
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/jpa/entity/ProcessEntity.java
  64. 3
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/jpa/repository/ProcessEntityRepository.java
  65. 10
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/service/impl/ProcessEntityServiceImpl.java
  66. 22
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/support/BpmnModelWrapper.java
  67. 9
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/support/CompleteTaskResponse.java
  68. 5
      io.sc.platform.lcdp.frontend/package.json
  69. 9
      io.sc.platform.lcdp.frontend/src/App.vue
  70. 4
      io.sc.platform.lcdp.frontend/webpack.config.mf.cjs
  71. 5
      io.sc.platform.mvc.frontend/package.json
  72. 9
      io.sc.platform.mvc.frontend/src/App.vue
  73. 4
      io.sc.platform.mvc.frontend/webpack.config.mf.cjs
  74. 10
      io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/controller/I18nMessageController.java
  75. 3
      io.sc.platform.mvc/src/main/resources/META-INF/platform/plugins/security.json
  76. 5
      io.sc.platform.security.frontend/package.json
  77. 51
      io.sc.platform.security.frontend/src/plugin.ts
  78. 4
      io.sc.platform.security/src/main/java/io/sc/platform/security/service/impl/UserDetailsServiceImpl.java
  79. 12
      io.sc.platform.security/src/main/java/io/sc/platform/security/service/support/User.java
  80. 2
      io.sc.platform.security/src/main/java/io/sc/platform/security/support/SecurityClaimNames.java
  81. 12
      io.sc.platform.security/src/main/java/io/sc/platform/security/support/SecurityUser.java
  82. 8
      io.sc.platform.security/src/main/java/io/sc/platform/security/util/SecurityUtil.java
  83. 11
      io.sc.platform.security/src/main/resources/META-INF/platform/plugins/application-properties.json
  84. 5
      io.sc.platform.system.frontend/package.json
  85. 2
      io.sc.platform.system.frontend/webpack.config.mf.cjs
  86. 23
      io.sc.platform.system/src/main/java/io/sc/platform/system/autoconfigure/MessageSourceAutoConfiguration.java
  87. 3
      io.sc.platform.system/src/main/java/io/sc/platform/system/autoconfigure/support/CompositeMessageSource.java
  88. 7
      io.sc.platform.system/src/main/java/io/sc/platform/system/autoconfigure/support/DatabaseMessageSource.java
  89. 15
      io.sc.platform.system/src/main/java/io/sc/platform/system/user/controller/UserController.java
  90. 17
      io.sc.platform.system/src/main/java/io/sc/platform/system/user/jpa/repository/UserRepository.java
  91. 8
      io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/UserService.java
  92. 19
      io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/impl/UserServiceImpl.java
  93. 3
      settings.gradle

1
build.gradle

@ -333,6 +333,7 @@ subprojects {
packageJson.name =project.name; packageJson.name =project.name;
packageJson.version =project.version; packageJson.version =project.version;
packageJson.dependencies['platform-core']=platform_core_frontend_version; packageJson.dependencies['platform-core']=platform_core_frontend_version;
packageJson.dependencies['platform-components']=platform_components_frontend_version;
def json = groovy.json.JsonOutput.toJson(packageJson); def json = groovy.json.JsonOutput.toJson(packageJson);
file('package.json').withWriter('UTF-8') { writer -> file('package.json').withWriter('UTF-8') { writer ->
writer.write(groovy.json.JsonOutput.prettyPrint(json)); writer.write(groovy.json.JsonOutput.prettyPrint(json));

3
gradle.properties

@ -38,7 +38,8 @@ application_version=1.0.0
platform_group=io.sc platform_group=io.sc
platform_version=8.1.8 platform_version=8.1.8
platform_plugin_version=8.1.8 platform_plugin_version=8.1.8
platform_core_frontend_version=8.1.12 platform_core_frontend_version=8.1.14
platform_components_frontend_version=8.1.2
########################################################### ###########################################################
# dependencies version # dependencies version

12
io.sc.platform.app/build.gradle

@ -1,15 +1,17 @@
dependencies { dependencies {
api( api(
project(":io.sc.platform.ws.cxf"), project(":io.sc.platform.csv"),
project(":io.sc.platform.system"), project(":io.sc.platform.communication"),
project(":io.sc.platform.security.loginform"), //project(":io.sc.platform.flowable"),
project(":io.sc.platform.groovy"),
project(":io.sc.platform.jdbc.liquibase"), project(":io.sc.platform.jdbc.liquibase"),
project(":io.sc.platform.jdbc.schemacrawler"), project(":io.sc.platform.jdbc.schemacrawler"),
project(":io.sc.platform.lcdp"), project(":io.sc.platform.lcdp"),
project(":io.sc.platform.lcdp.frontend"), project(":io.sc.platform.lcdp.frontend"),
project(":io.sc.platform.orm.mybatis"), project(":io.sc.platform.orm.mybatis"),
project(":io.sc.platform.csv"), project(":io.sc.platform.security.loginform"),
project(":io.sc.platform.groovy"), project(":io.sc.platform.system"),
project(":io.sc.platform.ws.cxf"),
project(":org.webjars.luckysheet-2.1.13"), project(":org.webjars.luckysheet-2.1.13"),
project(":org.webjars.tailwindcss-3.3.5"), project(":org.webjars.tailwindcss-3.3.5"),

7
io.sc.platform.communication/build.gradle

@ -0,0 +1,7 @@
dependencies {
api(
project(":io.sc.platform.mvc"),
"org.springframework.boot:spring-boot-starter-mail",
)
}

45
io.sc.platform.communication/src/main/java/io/sc/platform/communication/service/MailSenderService.java

@ -0,0 +1,45 @@
package io.sc.platform.communication.service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.springframework.mail.SimpleMailMessage;
/**
* 邮件发送器服务
*/
public interface MailSenderService {
/**
* 发送简单邮件
* @param from 发件人
* @param to 收件人
* @param cc 抄送人
* @param subject 标题
* @param text 文本
*/
public void sendSimpleMessage(String from,String[] to,String[] cc,String subject,String text);
/**
* 发送简单邮件
* @param messages 邮件消息
*/
public void sendSimpleMessage(SimpleMailMessage... messages);
/**
* 发送富文本邮件
* @param from 发件人
* @param to 收件人
* @param cc 抄送人
* @param subject 标题
* @param text 文本
* @throws MessagingException 违例
*/
public void sendMimeMessage(String from,String[] to,String[] cc,String subject,String text) throws MessagingException;
/**
* 发送富文本邮件
* @param mimeMessages 邮件消息
*/
public void sendMimeMessage(MimeMessage... mimeMessages);
}

66
io.sc.platform.communication/src/main/java/io/sc/platform/communication/service/impl/MailSenderServiceImpl.java

@ -0,0 +1,66 @@
package io.sc.platform.communication.service.impl;
import javax.annotation.PostConstruct;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import io.sc.platform.communication.service.MailSenderService;
import io.sc.platform.core.util.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
@Service
public class MailSenderServiceImpl implements MailSenderService {
@Autowired private ApplicationContext applicationContext;
private JavaMailSender mailSender;
@PostConstruct
public void initMailSenderService(){
this.mailSender = BeanUtil.getBean(applicationContext,JavaMailSender.class);
}
@Override
public void sendSimpleMessage(String from, String[] to, String[] cc, String subject, String text) {
if(mailSender!=null){
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(to);
message.setCc(cc);
message.setSubject(subject);
message.setText(text);
sendSimpleMessage(message);
}
}
@Override
public void sendSimpleMessage(SimpleMailMessage... messages) {
if(mailSender!=null){
mailSender.send(messages);
}
}
@Override
public void sendMimeMessage(String from, String[] to, String[] cc, String subject, String html) throws MessagingException {
if(mailSender!=null) {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setCc(cc);
helper.setSubject(subject);
helper.setText(html, true);
sendMimeMessage(message);
}
}
@Override
public void sendMimeMessage(MimeMessage... mimeMessages) {
if(mailSender!=null) {
mailSender.send(mimeMessages);
}
}
}

17
io.sc.platform.communication/src/main/resources/META-INF/platform/plugins/application-properties.json

@ -0,0 +1,17 @@
[
{
"module" : "io.sc.platform.communication",
"order" : 4000,
"description": "email configuration",
"properties": [
"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"
]
}
]

5
io.sc.platform.communication/src/main/resources/META-INF/platform/plugins/components.json

@ -0,0 +1,5 @@
{
"includes":[
"io.sc.platform.communication.service.impl"
]
}

22
io.sc.platform.communication/src/main/resources/META-INF/platform/plugins/restart-properties.json

@ -0,0 +1,22 @@
{
"container":[
"spring.mail.host",
"spring.mail.port",
"spring.mail.protocol",
"spring.mail.test-connection",
"spring.mail.default-encoding",
"spring.mail.properties.mail.smtp.auth",
"spring.mail.username",
"spring.mail.password"
],
"jar": [
"spring.mail.host",
"spring.mail.port",
"spring.mail.protocol",
"spring.mail.test-connection",
"spring.mail.default-encoding",
"spring.mail.properties.mail.smtp.auth",
"spring.mail.username",
"spring.mail.password"
]
}

4
io.sc.platform.components.frontend/package.json

@ -93,12 +93,10 @@
"platform-core": "8.1.12", "platform-core": "8.1.12",
"platform-components": "8.1.2", "platform-components": "8.1.2",
"quasar": "2.13.0", "quasar": "2.13.0",
"react-dnd-html5-backend": "16.0.1",
"tailwindcss": "3.3.5", "tailwindcss": "3.3.5",
"vue": "3.3.7", "vue": "3.3.7",
"vue-dompurify-html": "4.1.4", "vue-dompurify-html": "4.1.4",
"vue-i18n": "9.6.0", "vue-i18n": "9.6.0",
"vue-router": "4.2.5", "vue-router": "4.2.5"
"vue3-dnd": "2.0.2"
} }
} }

2
io.sc.platform.components.frontend/src/App.vue

@ -1,7 +1,5 @@
<template> <template>
<DndProvider :backend="HTML5Backend">
<w-platform-page></w-platform-page> <w-platform-page></w-platform-page>
</DndProvider>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

2
io.sc.platform.components.frontend/webpack.config.mf.cjs

@ -42,12 +42,10 @@ module.exports = {
'pinia': { requiredVersion: deps['pinia'], singleton: true }, 'pinia': { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true }, 'quasar': { requiredVersion: deps['quasar'], singleton: true },
'react-dnd-html5-backend':{ requiredVersion: deps['react-dnd-html5-backend'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true }, 'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'vue3-dnd':{ requiredVersion: deps['vue3-dnd'], singleton: true },
} }
}), }),
] ]

9
io.sc.platform.core.frontend/package.json

@ -1,6 +1,6 @@
{ {
"name": "platform-core", "name": "platform-core",
"version": "8.1.13", "version": "8.1.15",
"description": "前端核心包,用于快速构建前端的脚手架", "description": "前端核心包,用于快速构建前端的脚手架",
"//main": "库的主文件", "//main": "库的主文件",
"main": "dist/platform-core.js", "main": "dist/platform-core.js",
@ -48,7 +48,8 @@
}, },
"publishConfig": { "publishConfig": {
"registry": "http://nexus.sc.io:8000/repository/npm-releases/", "registry": "http://nexus.sc.io:8000/repository/npm-releases/",
"access": "public" "access": "public",
"no-git-checks": true
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.23.2", "@babel/core": "7.23.2",
@ -106,12 +107,10 @@
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"quasar": "2.13.0", "quasar": "2.13.0",
"react-dnd-html5-backend": "16.0.1",
"tailwindcss": "3.3.5", "tailwindcss": "3.3.5",
"vue": "3.3.7", "vue": "3.3.7",
"vue-dompurify-html": "4.1.4", "vue-dompurify-html": "4.1.4",
"vue-i18n": "9.6.0", "vue-i18n": "9.6.0",
"vue-router": "4.2.5", "vue-router": "4.2.5"
"vue3-dnd": "2.0.2"
} }
} }

9
io.sc.platform.core.frontend/src/App.vue

@ -1,10 +1,5 @@
<template> <template>
<DndProvider :backend="HTML5Backend"> <w-platform-page></w-platform-page>
<w-platform-page></w-platform-page>
</DndProvider>
</template> </template>
<script setup lang="ts"> <script setup lang="ts"></script>
import { DndProvider } from 'vue3-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
</script>

0
io.sc.platform.core.frontend/src/platform/component/app/WPlatformPage.vue → io.sc.platform.core.frontend/src/platform/components/app/WPlatformPage.vue

118
io.sc.platform.core.frontend/src/platform/components/dialog/PlatformDialog.vue

@ -0,0 +1,118 @@
<template>
<q-dialog v-model="dialog.dialogShow" allow-focus-outside v-bind="extractDialogProps(dialogProps)" :maximized="dialog.maximizedToggle">
<q-card :style="dialogStyleComputed">
<div class="w-full h-full">
<div style="height: 69px">
<q-card-section>
<div class="flex justify-between">
<div class="text-h6">{{ dialogTitle }}</div>
<div class="flex justify-end gap-4">
<template v-for="(btn, index) in dialogButtons as any" :key="index">
<q-btn
v-if="typeof btn === 'object'"
:loading="btn.loading ? btn.loading : false"
:label="btn.label"
:icon="btn.icon"
color="primary"
@click="btn.click()"
>
</q-btn>
</template>
<q-btn
v-if="dialogMaximized"
dense
flat
:icon="!dialog.maximizedToggle ? PlatformIconEnum.全屏 : PlatformIconEnum.退出全屏"
@click="dialogMaximizeBtnClick"
>
<q-tooltip v-if="!dialog.maximizedToggle">全屏</q-tooltip>
<q-tooltip v-else-if="dialog.maximizedToggle">退出全屏</q-tooltip>
</q-btn>
<q-btn v-close-popup dense flat :icon="PlatformIconEnum.关闭">
<q-tooltip>关闭</q-tooltip>
</q-btn>
</div>
</div>
</q-card-section>
<q-separator />
</div>
<div style="height: calc(100% - 69px)">
<q-card-section v-if="!dialogSplitter" style="height: 100%" class="scroll">
<slot name="content"></slot>
</q-card-section>
<q-splitter v-else v-model="dialog.splitterModel" :limits="dialog.splitterLimits" :horizontal="dialog.splitterHorizontal" style="height: 100%">
<template #before>
<slot name="splitterBefore"></slot>
</template>
<template #after>
<slot name="splitterAfter"></slot>
</template>
</q-splitter>
</div>
</div>
</q-card>
</q-dialog>
</template>
<script setup lang="ts">
import { reactive, computed } from 'vue';
import { extractDialogProps, PlatformIconEnum } from '@/platform/components/utils';
import '@/css/tailwind.css';
const props = defineProps({
dialogProps: {
type: Object,
default: () => {
return {};
},
},
dialogTitle: { type: String, default: '' },
dialogInitWidth: { type: String, default: '70%' },
dialogInitHeight: { type: String, default: '70%' },
dialogInitMaximized: { type: Boolean, default: false },
dialogMaximized: { type: Boolean, default: true },
dialogButtons: { type: Array, default: () => [] },
dialogSplitter: { type: Object, default: undefined },
});
const emit = defineEmits<{
(
e: 'dialogMaximize', //
maximizedToggle: boolean, // true:,false:退
): void;
}>();
const dialog = reactive({
dialogShow: false,
maximizedToggle: props.dialogInitMaximized,
splitterModel: props.dialogSplitter?.splitterModel || 50,
splitterLimits: props.dialogSplitter?.limits || [0, 100],
splitterHorizontal: props.dialogSplitter?.horizontal || false,
});
const dialogMaximizeBtnClick = () => {
dialog.maximizedToggle = !dialog.maximizedToggle;
emit('dialogMaximize', dialog.maximizedToggle);
};
const dialogStyleComputed = computed(() => {
if (!dialog.maximizedToggle) {
return { width: props.dialogInitWidth, 'max-width': '100vw', height: props.dialogInitHeight, 'max-height': '100vh' };
} else {
return { width: '100vw', 'max-width': '100vw', height: '100vh', 'max-height': '100vh' };
}
});
const dialogShow = () => {
dialog.dialogShow = true;
};
const dialogHide = () => {
dialog.dialogShow = false;
};
defineExpose({
dialogShow,
dialogHide,
});
</script>

107
io.sc.platform.core.frontend/src/platform/components/dialog/WDialog.vue

@ -0,0 +1,107 @@
<template>
<q-dialog v-model="dialog.dialogShow" allow-focus-outside v-bind="attrs">
<q-card
:style="{
width: dialog.maximized ? '100vw' : props.width,
'max-width': '100vw',
height: dialog.maximized ? '100vh' : props.height,
'max-height': '100vh',
}"
>
<div class="w-full h-full">
<div style="height: 69px">
<q-card-section>
<div class="flex justify-between">
<div class="text-h6">{{ title }}</div>
<div class="flex justify-end gap-4">
<template v-for="(btn, index) in buttons as any" :key="index">
<q-btn
v-if="typeof btn === 'object'"
:loading="btn.loading ? btn.loading : false"
:label="btn.label"
:icon="btn.icon"
color="primary"
@click="btn.click()"
>
</q-btn>
</template>
<q-btn v-if="canMaximize" dense flat :icon="!dialog.maximized ? IconEnum.全屏 : IconEnum.退出全屏" @click="maximizeBtnClick">
<q-tooltip v-if="!dialog.maximized">全屏</q-tooltip>
<q-tooltip v-else-if="dialog.maximized">退出全屏</q-tooltip>
</q-btn>
<q-btn v-close-popup dense flat :icon="IconEnum.关闭">
<q-tooltip>关闭</q-tooltip>
</q-btn>
</div>
</div>
</q-card-section>
<q-separator />
</div>
<div style="height: calc(100% - 69px)">
<q-card-section v-if="!splitter" style="height: 100%" class="scroll">
<slot name="content"></slot>
</q-card-section>
<q-splitter v-else v-model="dialog.splitterModel" :limits="dialog.splitterLimits" :horizontal="dialog.splitterHorizontal" style="height: 100%">
<template #before>
<slot name="splitterBefore"></slot>
</template>
<template #after>
<slot name="splitterAfter"></slot>
</template>
</q-splitter>
</div>
</div>
</q-card>
</q-dialog>
</template>
<script setup lang="ts">
import { reactive, useAttrs } from 'vue';
import { IconEnum } from '@/platform/enums';
import { Tools } from '@/platform/utils';
import '@/css/tailwind.css';
const attrs = useAttrs();
const props = defineProps({
title: { type: String, default: '' },
width: { type: String, default: '70%' },
height: { type: String, default: '70%' },
canMaximize: { type: Boolean, default: true },
buttons: { type: Array, default: () => [] },
splitter: { type: Object, default: undefined },
});
const emit = defineEmits<{
(
e: 'maximized', //
maximized: boolean, // true:,false:退
): void;
}>();
const dialog = reactive({
show: false,
maximized: attrs.maximized,
splitterModel: props.splitter?.splitterModel || 50,
splitterLimits: props.splitter?.limits || [0, 100],
splitterHorizontal: props.splitter?.horizontal || false,
});
const maximizeBtnClick = () => {
dialog.maximized = !dialog.maximized;
emit('maximized', dialog.maximized);
};
const show = () => {
dialog.dialogShow = true;
};
const hide = () => {
dialog.dialogShow = false;
};
defineExpose({
show,
hide,
});
</script>

103
io.sc.platform.core.frontend/src/platform/components/drawer/PlatformDrawer.vue

@ -0,0 +1,103 @@
<template>
<q-dialog v-model="drawer.drawerShow" v-bind="extractDialogProps(drawerProps)" :maximized="drawer.maximizedToggle">
<q-card :style="drawerStyleComputed">
<div class="w-full h-full">
<div style="height: 64px">
<q-card-section>
<div class="flex justify-between">
<div class="text-h6">{{ drawerTitle }}</div>
<div class="flex justify-end gap-4">
<q-btn
v-if="drawerMaximized"
dense
flat
:icon="!drawer.actualMaximizedToggle ? PlatformIconEnum.全屏 : PlatformIconEnum.退出全屏"
@click="drawerMaximizeBtnClick"
>
<q-tooltip v-if="!drawer.actualMaximizedToggle">全屏</q-tooltip>
<q-tooltip v-else-if="drawer.actualMaximizedToggle">退出全屏</q-tooltip>
</q-btn>
<q-btn v-close-popup dense flat :icon="PlatformIconEnum.关闭">
<q-tooltip>关闭</q-tooltip>
</q-btn>
</div>
</div>
</q-card-section>
<q-separator />
</div>
<div :style="drawerButtons && drawerButtons.length > 0 ? 'height:calc(100% - 132px)' : 'height:calc(100% - 64px)'">
<q-card-section style="height: 100%" class="scroll">
<slot name="content"></slot>
</q-card-section>
</div>
<div v-if="drawerButtons && drawerButtons.length > 0" style="height: 64px">
<q-separator />
<q-card-actions align="right" class="px-6 pt-4">
<template v-for="(btn, index) in drawerButtons as any" :key="index">
<q-btn
v-if="typeof btn === 'object'"
:loading="btn.loading ? btn.loading : false"
:label="btn.label"
:icon="btn.icon"
unelevated
outline
@click="btn.click()"
></q-btn>
</template>
</q-card-actions>
</div>
</div>
</q-card>
</q-dialog>
</template>
<script setup lang="ts">
import { reactive, computed } from 'vue';
import { extractDialogProps, PlatformIconEnum } from '@/platform/components/utils';
import '@/css/tailwind.css';
const props = defineProps({
drawerProps: { type: Object, default: () => {} },
drawerTitle: { type: String, default: '' },
drawerInitWidth: { type: String, default: '50vw' },
drawerInitHeight: { type: String, default: '100vh' },
drawerMaximized: { type: Boolean, default: true },
drawerButtons: { type: Array, default: () => [] },
});
const drawer = reactive({
drawerShow: false,
maximizedToggle: true,
/**
* 实际全屏属性Drawer 使用的 dialog 进行封装 dialog 的非全屏模式,
* 不管高宽给到多少Quasar 内置的 css 样式都会有一个 padding: 24px 的属性,
* 所以封装 Drawer 时默认就是 dialog 的全屏模式同时希望提供全屏的功能所以需要一个实际是否全屏的属性
*/
actualMaximizedToggle: false,
});
const drawerMaximizeBtnClick = () => {
drawer.actualMaximizedToggle = !drawer.actualMaximizedToggle;
};
const drawerStyleComputed = computed(() => {
if (!drawer.actualMaximizedToggle) {
return { width: props.drawerInitWidth, 'max-width': '100vw', height: props.drawerInitHeight, 'max-height': '100vh' };
} else {
return { width: '100vw', 'max-width': '100vw', height: '100vh', 'max-height': '100vh' };
}
});
const drawerShow = () => {
drawer.drawerShow = true;
};
const drawerHide = () => {
drawer.drawerShow = false;
};
defineExpose({
drawerShow,
drawerHide,
});
</script>

528
io.sc.platform.core.frontend/src/platform/components/form/PlatformForm.vue

@ -0,0 +1,528 @@
<template>
<q-form ref="formRef" v-bind="extractFormProps(formProps)">
<div class="grid gap-2" :class="formLayoutComputed">
<template v-for="(field, index) in formFields as any" :key="String(index)">
<q-input
v-if="field.type === 'dateRange' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.fmtModelName]"
:label="field.required ? '* ' + field.label : field.label"
:rules="fieldRulesFun(field.required, field)"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
>
<template #append>
<q-icon :name="PlatformIconEnum.日期范围" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-date
v-model="formData[field.modelName]"
range
:mask="field.mask ? field.mask : 'YYYY-MM-DD'"
:readonly="formStatus === 'view' || field.readonly ? true : false"
>
<div class="row items-center justify-end">
<q-btn v-close-popup label="关闭" color="primary" flat />
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-input
v-else-if="field.type === 'date' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.modelName]"
:label="field.required ? '* ' + field.label : field.label"
:rules="fieldRulesFun(field.required, field)"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
>
<template #append>
<q-icon :name="PlatformIconEnum.日期" class="cursor-pointer">
<q-popup-proxy cover transition-show="scale" transition-hide="scale">
<q-date
v-model="formData[field.modelName]"
today-btn
:mask="field.mask ? field.mask : 'YYYY-MM-DD'"
:readonly="formStatus === 'view' || field.readonly ? true : false"
>
<div class="row items-center justify-end">
<q-btn v-close-popup label="关闭" color="primary" flat />
</div>
</q-date>
</q-popup-proxy>
</q-icon>
</template>
</q-input>
<q-select
v-else-if="field.type === 'select' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.modelName]"
:label="field.required ? '* ' + field.label : field.label"
:rules="fieldRulesFun(field.required, field)"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
@filter="field.filterFun"
@focus="field.focusFun"
>
<template v-if="field.afterButton" #after>
<q-btn
:round="field.afterButton.round"
:dense="field.afterButton.dense"
:flat="field.afterButton.flat"
:unelevated="field.afterButton.unelevated"
:outline="field.afterButton.outline"
:color="field.afterButton.color"
:icon="field.afterButton.icon"
:label="field.afterButton.label"
:disable="formStatus === PageStatusEnum.查看 || field.afterButton.disable ? true : false"
@click="field.afterButton.click"
/>
</template>
</q-select>
<q-checkbox
v-else-if="field.type === 'checkbox' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.modelName]"
:label="field.required ? '* ' + field.label : field.label"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
/>
<div
v-else-if="field.type === 'optionGroup' && index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
class="border-solid border"
>
<span class="p-2.5">{{ field.label }}</span>
<q-option-group
v-model="formData[field.modelName]"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
/>
</div>
<q-input
v-else-if="index < queryFormShowFieldNumber"
v-show="!field.hasOwnProperty('hide') || !field.hide"
v-model="formData[field.modelName]"
:label="field.required ? '* ' + field.label : field.label"
:rules="fieldRulesFun(field.required, field)"
v-bind="extractFormItemComponentProps(field.type, field)"
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false"
@update:model-value="field.changeFun"
>
<template v-if="field.afterButton" #after>
<q-btn
round
dense
flat
:disable="formStatus === PageStatusEnum.查看 || field.afterButton.disable ? true : false"
:icon="field.afterButton.icon"
@click="field.afterButton.click"
/>
</template>
</q-input>
</template>
</div>
<slot></slot>
</q-form>
</template>
<script setup lang="ts">
import { ref, reactive, watch, computed, toRaw, defineProps } from 'vue';
import {
extractFormProps,
extractFormItemComponentProps,
arrayToMap,
PlatformIconEnum,
FormComponentValidateEnum,
PageStatusEnum,
isEmpty,
} from '@/platform/components/utils';
const props = defineProps({
formProps: {
type: Object,
default: () => {
return { autofocus: false, greedy: true };
},
},
formColsNumber: { type: Number, default: 3 },
formColsAuto: { type: Boolean, default: true },
formFields: {
type: Array,
default: () => {
return [];
},
},
queryFormShowFieldNumber: { type: Number, default: 999 },
});
const formRef = ref();
const formStatus = ref('add');
const formFieldsMap = arrayToMap('modelName', props.formFields);
// class tailwind css
const formLayoutComputed = computed(() => {
let className = '';
switch (props.formColsNumber) {
case 1:
className = !props.formColsAuto ? 'grid-cols-1' : 'xs:grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4';
break;
case 2:
className = !props.formColsAuto ? 'grid-cols-2' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4';
break;
case 4:
className = !props.formColsAuto ? 'grid-cols-4' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-4 xl:grid-cols-6';
break;
case 5:
className = !props.formColsAuto ? 'grid-cols-5' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-6';
break;
case 6:
className = !props.formColsAuto ? 'grid-cols-6' : 'xs:grid-cols-1 sm:grid-cols-3 md:grid-cols-6 lg:grid-cols-6 xl:grid-cols-6';
break;
case 7:
className = !props.formColsAuto ? 'grid-cols-7' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-7 lg:grid-cols-7 xl:grid-cols-7';
break;
case 8:
className = !props.formColsAuto ? 'grid-cols-8' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-8 lg:grid-cols-8 xl:grid-cols-8';
break;
case 9:
className = !props.formColsAuto ? 'grid-cols-9' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-9 lg:grid-cols-9 xl:grid-cols-9';
break;
case 10:
className = !props.formColsAuto ? 'grid-cols-10' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-10 lg:grid-cols-10 xl:grid-cols-10';
break;
case 11:
className = !props.formColsAuto ? 'grid-cols-11' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-11 lg:grid-cols-11 xl:grid-cols-11';
break;
case 12:
className = !props.formColsAuto ? 'grid-cols-12' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-12 lg:grid-cols-12 xl:grid-cols-12';
break;
default:
className = !props.formColsAuto ? 'grid-cols-3' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6';
}
return className;
});
const selectDefaultValue = (field) => {
if (field.hasOwnProperty.call('defaultValue') && field.defaultValue !== null) {
if (typeof field.defaultValue === 'string' || typeof field.defaultValue === 'boolean' || typeof field.defaultValue === 'number') {
const dftValue = field.options.filter((item) => {
return item.value === field.defaultValue;
});
if (dftValue && dftValue.length > 0) {
return field.multiple ? [dftValue[0]] : dftValue[0];
} else {
return field.multiple ? [] : '';
}
} else if (Array.isArray(field.defaultValue)) {
const dftValue = field.options.filter((item) => {
return field.defaultValue.filter((val) => {
return val === item.value;
});
});
return field.multiple ? dftValue : dftValue[0];
}
} else {
return field.multiple ? [] : '';
}
};
const numberDefaultValue = (field) => {
if (field.hasOwnProperty.call('defaultValue') && typeof field.defaultValue === 'number') {
return field.defaultValue;
} else {
return '';
}
};
const checkboxDefaultValue = (field) => {
if (field.hasOwnProperty.call('defaultValue')) {
return field.defaultValue;
} else {
return false;
}
};
const optionGroupDefaultValue = (field) => {
if (field.hasOwnProperty.call('defaultValue')) {
return field.defaultValue;
} else if (field.optionGroupType && field.optionGroupType === 'checkbox') {
return [];
} else {
return '';
}
};
const textDefaultValue = (field) => {
if (field.hasOwnProperty.call('defaultValue')) {
return field.defaultValue;
} else {
return '';
}
};
const formModel: any = {};
for (const field of props.formFields as any) {
if (field.type === 'dateRange') {
formModel[field.fmtModelName] = '';
} else if (field.type === 'select') {
formModel[field.modelName] = selectDefaultValue(field);
} else if (field.type === 'number') {
formModel[field.modelName] = numberDefaultValue(field);
} else if (field.type === 'checkbox') {
formModel[field.modelName] = checkboxDefaultValue(field);
} else if (field.type === 'optionGroup') {
formModel[field.modelName] = optionGroupDefaultValue(field);
} else {
formModel[field.modelName] = textDefaultValue(field);
}
}
const formData = reactive(formModel);
for (const field of props.formFields as any) {
if (field.type === 'dateRange') {
watch(
() => formData[field.modelName],
(newVal, oldVal) => {
if (!newVal || newVal.from === '') {
formData[field.fmtModelName] = '';
} else {
formData[field.fmtModelName] = newVal.from + ' 至 ' + newVal.to;
}
},
);
}
}
const isNumber = (num) => {
return !isNaN(parseFloat(num)) && isFinite(num);
};
const fieldRulesFun = (required, field) => {
let resultRules = <any>[];
if (field.type === 'select' && field.multiple && required) {
resultRules.push((val) => {
if (val !== null && val.length > 0) {
return true;
} else {
return '该字段为必填项';
}
});
} else if (required) {
resultRules.push((val) => (val !== null && val !== '') || '该字段为必填项');
}
if (field.rules && field.rules.length > 0) {
field.rules.forEach((rule) => {
if (typeof rule === 'string' && rule === FormComponentValidateEnum.字符串不能包含空格校验) {
//
resultRules.push((val) => {
if (isEmpty(val) || val.indexOf(' ') === -1) {
return true;
} else {
return '不能包含空格';
}
});
} else if (typeof rule === 'string' && rule === FormComponentValidateEnum.默认日期格式校验) {
resultRules.push((val) => {
if (isEmpty(val) || /^(\d{4})-(\d{2})-(\d{2})$/.test(val)) {
return true;
} else {
return '日期格式校验未通过';
}
});
} else if (typeof rule === 'string' && rule === FormComponentValidateEnum.必须为整数校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || (tmp.indexOf('.') === -1 && Number.isInteger(parseInt(tmp)))) {
return true;
} else {
return '只能输入整数';
}
});
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.字符串最大长度校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || tmp.length <= rule.value) {
return true;
} else {
return '最大允许输入的长度为:' + rule.value;
}
});
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.最大小数位数校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || tmp.indexOf('.') === -1 || tmp.substring(tmp.indexOf('.') + 1).length <= rule.value) {
return true;
} else {
return '最大允许输入的小数位数为:' + rule.value;
}
});
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.数字最小值校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || parseFloat(tmp) >= rule.value) {
return true;
} else {
return '最小允许输入的值为:' + rule.value;
}
});
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.数字最大值校验) {
//
resultRules.push((val) => {
const tmp = String(val);
if (val === null || parseFloat(tmp) <= rule.value) {
return true;
} else {
return '最大允许输入的值为:' + rule.value;
}
});
} else {
resultRules.push(rule);
}
});
}
return resultRules;
};
const formValidateFun = async () => {
const v = await formValidate();
return v;
};
const formValidate = async () => {
let validate = false;
await formRef.value.validate().then((success) => {
if (success) {
validate = true;
}
});
return validate;
};
const getFormDataFun = () => {
const data = { ...toRaw(formData) };
const selectFields = props.formFields.filter((item: any) => {
return item.type === 'select';
});
selectFields.forEach((item: any) => {
let selectValues = '';
if (item.multiple && data[item.modelName] && data[item.modelName].length > 0) {
data[item.modelName].forEach((val) => {
selectValues = selectValues + ',' + val.value;
});
selectValues = selectValues.substring(1, selectValues.length);
} else if (data[item.modelName]) {
selectValues = data[item.modelName].value ?? data[item.modelName];
}
data[item.modelName] = selectValues;
});
return data;
};
const setFormDataFun = (record) => {
for (const field of props.formFields as any) {
if (field.type === 'select') {
if (field.multiple && record[field.modelName].indexOf(',') > -1) {
const recordSelectValues = record[field.modelName].split(',');
const selectValues = <any>[];
recordSelectValues.forEach((item) => {
selectValues.push(setSelectValue(field.options, item));
});
formData[field.modelName] = selectValues;
} else {
formData[field.modelName] = setSelectValue(field.options, record[field.modelName]);
}
} else if (field.type === 'optionGroup') {
if (record[field.modelName]) {
formData[field.modelName] = record[field.modelName];
} else {
formData[field.modelName] = [];
}
} else {
formData[field.modelName] = record[field.modelName];
}
}
};
const setSelectValue = (options, val) => {
const opt = options.filter((option) => {
return option.value === val;
});
if (opt && opt.length > 0) {
return opt[0];
} else {
return val;
}
};
const setFieldValueFun = (fieldName, value) => {
const field = formFieldsMap.get(fieldName);
if (field.type === 'select') {
if (field.multiple && Array.isArray(value)) {
const selectValues = <any>[];
value.forEach((item) => {
selectValues.push(setSelectValue(field.options, item));
});
formData[field.modelName] = selectValues;
} else {
formData[field.modelName] = setSelectValue(field.options, value);
}
} else {
formData[field.modelName] = value;
}
};
const getFieldValueFun = (fieldName) => {
return formData[fieldName];
};
const resetFormDataFun = () => {
Object.keys(formData).forEach((key) => {
switch (typeof formData[key]) {
case 'string':
formData[key] = '';
break;
case 'boolean':
formData[key] = false;
break;
case 'number':
formData[key] = '';
break;
default:
formData[key] = undefined;
break;
}
});
};
const setFormStatusFun = (status) => {
formStatus.value = status;
};
const getFormStatusFun = () => {
return toRaw(formStatus.value);
};
const getFormFieldMapFun = () => {
return formFieldsMap;
};
defineExpose({
formValidateFun,
getFormDataFun,
setFormDataFun,
getFormStatusFun,
setFormStatusFun,
resetFormDataFun,
setFieldValueFun,
getFieldValueFun,
getFormFieldMapFun,
});
</script>

2322
io.sc.platform.core.frontend/src/platform/components/grid/PlatformGrid.vue

File diff suppressed because it is too large

30
io.sc.platform.core.frontend/src/platform/components/grid/PlatformGridTdDrag.vue

@ -0,0 +1,30 @@
<template>
<div :ref="(node) => drag(drop(node as any))" :class="borderClass">
<q-icon v-if="typeof tdValue[0] === 'boolean' && tdValue[0]" :name="PlatformIconEnum.是状态" color="green" size="sm"> </q-icon>
<template v-else-if="typeof tdValue[0] === 'boolean' && !tdValue[0]"> </template>
<template v-else>
{{ tdValue[0] }}
</template>
</div>
</template>
<script lang="ts" setup>
import { computed, unref } from 'vue';
import { toRefs } from '@vueuse/core';
import { PlatformIconEnum } from '@/platform/components/utils';
const props = defineProps({
tdValue: {
type: Array,
default: () => {
return [];
},
},
rowIndex: { type: Number, default: 0 },
});
const emit = defineEmits(['tableSortFun']);
export interface DropResult {
name: string;
}
</script>

0
io.sc.platform.core.frontend/src/platform/component/icon/WIconEmpty.vue → io.sc.platform.core.frontend/src/platform/components/icon/WIconEmpty.vue

26
io.sc.platform.core.frontend/src/platform/component/index.ts → io.sc.platform.core.frontend/src/platform/components/index.ts

@ -7,6 +7,12 @@ import WColorInput from './widget/color/WColorInput.vue';
import WColorInputPalette from './widget/color/WColorInputPalette.vue'; import WColorInputPalette from './widget/color/WColorInputPalette.vue';
import WPosition from './widget/position/WPosition.vue'; import WPosition from './widget/position/WPosition.vue';
import PlatformDialog from './dialog/PlatformDialog.vue';
import PlatformDrawer from './drawer/PlatformDrawer.vue';
import PlatformForm from './form/PlatformForm.vue';
import PlatformGrid from './grid/PlatformGrid.vue';
import PlatformGridTdDrag from './grid/PlatformGridTdDrag.vue';
export default { export default {
install: (app: App) => { install: (app: App) => {
app.component('WPlatformPage', WPlatformPage); app.component('WPlatformPage', WPlatformPage);
@ -16,7 +22,25 @@ export default {
app.component('WColorInput', WColorInput); app.component('WColorInput', WColorInput);
app.component('WColorInputPalette', WColorInputPalette); app.component('WColorInputPalette', WColorInputPalette);
app.component('WPosition', WPosition); app.component('WPosition', WPosition);
app.component('PlatformDialog', PlatformDialog);
app.component('PlatformDrawer', PlatformDrawer);
app.component('PlatformForm', PlatformForm);
app.component('PlatformGrid', PlatformGrid);
app.component('PlatformGridTdDrag', PlatformGridTdDrag);
}, },
}; };
export { WPlatformPage, WIconEmpty, WHScreenDiv, WColorInput, WColorInputPalette }; export {
WPlatformPage,
WIconEmpty,
WHScreenDiv,
WColorInput,
WColorInputPalette,
WPosition,
PlatformDialog,
PlatformDrawer,
PlatformForm,
PlatformGrid,
PlatformGridTdDrag,
};

0
io.sc.platform.core.frontend/src/platform/component/layout/WHScreenDiv.vue → io.sc.platform.core.frontend/src/platform/components/layout/WHScreenDiv.vue

0
io.sc.platform.core.frontend/src/platform/component/layout/WVExpandDiv.vue → io.sc.platform.core.frontend/src/platform/components/layout/WVExpandDiv.vue

85
io.sc.platform.core.frontend/src/platform/components/panel/PlatformInfo.vue

@ -0,0 +1,85 @@
<template>
<q-markup-table separator="cell" flat bordered wrap-cells>
<tbody>
<template v-for="(trItem, trIndex) in tableComputed" :key="trIndex">
<tr class="q-tr--no-hover">
<template v-for="(tdItem, tdIndex) in trItem as any" :key="tdIndex">
<td :class="labelAlignClassComputed">{{ tdItem.label }}</td>
<td :class="valueAlignClassComputed">{{ tdItem.value }}</td>
</template>
</tr>
</template>
</tbody>
</q-markup-table>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { getCssVar } from 'quasar';
import { Environment } from '@/platform';
const gc = Environment.getConfigure();
const darkBgColor = getCssVar('dark');
const bgColor = gc.theme.dark ? darkBgColor : gc.theme?.grid?.headBgColor || '#f5f7fa';
const props = defineProps({
column: { type: Number, default: 1 },
labelAlign: { type: String, default: 'left' },
valueAlign: { type: String, default: 'left' },
infoArray: {
type: Array,
default: () => {
return [];
},
},
});
const tableComputed = computed(() => {
const table = <any>[];
let tmp = <any>[];
props.infoArray.forEach((item, index) => {
if (tmp.length < props.column) {
tmp.push(item);
} else {
table.push(tmp);
tmp = [];
tmp.push(item);
}
});
table.push(tmp);
return table;
});
const labelAlignClassComputed = computed(() => {
let className = '';
switch (props.labelAlign) {
case 'right':
className = 'text-right';
break;
case 'center':
className = 'text-center';
break;
default:
className = 'text-left';
}
return className;
});
const valueAlignClassComputed = computed(() => {
let className = '';
switch (props.valueAlign) {
case 'right':
className = 'text-right';
break;
case 'center':
className = 'text-center';
break;
default:
className = 'text-left';
}
return className;
});
</script>
<style scoped>
.q-table td:nth-child(odd) {
background-color: v-bind(bgColor);
}
</style>

0
io.sc.platform.core.frontend/src/platform/component/svg/WSvgEditor.vue → io.sc.platform.core.frontend/src/platform/components/svg/WSvgEditor.vue

186
io.sc.platform.core.frontend/src/platform/components/utils/commUtil.ts

@ -0,0 +1,186 @@
import { QVueGlobals } from 'quasar';
/**
* icon使material icons
* 使便
*/
export enum PlatformIconEnum {
= 'search',
= 'zoom_in',
= 'restart_alt',
= 'loop',
= 'add',
2 = 'add_box',
3 = 'playlist_add_circle',
= 'edit',
= 'delete',
= 'visibility',
= 'fullscreen',
退 = 'fullscreen_exit',
= 'close',
= 'save',
= 'beenhere',
= 'abc',
= 'access_time',
= 'arrow_upward',
= 'arrow_downward',
= 'arrow_back',
= 'arrow_forward',
= 'attach_file',
= 'cancel',
= 'check_circle',
= 'home',
= 'settings',
2 = 'settings_applications',
= 'build_circle',
= 'arrow_drop_up',
= 'arrow_drop_down',
= 'info',
= 'warning',
= 'event',
= 'date_range',
= 'folder',
= 'published_with_changes',
= 'download',
= 'upload',
= 'find_in_page',
= 'assessment',
= 'file_copy',
= 'send',
}
/**
* =add=edit=view
*/
export enum PageStatusEnum {
= 'add',
= 'edit',
= 'view',
}
/**
* Form元素类型枚举
*/
export enum FormTypeEnum {
= 'text',
= 'textarea',
= 'select',
= 'selectMultiple',
= 'number',
= 'date',
= 'dateTime',
= 'dateRange',
}
/**
*
*/
export enum DataTypeEnum {
= 'String',
= 'Integer',
= 'BigDecimal',
= 'Date',
= 'Boolean',
}
/**
*
*/
export enum OptionComeFromEnum {
= 'dictionary',
Java接口 = 'javaApi',
= 'array',
}
/**
* Form组件内置校验name枚举
*/
export enum FormComponentValidateEnum {
= 'noSpace',
= 'integer',
= 'date',
= 'maxLength',
= 'maxPrecision',
= 'minValue',
= 'maxValue',
}
/**
*
*/
export enum OperatorTypeEnum {
isBlank = 'isBlank', // value is null or value=''
notBlank = 'notBlank', // value is not null && value<>''
isNull = 'isNull', // value is null
notNull = 'notNull', // value is not null
equals = 'equals', // =
notEqual = 'notEqual', // <>
greaterThan = 'greaterThan', // >
greaterOrEqual = 'greaterOrEqual', // >=
lessThan = 'lessThan', // <
lessOrEqual = 'lessOrEqual', // <=
contains = 'contains', // like %xxx%
notContains = 'notContains', // not like %xxx%
startsWith = 'startsWith', // like xxx%
notStartsWith = 'notStartsWith', // not like xxx%
endsWith = 'endsWith', // like %xxx
notEndsWith = 'notEndsWith', // not like %xxx
between = 'between', // min<x and x<max
betweenInclusive = 'betweenInclusive', // min<=x and x<=max
inSet = 'inSet', // in ()
notInSet = 'notInSet', // not in ()
}
// 查询对象
export type CriteriaType = {
fieldName: string;
operator: OperatorTypeEnum;
value: any;
};
/**
*
*/
export enum PlatformNotifyTypeEnum {
= 'positive',
= 'negative',
= 'warning',
= 'info',
= 'ongoing',
}
/**
*
* @param message
* @param type PlatformNotifyTypeEnum PlatformNotifyTypeEnum.
*/
export function platformNotify($q: QVueGlobals, message: string, type?: PlatformNotifyTypeEnum) {
$q.notify({
message: message,
position: 'top',
type: type ?? PlatformNotifyTypeEnum.,
actions: [{ label: '知道了', handler: () => {} }],
timeout: 3000,
});
}
/**
* (Form元素)
* @param obj
* @returns
*/
export function isEmpty(obj) {
if (typeof obj === 'undefined' || obj === null || obj === '') {
return true;
} else {
return false;
}
}

332
io.sc.platform.core.frontend/src/platform/components/utils/componentComm.ts

@ -0,0 +1,332 @@
import { Tools } from '@/platform/utils';
/**
*
* @param {Object} props
* @returns
*/
export function extractDialogProps(props: any) {
if (props) {
const result: any = {};
result.persistent = props.persistent; // 设置后,用户在对话框外单击或按 ESC 键时不再关闭对话框;此外,应用程序路由更改也不会关闭它
result.noEscDismiss = props.noEscDismiss; // 用户不能按 ESC 键关闭对话框;如果还设置了 'persistent' 属性,则无需设置它
result.noBackdropDismiss = props.noBackdropDismiss; // 用户不能通过单击对话框外部来关闭对话框;如果还设置了 'persistent' 属性,则无需设置它
result.noRouteDismiss = props.noRouteDismiss; // 更改路由应用程序不会关闭对话框;如果还设置了 'persistent' 属性,则无需设置它
result.autoClose = props.autoClose; // 对话框内的任何单击/点击都将关闭它
result.noShake = props.noShake; // 不要晃动对话框来引起用户的注意。
result.allowFocusOutside = props.allowFocusOutside; // 允许对话框外的元素可聚焦;出于辅助功能的原因,默认情况下 QDialog 不允许外部聚焦.
result.seamless = props.seamless; // 使对话框进入无缝模式;不使用背景,因此用户也可以与页面的其他部分进行交互
result.position = props.position; // 将对话框附着到一侧(默认:standard、top、right、bottom、left)
result.square = props.square; // 强制内容具有方形边框
return Tools.pickNotNil(result);
}
return {};
}
/**
* form表单组件属性
* @param {Object} props
* @returns
*/
export function extractFormProps(props: any) {
if (props) {
const result: any = {};
result.autofocus = props.autofocus; // 在初始组件渲染时将第一个可聚焦元素聚焦
result.greedy = props.greedy; // 验证表单中的所有字段(默认情况下,它在通过同步的验证找到第一个无效字段后停止)
return Tools.pickNotNil(result);
}
return {};
}
/**
*
* @param {String} type
* @param {Object} props
* @returns
*/
export function extractFormItemComponentProps(type: string, props: any) {
if ('dateRange' === type) {
return dateRange(props);
} else if ('date' === type) {
return date(props);
} else if ('select' === type) {
return select(props);
} else if ('checkbox' === type) {
return checkbox(props);
} else if ('optionGroup' === type) {
return optionGroup(props);
} else {
return input(props);
}
}
/**
* input组件
* @param props
* @returns
*/
function input(props: any) {
if (props) {
const result: any = {};
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
result.hideBottomSpace = props.hideBottomSpace ?? true;
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
result.prefix = props.prefix; // 前缀
result.suffix = props.suffix; // 后缀
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
result.counter = props.counter; // 在右下角显示自动计数器(字符数)
result.autogrow = props.autogrow; // 使字段及其内容自动增长(内容过长时组件变高,内容换行)
result.maxlength = props.maxlength; // 指定模型的最大长度
result.disable = props.disable; // 将组件置于禁用模式
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
result.filled = props.filled; // 对字段使用“填充”设计
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
result.type = props.type; // 组件类型
return Tools.pickNotNil(result);
}
return {};
}
/**
*
* @param props
* @returns
*/
function dateRange(props: any) {
if (props) {
const result: any = {};
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
result.hideBottomSpace = props.hideBottomSpace ?? true;
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
result.disable = props.disable; // 将组件置于禁用模式
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
result.filled = props.filled; // 对字段使用“填充”设计
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
return Tools.pickNotNil(result);
}
return {};
}
/**
*
* @param props
* @returns
*/
function date(props: any) {
if (props) {
const result: any = {};
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
result.hideBottomSpace = props.hideBottomSpace ?? true;
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
result.disable = props.disable; // 将组件置于禁用模式
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
result.filled = props.filled; // 对字段使用“填充”设计
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
return Tools.pickNotNil(result);
}
return {};
}
/**
*
* @param props
* @returns
*/
function select(props: any) {
if (props) {
const result: any = {};
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
result.hideBottomSpace = props.hideBottomSpace ?? true;
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
result.prefix = props.prefix; // 前缀
result.suffix = props.suffix; // 后缀
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
result.counter = props.counter; // 在右下角显示自动计数器(字符数)
result.useInput = props.useInput; // 使用一个输入标签,用户可以在其中输入
result.autogrow = props.autogrow; // 使字段及其内容自动增长(内容过长时组件变高,内容换行)
result.disable = props.disable; // 将组件置于禁用模式
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
result.filled = props.filled; // 对字段使用“填充”设计
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
result.multiple = props.multiple; // 支持多选
result.options = props.options; // 下拉选项集合
result.maxValues = props.maxValues; // 允许用户可以进行的最大选择数
result.useChips = props.useChips; // 使用QChip显示当前选择的内容
return Tools.pickNotNil(result);
}
return {};
}
/**
*
* @param props
* @returns
*/
function checkbox(props: any) {
if (props) {
const result: any = {};
result.keepColor = props.keepColor; // 当组件未勾选/关闭时,是否应保留颜色?
result.checkedIcon = props.checkedIcon; // 此图标将会在 model 值为 true 时被使用(代替默认的设计)
result.uncheckedIcon = props.uncheckedIcon; // 此图标将会在 model 值为 false 时被使用(代替默认的设计)
result.toggleIndeterminate = props.toggleIndeterminate ?? false; // 当用户点击组件时,除 true 和 false 外,是否还添加一个不确定(indeterminate)的状态?
result.leftLabel = props.leftLabel; // 如有标签,应显示在组件的左侧
result.trueValue = props.trueValue; // model 为何值时被视为选中/勾选/启用?
result.falseValue = props.falseValue; // model 为何值时被视为未选中/未勾选/关闭?
result.disable = props.disable; // 将组件置于禁用模式
result.size = props.size; // 带有 CSS 单位的尺寸大小,包括单位的名称或标准大小名称(xs | sm | md | lg | xl)
result.color = props.color; // 组件的颜色,来自 Quasar 调色板的颜色名称
result.dense = props.dense; // 紧凑模式,占用更少的空间
return Tools.pickNotNil(result);
}
return {};
}
/**
*
* @param props
* @returns
*/
function optionGroup(props: any) {
if (props) {
const result: any = {};
result.name = props.name; // 用于指定控件的名称;如果处理直接提交到 URL 的表单时很有用
result.keepColor = props.keepColor; // 当组件未勾选/关闭时,是否应保留颜色?
result.type = props.optionGroupType; // 要使用的输入组件类型,默认radio,可选:radio、checkbox、toggle
result.leftLabel = props.leftLabel; // 如有标签,应显示在组件的左侧
result.inline = props.inline ?? true; // 将输入组件显示为内联块,而不是每个组件都有自己的行
result.options = props.options; //具有值、标签和禁用(可选)属性的对象数组,包含的属性:label、value、disable等
result.disable = props.disable; // 将组件置于禁用模式下
result.size = props.size; // 带有 CSS 单位的尺寸大小,包括单位的名称或标准大小名称(xs | sm | md | lg | xl)
result.color = props.color; // 组件的颜色,来自 Quasar 调色板的颜色名称
result.dense = props.dense; // 紧凑模式,占用更少的空间
return Tools.pickNotNil(result);
}
return {};
}
/**
*
* @param {Object} props
* @returns
*/
export function extractTableProps(props: any) {
if (props) {
const result: any = {};
result.color = props.color; // 组件的颜色,来自 Quasar 调色板的颜色名称
result.dense = props.dense; // 密恐模式;
result.dark = props.dark; // 设置组件背景为深色
result.flat = props.flat; // 应用“平面”设计(无默认阴影)
result.bordered = props.bordered; // 将默认边框应用于组件
result.square = props.square; // 删除边框圆角(border-radius),使边框为正方形
return Tools.pickNotNil(result);
}
return {};
}
function columnStyle(item: any) {
let style = '';
if (Object.hasOwnProperty.call(item, 'style')) {
style = item.style;
}
if (Object.hasOwnProperty.call(item, 'width')) {
item.style = `min-width: ` + item.width + `px; max-width: ` + item.width + `px;` + style;
delete item.width;
if (Object.hasOwnProperty.call(item, 'classes')) {
item.classes = item.classes + ' truncate';
} else {
item.classes = 'truncate';
}
}
}
function columnChildrenHandler(item: any, gridColumns: any) {
if (item.childrenColumns && item.childrenColumns.length > 0) {
item.childrenColumns.forEach((column) => {
columnChildrenHandler(column, gridColumns);
});
} else {
columnStyle(item);
gridColumns.push({
...{ align: 'left', label: item.name, field: item.name, sortable: true },
...item,
});
}
}
/**
*
*/
export function extractTableColumnsProps(props: any) {
const gridColumns = <any>[];
if (props.tableColumns && props.tableColumns.length > 0) {
if (props.tableShowSortNo) {
gridColumns.push({ name: '_sortNo_', align: 'center', label: '序号', field: '_sortNo_' });
}
props.tableColumns.forEach((item: any) => {
columnChildrenHandler(item, gridColumns);
});
return gridColumns;
}
return [];
}
const formColsScreenMap = new Map();
formColsScreenMap.set(1, { xs: 1, sm: 1, md: 2, lg: 3, xl: 4 });
formColsScreenMap.set(2, { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 });
formColsScreenMap.set(3, { xs: 1, sm: 2, md: 3, lg: 4, xl: 6 });
formColsScreenMap.set(4, { xs: 1, sm: 2, md: 4, lg: 4, xl: 6 });
formColsScreenMap.set(5, { xs: 1, sm: 2, md: 5, lg: 6, xl: 6 });
formColsScreenMap.set(6, { xs: 1, sm: 3, md: 6, lg: 6, xl: 6 });
formColsScreenMap.set(7, { xs: 1, sm: 4, md: 7, lg: 7, xl: 7 });
formColsScreenMap.set(8, { xs: 1, sm: 4, md: 8, lg: 8, xl: 8 });
formColsScreenMap.set(9, { xs: 1, sm: 4, md: 9, lg: 9, xl: 9 });
formColsScreenMap.set(10, { xs: 1, sm: 4, md: 10, lg: 10, xl: 10 });
formColsScreenMap.set(11, { xs: 1, sm: 4, md: 11, lg: 11, xl: 11 });
formColsScreenMap.set(12, { xs: 1, sm: 4, md: 12, lg: 12, xl: 12 });
/**
*
* @param configColsNumber
* @param screen
*/
export function getQueryFormColsNumberByScreen(configColsNumber: number, screen: any) {
return formColsScreenMap.get(configColsNumber)[screen];
}
/**
* key转map
* @param key
* @param array
*/
export function arrayToMap(key, array) {
const map = new Map();
array.forEach((item) => {
if (item.name !== '_sortNo_') {
map.set(item[key], item);
}
});
return map;
}

19
io.sc.platform.core.frontend/src/platform/components/utils/index.ts

@ -0,0 +1,19 @@
export { PlatformIconEnum } from './commUtil';
export { PageStatusEnum } from './commUtil';
export { FormTypeEnum } from './commUtil';
export { DataTypeEnum } from './commUtil';
export { OptionComeFromEnum } from './commUtil';
export { FormComponentValidateEnum } from './commUtil';
export { OperatorTypeEnum } from './commUtil';
export type { CriteriaType } from './commUtil';
export { PlatformNotifyTypeEnum } from './commUtil';
export { platformNotify } from './commUtil';
export { isEmpty } from './commUtil';
export { extractDialogProps } from './componentComm';
export { extractFormProps } from './componentComm';
export { extractFormItemComponentProps } from './componentComm';
export { extractTableProps } from './componentComm';
export { extractTableColumnsProps } from './componentComm';
export { getQueryFormColsNumberByScreen } from './componentComm';
export { arrayToMap } from './componentComm';

0
io.sc.platform.core.frontend/src/platform/component/widget/color/WColorInput.vue → io.sc.platform.core.frontend/src/platform/components/widget/color/WColorInput.vue

0
io.sc.platform.core.frontend/src/platform/component/widget/color/WColorInputPalette.vue → io.sc.platform.core.frontend/src/platform/components/widget/color/WColorInputPalette.vue

0
io.sc.platform.core.frontend/src/platform/component/widget/position/WPosition.vue → io.sc.platform.core.frontend/src/platform/components/widget/position/WPosition.vue

48
io.sc.platform.core.frontend/src/platform/enums/IconEnum.ts

@ -0,0 +1,48 @@
/**
* icon使material icons
* 使便
*/
export enum IconEnum {
= 'search',
= 'zoom_in',
= 'restart_alt',
= 'loop',
= 'add',
2 = 'add_box',
3 = 'playlist_add_circle',
= 'edit',
= 'delete',
= 'visibility',
= 'fullscreen',
退 = 'fullscreen_exit',
= 'close',
= 'save',
= 'beenhere',
= 'abc',
= 'access_time',
= 'arrow_upward',
= 'arrow_downward',
= 'arrow_back',
= 'arrow_forward',
= 'attach_file',
= 'cancel',
= 'check_circle',
= 'home',
= 'settings',
2 = 'settings_applications',
= 'build_circle',
= 'arrow_drop_up',
= 'arrow_drop_down',
= 'info',
= 'warning',
= 'event',
= 'date_range',
= 'folder',
= 'published_with_changes',
= 'download',
= 'upload',
= 'find_in_page',
= 'assessment',
= 'file_copy',
= 'send',
}

1
io.sc.platform.core.frontend/src/platform/enums/index.ts

@ -0,0 +1 @@
export { IconEnum } from './IconEnum';

38
io.sc.platform.core.frontend/src/platform/index.ts

@ -2,7 +2,7 @@ import { App } from 'vue';
import PlatformPlugin from './plugin'; import PlatformPlugin from './plugin';
import QuasarPlugin from './plugin/quasar'; import QuasarPlugin from './plugin/quasar';
import ComponentPlugin from './component'; import ComponentPlugin from './components';
import DirectivePlugin from './directive'; import DirectivePlugin from './directive';
import VueDOMPurifyHTML from 'vue-dompurify-html'; import VueDOMPurifyHTML from 'vue-dompurify-html';
@ -52,13 +52,28 @@ export type {
UserType, UserType,
} from './types'; } from './types';
/**
*
*/
export { PConst } from './PConst'; export { PConst } from './PConst';
/**
*
*/
export { IconEnum } from './enums';
/**
*
*/
export { axios } from './plugin'; export { axios } from './plugin';
export { eventBus } from './plugin'; export { eventBus } from './plugin';
export { i18n } from './plugin'; export { i18n } from './plugin';
export { usePlatformStore } from './plugin'; export { usePlatformStore } from './plugin';
export { router } from './plugin'; export { router } from './plugin';
/**
*
*/
export { Environment } from './plugin'; export { Environment } from './plugin';
export { ApplicationInitializer } from './plugin'; export { ApplicationInitializer } from './plugin';
export { ComponentManager } from './plugin'; export { ComponentManager } from './plugin';
@ -71,10 +86,27 @@ export { RouterManager } from './plugin';
export { SessionManager } from './plugin'; export { SessionManager } from './plugin';
export { TagViewManager } from './plugin'; export { TagViewManager } from './plugin';
/**
*
*/
export { Tools } from './utils'; export { Tools } from './utils';
export { QuasarTools } from './utils'; export { QuasarTools } from './utils';
export { JavascriptLoader } from './utils'; export { JavascriptLoader } from './utils';
export { TreeBuilder } from './utils'; export { TreeBuilder } from './utils';
// 导出平台 UI 组件 /**
export { WColorInput, WColorInputPalette, WHScreenDiv, WIconEmpty, WPlatformPage } from './component'; * UI
*/
export {
WPlatformPage,
WIconEmpty,
WHScreenDiv,
WColorInput,
WColorInputPalette,
WPosition,
PlatformDialog,
PlatformDrawer,
PlatformForm,
PlatformGrid,
PlatformGridTdDrag,
} from './components';

32
io.sc.platform.core.frontend/src/platform/mock/api/system/user/appConfigure.json → io.sc.platform.core.frontend/src/platform/mock/api/lcdp/configure/getActiveConfigure.json

@ -1,30 +1,15 @@
{ {
"enable": true, "enable": true,
"url": "/api/system/user/appConfigure", "url": "/api/lcdp/configure/getActiveConfigure",
"method": "get", "method": "get",
"response": { "response": {
"code" : 200, "code" : 200,
"messageI18nKey" : "success", "messageI18nKey" : "success",
"message" : "success", "message" : "success",
"data" : { "data" : {
"i18nMessages" : {
"en" : {
"application.copyright" : "Copyright © 2019–2022",
"application.title" : "Developer Platform"
},
"zh_CN" : {
"application.copyright" : "Copyright © 2019–2022",
"application.title" : "应用开发平台"
},
"tw_CN" : {
"application.copyright" : "Copyright © 2019–2022",
"application.title" : "應用開發平台"
}
},
"setting" : { "setting" : {
"routerHistoryMode" : "hash", "routerHistoryMode" : "hash",
"logoutConfirm" : true, "homePage" : "/home",
"notifyTimeout" : 1000,
"i18n" : { "i18n" : {
"availableLocales" : [ "en", "zh_CN", "tw_CN" ], "availableLocales" : [ "en", "zh_CN", "tw_CN" ],
"locale" : "zh_CN", "locale" : "zh_CN",
@ -32,8 +17,7 @@
"fallbackWarn" : false, "fallbackWarn" : false,
"missingWarn" : false, "missingWarn" : false,
"changeNotify" : true "changeNotify" : true
}, }
"homePage" : "/home"
}, },
"theme" : { "theme" : {
"dark" : false, "dark" : false,
@ -116,14 +100,15 @@
"containerBgColor" : "#EEEEEE" "containerBgColor" : "#EEEEEE"
}, },
"footer" : { "footer" : {
"show" : true, "show" : false,
"height" : 40, "height" : 40,
"color" : "#ffffff", "color" : "#ffffff",
"bgColor" : "#14234a" "bgColor" : "#14234a"
}, },
"login" : { "login" : {
"bgImage" : "login-bg.jpg", "bgImage" : "login-bg.jpg",
"encodePassword" : true "encodePassword" : true,
"logoutConfirm" : true
}, },
"scroller" : { "scroller" : {
"enable" : true, "enable" : true,
@ -137,6 +122,11 @@
"notifier" : { "notifier" : {
"position" : "top", "position" : "top",
"timeout" : 2000 "timeout" : 2000
},
"grid" : {
"headBgColor" : "#f5f7fa",
"stickyBgColor" : "#ffffff",
"borderColor" : "rgba(0, 0, 0, 0.12)"
} }
} }
} }

4
io.sc.platform.core.frontend/src/platform/mock/index.ts

@ -1,7 +1,7 @@
import login from './api/login.json'; import login from './api/login.json';
import session from './api/system/user/session.json'; import session from './api/system/user/session.json';
import appConfigure from './api/system/user/appConfigure.json'; import activeConfigure from './api/lcdp/configure/getActiveConfigure.json';
const PLATFORM_MOCKS = [login, session, appConfigure]; const PLATFORM_MOCKS = [login, session, activeConfigure];
export default PLATFORM_MOCKS; export default PLATFORM_MOCKS;

20
io.sc.platform.core.frontend/src/platform/utils/Tools.ts

@ -722,6 +722,26 @@ class Tools {
} }
return true; return true;
} }
/**
*
* @param object
*/
public static pickNotNil(object: object): object {
if (object) {
for (const property in object) {
const value = object[property];
if (Tools.isObject(value) && !Tools.isArray(value)) {
Tools.pickNotNil(value);
} else {
if (Tools.isUndefinedOrNull(value)) {
delete object[property];
}
}
}
}
return object;
}
} }
export { Tools }; export { Tools };

38
io.sc.platform.core.frontend/src/views/View1.vue

@ -1,9 +1,39 @@
<template> <template>
<div>{{ message }}</div> <w-dialog
ref="dialogRef"
:persistent="true"
:maximized="false"
title="xxx"
width="50%"
height="50%"
:can-maximize="false"
:buttons="[
{
icon: IconEnum.保存,
label: '保存',
loading: false,
click: async () => {},
},
]"
@maximized="dialogMaximize"
></w-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Environment, axios } from '@/platform'; // import { Environment, axios } from '@/platform';
const response = await axios.get(Environment.apiContextPath('/api/sample/action1')); // const response = await axios.get(Environment.apiContextPath('/api/sample/action1'));
const message = response.data.message; // const message = response.data.message;
import { ref, reactive, onMounted } from 'vue';
import { IconEnum } from '@/platform';
const dialogRef = ref();
const dialogMaximize = (maximizedToggle: boolean) => {
console.log(maximizedToggle);
};
onMounted(() => {
dialogRef.value.show();
});
</script> </script>

8
io.sc.platform.core.frontend/template-project/package.json

@ -1,6 +1,6 @@
{ {
"name": "platform-core", "name": "platform-core",
"version": "8.1.13", "version": "8.1.15",
"description": "前端核心包,用于快速构建前端的脚手架", "description": "前端核心包,用于快速构建前端的脚手架",
"private": false, "private": false,
"keywords": [], "keywords": [],
@ -77,14 +77,12 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.13", "platform-core": "8.1.15",
"quasar": "2.13.0", "quasar": "2.13.0",
"react-dnd-html5-backend": "16.0.1",
"tailwindcss": "3.3.5", "tailwindcss": "3.3.5",
"vue": "3.3.7", "vue": "3.3.7",
"vue-dompurify-html": "4.1.4", "vue-dompurify-html": "4.1.4",
"vue-i18n": "9.6.0", "vue-i18n": "9.6.0",
"vue-router": "4.2.5", "vue-router": "4.2.5"
"vue3-dnd": "2.0.2"
} }
} }

5
io.sc.platform.core.frontend/template-project/src/App.vue

@ -1,10 +1,7 @@
<template> <template>
<DndProvider :backend="HTML5Backend">
<w-platform-page></w-platform-page> <w-platform-page></w-platform-page>
</DndProvider>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { DndProvider } from 'vue3-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
</script> </script>

38
io.sc.platform.core.frontend/template-project/src/views/View1.vue

@ -1,9 +1,39 @@
<template> <template>
<div>{{ message }}</div> <w-dialog
ref="dialogRef"
:persistent="true"
:maximized="false"
title="xxx"
width="50%"
height="50%"
:can-maximize="false"
:buttons="[
{
icon: IconEnum.保存,
label: '保存',
loading: false,
click: async () => {},
},
]"
@maximized="dialogMaximize"
></w-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Environment, axios } from 'platform-core'; // import { Environment, axios } from 'platform-core';
const response = await axios.get(Environment.apiContextPath('/api/sample/action1')); // const response = await axios.get(Environment.apiContextPath('/api/sample/action1'));
const message = response.data.message; // const message = response.data.message;
import { ref, reactive, onMounted } from 'vue';
import { IconEnum } from 'platform-core';
const dialogRef = ref();
const dialogMaximize = (maximizedToggle: boolean) => {
console.log(maximizedToggle);
};
onMounted(() => {
dialogRef.value.show();
});
</script> </script>

2
io.sc.platform.core.frontend/template-project/webpack.config.mf.cjs

@ -42,12 +42,10 @@ module.exports = {
'pinia': { requiredVersion: deps['pinia'], singleton: true }, 'pinia': { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true }, 'quasar': { requiredVersion: deps['quasar'], singleton: true },
'react-dnd-html5-backend':{ requiredVersion: deps['react-dnd-html5-backend'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true }, 'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'vue3-dnd':{ requiredVersion: deps['vue3-dnd'], singleton: true },
} }
}), }),
] ]

2
io.sc.platform.core.frontend/webpack.config.mf.cjs

@ -42,12 +42,10 @@ module.exports = {
'pinia': { requiredVersion: deps['pinia'], singleton: true }, 'pinia': { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true }, 'quasar': { requiredVersion: deps['quasar'], singleton: true },
'react-dnd-html5-backend':{ requiredVersion: deps['react-dnd-html5-backend'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true }, 'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'vue3-dnd':{ requiredVersion: deps['vue3-dnd'], singleton: true },
} }
}), }),
] ]

3
io.sc.platform.core/src/main/java/io/sc/platform/core/i18n/PlatformResourceBundleMessageSource.java

@ -19,6 +19,9 @@ public class PlatformResourceBundleMessageSource extends ResourceBundleMessageSo
@Override @Override
public Map<Language, Map<String, String>> getMessages(String... messageKeys) { public Map<Language, Map<String, String>> getMessages(String... messageKeys) {
if(messageKeys==null || messageKeys.length<=0){
return Collections.emptyMap();
}
Map<Language, Map<String, String>> messageMap =PlatformMessageSourceLoader.getInstance().getMessages(this.getBasenameSet()); Map<Language, Map<String, String>> messageMap =PlatformMessageSourceLoader.getInstance().getMessages(this.getBasenameSet());
if(messageMap.isEmpty()){ if(messageMap.isEmpty()){
return Collections.emptyMap(); return Collections.emptyMap();

4
io.sc.platform.core/src/main/java/io/sc/platform/core/service/impl/RuntimeServiceImpl.java

@ -58,7 +58,7 @@ public class RuntimeServiceImpl implements RuntimeService {
@Override @Override
public boolean isInstallerReady() { public boolean isInstallerReady() {
Object bean =BeanUtil.getBeanByClassName(applicationContext,INSTALLER_SERVICE_CLASS); Object bean =BeanUtil.getBean(applicationContext,INSTALLER_SERVICE_CLASS);
if(bean!=null){ if(bean!=null){
try { try {
Object value = BeanUtil.invoke(bean, "isEnabled"); Object value = BeanUtil.invoke(bean, "isEnabled");
@ -80,7 +80,7 @@ public class RuntimeServiceImpl implements RuntimeService {
@Override @Override
public boolean isDatabaseUpdaterReady() { public boolean isDatabaseUpdaterReady() {
Object bean =BeanUtil.getBeanByClassName(applicationContext,LIQUIBASE_SERVICE_CLASS); Object bean =BeanUtil.getBean(applicationContext,LIQUIBASE_SERVICE_CLASS);
if(bean!=null){ if(bean!=null){
try { try {
Object value = BeanUtil.invoke(bean, "isEnabled"); Object value = BeanUtil.invoke(bean, "isEnabled");

19
io.sc.platform.core/src/main/java/io/sc/platform/core/util/BeanUtil.java

@ -2,6 +2,7 @@ package io.sc.platform.core.util;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -10,14 +11,28 @@ import java.lang.reflect.Method;
public class BeanUtil { public class BeanUtil {
private static final Logger log = LoggerFactory.getLogger(BeanUtil.class); private static final Logger log = LoggerFactory.getLogger(BeanUtil.class);
private BeanUtil(){} private BeanUtil(){}
public static Object getBeanByClassName(ApplicationContext applicationContext, String beanClassName){
public static <T> T getBean(ApplicationContext applicationContext, Class<T> beanClass){
try { try {
Class<?> beanClass = Class.forName(beanClassName);
return applicationContext.getBean(beanClass); return applicationContext.getBean(beanClass);
} catch (BeansException e) {
return null;
}
}
public static Object getBean(ApplicationContext applicationContext, String beanClassName){
Class<?> beanClass = null;
try {
beanClass = Class.forName(beanClassName);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
log.error("",e); log.error("",e);
return null; return null;
} }
try {
return applicationContext.getBean(beanClass);
} catch (BeansException e) {
return null;
}
} }
public static Object invoke(Object bean,String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { public static Object invoke(Object bean,String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

1
io.sc.platform.developer.doc/asciidoc/9999-appendix/docker-compose/docker-compose.adoc

@ -10,6 +10,7 @@ Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器
这时候就需要一个工具能够管理一组相关联的的应用容器,这就是 Docker Compose。 这时候就需要一个工具能够管理一组相关联的的应用容器,这就是 Docker Compose。
Compose有2个重要的概念: Compose有2个重要的概念:
* 项目(Project): 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。 * 项目(Project): 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
* 服务(Service): 一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。 * 服务(Service): 一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。

2
io.sc.platform.developer.doc/asciidoc/9999-appendix/docker/mysql/mysql.adoc

@ -1,4 +1,6 @@
== Mysql 8 == Mysql 8
=== docker-compose.yml
=== 安装 === 安装
[source,bash] [source,bash]
---- ----

5
io.sc.platform.developer.frontend/package.json

@ -79,14 +79,13 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.12", "platform-core": "8.1.14",
"quasar": "2.13.0", "quasar": "2.13.0",
"react-dnd-html5-backend": "16.0.1",
"tailwindcss": "3.3.5", "tailwindcss": "3.3.5",
"vue": "3.3.7", "vue": "3.3.7",
"vue-dompurify-html": "4.1.4", "vue-dompurify-html": "4.1.4",
"vue-i18n": "9.6.0", "vue-i18n": "9.6.0",
"vue-router": "4.2.5", "vue-router": "4.2.5",
"vue3-dnd": "2.0.2" "platform-components": "8.1.2"
} }
} }

2
io.sc.platform.developer.frontend/webpack.config.mf.cjs

@ -42,12 +42,10 @@ module.exports = {
'pinia': { requiredVersion: deps['pinia'], singleton: true }, 'pinia': { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true }, 'quasar': { requiredVersion: deps['quasar'], singleton: true },
'react-dnd-html5-backend':{ requiredVersion: deps['react-dnd-html5-backend'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true }, 'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'vue3-dnd':{ requiredVersion: deps['vue3-dnd'], singleton: true },
} }
}), }),
] ]

1
io.sc.platform.flowable/build.gradle

@ -1,5 +1,6 @@
dependencies { dependencies {
api( api(
project(":io.sc.platform.communication"),
project(":io.sc.platform.system"), project(":io.sc.platform.system"),
"org.flowable:flowable-spring-boot-starter-process:${flowable_version}", "org.flowable:flowable-spring-boot-starter-process:${flowable_version}",

2
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/AgentWebController.java

@ -5,6 +5,7 @@ import io.sc.platform.flowable.jpa.repository.AgentRepository;
import io.sc.platform.flowable.service.AgentService; import io.sc.platform.flowable.service.AgentService;
import io.sc.platform.mvc.controller.support.RestCrudController; import io.sc.platform.mvc.controller.support.RestCrudController;
import io.sc.platform.security.util.SecurityUtil; import io.sc.platform.security.util.SecurityUtil;
import io.sc.platform.system.api.user.User;
import io.sc.platform.system.user.jpa.entity.UserEntity; import io.sc.platform.system.user.jpa.entity.UserEntity;
import io.sc.platform.system.user.jpa.repository.UserRepository; import io.sc.platform.system.user.jpa.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List;
import java.util.Map; import java.util.Map;
@Controller @Controller

27
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/FlowableModelerEditorWebController.java

@ -4,6 +4,16 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import io.sc.platform.core.Environment;
import io.sc.platform.core.util.LocaleUtil;
import io.sc.platform.flowable.service.FlowableModelerService;
import io.sc.platform.flowable.support.BpmnModelWrapper;
import io.sc.platform.flowable.support.FlowableGroupList;
import io.sc.platform.flowable.support.FlowableUser;
import io.sc.platform.flowable.support.FlowableUserList;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.system.role.service.RoleService;
import io.sc.platform.system.user.service.UserService;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.BpmnModel;
import org.flowable.editor.language.json.converter.BpmnJsonConverter; import org.flowable.editor.language.json.converter.BpmnJsonConverter;
@ -21,18 +31,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.wsp.framework.core.Environment;
import org.wsp.framework.core.util.LocaleUtil;
import org.wsp.framework.flowable.service.FlowableModelerService;
import org.wsp.framework.flowable.support.BpmnModelWrapper;
import org.wsp.framework.flowable.support.FlowableGroupList;
import org.wsp.framework.flowable.support.FlowableUser;
import org.wsp.framework.flowable.support.FlowableUserList;
import org.wsp.framework.jpa.service.support.protocol.QueryParameter;
import org.wsp.framework.jpa.service.support.protocol.criteria.TextMatchStyle;
import org.wsp.framework.system.role.service.RoleService;
import org.wsp.framework.system.user.entity.User;
import org.wsp.framework.system.user.service.UserService;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
@ -74,7 +72,7 @@ public class FlowableModelerEditorWebController {
@RequestMapping(value = "app/rest/stencil-sets/editor", method = RequestMethod.GET) @RequestMapping(value = "app/rest/stencil-sets/editor", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public String stencilsets(Locale locale) throws Exception{ public String stencilsets(Locale locale) throws Exception{
String[] candidateCodes =LocaleUtil.getCandidateCode(locale); String[] candidateCodes = LocaleUtil.getCandidateCode(locale);
Resource rs =null; Resource rs =null;
for(String candidateCode : candidateCodes){ for(String candidateCode : candidateCodes){
rs =new DefaultResourceLoader().getResource("classpath:/org/wsp/framework/flowable/controller/stencilsets_" + candidateCode + ".json"); rs =new DefaultResourceLoader().getResource("classpath:/org/wsp/framework/flowable/controller/stencilsets_" + candidateCode + ".json");
@ -85,7 +83,7 @@ public class FlowableModelerEditorWebController {
if(!rs.exists()) { if(!rs.exists()) {
rs =new DefaultResourceLoader().getResource("classpath:/org/wsp/framework/flowable/controller/stencilsets.json"); rs =new DefaultResourceLoader().getResource("classpath:/org/wsp/framework/flowable/controller/stencilsets.json");
} }
return IOUtils.toString(rs.getInputStream(),Environment.DEFAULT_ENCODING); return IOUtils.toString(rs.getInputStream(), Environment.DEFAULT_CHARSET_NAME);
} }
/** /**
@ -138,7 +136,6 @@ public class FlowableModelerEditorWebController {
User queryExampleEntity =new User(); User queryExampleEntity =new User();
queryExampleEntity.setLoginName(filter); queryExampleEntity.setLoginName(filter);
QueryParameter queryParameter =new QueryParameter(); QueryParameter queryParameter =new QueryParameter();
queryParameter.setTextMatchStyle(TextMatchStyle.substring);
return FlowableUserList.fromUsers(userService.query(queryExampleEntity, queryParameter)); return FlowableUserList.fromUsers(userService.query(queryExampleEntity, queryParameter));
} }

12
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/ProcessEntityWebController.java

@ -1,20 +1,20 @@
package io.sc.platform.flowable.controller; package io.sc.platform.flowable.controller;
import io.sc.platform.flowable.jpa.entity.ProcessEntity;
import io.sc.platform.flowable.jpa.repository.ProcessEntityRepository;
import io.sc.platform.flowable.service.ProcessEntityService;
import io.sc.platform.mvc.controller.support.RestCrudController;
import io.sc.platform.security.util.SecurityUtil;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.wsp.framework.flowable.entity.ProcessEntity;
import org.wsp.framework.flowable.repository.ProcessEntityRepository;
import org.wsp.framework.flowable.service.ProcessEntityService;
import org.wsp.framework.mvc.controller.support.SmartClientRestfulCrudController;
import org.wsp.framework.security.util.SecurityUtil;
@Controller @Controller
@RequestMapping("/api/system/process") @RequestMapping("/api/system/process")
public class ProcessEntityWebController extends SmartClientRestfulCrudController<ProcessEntity,String,ProcessEntityRepository,ProcessEntityService>{ public class ProcessEntityWebController extends RestCrudController<ProcessEntity,String, ProcessEntityRepository, ProcessEntityService> {
//========================================================================================================= //=========================================================================================================
// 菜单入口 // 菜单入口
//========================================================================================================= //=========================================================================================================

10
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/ProcessOperationWebController.java

@ -1,12 +1,12 @@
package io.sc.platform.flowable.controller; package io.sc.platform.flowable.controller;
import io.sc.platform.flowable.controller.support.ProcessProperties;
import io.sc.platform.flowable.service.ProcessOperationService;
import io.sc.platform.flowable.support.CompleteTaskException;
import io.sc.platform.flowable.support.CompleteTaskResponse;
import io.sc.platform.flowable.support.Goback;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.wsp.framework.flowable.controller.support.ProcessProperties;
import org.wsp.framework.flowable.service.ProcessOperationService;
import org.wsp.framework.flowable.support.CompleteTaskException;
import org.wsp.framework.flowable.support.CompleteTaskResponse;
import org.wsp.framework.flowable.support.Goback;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;

12
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/ProcessQueryWebController.java

@ -1,14 +1,10 @@
package io.sc.platform.flowable.controller; package io.sc.platform.flowable.controller;
import io.sc.platform.flowable.service.ProcessQueryService;
import io.sc.platform.flowable.support.*;
import io.sc.platform.mvc.support.FileDownloader;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.wsp.framework.flowable.entity.ProcessEntity;
import org.wsp.framework.flowable.service.ProcessQueryService;
import org.wsp.framework.flowable.support.*;
import org.wsp.framework.jpa.service.support.protocol.QueryParameter;
import org.wsp.framework.mvc.protocol.response.ResponseWrapper;
import org.wsp.framework.mvc.protocol.response.support.ResponseWrapperBuilder;
import org.wsp.framework.mvc.support.FileDownloader;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -41,7 +37,7 @@ public class ProcessQueryWebController {
@RequestMapping(value="instance/isc/fetch", method=RequestMethod.GET) @RequestMapping(value="instance/isc/fetch", method=RequestMethod.GET)
@ResponseBody @ResponseBody
public ResponseWrapper<ProcessInstanceWrapper> processInstanceQuery(@RequestParam(name="businessKey",required=false)String businessKey,ProcessEntity queryExampleEntity, QueryParameter queryParameter) throws Exception{ public ResponseWrapper<ProcessInstanceWrapper> processInstanceQuery(@RequestParam(name="businessKey",required=false)String businessKey, ProcessEntity queryExampleEntity, QueryParameter queryParameter) throws Exception{
return ResponseWrapperBuilder.query(service.queryProcessInstances(businessKey,queryExampleEntity,queryParameter)); return ResponseWrapperBuilder.query(service.queryProcessInstances(businessKey,queryExampleEntity,queryParameter));
} }

4
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/support/ProcessProperties.java

@ -2,9 +2,9 @@ package io.sc.platform.flowable.controller.support;
import java.util.Map; import java.util.Map;
import org.wsp.framework.core.util.JacksonObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import io.sc.platform.core.util.ObjectMapper4Json;
public class ProcessProperties { public class ProcessProperties {
private String bussinessKey; private String bussinessKey;
@ -40,7 +40,7 @@ public class ProcessProperties {
@Override @Override
public String toString() { public String toString() {
try { try {
return JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(this); return ObjectMapper4Json.getMapper().writeValueAsString(this);
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
return super.toString(); return super.toString();
} }

18
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/extension/listener/VariableSetterListener.java

@ -2,6 +2,7 @@ package io.sc.platform.flowable.extension.listener;
import java.util.Map; import java.util.Map;
import io.sc.platform.core.util.ObjectMapper4Json;
import org.flowable.common.engine.api.delegate.Expression; import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener; import org.flowable.engine.delegate.ExecutionListener;
@ -10,7 +11,6 @@ import org.flowable.task.service.delegate.DelegateTask;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.wsp.framework.core.util.JacksonObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
@ -35,7 +35,7 @@ public class VariableSetterListener implements ExecutionListener, TaskListener{
if(variables!=null){ if(variables!=null){
String variablesText =variables.getExpressionText(); String variablesText =variables.getExpressionText();
if(StringUtils.hasText(variablesText)){ if(StringUtils.hasText(variablesText)){
Map<String,Object> map =JacksonObjectMapper.getDefaultObjectMapper().readValue(variablesText, new TypeReference<Map<String,Object>>(){}); Map<String,Object> map = ObjectMapper4Json.getMapper().readValue(variablesText, new TypeReference<Map<String,Object>>(){});
if(map!=null && map.size()>0){ if(map!=null && map.size()>0){
for(String key : map.keySet()){ for(String key : map.keySet()){
execution.setVariable(key, map.get(key)); execution.setVariable(key, map.get(key));
@ -47,7 +47,7 @@ public class VariableSetterListener implements ExecutionListener, TaskListener{
if(variablesLocal!=null){ if(variablesLocal!=null){
String variablesLocalText =variablesLocal.getExpressionText(); String variablesLocalText =variablesLocal.getExpressionText();
if(StringUtils.hasText(variablesLocalText)){ if(StringUtils.hasText(variablesLocalText)){
Map<String,Object> map =JacksonObjectMapper.getDefaultObjectMapper().readValue(variablesLocalText, new TypeReference<Map<String,Object>>(){}); Map<String,Object> map =ObjectMapper4Json.getMapper().readValue(variablesLocalText, new TypeReference<Map<String,Object>>(){});
if(map!=null && map.size()>0){ if(map!=null && map.size()>0){
for(String key : map.keySet()){ for(String key : map.keySet()){
execution.setVariableLocal(key, map.get(key)); execution.setVariableLocal(key, map.get(key));
@ -59,7 +59,7 @@ public class VariableSetterListener implements ExecutionListener, TaskListener{
if(transientVariables!=null){ if(transientVariables!=null){
String transientVariablesText =transientVariables.getExpressionText(); String transientVariablesText =transientVariables.getExpressionText();
if(StringUtils.hasText(transientVariablesText)){ if(StringUtils.hasText(transientVariablesText)){
Map<String,Object> map =JacksonObjectMapper.getDefaultObjectMapper().readValue(transientVariablesText, new TypeReference<Map<String,Object>>(){}); Map<String,Object> map =ObjectMapper4Json.getMapper().readValue(transientVariablesText, new TypeReference<Map<String,Object>>(){});
if(map!=null && map.size()>0){ if(map!=null && map.size()>0){
for(String key : map.keySet()){ for(String key : map.keySet()){
execution.setTransientVariable(key, map.get(key)); execution.setTransientVariable(key, map.get(key));
@ -71,7 +71,7 @@ public class VariableSetterListener implements ExecutionListener, TaskListener{
if(transientVariablesLocal!=null){ if(transientVariablesLocal!=null){
String transientVariablesLocalText =transientVariablesLocal.getExpressionText(); String transientVariablesLocalText =transientVariablesLocal.getExpressionText();
if(StringUtils.hasText(transientVariablesLocalText)){ if(StringUtils.hasText(transientVariablesLocalText)){
Map<String,Object> map =JacksonObjectMapper.getDefaultObjectMapper().readValue(transientVariablesLocalText, new TypeReference<Map<String,Object>>(){}); Map<String,Object> map =ObjectMapper4Json.getMapper().readValue(transientVariablesLocalText, new TypeReference<Map<String,Object>>(){});
if(map!=null && map.size()>0){ if(map!=null && map.size()>0){
for(String key : map.keySet()){ for(String key : map.keySet()){
execution.setTransientVariableLocal(key, map.get(key)); execution.setTransientVariableLocal(key, map.get(key));
@ -91,7 +91,7 @@ public class VariableSetterListener implements ExecutionListener, TaskListener{
if(variables!=null){ if(variables!=null){
String variablesText =variables.getExpressionText(); String variablesText =variables.getExpressionText();
if(StringUtils.hasText(variablesText)){ if(StringUtils.hasText(variablesText)){
Map<String,Object> map =JacksonObjectMapper.getDefaultObjectMapper().readValue(variablesText, new TypeReference<Map<String,Object>>(){}); Map<String,Object> map =ObjectMapper4Json.getMapper().readValue(variablesText, new TypeReference<Map<String,Object>>(){});
if(map!=null && map.size()>0){ if(map!=null && map.size()>0){
for(String key : map.keySet()){ for(String key : map.keySet()){
delegateTask.setVariable(key, map.get(key)); delegateTask.setVariable(key, map.get(key));
@ -103,7 +103,7 @@ public class VariableSetterListener implements ExecutionListener, TaskListener{
if(variablesLocal!=null){ if(variablesLocal!=null){
String variablesLocalText =variablesLocal.getExpressionText(); String variablesLocalText =variablesLocal.getExpressionText();
if(StringUtils.hasText(variablesLocalText)){ if(StringUtils.hasText(variablesLocalText)){
Map<String,Object> map =JacksonObjectMapper.getDefaultObjectMapper().readValue(variablesLocalText, new TypeReference<Map<String,Object>>(){}); Map<String,Object> map =ObjectMapper4Json.getMapper().readValue(variablesLocalText, new TypeReference<Map<String,Object>>(){});
if(map!=null && map.size()>0){ if(map!=null && map.size()>0){
for(String key : map.keySet()){ for(String key : map.keySet()){
delegateTask.setVariableLocal(key, map.get(key)); delegateTask.setVariableLocal(key, map.get(key));
@ -115,7 +115,7 @@ public class VariableSetterListener implements ExecutionListener, TaskListener{
if(transientVariables!=null){ if(transientVariables!=null){
String transientVariablesText =transientVariables.getExpressionText(); String transientVariablesText =transientVariables.getExpressionText();
if(StringUtils.hasText(transientVariablesText)){ if(StringUtils.hasText(transientVariablesText)){
Map<String,Object> map =JacksonObjectMapper.getDefaultObjectMapper().readValue(transientVariablesText, new TypeReference<Map<String,Object>>(){}); Map<String,Object> map =ObjectMapper4Json.getMapper().readValue(transientVariablesText, new TypeReference<Map<String,Object>>(){});
if(map!=null && map.size()>0){ if(map!=null && map.size()>0){
for(String key : map.keySet()){ for(String key : map.keySet()){
delegateTask.setTransientVariable(key, map.get(key)); delegateTask.setTransientVariable(key, map.get(key));
@ -127,7 +127,7 @@ public class VariableSetterListener implements ExecutionListener, TaskListener{
if(transientVariablesLocal!=null){ if(transientVariablesLocal!=null){
String transientVariablesLocalText =transientVariablesLocal.getExpressionText(); String transientVariablesLocalText =transientVariablesLocal.getExpressionText();
if(StringUtils.hasText(transientVariablesLocalText)){ if(StringUtils.hasText(transientVariablesLocalText)){
Map<String,Object> map =JacksonObjectMapper.getDefaultObjectMapper().readValue(transientVariablesLocalText, new TypeReference<Map<String,Object>>(){}); Map<String,Object> map =ObjectMapper4Json.getMapper().readValue(transientVariablesLocalText, new TypeReference<Map<String,Object>>(){});
if(map!=null && map.size()>0){ if(map!=null && map.size()>0){
for(String key : map.keySet()){ for(String key : map.keySet()){
delegateTask.setTransientVariableLocal(key, map.get(key)); delegateTask.setTransientVariableLocal(key, map.get(key));

14
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/extension/listener/task/SendMailListener.java

@ -1,5 +1,8 @@
package io.sc.platform.flowable.extension.listener.task; package io.sc.platform.flowable.extension.listener.task;
import io.sc.platform.communication.service.MailSenderService;
import io.sc.platform.system.user.jpa.entity.UserEntity;
import io.sc.platform.system.user.service.UserService;
import org.flowable.common.engine.api.delegate.Expression; import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.engine.delegate.TaskListener; import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask; import org.flowable.task.service.delegate.DelegateTask;
@ -9,9 +12,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.wsp.framework.communication.mail.service.MailSenderService;
import org.wsp.framework.system.user.entity.User;
import org.wsp.framework.system.user.service.UserService;
@Component("flowableSendMailListener") @Component("flowableSendMailListener")
public class SendMailListener implements TaskListener{ public class SendMailListener implements TaskListener{
@ -42,10 +42,10 @@ public class SendMailListener implements TaskListener{
String assignee =delegateTask.getAssignee(); String assignee =delegateTask.getAssignee();
if(StringUtils.hasText(assignee)) { if(StringUtils.hasText(assignee)) {
User user =userService.getRepository().findByLoginName(assignee); UserEntity userEntity =userService.getRepository().findByLoginName(assignee);
if(user!=null) { if(userEntity!=null) {
String userName =user.getNickName(); String userName =userEntity.getUserName();
String to =user.getEmail(); String to =userEntity.getEmail();
if(StringUtils.hasText(to)) { if(StringUtils.hasText(to)) {
mailSenderService.sendSimpleMessage( mailSenderService.sendSimpleMessage(
"wangshaoping@gbicc.net", "wangshaoping@gbicc.net",

24
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/jpa/entity/Agent.java

@ -17,11 +17,9 @@ import org.hibernate.annotations.GenericGenerator;
/** /**
* 代理人实体类 * 代理人实体类
* @author wangshaoping
*
*/ */
@Entity @Entity
@Table(name="FR_SYS_AGENT") @Table(name="SYS_AGENT")
public class Agent extends AuditorEntity implements Serializable{ public class Agent extends AuditorEntity implements Serializable{
private static final long serialVersionUID = 2228732422179849265L; private static final long serialVersionUID = 2228732422179849265L;
@ -29,50 +27,50 @@ public class Agent extends AuditorEntity implements Serializable{
@Id @Id
@GeneratedValue(generator = "system-uuid") @GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid2") @GenericGenerator(name = "system-uuid", strategy = "uuid2")
@Column(name="FD_ID") @Column(name="_ID")
@Size(max=36) @Size(max=36)
private String id; private String id;
//被代理人登录名 //被代理人登录名
@Column(name="FD_LOGINNAME") @Column(name="_LOGINNAME")
@Size(max=255) @Size(max=255)
private String loginName; private String loginName;
//被代理人用户名 //被代理人用户名
@Column(name="FD_USERNAME") @Column(name="_USERNAME")
@Size(max=255) @Size(max=255)
private String userName; private String userName;
//代理人登录名 //代理人登录名
@Column(name="FD_AGENT_LOGINNAME") @Column(name="_AGENT_LOGINNAME")
@Size(max=255) @Size(max=255)
private String agentLoginName; private String agentLoginName;
//代理人用户名 //代理人用户名
@Column(name="FD_AGENT_USERNAME") @Column(name="_AGENT_USERNAME")
@Size(max=255) @Size(max=255)
private String agentUserName; private String agentUserName;
//开始日期 //开始日期
@Column(name="FD_START_DATE") @Column(name="_START_DATE")
private Date startDate; private Date startDate;
//结束日期 //结束日期
@Column(name="FD_END_DATE") @Column(name="_END_DATE")
private Date endDate; private Date endDate;
//代理原因 //代理原因
@Column(name="FD_REASONS") @Column(name="_REASONS")
@Size(max=255) @Size(max=255)
private String reasons; private String reasons;
//是否生效 //是否生效
@Column(name="FD_EFFECTIVE") @Column(name="_EFFECTIVE")
@Convert(converter= NumericBooleanConverter.class) @Convert(converter= NumericBooleanConverter.class)
private Boolean effective; private Boolean effective;
//意见(主要用于记录审批意见) //意见(主要用于记录审批意见)
@Column(name="FD_COMMENTS") @Column(name="_COMMENTS")
@Size(max=1024) @Size(max=1024)
private String comments; private String comments;

26
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/jpa/entity/ProcessEntity.java

@ -12,18 +12,16 @@ import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import io.sc.platform.flowable.support.ProcessStatus;
import io.sc.platform.orm.converter.NumericBooleanConverter; import io.sc.platform.orm.converter.NumericBooleanConverter;
import io.sc.platform.orm.entity.AuditorEntity; import io.sc.platform.orm.entity.AuditorEntity;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import org.wsp.framework.flowable.support.ProcessStatus;
/** /**
* 流程定义实体类 * 流程定义实体类
* @author wangshaoping
*
*/ */
@Entity @Entity
@Table(name="FR_SYS_PROCESS") @Table(name="SYS_PROCESS")
public class ProcessEntity extends AuditorEntity implements Serializable{ public class ProcessEntity extends AuditorEntity implements Serializable{
private static final long serialVersionUID = 2056614495312244260L; private static final long serialVersionUID = 2056614495312244260L;
@ -31,50 +29,50 @@ public class ProcessEntity extends AuditorEntity implements Serializable{
@Id @Id
@GeneratedValue(generator = "system-uuid") @GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid2") @GenericGenerator(name = "system-uuid", strategy = "uuid2")
@Column(name="FD_ID") @Column(name="_ID")
@Size(max=36) @Size(max=36)
private String id; private String id;
//流程分类 //流程分类
@Column(name="FD_CATEGORY") @Column(name="_CATEGORY")
@Size(max=255) @Size(max=255)
private String category; private String category;
//代码 //代码
@Column(name="FD_KEY") @Column(name="_KEY")
@Size(max=255) @Size(max=255)
private String key; private String key;
//名称 //名称
@Column(name="FD_NAME") @Column(name="_NAME")
@Size(max=255) @Size(max=255)
private String name; private String name;
//描述 //描述
@Column(name="FD_DESCRIPTION") @Column(name="_DESCRIPTION")
@Size(max=255) @Size(max=255)
private String description; private String description;
//流程引擎中的发布ID //流程引擎中的发布ID
@Column(name="FD_DEPLOYED_ID") @Column(name="_DEPLOYED_ID")
@Size(max=255) @Size(max=255)
private String deployedId; private String deployedId;
//版本 //版本
@Column(name="FD_VERSION") @Column(name="_VERSION")
private Integer version; private Integer version;
//Flowable 流程定义 xml //Flowable 流程定义 xml
@Column(name="FD_XML") @Column(name="_XML")
private String xml; private String xml;
//流程定义状态 //流程定义状态
@Column(name="FD_STATUS", length=10) @Column(name="_STATUS", length=10)
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
private ProcessStatus status; private ProcessStatus status;
//是否可以自行领取任务 //是否可以自行领取任务
@Column(name="FD_CAN_CLAIM_TASK") @Column(name="_CAN_CLAIM_TASK")
@Convert(converter= NumericBooleanConverter.class) @Convert(converter= NumericBooleanConverter.class)
private Boolean canClaimTask; private Boolean canClaimTask;

3
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/jpa/repository/ProcessEntityRepository.java

@ -1,6 +1,7 @@
package io.sc.platform.flowable.jpa.repository; package io.sc.platform.flowable.jpa.repository;
import io.sc.platform.flowable.jpa.entity.ProcessEntity; import io.sc.platform.flowable.jpa.entity.ProcessEntity;
import io.sc.platform.flowable.support.ProcessStatus;
import io.sc.platform.orm.repository.DaoRepository; import io.sc.platform.orm.repository.DaoRepository;
import java.util.List; import java.util.List;
@ -20,7 +21,7 @@ public interface ProcessEntityRepository extends DaoRepository<ProcessEntity,Str
* @param status 流程状态 * @param status 流程状态
* @return 流程定义实体 * @return 流程定义实体
*/ */
public ProcessEntity findByCategoryAndStatus(String category,ProcessStatus status); public ProcessEntity findByCategoryAndStatus(String category, ProcessStatus status);
/** /**
* 通过流程发布ID获取流程定义实体 * 通过流程发布ID获取流程定义实体

10
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/service/impl/ProcessEntityServiceImpl.java

@ -2,8 +2,10 @@ package io.sc.platform.flowable.service.impl;
import java.util.List; import java.util.List;
import io.sc.platform.core.Environment;
import io.sc.platform.flowable.jpa.entity.ProcessEntity; import io.sc.platform.flowable.jpa.entity.ProcessEntity;
import io.sc.platform.flowable.jpa.repository.ProcessEntityRepository; import io.sc.platform.flowable.jpa.repository.ProcessEntityRepository;
import io.sc.platform.flowable.service.ProcessEntityService;
import io.sc.platform.flowable.support.ProcessStatus; import io.sc.platform.flowable.support.ProcessStatus;
import io.sc.platform.flowable.util.BpmnConverterUtil; import io.sc.platform.flowable.util.BpmnConverterUtil;
import io.sc.platform.orm.service.impl.DaoServiceImpl; import io.sc.platform.orm.service.impl.DaoServiceImpl;
@ -20,7 +22,7 @@ import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@Service @Service
public class ProcessEntityServiceImpl extends DaoServiceImpl<ProcessEntity, String, ProcessEntityRepository> implements ProcessEntityService{ public class ProcessEntityServiceImpl extends DaoServiceImpl<ProcessEntity, String, ProcessEntityRepository> implements ProcessEntityService {
@Autowired private RepositoryService repositoryService; @Autowired private RepositoryService repositoryService;
@ -34,7 +36,7 @@ public class ProcessEntityServiceImpl extends DaoServiceImpl<ProcessEntity, Stri
} }
@Override @Override
public ProcessEntity findByUniqueKey(ProcessEntity entity) throws Exception { public ProcessEntity findByUniqueKey(ProcessEntity entity) {
if(entity.getVersion()==null){ if(entity.getVersion()==null){
return repository.findByCategoryAndKeyAndVersionIsNull(entity.getCategory(), entity.getKey()); return repository.findByCategoryAndKeyAndVersionIsNull(entity.getCategory(), entity.getKey());
}else{ }else{
@ -50,7 +52,7 @@ public class ProcessEntityServiceImpl extends DaoServiceImpl<ProcessEntity, Stri
//如果流程定义 xml 文件为空,产生一个示例流程定义 xml //如果流程定义 xml 文件为空,产生一个示例流程定义 xml
if(!StringUtils.hasText(entity.getXml())){ if(!StringUtils.hasText(entity.getXml())){
Resource rs =getSampleResource(entity.getCategory()); Resource rs =getSampleResource(entity.getCategory());
String xml =IOUtils.toString(rs.getInputStream(),Environment.DEFAULT_ENCODING); String xml =IOUtils.toString(rs.getInputStream(), Environment.DEFAULT_CHARSET_NAME);
entity.setXml(xml); entity.setXml(xml);
} }
//解析流程定义 xml,并根据新建时填写的流程代码和名称设置流程定义 xml 文件中的相应属性 //解析流程定义 xml,并根据新建时填写的流程代码和名称设置流程定义 xml 文件中的相应属性
@ -114,7 +116,7 @@ public class ProcessEntityServiceImpl extends DaoServiceImpl<ProcessEntity, Stri
@Override @Override
public void deploy(String id) throws Exception { public void deploy(String id) throws Exception {
ProcessEntity entity =repository.findOne(id); ProcessEntity entity =repository.getOne(id);
if(entity!=null){ if(entity!=null){
Deployment deployment =repositoryService.createDeployment() Deployment deployment =repositoryService.createDeployment()
.addString(entity.getName() + ".bpmn", entity.getXml()) .addString(entity.getName() + ".bpmn", entity.getXml())

22
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/support/BpmnModelWrapper.java

@ -1,13 +1,18 @@
package io.sc.platform.flowable.support; package io.sc.platform.flowable.support;
import java.io.IOException;
import java.util.Date; import java.util.Date;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.BpmnModel;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
@JsonSerialize(using=BpmnModelWrapperSerializer.class) @JsonSerialize(using=BpmnModelWrapperSerializer.class)
public class BpmnModelWrapper { public class BpmnModelWrapper extends JsonSerializer<BpmnModelWrapper> {
private String modelId; private String modelId;
private String name; private String name;
private String key; private String key;
@ -59,4 +64,19 @@ public class BpmnModelWrapper {
public void setModel(BpmnModel model) { public void setModel(BpmnModel model) {
this.model = model; this.model = model;
} }
@Override
public void serialize(BpmnModelWrapper value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
gen.writeStartObject();
gen.writeObjectField("modelId", value.getModelId());
gen.writeObjectField("name", value.getName());
gen.writeObjectField("key", value.getKey());
gen.writeObjectField("description", value.getDescription());
gen.writeObjectField("lastUpdated", value.getLastUpdated());
gen.writeObjectField("lastUpdatedBy", value.getLastUpdatedBy());
gen.writeObjectField("model", jsonConverter.convertToJson(value.getModel()));
gen.writeEndObject();
}
} }

9
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/support/CompleteTaskResponse.java

@ -1,17 +1,14 @@
package io.sc.platform.flowable.support; package io.sc.platform.flowable.support;
import java.util.ArrayList; import com.fasterxml.jackson.core.type.TypeReference;
import java.util.List;
import io.sc.platform.core.util.ObjectMapper4Json; import io.sc.platform.core.util.ObjectMapper4Json;
import org.wsp.framework.core.util.JacksonObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference; import java.util.ArrayList;
import java.util.List;
/** /**
* 完成任务响应 * 完成任务响应
* 当客户端提交并完成任务时,服务器进行处理并返回该类的对象 * 当客户端提交并完成任务时,服务器进行处理并返回该类的对象
* @author wangshaoping
* *
*/ */
public class CompleteTaskResponse { public class CompleteTaskResponse {

5
io.sc.platform.lcdp.frontend/package.json

@ -79,14 +79,13 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.12", "platform-core": "8.1.14",
"quasar": "2.13.0", "quasar": "2.13.0",
"react-dnd-html5-backend": "16.0.1",
"tailwindcss": "3.3.5", "tailwindcss": "3.3.5",
"vue": "3.3.7", "vue": "3.3.7",
"vue-dompurify-html": "4.1.4", "vue-dompurify-html": "4.1.4",
"vue-i18n": "9.6.0", "vue-i18n": "9.6.0",
"vue-router": "4.2.5", "vue-router": "4.2.5",
"vue3-dnd": "2.0.2" "platform-components": "8.1.2"
} }
} }

9
io.sc.platform.lcdp.frontend/src/App.vue

@ -1,10 +1,5 @@
<template> <template>
<DndProvider :backend="HTML5Backend"> <w-platform-page></w-platform-page>
<w-platform-page></w-platform-page>
</DndProvider>
</template> </template>
<script setup lang="ts"> <script setup lang="ts"></script>
import { DndProvider } from 'vue3-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
</script>

4
io.sc.platform.lcdp.frontend/webpack.config.mf.cjs

@ -2,7 +2,7 @@
* webpack module federation 配置 * webpack module federation 配置
*/ */
const fs = require('fs'); // 文件读取 const fs = require('fs'); // 文件读取
const Json5 =require('json5'); // json5 const Json5 =require('json5'); // json5
const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件
const packageJson = require('./package.json'); // package.json const packageJson = require('./package.json'); // package.json
const projectName =packageJson.name; // 项目名称 const projectName =packageJson.name; // 项目名称
@ -42,12 +42,10 @@ module.exports = {
'pinia': { requiredVersion: deps['pinia'], singleton: true }, 'pinia': { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true }, 'quasar': { requiredVersion: deps['quasar'], singleton: true },
'react-dnd-html5-backend':{ requiredVersion: deps['react-dnd-html5-backend'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true }, 'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'vue3-dnd':{ requiredVersion: deps['vue3-dnd'], singleton: true },
} }
}), }),
] ]

5
io.sc.platform.mvc.frontend/package.json

@ -79,14 +79,13 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.12", "platform-core": "8.1.14",
"quasar": "2.13.0", "quasar": "2.13.0",
"react-dnd-html5-backend": "16.0.1",
"tailwindcss": "3.3.5", "tailwindcss": "3.3.5",
"vue": "3.3.7", "vue": "3.3.7",
"vue-dompurify-html": "4.1.4", "vue-dompurify-html": "4.1.4",
"vue-i18n": "9.6.0", "vue-i18n": "9.6.0",
"vue-router": "4.2.5", "vue-router": "4.2.5",
"vue3-dnd": "2.0.2" "platform-components": "8.1.2"
} }
} }

9
io.sc.platform.mvc.frontend/src/App.vue

@ -1,10 +1,5 @@
<template> <template>
<DndProvider :backend="HTML5Backend"> <w-platform-page></w-platform-page>
<w-platform-page></w-platform-page>
</DndProvider>
</template> </template>
<script setup lang="ts"> <script setup lang="ts"></script>
import { DndProvider } from 'vue3-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
</script>

4
io.sc.platform.mvc.frontend/webpack.config.mf.cjs

@ -2,7 +2,7 @@
* webpack module federation 配置 * webpack module federation 配置
*/ */
const fs = require('fs'); // 文件读取 const fs = require('fs'); // 文件读取
const Json5 =require('json5'); // json5 const Json5 =require('json5'); // json5
const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件
const packageJson = require('./package.json'); // package.json const packageJson = require('./package.json'); // package.json
const projectName =packageJson.name; // 项目名称 const projectName =packageJson.name; // 项目名称
@ -42,12 +42,10 @@ module.exports = {
'pinia': { requiredVersion: deps['pinia'], singleton: true }, 'pinia': { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true }, 'quasar': { requiredVersion: deps['quasar'], singleton: true },
'react-dnd-html5-backend':{ requiredVersion: deps['react-dnd-html5-backend'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true }, 'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'vue3-dnd':{ requiredVersion: deps['vue3-dnd'], singleton: true },
} }
}), }),
] ]

10
io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/controller/I18nMessageController.java

@ -3,10 +3,7 @@ package io.sc.platform.mvc.controller;
import io.sc.platform.core.enums.Language; import io.sc.platform.core.enums.Language;
import io.sc.platform.core.service.MessageSourceService; import io.sc.platform.core.service.MessageSourceService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map; import java.util.Map;
@ -19,4 +16,9 @@ public class I18nMessageController {
public Map<String,String> getI18nMessages(@PathVariable(name = "lang",required = false) Language language) throws Exception{ public Map<String,String> getI18nMessages(@PathVariable(name = "lang",required = false) Language language) throws Exception{
return messageSourceService.getMessages(language==null? Language.getDefault():language); return messageSourceService.getMessages(language==null? Language.getDefault():language);
} }
@GetMapping("getI18nMessagesByKeys")
public Map<Language, Map<String, String>> getI18nMessages(@RequestParam(name="key",required=false) String[] keys) throws Exception{
return messageSourceService.getMessages(keys);
}
} }

3
io.sc.platform.mvc/src/main/resources/META-INF/platform/plugins/security.json

@ -2,6 +2,7 @@
"permitPatterns":[ "permitPatterns":[
"/api/mvc/frontend/regist", "/api/mvc/frontend/regist",
"/api/mvc/i18n/getI18nMessages", "/api/mvc/i18n/getI18nMessages",
"/api/mvc/i18n/getI18nMessages/**/*" "/api/mvc/i18n/getI18nMessages/**/*",
"/api/mvc/i18n/getI18nMessagesByKeys"
] ]
} }

5
io.sc.platform.security.frontend/package.json

@ -79,14 +79,13 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.12", "platform-core": "8.1.14",
"quasar": "2.13.0", "quasar": "2.13.0",
"react-dnd-html5-backend": "16.0.1",
"tailwindcss": "3.3.5", "tailwindcss": "3.3.5",
"vue": "3.3.7", "vue": "3.3.7",
"vue-dompurify-html": "4.1.4", "vue-dompurify-html": "4.1.4",
"vue-i18n": "9.6.0", "vue-i18n": "9.6.0",
"vue-router": "4.2.5", "vue-router": "4.2.5",
"vue3-dnd": "2.0.2" "platform-components": "8.1.2"
} }
} }

51
io.sc.platform.security.frontend/src/plugin.ts

@ -17,29 +17,34 @@ class Initializer {
gc.webContextPath = window['webContextPath']; gc.webContextPath = window['webContextPath'];
gc.loginError = window['loginError'] === 'true' ? true : false; gc.loginError = window['loginError'] === 'true' ? true : false;
for (const key in gc.i18nMessages['en']) { fetch(window['webContextPath'] + 'api/mvc/i18n/getI18nMessagesByKeys?key=application.title&key=application.copyright')
en[key] = gc.i18nMessages['en'][key]; .then((response) => response.json())
} .then((data) => {
for (const key in gc.i18nMessages['zh_CN']) { const i18nMessages = data.data;
zh_CN[key] = gc.i18nMessages['zh_CN'][key]; for (const key in i18nMessages['en']) {
} en[key] = i18nMessages['en'][key];
for (const key in gc.i18nMessages['tw_CN']) { }
tw_CN[key] = gc.i18nMessages['tw_CN'][key]; for (const key in i18nMessages['zh_CN']) {
} zh_CN[key] = i18nMessages['zh_CN'][key];
i18n = createI18n({ }
legacy: false, for (const key in i18nMessages['tw_CN']) {
availableLocales: gc.setting.i18n.availableLocales, tw_CN[key] = i18nMessages['tw_CN'][key];
locale: gc.setting.i18n.locale, }
fallbackLocale: gc.setting.i18n.fallbackLocale, i18n = createI18n({
missingWarn: gc.setting.i18n.missingWarn, legacy: false,
fallbackWarn: gc.setting.i18n.fallbackWarn, availableLocales: gc.setting.i18n.availableLocales,
messages: { locale: gc.setting.i18n.locale,
en: en, fallbackLocale: gc.setting.i18n.fallbackLocale,
zh_CN: zh_CN, missingWarn: gc.setting.i18n.missingWarn,
tw_CN: tw_CN, fallbackWarn: gc.setting.i18n.fallbackWarn,
}, messages: {
}); en: en,
callback(); zh_CN: zh_CN,
tw_CN: tw_CN,
},
});
callback();
});
}); });
} }
} }

4
io.sc.platform.security/src/main/java/io/sc/platform/security/service/impl/UserDetailsServiceImpl.java

@ -73,7 +73,7 @@ public class UserDetailsServiceImpl implements UserDetailsService{
); );
user.setUserId(u.getId()); user.setUserId(u.getId());
user.setLoginName(u.getLoginName()); user.setLoginName(u.getLoginName());
user.setNickName(u.getNickName()); user.setUserName(u.getUserName());
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
//设置默认角色 //设置默认角色
@ -213,7 +213,7 @@ public class UserDetailsServiceImpl implements UserDetailsService{
sb.append("{").append("\n"); sb.append("{").append("\n");
sb.append(" ").append("id : ").append(user.getUserId()).append(",\n"); sb.append(" ").append("id : ").append(user.getUserId()).append(",\n");
sb.append(" ").append("loginName : ").append(user.getLoginName()).append(",\n"); sb.append(" ").append("loginName : ").append(user.getLoginName()).append(",\n");
sb.append(" ").append("nickName : ").append(user.getNickName()).append(",\n"); sb.append(" ").append("userName : ").append(user.getUserName()).append(",\n");
sb.append("\n"); sb.append("\n");
sb.append(" ").append("enabled : ").append(user.isEnabled()).append(",\n"); sb.append(" ").append("enabled : ").append(user.isEnabled()).append(",\n");
sb.append(" ").append("accountNonExpired : ").append(user.isAccountNonExpired()).append(",\n"); sb.append(" ").append("accountNonExpired : ").append(user.isAccountNonExpired()).append(",\n");

12
io.sc.platform.security/src/main/java/io/sc/platform/security/service/support/User.java

@ -10,7 +10,7 @@ import java.sql.SQLException;
public class User { public class User {
private String id; private String id;
private String loginName; private String loginName;
private String nickName; private String userName;
private String password; private String password;
private String description; private String description;
private Boolean enable; private Boolean enable;
@ -53,7 +53,7 @@ public class User {
User user = new User(); User user = new User();
user.setId(rs.getString("_ID")); user.setId(rs.getString("_ID"));
user.setLoginName(rs.getString("_LOGINNAME")); user.setLoginName(rs.getString("_LOGINNAME"));
user.setNickName(rs.getString("_USERNAME")); user.setUserName(rs.getString("_USERNAME"));
user.setPassword(rs.getString("_PASSWORD")); user.setPassword(rs.getString("_PASSWORD"));
user.setEnable(1 == rs.getInt("_ENABLE") ? true : false); user.setEnable(1 == rs.getInt("_ENABLE") ? true : false);
user.setAccountExpired(1 == rs.getInt("_IS_ACCOUNT_EXPIRED") ? true : false); user.setAccountExpired(1 == rs.getInt("_IS_ACCOUNT_EXPIRED") ? true : false);
@ -85,12 +85,12 @@ public class User {
this.loginName = loginName; this.loginName = loginName;
} }
public String getNickName() { public String getUserName() {
return nickName; return userName;
} }
public void setNickName(String nickName) { public void setUserName(String userName) {
this.nickName = nickName; this.userName = userName;
} }
public String getPassword() { public String getPassword() {

2
io.sc.platform.security/src/main/java/io/sc/platform/security/support/SecurityClaimNames.java

@ -4,7 +4,7 @@ public class SecurityClaimNames {
public static final class User { public static final class User {
public static final String USER_ID = "userId"; //用户ID public static final String USER_ID = "userId"; //用户ID
public static final String LOGIN_NAME = "loginName"; //用户登录名 public static final String LOGIN_NAME = "loginName"; //用户登录名
public static final String NICK_NAME = "userName"; //用户别名 public static final String USER_NAME = "userName"; //用户别名
public static final String DEFAULT_APP_ID = "defaultAppId"; //默认应用ID public static final String DEFAULT_APP_ID = "defaultAppId"; //默认应用ID
public static final String DEFAULT_APP_CODE = "defaultAppCode"; //默认应用代码 public static final String DEFAULT_APP_CODE = "defaultAppCode"; //默认应用代码

12
io.sc.platform.security/src/main/java/io/sc/platform/security/support/SecurityUser.java

@ -25,7 +25,7 @@ public class SecurityUser extends User{
//扩展属性 //扩展属性
private String userId; //用户ID private String userId; //用户ID
private String loginName; //用户登录名 private String loginName; //用户登录名
private String nickName; //用户 private String userName; //用户名
private String defaultAppId; //默认应用ID private String defaultAppId; //默认应用ID
private String defaultAppCode; //默认应用代码 private String defaultAppCode; //默认应用代码
@ -70,11 +70,11 @@ public class SecurityUser extends User{
public void setLoginName(String loginName) { public void setLoginName(String loginName) {
this.loginName = loginName; this.loginName = loginName;
} }
public String getNickName() { public String getUserName() {
return nickName; return userName;
} }
public void setNickName(String nickName) { public void setUserName(String userName) {
this.nickName = nickName; this.userName = userName;
} }
public String getDefaultAppId() { public String getDefaultAppId() {
return defaultAppId; return defaultAppId;
@ -184,7 +184,7 @@ public class SecurityUser extends User{
return "SecurityUser{" + return "SecurityUser{" +
"userId='" + userId + '\'' + "userId='" + userId + '\'' +
", loginName='" + loginName + '\'' + ", loginName='" + loginName + '\'' +
", nickName='" + nickName + '\'' + ", userName='" + userName + '\'' +
", defaultAppId='" + this.defaultAppId + '\'' + ", defaultAppId='" + this.defaultAppId + '\'' +
", defaultAppCode='" + this.defaultAppCode + '\'' + ", defaultAppCode='" + this.defaultAppCode + '\'' +
", defaultAppName='" + this.defaultAppName + '\'' + ", defaultAppName='" + this.defaultAppName + '\'' +

8
io.sc.platform.security/src/main/java/io/sc/platform/security/util/SecurityUtil.java

@ -29,7 +29,7 @@ public class SecurityUtil {
if(user!=null){ if(user!=null){
put(map,SecurityClaimNames.User.USER_ID,user.getUserId()); //用户ID put(map,SecurityClaimNames.User.USER_ID,user.getUserId()); //用户ID
put(map,SecurityClaimNames.User.LOGIN_NAME,user.getLoginName()); //用户登录名 put(map,SecurityClaimNames.User.LOGIN_NAME,user.getLoginName()); //用户登录名
put(map,SecurityClaimNames.User.NICK_NAME,user.getNickName()); //用户 put(map,SecurityClaimNames.User.USER_NAME,user.getUserName()); //用户名
put(map,SecurityClaimNames.User.DEFAULT_APP_ID,user.getDefaultAppId()); //默认应用ID put(map,SecurityClaimNames.User.DEFAULT_APP_ID,user.getDefaultAppId()); //默认应用ID
put(map,SecurityClaimNames.User.DEFAULT_APP_CODE,user.getDefaultAppCode()); //默认应用代码 put(map,SecurityClaimNames.User.DEFAULT_APP_CODE,user.getDefaultAppCode()); //默认应用代码
@ -65,7 +65,7 @@ public class SecurityUtil {
SecurityUser user =new SecurityUser(userId,"******",authorities); SecurityUser user =new SecurityUser(userId,"******",authorities);
user.setUserId(StringUtil.toString(map.get(SecurityClaimNames.User.USER_ID))); user.setUserId(StringUtil.toString(map.get(SecurityClaimNames.User.USER_ID)));
user.setLoginName(StringUtil.toString(map.get(SecurityClaimNames.User.LOGIN_NAME))); user.setLoginName(StringUtil.toString(map.get(SecurityClaimNames.User.LOGIN_NAME)));
user.setNickName(StringUtil.toString(map.get(SecurityClaimNames.User.NICK_NAME))); user.setUserName(StringUtil.toString(map.get(SecurityClaimNames.User.USER_NAME)));
user.setDefaultAppId(StringUtil.toString(map.get(SecurityClaimNames.User.DEFAULT_APP_ID))); user.setDefaultAppId(StringUtil.toString(map.get(SecurityClaimNames.User.DEFAULT_APP_ID)));
user.setDefaultAppCode(StringUtil.toString(map.get(SecurityClaimNames.User.DEFAULT_APP_CODE))); user.setDefaultAppCode(StringUtil.toString(map.get(SecurityClaimNames.User.DEFAULT_APP_CODE)));
@ -125,10 +125,10 @@ public class SecurityUtil {
* 获取当前登录用户的用户名(通常是中文名) * 获取当前登录用户的用户名(通常是中文名)
* @return 当前登录用户的用户名(通常是中文名) * @return 当前登录用户的用户名(通常是中文名)
*/ */
public static String getNickName(){ public static String getUserName(){
SecurityUser user =getSecurityUser(); SecurityUser user =getSecurityUser();
if(user!=null){ if(user!=null){
return user.getNickName(); return user.getUserName();
} }
return null; return null;
} }

11
io.sc.platform.security/src/main/resources/META-INF/platform/plugins/application-properties.json

@ -0,0 +1,11 @@
[
{
"module" : "io.sc.platform.security",
"order" : 153,
"description" : "",
"properties": [
"# - io.sc.platform.security",
"application.default-password = password"
]
}
]

5
io.sc.platform.system.frontend/package.json

@ -79,14 +79,13 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.12", "platform-core": "8.1.14",
"quasar": "2.13.0", "quasar": "2.13.0",
"react-dnd-html5-backend": "16.0.1",
"tailwindcss": "3.3.5", "tailwindcss": "3.3.5",
"vue": "3.3.7", "vue": "3.3.7",
"vue-dompurify-html": "4.1.4", "vue-dompurify-html": "4.1.4",
"vue-i18n": "9.6.0", "vue-i18n": "9.6.0",
"vue-router": "4.2.5", "vue-router": "4.2.5",
"vue3-dnd": "2.0.2" "platform-components": "8.1.2"
} }
} }

2
io.sc.platform.system.frontend/webpack.config.mf.cjs

@ -42,12 +42,10 @@ module.exports = {
'pinia': { requiredVersion: deps['pinia'], singleton: true }, 'pinia': { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true }, 'quasar': { requiredVersion: deps['quasar'], singleton: true },
'react-dnd-html5-backend':{ requiredVersion: deps['react-dnd-html5-backend'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true }, 'vue': { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'vue3-dnd':{ requiredVersion: deps['vue3-dnd'], singleton: true },
} }
}), }),
] ]

23
io.sc.platform.system/src/main/java/io/sc/platform/system/autoconfigure/MessageSourceAutoConfiguration.java

@ -2,6 +2,7 @@ package io.sc.platform.system.autoconfigure;
import io.sc.platform.core.i18n.MessageSourceBaseName; import io.sc.platform.core.i18n.MessageSourceBaseName;
import io.sc.platform.core.i18n.PlatformResourceBundleMessageSource; import io.sc.platform.core.i18n.PlatformResourceBundleMessageSource;
import io.sc.platform.core.service.RuntimeService;
import io.sc.platform.system.autoconfigure.support.CompositeMessageSource; import io.sc.platform.system.autoconfigure.support.CompositeMessageSource;
import io.sc.platform.system.autoconfigure.support.DatabaseMessageSource; import io.sc.platform.system.autoconfigure.support.DatabaseMessageSource;
import io.sc.platform.system.i18n.jpa.repository.I18nRepository; import io.sc.platform.system.i18n.jpa.repository.I18nRepository;
@ -12,6 +13,7 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.context.MessageSourceProperties; import org.springframework.boot.autoconfigure.context.MessageSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -30,6 +32,7 @@ import java.time.Duration;
@AutoConfigureBefore(io.sc.platform.core.autoconfigure.MessageSourceAutoConfiguration.class) @AutoConfigureBefore(io.sc.platform.core.autoconfigure.MessageSourceAutoConfiguration.class)
@EnableConfigurationProperties @EnableConfigurationProperties
public class MessageSourceAutoConfiguration { public class MessageSourceAutoConfiguration {
@Autowired private RuntimeService runtimeService;
@Autowired private I18nRepository repository; @Autowired private I18nRepository repository;
@Bean @Bean
@ -41,6 +44,17 @@ public class MessageSourceAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public MessageSource messageSource(MessageSourceProperties messageSourceProperties){ public MessageSource messageSource(MessageSourceProperties messageSourceProperties){
//组合消息源(先从数据库消息源中查找,如果不存在,再从资源包消息源中查找)
CompositeMessageSource compositeMessageSource =new CompositeMessageSource();
//数据库消息源
if(runtimeService.isReady()) {
DatabaseMessageSource databaseMessageSource = new DatabaseMessageSource(repository);
databaseMessageSource.reload();
compositeMessageSource.addMessageSource(databaseMessageSource);
}
// 资源包消息源
PlatformResourceBundleMessageSource resourceBundleMessageSource = new PlatformResourceBundleMessageSource(); PlatformResourceBundleMessageSource resourceBundleMessageSource = new PlatformResourceBundleMessageSource();
resourceBundleMessageSource.setBasenames(MessageSourceBaseName.getBaseNames(messageSourceProperties.getBasename())); resourceBundleMessageSource.setBasenames(MessageSourceBaseName.getBaseNames(messageSourceProperties.getBasename()));
if (messageSourceProperties.getEncoding() != null) { if (messageSourceProperties.getEncoding() != null) {
@ -53,15 +67,8 @@ public class MessageSourceAutoConfiguration {
if (cacheDuration != null) { if (cacheDuration != null) {
resourceBundleMessageSource.setCacheMillis(cacheDuration.toMillis()); resourceBundleMessageSource.setCacheMillis(cacheDuration.toMillis());
} }
//数据库消息源
DatabaseMessageSource databaseMessageSource =new DatabaseMessageSource(repository);
databaseMessageSource.reload();
//组合消息源(先从数据库消息源中查找,如果不存在,再从资源包消息源中查找)
CompositeMessageSource compositeMessageSource =new CompositeMessageSource();
compositeMessageSource.addMessageSource(databaseMessageSource);
compositeMessageSource.addMessageSource(resourceBundleMessageSource); compositeMessageSource.addMessageSource(resourceBundleMessageSource);
return compositeMessageSource; return compositeMessageSource;
} }
} }

3
io.sc.platform.system/src/main/java/io/sc/platform/system/autoconfigure/support/CompositeMessageSource.java

@ -64,6 +64,9 @@ public class CompositeMessageSource implements MessageSource, PlatformMessageSou
@Override @Override
public Map<Language, Map<String, String>> getMessages(String... messageKeys) { public Map<Language, Map<String, String>> getMessages(String... messageKeys) {
if(messageKeys==null || messageKeys.length<=0){
return Collections.emptyMap();
}
Map<Language, Map<String, String>> messageMap = getMessages(); Map<Language, Map<String, String>> messageMap = getMessages();
if(messageMap.isEmpty()){ if(messageMap.isEmpty()){
return Collections.emptyMap(); return Collections.emptyMap();

7
io.sc.platform.system/src/main/java/io/sc/platform/system/autoconfigure/support/DatabaseMessageSource.java

@ -3,10 +3,12 @@ package io.sc.platform.system.autoconfigure.support;
import io.sc.platform.core.Environment; import io.sc.platform.core.Environment;
import io.sc.platform.core.enums.Language; import io.sc.platform.core.enums.Language;
import io.sc.platform.core.i18n.PlatformMessageSource; import io.sc.platform.core.i18n.PlatformMessageSource;
import io.sc.platform.core.service.RuntimeService;
import io.sc.platform.core.util.LocaleUtil; import io.sc.platform.core.util.LocaleUtil;
import io.sc.platform.system.api.i18n.I18nLanguage; import io.sc.platform.system.api.i18n.I18nLanguage;
import io.sc.platform.system.i18n.jpa.entity.I18nEntity; import io.sc.platform.system.i18n.jpa.entity.I18nEntity;
import io.sc.platform.system.i18n.jpa.repository.I18nRepository; import io.sc.platform.system.i18n.jpa.repository.I18nRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable; import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException; import org.springframework.context.NoSuchMessageException;
@ -33,7 +35,7 @@ public class DatabaseMessageSource implements MessageSource, PlatformMessageSour
*/ */
public void reload() { public void reload() {
messages.clear(); messages.clear();
messages =load(); messages = load();
} }
@Override @Override
@ -46,6 +48,9 @@ public class DatabaseMessageSource implements MessageSource, PlatformMessageSour
@Override @Override
public Map<Language, Map<String, String>> getMessages(String... messageKeys) { public Map<Language, Map<String, String>> getMessages(String... messageKeys) {
if(messageKeys==null || messageKeys.length<=0){
return Collections.emptyMap();
}
Map<Language, Map<String, String>> messageMap = getMessages(); Map<Language, Map<String, String>> messageMap = getMessages();
if(messageMap.isEmpty()){ if(messageMap.isEmpty()){
return Collections.emptyMap(); return Collections.emptyMap();

15
io.sc.platform.system/src/main/java/io/sc/platform/system/user/controller/UserController.java

@ -5,11 +5,10 @@ import io.sc.platform.system.user.jpa.entity.UserEntity;
import io.sc.platform.system.user.jpa.repository.UserRepository; import io.sc.platform.system.user.jpa.repository.UserRepository;
import io.sc.platform.system.user.service.UserService; import io.sc.platform.system.user.service.UserService;
import io.sc.platform.system.user.service.support.UserSession; import io.sc.platform.system.user.service.support.UserSession;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.List;
@RestController @RestController
@RequestMapping("/api/system/user") @RequestMapping("/api/system/user")
@ -18,4 +17,14 @@ public class UserController extends RestCrudController<UserEntity,String, UserRe
public UserSession session(HttpServletRequest request){ public UserSession session(HttpServletRequest request){
return service.getUserSession(request); return service.getUserSession(request);
} }
/**
* 重置用户的登录密码
* @param loginNames 用户登录名集合
* @throws Exception 违例
*/
@PostMapping("resetPassword")
public void resetPassword(@RequestBody List<String> loginNames) throws Exception{
service.resetPassword(loginNames);
}
} }

17
io.sc.platform.system/src/main/java/io/sc/platform/system/user/jpa/repository/UserRepository.java

@ -2,7 +2,24 @@ package io.sc.platform.system.user.jpa.repository;
import io.sc.platform.orm.repository.DaoRepository; import io.sc.platform.orm.repository.DaoRepository;
import io.sc.platform.system.user.jpa.entity.UserEntity; import io.sc.platform.system.user.jpa.entity.UserEntity;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface UserRepository extends DaoRepository<UserEntity,String> { public interface UserRepository extends DaoRepository<UserEntity,String> {
/**
* 通过登录名查询用户实体,采用 left join fetch 查找,可一次性找出用户及其所属的所有角色
* @param loginName 登录名
* @return 用户实体
*/
@Query("select user from UserEntity as user left join fetch user.roles where user.loginName=:loginName")
public UserEntity findByLoginName(@Param("loginName") String loginName);
/**
* 通过登录名查询用户实体
* @param loginNames 登录名集合
* @return 用户实体列表
*/
public List<UserEntity> findByLoginNameIn(List<String> loginNames);
} }

8
io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/UserService.java

@ -7,7 +7,15 @@ import io.sc.platform.system.user.jpa.repository.UserRepository;
import io.sc.platform.system.user.service.support.UserSession; import io.sc.platform.system.user.service.support.UserSession;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.List;
public interface UserService extends DaoService<UserEntity, String, UserRepository> { public interface UserService extends DaoService<UserEntity, String, UserRepository> {
public UserSession getUserSession(HttpServletRequest request); public UserSession getUserSession(HttpServletRequest request);
/**
* 重置用户密码
* @param userIds 用户ID集合
* @throws Exception 违例
*/
public void resetPassword(List<String> userIds) throws Exception;
} }

19
io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/impl/UserServiceImpl.java

@ -16,17 +16,22 @@ import io.sc.platform.system.user.jpa.repository.UserRepository;
import io.sc.platform.system.user.service.UserService; import io.sc.platform.system.user.service.UserService;
import io.sc.platform.system.user.service.support.UserSession; import io.sc.platform.system.user.service.support.UserSession;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Service @Service
public class UserServiceImpl extends DaoServiceImpl<UserEntity, String, UserRepository> implements UserService { public class UserServiceImpl extends DaoServiceImpl<UserEntity, String, UserRepository> implements UserService {
@Autowired private Environment environment;
@Autowired private MenuService menuService; @Autowired private MenuService menuService;
@Autowired private FrontEndService frontEndService; @Autowired private FrontEndService frontEndService;
@Autowired private I18nService i18nService; @Autowired private I18nService i18nService;
@Autowired private PasswordEncoder passwordEncoder;
@Override @Override
public UserSession getUserSession(HttpServletRequest request) { public UserSession getUserSession(HttpServletRequest request) {
@ -39,6 +44,20 @@ public class UserServiceImpl extends DaoServiceImpl<UserEntity, String, UserRepo
return result; return result;
} }
@Override
@Transactional
public void resetPassword(List<String> userIds) throws Exception{
if(userIds!=null && !userIds.isEmpty()){
List<UserEntity> entities =repository.findAllById(userIds);
if(entities!=null && !entities.isEmpty()){
for(UserEntity entity : entities){
entity.setPassword(passwordEncoder.encode(environment.getProperty("application.default-password","")));
}
repository.saveAll(entities);
}
}
}
private List<FrontEndRoute> getFrontEndRoutes(List<Menu> menus){ private List<FrontEndRoute> getFrontEndRoutes(List<Menu> menus){
List<FrontEndRoute> result =new ArrayList<>(); List<FrontEndRoute> result =new ArrayList<>();
addFrontEndRoutes(result,menus); addFrontEndRoutes(result,menus);

3
settings.gradle

@ -4,6 +4,7 @@ include ':app.platform'
include ':io.sc.example' include ':io.sc.example'
include ':io.sc.platform.app' include ':io.sc.platform.app'
include ':io.sc.platform.app-nacos' include ':io.sc.platform.app-nacos'
include ':io.sc.platform.communication'
include ':io.sc.platform.core' include ':io.sc.platform.core'
include ':io.sc.platform.core.frontend' include ':io.sc.platform.core.frontend'
include ':io.sc.platform.components.frontend' include ':io.sc.platform.components.frontend'
@ -11,7 +12,7 @@ include ':io.sc.platform.csv'
include ':io.sc.platform.developer' include ':io.sc.platform.developer'
include ':io.sc.platform.developer.frontend' include ':io.sc.platform.developer.frontend'
include ':io.sc.platform.developer.doc' include ':io.sc.platform.developer.doc'
//include ':io.sc.platform.flowable' include ':io.sc.platform.flowable'
include ':io.sc.platform.gradle' include ':io.sc.platform.gradle'
include ':io.sc.platform.groovy' include ':io.sc.platform.groovy'
include ':io.sc.platform.installer' include ':io.sc.platform.installer'

Loading…
Cancel
Save