Browse Source

update

main
wangshaoping 9 months ago
parent
commit
dcd7c47419
  1. 2
      io.sc.platform.core.frontend/package.json
  2. 18
      io.sc.platform.core.frontend/src/platform/components/grid/WGrid.vue
  3. 121
      io.sc.platform.core.frontend/src/views/testcase/form/form.vue
  4. 102
      io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectApplicationDialog.vue
  5. 141
      io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectApplicationGrid.vue
  6. 123
      io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectMenuTreeGrid.vue
  7. 97
      io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectOrgTreeGrid.vue
  8. 102
      io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectRoleDialog.vue
  9. 141
      io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectRoleGrid.vue
  10. 106
      io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectUserDialog.vue
  11. 161
      io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectUserGrid.vue
  12. 17
      io.sc.platform.core.frontend/src/views/testcase/form/shared/UserStatusTag.vue
  13. 4
      io.sc.platform.core.frontend/template-project/package.json
  14. 2
      io.sc.platform.core.frontend/template-project/src/components/index.ts
  15. 1
      io.sc.platform.core.frontend/template-project/src/i18n/messages.json
  16. 1
      io.sc.platform.core.frontend/template-project/src/i18n/messages_tw_CN.json
  17. 1
      io.sc.platform.core.frontend/template-project/src/i18n/messages_zh_CN.json
  18. 11
      io.sc.platform.core.frontend/template-project/src/menus/menus.json
  19. 13
      io.sc.platform.core.frontend/template-project/src/routes/routes.json
  20. 449
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/form.vue
  21. 102
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectApplicationDialog.vue
  22. 141
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectApplicationGrid.vue
  23. 123
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectMenuTreeGrid.vue
  24. 97
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectOrgTreeGrid.vue
  25. 102
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectRoleDialog.vue
  26. 141
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectRoleGrid.vue
  27. 106
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectUserDialog.vue
  28. 161
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectUserGrid.vue
  29. 17
      io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/UserStatusTag.vue
  30. 4
      io.sc.platform.developer.frontend/src/views/backend/sql/Sql.vue
  31. 2
      io.sc.platform.lcdp.frontend/package.json
  32. 9
      io.sc.platform.system.api/src/main/java/io/sc/platform/system/api/menu/MenuVo.java
  33. 2
      io.sc.platform.system.frontend/package.json
  34. 14
      io.sc.platform.system.frontend/src/views/application/Application.vue
  35. 3
      io.sc.platform.system.frontend/src/views/shared/SelectMenuTreeGrid.vue
  36. 15
      io.sc.platform.system/src/main/java/io/sc/platform/system/menu/controller/MenuWebController.java
  37. 2
      io.sc.platform.system/src/main/java/io/sc/platform/system/menu/service/impl/MenuServiceImpl.java

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

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

18
io.sc.platform.core.frontend/src/platform/components/grid/WGrid.vue

@ -1519,11 +1519,11 @@ const addRowKey = (rows: []) => {
rows.forEach((item: any, index) => {
item[rowKey_] = Tools.uuid();
if (item[table.tickedField] === true) {
item['tickedCount'] = 1;
} else if (item['tickedCount'] === false) {
item['tickedCount'] = 0;
item['_tickedCount'] = 1;
} else if (item['_tickedCount'] === false) {
item['_tickedCount'] = 0;
} else {
item['tickedCount'] = 0;
item['_tickedCount'] = 0;
}
item[table.tickedField] = item[table.tickedField] || false;
item[table.selectedField] = item[table.selectedField] || false;
@ -1532,15 +1532,19 @@ const addRowKey = (rows: []) => {
}
if (props.tree && item.children && item.children.length > 0) {
addRowKey(item.children);
item['_childrenTickedCount'] = 0;
item.children.forEach((child) => {
item['tickedCount'] = child['tickedCount'] === null ? item['tickedCount'] : item['tickedCount'] + child['tickedCount'];
item['_childrenTickedCount'] += child['_tickedCount'];
});
if (item['tickedCount'] === 0) {
if (item['_childrenTickedCount'] === 0) {
item[table.tickedField] = false;
} else if (item['tickedCount'] === item.children.length) {
item['_tickedCount'] = 0;
} else if (item['_childrenTickedCount'] === item.children.length) {
item[table.tickedField] = true;
item['_tickedCount'] = 1;
} else {
item[table.tickedField] = null;
item['_tickedCount'] = 0;
}
}
});

121
io.sc.platform.core.frontend/src/views/testcase/form/form.vue

@ -1,10 +1,125 @@
<template>
<div style="height: 100%">
<w-color-input-palette v-model="colorRef"></w-color-input-palette>
<q-splitter :model-value="60" class="w-full" style="height: 100%">
<template #before>
<div class="pr-1" style="height: 100%">
<w-grid
ref="applicationGridRef"
:title="$t('system.application.grid.title')"
:config-button="true"
selection="multiple"
:checkbox-selection="true"
:data-url="Environment.apiContextPath('/api/system/application')"
:sort-by="['order']"
:query-form-cols-num="3"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'name', label: $t('name'), type: 'text' },
{ name: 'enable', label: $t('isEnable'), type: 'select', options: Options.yesNo() },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'add', 'clone', 'edit', 'remove', 'separator', 'view', 'separator', 'export']"
:columns="[
{ width: 60, name: 'order', label: $t('order') },
{ width: 100, name: 'code', label: $t('code') },
{ width: '100%', name: 'name', label: $t('name') },
{ width: 80, name: 'enable', label: $t('status'), format: Formater.enableTag() },
{ width: 120, name: 'lastModifier', label: $t('lastModifier') },
{ width: 120, 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: 'name', label: $t('name'), type: 'text', required: true },
{ name: 'description', label: $t('description'), type: 'textarea', rows: 1 },
{ name: 'order', label: $t('order'), type: 'number' },
{ name: 'enable', label: $t('enable'), type: 'checkbox', defaultValue: true },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'enable', label: $t('enable'), format: Formater.none() },
{ name: 'order', label: $t('order') },
{ 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') },
],
},
}"
@row-click="
(evt, row, index) => {
currentSelectedApplicationId = row.id;
menuTreeGridRef?.refresh();
userGridRef?.refresh();
}
"
@before-request-data="
() => {
currentSelectedApplicationId = '';
menuTreeGridRef?.refresh();
userGridRef?.refresh();
}
"
>
</w-grid>
</div>
</template>
<template #after>
<div class="pl-1" style="height: 100%">
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0" no-caps>
<q-tab name="menu" icon="bi-menu-app" :label="$t('menu')" />
</q-tabs>
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive style="height: calc(100% - 48px)">
<q-tab-panel name="menu" class="px-0 pb-0" style="height: 100%; padding-left: 0px; padding-right: 0px; padding-bottom: 0px">
<SelectMenuTreeGrid
ref="menuTreeGridRef"
:fetch-data-url="Environment.apiContextPath('/api/system/menu/listAllMenusWithSelectedStatusByApplication')"
foreign-key="applicationId"
:foreign-value="currentSelectedApplicationId"
@update="update"
></SelectMenuTreeGrid>
</q-tab-panel>
</q-tab-panels>
</div>
</template>
</q-splitter>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Environment, axios, EnumTools, Options, Formater } from '@/platform';
import SelectMenuTreeGrid from './shared/SelectMenuTreeGrid.vue';
const applicationGridRef = ref();
const userGridRef = ref();
const menuTreeGridRef = ref();
const selectedTabRef = ref('menu');
const currentSelectedApplicationId = ref('');
const colorRef = ref('#EEEEEE');
const update = (ids, gridComponent) => {
axios
.post(Environment.apiContextPath('/api/system/application/updateMenus'), {
one: applicationGridRef.value.getSelectedRows()[0].id,
many: ids,
})
.then(() => {
gridComponent.refresh();
});
};
</script>

102
io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectApplicationDialog.vue

