Browse Source

update

main
wangshaoping 1 year ago
parent
commit
a059c9093d
  1. 4
      gradle.properties
  2. 2
      io.sc.platform.core.frontend/package.json
  3. 9
      io.sc.platform.core.frontend/src/platform/components-ext/formater/BooleanFormater.ts
  4. 6
      io.sc.platform.core.frontend/src/platform/components-ext/formater/EnumFormater.ts
  5. 6
      io.sc.platform.core.frontend/src/platform/components-ext/formater/index.ts
  6. 11
      io.sc.platform.core.frontend/src/platform/components/form/elements/WSelectUserText.vue
  7. 3
      io.sc.platform.core.frontend/src/platform/components/index.ts
  8. 13
      io.sc.platform.core.frontend/src/platform/components/tag/WSuccessFailedTag.vue
  9. 1
      io.sc.platform.core.frontend/src/platform/index.ts
  10. 100
      io.sc.platform.core.frontend/src/views/TreeGrid.vue
  11. 4
      io.sc.platform.core.frontend/template-project/package.json
  12. 100
      io.sc.platform.core.frontend/template-project/src/views/TreeGrid.vue
  13. 35
      io.sc.platform.core/src/main/java/io/sc/platform/core/support/FileWrapper.java
  14. 4
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words.properties
  15. 4
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_tw_CN.properties
  16. 4
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_zh_CN.properties
  17. 4
      io.sc.platform.developer.frontend/package.json
  18. 79
      io.sc.platform.developer.frontend/src/views/plugin/Menus.vue
  19. 4
      io.sc.platform.gradle/templates/pgp/app/build.gradle
  20. 3
      io.sc.platform.gradle/templates/pgp/app/src/main/java/app/platform/Application.java.txt
  21. 4
      io.sc.platform.gradle/templates/pgp/setup/build.gradle.txt
  22. 8
      io.sc.platform.gradle/templates/pgp/setup/gradle.properties
  23. 4
      io.sc.platform.lcdp.frontend/package.json
  24. 4
      io.sc.platform.mvc.frontend/package.json
  25. 18
      io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/QueryResult.java
  26. 4
      io.sc.platform.security.frontend/package.json
  27. 4
      io.sc.platform.system.frontend/package.json
  28. 22
      io.sc.platform.system.frontend/src/i18n/messages.json
  29. 22
      io.sc.platform.system.frontend/src/i18n/messages_tw_CN.json
  30. 22
      io.sc.platform.system.frontend/src/i18n/messages_zh_CN.json
  31. 107
      io.sc.platform.system.frontend/src/views/dictionary/Dictionary.vue
  32. 158
      io.sc.platform.system.frontend/src/views/i18n/I18n.vue
  33. 135
      io.sc.platform.system.frontend/src/views/menu/ImportMenuPluginDialog.vue
  34. 54
      io.sc.platform.system.frontend/src/views/menu/Menu.vue
  35. 156
      io.sc.platform.system.frontend/src/views/monitor/AuditLog.vue
  36. 156
      io.sc.platform.system.frontend/src/views/monitor/Log.vue
  37. 154
      io.sc.platform.system.frontend/src/views/parameter/Parameter.vue
  38. 2
      io.sc.platform.system/src/main/java/io/sc/platform/system/dictionary/jpa/entity/DictionaryEntity.java
  39. 2
      io.sc.platform.system/src/main/java/io/sc/platform/system/i18n/jpa/entity/I18nEntity.java
  40. 4
      io.sc.platform.system/src/main/java/io/sc/platform/system/i18n/service/impl/I18nServiceImpl.java
  41. 16
      io.sc.platform.system/src/main/java/io/sc/platform/system/menu/controller/MenuWebController.java
  42. 7
      io.sc.platform.system/src/main/java/io/sc/platform/system/menu/service/MenuService.java
  43. 71
      io.sc.platform.system/src/main/java/io/sc/platform/system/menu/service/impl/MenuServiceImpl.java
  44. 109
      io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/controller/LogViewerWebController.java
  45. 36
      io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/support/LogFileLastModifyDateComparator.java
  46. 25
      io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/support/LogFileNameComparator.java
  47. 38
      io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/support/LogFileSizeComparator.java
  48. 2
      io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/jpa/entity/ParameterEntity.java
  49. 1
      io.sc.platform.system/src/main/java/io/sc/platform/system/plugins/PluginManager.java
  50. 11
      io.sc.platform.system/src/main/java/io/sc/platform/system/plugins/item/MenuItem.java

4
gradle.properties

@ -36,9 +36,9 @@ application_version=1.0.0
# platform
###########################################################
platform_group=io.sc
platform_version=8.1.20
platform_version=8.1.22
platform_plugin_version=8.1.13
platform_core_frontend_version=8.1.83
platform_core_frontend_version=8.1.88
###########################################################
# dependencies version

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

@ -1,6 +1,6 @@
{
"name": "platform-core",
"version": "8.1.87",
"version": "8.1.92",
"description": "前端核心包,用于快速构建前端的脚手架",
"//main": "库的主文件",
"main": "dist/platform-core.js",

9
io.sc.platform.core.frontend/src/platform/components-ext/formater/BooleanFormater.ts

@ -21,4 +21,11 @@ const enableTagFormater = (value) => {
};
};
export { yesNoFormater, trueFalseFormater, enableTagFormater };
const successFailedTagFormater = (value) => {
return {
componentType: 'WSuccessFailedTag',
attrs: { success: value },
};
};
export { yesNoFormater, trueFalseFormater, enableTagFormater, successFailedTagFormater };

6
io.sc.platform.core.frontend/src/platform/components-ext/formater/EnumFormater.ts

@ -1,19 +1,25 @@
import type { OptionItemType } from '@/platform/types';
import { i18n } from '@/platform/plugin';
import { Tools } from '@/platform/utils';
class EnumFormater {
#enumMap = {};
constructor(options: OptionItemType[]) {
for (const option of options) {
if (!Tools.isUndefinedOrNull(option.value)) {
this.#enumMap[option.value] = option.label;
}
}
}
public formater() {
const enumMap = this.#enumMap;
return (value) => {
if (!Tools.isUndefinedOrNull(value)) {
return i18n.global.t(enumMap[value]);
}
return '';
};
}
}

6
io.sc.platform.core.frontend/src/platform/components-ext/formater/index.ts

@ -1,5 +1,5 @@
import type { EnumType } from '@/platform/types';
import { yesNoFormater, trueFalseFormater, enableTagFormater } from './BooleanFormater';
import { yesNoFormater, trueFalseFormater, enableTagFormater, successFailedTagFormater } from './BooleanFormater';
import { dateOnlyFormater } from './DatetimeFormater';
import { menuTypeFormater } from './MenuTypeFormater';
import { EnumFormater } from './EnumFormater';
@ -11,6 +11,10 @@ class Formater {
return enableTagFormater;
}
public static successTag() {
return successFailedTagFormater;
}
public static yesNo() {
return yesNoFormater;
}

11
io.sc.platform.core.frontend/src/platform/components/form/elements/WEditor.vue → io.sc.platform.core.frontend/src/platform/components/form/elements/WSelectUserText.vue

@ -2,18 +2,19 @@
<div>
<q-input
v-show="!hideIfComputed"
ref="textareaRef"
ref="textRef"
:hide-bottom-space="true"
:hide-hint="true"
:outlined="true"
:dense="true"
v-bind="attrs"
type="textarea"
type="text"
:rules="rulesComputed"
:readonly="readonlyIfComputed"
:disable="disableIfComputed"
>
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template>
</template>
</q-input>
</div>
</template>
@ -22,7 +23,7 @@
import { ref, computed, defineProps, useAttrs } from 'vue';
import { FormValidators } from '@/platform/components';
const textareaRef = ref();
const textRef = ref();
const attrs = useAttrs();
const inRules = attrs.rules;
const props = defineProps({
@ -65,8 +66,8 @@ const rulesComputed = computed(() => {
} else if (hideIfComputed.value) {
rules = [];
}
if (textareaRef?.value) {
textareaRef.value.resetValidation();
if (textRef?.value) {
textRef.value.resetValidation();
}
return rules;
});

3
io.sc.platform.core.frontend/src/platform/components/index.ts

@ -27,6 +27,7 @@ import WInfoPanel from './panel/WInfoPanel.vue';
import WGrid from './grid/WGrid.vue';
import WToolbar from './toolbar/WToolbar.vue';
import WEnableTag from './tag/WEnableTag.vue';
import WSuccessFailedTag from './tag/WSuccessFailedTag.vue';
export default {
install: (app: App) => {
@ -57,6 +58,7 @@ export default {
app.component('WGrid', WGrid);
app.component('WToolbar', WToolbar);
app.component('WEnableTag', WEnableTag);
app.component('WSuccessFailedTag', WSuccessFailedTag);
},
};
@ -83,6 +85,7 @@ export {
WGrid,
WToolbar,
WEnableTag,
WSuccessFailedTag,
};
export { PlatformIconEnum } from './utils';

13
io.sc.platform.core.frontend/src/platform/components/tag/WSuccessFailedTag.vue

@ -0,0 +1,13 @@
<template>
<div v-if="!Tools.isUndefinedOrNull(success)">
<q-chip v-if="success === true || success === 'success'" color="green" text-color="white" :label="$t('success')" dense></q-chip>
<q-chip v-if="success !== true && success !== 'success'" color="red" text-color="white" :label="$t('failed')" dense></q-chip>
</div>
</template>
<script setup lang="ts">
import { Tools } from '@/platform/utils';
const props = defineProps({
success: { type: [Boolean, String], default: true },
});
</script>

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

@ -120,6 +120,7 @@ export {
WGrid,
WTreeGrid,
WEnableTag,
WSuccessFailedTag,
} from './components';
export { PlatformIconEnum } from './components';

100
io.sc.platform.core.frontend/src/views/TreeGrid.vue

@ -1,56 +1,58 @@
<template>
<w-list-grid
:tree="true"
title="User List"
:no-action-icon="true"
:target-object-name="$t('菜单')"
:actions="[
'query',
'refresh',
'expandAll',
'selectAll',
'separator',
'add',
'clone',
'edit',
'remove',
'removeAll',
'separator',
'detail',
'addTop',
'addChild',
<w-grid
ref="auditLogGridRef"
:title="$t('system.user.grid.title')"
selection="multiple"
:data-url="Environment.apiContextPath('/api/system/monitor/auditlog')"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'message', label: $t('i18nMessage'), type: 'text' },
{ name: 'lang', label: $t('language'), type: 'select' },
{ name: 'dataComeFrom', label: $t('dataComeFrom'), type: 'select' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'view', 'export']"
:columns="[
{ width: 100, name: 'status', label: $t('status'), format: Formater.successTag() },
{ width: 60, name: 'action', label: $t('action') },
{ width: 100, name: 'startDate', label: $t('startDate') },
{ width: 60, name: 'executeTime', label: $t('executeTime') },
{ width: 80, name: 'loginName', label: $t('loginName') },
{ width: 60, name: 'httpMethod', label: $t('httpMethod') },
{ width: 200, name: 'url', label: $t('url') },
{ width: 100, name: 'ip', label: $t('ip') },
{ width: 100, name: 'className', label: $t('className') },
{ width: 100, name: 'methodName', label: $t('methodName') },
{ width: 100, name: 'oldValue', label: $t('oldValue') },
{ width: 100, name: 'newValue', label: $t('newValue') },
{ width: 100, name: 'exception', label: $t('exception') },
{ width: 100, name: 'exceptionMessage', label: $t('exceptionMessage') },
{ width: 100, name: 'exceptionStackTrace', label: $t('exceptionStackTrace') },
]"
:columns="columns"
:auto-fetch-data="true"
:data-url="Environment.apiContextPath('/api/system/menu/allMenus')"
></w-list-grid>
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'lang', label: $t('language') },
{ name: 'message', label: $t('i18nMessage') },
{ 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') },
],
},
}"
@row-click="(evt, row, index) => {}"
>
</w-grid>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment } from '@/platform';
import { Environment, axios, Formater, Options } from '@/platform';
const { t } = useI18n();
const columns = [
{
name: 'name',
required: true,
label: t('name'),
align: 'left',
field: 'name',
sortable: true,
format: (value, data) => {
return t(data.titleI18nKey);
},
},
{ name: 'type', align: 'center', label: 'type', field: 'type', sortable: true },
{ name: 'enable', label: 'enable', field: 'enable', sortable: true },
{ name: 'dataComeFrom', label: 'dataComeFrom', field: 'dataComeFrom' },
{ name: 'lastModifier', label: 'lastModifier', field: 'lastModifier' },
{ name: 'lastModifyDate', label: 'lastModifyDate', field: 'lastModifyDate' },
{ name: 'corporationCode', label: 'corporationCode', field: 'corporationCode', sortable: true },
];
const auditLogGridRef = ref();
</script>

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

