Browse Source

基础框架发布: 8.2.27

1)  修复 jpa 中的一些 bug

前端核心发布: 8.2.92
 1) 工作台界面调整
main
wangshaoping 2 months ago
parent
commit
dc65676a9a
  1. 16
      io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/function/SpecialValueFunction.java
  2. 4
      io.sc.platform.core.frontend/src/platform/views/Home.vue
  3. 27
      io.sc.platform.core.frontend/src/platform/views/home/Announcement.vue
  4. 13
      io.sc.platform.core.frontend/src/platform/views/home/ChatDialog.vue
  5. 36
      io.sc.platform.core.frontend/src/platform/views/home/DoneTask.vue
  6. 36
      io.sc.platform.core.frontend/src/platform/views/home/FinishedTask.vue
  7. 37
      io.sc.platform.core.frontend/src/platform/views/home/Message.vue
  8. 36
      io.sc.platform.core.frontend/src/platform/views/home/Task.vue
  9. 20
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/controller/ProcessEntityWebController.java
  10. 7
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/jpa/repository/ProcessEntityRepository.java
  11. 15
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/service/ProcessEntityService.java
  12. 3
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/service/impl/AssigneeQueryServiceImpl.java
  13. 41
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/service/impl/ProcessEntityServiceImpl.java
  14. 17
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/service/impl/ProcessQueryServiceImpl.java
  15. 9
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/support/BusinessKeyAndDescription.java
  16. 10
      io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/support/ProcessTaskWrapper.java
  17. 27
      io.sc.platform.lcdp.frontend/src/views/bpm/Bpm.vue
  18. 9
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/Criteria.java
  19. 28
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/Between.java
  20. 3
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/BetweenInclusive.java
  21. 9
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/EndWith.java
  22. 2
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/Equals.java
  23. 17
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/GreaterOrEquals.java
  24. 3
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/GreaterThan.java
  25. 2
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/InSet.java
  26. 6
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/IsBlank.java
  27. 6
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/IsNotNull.java
  28. 7
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/IsNull.java
  29. 17
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/LessOrEquals.java
  30. 17
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/LessThan.java
  31. 6
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/NotBlank.java
  32. 9
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/StartWith.java
  33. 11
      io.sc.platform.system.frontend/src/i18n/messages.json
  34. 11
      io.sc.platform.system.frontend/src/i18n/messages_tw_CN.json
  35. 11
      io.sc.platform.system.frontend/src/i18n/messages_zh_CN.json
  36. 16
      io.sc.platform.system.frontend/src/views/notification/NotificationManager.vue
  37. 53
      io.sc.platform.system.frontend/src/views/workbench/Announcement.vue
  38. 63
      io.sc.platform.system.frontend/src/views/workbench/MyMessage.vue
  39. 89
      io.sc.platform.system.frontend/src/views/workbench/MyTask.vue
  40. 8
      io.sc.platform.system/src/main/java/io/sc/platform/system/notification/controller/NotificationManagerWebController.java
  41. 1
      io.sc.platform.system/src/main/java/io/sc/platform/system/notification/service/NotificationService.java
  42. 27
      io.sc.platform.system/src/main/java/io/sc/platform/system/notification/service/impl/NotificationServiceImpl.java

16
io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/function/SpecialValueFunction.java