@ -0,0 +1,102 @@
<template>
<w-dialog
ref="dialogRef"
:title="$t('system.shared.selectApplication.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" style="height: 100%">
<w-grid
ref="gridRef"
:title="$t('system.shared.selectApplication.dialog.grid.title')"
selection="multiple"
:full-screen-button="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh']"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'name', label: $t('name'), type: 'text' },
{
name: 'enable',
label: $t('enable'),
type: 'select',
options: Options.yesNo(),
queryOperator: 'equals',
},
{
name: 'dataComeFrom',
label: $t('dataComeFrom'),
type: 'select',
options: Options.enum(DataComeFromEnum),
queryOperator: 'equals',
},
]"
:auto-fetch-data="false"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:columns="[
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{
name: 'status',
label: t('status'),
format: Formater.enableTag(),
},
{ name: 'lastModifier', label: t('lastModifier') },
{ name: 'lastModifyDate', label: t('lastModifyDate') },
]"
></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>

141
io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectApplicationGrid.vue

@ -0,0 +1,141 @@
<template>
<w-grid
ref="gridRef"
:title="$t('system.shared.selectApplication.grid.title')"
:config-button="false"
selection="multiple"
:checkbox-selection="true"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:auto-fetch-data="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'selectIn',
label: $t('system.shared.selectApplication.grid.toolbar.selectIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
dialogRef.open(foreignValue);
},
},
{
name: 'selectOut',
label: $t('system.shared.selectApplication.grid.toolbar.selectOut'),
enableIf: () => {
return foreignValue && gridRef?.getSelectedRows()?.length > 0;
},
click: (arg) => {
const ids = Tools.extractProperties(arg.selecteds, 'id');
DialogManager.confirm($t('system.shared.selectApplication.grid.toolbar.selectOut.tip'), () => {
emit('selectOut', ids, gridRef);
});
},
},
'separator',
{
name: 'selectAllIn',
label: $t('system.shared.selectApplication.grid.toolbar.selectAllIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
DialogManager.confirm($t('system.shared.selectApplication.grid.toolbar.selectAllIn.tip'), () => {
emit('selectAllIn', gridRef);
});
},
},
{
name: 'selectAllOut',
label: $t('system.shared.selectApplication.grid.toolbar.selectAllOut'),
enableIf: () => {
return foreignValue && gridRef?.getRows()?.length > 0;
},
click: () => {
DialogManager.confirm($t('system.shared.selectApplication.grid.toolbar.selectAllOut.tip'), () => {
emit('selectAllOut', gridRef);
});
},
},
'separator',
'view',
]"
:columns="[
{ width: 150, name: 'code', label: $t('code') },
{ width: '100%', name: 'name', label: $t('name') },
{
width: 80,
name: 'enable',
label: $t('status'),
format: Formater.enableTag(),
},
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'enable', label: $t('enable') },
{ 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>
<SelectApplicationDialog
ref="dialogRef"
:opener="gridRef"
:fetch-data-url="fetchOtherDataUrl"
:foreign-key="foreignKey"
:foreign-value="foreignValue"
@after-selected="
(ids: string[]) => {
emit('selectIn', ids, gridRef, dialogRef);
}
"
></SelectApplicationDialog>
</template>
<script setup lang="ts">
import { ref, onUpdated } from 'vue';
import { EnumTools, DialogManager, Formater, Tools } from 'platform-core';
import SelectApplicationDialog from './SelectApplicationDialog.vue';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
fetchOtherDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'selectIn', ids: string[], gridComponent: any, dialogComponent: any): void;
(e: 'selectOut', ids: string[], gridComponent: any): void;
(e: 'selectAllIn', gridComponent: any): void;
(e: 'selectAllOut', gridComponent: any): void;
}>();
const gridRef = ref();
const dialogRef = ref();
const refresh = () => {
gridRef.value.refresh();
};
onUpdated(() => {
gridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

123
io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectMenuTreeGrid.vue

@ -0,0 +1,123 @@
<template>
<w-grid
ref="treeGridRef"
:title="$t('system.shared.selectMenu.grid.title')"
hide-bottom
:config-button="false"
:tree="true"
selection="multiple"
:checkbox-selection="true"
tree-tick-strategy="strict"
: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 };
}
}
"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:pageable="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
extend: 'expand',
enableIf: () => {
return foreignValue && treeGridRef?.getRows()?.length > 0;
},
},
{
name: 'save',
label: $t('save'),
enableIf: () => {
return foreignValue && treeGridRef?.getRows()?.length > 0;
},
click: (arg) => {
DialogManager.confirm($t('system.shared.selectMenu.grid.toolbar.save.tip'), () => {
const ids = Tools.extractProperties(arg.tickeds, 'id');
emit('update', ids, treeGridRef);
});
},
},
'separator',
'view',
]"
: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: 'enable', label: $t('status'), format: Formater.enableTag(), sortable: false },
]"
: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') },
{ 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">
import { ref, onUpdated } from 'vue';
import { DialogManager, Formater, Tools } from '@/platform';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'update', ids: string[], gridComponent: any): void;
}>();
const treeGridRef = ref();
const refresh = () => {
treeGridRef.value.refresh();
};
onUpdated(() => {
treeGridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

97
io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectOrgTreeGrid.vue

@ -0,0 +1,97 @@
<template>
<w-grid
ref="treeGridRef"
:title="$t('system.shared.selectOrg.grid.title')"
hide-bottom
:config-button="false"
:tree="true"
selection="multiple"
:checkbox-selection="true"
tree-tick-strategy="strict"
ticked-field="selected"
:tree-icon="
(row) => {
return { name: 'folder', color: 'amber' };
}
"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:pageable="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
extend: 'expand',
enableIf: () => {
return foreignValue && treeGridRef?.getRows()?.length > 0;
},
},
{
name: 'save',
label: $t('save'),
enableIf: () => {
return foreignValue && treeGridRef?.getRows()?.length > 0;
},
click: () => {
DialogManager.confirm($t('system.shared.selectOrg.grid.toolbar.save.tip'), () => {
const ids = Tools.extractProperties(treeGridRef?.getTickedRows(), 'id');
emit('update', ids, treeGridRef);
});
},
},
'separator',
'view',
]"
:columns="[
{ width: '100%', name: 'name', label: $t('name') },
{ width: 100, name: 'code', label: $t('code') },
{ width: 80, name: 'enable', label: $t('status'), format: Formater.enableTag(), sortable: false },
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'enable', label: $t('enable') },
{ 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">
import { ref, onUpdated } from 'vue';
import { Environment, DialogManager, Formater, Tools } from 'platform-core';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'update', ids: string[], gridComponent: any): void;
}>();
const treeGridRef = ref();
const refresh = () => {
treeGridRef.value.refresh();
};
onUpdated(() => {
treeGridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

102
io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectRoleDialog.vue

@ -0,0 +1,102 @@
<template>
<w-dialog
ref="dialogRef"
:title="$t('system.shared.selectRole.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" style="height: 100%">
<w-grid
ref="gridRef"
:title="$t('system.shared.selectRole.dialog.grid.title')"
selection="multiple"
:full-screen-button="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh']"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'name', label: $t('name'), type: 'text' },
{
name: 'enable',
label: $t('enable'),
type: 'select',
options: Options.yesNo(),
queryOperator: 'equals',
},
{
name: 'dataComeFrom',
label: $t('dataComeFrom'),
type: 'select',
options: Options.enum(DataComeFromEnum),
queryOperator: 'equals',
},
]"
:auto-fetch-data="false"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:columns="[
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{
name: 'status',
label: t('status'),
format: Formater.enableTag(),
},
{ name: 'lastModifier', label: t('lastModifier') },
{ name: 'lastModifyDate', label: t('lastModifyDate') },
]"
></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>

141
io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectRoleGrid.vue