@ -1,6 +1,6 @@
{
"name": "platform-core",
"version": "8.1.87",
"version": "8.1.92",
"description": "前端核心包,用于快速构建前端的脚手架",
"private": false,
"keywords": [],
@ -92,7 +92,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.87",
"platform-core": "8.1.92",
"quasar": "2.14.2",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

100
io.sc.platform.core.frontend/template-project/src/views/TreeGrid.vue

@ -1,56 +1,58 @@
<template>
<w-list-grid
:tree="true"
title="User List"
:no-action-icon="true"
:target-object-name="$t('菜单')"
:actions="[
'query',
'refresh',
'expandAll',
'selectAll',
'separator',
'add',
'clone',
'edit',
'remove',
'removeAll',
'separator',
'detail',
'addTop',
'addChild',
<w-grid
ref="auditLogGridRef"
:title="$t('system.user.grid.title')"
selection="multiple"
:data-url="Environment.apiContextPath('/api/system/monitor/auditlog')"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'message', label: $t('i18nMessage'), type: 'text' },
{ name: 'lang', label: $t('language'), type: 'select' },
{ name: 'dataComeFrom', label: $t('dataComeFrom'), type: 'select' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'view', 'export']"
:columns="[
{ width: 100, name: 'status', label: $t('status'), format: Formater.successTag() },
{ width: 60, name: 'action', label: $t('action') },
{ width: 100, name: 'startDate', label: $t('startDate') },
{ width: 60, name: 'executeTime', label: $t('executeTime') },
{ width: 80, name: 'loginName', label: $t('loginName') },
{ width: 60, name: 'httpMethod', label: $t('httpMethod') },
{ width: 200, name: 'url', label: $t('url') },
{ width: 100, name: 'ip', label: $t('ip') },
{ width: 100, name: 'className', label: $t('className') },
{ width: 100, name: 'methodName', label: $t('methodName') },
{ width: 100, name: 'oldValue', label: $t('oldValue') },
{ width: 100, name: 'newValue', label: $t('newValue') },
{ width: 100, name: 'exception', label: $t('exception') },
{ width: 100, name: 'exceptionMessage', label: $t('exceptionMessage') },
{ width: 100, name: 'exceptionStackTrace', label: $t('exceptionStackTrace') },
]"
:columns="columns"
:auto-fetch-data="true"
:data-url="Environment.apiContextPath('/api/system/menu/allMenus')"
></w-list-grid>
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'lang', label: $t('language') },
{ name: 'message', label: $t('i18nMessage') },
{ 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') },
],
},
}"
@row-click="(evt, row, index) => {}"
>
</w-grid>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment } from '@/platform';
import { Environment, axios, Formater, Options } from '@/platform';
const { t } = useI18n();
const columns = [
{
name: 'name',
required: true,
label: t('name'),
align: 'left',
field: 'name',
sortable: true,
format: (value, data) => {
return t(data.titleI18nKey);
},
},
{ name: 'type', align: 'center', label: 'type', field: 'type', sortable: true },
{ name: 'enable', label: 'enable', field: 'enable', sortable: true },
{ name: 'dataComeFrom', label: 'dataComeFrom', field: 'dataComeFrom' },
{ name: 'lastModifier', label: 'lastModifier', field: 'lastModifier' },
{ name: 'lastModifyDate', label: 'lastModifyDate', field: 'lastModifyDate' },
{ name: 'corporationCode', label: 'corporationCode', field: 'corporationCode', sortable: true },
];
const auditLogGridRef = ref();
</script>

35
io.sc.platform.core/src/main/java/io/sc/platform/core/support/FileWrapper.java