@ -80,7 +80,7 @@ public class SpecialValueFunction {
* @param nullValue null 或空字符串时返回值
* @return 空值处理后的值
*/
public static Object nil(Object value, Object nullValue) {
public static <T> T nil(T value, T nullValue) {
if(value==null) return nullValue;
if(value instanceof String) {
if(!StringUtils.hasText((String)value)){
@ -97,13 +97,13 @@ public class SpecialValueFunction {
* @param nanValue 不是一个数字时的返回值
* @return 非数字处理后的值
*/
public static Object nan(Object value, Object nanValue) {
public static <T> T nan(T value, T nanValue) {
if(value instanceof Float){
if(Float.isNaN((float)value)){
if(Float.isNaN((Float)value)){
return nanValue;
}
}else if(value instanceof Double){
if(Double.isNaN((double)value)){
if(Double.isNaN((Double)value)){
return nanValue;
}
}
@ -117,13 +117,13 @@ public class SpecialValueFunction {
* @param infiniteValue 无穷时的返回值
* @return 无穷处理后的值
*/
public static Object infinite(Object value, Object infiniteValue) {
public static <T> T infinite(T value, T infiniteValue) {
if(value instanceof Float){
if(Float.isInfinite((float)value)){
if(Float.isInfinite((Float)value)){
return infiniteValue;
}
}else if(value instanceof Double){
if(Double.isInfinite((double)value)){
if(Double.isInfinite((Double)value)){
return infiniteValue;
}
}
@ -136,7 +136,7 @@ public class SpecialValueFunction {
* @param zeroValue 为数值零时返回值
* @return 零值处理后的值
*/
public static Object zero(Object value, Object zeroValue) {
public static <T> T zero(T value, T zeroValue) {
if((value instanceof Number) && new BigDecimal(value.toString()).equals(BigDecimal.valueOf(0))){
return zeroValue;
}

4
io.sc.platform.core.frontend/src/platform/views/Home.vue

@ -6,14 +6,14 @@
</div>
</div>
<div class="row p-2">
<div class="col-6 pr-2">
<div class="col-7 pr-2">
<Task></Task>
<div style="height: 10px"></div>
<DoneTask></DoneTask>
<div style="height: 10px"></div>
<FinishedTask></FinishedTask>
</div>
<div class="col-6 pl-2">
<div class="col-5 pl-2">
<Message></Message>
<div style="height: 10px"></div>
<Announcement></Announcement>

27
io.sc.platform.core.frontend/src/platform/views/home/Announcement.vue

@ -1,5 +1,6 @@
<template>
<q-card flat bordered>
<q-card ref="cardRef" flat bordered :style="{ width: '100%', height: cardHeightRef + 'px' }">
<q-resize-observer @resize="changeFirstColMaxWidth" />
<q-card-section class="text-orange px-2 pt-1 pb-0">
<div class="row no-wrap items-center">
<q-icon name="bi-megaphone" size="1.3em" />
@ -18,15 +19,14 @@
</div>
</q-card-section>
<q-card-section class="p-0">
<q-markup-table flat dense separator="none" style="height: 130px; overflow-y: auto">
<q-markup-table flat dense separator="none" :style="{ width: '100%', height: tableHeightRef + 'px', overflowY: 'auto' }">
<tbody>
<tr v-for="item in unReadedAnnouncementsRef" :key="item.id" @click="handleTask(item)">
<td width="100%">
<div class="truncate" style="width: 350px">{{ item.title }}</div>
<tr v-for="item in itemsRef" :key="item.id">
<td width="100%" :title="item.content" class="truncate" :style="{ maxWidth: firstColMaxWidthRef + 'px' }">
<a href="javascript:void(0);" style="cursor: pointer; color: blue" @click="handleTask(item)" v-html="item.content"></a>
</td>
<td width="100px">{{ item.lastModifyDateAndNowDiff }}{{ $t(item.lastModifyDateAndNowDiffUnit) }}{{ $t('before') }}</td>
<td width="100px">
<q-btn color="primary" no-caps :label="$t('home.card.announcement.action.view')" size="11px" @click="handleTask(item)" />
<td width="80px" :title="item.lastModifyDate" class="smallFont truncate" style="max-width: 80px" align="right">
{{ item.lastModifyDateAndNowDiff + $t(item.lastModifyDateAndNowDiffUnit) + $t('before') }}
</td>
</tr>
</tbody>
@ -40,10 +40,21 @@ import { ref } from 'vue';
import { axios, Environment } from '@/platform';
import AnnouncementDialog from './AnnouncementDialog.vue';
const cardRef = ref();
const cardHeightRef = ref(300);
const tableHeightRef = ref(300 - 30);
const firstColMaxWidthRef = ref(100);
const itemsRef = ref([]);
const loadingRef = ref(false);
const dialogRef = ref();
const changeFirstColMaxWidth = () => {
let width = Math.ceil(cardRef.value.$el.clientWidth);
width = width - 100;
firstColMaxWidthRef.value = width > 100 ? width : 100;
};
const refresh = () => {
loadingRef.value = true;
axios

13
io.sc.platform.core.frontend/src/platform/views/home/ChatDialog.vue

@ -11,17 +11,19 @@
<template #before>
<div class="px-4">
<template v-for="message in messagesRef" :key="message.id">
<template v-if="message.sender === senderRef">
<q-chat-message :name="senderRef" :text="[message.content]" bg-color="white" style="width: 85%">
<template v-if="message.sender === senderRef"
><!-- 他人发送的消息 -->
<q-chat-message :name="senderRef" :text-html="true" :text="[message.content]" bg-color="blue" text-color="white" size="6">
<template #avatar>
<q-icon name="bi-person-circle" size="32px" color="blue" right />
<q-icon name="bi-person-circle" size="32px" color="blue" right class="p-2" />
</template>
</q-chat-message>
</template>
<template v-else>
<q-chat-message :text="[message.content]" sent bg-color="white">
<!-- 我发送的消息 -->
<q-chat-message sent :text-html="true" :text="[message.content]" bg-color="green" text-color="white" size="6">
<template #avatar>
<q-icon name="bi-person-circle" size="32px" color="green" left />
<q-icon name="bi-person-circle" size="32px" color="green" left class="p-2" />
</template>
</q-chat-message>
</template>
@ -56,7 +58,6 @@ const dialogRef = ref();
const senderRef = ref();
const textareaRef = ref();
const questionRef = ref();
const questionHistoryRef = ref([]);
const messagesRef = ref([]);
const open = (sender: string) => {

36
io.sc.platform.core.frontend/src/platform/views/home/DoneTask.vue

@ -1,5 +1,6 @@
<template>
<q-card flat bordered>
<q-card ref="cardRef" flat bordered :style="{ width: '100%', height: cardHeightRef + 'px' }">
<q-resize-observer @resize="changeFirstColMaxWidth" />
<q-card-section class="text-secondary px-2 pt-1 pb-0">
<div class="row no-wrap items-center">
<q-icon name="bi-list-check" size="1.5em" />
@ -18,14 +19,24 @@
</div>
</q-card-section>
<q-card-section class="p-0">
<q-markup-table flat dense separator="none" style="height: 130px; overflow-y: auto">
<q-markup-table flat dense separator="none" :style="{ width: '100%', height: tableHeightRef + 'px', overflowY: 'auto' }">
<tbody>
<tr v-for="item in itemsRef" :key="item.id" @click="handleTask(item)">
<td width="100%">
<div class="truncate" style="width: 350px">{{ item.businessDescription }}</div>
<td width="100%" :title="item.businessDescription" class="truncate" :style="{ maxWidth: firstColMaxWidthRef + 'px' }">
<w-html-a :label="item.businessDescription" @click="handleTask(item)"></w-html-a>
</td>
<td width="80px" :title="item.processDefinitionName" class="smallFont truncate" style="max-width: 80px; font-size: 0.8em; padding: 0px 4px">
{{ item.processDefinitionName }}
</td>
<td width="60px" :title="item.name" class="smallFont truncate" style="max-width: 60px; font-size: 0.8em; padding: 0px 4px">
{{ item.name }}
</td>
<td width="60px" :title="item.previousAssignee" class="smallFont truncate" style="max-width: 60px; font-size: 0.8em; padding: 0px 4px">
{{ item.previousAssignee }}
</td>
<td width="80px" :title="item.createTime" class="smallFont truncate" style="max-width: 80px; font-size: 0.8em; padding: 0px 4px" align="right">
{{ item.createTimeAndNowDiff + $t(item.createTimeAndNowDiffUnit) + $t('before') }}
</td>
<td width="100px">{{ item.previousAssignee }}, {{ item.createTimeAndNowDiff }}{{ $t(item.createTimeAndNowDiffUnit) }}{{ $t('before') }}</td>
<td width="100px"><q-btn color="primary" no-caps :label="$t('home.card.doneTask.action.view')" size="11px" @click="handleTask(item)" /></td>
</tr>
</tbody>
</q-markup-table>
@ -36,10 +47,21 @@
import { h, ref, defineAsyncComponent, nextTick } from 'vue';
import { axios, Environment, ComponentManager, Tools } from '@/platform';
const cardRef = ref();
const cardHeightRef = ref(200);
const tableHeightRef = ref(200 - 30);
const firstColMaxWidthRef = ref(100);
const itemsRef = ref([]);
const loadingRef = ref(false);
const componentRef = ref();
const changeFirstColMaxWidth = () => {
let width = Math.ceil(cardRef.value.$el.clientWidth);
width = width - 280;
firstColMaxWidthRef.value = width > 100 ? width : 100;
};
const refresh = () => {
loadingRef.value = true;
axios
@ -60,7 +82,7 @@ const handleTask = async (item: any) => {
nextTick(() => {
const component = defineAsyncComponent(ComponentManager.getRemoteComponent(item.taskHandFrontendModelName, item.taskHandFrontendComponentName));
const properties = Tools.mergeObject(
{ taskId: item.id, businessKey: item.businessKey, action: 'view' },
{ taskId: item.id, businessKey: item.businessKey, action: 'process' },
Tools.json2Object(item.taskHandFrontendComponentProperties),
);
componentRef.value = h(component, properties);

36
io.sc.platform.core.frontend/src/platform/views/home/FinishedTask.vue

@ -1,5 +1,6 @@
<template>
<q-card flat bordered>
<q-card ref="cardRef" flat bordered :style="{ width: '100%', height: cardHeightRef + 'px' }">
<q-resize-observer @resize="changeFirstColMaxWidth" />
<q-card-section class="text-info px-2 pt-1 pb-0">
<div class="row no-wrap items-center">
<q-icon name="bi-card-list" size="1.4em" />
@ -18,14 +19,24 @@
</div>
</q-card-section>
<q-card-section class="p-0">
<q-markup-table flat dense separator="none" style="height: 130px; overflow-y: auto">
<q-markup-table flat dense separator="none" :style="{ width: '100%', height: tableHeightRef + 'px', overflowY: 'auto' }">
<tbody>
<tr v-for="item in itemsRef" :key="item.id" @click="handleTask(item)">
<td width="100%">
<div class="truncate" style="width: 350px">{{ item.businessDescription }}</div>
<td width="100%" :title="item.businessDescription" class="truncate" :style="{ maxWidth: firstColMaxWidthRef + 'px' }">
<w-html-a :label="item.businessDescription" @click="handleTask(item)"></w-html-a>
</td>
<td width="80px" :title="item.processDefinitionName" class="smallFont truncate" style="max-width: 80px; font-size: 0.8em; padding: 0px 4px">
{{ item.processDefinitionName }}
</td>
<td width="60px" :title="item.name" class="smallFont truncate" style="max-width: 60px; font-size: 0.8em; padding: 0px 4px">
{{ item.name }}
</td>
<td width="60px" :title="item.previousAssignee" class="smallFont truncate" style="max-width: 60px; font-size: 0.8em; padding: 0px 4px">
{{ item.previousAssignee }}
</td>
<td width="80px" :title="item.createTime" class="smallFont truncate" style="max-width: 80px; font-size: 0.8em; padding: 0px 4px" align="right">
{{ item.createTimeAndNowDiff + $t(item.createTimeAndNowDiffUnit) + $t('before') }}
</td>
<td width="100px">{{ item.previousAssignee }}, {{ item.createTimeAndNowDiff }}{{ $t(item.createTimeAndNowDiffUnit) }}{{ $t('before') }}</td>
<td width="100px"><q-btn color="primary" no-caps :label="$t('home.card.finishTask.action.view')" size="11px" @click="handleTask(item)" /></td>
</tr>
</tbody>
</q-markup-table>
@ -36,10 +47,21 @@
import { h, ref, defineAsyncComponent, nextTick } from 'vue';
import { axios, Environment, ComponentManager, Tools } from '@/platform';
const cardRef = ref();
const cardHeightRef = ref(200);
const tableHeightRef = ref(200 - 30);
const firstColMaxWidthRef = ref(100);
const itemsRef = ref([]);
const loadingRef = ref(false);
const componentRef = ref();
const changeFirstColMaxWidth = () => {
let width = Math.ceil(cardRef.value.$el.clientWidth);
width = width - 280;
firstColMaxWidthRef.value = width > 100 ? width : 100;
};
const refresh = () => {
loadingRef.value = true;
axios
@ -60,7 +82,7 @@ const handleTask = async (item: any) => {
nextTick(() => {
const component = defineAsyncComponent(ComponentManager.getRemoteComponent(item.taskHandFrontendModelName, item.taskHandFrontendComponentName));
const properties = Tools.mergeObject(
{ taskId: item.id, businessKey: item.businessKey, action: 'view' },
{ taskId: item.id, businessKey: item.businessKey, action: 'process' },
Tools.json2Object(item.taskHandFrontendComponentProperties),
);
componentRef.value = h(component, properties);

37
io.sc.platform.core.frontend/src/platform/views/home/Message.vue

@ -1,5 +1,6 @@
<template>
<q-card flat bordered>
<q-card ref="cardRef" flat bordered :style="{ width: '100%', height: cardHeightRef + 'px' }">
<q-resize-observer @resize="changeFirstColMaxWidth" />
<q-card-section class="text-positive px-2 pt-1 pb-0">
<div class="row no-wrap items-center">
<q-icon name="bi-chat-text" size="1.5em" />
@ -18,15 +19,17 @@
</div>
</q-card-section>
<q-card-section class="p-0">
<q-markup-table flat dense separator="none" style="width: 100%; height: 130px; overflow-y: auto">
<q-markup-table flat dense separator="none" :style="{ width: '100%', height: tableHeightRef + 'px', overflowY: 'auto' }">
<tbody>
<tr v-for="item in itemsRef" :key="item.id">
<td width="100%">
<div class="truncate" style="width: 350px">{{ item.content }}</div>
<td width="100%" :title="item.content" class="truncate" :style="{ maxWidth: firstColMaxWidthRef + 'px' }">
<a href="javascript:void(0);" style="cursor: pointer; color: blue" @click="handleTask(item)" v-html="item.content"></a>
</td>
<td width="100px">{{ item.sender + ', ' + item.sendDateAndNowDiff + $t(item.sendDateAndNowDiffUnit) + $t('before') }}</td>
<td width="100px">
<q-btn color="primary" no-caps :label="$t('home.card.message.action.reply')" size="11px" @click="handleTask(item)" />
<td width="80px" :title="item.sender" class="smallFont truncate" style="max-width: 80px">
{{ item.sender }}
</td>
<td width="80px" :title="item.sendDate" class="smallFont truncate" style="max-width: 80px" align="right">
{{ item.sendDateAndNowDiff + $t(item.sendDateAndNowDiffUnit) + $t('before') }}
</td>
</tr>
</tbody>
@ -40,10 +43,21 @@ import { ref } from 'vue';
import { axios, Environment } from '@/platform';
import ChatDialog from './ChatDialog.vue';
const cardRef = ref();
const cardHeightRef = ref(310);
const tableHeightRef = ref(300 - 30);
const firstColMaxWidthRef = ref(100);
const itemsRef = ref([]);
const loadingRef = ref(false);
const chatDialogRef = ref();
const changeFirstColMaxWidth = () => {
let width = Math.ceil(cardRef.value.$el.clientWidth);
width = width - 160;
firstColMaxWidthRef.value = width > 100 ? width : 100;
};
const refresh = () => {
loadingRef.value = true;
axios
@ -63,3 +77,12 @@ const handleTask = (item: any) => {
refresh();
</script>
<style scoped>
.q-markup-table td {
padding: 0px 4px;
}
.smallFont {
font-size: 0.8em;
}
</style>

36
io.sc.platform.core.frontend/src/platform/views/home/Task.vue

@ -1,5 +1,6 @@
<template>
<q-card flat bordered>
<q-card ref="cardRef" flat bordered :style="{ width: '100%', height: cardHeightRef + 'px' }">
<q-resize-observer @resize="changeFirstColMaxWidth" />
<q-card-section class="text-warning px-2 pt-1 pb-0">
<div class="row no-wrap items-center">
<q-icon name="bi-list-ol" size="1.5em" />
@ -17,15 +18,25 @@
/>
</div>
</q-card-section>
<q-card-section class="p-0">
<q-markup-table flat dense separator="none" style="width: 100%; height: 130px; overflow-y: auto">
<q-card-section class="px-0 py-0">
<q-markup-table flat dense separator="none" :style="{ width: '100%', height: tableHeightRef + 'px', overflowY: 'auto' }">
<tbody>
<tr v-for="item in itemsRef" :key="item.id">
<td width="100%">
<div class="truncate" style="width: 350px">{{ item.processDefinitionName + ' [' + item.name + '] : ' + item.businessDescription }}</div>
<td width="100%" :title="item.businessDescription" class="truncate" :style="{ maxWidth: firstColMaxWidthRef + 'px', padding: '0px 4px' }">
<w-html-a :label="item.businessDescription" @click="handleTask(item)"></w-html-a>
</td>
<td width="100px" :title="item.processDefinitionName" class="smallFont truncate" style="max-width: 100px; font-size: 0.8em; padding: 0px 4px">
{{ item.processDefinitionName }}
</td>
<td width="80px" :title="item.name" class="smallFont truncate" style="max-width: 80px; font-size: 0.8em; padding: 0px 4px">
{{ item.name }}
</td>
<td width="80px" :title="item.previousAssignee" class="smallFont truncate" style="max-width: 80px; font-size: 0.8em; padding: 0px 4px">
{{ item.previousAssignee }}
</td>
<td width="80px" :title="item.createTime" class="smallFont truncate" style="max-width: 80px; font-size: 0.8em; padding: 0px 4px" align="right">
{{ item.createTimeAndNowDiff + $t(item.createTimeAndNowDiffUnit) + $t('before') }}
</td>
<td width="100px">{{ item.previousAssignee + ', ' + item.createTimeAndNowDiff + $t(item.createTimeAndNowDiffUnit) + $t('before') }}</td>
<td width="100px"><q-btn color="primary" no-caps :label="$t('home.card.task.action.process')" size="11px" @click="handleTask(item)" /></td>
</tr>
</tbody>
</q-markup-table>
@ -37,10 +48,21 @@
import { h, ref, defineAsyncComponent, nextTick } from 'vue';
import { axios, Environment, ComponentManager, Tools } from '@/platform';
const cardRef = ref();
const cardHeightRef = ref(200);
const tableHeightRef = ref(200 - 30);
const firstColMaxWidthRef = ref(100);
const itemsRef = ref([]);
const loadingRef = ref(false);
const componentRef = ref();
const changeFirstColMaxWidth = () => {
let width = Math.ceil(cardRef.value.$el.clientWidth);
width = width - 340;
firstColMaxWidthRef.value = width > 100 ? width : 100;
};
const refresh = () => {
loadingRef.value = true;
axios

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

@ -1,14 +1,16 @@
package io.sc.platform.flowable.controller;
import io.sc.platform.core.support.KeyValue;
import io.sc.platform.core.support.Option;
import io.sc.platform.flowable.api.ProcessVo;
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 org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.flowable.bpmn.model.UserTask;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController("io.sc.platform.flowable.controller.ProcessEntityWebController")
@RequestMapping("/api/flowable/process")
@ -17,4 +19,14 @@ public class ProcessEntityWebController extends RestCrudController<ProcessVo, Pr
public void deploy(@PathVariable(name="id") String id) throws Exception{
service.deploy(id);
}
@GetMapping("findAllDeployedProcessDefines")
public List<ProcessVo> findAllDeployedProcessDefines() throws Exception {
return service.findAllDeployedProcessDefines();
}
@GetMapping("findUserTasksByProcessDeployId/{deployId}")
public List<Option<String>> findUserTasksByProcessDeployId(@PathVariable("deployId") String deployId) throws Exception {
return service.findUserTasksByProcessDeployId(deployId);
}
}

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

@ -47,4 +47,11 @@ public interface ProcessEntityRepository extends DaoRepository<ProcessEntity,Str
* @return 流程定义实体
*/
public ProcessEntity findByCategoryAndKeyAndVersionIsNull(String category,String key);
/**
* 通过流程状态查找流程定义实体
* @param status 状态
* @return 流程定义实体
*/
public List<ProcessEntity> findByStatusOrderByVersion(ProcessStatus status);
}

15
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/service/ProcessEntityService.java

@ -1,9 +1,15 @@
package io.sc.platform.flowable.service;
import io.sc.platform.core.support.KeyValue;
import io.sc.platform.core.support.Option;
import io.sc.platform.flowable.api.ProcessVo;
import io.sc.platform.flowable.jpa.entity.ProcessEntity;
import io.sc.platform.flowable.jpa.repository.ProcessEntityRepository;
import io.sc.platform.orm.service.DaoService;
import org.flowable.bpmn.model.UserTask;
import java.util.List;
public interface ProcessEntityService extends DaoService<ProcessEntity, String, ProcessEntityRepository> {
@ -34,4 +40,13 @@ public interface ProcessEntityService extends DaoService<ProcessEntity, String,
* @throws Exception 违例
*/
public void deploy(String id) throws Exception;
/**
* 查询所有发布的流程定义
* @return 所有发布的流程定义
* @throws Exception 违例
*/
public List<ProcessVo> findAllDeployedProcessDefines() throws Exception;
public List<Option<String>> findUserTasksByProcessDeployId(String deployId) throws Exception;
}

3
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/service/impl/AssigneeQueryServiceImpl.java

@ -12,6 +12,7 @@ import org.flowable.bpmn.model.UserTask;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
@ -83,7 +84,7 @@ public class AssigneeQueryServiceImpl implements AssigneeQueryService {
for(OrgEntity org : orgs){
orgAndParentOrgs.add(org);
OrgEntity parentOrg =org.getParent();
while(parentOrg!=null){
while(parentOrg!=null && !StringUtils.hasText(parentOrg.getId())){
orgAndParentOrgs.add(parentOrg);
parentOrg =parentOrg.getParent();
}

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

@ -1,16 +1,23 @@
package io.sc.platform.flowable.service.impl;
import java.util.List;
import java.util.*;
import io.sc.platform.core.Environment;
import io.sc.platform.core.support.KeyValue;
import io.sc.platform.core.support.Option;
import io.sc.platform.core.util.PinyinUtil;
import io.sc.platform.flowable.api.ProcessVo;
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.flowable.enums.ProcessStatus;
import io.sc.platform.flowable.util.BpmnConverterUtil;
import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.orm.util.EntityVoUtil;
import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
@ -144,4 +151,36 @@ public class ProcessEntityServiceImpl extends DaoServiceImpl<ProcessEntity, Stri
}
}
}
@Override
public List<ProcessVo> findAllDeployedProcessDefines() throws Exception {
List<ProcessEntity> entities =repository.findByStatusOrderByVersion(ProcessStatus.RELEASE);
if(entities==null || entities.isEmpty()) { return Collections.emptyList(); }
return EntityVoUtil.toVo(entities);
}
@Override
public List<Option<String>> findUserTasksByProcessDeployId(String deployId) throws Exception {
if(!StringUtils.hasText(deployId)) { return Collections.emptyList(); }
BpmnModel model = repositoryService.getBpmnModel(deployId);
if(model==null) { return Collections.emptyList(); }
Collection<FlowElement> elements =model.getMainProcess().getFlowElements();
if(elements==null || elements.isEmpty()) { return Collections.emptyList(); }
List<Option<String>> result =new ArrayList<>();
for(FlowElement element : elements){
if(element instanceof UserTask){
UserTask userTask =(UserTask)element;
result.add(new Option<>(userTask.getId(),userTask.getName()));
}
}
Collections.sort(result, new Comparator<Option<String>>() {
@Override
public int compare(Option<String> o1, Option<String> o2) {
return PinyinUtil.compare(o1.getValue(),o2.getValue());
}
});
return result;
}
}

17
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/service/impl/ProcessQueryServiceImpl.java

@ -9,6 +9,7 @@ import io.sc.platform.jdbc.sql.dialect.Dialect;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.QueryResult;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.orm.service.support.criteria.impl.Contains;
import io.sc.platform.orm.service.support.criteria.impl.Equals;
import io.sc.platform.security.util.SecurityUtil;
import io.sc.platform.util.CollectionUtil;
@ -233,6 +234,20 @@ public class ProcessQueryServiceImpl implements ProcessQueryService {
Equals _assigneeCriteria =(Equals)assigneeCriteria;
query.taskAssignee(_assigneeCriteria.getValue());
}
// 任务节点 KEY
Criteria taskDefinitionKeyCriteria =queryParameter.getCriteriaByFieldName("taskDefinitionKey");
if(taskDefinitionKeyCriteria!=null && taskDefinitionKeyCriteria instanceof Equals){
Equals _taskDefinitionKeyCriteria =(Equals)taskDefinitionKeyCriteria;
query.taskDefinitionKey(_taskDefinitionKeyCriteria.getValue());
}
// 任务描述
Criteria taskDescriptionCriteria =queryParameter.getCriteriaByFieldName("description");
if(taskDescriptionCriteria!=null && taskDescriptionCriteria instanceof Contains){
Contains _taskDescriptionCriteria =(Contains)taskDescriptionCriteria;
query.taskDescriptionLike("%" + StringUtil.escapeSqlSpecialChar(_taskDescriptionCriteria.getValue()) + "%");
}
}
if(queryParameter!=null && queryParameter.existsSortBy()){
Order order =queryParameter.getFirstSort();
@ -323,6 +338,7 @@ public class ProcessQueryServiceImpl implements ProcessQueryService {
BusinessKeyAndDescription businessKeyAndDescription =processInstanceAndBusinessMap.get(processInstance.getId());
if(businessKeyAndDescription!=null){
businessKeyAndDescription.setProcessDefinitionName(processInstance.getProcessDefinitionName());
businessKeyAndDescription.setProcessDefinitionVersion(processInstance.getProcessDefinitionVersion());
businessKeyAndDescription.setBusinessKey(processInstance.getBusinessKey());
businessKeyAndDescription.setBusinessDescription(processInstance.getProcessDefinitionName());
@ -392,6 +408,7 @@ public class ProcessQueryServiceImpl implements ProcessQueryService {
wrapper.setBusinessKey(businessKeyAndDescription.getBusinessKey());
wrapper.setBusinessDescription(businessKeyAndDescription.getBusinessDescription());
wrapper.setProcessDefinitionName(businessKeyAndDescription.getProcessDefinitionName());
wrapper.setProcessDefinitionVersion(businessKeyAndDescription.getProcessDefinitionVersion());
wrapper.setTaskHandFrontendModelName(businessKeyAndDescription.getTaskHandFrontendModelName());
wrapper.setTaskHandFrontendComponentName(businessKeyAndDescription.getTaskHandFrontendComponentName());
wrapper.setTaskHandFrontendComponentProperties(businessKeyAndDescription.getTaskHandFrontendComponentProperties());

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

@ -3,6 +3,7 @@ package io.sc.platform.flowable.support;
public class BusinessKeyAndDescription {
private String previousAssignee;
private String processDefinitionName;
private Integer processDefinitionVersion;
private String businessKey;
private String businessDescription;
private String taskHandFrontendModelName;
@ -25,6 +26,14 @@ public class BusinessKeyAndDescription {
this.processDefinitionName = processDefinitionName;
}
public Integer getProcessDefinitionVersion() {
return processDefinitionVersion;
}
public void setProcessDefinitionVersion(Integer processDefinitionVersion) {
this.processDefinitionVersion = processDefinitionVersion;
}
public String getBusinessKey() {
return businessKey;
}

10
io.sc.platform.flowable/src/main/java/io/sc/platform/flowable/support/ProcessTaskWrapper.java

@ -33,6 +33,7 @@ public class ProcessTaskWrapper {
private String previousAssignee;
private String processDefinitionName;
private Integer processDefinitionVersion;
private String businessKey;
private String businessDescription;
private String taskHandFrontendModelName;
@ -187,6 +188,15 @@ public class ProcessTaskWrapper {
public void setProcessDefinitionName(String processDefinitionName) {
this.processDefinitionName = processDefinitionName;
}
public Integer getProcessDefinitionVersion() {
return processDefinitionVersion;
}
public void setProcessDefinitionVersion(Integer processDefinitionVersion) {
this.processDefinitionVersion = processDefinitionVersion;
}
public String getBusinessKey() {
return businessKey;
}

27
io.sc.platform.lcdp.frontend/src/views/bpm/Bpm.vue

@ -15,7 +15,7 @@
<w-grid
ref="processDefineGridRef"
:title="$t('lcdp.bpm.processDefine.grid.title')"
db-click-operation="design"
db-click-operation="edit"
:checkbox-selection="true"
:data-url="Environment.apiContextPath('/api/flowable/process')"
:pageable="true"
@ -43,13 +43,8 @@
'clone',
{
extend: 'edit',
enableIf: (arg) => {
if (arg.selected) {
if ('SKETCH' === arg.selected.status) {
enableIf: () => {
return true;
}
}
return false;
},
},
{
@ -192,15 +187,14 @@
form.setFieldValue('key', value);
form.setFieldValue('name', Formater.dictionary(ProcessCategoryDictionaries)(value));
},
readOnlyIf: true,
},
{
name: 'key',
label: $t('code'),
type: 'w-text',
defaultValue: 'SAMPLE',
readonlyIf: () => {
return true;
},
readOnlyIf: true,
},
{
name: 'name',
@ -208,12 +202,16 @@
type: 'w-text',
requiredIf: true,
defaultValue: Formater.dictionary(ProcessCategoryDictionaries)('SAMPLE'),
readonlyIf: () => {
return true;
},
},
{ colSpan: 3, name: 'description', label: $t('description'), type: 'w-textarea', rows: 1 },
{ colSpan: 3, name: 'xml', label: $t('xml'), type: 'w-textarea', rows: 5 },
{
colSpan: 3,
name: 'xml',
label: $t('xml'),
type: 'w-textarea',
rows: 5,
readOnlyIf: true,
},
{ name: 'status', label: $t('status'), type: 'w-text', defaultValue: 'SKETCH', showIf: false },
{
name: 'canClaimTask',
@ -221,6 +219,7 @@
type: 'w-checkbox',
defaultValue: true,
rule: [],
disableIf: true,
},
{
colSpan: 2,

9
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/Criteria.java

@ -141,7 +141,14 @@ public abstract class Criteria<E> {
result.setAttributeName(splits[0]);
}
}
Path path =root.get(result.getAttributeName());
Path path =null;
try {
path = root.get(result.getAttributeName());
} catch (IllegalArgumentException e) { // if attribute of the given name does not otherwise exist
return null;
} catch (IllegalStateException e){ // if invoked on a path that corresponds to a basic type
throw e;
}
if(SingularAttributePath.class.isAssignableFrom(path.getClass())){
Optional<RepositoryInformation> repositoryInformation =repositories.getRepositoryInformationFor(path.getJavaType());
if(repositoryInformation.isPresent()){

28
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/Between.java

@ -16,10 +16,14 @@ public class Between<E> extends Criteria<E> {
@Override
@SuppressWarnings("unchecked")
public Predicate getPredicate(Root<E> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
if(!StringUtils.hasText(start) && !StringUtils.hasText(end)){
throw new IllegalArgumentException("[" + operator + "] need a [start] or [end] value");
Path path =null;
try {
path = root.get(fieldName);
} catch (IllegalArgumentException e) { // if attribute of the given name does not otherwise exist
return null;
} catch (IllegalStateException e){ // if invoked on a path that corresponds to a basic type
throw e;
}
Path path =root.get(fieldName);
Class<?> clazz =path.getJavaType();
if(Comparable.class.isAssignableFrom(clazz)){
if(StringUtils.hasText(start) && StringUtils.hasText(end)) {
@ -39,9 +43,6 @@ public class Between<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
if(!StringUtils.hasText(start) && !StringUtils.hasText(end)){
throw new IllegalArgumentException("[" + operator + "] need a [start] or [end] value");
}
Class<?> clazz =typeMapping.get(fieldName);
Object pStart =start;
Object pEnd =end;
@ -59,4 +60,19 @@ public class Between<E> extends Criteria<E> {
return condition;
}
public String getStart() {
return start;
}
public void setStart(String start) {
this.start = start;
}
public String getEnd() {
return end;
}
public void setEnd(String end) {
this.end = end;
}
}

3
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/BetweenInclusive.java

@ -12,9 +12,6 @@ public class BetweenInclusive<E> extends Between<E> {
@Override
@SuppressWarnings("unchecked")
public Predicate getPredicate(Root<E> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
if(!StringUtils.hasText(start) && !StringUtils.hasText(end)){
throw new IllegalArgumentException("[" + operator + "] need a [start] or [end] value");
}
Path path =null;
try {
path = root.get(fieldName);

9
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/EndWith.java

@ -3,6 +3,7 @@ package io.sc.platform.orm.service.support.criteria.impl;
import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.orm.service.support.OperatorTypeNotSupportedException;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.util.StringUtil;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.StringUtils;
@ -35,6 +36,12 @@ public class EndWith<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
throw new OperatorTypeNotSupportedException();
if(!StringUtils.hasText(value)){
throw new IllegalArgumentException("[" + operator + "] need a [value] value");
}
String where = StringUtil.format("${0} like '%${1}'",fieldName,StringUtil.escapeSqlSpecialChar(value));
Condition condition =new Condition();
condition.setWhere(where);
return condition;
}
}

2
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/Equals.java

@ -19,6 +19,8 @@ public class Equals<E> extends Criteria<E> {
throw new IllegalArgumentException("[" + operator + "] need a [value] value");
}
PathInformation pi =getPathInformation(root);
if(pi==null) { return null; }
Path path =null;
try {
path = root.get(pi.getAttributeName());

17
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/GreaterOrEquals.java

@ -3,11 +3,13 @@ package io.sc.platform.orm.service.support.criteria.impl;
import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.orm.service.support.OperatorTypeNotSupportedException;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.util.StringUtil;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.StringUtils;
import javax.persistence.criteria.*;
import java.util.Map;
import java.util.UUID;
public class GreaterOrEquals<E> extends Criteria<E> {
protected String value;
@ -36,7 +38,20 @@ public class GreaterOrEquals<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
throw new OperatorTypeNotSupportedException();
if(!StringUtils.hasText(value)){
throw new IllegalArgumentException("[" + operator + "] need a [value] value");
}
Object pValue =value;
Class<?> clazz =typeMapping.get(fieldName);
if(clazz!=null) {
pValue = conversionService.convert(value, clazz);
}
String name =":" + fieldName + UUID.randomUUID().toString().replace('-','_');
String where = StringUtil.format("${0} >= ${1}",fieldName,name);
Condition condition =new Condition();
condition.setWhere(where);
condition.getParameters().put(name.substring(1),pValue);
return condition;
}
public String getValue() {

3
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/GreaterThan.java

@ -8,6 +8,7 @@ import org.springframework.util.StringUtils;
import javax.persistence.criteria.*;
import java.util.Map;
import java.util.UUID;
public class GreaterThan<E> extends Criteria<E> {
protected String value;
@ -44,7 +45,7 @@ public class GreaterThan<E> extends Criteria<E> {
if(clazz!=null) {
pValue = conversionService.convert(value, clazz);
}
String name =":" + fieldName;
String name =":" + fieldName + UUID.randomUUID().toString().replace('-','_');
String where = StringUtil.format("${0} > ${1}",fieldName,name);
Condition condition =new Condition();
condition.setWhere(where);

2
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/InSet.java

@ -21,6 +21,8 @@ public class InSet<E> extends Criteria<E> {
throw new IllegalArgumentException("[" + operator + "] need a [start] or [end] value");
}
PathInformation pi =getPathInformation(root);
if(pi==null) { return null; }
Path path =null;
try {
path = root.get(pi.getAttributeName());

6
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/IsBlank.java

@ -3,6 +3,7 @@ package io.sc.platform.orm.service.support.criteria.impl;
import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.orm.service.support.OperatorTypeNotSupportedException;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.util.StringUtil;
import org.springframework.core.convert.ConversionService;
import javax.persistence.criteria.*;
@ -25,6 +26,9 @@ public class IsBlank<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
throw new OperatorTypeNotSupportedException();
String where = StringUtil.format("${0} is null or trim(${0})=''",fieldName);
Condition condition =new Condition();
condition.setWhere(where);
return condition;
}
}

6
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/IsNotNull.java

@ -3,6 +3,7 @@ package io.sc.platform.orm.service.support.criteria.impl;
import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.orm.service.support.OperatorTypeNotSupportedException;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.util.StringUtil;
import org.springframework.core.convert.ConversionService;
import javax.persistence.criteria.*;
@ -25,6 +26,9 @@ public class IsNotNull<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
throw new OperatorTypeNotSupportedException();
String where = StringUtil.format("${0} is not null",fieldName);
Condition condition =new Condition();
condition.setWhere(where);
return condition;
}
}

7
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/IsNull.java

@ -3,7 +3,9 @@ package io.sc.platform.orm.service.support.criteria.impl;
import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.orm.service.support.OperatorTypeNotSupportedException;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.util.StringUtil;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.StringUtils;
import javax.persistence.criteria.*;
import java.util.Map;
@ -25,6 +27,9 @@ public class IsNull<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
throw new OperatorTypeNotSupportedException();
String where = StringUtil.format("${0} is null",fieldName);
Condition condition =new Condition();
condition.setWhere(where);
return condition;
}
}

17
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/LessOrEquals.java

@ -3,11 +3,13 @@ package io.sc.platform.orm.service.support.criteria.impl;
import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.orm.service.support.OperatorTypeNotSupportedException;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.util.StringUtil;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.StringUtils;
import javax.persistence.criteria.*;
import java.util.Map;
import java.util.UUID;
public class LessOrEquals<E> extends Criteria<E> {
protected String value;
@ -36,7 +38,20 @@ public class LessOrEquals<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
throw new OperatorTypeNotSupportedException();
if(!StringUtils.hasText(value)){
throw new IllegalArgumentException("[" + operator + "] need a [value] value");
}
Object pValue =value;
Class<?> clazz =typeMapping.get(fieldName);
if(clazz!=null) {
pValue = conversionService.convert(value, clazz);
}
String name =":" + fieldName + UUID.randomUUID().toString().replace('-','_');
String where = StringUtil.format("${0} <= ${1}",fieldName,name);
Condition condition =new Condition();
condition.setWhere(where);
condition.getParameters().put(name.substring(1),pValue);
return condition;
}
public String getValue() {

17
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/LessThan.java

@ -3,11 +3,13 @@ package io.sc.platform.orm.service.support.criteria.impl;
import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.orm.service.support.OperatorTypeNotSupportedException;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.util.StringUtil;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.StringUtils;
import javax.persistence.criteria.*;
import java.util.Map;
import java.util.UUID;
public class LessThan<E> extends Criteria<E> {
protected String value;
@ -36,7 +38,20 @@ public class LessThan<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
throw new OperatorTypeNotSupportedException();
if(!StringUtils.hasText(value)){
throw new IllegalArgumentException("[" + operator + "] need a [value] value");
}
Object pValue =value;
Class<?> clazz =typeMapping.get(fieldName);
if(clazz!=null) {
pValue = conversionService.convert(value, clazz);
}
String name =":" + fieldName + UUID.randomUUID().toString().replace('-','_');
String where = StringUtil.format("${0} < ${1}",fieldName,name);
Condition condition =new Condition();
condition.setWhere(where);
condition.getParameters().put(name.substring(1),pValue);
return condition;
}
public String getValue() {

6
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/NotBlank.java

@ -3,6 +3,7 @@ package io.sc.platform.orm.service.support.criteria.impl;
import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.orm.service.support.OperatorTypeNotSupportedException;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.util.StringUtil;
import org.springframework.core.convert.ConversionService;
import javax.persistence.criteria.*;
@ -25,6 +26,9 @@ public class NotBlank<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
throw new OperatorTypeNotSupportedException();
String where = StringUtil.format("${0} is not null and trim(${0})!=''",fieldName);
Condition condition =new Condition();
condition.setWhere(where);
return condition;
}
}

9
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/criteria/impl/StartWith.java

@ -3,6 +3,7 @@ package io.sc.platform.orm.service.support.criteria.impl;
import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.orm.service.support.OperatorTypeNotSupportedException;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.util.StringUtil;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.StringUtils;
@ -36,6 +37,12 @@ public class StartWith<E> extends Criteria<E> {
@Override
public Condition getCondition(Map<String, Class<?>> typeMapping) {
throw new OperatorTypeNotSupportedException();
if(!StringUtils.hasText(value)){
throw new IllegalArgumentException("[" + operator + "] need a [value] value");
}
String where = StringUtil.format("${0} like '${1}%'",fieldName,StringUtil.escapeSqlSpecialChar(value));
Condition condition =new Condition();
condition.setWhere(where);
return condition;
}
}

11
io.sc.platform.system.frontend/src/i18n/messages.json

@ -210,5 +210,14 @@
"route.system.settings": "Settings",
"settings.shortcutMenus": "Shortcut Menus",
"settings.shortcutMenus.entity.shortcutMenuName": "Shortcut Menu Name",
"settings.shortcutMenus.entity.menuIconColor": "Icon Color"
"settings.shortcutMenus.entity.menuIconColor": "Icon Color",
"workbench.myTask.grid.title": "My Tasks",
"workbench.myTask.grid.action.process": "Process",
"workbench.myTask.grid.entity.businessDescription": "Business Description",
"workbench.myTask.grid.entity.processDefinitionName": "Process Name",
"workbench.myTask.grid.entity.activityName": "Activity Name",
"workbench.myTask.grid.entity.taskDescription": "Task Description",
"workbench.myTask.grid.entity.prefixAssignee": "Prefix Assignee",
"workbench.myTask.grid.entity.createTime": "Task Create Time"
}

11
io.sc.platform.system.frontend/src/i18n/messages_tw_CN.json

@ -188,5 +188,14 @@
"route.system.settings": "設置",
"settings.shortcutMenus": "常用菜單",
"settings.shortcutMenus.entity.shortcutMenuName": "快捷菜單名稱",
"settings.shortcutMenus.entity.menuIconColor": "圖標顏色"
"settings.shortcutMenus.entity.menuIconColor": "圖標顏色",
"workbench.myTask.grid.title": "代辦任務",
"workbench.myTask.grid.action.process": "辦理",
"workbench.myTask.grid.entity.businessDescription": "業務流水號",
"workbench.myTask.grid.entity.processDefinitionName": "流程名稱",
"workbench.myTask.grid.entity.activityName": "任務節點",
"workbench.myTask.grid.entity.taskDescription": "任務描述",
"workbench.myTask.grid.entity.prefixAssignee": "前一處理人",
"workbench.myTask.grid.entity.createTime": "任務開始日期"
}

11
io.sc.platform.system.frontend/src/i18n/messages_zh_CN.json

@ -218,5 +218,14 @@
"route.system.settings": "设置",
"settings.shortcutMenus": "常用菜单",
"settings.shortcutMenus.entity.shortcutMenuName": "快捷菜单名称",
"settings.shortcutMenus.entity.menuIconColor": "图标颜色"
"settings.shortcutMenus.entity.menuIconColor": "图标颜色",
"workbench.myTask.grid.title": "代办任务",
"workbench.myTask.grid.action.process": "办理",
"workbench.myTask.grid.entity.businessDescription": "业务流水号",
"workbench.myTask.grid.entity.processDefinitionName": "流程名称",
"workbench.myTask.grid.entity.activityName": "任务节点",
"workbench.myTask.grid.entity.taskDescription": "任务描述",
"workbench.myTask.grid.entity.prefixAssignee": "前一处理人",
"workbench.myTask.grid.entity.createTime": "任务开始日期"
}

16
io.sc.platform.system.frontend/src/views/notification/NotificationManager.vue

@ -29,8 +29,18 @@
form: {
colsNum: 1,
fields: [
{ name: 'receiver', label: $t('receiver'), type: 'w-user-select', requiredIf: true },
{ name: 'content', label: $t('content'), type: 'q-editor', requiredIf: true, minHeight: '10rem', defaultValue: '' },
{
name: 'receiver',
label: $t('receiver'),
type: 'w-user-select',
requiredIf: true,
queryCriteria: {
fieldName: 'loginName',
operator: 'notEquals',
value: SessionManager.getUser().loginName,
},
},
{ name: 'content', label: $t('content'), type: 'w-text-editor', requiredIf: true, minHeight: '10rem', defaultValue: '' },
],
},
}"
@ -58,5 +68,5 @@
</template>
<script setup lang="ts">
import 'tailwindcss/utilities.css';
import { Environment } from 'platform-core';
import { Environment, SessionManager } from 'platform-core';
</script>

53
io.sc.platform.system.frontend/src/views/workbench/Announcement.vue

@ -1,4 +1,53 @@
<template>
<div>Announcement</div>
<w-grid
ref="gridRef"
:title="$t('system.announcementManager.grid.title')"
:config-button="true"
db-click-operation="edit"
selection="multiple"
:checkbox-selection="true"
:data-url="Environment.apiContextPath('/api/system/announcement')"
:sort-by="['-lastModifyDate']"
:query-form-cols-num="2"
:query-form-fields="[{ name: 'title', label: $t('title'), type: 'w-text', clearable: true }]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'view', 'separator', 'export']"
:columns="[
{ width: 300, name: 'title', label: $t('title') },
{ width: '100%', name: 'content', label: $t('content'), sortable: false },
{ width: 150, name: 'createDate', label: $t('createDate') },
]"
:editor="{
dialog: {
width: '800px',
},
form: {
colsNum: 1,
fields: [
{ name: 'title', label: $t('title'), type: 'w-text', requiredIf: true },
{ name: 'content', label: $t('content'), type: 'q-editor', requiredIf: true, minHeight: '10rem', defaultValue: '' },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'title', label: $t('title') },
{ name: 'content', label: $t('content') },
{ name: 'dataComeFrom', label: $t('dataComeFrom') },
{ name: 'creator', label: $t('creator') },
{ name: 'createDate', label: $t('createDate') },
{ name: 'lastModifier', label: $t('lastModifier') },
{ name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() },
{ name: 'corporationCode', label: $t('corporationCode') },
],
},
}"
></w-grid>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import 'tailwindcss/utilities.css';
import { Environment, Formater } from 'platform-core';
</script>

63
io.sc.platform.system.frontend/src/views/workbench/MyMessage.vue

@ -1,4 +1,63 @@
<template>
<div>MyMessage</div>
<w-grid
ref="gridRef"
:title="$t('system.notification.grid.title')"
:config-button="true"
db-click-operation="edit"
selection="multiple"
:checkbox-selection="true"
:fetch-data-url="Environment.apiContextPath('/api/system/notification/findNotifications')"
:data-url="Environment.apiContextPath('/api/system/notification')"
:sort-by="['-sendDate']"
:query-form-cols-num="4"
:query-form-fields="[
{ name: 'sender', label: $t('system.notification.grid.entity.sender'), type: 'w-user-select', queryOperator: 'equals' },
{ name: 'receiver', label: $t('system.notification.grid.entity.receiver'), type: 'w-user-select', queryOperator: 'equals' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'add', 'clone', 'edit', 'remove', 'separator', 'view', 'separator', 'export']"
:columns="[
{ width: 100, name: 'sender', label: $t('system.notification.grid.entity.sender') },
{ width: 150, name: 'sendDate', label: $t('system.notification.grid.entity.sendDate') },
{ width: 100, name: 'receiver', label: $t('system.notification.grid.entity.receiver') },
{ width: 150, name: 'receiveDate', label: $t('system.notification.grid.entity.receiveDate') },
{ width: '100%', name: 'content', label: $t('content'), sortable: false },
]"
:editor="{
dialog: {
width: '800px',
},
form: {
colsNum: 1,
fields: [
{ name: 'receiver', label: $t('receiver'), type: 'w-user-select', requiredIf: true },
{ name: 'content', label: $t('content'), type: 'q-editor', requiredIf: true, minHeight: '10rem', defaultValue: '' },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'sender', label: $t('system.notification.grid.entity.sender') },
{ name: 'sendDate', label: $t('system.notification.grid.entity.sendDate') },
{ name: 'title', label: $t('title') },
{ name: 'content', label: $t('content'), sortable: false },
{ name: 'receiver', label: $t('system.notification.grid.entity.receiver') },
{ name: 'receiveDate', label: $t('system.notification.grid.entity.receiveDate') },
{ name: 'dataComeFrom', label: $t('dataComeFrom') },
{ name: 'creator', label: $t('creator') },
{ name: 'createDate', label: $t('createDate') },
{ name: 'lastModifier', label: $t('lastModifier') },
{ name: 'lastModifyDate', label: $t('lastModifyDate') },
{ name: 'corporationCode', label: $t('corporationCode') },
],
},
}"
></w-grid>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import 'tailwindcss/utilities.css';
import { Environment } from 'platform-core';
</script>

89
io.sc.platform.system.frontend/src/views/workbench/MyTask.vue

@ -1,4 +1,89 @@
<template>
<div>MyTask</div>
<w-grid
ref="gridRef"
:title="$t('workbench.myTask.grid.title')"
:config-button="true"
:checkbox-selection="false"
db-click-operation="edit"
:sort-no="true"
:data-url="Environment.apiContextPath('/api/flowable/process/query/task')"
:sort-by="['-createTime']"
:query-form-cols-num="4"
:query-form-fields="[
{ name: 'businessDescription', label: $t('workbench.myTask.grid.entity.businessDescription'), type: 'w-text' },
{
name: 'processDefinitionName',
label: $t('workbench.myTask.grid.entity.processDefinitionName'),
type: 'w-select',
options: processDefinitionsRef,
onUpdateValue: async (args: any) => {
const form = gridRef.getQueryForm();
form.setFieldValue('taskDefinitionKey', undefined);
const field = form.getFields().taskDefinitionKey;
let options = [];
if (args?.value) {
const response = await axios.get(Environment.apiContextPath('/api/flowable/process/findUserTasksByProcessDeployId/' + args.value));
if (response) {
options = response.data;
}
}
field.options = options;
},
},
{
name: 'taskDefinitionKey',
label: $t('workbench.myTask.grid.entity.activityName'),
type: 'w-select',
options: [],
queryOperator: 'equals',
},
{ name: 'description', label: $t('workbench.myTask.grid.entity.taskDescription'), type: 'w-text' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'query',
'reset',
'separator',
{
name: 'process',
icon: 'bi-caret-right',
label: $t('workbench.myTask.grid.action.process'),
enableIf: (args) => {
return args.selected;
},
click: () => {},
},
]"
:columns="[
{ width: '100%', name: 'businessDescription', label: $t('workbench.myTask.grid.entity.businessDescription'), sortable: false },
{
width: 200,
name: 'processDefinitionName',
label: $t('workbench.myTask.grid.entity.processDefinitionName'),
format: (value, row) => {
return value + '_V' + row.processDefinitionVersion;
},
},
{ width: 100, name: 'name', label: $t('workbench.myTask.grid.entity.activityName') },
{ width: 100, name: 'description', label: $t('workbench.myTask.grid.entity.taskDescription') },
{ width: 100, name: 'assignee', label: $t('workbench.myTask.grid.entity.prefixAssignee') },
{ width: 150, name: 'createTime', label: $t('workbench.myTask.grid.entity.createTime') },
]"
></w-grid>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { ref } from 'vue';
import { axios, Environment, Formater } from 'platform-core';
const gridRef = ref();
const processDefinitionsRef = ref([]);
const response = await axios.get(Environment.apiContextPath('/api/flowable/process/findAllDeployedProcessDefines'));
if (response) {
const options: any[] = [];
for (const item of response.data) {
options.push({ label: item.name, value: item.deployedId });
}
processDefinitionsRef.value = options;
}
</script>

8
io.sc.platform.system/src/main/java/io/sc/platform/system/notification/controller/NotificationManagerWebController.java

@ -28,6 +28,14 @@ public class NotificationManagerWebController extends RestCrudController<Notific
return service.findUnReadedNotifications(queryParameter);
}
@GetMapping("findNotifications")
public Page<NotificationVo> findNotifications(QueryParameter queryParameter) throws Exception {
if(queryParameter==null){
return QueryResult.emptyPage();
}
return service.findNotifications(queryParameter);
}
@GetMapping("findNotificationsBySender/{sender}")
public List<NotificationVo> findNotificationsBySender(@PathVariable("sender")String sender) throws Exception {
if(!StringUtils.hasText(sender)){

1
io.sc.platform.system/src/main/java/io/sc/platform/system/notification/service/NotificationService.java

@ -11,5 +11,6 @@ import java.util.List;
public interface NotificationService extends DaoService<NotificationEntity, String, NotificationRepository> {
public Page<NotificationVo> findUnReadedNotifications(QueryParameter queryParameter) throws Exception;
public Page<NotificationVo> findNotifications(QueryParameter queryParameter) throws Exception;
public List<NotificationVo> findNotificationsBySender(String sender) throws Exception;
}

27
io.sc.platform.system/src/main/java/io/sc/platform/system/notification/service/impl/NotificationServiceImpl.java

@ -3,6 +3,9 @@ package io.sc.platform.system.notification.service.impl;
import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.QueryResult;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.orm.service.support.criteria.impl.Equals;
import io.sc.platform.orm.service.support.criteria.impl.Or;
import io.sc.platform.orm.util.EntityVoUtil;
import io.sc.platform.security.util.SecurityUtil;
import io.sc.platform.system.api.notification.NotificationVo;
@ -15,6 +18,7 @@ import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@ -37,6 +41,29 @@ public class NotificationServiceImpl extends DaoServiceImpl<NotificationEntity,
return QueryResult.page(EntityVoUtil.toVo(page),queryParameter);
}
@Override
@Transactional
public Page<NotificationVo> findNotifications(QueryParameter queryParameter) throws Exception {
String loginName =SecurityUtil.getLoginName();
List<Criteria> criterias =new ArrayList<>();
Equals senderCriteria =new Equals();
senderCriteria.setFieldName("sender");
senderCriteria.setValue(loginName);
criterias.add(senderCriteria);
Equals receiverCriteria =new Equals();
receiverCriteria.setFieldName("receiver");
receiverCriteria.setValue(loginName);
criterias.add(receiverCriteria);
Or or =new Or();
or.setCriteria(criterias);
queryParameter.addCriteria(or);
return EntityVoUtil.toVo(query(queryParameter));
}
@Override
@Transactional
public List<NotificationVo> findNotificationsBySender(String sender) throws Exception {

Loading…
Cancel
Save