@ -0,0 +1,141 @@
<template>
<w-grid
ref="gridRef"
:title="$t('system.shared.selectRole.grid.title')"
:config-button="false"
selection="multiple"
:checkbox-selection="true"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:auto-fetch-data="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'selectIn',
label: $t('system.shared.selectRole.grid.toolbar.selectIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
dialogRef.open(foreignValue);
},
},
{
name: 'selectOut',
label: $t('system.shared.selectRole.grid.toolbar.selectOut'),
enableIf: () => {
return foreignValue && gridRef?.getSelectedRows()?.length > 0;
},
click: (arg) => {
const ids = Tools.extractProperties(arg.selecteds, 'id');
DialogManager.confirm($t('system.shared.selectRole.grid.toolbar.selectOut.tip'), () => {
emit('selectOut', ids, gridRef);
});
},
},
'separator',
{
name: 'selectAllIn',
label: $t('system.shared.selectRole.grid.toolbar.selectAllIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
DialogManager.confirm($t('system.shared.selectRole.grid.toolbar.selectAllIn.tip'), () => {
emit('selectAllIn', gridRef);
});
},
},
{
name: 'selectAllOut',
label: $t('system.shared.selectRole.grid.toolbar.selectAllOut'),
enableIf: () => {
return foreignValue && gridRef?.getRows()?.length > 0;
},
click: () => {
DialogManager.confirm($t('system.shared.selectRole.grid.toolbar.selectAllOut.tip'), () => {
emit('selectAllOut', gridRef);
});
},
},
'separator',
'view',
]"
:columns="[
{ width: 150, name: 'code', label: $t('code') },
{ width: '100%', name: 'name', label: $t('name') },
{
width: 80,
name: 'enable',
label: $t('status'),
format: Formater.enableTag(),
},
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'enable', label: $t('enable') },
{ 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>
<SelectRoleDialog
ref="dialogRef"
:opener="gridRef"
:fetch-data-url="fetchOtherDataUrl"
:foreign-key="foreignKey"
:foreign-value="foreignValue"
@after-selected="
(ids: string[]) => {
emit('selectIn', ids, gridRef, dialogRef);
}
"
></SelectRoleDialog>
</template>
<script setup lang="ts">
import { ref, onUpdated } from 'vue';
import { EnumTools, DialogManager, Formater, Tools } from 'platform-core';
import SelectRoleDialog from './SelectRoleDialog.vue';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
fetchOtherDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'selectIn', ids: string[], gridComponent: any, dialogComponent: any): void;
(e: 'selectOut', ids: string[], gridComponent: any): void;
(e: 'selectAllIn', gridComponent: any): void;
(e: 'selectAllOut', gridComponent: any): void;
}>();
const gridRef = ref();
const dialogRef = ref();
const refresh = () => {
gridRef.value.refresh();
};
onUpdated(() => {
gridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

106
io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectUserDialog.vue

@ -0,0 +1,106 @@
<template>
<w-dialog
ref="dialogRef"
:title="$t('system.shared.selectUser.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" style="height: 100%">
<w-grid
ref="gridRef"
:title="$t('system.shared.selectUser.dialog.grid.title')"
selection="multiple"
:full-screen-button="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh']"
:query-form-fields="[
{ name: 'loginName', label: $t('loginName'), type: 'text' },
{ name: 'userName', label: $t('userName'), type: 'text' },
{
name: 'enable',
label: $t('enable'),
type: 'select',
options: Options.yesNo(),
queryOperator: 'equals',
},
{
name: 'dataComeFrom',
label: $t('dataComeFrom'),
type: 'select',
options: Options.enum(DataComeFromEnum),
queryOperator: 'equals',
},
]"
:auto-fetch-data="false"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:columns="[
{ width: 100, name: 'loginName', label: $t('loginName') },
{ width: 100, name: 'userName', label: $t('userName') },
{
name: 'status',
label: $t('status'),
format: (value, row) => {
return {
componentType: UserStatusTag,
attrs: row,
};
},
},
]"
></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';
import UserStatusTag from './UserStatusTag.vue';
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>

161
io.sc.platform.core.frontend/src/views/testcase/form/shared/SelectUserGrid.vue

@ -0,0 +1,161 @@
<template>
<w-grid
ref="gridRef"
:title="$t('system.shared.selectUser.grid.title')"
:config-button="false"
selection="multiple"
:checkbox-selection="true"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:auto-fetch-data="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'selectIn',
label: $t('system.shared.selectUser.grid.toolbar.selectIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
dialogRef.open(foreignValue);
},
},
{
name: 'selectOut',
label: $t('system.shared.selectUser.grid.toolbar.selectOut'),
enableIf: () => {
return foreignValue && gridRef?.getSelectedRows()?.length > 0;
},
click: (arg) => {
const ids = Tools.extractProperties(arg.selecteds, 'id');
DialogManager.confirm($t('system.shared.selectUser.grid.toolbar.selectOut.tip'), () => {
emit('selectOut', ids, gridRef);
});
},
},
'separator',
{
name: 'selectAllIn',
label: $t('system.shared.selectUser.grid.toolbar.selectAllIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
DialogManager.confirm($t('system.shared.selectUser.grid.toolbar.selectAllIn.tip'), () => {
emit('selectAllIn', gridRef);
});
},
},
{
name: 'selectAllOut',
label: $t('system.shared.selectUser.grid.toolbar.selectAllOut'),
enableIf: () => {
return foreignValue && gridRef?.getRows()?.length > 0;
},
click: () => {
DialogManager.confirm($t('system.shared.selectUser.grid.toolbar.selectAllOut.tip'), () => {
emit('selectAllOut', gridRef);
});
},
},
'separator',
'view',
]"
:columns="[
{ width: 150, name: 'loginName', label: $t('loginName') },
{ width: '100%', name: 'userName', label: $t('userName') },
{
width: 150,
name: 'enable',
label: $t('status'),
format: (value, row) => {
return {
componentType: UserStatusTag,
attrs: row,
};
},
},
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'loginName', label: $t('loginName') },
{ name: 'userName', label: $t('userName') },
{ name: 'description', label: $t('description') },
{
name: 'enable',
label: $t('enable'),
format: (value) => {
return value;
},
},
{ name: 'accountExpired', label: $t('accountExpired') },
{ name: 'accountLocked', label: $t('accountLocked') },
{ name: 'credentialsExpired', label: $t('credentialsExpired') },
{ name: 'email', label: $t('email') },
{ name: 'phone', label: $t('phone') },
{ name: 'mobile', label: $t('mobile') },
{ name: 'weixin', label: $t('weixin') },
{ name: 'qq', label: $t('qq') },
{ 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>
<SelectUserDialog
ref="dialogRef"
:opener="gridRef"
:fetch-data-url="fetchOtherDataUrl"
:foreign-key="foreignKey"
:foreign-value="foreignValue"
@after-selected="
(ids: string[]) => {
emit('selectIn', ids, gridRef, dialogRef);
}
"
></SelectUserDialog>
</template>
<script setup lang="ts">
import { ref, onUpdated } from 'vue';
import { DialogManager, Tools } from 'platform-core';
import SelectUserDialog from './SelectUserDialog.vue';
import UserStatusTag from './UserStatusTag.vue';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
fetchOtherDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'selectIn', ids: string[], gridComponent: any, dialogComponent: any): void;
(e: 'selectOut', ids: string[], gridComponent: any): void;
(e: 'selectAllIn', gridComponent: any): void;
(e: 'selectAllOut', gridComponent: any): void;
}>();
const gridRef = ref();
const dialogRef = ref();
const refresh = () => {
gridRef.value.refresh();
};
onUpdated(() => {
console.log('onUpdated....');
gridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

17
io.sc.platform.core.frontend/src/views/testcase/form/shared/UserStatusTag.vue

@ -0,0 +1,17 @@
<template>
<div>
<q-chip v-if="enable && !accountExpired && !accountLocked && !credentialsExpired" color="green" text-color="white" :label="$t('normal')" dense></q-chip>
<q-chip v-if="!enable" color="red" text-color="white" :label="$t('disable')" dense></q-chip>
<q-chip v-if="accountExpired" color="red" text-color="white" :label="$t('accountExpired')" dense></q-chip>
<q-chip v-if="accountLocked" color="red" text-color="white" :label="$t('accountLocked')" dense></q-chip>
<q-chip v-if="credentialsExpired" color="red" text-color="white" :label="$t('credentialsExpired')" dense></q-chip>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
enable: { type: Boolean, default: true },
accountExpired: { type: Boolean, default: false },
accountLocked: { type: Boolean, default: false },
credentialsExpired: { type: Boolean, default: false },
});
</script>

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

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

2
io.sc.platform.core.frontend/template-project/src/components/index.ts