@ -1,18 +1,22 @@
package io.sc.platform.core.support;
import io.sc.platform.core.util.StringUtil;
import java.util.Date;
public class FileWrapper {
private String name;
private Date lastModified;
private String size;
private Date lastModifyDate;
private long size;
private String commaSize;
public FileWrapper(){}
public FileWrapper(String name,Date lastModified,String size){
public FileWrapper(String name,Date lastModifyDate,long size){
this.name =name;
this.lastModified =lastModified;
this.lastModifyDate =lastModifyDate;
this.size =size;
this.commaSize = StringUtil.commaStyle(size);
}
public String getName() {
@ -21,16 +25,27 @@ public class FileWrapper {
public void setName(String name) {
this.name = name;
}
public Date getLastModified() {
return lastModified;
public Date getLastModifyDate() {
return lastModifyDate;
}
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
public void setLastModifyDate(Date lastModifyDate) {
this.lastModifyDate = lastModifyDate;
}
public String getSize() {
public long getSize() {
return size;
}
public void setSize(String size) {
public void setSize(long size) {
this.size = size;
}
public String getCommaSize() {
return commaSize;
}
public void setCommaSize(String commaSize) {
this.commaSize = commaSize;
}
}

4
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words.properties

@ -115,6 +115,7 @@ query=Query
redirect=Redirect
refresh=Refresh
remove=Remove
removeAll=Remove All
reset=Reset
restore=Restore
reverse=Reverse
@ -156,4 +157,5 @@ confirmNewPassword=Confirm New Password
accountExpired=Expired
accountLocked=Locked
credentialsExpired=Credentials Expired
javascript=JavaScript
icon=Icon
i18nMessage=I18N Message

4
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_tw_CN.properties

@ -115,6 +115,7 @@ query=\u67E5\u8A62
redirect=\u91CD\u5B9A\u5411
refresh=\u5237\u65B0
remove=\u79FB\u9664
removeAll=\u79FB\u9664\u6240\u6709
reset=\u91CD\u7F6E
restore=\u6062\u5FA9
reverse=\u53CD\u8F49
@ -156,4 +157,5 @@ confirmNewPassword=\u78BA\u8A8D\u65B0\u5BC6\u78BC
accountExpired=\u904E\u671F
accountLocked=\u9396\u5B9A
credentialsExpired=\u5BC6\u78BC\u904E\u671F
javascript=JavaScript
icon=\u5716\u6A19
i18nMessage=\u591A\u8A9E\u8A00\u6D88\u606F

4
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_zh_CN.properties

@ -115,6 +115,7 @@ query=\u67E5\u8BE2
redirect=\u91CD\u5B9A\u5411
refresh=\u5237\u65B0
remove=\u79FB\u9664
removeAll=\u79FB\u9664\u6240\u6709
reset=\u91CD\u7F6E
restore=\u6062\u590D
reverse=\u53CD\u8F6C
@ -156,4 +157,5 @@ confirmNewPassword=\u786E\u8BA4\u65B0\u5BC6\u7801
accountExpired=\u8FC7\u671F
accountLocked=\u9501\u5B9A
credentialsExpired=\u5BC6\u7801\u8FC7\u671F
javascript=JavaScript
icon=\u56FE\u6807
i18nMessage=\u591A\u8BED\u8A00\u6D88\u606F

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

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.developer.frontend",
"version": "8.1.20",
"version": "8.1.22",
"description": "",
"private": false,
"keywords": [],
@ -78,7 +78,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.83",
"platform-core": "8.1.88",
"quasar": "2.14.2",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

79
io.sc.platform.developer.frontend/src/views/plugin/Menus.vue

@ -1,4 +1,79 @@
<template>
<div>Menus</div>
<w-grid
:tree="true"
dense-body
:title="$t('menu.developer.plugin.menus')"
:data-url="Environment.apiContextPath('/api/system/menu/getAllMenuPlugins')"
primary-key="id"
foreign-key="parentId"
selection="multiple"
:checkbox-selection="false"
:pageable="false"
:full-screen-button="false"
:tree-icon="
(row) => {
if (row.type === 'SEPARATOR') {
return { name: 'bi-dash-lg' };
} else if (row.type === 'ROUTE_ACTION') {
return { name: 'sym_o_crop_16_9' };
} else {
return { name: row.icon };
}
}
"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['refresh', 'separator', 'view', 'export']"
:columns="[
{
width: 400,
name: 'titleI18nKey',
label: $t('name'),
sortable: false,
format: (value, row) => {
if (row.type === 'SEPARATOR') {
return `<hr style='width:100px'/>`;
} else if (row.type === 'ROUTE_ACTION') {
return $t(row.i18nKey);
} else {
return $t(value);
}
},
},
{ width: 100, name: 'order', label: $t('order'), align: 'right', sortable: false },
{ width: '100%', name: 'configurationFileUrl', label: $t('url'), sortable: false },
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'parentId', label: $t('parentId') },
{
name: 'titleI18nKey',
label: $t('system.menu.grid.entity.titleI18nKey'),
format: (value) => {
return value;
},
},
{ name: 'icon', label: $t('icon') },
{ name: 'order', label: $t('order') },
{ name: 'javaScript', label: $t('system.menu.grid.entity.javaScript') },
{ name: 'url', label: $t('system.menu.grid.entity.url') },
{ name: 'urlOpenType', label: $t('system.menu.grid.entity.urlOpenType') },
{ name: 'routeName', label: $t('system.menu.grid.entity.routeName') },
{
name: 'routeQuery',
label: $t('system.menu.grid.entity.routeQuery'),
format: (value) => {
return JSON.stringify(value);
},
},
{ name: 'configurationFileUrl', label: $t('url') },
],
},
}"
></w-grid>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { Environment } from 'platform-core';
</script>

4
io.sc.platform.gradle/templates/pgp/app/build.gradle

@ -13,7 +13,11 @@ dependencies {
implementation (
project(":io.sc.platform.app"),
project(":io.sc.platform.developer"),
//project(":io.sc.platform.job.core"),
//project(":io.sc.platform.job.executor"),
//project(":io.sc.platform.job.manager"),
)
}

3
io.sc.platform.gradle/templates/pgp/app/src/main/java/app/platform/Application.java.txt

@ -2,12 +2,9 @@ package app.platform;
import io.sc.platform.core.ApplicationLauncher;
import io.sc.platform.core.PlatformSpringBootServletInitializer;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.WebApplicationInitializer;
import java.sql.Types;
/**
* 应用程序入口
*/

4
io.sc.platform.gradle/templates/pgp/setup/build.gradle.txt

@ -371,8 +371,6 @@ subprojects {
* pnpm sync
*----------------------------------------------------------------*/
task frontendNpmSync(type:Exec){
commandLine 'cd', '.'
/*
if(isFrontendProject(file('.')) && !project.name.contains("io.sc.platform.security.frontend")){
workingDir '.'
if(org.gradle.internal.os.OperatingSystem.current().isWindows()){
@ -386,7 +384,7 @@ subprojects {
}else{
commandLine 'cd', '.'
}
}*/
}
}
tasks.frontendNpmSync.doFirst {
if(isFrontendProject(file('.'))) {

8
io.sc.platform.gradle/templates/pgp/setup/gradle.properties

@ -36,9 +36,9 @@ application_version=1.0.0
# platform
###########################################################
platform_group=io.sc
platform_version=8.1.19
platform_version=8.1.22
platform_plugin_version=8.1.13
platform_core_frontend_version=8.1.45
platform_core_frontend_version=8.1.88
###########################################################
# dependencies version
@ -50,6 +50,7 @@ cxf_version=3.2.7
dm_hibernate_version=8.1.2.192
flowable_version=6.8.0
guava_version=31.1-jre
ipaddress_version=5.4.0
jackson_version=2.13.5
jasypt_version=2.1.2
jboss_logging_version=3.3.2.Final
@ -64,6 +65,7 @@ mybatis_version=3.5.10
opencsv_version=5.7.1
oshi_version=6.4.2
p6spy_version=3.9.1
pinyin4j_version=2.5.1
poi_ooxml_version=3.17
schemacrawler_version=16.19.11
#schemacrawler_version=14.21.02
@ -71,7 +73,7 @@ spring_boot_version=2.7.18
spring_cloud_alibaba_version=2021.0.4.0
spring_cloud_context_version=3.1.4
spring_cloud_version=2021.0.8
spring_security_oauth2_authorization_server_version=0.4.4
spring_security_oauth2_authorization_server_version=0.4.5
spring_statemachine_version=3.2.1
webjars_locator_weblogic_version=0.10
zip4j_version=2.11.5

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

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.lcdp.frontend",
"version": "8.1.20",
"version": "8.1.22",
"description": "",
"private": false,
"keywords": [],
@ -91,7 +91,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.83",
"platform-core": "8.1.88",
"quasar": "2.14.2",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

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

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.mvc.frontend",
"version": "8.1.20",
"version": "8.1.22",
"description": "",
"private": false,
"keywords": [],
@ -78,7 +78,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.83",
"platform-core": "8.1.88",
"quasar": "2.14.2",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

18
io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/support/QueryResult.java

@ -2,7 +2,9 @@ package io.sc.platform.orm.service.support;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -23,4 +25,20 @@ public class QueryResult {
return new PageImpl<T>(Collections.emptyList());
}
}
public static <T> Page<T> page(List<T> list, Pageable pageable){
if(list!=null && !list.isEmpty()) {
int page =pageable.getPageNumber();
int pageSize =pageable.getPageSize();
int total =list.size();
int first =pageSize * page;
List<T> result =new ArrayList<>();
for(int i=first;i<first+pageSize;i++){
result.add(list.get(i));
}
return new PageImpl<T>(result,pageable,total);
}else{
return new PageImpl<T>(Collections.emptyList());
}
}
}

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

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.security.frontend",
"version": "8.1.20",
"version": "8.1.22",
"description": "",
"private": false,
"keywords": [
@ -99,6 +99,6 @@
"vue-dompurify-html": "5.0.1",
"vue-i18n": "9.8.0",
"vue-router": "4.2.5",
"platform-core": "8.1.83"
"platform-core": "8.1.88"
}
}

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

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.system.frontend",
"version": "8.1.20",
"version": "8.1.22",
"description": "",
"private": false,
"keywords": [],
@ -78,7 +78,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.87",
"platform-core": "8.1.92",
"quasar": "2.14.2",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

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

@ -51,6 +51,8 @@
"system.shared.selectMenu.grid.toolbar.save":"Save",
"system.shared.selectMenu.grid.toolbar.save.tip":"Are you sure to update menus?",
"system.shared.importMenuPlugin.dialog.title": "Import Menu Plugins",
"system.corporation.grid.title":"Corporation Tree",
"system.corporation.grid.toolbar.addTop":"Add Top Corporation",
"system.corporation.grid.toolbar.addChild":"Add Child Corporation",
@ -66,19 +68,29 @@
"system.role.grid.title":"Role List",
"system.org.grid.title":"Organization Tree",
"system.org.grid.toolbar.addTop":"Add Top Org",
"system.org.grid.toolbar.addChild":"Add Child Org",
"system.menu.grid.title":"Menu Tree",
"system.menu.grid.toolbar.addTop":"Add Top Menu",
"system.menu.grid.toolbar.addChild":"Add Child Menu",
"system.menu.grid.entity.titleI18nKey":"Title i18n Key",
"system.menu.grid.entity.routeName":"Title i18n Key",
"system.menu.grid.entity.javaScript":"JavaScript",
"system.menu.grid.entity.routeName":"Route Name",
"system.menu.grid.entity.routeQuery":"Route Query",
"system.menu.grid.entity.url":"URL",
"system.menu.grid.entity.urlOpenType":"URL Open Type",
"system.announcementManager.grid.title":"Announcement List",
"system.notification.grid.title":"Messages List",
"system.i18n.grid.toolbar.removeAll.tip":"Are you sure to remove ALL i18n messages?",
"system.i18n.grid.toolbar.importAll.tip":"Are you sure to import ALL i18n messages?",
"system.monitor.log.viewer.logRows":"The Last Row Count of Log File",
"system.monitor.log.viewer.autoRefresh":"Auto Refresh(1 / 2 sec, stop after 300 times auto refreshed)",
"system.monitor.log.viewer.action.refreshNow":"Refresh",
"system.monitor.log.download.grid.title":"Log File List",
"system.monitor.log.level.grid.title":"Log Level List",
"system.monitor.log.level.entity.configuredLevel":"Configured",
"system.monitor.log.level.entity.effectiveLevel":"Effective",
"system.monitor.log.tab.view":"Log View",
"system.monitor.log.tab.download":"Log Download",

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

@ -87,17 +87,35 @@
"system.shared.selectMenu.grid.toolbar.save":"保存",
"system.shared.selectMenu.grid.toolbar.save.tip":"您确定要更新菜單吗?",
"system.shared.importMenuPlugin.dialog.title": "導入菜單插件",
"system.announcement.gridTitle":"公告列表",
"system.monitor.auditlog.gridTitle":"審計日誌列表",
"system.menu.action.addTop":"新增頂級菜單",
"system.menu.action.addChild":"新增子菜單",
"system.menu.grid.title":"菜單樹",
"system.menu.grid.entity.titleI18nKey":"標題多語言消息鍵",
"system.menu.grid.entity.javaScript":"JavaScript",
"system.menu.grid.entity.routeName":"路由名稱",
"system.menu.grid.entity.routeQuery":"路由查詢參數",
"system.menu.grid.entity.url":"URL",
"system.menu.grid.entity.urlOpenType":"URL 打開方式",
"system.announcementManager.grid.title":"公告列表",
"system.notification.grid.title":"消息列表",
"system.i18n.grid.toolbar.removeAll.tip":"您確定要刪除所有多語言消息嗎?",
"system.i18n.grid.toolbar.importAll.tip":"您確定要所導入所有多語言消息嗎?",
"system.monitor.log.viewer.logRows":"顯示日誌文件最後行數",
"system.monitor.log.viewer.autoRefresh":"自動刷新(頻率:1次/2秒,超過 300 次后停止自動刷新)",
"system.monitor.log.viewer.action.refreshNow":"刷新",
"system.monitor.log.download.grid.title":"日誌文件列表",
"system.monitor.log.level.grid.title":"日誌級別列表",
"system.monitor.log.level.entity.configuredLevel":"配置級別",
"system.monitor.log.level.entity.effectiveLevel":"生效級別",
"system.corporation.action.addTop":"新增頂級法人",
"system.corporation.action.addChild":"新增子法人",

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

@ -51,6 +51,8 @@
"system.shared.selectMenu.grid.toolbar.save":"保存",
"system.shared.selectMenu.grid.toolbar.save.tip":"您确定要更新菜单吗?",
"system.shared.importMenuPlugin.dialog.title": "导入菜单插件",
"system.corporation.grid.title":"法人树",
"system.corporation.grid.toolbar.addTop":"新增顶级法人",
"system.corporation.grid.toolbar.addChild":"新增子法人",
@ -66,18 +68,30 @@
"system.role.grid.title":"角色列表",
"system.org.grid.title":"机构树",
"system.org.grid.toolbar.addTop":"新增顶级机构",
"system.org.grid.toolbar.addChild":"新增子机构",
"system.menu.grid.title":"菜单树",
"system.menu.grid.toolbar.addTop":"新增顶级菜单",
"system.menu.grid.toolbar.addChild":"新增子菜单",
"system.menu.grid.entity.titleI18nKey":"标题多语言消息键",
"system.menu.grid.entity.javaScript":"JavaScript",
"system.menu.grid.entity.routeName":"路由名称",
"system.menu.grid.entity.routeQuery":"路由查询参数",
"system.menu.grid.entity.url":"URL",
"system.menu.grid.entity.urlOpenType":"URL 打开方式",
"system.announcementManager.grid.title":"公告列表",
"system.notification.grid.title":"消息列表",
"system.i18n.grid.toolbar.removeAll.tip":"您确定要删除所有多语言消息吗?",
"system.i18n.grid.toolbar.importAll.tip":"您确定要导入所有多语言消息吗?",
"system.monitor.log.viewer.logRows":"显示日志文件最后行数",
"system.monitor.log.viewer.autoRefresh":"自动刷新(频率:1次/2秒,超过 300 次后停止自动刷新)",
"system.monitor.log.viewer.action.refreshNow":"刷新",
"system.monitor.log.download.grid.title":"日志文件列表",
"system.monitor.log.level.grid.title":"日志级别列表",
"system.monitor.log.level.entity.configuredLevel":"配置级别",
"system.monitor.log.level.entity.effectiveLevel":"生效级别",
"system.announcement.gridTitle":"公告列表",
"system.monitor.auditlog.gridTitle":"审计日志列表",

107
io.sc.platform.system.frontend/src/views/dictionary/Dictionary.vue

@ -1,62 +1,63 @@
<template>
<div>
<platform-grid
<w-grid
ref="dictionaryGridRef"
:table-props="{ borderded: false, flat: true }"
:table-title="dictionaryConfigure.tableTitle"
:table-init-load-data="dictionaryConfigure.tableInitLoadData"
:table-row-key="dictionaryConfigure.tableRowKey"
:table-data-url="dictionaryConfigure.tableDataUrl"
:table-columns="dictionaryConfigure.tableColumns"
:table-buttons="dictionaryConfigure.tableButtons"
:add-form-props="dictionaryConfigure.addFormProps"
:table-show-sort-no="false"
:table-dense="true"
:table-row-drag="true"
:table-pagination="dictionaryConfigure.tablePagination"
@row-drag-drop-after="rowDragDropAfter"
>
</platform-grid>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment, axios } from 'platform-core';
const { t } = useI18n();
const dictionaryGridRef = ref();
const dictionaryConfigure = {
tableTitle: '数据字典列表',
tableInitLoadData: true,
tableRowKey: 'id',
tableDataUrl: Environment.apiContextPath('/api/system/dictionary'),
tablePagination: {
sortBy: 'order',
descending: false,
reqPageStart: 0,
rowsPerPage: 0,
:title="$t('system.user.grid.title')"
selection="multiple"
:data-url="Environment.apiContextPath('/api/system/dictionary')"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'dataComeFrom', label: $t('dataComeFrom'), type: 'select', options: Options.enum(DataComeFromEnum), queryOperator: 'equals' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['refresh', 'separator', 'add', 'edit', 'remove', 'separator', 'view', 'export']"
:columns="[
{ width: 200, name: 'code', label: $t('code') },
{ width: 200, name: 'value', label: $t('value') },
{ width: '100%', name: 'value', label: $t('displayValue'), format: (value) => $t(value) },
{ width: 100, name: 'order', label: $t('order'), align: 'right' },
{ width: 100, name: 'dataComeFrom', label: $t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) },
{ width: 100, name: 'lastModifier', label: $t('lastModifier') },
{ width: 100, name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.dateOnly() },
]"
:editor="{
dialog: {
width: '600px',
height: '300px',
},
tableColumns: [
{ name: 'code', label: t('code') },
{ name: 'value', label: t('value') },
{ name: 'value', label: t('displayValue'), format: (value) => t(value) },
{ name: 'order', label: t('order') },
form: {
colsNum: 1,
fields: [
{ name: 'code', label: $t('code'), type: 'text', required: true },
{ name: 'value', label: $t('value'), type: 'text', required: true },
{ name: 'order', label: $t('order') },
],
tableButtons: ['refresh', 'add', 'edit', 'delete'],
addFormProps: {
dialogInitWidth: '50%',
dialogInitHeight: '90%',
formColsNumber: 1,
formColsAuto: false,
formFields: [
{ modelName: 'code', label: t('code'), type: 'text', required: true },
{ modelName: 'value', label: t('value'), type: 'text', required: true },
{ modelName: 'order', label: t('order'), type: 'text', required: true },
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'value', label: $t('value') },
{ name: 'dataComeFrom', label: $t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) },
{ 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') },
],
},
};
}"
@row-click="(evt, row, index) => {}"
></w-grid>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Environment, axios, EnumTools, Formater, Options } from 'platform-core';
const dictionaryGridRef = ref();
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom');
const rowDragDropAfter = () => {
const rows = dictionaryGridRef.value.getRowsFun();

158
io.sc.platform.system.frontend/src/views/i18n/I18n.vue

@ -1,70 +1,102 @@
<template>
<div>
<platform-grid
<w-grid
ref="i18nGridRef"
:table-props="{ borderded: false, flat: true }"
:table-title="i18nConfigure.tableTitle"
:table-init-load-data="i18nConfigure.tableInitLoadData"
:table-row-key="i18nConfigure.tableRowKey"
:table-data-url="i18nConfigure.tableDataUrl"
:table-columns="i18nConfigure.tableColumns"
:table-buttons="i18nConfigure.tableButtons"
:add-form-props="i18nConfigure.addFormProps"
:table-show-sort-no="false"
:table-dense="true"
:table-row-drag="true"
:table-pagination="i18nConfigure.tablePagination"
>
</platform-grid>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment, axios } from 'platform-core';
const { t } = useI18n();
const Language = {
en: '英文',
zh_CN: '简体中文',
tw_CN: '繁体中文',
};
const LanguageOptions = [
{ label: '英文', value: 'en' },
{ label: '简体中文', value: 'zh_CN' },
{ label: '繁体中文', value: 'tw_CN' },
];
const i18nGridRef = ref();
const i18nConfigure = {
tableTitle: '多语言消息列表',
tableInitLoadData: true,
tableRowKey: 'id',
tableDataUrl: Environment.apiContextPath('/api/system/i18n'),
tablePagination: {
sortBy: 'code',
descending: false,
reqPageStart: 0,
rowsPerPage: 20,
:title="$t('system.user.grid.title')"
selection="multiple"
:data-url="Environment.apiContextPath('/api/system/i18n')"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'message', label: $t('i18nMessage'), type: 'text' },
{ name: 'lang', label: $t('language'), type: 'select', options: Options.enum(LanguageEnum), queryOperator: 'equals' },
{ name: 'dataComeFrom', label: $t('dataComeFrom'), type: 'select', options: Options.enum(DataComeFromEnum), queryOperator: 'equals' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'query',
'refresh',
'separator',
'add',
'clone',
'edit',
'remove',
{
name: 'deleteAll',
label: $t('deleteAll'),
icon: 'bi-trash3',
click: () => {
DialogManager.confirm($t('system.i18n.grid.toolbar.removeAll.tip'), () => {
axios.post(Environment.apiContextPath('/api/system/i18n/removeMessages')).then(() => {
NotifyManager.info($t('operationSuccess'));
i18nGridRef.refresh();
});
});
},
},
tableColumns: [
{ name: 'code', label: t('code') },
{ name: 'lang', label: t('lang'), format: (value) => Language[value] },
{ name: 'message', label: t('message') },
'separator',
{
name: 'importAll',
label: $t('import'),
icon: 'bi-arrow-right-circle',
click: () => {
DialogManager.confirm($t('system.i18n.grid.toolbar.importAll.tip'), () => {
axios.post(Environment.apiContextPath('/api/system/i18n/importMessages')).then(() => {
NotifyManager.info($t('operationSuccess'));
i18nGridRef.refresh();
});
});
},
},
'separator',
'view',
'export',
]"
:columns="[
{ name: 'code', label: $t('code') },
{ name: 'lang', label: $t('language'), format: Formater.enum(LanguageEnum) },
{ name: 'message', label: $t('i18nMessage') },
{ width: 100, name: 'dataComeFrom', label: $t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) },
{ width: 100, name: 'lastModifier', label: $t('lastModifier') },
{ width: 100, name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.dateOnly() },
]"
:editor="{
dialog: {
width: '600px',
height: '300px',
},
form: {
colsNum: 1,
fields: [
{ name: 'code', label: $t('code'), type: 'text', required: true },
{ name: 'lang', label: $t('language'), type: 'select', required: true, options: Options.enum(LanguageEnum) },
{ name: 'message', label: $t('i18nMessage'), type: 'text', required: true },
],
tableButtons: ['refresh', 'add', 'edit', 'delete'],
addFormProps: {
dialogInitWidth: '50%',
dialogInitHeight: '90%',
formColsNumber: 1,
formColsAuto: false,
formFields: [
{ modelName: 'code', label: t('code'), type: 'text', required: true },
{ modelName: 'lang', label: t('lang'), type: 'select', required: true, options: LanguageOptions },
{ modelName: 'message', label: t('message'), type: 'text', required: true },
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'lang', label: $t('language') },
{ name: 'message', label: $t('i18nMessage') },
{ 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') },
],
},
};
}"
@row-click="(evt, row, index) => {}"
></w-grid>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { axios, Environment, EnumTools, Formater, Options, DialogManager, NotifyManager } from 'platform-core';
const i18nGridRef = ref();
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom');
const LanguageEnum = await EnumTools.fetch('io.sc.platform.core.enums.Language');
</script>

135
io.sc.platform.system.frontend/src/views/menu/ImportMenuPluginDialog.vue

@ -0,0 +1,135 @@
<template>
<w-dialog
ref="dialogRef"
:title="$t('system.shared.importMenuPlugin.dialog.title')"
width="800px"
height="500px"
:can-maximize="false"
:buttons="[
{
label: $t('confirm'),
click: () => {
const ids = Tools.extractProperties(gridRef.getSelectedRows(), 'id');
emit('afterSelected', ids, dialogRef);
},
},
]"
>
<div class="px-2">
<w-grid
:tree="true"
dense-body
:data-url="Environment.apiContextPath('/api/system/menu/getAllMenuPlugins')"
primary-key="id"
foreign-key="parentId"
selection="multiple"
:checkbox-selection="true"
tick-strategy="strict"
:pageable="false"
:config-button="false"
:full-screen-button="false"
:tree-icon="
(row) => {
if (row.type === 'SEPARATOR') {
return { name: 'bi-dash-lg' };
} else if (row.type === 'ROUTE_ACTION') {
return { name: 'sym_o_crop_16_9' };
} else {
return { name: row.icon };
}
}
"
:columns="[
{
width: '100%',
name: 'titleI18nKey',
label: $t('name'),
sortable: false,
format: (value, row) => {
if (row.type === 'SEPARATOR') {
return `<hr style='width:100px'/>`;
} else if (row.type === 'ROUTE_ACTION') {
return $t(row.i18nKey);
} else {
return $t(value);
}
},
},
{ width: 100, name: 'order', label: $t('order'), align: 'right', sortable: false },
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'parentId', label: $t('parentId') },
{
name: 'titleI18nKey',
label: $t('system.menu.grid.entity.titleI18nKey'),
format: (value) => {
return value;
},
},
{ name: 'icon', label: $t('icon') },
{ name: 'order', label: $t('order') },
{ name: 'javaScript', label: $t('system.menu.grid.entity.javaScript') },
{ name: 'url', label: $t('system.menu.grid.entity.url') },
{ name: 'urlOpenType', label: $t('system.menu.grid.entity.urlOpenType') },
{ name: 'routeName', label: $t('system.menu.grid.entity.routeName') },
{
name: 'routeQuery',
label: $t('system.menu.grid.entity.routeQuery'),
format: (value) => {
return JSON.stringify(value);
},
},
{ name: 'configurationFileUrl', label: $t('url') },
],
},
}"
></w-grid>
</div>
</w-dialog>
</template>
<script setup lang="ts">
import { ref, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment, Tools, EnumTools, Options, Formater } from 'platform-core';
const props = defineProps({
opener: { type: Object, default: undefined },
fetchDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'afterSelected', ids: string[], dialogComponent: any): void;
}>();
const { t } = useI18n();
const dialogRef = ref();
const gridRef = ref();
const foreignKeyRef = ref();
const open = (foreignKey: string) => {
foreignKeyRef.value = foreignKey;
dialogRef.value.show();
nextTick(() => {
gridRef.value.refresh();
});
};
const close = () => {
dialogRef.value.hide();
};
defineExpose({
open,
close,
});
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom');
</script>