@ -5,6 +5,7 @@
import component_testcase_openNoMenuRoute from '@/views/testcase/route/OpenNoMenuRoute.vue';
import component_testcase_noMenuRoute from '@/views/testcase/route/NoMenuRoute.vue';
import component_testcase_mathEditor from '@/views/testcase/math/MathEditor.vue';
import component_testcase_form from '@/views/testcase/form/form.vue';
import component_testcase_excel from '@/views/testcase/excel/Excel.vue';
import component_testcase_word from '@/views/testcase/word/Word.vue';
import component_testcase_likmDialog from '@/views/likm/Dialog.vue';
@ -21,6 +22,7 @@ const localComponents = {
'component.testcase.openNoMenuRoute': component_testcase_openNoMenuRoute,
'component.testcase.noMenuRoute': component_testcase_noMenuRoute,
'component.testcase.mathEditor': component_testcase_mathEditor,
'component.testcase.form': component_testcase_form,
'component.testcase.excel': component_testcase_excel,
'component.testcase.word': component_testcase_word,
'component.testcase.likmDialog': component_testcase_likmDialog,

1
io.sc.platform.core.frontend/template-project/src/i18n/messages.json

@ -2,6 +2,7 @@
"menu.testcase": "Test Case",
"menu.testcase.openNoMenuRoute": "Open No Menu Route",
"menu.testcase.mathEditor": "Math Formual Editor",
"menu.testcase.form":"Form Element",
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",

1
io.sc.platform.core.frontend/template-project/src/i18n/messages_tw_CN.json

@ -2,6 +2,7 @@
"menu.testcase": "測試用例",
"menu.testcase.openNoMenuRoute": "打開無關聯菜單的路由",
"menu.testcase.mathEditor": "數學公式編輯器",
"menu.testcase.form":"表單元素",
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",

1
io.sc.platform.core.frontend/template-project/src/i18n/messages_zh_CN.json

@ -2,6 +2,7 @@
"menu.testcase": "测试用例",
"menu.testcase.openNoMenuRoute": "打开无关联菜单的路由示例",
"menu.testcase.mathEditor": "数学公式编辑器",
"menu.testcase.form":"表单元素",
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",

11
io.sc.platform.core.frontend/template-project/src/menus/menus.json

@ -40,6 +40,15 @@
"type": "ROUTE",
"order": 300,
"parentId": "menu.testcase",
"id": "menu.testcase.form",
"titleI18nKey": "menu.testcase.form",
"icon": "bi-palette",
"routeName": "route.testcase.form"
},
{
"type": "ROUTE",
"order": 400,
"parentId": "menu.testcase",
"id": "menu.testcase.excel",
"titleI18nKey": "menu.testcase.excel",
"icon": "bi-palette",
@ -47,7 +56,7 @@
},
{
"type": "ROUTE",
"order": 400,
"order": 500,
"parentId": "menu.testcase",
"id": "menu.testcase.word",
"titleI18nKey": "menu.testcase.word",

13
io.sc.platform.core.frontend/template-project/src/routes/routes.json

@ -39,6 +39,19 @@
}
},
{
"name": "route.testcase.form",
"path": "testcase/form",
"parent": "/",
"priority": 0,
"component": "component.testcase.form",
"componentPath": "@/views/testcase/form/form.vue",
"redirect": null,
"meta": {
"permissions": ["/testcase/form/**/*"]
}
},
{
"name": "route.testcase.excel",
"path": "testcase/excel",

449
io.sc.platform.core.frontend/template-project/src/views/testcase/form/form.vue

@ -1,325 +1,44 @@
<template>
<div style="height: 100%">
<q-splitter :model-value="60" class="w-full" style="height: 100%">
<template #before>
<div class="pr-1" style="height: 100%">
<w-grid
:title="$t('lcdp.scheduler.task.grid.title')"
ref="applicationGridRef"
:title="$t('system.application.grid.title')"
:config-button="true"
selection="multiple"
:checkbox-selection="true"
:query-form-cols-num="12"
:data-url="Environment.apiContextPath('/api/system/application')"
:sort-by="['order']"
:query-form-cols-num="3"
:query-form-fields="[
{ colSpan: 4, name: 'name', label: $t('name'), type: 'text' },
{
colSpan: 4,
name: 'executor',
label: $t('lcdp.scheduler.task.grid.entity.executor'),
type: 'select',
clearable: true,
queryOperator: 'equals',
options: executorOptionsRef,
},
{
colSpan: 2,
name: 'status',
label: $t('status'),
type: 'select',
clearable: true,
queryOperator: 'equals',
options: Options.enum(Enums.TaskStatus),
},
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'name', label: $t('name'), type: 'text' },
{ name: 'enable', label: $t('isEnable'), type: 'select', options: Options.yesNo() },
]"
:data-url="Environment.apiContextPath('/api/scheduler/manager/task')"
:pageable="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'query',
'refresh',
'separator',
'add',
'edit',
'remove',
'separator',
{
name: 'execute',
label: $t('lcdp.scheduler.task.grid.toolbar.execute'),
icon: 'bi-caret-right-fill',
enableIf: (selecteds) => {
return selecteds && selecteds.length > 0;
},
click: () => {},
},
{
name: 'schedule',
label: $t('lcdp.scheduler.task.grid.toolbar.schedule'),
icon: 'bi-cloud-arrow-up',
enableIf: (selecteds) => {
return selecteds && selecteds.length > 0;
},
click: () => {},
},
{
name: 'log',
label: $t('lcdp.scheduler.task.grid.toolbar.log'),
icon: 'bi-receipt',
enableIf: (selecteds) => {
return selecteds && selecteds.length > 0;
},
click: () => {},
},
'separator',
'view',
'separator',
'export',
]"
:toolbar-actions="['query', 'refresh', 'separator', 'add', 'clone', 'edit', 'remove', 'separator', 'view', 'separator', 'export']"
:columns="[
{
width: 80,
name: 'status',
label: $t('status'),
align: 'center',
format: (value) => {
return {
componentType: 'QChip',
attrs: { color: value == 'RUNNING' ? 'green' : 'gray', label: Formater.enum(Enums.TaskStatus)(value), dense: true },
};
},
},
{
width: 90,
name: 'type',
label: $t('lcdp.scheduler.task.grid.entity.type'),
format: Formater.enum(Enums.TaskType),
},
{ width: 150, name: 'name', label: $t('name') },
{
width: 100,
name: 'scheduleType',
label: $t('lcdp.scheduler.task.grid.entity.scheduleType'),
format: (value, row) => {
console.log(row);
return Formater.enum(Enums.ScheduleType)(value);
},
},
{
width: 140,
name: 'triggerLastTime',
label: $t('lcdp.scheduler.task.grid.entity.triggerLastTime'),
},
{ width: 140, name: 'triggerNextTime', label: $t('lcdp.scheduler.task.grid.entity.triggerNextTime') },
{
width: 400,
name: 'executorName',
label: $t('lcdp.scheduler.task.grid.entity.executorName'),
format: (value, row) => {
return {
componentType: 'q-btn',
attrs: {
flat: true,
rounded: true,
noCaps: true,
label: row.executorApplicationName + ':' + row.executorName,
color: 'blue',
onClick: () => {
executorRegistryDialogRef.open(row);
},
},
};
},
},
{ width: 80, name: 'author', label: $t('lcdp.scheduler.task.grid.entity.author') },
{ width: 200, name: 'alarmEmail', label: $t('lcdp.scheduler.task.grid.entity.alarmEmail') },
{
width: 100,
name: 'routeStrategy',
label: $t('lcdp.scheduler.task.grid.entity.routeStrategy'),
format: (value) => {
return Formater.enum(Enums.RouteStrategy)(value);
},
},
{
width: 100,
name: 'expirationPolicy',
label: $t('lcdp.scheduler.task.grid.entity.expirationPolicy'),
format: (value) => {
return Formater.enum(Enums.ExpirationPolicy)(value);
},
},
{
width: 100,
name: 'blockStrategy',
label: $t('lcdp.scheduler.task.grid.entity.blockStrategy'),
format: (value) => {
return Formater.enum(Enums.BlockStrategy)(value);
},
},
{ width: 80, name: 'timeout', label: $t('lcdp.scheduler.task.grid.entity.timeout') },
{ width: 90, name: 'failRetryCount', label: $t('lcdp.scheduler.task.grid.entity.failRetryCount') },
{ width: 60, name: 'order', label: $t('order') },
{ width: 100, name: 'code', label: $t('code') },
{ width: '100%', name: 'name', label: $t('name') },
{ width: 80, name: 'enable', label: $t('status'), format: Formater.enableTag() },
{ width: 120, name: 'lastModifier', label: $t('lastModifier') },
{ width: 120, name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.dateOnly() },
]"
:editor="{
dialog: {
width: '800px',
width: '600px',
height: '300px',
},
form: {
colsNum: 2,
colsNum: 1,
fields: [
{
name: 'type',
label: $t('lcdp.scheduler.task.grid.entity.type'),
required: true,
type: 'select',
options: Options.enum(Enums.TaskType),
},
{
name: 'executor',
label: $t('lcdp.scheduler.task.grid.entity.executor'),
required: true,
type: 'select',
clearable: true,
options: executorOptionsRef,
},
{ colsFirst: true, name: 'name', label: $t('name'), type: 'text', required: true },
{ name: 'description', label: $t('description'), type: 'text' },
{ name: 'author', label: $t('lcdp.scheduler.task.grid.entity.author'), type: 'text' },
{ name: 'alarmEmail', label: $t('lcdp.scheduler.task.grid.entity.alarmEmail'), type: 'text' },
{
colsFirst: true,
name: 'scheduleType',
label: $t('lcdp.scheduler.task.grid.entity.scheduleType'),
required: true,
type: 'select',
options: Options.enum(Enums.ScheduleType),
defaultValue: 'FIX_RATE',
},
{
name: 'scheduleCron',
label: $t('lcdp.scheduler.task.grid.entity.scheduleCron'),
type: 'cron',
showIf: (arg) => {
return arg.form.getFieldValue('scheduleType') === 'CRON';
},
},
{
name: 'scheduleFixRate',
label: $t('lcdp.scheduler.task.grid.entity.scheduleFixRate'),
type: 'number',
showIf: (arg) => {
return arg.form.getFieldValue('scheduleType') === 'FIX_RATE';
},
},
{
name: 'scheduleFixDelay',
label: $t('lcdp.scheduler.task.grid.entity.scheduleFixDelay'),
type: 'number',
showIf: (arg) => {
return arg.form.getFieldValue('scheduleType') === 'FIX_DELAY';
},
},
{
colsFirst: true,
colSpan: 2,
name: 'bean',
label: $t('lcdp.scheduler.task.grid.entity.type.bean'),
type: 'text',
showIf: (arg) => {
return arg.form.getFieldValue('type') === 'BEAN';
},
},
{
colsFirst: true,
colSpan: 2,
name: 'groovy',
label: $t('lcdp.scheduler.task.grid.entity.type.groovy'),
type: 'code-mirror',
rows: 8,
lang: 'groovy',
showIf: (arg) => {
return arg.form.getFieldValue('type') === 'GROOVY';
},
},
{
colsFirst: true,
colSpan: 2,
name: 'shell',
label: $t('lcdp.scheduler.task.grid.entity.type.shell'),
type: 'code-mirror',
rows: 8,
lang: 'shell',
showIf: (arg) => {
return arg.form.getFieldValue('type') === 'SHELL';
},
},
{
colsFirst: true,
colSpan: 2,
name: 'python',
label: $t('lcdp.scheduler.task.grid.entity.type.python'),
type: 'code-mirror',
rows: 8,
lang: 'python',
showIf: (arg) => {
return arg.form.getFieldValue('type') === 'PYTHON';
},
},
{
colsFirst: true,
colSpan: 2,
name: 'php',
label: $t('lcdp.scheduler.task.grid.entity.type.php'),
type: 'code-mirror',
rows: 8,
lang: 'php',
showIf: (arg) => {
return arg.form.getFieldValue('type') === 'PHP';
},
},
{
colsFirst: true,
colSpan: 2,
name: 'nodejs',
label: $t('lcdp.scheduler.task.grid.entity.type.nodejs'),
type: 'code-mirror',
rows: 8,
lang: 'nodejs',
showIf: (arg) => {
return arg.form.getFieldValue('type') === 'NODEJS';
},
},
{
colsFirst: true,
colSpan: 2,
name: 'powershell',
label: $t('lcdp.scheduler.task.grid.entity.type.powershell'),
type: 'code-mirror',
rows: 8,
lang: 'powershell',
showIf: (arg) => {
return arg.form.getFieldValue('type') === 'POWERSHELL';
},
},
{ colSpan: 2, name: 'parameter', label: $t('lcdp.scheduler.task.grid.entity.parameter'), type: 'textarea', rows: 5 },
{
name: 'routeStrategy',
label: $t('lcdp.scheduler.task.grid.entity.routeStrategy'),
required: true,
type: 'select',
options: Options.enum(Enums.RouteStrategy),
defaultValue: 'FIRST',
},
{
name: 'expirationPolicy',
label: $t('lcdp.scheduler.task.grid.entity.expirationPolicy'),
required: true,
type: 'select',
options: Options.enum(Enums.ExpirationPolicy),
},
{
name: 'blockStrategy',
label: $t('lcdp.scheduler.task.grid.entity.blockStrategy'),
required: true,
type: 'select',
options: Options.enum(Enums.BlockStrategy),
},
{ colsFirst: true, name: 'timeout', label: $t('lcdp.scheduler.task.grid.entity.timeout.label'), type: 'number' },
{ name: 'failRetryCount', label: $t('lcdp.scheduler.task.grid.entity.failRetryCount.label'), type: 'number' },
{ name: 'code', label: $t('code'), type: 'text', required: true },
{ name: 'name', label: $t('name'), type: 'text', required: true },
{ name: 'description', label: $t('description'), type: 'textarea', rows: 1 },
{ name: 'order', label: $t('order'), type: 'number' },
{ name: 'enable', label: $t('enable'), type: 'checkbox', defaultValue: true },
],
},
}"
@ -328,81 +47,79 @@
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'parent', label: $t('parent') },
{ name: 'type', label: $t('lcdp.scheduler.task.grid.entity.type') },
{ name: 'executor', label: $t('lcdp.scheduler.task.grid.entity.executorId') },
{ name: 'executorName', label: $t('lcdp.scheduler.task.grid.entity.executorName') },
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'author', label: $t('lcdp.scheduler.task.grid.entity.author') },
{ name: 'alarmEmail', label: $t('lcdp.scheduler.task.grid.entity.alarmEmail') },
{ name: 'scheduleType', label: $t('lcdp.scheduler.task.grid.entity.scheduleType') },
{ name: 'scheduleConf', label: $t('lcdp.scheduler.task.grid.entity.scheduleConf') },
{ name: 'bean', label: $t('lcdp.scheduler.task.grid.entity.type.bean') },
{ name: 'groovy', label: $t('lcdp.scheduler.task.grid.entity.type.groovy') },
{ name: 'shell', label: $t('lcdp.scheduler.task.grid.entity.type.shell') },
{ name: 'python', label: $t('lcdp.scheduler.task.grid.entity.type.python') },
{ name: 'php', label: $t('lcdp.scheduler.task.grid.entity.type.php') },
{ name: 'nodejs', label: $t('lcdp.scheduler.task.grid.entity.type.nodejs') },
{ name: 'powershell', label: $t('lcdp.scheduler.task.grid.entity.type.powershell') },
{ name: 'parameter', label: $t('lcdp.scheduler.task.grid.entity.parameter') },
{ name: 'routeStrategy', label: $t('lcdp.scheduler.task.grid.entity.routeStrategy') },
{ name: 'expirationPolicy', label: $t('lcdp.scheduler.task.grid.entity.expirationPolicy') },
{ name: 'blockStrategy', label: $t('lcdp.scheduler.task.grid.entity.blockStrategy') },
{ name: 'timeout', label: $t('lcdp.scheduler.task.grid.entity.timeout') },
{ name: 'failRetryCount', label: $t('lcdp.scheduler.task.grid.entity.failRetryCount') },
{ name: 'triggerStatus', label: $t('lcdp.scheduler.task.grid.entity.triggerStatus') },
{ name: 'triggerLastTime', label: $t('lcdp.scheduler.task.grid.entity.triggerLastTime') },
{ name: 'triggerNextTime', label: $t('lcdp.scheduler.task.grid.entity.triggerNextTime') },
{ name: 'enable', label: $t('enable'), format: Formater.none() },
{ name: 'order', label: $t('order') },
{ 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>
<ExecutorRegistryDialog ref="executorRegistryDialogRef"></ExecutorRegistryDialog>
@row-click="
(evt, row, index) => {
currentSelectedApplicationId = row.id;
menuTreeGridRef?.refresh();
userGridRef?.refresh();
}
"
@before-request-data="
() => {
currentSelectedApplicationId = '';
menuTreeGridRef?.refresh();
userGridRef?.refresh();
}
"
>
</w-grid>
</div>
</template>
<template #after>
<div class="pl-1" style="height: 100%">
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0" no-caps>
<q-tab name="menu" icon="bi-menu-app" :label="$t('menu')" />
</q-tabs>
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive style="height: calc(100% - 48px)">
<q-tab-panel name="menu" class="px-0 pb-0" style="height: 100%; padding-left: 0px; padding-right: 0px; padding-bottom: 0px">
<SelectMenuTreeGrid
ref="menuTreeGridRef"
:fetch-data-url="Environment.apiContextPath('/api/system/menu/listAllMenusWithSelectedStatusByApplication')"
foreign-key="applicationId"
:foreign-value="currentSelectedApplicationId"
@update="update"
></SelectMenuTreeGrid>
</q-tab-panel>
</q-tab-panels>
</div>
</template>
</q-splitter>
</template>
<script setup lang="ts">
import { ref, inject } from 'vue';
import { axios, Environment, EnumTools, Formater, Options } from 'platform-core';
import ExecutorRegistryDialog from './ExecutorRegistryDialog.vue';
import { ref } from 'vue';
import { Environment, axios, EnumTools, Options, Formater } from '@/platform';
import SelectMenuTreeGrid from './shared/SelectMenuTreeGrid.vue';
const eventBus = inject('eventBus');
const applicationGridRef = ref();
const userGridRef = ref();
const menuTreeGridRef = ref();
const Enums = await EnumTools.fetch([
'io.sc.platform.scheduler.core.enums.RouteStrategy',
'io.sc.platform.scheduler.core.enums.ExpirationPolicy',
'io.sc.platform.scheduler.core.enums.BlockStrategy',
'io.sc.platform.scheduler.core.enums.TaskType',
'io.sc.platform.scheduler.core.enums.ScheduleType',
'io.sc.platform.scheduler.core.enums.TaskStatus',
]);
const selectedTabRef = ref('menu');
const currentSelectedApplicationId = ref('');
const executorRegistryDialogRef = ref();
const executorOptionsRef = ref([]);
const reloadExecutor = () => {
axios.get(Environment.apiContextPath('/api/scheduler/manager/executor?pageable=false')).then((response) => {
executorOptionsRef.value.splice(0, executorOptionsRef.value.length);
const list = response?.data?.content;
if (list) {
for (const item of list) {
executorOptionsRef.value.push({ label: item.applicationName + ' : ' + item.name, value: item.id });
}
}
const update = (ids, gridComponent) => {
axios
.post(Environment.apiContextPath('/api/system/application/updateMenus'), {
one: applicationGridRef.value.getSelectedRows()[0].id,
many: ids,
})
.then(() => {
gridComponent.refresh();
});
};
reloadExecutor();
</script>

102
io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectApplicationDialog.vue

@ -0,0 +1,102 @@
<template>
<w-dialog
ref="dialogRef"
:title="$t('system.shared.selectApplication.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" style="height: 100%">
<w-grid
ref="gridRef"
:title="$t('system.shared.selectApplication.dialog.grid.title')"
selection="multiple"
:full-screen-button="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh']"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'name', label: $t('name'), type: 'text' },
{
name: 'enable',
label: $t('enable'),
type: 'select',
options: Options.yesNo(),
queryOperator: 'equals',
},
{
name: 'dataComeFrom',
label: $t('dataComeFrom'),
type: 'select',
options: Options.enum(DataComeFromEnum),
queryOperator: 'equals',
},
]"
:auto-fetch-data="false"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:columns="[
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{
name: 'status',
label: t('status'),
format: Formater.enableTag(),
},
{ name: 'lastModifier', label: t('lastModifier') },
{ name: 'lastModifyDate', label: t('lastModifyDate') },
]"
></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>

141
io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectApplicationGrid.vue

@ -0,0 +1,141 @@
<template>
<w-grid
ref="gridRef"
:title="$t('system.shared.selectApplication.grid.title')"
:config-button="false"
selection="multiple"
:checkbox-selection="true"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:auto-fetch-data="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'selectIn',
label: $t('system.shared.selectApplication.grid.toolbar.selectIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
dialogRef.open(foreignValue);
},
},
{
name: 'selectOut',
label: $t('system.shared.selectApplication.grid.toolbar.selectOut'),
enableIf: () => {
return foreignValue && gridRef?.getSelectedRows()?.length > 0;
},
click: (arg) => {
const ids = Tools.extractProperties(arg.selecteds, 'id');
DialogManager.confirm($t('system.shared.selectApplication.grid.toolbar.selectOut.tip'), () => {
emit('selectOut', ids, gridRef);
});
},
},
'separator',
{
name: 'selectAllIn',
label: $t('system.shared.selectApplication.grid.toolbar.selectAllIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
DialogManager.confirm($t('system.shared.selectApplication.grid.toolbar.selectAllIn.tip'), () => {
emit('selectAllIn', gridRef);
});
},
},
{
name: 'selectAllOut',
label: $t('system.shared.selectApplication.grid.toolbar.selectAllOut'),
enableIf: () => {
return foreignValue && gridRef?.getRows()?.length > 0;
},
click: () => {
DialogManager.confirm($t('system.shared.selectApplication.grid.toolbar.selectAllOut.tip'), () => {
emit('selectAllOut', gridRef);
});
},
},
'separator',
'view',
]"
:columns="[
{ width: 150, name: 'code', label: $t('code') },
{ width: '100%', name: 'name', label: $t('name') },
{
width: 80,
name: 'enable',
label: $t('status'),
format: Formater.enableTag(),
},
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'enable', label: $t('enable') },
{ 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>
<SelectApplicationDialog
ref="dialogRef"
:opener="gridRef"
:fetch-data-url="fetchOtherDataUrl"
:foreign-key="foreignKey"
:foreign-value="foreignValue"
@after-selected="
(ids: string[]) => {
emit('selectIn', ids, gridRef, dialogRef);
}
"
></SelectApplicationDialog>
</template>
<script setup lang="ts">
import { ref, onUpdated } from 'vue';
import { EnumTools, DialogManager, Formater, Tools } from 'platform-core';
import SelectApplicationDialog from './SelectApplicationDialog.vue';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
fetchOtherDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'selectIn', ids: string[], gridComponent: any, dialogComponent: any): void;
(e: 'selectOut', ids: string[], gridComponent: any): void;
(e: 'selectAllIn', gridComponent: any): void;
(e: 'selectAllOut', gridComponent: any): void;
}>();
const gridRef = ref();
const dialogRef = ref();
const refresh = () => {
gridRef.value.refresh();
};
onUpdated(() => {
gridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

123
io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectMenuTreeGrid.vue

@ -0,0 +1,123 @@
<template>
<w-grid
ref="treeGridRef"
:title="$t('system.shared.selectMenu.grid.title')"
hide-bottom
:config-button="false"
:tree="true"
selection="multiple"
:checkbox-selection="true"
tree-tick-strategy="strict"
: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 };
}
}
"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:pageable="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
extend: 'expand',
enableIf: () => {
return foreignValue && treeGridRef?.getRows()?.length > 0;
},
},
{
name: 'save',
label: $t('save'),
enableIf: () => {
return foreignValue && treeGridRef?.getRows()?.length > 0;
},
click: (arg) => {
DialogManager.confirm($t('system.shared.selectMenu.grid.toolbar.save.tip'), () => {
const ids = Tools.extractProperties(arg.tickeds, 'id');
emit('update', ids, treeGridRef);
});
},
},
'separator',
'view',
]"
: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: 'enable', label: $t('status'), format: Formater.enableTag(), sortable: false },
]"
: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') },
{ 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">
import { ref, onUpdated } from 'vue';
import { DialogManager, Formater, Tools } from '@/platform';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'update', ids: string[], gridComponent: any): void;
}>();
const treeGridRef = ref();
const refresh = () => {
treeGridRef.value.refresh();
};
onUpdated(() => {
treeGridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

97
io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectOrgTreeGrid.vue

@ -0,0 +1,97 @@
<template>
<w-grid
ref="treeGridRef"
:title="$t('system.shared.selectOrg.grid.title')"
hide-bottom
:config-button="false"
:tree="true"
selection="multiple"
:checkbox-selection="true"
tree-tick-strategy="strict"
ticked-field="selected"
:tree-icon="
(row) => {
return { name: 'folder', color: 'amber' };
}
"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:pageable="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
extend: 'expand',
enableIf: () => {
return foreignValue && treeGridRef?.getRows()?.length > 0;
},
},
{
name: 'save',
label: $t('save'),
enableIf: () => {
return foreignValue && treeGridRef?.getRows()?.length > 0;
},
click: () => {
DialogManager.confirm($t('system.shared.selectOrg.grid.toolbar.save.tip'), () => {
const ids = Tools.extractProperties(treeGridRef?.getTickedRows(), 'id');
emit('update', ids, treeGridRef);
});
},
},
'separator',
'view',
]"
:columns="[
{ width: '100%', name: 'name', label: $t('name') },
{ width: 100, name: 'code', label: $t('code') },
{ width: 80, name: 'enable', label: $t('status'), format: Formater.enableTag(), sortable: false },
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'enable', label: $t('enable') },
{ 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">
import { ref, onUpdated } from 'vue';
import { Environment, DialogManager, Formater, Tools } from 'platform-core';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'update', ids: string[], gridComponent: any): void;
}>();
const treeGridRef = ref();
const refresh = () => {
treeGridRef.value.refresh();
};
onUpdated(() => {
treeGridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

102
io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectRoleDialog.vue

@ -0,0 +1,102 @@
<template>
<w-dialog
ref="dialogRef"
:title="$t('system.shared.selectRole.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" style="height: 100%">
<w-grid
ref="gridRef"
:title="$t('system.shared.selectRole.dialog.grid.title')"
selection="multiple"
:full-screen-button="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh']"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'name', label: $t('name'), type: 'text' },
{
name: 'enable',
label: $t('enable'),
type: 'select',
options: Options.yesNo(),
queryOperator: 'equals',
},
{
name: 'dataComeFrom',
label: $t('dataComeFrom'),
type: 'select',
options: Options.enum(DataComeFromEnum),
queryOperator: 'equals',
},
]"
:auto-fetch-data="false"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:columns="[
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{
name: 'status',
label: t('status'),
format: Formater.enableTag(),
},
{ name: 'lastModifier', label: t('lastModifier') },
{ name: 'lastModifyDate', label: t('lastModifyDate') },
]"
></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>