54
io.sc.platform.system.frontend/src/views/menu/Menu.vue

@ -34,7 +34,10 @@
{
name: 'import',
label: $t('import'),
click: () => {},
icon: 'bi-arrow-right-circle',
click: () => {
importMenuPluginDialogRef.open();
},
},
'separator',
'view',
@ -44,7 +47,7 @@
{
width: '100%',
name: 'titleI18nKey',
label: $t('name'),
label: $t('system.menu.grid.entity.titleI18nKey'),
sortable: false,
format: (value, row) => {
if (row.type === 'SEPARATOR') {
@ -66,33 +69,57 @@
:editor="{
dialog: {
width: '600px',
height: '550px',
height: '450px',
},
form: {
colsNum: 1,
fields: [
{ name: 'type', label: $t('type'), type: 'select', required: true, options: Options.enum(MenuTypeEnum, false) },
{ name: 'titleI18nKey', label: $t('titleI18nKey'), type: 'text', required: true },
{ name: 'type', label: $t('type'), type: 'select', required: true, options: Options.enum(MenuTypeEnum, false), defaultValue: 'GROUP' },
{ name: 'titleI18nKey', label: $t('system.menu.grid.entity.titleI18nKey'), type: 'text', required: true },
{ name: 'icon', label: $t('icon'), type: 'text' },
{ name: 'enable', label: $t('enable'), type: 'checkbox', defaultValue: true },
{ name: 'order', label: $t('order'), type: 'text' },
{
name: 'javaScript',
label: $t('javascript'),
label: $t('system.menu.grid.entity.javaScript'),
type: 'textarea',
showIf: (form) => {
return form.getFieldValue('type') === 'JAVASCRIPT';
},
},
{
name: 'routeName',
label: $t('system.menu.grid.entity.routeName'),
type: 'text',
enableIf: (row) => {
console.log(row);
showIf: (form) => {
return form.getFieldValue('type') === 'ROUTE';
},
},
{
name: 'routeQuery',
label: $t('system.menu.grid.entity.routeQuery'),
type: 'text',
showIf: (form) => {
return form.getFieldValue('type') === 'ROUTE';
},
},
{
name: 'url',
label: $t('url'),
type: 'text',
showIf: (form) => {
return form.getFieldValue('type') === 'URL';
},
},
{ name: 'routeName', label: $t('routeName'), type: 'text' },
{ name: 'routeQuery', label: $t('routeQuery'), type: 'text' },
{ name: 'url', label: $t('url'), type: 'text' },
{
name: 'urlOpenType',
label: $t('urlOpenType'),
label: $t('system.menu.grid.entity.urlOpenType'),
type: 'select',
options: Options.enum(UrlOpenTypeEnum, false),
defaultValue: 'NEW_WINDOW',
showIf: (form) => {
return form.getFieldValue('type') === 'URL';
},
},
],
},
@ -167,6 +194,7 @@
</q-tab-panels>
</div>
</template>
<ImportMenuPluginDialog ref="importMenuPluginDialogRef"></ImportMenuPluginDialog>
<AddTopMenuDialog ref="addTopMenuDialog" title="菜单" :maximized="false" width="50%" height="340px"></AddTopMenuDialog>
<AddMenuDialog ref="addMenuDialog" title="菜单" :maximized="false" width="50%" height="440px"></AddMenuDialog>
<EditMenuDialog ref="editMenuDialog" title="菜单" :maximized="false" width="50%" height="440px"></EditMenuDialog>
@ -177,6 +205,7 @@ import { ref } from 'vue';
import { Environment, axios, EnumTools, Formater, Options } from 'platform-core';
import SelectRoleGrid from '../shared/SelectRoleGrid.vue';
import SelectOrgTreeGrid from '../shared/SelectOrgTreeGrid.vue';
import ImportMenuPluginDialog from './ImportMenuPluginDialog.vue';
import AddTopMenuDialog from './AddTopMenuDialog.vue';
import AddMenuDialog from './AddMenuDialog.vue';
import EditMenuDialog from './EditMenuDialog.vue';
@ -189,6 +218,7 @@ console.log(Options.enum(UrlOpenTypeEnum, false));
const menuTreeGridRef = ref();
const roleGridRef = ref();
const orgTreeGridRef = ref();
const importMenuPluginDialogRef = ref();
const selectedTabRef = ref('role');
const currentSelectedMenuId = ref('');

156
io.sc.platform.system.frontend/src/views/monitor/AuditLog.vue

@ -1,39 +1,93 @@
<template>
<div>
<platform-grid
ref="auditlogGridRef"
:table-props="{ borderded: false, flat: true }"
:query-form-cols-number="auditlogConfigure.queryFormColsNumber"
:query-form-cols-auto="auditlogConfigure.queryFormColsAuto"
:table-title="auditlogConfigure.tableTitle"
:table-row-key="auditlogConfigure.tableRowKey"
:table-init-load-data="auditlogConfigure.tableInitLoadData"
:table-data-url="auditlogConfigure.tableDataUrl"
:table-show-sort-no="false"
:table-columns="auditlogConfigure.tableColumns"
:table-left-column-sticky-number="auditlogConfigure.tableLeftColumnStickyNumber"
:table-buttons="auditlogConfigure.tableButtons"
:query-form-fields="auditlogConfigure.queryFormFields"
:table-pagination="auditlogConfigure.tablePagination"
:add-form-props="auditlogConfigure.addFormProps"
:table-dense="false"
<w-grid
ref="auditLogGridRef"
:title="$t('system.user.grid.title')"
selection="multiple"
:data-url="Environment.apiContextPath('/api/system/monitor/auditlog')"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'message', label: $t('i18nMessage'), type: 'text' },
{ name: 'lang', label: $t('language'), type: 'select' },
{ name: 'dataComeFrom', label: $t('dataComeFrom'), type: 'select' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'view', 'export']"
:pagination="{
sortBy: 'startDate',
descending: true,
}"
:columns="[
{ width: 80, name: 'status', label: $t('status'), format: Formater.successTag() },
{
width: 60,
name: 'action',
label: $t('action'),
format: (value) => {
console.log(value);
return value ? AuditLogAction[value] : '';
},
},
{ width: 150, name: 'startDate', label: $t('startDate') },
{ width: 100, name: 'executeTime', label: $t('executeTime') },
{ width: 200, name: 'loginName', label: $t('loginName') },
{ width: 100, name: 'httpMethod', label: $t('httpMethod') },
{ width: 200, name: 'url', label: $t('url') },
{ width: 100, name: 'ip', label: $t('ip') },
{ width: 200, name: 'className', label: $t('className') },
{ width: 100, name: 'methodName', label: $t('methodName') },
{ width: 100, name: 'oldValue', label: $t('oldValue') },
{ width: 100, name: 'newValue', label: $t('newValue') },
{ width: 100, name: 'exception', label: $t('exception') },
{ width: 100, name: 'exceptionMessage', label: $t('exceptionMessage') },
{ width: 100, name: 'exceptionStackTrace', label: $t('exceptionStackTrace') },
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{
name: 'status',
label: $t('status'),
format: (value) => {
return value;
},
},
{
name: 'action',
label: $t('action'),
format: (value) => {
return value;
},
},
{ name: 'startDate', label: $t('startDate') },
{ name: 'executeTime', label: $t('executeTime') },
{ name: 'loginName', label: $t('loginName') },
{ name: 'httpMethod', label: $t('httpMethod') },
{ name: 'url', label: $t('url') },
{ name: 'ip', label: $t('ip') },
{ name: 'className', label: $t('className') },
{ name: 'methodName', label: $t('methodName') },
{ name: 'oldValue', label: $t('oldValue') },
{ name: 'newValue', label: $t('newValue') },
{ name: 'exception', label: $t('exception') },
{ name: 'exceptionMessage', label: $t('exceptionMessage') },
{ name: 'exceptionStackTrace', label: $t('exceptionStackTrace') },
],
},
}"
@row-click="(evt, row, index) => {}"
>
</platform-grid>
</div>
</w-grid>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment, axios } from 'platform-core';
import { Environment, axios, Formater, Options } from 'platform-core';
const { t } = useI18n();
const Status = {
success: t('success'),
failed: t('failed'),
};
const Actions = {
const AuditLogAction = {
'io.sc.platform.core.audit.AuditLogAction.ADD': t('io.sc.platform.core.audit.AuditLogAction.ADD'),
'io.sc.platform.core.audit.AuditLogAction.REMOVE': t('io.sc.platform.core.audit.AuditLogAction.REMOVE'),
'io.sc.platform.core.audit.AuditLogAction.UPDATE': t('io.sc.platform.core.audit.AuditLogAction.UPDATE'),
@ -44,51 +98,5 @@ const Actions = {
'io.sc.platform.core.audit.AuditLogAction.LOGOUT': t('io.sc.platform.core.audit.AuditLogAction.LOGOUT'),
};
console.log(Status);
const auditlogConfigure = {
queryFormColsNumber: 4,
queryFormColsAuto: false,
hideBottom: false,
tableInitLoadData: true,
tableLeftColumnStickyNumber: 0,
tableTitle: t('system.monitor.auditlog.gridTitle'),
tableRowKey: 'id',
tableDataUrl: Environment.apiContextPath('/api/system/monitor/auditlog'),
tablePagination: {
sortBy: 'startDate',
descending: true,
reqPageStart: 0,
rowsPerPage: 10,
},
queryFormFields: [],
tableButtons: ['view', 'inFullscreen'],
tableColumns: [
{ width: 60, name: 'status', label: t('status'), format: (value) => Status[value] },
{ width: 60, name: 'action', label: t('action'), format: (value) => Actions[value] },
{ width: 100, name: 'startDate', label: t('startDate') },
{ width: 60, name: 'executeTime', label: t('executeTime') },
{ width: 80, name: 'loginName', label: t('loginName') },
{ width: 60, name: 'httpMethod', label: t('httpMethod') },
{ width: 200, name: 'url', label: t('url') },
{ width: 100, name: 'ip', label: t('ip') },
{ width: 100, name: 'className', label: t('className') },
{ width: 100, name: 'methodName', label: t('methodName') },
{ width: 100, name: 'oldValue', label: t('oldValue') },
{ width: 100, name: 'newValue', label: t('newValue') },
{ width: 100, name: 'exception', label: t('exception') },
{ width: 100, name: 'exceptionMessage', label: t('exceptionMessage') },
{ width: 100, name: 'exceptionStackTrace', label: t('exceptionStackTrace') },
],
addFormProps: {
dialogInitWidth: '50%',
dialogInitHeight: '90%',
formColsNumber: 1,
formColsAuto: false,
formFields: [
{ modelName: 'title', label: t('title'), type: 'text', required: true },
{ modelName: 'content', label: t('content'), type: 'textarea', required: true },
],
},
};
const auditLogGridRef = ref();
</script>

156
io.sc.platform.system.frontend/src/views/monitor/Log.vue

@ -3,21 +3,21 @@
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0">
<q-tab name="view" icon="bi-receipt" :label="$t('system.monitor.log.tab.view')" />
<q-tab name="download" icon="bi-download" :label="$t('system.monitor.log.tab.download')" />
<q-tab name="level" icon="bi-123" :label="$t('system.monitor.log.tab.level')" />
<q-tab name="level" icon="bi-sort-numeric-up" :label="$t('system.monitor.log.tab.level')" />
</q-tabs>
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive>
<q-tab-panel name="view">
<div class="row q-pt-sm">
<div class="col-2">
<q-input v-model="logRows" label="显示日志文件最后行数" outlined dense />
<q-input v-model="logRows" :label="$t('system.monitor.log.viewer.logRows')" outlined dense />
</div>
<div class="col-5 q-pl-sm">
<q-checkbox v-model="autoRefresh" label="自动刷新(频率:1次/2秒,超过 300 次后停止自动刷新)" outlined dense />
<q-checkbox v-model="autoRefresh" :label="$t('system.monitor.log.viewer.autoRefresh')" outlined dense />
</div>
<div class="col-4"></div>
<div class="col-1">
<q-btn label="立即刷新" @click="refreshLog" />
<q-btn :label="$t('system.monitor.log.viewer.action.refreshNow')" @click="refresh" />
</div>
</div>
<div class="row q-pt-sm">
@ -27,43 +27,90 @@
</div>
</q-tab-panel>
<q-tab-panel name="download">
<platform-grid
<w-grid
ref="downloadGridRef"
:table-props="{ borderded: false, flat: true }"
:table-title="downloadConfigure.tableTitle"
:table-init-load-data="downloadConfigure.tableInitLoadData"
:table-row-key="downloadConfigure.tableRowKey"
:table-data-url="downloadConfigure.tableDataUrl"
:table-columns="downloadConfigure.tableColumns"
:table-buttons="downloadConfigure.tableButtons"
:table-show-sort-no="false"
:table-pagination="downloadConfigure.tablePagination"
:table-dense="false"
:title="$t('system.monitor.log.download.grid.title')"
selection="multiple"
:data-url="Environment.apiContextPath('/api/monitor/logger/getLogFiles')"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'download',
label: t('download'),
icon: 'bi-download',
click: () => {
let url = Environment.apiContextPath('/api/monitor/logger/downloadLogFile?');
url += 'fileName=' + encodeURIComponent(downloadGridRef.getSelectedRows()[0].name);
downloadIframe.src = url;
},
},
]"
:pageable="false"
dense-body
:pagination="{
sortBy: 'startDate',
descending: true,
}"
:columns="[
{ width: '100%', name: 'name', label: $t('name') },
{ width: 150, name: 'lastModifyDate', label: $t('lastModifyDate') },
{
width: 200,
name: 'size',
label: $t('size'),
align: 'right',
format: (value, row) => {
return row.commaSize;
},
},
]"
>
</platform-grid>
</w-grid>
</q-tab-panel>
<q-tab-panel name="level">
<platform-grid
<w-grid
ref="levelGridRef"
:table-props="{ borderded: false, flat: true }"
:table-title="levelConfigure.tableTitle"
:table-init-load-data="levelConfigure.tableInitLoadData"
:table-row-key="levelConfigure.tableRowKey"
:table-data-url="levelConfigure.tableDataUrl"
:table-columns="levelConfigure.tableColumns"
:table-buttons="levelConfigure.tableButtons"
:table-show-sort-no="false"
:table-pagination="levelConfigure.tablePagination"
:table-dense="true"
:title="$t('system.monitor.log.level.grid.title')"
selection="multiple"
:data-url="Environment.apiContextPath('/api/monitor/logger/getLogConfigurationLevels')"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'edit']"
dense-body
:pagination="{
sortBy: 'startDate',
descending: true,
}"
:query-form-fields="[
{ name: 'name', label: $t('name'), type: 'text' },
{ name: 'configuredLevel', label: $t('system.monitor.log.level.entity.configuredLevel'), type: 'select' },
{ name: 'effectiveLevel', label: $t('system.monitor.log.level.entity.effectiveLevel'), type: 'select' },
]"
:columns="[
{ width: 700, name: 'name', label: $t('name') },
{ width: 100, name: 'configuredLevel', label: $t('system.monitor.log.level.entity.configuredLevel') },
{ width: 100, name: 'effectiveLevel', label: $t('system.monitor.log.level.entity.effectiveLevel') },
]"
:editor="{
dialog: {
width: '600px',
height: '210px',
},
form: {
colsNum: 1,
fields: [{ name: 'effectiveLevel', label: $t('system.monitor.log.level.entity.effectiveLevel'), type: 'select' }],
},
}"
>
</platform-grid>
</w-grid>
</q-tab-panel>
</q-tab-panels>
<iframe ref="downloadIframe" src="javascript:;" style="width: 0px; height: 0px"></iframe>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { ref, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment, axios } from 'platform-core';
@ -78,54 +125,7 @@ const downloadIframe = ref();
const downloadGridRef = ref();
const levelGridRef = ref();
const downloadConfigure = {
tableTitle: '日志列表',
tableInitLoadData: true,
tablePagination: {
sortBy: 'lastModifyDate',
descending: true,
reqPageStart: 0,
rowsPerPage: 10,
},
tableRowKey: 'name',
tableDataUrl: Environment.apiContextPath('/api/monitor/logger/getLogFiles'),
tableColumns: [
{ width: 100, name: 'name', label: t('name') },
{ width: 100, name: 'lastModifyDate', label: t('lastModifyDate') },
{ width: 100, name: 'size', label: t('size') },
],
tableButtons: [
{
name: 'download',
label: t('download'),
click: () => {
let url = Environment.apiContextPath('/api/monitor/logger/downloadLogFile?');
url += 'fileName=' + encodeURIComponent(downloadGridRef.value.getSelectedRows()[0].name);
downloadIframe.value.src = url;
},
},
],
};
const levelConfigure = {
tableTitle: '日志级别列表',
tableInitLoadData: true,
tablePagination: {
sortBy: 'lastModifyDate',
descending: true,
reqPageStart: 0,
rowsPerPage: 10,
},
tableRowKey: 'name',
tableDataUrl: Environment.apiContextPath('/api/monitor/logger/getLogConfigurationLevels'),
tableColumns: [
{ width: 100, name: 'name', label: t('name') },
{ width: 100, name: 'configuredLevel', label: t('configuredLevel') },
{ width: 100, name: 'effectiveLevel', label: t('effectiveLevel') },
],
};
const refreshLog = () => {
const refresh = () => {
axios
.post(Environment.apiContextPath('/api/monitor/logger/getLogFileContents'), {
rows: logRows.value,
@ -136,6 +136,6 @@ const refreshLog = () => {
};
onMounted(() => {
refreshLog();
refresh();
});
</script>

154
io.sc.platform.system.frontend/src/views/parameter/Parameter.vue

@ -1,73 +1,91 @@
<template>
<q-splitter :model-value="70" class="w-full h-full">
<template #before>
<w-tree-grid ref="parameterTreeGridRef" title="系统参数树" label-key="code" label-i18n @update:selected="parameterSelected" />
</template>
<template #after>
<div class="row">
<div class="col-12">
<q-input v-model="code" label="代码" outlined class="p-1" />
</div>
</div>
<div class="row">
<div class="col-12">
<q-input v-model="value" label="值" outlined class="p-1" />
</div>
</div>
<div class="row">
<div class="col-12 flex justify-center q-gutter-md pt-5">
<q-btn label="保存" color="primary" outlined class="p-1" style="width: 100px" @click="save" />
</div>
</div>
<div class="row" style="height: 200px"></div>
</template>
</q-splitter>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment, axios } from 'platform-core';
const { t } = useI18n();
const parameterTreeGridRef = ref();
const id = ref('');
const code = ref('');
const value = ref('');
const parameterSelected = (target) => {
if (target) {
const node = parameterTreeGridRef.value.getNodeById(target);
id.value = node.id;
code.value = node.code;
value.value = node.value;
} else {
id.value = '';
code.value = '';
value.value = '';
<w-grid
ref="parameterTreeGridRef"
:tree="true"
dense-body
:title="$t('system.menu.grid.title')"
:data-url="Environment.apiContextPath('/api/system/parameter')"
selection="multiple"
:checkbox-selection="false"
:pageable="false"
:full-screen-button="false"
default-expand-all
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'refresh',
'separator',
'expand',
{
extend: 'edit',
enableIf: (selecteds) => {
if (selecteds && selecteds.length > 0) {
return !Tools.isUndefinedOrNull(selecteds[0].value);
}
};
return false;
},
},
'separator',
'export',
]"
:columns="[
{
width: 300,
name: 'code',
label: $t('code'),
sortable: false,
format: (value) => {
return $t(value);
},
},
{ width: '100%', name: 'value', label: $t('value'), sortable: false },
{ width: 100, name: 'dataComeFrom', label: $t('dataComeFrom'), sortable: false, format: Formater.enum(DataComeFromEnum) },
{ width: 100, name: 'lastModifier', label: $t('lastModifier'), sortable: false },
{ width: 100, name: 'lastModifyDate', label: $t('lastModifyDate'), sortable: false, format: Formater.dateOnly() },
]"
:editor="{
dialog: {
width: '600px',
height: '250px',
},
form: {
colsNum: 1,
fields: [
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'value', label: $t('value'), type: 'text' },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'type', label: $t('type') },
{ name: 'name', label: $t('name') },
{ name: 'titleI18nKey', label: $t('titleI18nKey') },
{ name: 'icon', label: $t('icon') },
{ name: 'enable', label: $t('enable') },
{ name: 'order', label: $t('order') },
{ name: 'javaScript', label: $t('javaScript') },
{ name: 'url', label: $t('url') },
{ name: 'urlOpenType', label: $t('urlOpenType') },
{ name: 'routeName', label: $t('routeName') },
{ name: 'routeQuery', label: $t('routeQuery') },
const save = () => {
const node = parameterTreeGridRef.value.getNodeById(id.value);
const data = {
id: node.id,
code: node.code,
value: value.value,
parent: node.parentId,
corporationCode: node.corporationCode,
dataComeFrom: node.dataComeFrom,
creator: node.creator,
createDate: node.createDate,
lastModifier: node.lastModifier,
lastModifyDate: node.lastModifyDate,
};
axios.put(Environment.apiContextPath('/api/system/parameter/') + id.value, data).then((response) => {});
};
{ 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') },
],
},
}"
@row-click="(evt, row, index) => {}"
></w-grid>
</template>
<script setup lang="ts">
import { Environment, Tools, EnumTools, Formater, Options } from 'platform-core';
onMounted(() => {
axios.get(Environment.apiContextPath('/api/system/parameter?pageable=false&sortBy=code')).then((response) => {
parameterTreeGridRef.value.setNodes(response.data.content);
});
});
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom');
</script>

2
io.sc.platform.system/src/main/java/io/sc/platform/system/dictionary/jpa/entity/DictionaryEntity.java

@ -47,7 +47,7 @@ public class DictionaryEntity extends CorporationAuditorEntity<DictionaryVo> {
@Override
public DictionaryVo toVo() {
DictionaryVo vo =new DictionaryVo();
CorporationAuditorEntity.toVo(vo,this);
super.toVo(vo);
vo.setId(this.getId());
vo.setCode(this.getCode());
vo.setValue(this.getValue());

2
io.sc.platform.system/src/main/java/io/sc/platform/system/i18n/jpa/entity/I18nEntity.java

@ -52,7 +52,7 @@ public class I18nEntity extends CorporationAuditorEntity<I18nVo> {
@Override
public I18nVo toVo() {
I18nVo vo =new I18nVo();
CorporationAuditorEntity.toVo(vo,this);
super.toVo(vo);
vo.setId(this.getId());
vo.setCode(this.getCode());
vo.setLang(this.getLang().toString());

4
io.sc.platform.system/src/main/java/io/sc/platform/system/i18n/service/impl/I18nServiceImpl.java

@ -42,6 +42,10 @@ public class I18nServiceImpl extends DaoServiceImpl<I18nEntity, String, I18nRepo
repository.save(obj);
}
}else{
obj =new I18nEntity();
obj.setCode(code);
obj.setLang(language);
obj.setMessage(message);
repository.save(obj);
}
}

16
io.sc.platform.system/src/main/java/io/sc/platform/system/menu/controller/MenuWebController.java

@ -14,6 +14,7 @@ import io.sc.platform.system.api.menu.MenuVo;
import io.sc.platform.system.menu.jpa.entity.MenuEntity;
import io.sc.platform.system.menu.jpa.repository.MenuRepository;
import io.sc.platform.system.menu.service.MenuService;
import io.sc.platform.system.plugins.item.MenuItem;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
@ -65,16 +66,6 @@ public class MenuWebController extends RestCrudController<MenuVo,MenuEntity,Stri
return QueryResult.emptyPage();
}
@PostMapping("addMenu")
public void addMenu(@RequestBody Map<String,String> map) throws Exception{
service.addMenu(map);
}
@PostMapping("updateMenu")
public void updateMenu(@RequestBody Map<String,String> map) throws Exception{
service.updateMenu(map);
}
/**
* 列出所有菜单树,并且将角色所拥有的菜单列表作出标记
* @param roleId 角色ID
@ -157,6 +148,11 @@ public class MenuWebController extends RestCrudController<MenuVo,MenuEntity,Stri
}
}
@GetMapping("getAllMenuPlugins")
public List<MenuItem> getAllMenuPlugins() throws Exception{
return service.getAllMenuPlugins();
}
/**
* 将菜单插件导入到菜单表中
* @param pluginIds 需要导入的菜单插件ID集合

7
io.sc.platform.system/src/main/java/io/sc/platform/system/menu/service/MenuService.java

@ -7,16 +7,12 @@ import io.sc.platform.system.api.menu.MenuVo;
import io.sc.platform.system.menu.jpa.entity.MenuEntity;
import io.sc.platform.system.menu.jpa.repository.MenuRepository;
import io.sc.platform.system.org.jpa.entity.OrgEntity;
import io.sc.platform.system.plugins.item.MenuItem;
import java.util.List;
import java.util.Map;
public interface MenuService extends DaoService<MenuEntity, String, MenuRepository> {
public void addMenu(Map<String,String> map) throws Exception;
public void updateMenu(Map<String,String> map) throws Exception;
public List<MenuEntity> getMenusByUser(String userId) throws Exception;
@ -91,6 +87,7 @@ public interface MenuService extends DaoService<MenuEntity, String, MenuReposito
*/
public void updateOrgs(CascadeMany2Many<String,String> wrapper) throws Exception;
public List<MenuItem> getAllMenuPlugins() throws Exception;
/**
* 导入菜单插件
* @param pluginIds 需要导入的菜单插件ID集合

71
io.sc.platform.system/src/main/java/io/sc/platform/system/menu/service/impl/MenuServiceImpl.java

@ -38,63 +38,6 @@ public class MenuServiceImpl extends DaoServiceImpl<MenuEntity, String, MenuRepo
private TreeBuilder<MenuEntity,String> treeBuilder =new MenuEntityTreeBuilder();
@Autowired private JdbcTemplate jdbcTemplate;
@Transactional
public void addMenu(Map<String,String> map) throws Exception{
String parentId =map.get("parentId");
if(!StringUtils.hasText(parentId)){
MenuGroupEntity entity = new MenuGroupEntity();
entity.setName(map.get("name"));
entity.setTitleI18nKey(map.get("name"));
entity.setIcon(map.get("icon"));
entity.setEnable(Boolean.parseBoolean(map.get("enable")));
entity.setOrder(Integer.parseInt(map.get("order")));
this.add(entity);
return;
}
MenuEntity parentEntity =this.findById(parentId);
if(parentEntity!=null && parentEntity instanceof MenuGroupEntity) {
MenuGroupEntity parent = (MenuGroupEntity) parentEntity;
MenuRouteEntity entity = new MenuRouteEntity();
entity.setName(map.get("name"));
entity.setTitleI18nKey(map.get("name"));
entity.setIcon(map.get("icon"));
entity.setEnable(Boolean.parseBoolean(map.get("enable")));
entity.setOrder(Integer.parseInt(map.get("order")));
entity.setRouteName(map.get("routeName"));
String routeQuery =map.get("routeQuery");
if(StringUtils.hasText(routeQuery)) {
entity.setRouteQuery(ObjectMapper4Json.getMapper().readValue(map.get("routeQuery"), new TypeReference<Map<String, String>>() {}));
}
entity.setParent(parent);
this.add(entity);
}
}
@Transactional
public void updateMenu(Map<String,String> map) throws Exception{
String id =map.get("id");
if(StringUtils.hasText(id)){
MenuEntity menuEntity =this.findById(id);
if(menuEntity!=null && menuEntity instanceof MenuRouteEntity) {
MenuRouteEntity entity = (MenuRouteEntity) menuEntity;
entity.setName(map.get("name"));
entity.setTitleI18nKey(map.get("name"));
entity.setIcon(map.get("icon"));
entity.setEnable(Boolean.parseBoolean(map.get("enable")));
entity.setOrder(Integer.parseInt(map.get("order")));
entity.setRouteName(map.get("routeName"));
String routeQuery = map.get("routeQuery");
System.out.println(routeQuery);
if (StringUtils.hasText(routeQuery)) {
entity.setRouteQuery(ObjectMapper4Json.getMapper().readValue(routeQuery, new TypeReference<Map<String, String>>() {
}));
}
repository.save(entity);
}
}
}
@Override
public List<MenuEntity> getMenusByUser(String userId) throws Exception {
if(!StringUtils.hasText(userId)){
@ -375,6 +318,20 @@ public class MenuServiceImpl extends DaoServiceImpl<MenuEntity, String, MenuRepo
repository.saveAll(entities);
}
@Override
public List<MenuItem> getAllMenuPlugins() throws Exception {
List<MenuItem> result =PluginManager.getInstance().getMenuItems();
if(result!=null && !result.isEmpty()){
result.sort(new Comparator<MenuItem>() {
@Override
public int compare(MenuItem o1, MenuItem o2) {
return o1.getOrder()-o2.getOrder();
}
});
}
return result;
}
@Override
public List<MenuVo> getAllMenus() {
List<MenuEntity> entities =jdbcTemplate.query("select * from SYS_MENU where ENABLE_=1 order by ORDER_",new MenuEntityMapper());

109
io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/controller/LogViewerWebController.java

@ -1,16 +1,22 @@
package io.sc.platform.system.monitor.controller;
import io.sc.platform.core.DirectoryManager;
import io.sc.platform.core.support.FileWrapper;
import io.sc.platform.core.support.LoggerLevelInfo;
import io.sc.platform.core.util.FileUtil;
import io.sc.platform.core.util.StringUtil;
import io.sc.platform.mvc.support.FileDownloader;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.QueryResult;
import io.sc.platform.system.monitor.support.LogFileLastModifyDateComparator;
import io.sc.platform.system.monitor.support.LogFileNameComparator;
import io.sc.platform.system.monitor.support.LogFileSizeComparator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.logging.LoggersEndpoint;
import org.springframework.boot.actuate.logging.LoggersEndpoint.LoggerLevels;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort.Order;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@ -32,23 +38,65 @@ public class LogViewerWebController {
}
@GetMapping("getLogFiles")
public Page<FileWrapper> getLogFiles() throws IOException {
public Page<FileWrapper> getLogFiles(QueryParameter queryParameter) throws IOException {
File dir =new File(DirectoryManager.getInstance().getByName("dir.log"));
File[] files =dir.listFiles();
if(files!=null && files.length>0){
List<FileWrapper> result =new ArrayList<FileWrapper>();
for(File file : files){
FileWrapper wrapper =new FileWrapper(file.getName(),new Date(file.lastModified()), StringUtil.commaStyle(file.length()));
FileWrapper wrapper =new FileWrapper(file.getName(),new Date(file.lastModified()), file.length());
result.add(wrapper);
}
if(queryParameter!=null){
Order order =queryParameter.getFirstSort();
if(order!=null){
String fieldName =order.getProperty();
boolean asc =order.isAscending();
if("name".equalsIgnoreCase(fieldName)){
if(asc){
result.sort(new LogFileNameComparator(true));
}else{
result.sort(new LogFileNameComparator(false));
}
}else if("size".equalsIgnoreCase(fieldName)){
if(asc){
result.sort(new LogFileSizeComparator(true));
}else{
result.sort(new LogFileSizeComparator(false));
}
}else if("lastModifyDate".equalsIgnoreCase(fieldName)){
if(asc){
result.sort(new LogFileLastModifyDateComparator(true));
}else{
result.sort(new LogFileLastModifyDateComparator(false));
}
}
}
}
return QueryResult.page(result);
}
return QueryResult.emptyPage();
}
@GetMapping("getLogConfigurationLevels")
public Page<LoggerLevelInfo> getLogConfigurationLevels(LoggerLevelInfo levelInfo) throws Exception{
return QueryResult.page(findLevelsFromActuator(levelInfo));
public Page<LoggerLevelInfo> getLogConfigurationLevels(QueryParameter queryParameter) throws Exception{
Map<String,Object> configurations =loggersEndpoint.loggers();
if(configurations==null){
return QueryResult.emptyPage();
}
Object o =configurations.get("loggers");
if(o==null){
return QueryResult.emptyPage();
}
List<LoggerLevelInfo> result =new ArrayList<LoggerLevelInfo>();
if(o instanceof Map){
Map<String, LoggerLevels> map =(Map<String, LoggerLevels>)o;
for(String key : map.keySet()){
LoggerLevels loggerLevels =map.get(key);
result.add(new LoggerLevelInfo(key,loggerLevels.getConfiguredLevel(),"INFO"));
}
}
return QueryResult.page(result,queryParameter.getJpaPageable());
}
/**
@ -64,61 +112,26 @@ public class LogViewerWebController {
FileDownloader.download(request, response, fileName, resource);
}
private static class FileWrapper{
private String name;
private Date lastModifyDate;
private String size;
public FileWrapper(String name,Date lastModifyDate,String size){
this.name =name;
this.lastModifyDate =lastModifyDate;
this.size =size;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getLastModifyDate() {
return lastModifyDate;
}
public void setLastModifyDate(Date lastModifyDate) {
this.lastModifyDate = lastModifyDate;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
}
public List<LoggerLevelInfo> findLevelsFromActuator(LoggerLevelInfo levelInfo) throws Exception {
public Page<LoggerLevelInfo> findLevelsFromActuator(QueryParameter queryParameter) throws Exception {
Map<String,Object> configurations =loggersEndpoint.loggers();
if(configurations==null){
return Collections.emptyList();
return QueryResult.emptyPage();
}
Object o =configurations.get("loggers");
if(o==null){
return Collections.emptyList();
return QueryResult.emptyPage();
}
List<LoggerLevelInfo> result =new ArrayList<LoggerLevelInfo>();
if(o instanceof Map){
Map<String, LoggersEndpoint.LoggerLevels> map =(Map<String, LoggersEndpoint.LoggerLevels>)o;
Map<String, LoggerLevels> map =(Map<String, LoggerLevels>)o;
for(String key : map.keySet()){
LoggersEndpoint.LoggerLevels loggerLevels =map.get(key);
LoggerLevels loggerLevels =map.get(key);
result.add(new LoggerLevelInfo(key,loggerLevels.getConfiguredLevel(),"INFO"));
}
}
return QueryResult.page(result,queryParameter.getJpaPageable());
/*
if(
!StringUtils.hasText(levelInfo.getName())
&& levelInfo.getConfiguredLevel()!=null
@ -157,5 +170,7 @@ public class LogViewerWebController {
result =filter;
}
return result;
*/
}
}