141
io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectRoleGrid.vue

@ -0,0 +1,141 @@
<template>
<w-grid
ref="gridRef"
:title="$t('system.shared.selectRole.grid.title')"
:config-button="false"
selection="multiple"
:checkbox-selection="true"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:auto-fetch-data="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'selectIn',
label: $t('system.shared.selectRole.grid.toolbar.selectIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
dialogRef.open(foreignValue);
},
},
{
name: 'selectOut',
label: $t('system.shared.selectRole.grid.toolbar.selectOut'),
enableIf: () => {
return foreignValue && gridRef?.getSelectedRows()?.length > 0;
},
click: (arg) => {
const ids = Tools.extractProperties(arg.selecteds, 'id');
DialogManager.confirm($t('system.shared.selectRole.grid.toolbar.selectOut.tip'), () => {
emit('selectOut', ids, gridRef);
});
},
},
'separator',
{
name: 'selectAllIn',
label: $t('system.shared.selectRole.grid.toolbar.selectAllIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
DialogManager.confirm($t('system.shared.selectRole.grid.toolbar.selectAllIn.tip'), () => {
emit('selectAllIn', gridRef);
});
},
},
{
name: 'selectAllOut',
label: $t('system.shared.selectRole.grid.toolbar.selectAllOut'),
enableIf: () => {
return foreignValue && gridRef?.getRows()?.length > 0;
},
click: () => {
DialogManager.confirm($t('system.shared.selectRole.grid.toolbar.selectAllOut.tip'), () => {
emit('selectAllOut', gridRef);
});
},
},
'separator',
'view',
]"
:columns="[
{ width: 150, name: 'code', label: $t('code') },
{ width: '100%', name: 'name', label: $t('name') },
{
width: 80,
name: 'enable',
label: $t('status'),
format: Formater.enableTag(),
},
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'enable', label: $t('enable') },
{ 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>
<SelectRoleDialog
ref="dialogRef"
:opener="gridRef"
:fetch-data-url="fetchOtherDataUrl"
:foreign-key="foreignKey"
:foreign-value="foreignValue"
@after-selected="
(ids: string[]) => {
emit('selectIn', ids, gridRef, dialogRef);
}
"
></SelectRoleDialog>
</template>
<script setup lang="ts">
import { ref, onUpdated } from 'vue';
import { EnumTools, DialogManager, Formater, Tools } from 'platform-core';
import SelectRoleDialog from './SelectRoleDialog.vue';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
fetchOtherDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'selectIn', ids: string[], gridComponent: any, dialogComponent: any): void;
(e: 'selectOut', ids: string[], gridComponent: any): void;
(e: 'selectAllIn', gridComponent: any): void;
(e: 'selectAllOut', gridComponent: any): void;
}>();
const gridRef = ref();
const dialogRef = ref();
const refresh = () => {
gridRef.value.refresh();
};
onUpdated(() => {
gridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

106
io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectUserDialog.vue

@ -0,0 +1,106 @@
<template>
<w-dialog
ref="dialogRef"
:title="$t('system.shared.selectUser.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" style="height: 100%">
<w-grid
ref="gridRef"
:title="$t('system.shared.selectUser.dialog.grid.title')"
selection="multiple"
:full-screen-button="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh']"
:query-form-fields="[
{ name: 'loginName', label: $t('loginName'), type: 'text' },
{ name: 'userName', label: $t('userName'), type: 'text' },
{
name: 'enable',
label: $t('enable'),
type: 'select',
options: Options.yesNo(),
queryOperator: 'equals',
},
{
name: 'dataComeFrom',
label: $t('dataComeFrom'),
type: 'select',
options: Options.enum(DataComeFromEnum),
queryOperator: 'equals',
},
]"
:auto-fetch-data="false"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:columns="[
{ width: 100, name: 'loginName', label: $t('loginName') },
{ width: 100, name: 'userName', label: $t('userName') },
{
name: 'status',
label: $t('status'),
format: (value, row) => {
return {
componentType: UserStatusTag,
attrs: row,
};
},
},
]"
></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';
import UserStatusTag from './UserStatusTag.vue';
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>