36
io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/support/LogFileLastModifyDateComparator.java

@ -0,0 +1,36 @@
package io.sc.platform.system.monitor.support;
import io.sc.platform.core.support.FileWrapper;
import java.util.Comparator;
public class LogFileLastModifyDateComparator implements Comparator<FileWrapper> {
private boolean asc =true;
public LogFileLastModifyDateComparator(){}
public LogFileLastModifyDateComparator(boolean asc){
this.asc =asc;
}
@Override
public int compare(FileWrapper o1, FileWrapper o2) {
if(asc) {
if(o1.getLastModifyDate().getTime()>o2.getLastModifyDate().getTime()){
return 1;
}else if(o1.getLastModifyDate().getTime()==o2.getLastModifyDate().getTime()){
return 0;
}else{
return -1;
}
}else{
if(o2.getLastModifyDate().getTime()>o1.getLastModifyDate().getTime()){
return 1;
}else if(o2.getLastModifyDate().getTime()==o1.getLastModifyDate().getTime()){
return 0;
}else{
return -1;
}
}
}
}

25
io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/support/LogFileNameComparator.java

@ -0,0 +1,25 @@
package io.sc.platform.system.monitor.support;
import io.sc.platform.core.support.FileWrapper;
import io.sc.platform.core.util.PinyinUtil;
import java.util.Comparator;
public class LogFileNameComparator implements Comparator<FileWrapper> {
private boolean asc =true;
public LogFileNameComparator(){}
public LogFileNameComparator(boolean asc){
this.asc =asc;
}
@Override
public int compare(FileWrapper o1, FileWrapper o2) {
if(asc) {
return PinyinUtil.compare(o1.getName(), o2.getName());
}else{
return PinyinUtil.compare(o2.getName(), o1.getName());
}
}
}

38
io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/support/LogFileSizeComparator.java

@ -0,0 +1,38 @@
package io.sc.platform.system.monitor.support;
import io.sc.platform.core.support.FileWrapper;
import io.sc.platform.core.util.PinyinUtil;
import io.sc.platform.system.api.org.OrgVo;
import java.util.Comparator;
public class LogFileSizeComparator implements Comparator<FileWrapper> {
private boolean asc =true;
public LogFileSizeComparator(){}
public LogFileSizeComparator(boolean asc){
this.asc =asc;
}
@Override
public int compare(FileWrapper o1, FileWrapper o2) {
if(asc) {
if(o1.getSize()>o2.getSize()){
return 1;
}else if(o1.getSize()==o2.getSize()){
return 0;
}else{
return -1;
}
}else{
if(o2.getSize()>o1.getSize()){
return 1;
}else if(o2.getSize()==o1.getSize()){
return 0;
}else{
return -1;
}
}
}
}

2
io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/jpa/entity/ParameterEntity.java

@ -43,7 +43,7 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> {
@Override
public ParameterVo toVo() {
ParameterVo vo =new ParameterVo();
CorporationAuditorEntity.toVo(vo,this);
super.toVo(vo);
vo.setId(this.getId());
vo.setCode(this.getCode());
vo.setValue(this.getValue());

1
io.sc.platform.system/src/main/java/io/sc/platform/system/plugins/PluginManager.java

@ -80,6 +80,7 @@ public class PluginManager {
if(menu.getId()==null){
menu.setId(UUID.randomUUID().toString());
}
menu.setConfigurationFileUrl(plugin.getFileUrl());
menuItemMap.put(menu.getId(),menu);
items.add(menu);
}

11
io.sc.platform.system/src/main/java/io/sc/platform/system/plugins/item/MenuItem.java

@ -20,6 +20,9 @@ public abstract class MenuItem {
private String icon;
private int order;
//附加属性
private String configurationFileUrl; //菜单贡献项配置文件位置
public String getId() {
return id;
}
@ -59,4 +62,12 @@ public abstract class MenuItem {
public void setOrder(int order) {
this.order = order;
}
public String getConfigurationFileUrl() {
return configurationFileUrl;
}
public void setConfigurationFileUrl(String configurationFileUrl) {
this.configurationFileUrl = configurationFileUrl;
}
}

Loading…
Cancel
Save