161
io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/SelectUserGrid.vue

@ -0,0 +1,161 @@
<template>
<w-grid
ref="gridRef"
:title="$t('system.shared.selectUser.grid.title')"
:config-button="false"
selection="multiple"
:checkbox-selection="true"
:fetch-data-url="fetchDataUrl + '?' + foreignKey + '=' + foreignValue"
:auto-fetch-data="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'selectIn',
label: $t('system.shared.selectUser.grid.toolbar.selectIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
dialogRef.open(foreignValue);
},
},
{
name: 'selectOut',
label: $t('system.shared.selectUser.grid.toolbar.selectOut'),
enableIf: () => {
return foreignValue && gridRef?.getSelectedRows()?.length > 0;
},
click: (arg) => {
const ids = Tools.extractProperties(arg.selecteds, 'id');
DialogManager.confirm($t('system.shared.selectUser.grid.toolbar.selectOut.tip'), () => {
emit('selectOut', ids, gridRef);
});
},
},
'separator',
{
name: 'selectAllIn',
label: $t('system.shared.selectUser.grid.toolbar.selectAllIn'),
enableIf: () => {
return foreignValue ? true : false;
},
click: () => {
DialogManager.confirm($t('system.shared.selectUser.grid.toolbar.selectAllIn.tip'), () => {
emit('selectAllIn', gridRef);
});
},
},
{
name: 'selectAllOut',
label: $t('system.shared.selectUser.grid.toolbar.selectAllOut'),
enableIf: () => {
return foreignValue && gridRef?.getRows()?.length > 0;
},
click: () => {
DialogManager.confirm($t('system.shared.selectUser.grid.toolbar.selectAllOut.tip'), () => {
emit('selectAllOut', gridRef);
});
},
},
'separator',
'view',
]"
:columns="[
{ width: 150, name: 'loginName', label: $t('loginName') },
{ width: '100%', name: 'userName', label: $t('userName') },
{
width: 150,
name: 'enable',
label: $t('status'),
format: (value, row) => {
return {
componentType: UserStatusTag,
attrs: row,
};
},
},
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'loginName', label: $t('loginName') },
{ name: 'userName', label: $t('userName') },
{ name: 'description', label: $t('description') },
{
name: 'enable',
label: $t('enable'),
format: (value) => {
return value;
},
},
{ name: 'accountExpired', label: $t('accountExpired') },
{ name: 'accountLocked', label: $t('accountLocked') },
{ name: 'credentialsExpired', label: $t('credentialsExpired') },
{ name: 'email', label: $t('email') },
{ name: 'phone', label: $t('phone') },
{ name: 'mobile', label: $t('mobile') },
{ name: 'weixin', label: $t('weixin') },
{ name: 'qq', label: $t('qq') },
{ 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>
<SelectUserDialog
ref="dialogRef"
:opener="gridRef"
:fetch-data-url="fetchOtherDataUrl"
:foreign-key="foreignKey"
:foreign-value="foreignValue"
@after-selected="
(ids: string[]) => {
emit('selectIn', ids, gridRef, dialogRef);
}
"
></SelectUserDialog>
</template>
<script setup lang="ts">
import { ref, onUpdated } from 'vue';
import { DialogManager, Tools } from 'platform-core';
import SelectUserDialog from './SelectUserDialog.vue';
import UserStatusTag from './UserStatusTag.vue';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
fetchOtherDataUrl: { type: String, default: '' },
foreignKey: { type: String, default: '' },
foreignValue: { type: String, default: '' },
});
const emit = defineEmits<{
(e: 'selectIn', ids: string[], gridComponent: any, dialogComponent: any): void;
(e: 'selectOut', ids: string[], gridComponent: any): void;
(e: 'selectAllIn', gridComponent: any): void;
(e: 'selectAllOut', gridComponent: any): void;
}>();
const gridRef = ref();
const dialogRef = ref();
const refresh = () => {
gridRef.value.refresh();
};
onUpdated(() => {
console.log('onUpdated....');
gridRef.value.refresh();
});
defineExpose({
refresh,
});
</script>

17
io.sc.platform.core.frontend/template-project/src/views/testcase/form/shared/UserStatusTag.vue

@ -0,0 +1,17 @@
<template>
<div>
<q-chip v-if="enable && !accountExpired && !accountLocked && !credentialsExpired" color="green" text-color="white" :label="$t('normal')" dense></q-chip>
<q-chip v-if="!enable" color="red" text-color="white" :label="$t('disable')" dense></q-chip>
<q-chip v-if="accountExpired" color="red" text-color="white" :label="$t('accountExpired')" dense></q-chip>
<q-chip v-if="accountLocked" color="red" text-color="white" :label="$t('accountLocked')" dense></q-chip>
<q-chip v-if="credentialsExpired" color="red" text-color="white" :label="$t('credentialsExpired')" dense></q-chip>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
enable: { type: Boolean, default: true },
accountExpired: { type: Boolean, default: false },
accountLocked: { type: Boolean, default: false },
credentialsExpired: { type: Boolean, default: false },
});
</script>

4
io.sc.platform.developer.frontend/src/views/backend/sql/Sql.vue

@ -1,6 +1,6 @@
<template>
<div>
<q-toolbar class="q-gutter-md py-2">
<q-toolbar class="q-gutter-md">
<q-select
v-model="valueReactive.datasource"
:label="$t('developer.backend.sql.datasource')"
@ -46,7 +46,7 @@
"
/>
</q-toolbar>
<div class="px-3">
<div class="px-3 pt-2">
<w-code-mirror label="SQL" :rows="10" lang="sql"></w-code-mirror>
</div>
<ImportExcel ref="importExcelDialogRef"></ImportExcel>

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.220",
"platform-core": "8.1.221",
"quasar": "2.15.3",
"tailwindcss": "3.4.3",
"vue": "3.4.24",

9
io.sc.platform.system.api/src/main/java/io/sc/platform/system/api/menu/MenuVo.java

@ -14,6 +14,7 @@ public abstract class MenuVo extends CorporationAuditorVo {
protected Integer order;
protected String authorizeExpression;
protected boolean selected;
protected boolean ticked;
public MenuType getType() {
return type;
@ -94,4 +95,12 @@ public abstract class MenuVo extends CorporationAuditorVo {
public void setSelected(boolean selected) {
this.selected = selected;
}
public boolean getTicked() {
return ticked;
}
public void setTicked(boolean ticked) {
this.ticked = ticked;
}
}

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.219",
"platform-core": "8.1.223",
"quasar": "2.15.3",
"tailwindcss": "3.4.3",
"vue": "3.4.24",

14
io.sc.platform.system.frontend/src/views/application/Application.vue

@ -63,14 +63,14 @@
}"
@row-click="
(evt, row, index) => {
currentSelectedRoleId = row.id;
currentSelectedApplicationId = row.id;
menuTreeGridRef?.refresh();
userGridRef?.refresh();
}
"
@before-request-data="
() => {
currentSelectedRoleId = '';
currentSelectedApplicationId = '';
menuTreeGridRef?.refresh();
userGridRef?.refresh();
}
@ -89,9 +89,9 @@
<q-tab-panel name="menu" class="px-0 pb-0" style="height: 100%; padding-left: 0px; padding-right: 0px; padding-bottom: 0px">
<SelectMenuTreeGrid
ref="menuTreeGridRef"
:fetch-data-url="Environment.apiContextPath('/api/system/menu/listAllMenusWithSelectedStatusByRole')"
foreign-key="roleId"
:foreign-value="currentSelectedRoleId"
:fetch-data-url="Environment.apiContextPath('/api/system/menu/listAllMenusWithSelectedStatusByApplication')"
foreign-key="applicationId"
:foreign-value="currentSelectedApplicationId"
@update="update"
></SelectMenuTreeGrid>
</q-tab-panel>
@ -105,14 +105,12 @@ import { ref } from 'vue';
import { Environment, axios, EnumTools, Options, Formater } from 'platform-core';
import SelectMenuTreeGrid from '../shared/SelectMenuTreeGrid.vue';
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom');
const applicationGridRef = ref();
const userGridRef = ref();
const menuTreeGridRef = ref();
const selectedTabRef = ref('menu');
const currentSelectedRoleId = ref('');
const currentSelectedApplicationId = ref('');
const update = (ids, gridComponent) => {
axios

3
io.sc.platform.system.frontend/src/views/shared/SelectMenuTreeGrid.vue

@ -8,7 +8,6 @@
selection="multiple"
:checkbox-selection="true"
tree-tick-strategy="strict"
ticked-field="selected"
:tree-icon="
(row) => {
if (row.type === 'SEPARATOR') {
@ -40,7 +39,7 @@
},
click: (arg) => {
DialogManager.confirm($t('system.shared.selectMenu.grid.toolbar.save.tip'), () => {
const ids = Tools.extractProperties(arg.selecteds, 'id');
const ids = Tools.extractProperties(arg.tickeds, 'id');
emit('update', ids, treeGridRef);
});
},

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

@ -96,6 +96,21 @@ public class MenuWebController extends RestCrudController<MenuVo,MenuEntity,Stri
return QueryResult.emptyList();
}
/**
* 列出所有菜单树,并且将应用所拥有的菜单列表作出标记
* @param applicationId 应用ID
* @param queryParameter 查询参数
* @return 列出所有菜单树,并且将应用所拥有的菜单列表作出标记
* @throws Exception 违例
*/
@GetMapping("listAllMenusWithSelectedStatusByApplication")
public List<MenuVo> listAllMenusWithSelectedStatusByApplication(@RequestParam(name="applicationId",required=false) String applicationId, QueryParameter queryParameter) throws Exception{
if(StringUtils.hasText(applicationId)){
return service.listAllMenusWithSelectedStatusByApplication(applicationId,queryParameter);
}
return QueryResult.emptyList();
}
/**
* 给菜单添加角色
* @param wrapper 具有级联关系的菜单和角色关系封装器, 由于菜单具有级联关系(如果某个角色拥有一个子菜单的访问权限,那么该角色同时拥有该子菜单所有父菜单分类的访问权限)

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

@ -210,7 +210,7 @@ public class MenuServiceImpl extends DaoServiceImpl<MenuEntity, String, MenuRepo
}
for (MenuVo allMenu : allMenus) {
if (selectedMenuIds.contains(allMenu.getId())) {
allMenu.setSelected(true);
allMenu.setTicked(true);
}
}
return allMenus;

Loading…
Cancel
Save