Browse Source

修复优化以下问题:

1、dbClickOperation修改为配置按钮的name,触发事件为按钮的click。
2、表格第一列选择框全选只有勾选未选中与勾选单条行为不一致。
3、提供表格编辑模式,双击或者点击按钮直接在表格上编辑。
main
likunming 7 months ago
parent
commit
14568bc9f9
  1. 14
      io.sc.platform.core.frontend/src/platform/components/dialog/WDialog.vue
  2. 18
      io.sc.platform.core.frontend/src/platform/components/form/elements/WCheckbox.vue
  3. 5
      io.sc.platform.core.frontend/src/platform/components/form/elements/WCodeMirror.vue
  4. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WColorInput.vue
  5. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WColorInputPalette.vue
  6. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WCron.vue
  7. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WDate.vue
  8. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WFile.vue
  9. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WIcon.vue
  10. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WNumber.vue
  11. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WPassword.vue
  12. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WPosition.vue
  13. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WSelect.vue
  14. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WSelectUserText.vue
  15. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WText.vue
  16. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WTextBtn.vue
  17. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WTextarea.vue
  18. 8
      io.sc.platform.core.frontend/src/platform/components/form/elements/WTreeSelect.vue
  19. 351
      io.sc.platform.core.frontend/src/platform/components/grid/GridBody.vue
  20. 44
      io.sc.platform.core.frontend/src/platform/components/grid/GridConfig.vue
  21. 324
      io.sc.platform.core.frontend/src/platform/components/grid/GridEditToolbar.vue
  22. 227
      io.sc.platform.core.frontend/src/platform/components/grid/GridEditor.vue
  23. 539
      io.sc.platform.core.frontend/src/platform/components/grid/GridHeader.vue
  24. 73
      io.sc.platform.core.frontend/src/platform/components/grid/GridPagination.vue
  25. 77
      io.sc.platform.core.frontend/src/platform/components/grid/GridTd.vue
  26. 654
      io.sc.platform.core.frontend/src/platform/components/grid/GridTop.vue
  27. 100
      io.sc.platform.core.frontend/src/platform/components/grid/GridView.vue
  28. 201
      io.sc.platform.core.frontend/src/platform/components/grid/TreeGridRow.vue
  29. 2414
      io.sc.platform.core.frontend/src/platform/components/grid/WGrid.vue
  30. 39
      io.sc.platform.core.frontend/src/platform/components/grid/WTreeGrid.vue
  31. 645
      io.sc.platform.core.frontend/src/platform/components/grid/css/grid.css
  32. 59
      io.sc.platform.core.frontend/src/platform/components/grid/ts/grid.ts
  33. 12
      io.sc.platform.core.frontend/src/platform/components/index.ts
  34. 4
      io.sc.platform.core.frontend/src/platform/components/toolbar/WToolbar.vue
  35. 69
      io.sc.platform.core.frontend/src/platform/components/utils/commUtil.ts
  36. 334
      io.sc.platform.core.frontend/src/platform/components/utils/componentComm.ts
  37. 12
      io.sc.platform.core.frontend/src/platform/components/utils/index.ts
  38. 12
      io.sc.platform.core.frontend/src/platform/index.ts
  39. 54
      io.sc.platform.core.frontend/src/views/likm/Grid.vue
  40. 18
      io.sc.platform.core.frontend/src/views/likm/GridForamt.vue
  41. 801
      io.sc.platform.core.frontend/src/views/likm/QuasarGrid.vue
  42. 32
      io.sc.platform.core.frontend/src/views/likm/TreeGrid.vue
  43. 178
      io.sc.platform.core.frontend/template-project/src/views/testcase/math/MathEditorForm.vue

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

@ -56,7 +56,7 @@
</template>
<script setup lang="ts">
import { ref, reactive, useAttrs } from 'vue';
import { ref, reactive, useAttrs, watch } from 'vue';
import { useQuasar } from 'quasar';
const attrs = useAttrs();
@ -81,6 +81,13 @@ const dialog = reactive({
show: false,
maximized: attrs.maximized || false,
});
const titleRef = ref(props.title);
watch(
() => props.title,
(newVal, oldVal) => {
titleRef.value = newVal;
},
);
const maximizeBtnClick = () => {
dialog.maximized = !dialog.maximized;
@ -145,9 +152,14 @@ const getContent = () => {
return null;
};
const setTitle = (title) => {
titleRef.value = title;
};
defineExpose({
show,
hide,
getContent,
setTitle,
});
</script>

18
io.sc.platform.core.frontend/src/platform/components/form/elements/WCheckbox.vue

@ -1,13 +1,6 @@
<template>
<div v-show="showIfComputed">
<q-checkbox
v-model="checkboxValue"
v-bind="attrs"
:rules="rulesComputed"
:disable="disableIfComputed"
@update:model-value="updateModelValue"
@change="changeValue"
></q-checkbox>
<q-checkbox v-model="checkboxValue" v-bind="attrs" :disable="disableIfComputed" @update:model-value="updateModelValue" @change="changeValue"></q-checkbox>
</div>
</template>
@ -15,7 +8,6 @@
import { computed, useAttrs, ref, watch } from 'vue';
const attrs = useAttrs();
const rules = attrs.rules;
const props = defineProps({
onChange: {
type: Function,
@ -48,14 +40,6 @@ watch(
},
);
const rulesComputed = computed(() => {
let result = rules || <any>[];
if (!showIfComputed.value) {
result = [];
}
return result;
});
const showIfComputed = computed(() => {
return props.showIf({
value: checkboxValue.value,

5
io.sc.platform.core.frontend/src/platform/components/form/elements/WCodeMirror.vue

@ -376,9 +376,14 @@ const buttonClick = (button) => {
}
};
const validate = () => {
return fieldRef.value.validate();
};
defineExpose({
getValue,
setValue,
configure,
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WColorInput.vue

@ -194,4 +194,12 @@ const restoreDefaultValue = () => {
colorValueRef.value = restoreValue;
emit('update:modelValue', restoreValue, props.form);
};
const validate = () => {
return colorRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WColorInputPalette.vue

@ -429,4 +429,12 @@ const restoreDefaultValue = () => {
colorValueRef.value = restoreValue;
emit('update:modelValue', restoreValue, props.form);
};
const validate = () => {
return colorRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WCron.vue

@ -207,4 +207,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return cronRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WDate.vue

@ -150,4 +150,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return dateRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WFile.vue

@ -134,4 +134,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return fileRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WIcon.vue

@ -267,4 +267,12 @@ const show = () => {
searchRef.value = '';
document.getElementById(valueRef.value)?.scrollIntoView(true);
};
const validate = () => {
return iconRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WNumber.vue

@ -133,4 +133,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return numberRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WPassword.vue

@ -132,4 +132,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return pwdRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WPosition.vue

@ -195,4 +195,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return positionRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WSelect.vue

@ -133,4 +133,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return selectRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WSelectUserText.vue

@ -88,4 +88,12 @@ const readonlyIfComputed = computed(() => {
const disableIfComputed = computed(() => {
return props.disableIf(props.form);
});
const validate = () => {
return textRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WText.vue

@ -131,4 +131,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return textRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WTextBtn.vue

@ -144,4 +144,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return textBtnRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WTextarea.vue

@ -131,4 +131,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return textareaRef.value.validate();
};
defineExpose({
validate,
});
</script>

8
io.sc.platform.core.frontend/src/platform/components/form/elements/WTreeSelect.vue

@ -143,4 +143,12 @@ const changeValue = (value) => {
form: props.form,
});
};
const validate = () => {
return selectRef.value.validate();
};
defineExpose({
validate,
});
</script>

351
io.sc.platform.core.frontend/src/platform/components/grid/GridBody.vue

@ -0,0 +1,351 @@
<template>
<template v-if="props.grid.props.tree">
<TreeGridRow
:ref="(el) => setTreeRowComponentRef(el, scope.row)"
:grid="props.grid"
:columns-map="props.tableColumnsMap"
:row="props.scope.row"
:cols="props.scope.cols"
:row-key="props.rowKeyName"
:grid-row-click="props.rowClick"
:grid-row-db-click="props.rowDbClick"
:after-row-draggable="props.afterRowDraggable"
:get-row="props.getRow"
:url="props.url"
:get-row-component-refs="getRowComponentRefs"
:set-old-value="setOldValue"
:no-data-tr-colspan="noDataTrColspan"
></TreeGridRow>
</template>
<template v-else>
<q-tr
ref="trRef"
:class="props.scope.row[table.selectedField] ? 'selected' : ''"
:props="props.scope"
:draggable="
((typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable) ||
(typeof props.grid.props.draggable === 'string' && props.grid.props.draggable === 'local')) &&
table.bodyEditStatus === 'none'
? true
: false
"
@click.stop="rowClick($event, scope.row, scope.rowIndex)"
@dblclick.stop="rowDbClick($event, scope.row, scope.rowIndex)"
@dragenter="onDragEnter($event, scope)"
@dragleave="onDragLeave"
@dragover="onDragOver($event, scope)"
@drop="onDrop($event, scope)"
@dragstart="onDragStart($event, scope)"
>
<q-td v-if="table.checkboxSelection" class="text-center" style="padding: 0; width: 50px">
<q-checkbox
v-model="props.getRow(table.rows, scope.row[props.rowKeyName], false)[table.tickedField]"
flat
:dense="props.denseBody"
@update:model-value="updateTicked($event, scope.row)"
/>
</q-td>
<template v-for="(col, index) in scope.cols" :key="index">
<GridTd
:ref="(el) => setComponentRef(el, scope.row, col)"
:grid="props.grid"
:get-row="props.getRow"
:row-key-name="props.rowKeyName"
:scope="scope"
:col="col"
:value="col.value"
:is-selected-row="isSelectedRowComputed"
></GridTd>
</template>
</q-tr>
<GridEditToolbar
:grid="props.grid"
:url="props.url"
:row="props.scope.row"
:row-key-name="props.rowKeyName"
:get-row="props.getRow"
:get-row-component-refs="getRowComponentRefs"
:set-old-value="setOldValue"
:no-data-tr-colspan="noDataTrColspan"
></GridEditToolbar>
</template>
</template>
<script setup lang="ts">
import { computed, inject, ref, toRaw } from 'vue';
import { Tools } from '@/platform';
import TreeGridRow from './TreeGridRow.vue';
import GridTd from './GridTd.vue';
import GridEditToolbar from './GridEditToolbar.vue';
const trRef = ref();
const props = defineProps({
grid: {
//
type: Object,
default: () => {
return {};
},
},
url: {
// url
type: Object,
default: () => {
return {};
},
},
scope: {
//
type: Object,
default: () => {
return {};
},
},
tableColumnsMap: {
type: Map,
default: () => {
return new Map();
},
},
rowKeyName: {
type: String,
default: '',
},
rowClick: {
type: Function,
default: () => {},
},
rowDbClick: {
type: Function,
default: () => {},
},
afterRowDraggable: {
type: Function,
default: () => {},
},
denseBody: {
type: Boolean,
default: () => {
return false;
},
},
getRow: {
type: Function,
default: () => {},
},
setOldValue: {
type: Function,
default: () => {},
},
noDataTrColspan: {
type: Number,
default: () => {
return 0;
},
},
});
const table = inject('table');
const componentRef = ref({});
const getRowComponentRefs = (rowKey: string | Array<string>) => {
const refs = <any>[];
if (!Tools.isEmpty(componentRef.value)) {
const filterResult = Object.keys(componentRef.value).filter((item) => {
if (typeof rowKey === 'string') {
return item.startsWith(rowKey + '_');
} else {
return true;
}
});
if (filterResult.length > 0) {
filterResult.forEach((key) => {
refs.push(componentRef.value[key]);
});
}
}
return refs;
};
const setComponentRef = (el, row, col) => {
if (el && !Tools.isEmpty(col.type)) {
componentRef.value[row[props.rowKeyName] + '_' + col.name] = el;
}
};
const setTreeRowComponentRef = (el, row) => {
if (el && !Tools.isEmpty(row)) {
componentRef.value[row[props.rowKeyName] + '_'] = el;
}
};
const isSelectedRowComputed = computed(() => {
const selected = props.grid.getSelectedRow();
if (!Tools.isEmpty(selected)) {
return props.scope.row[props.rowKeyName] === props.grid.getSelectedRow()[props.rowKeyName];
}
return false;
});
//
const gridTrMiddleHeightComputed = computed(() => {
if (trRef?.value) {
return trRef.value.$el.offsetHeight / 2;
} else {
return (table.dense || table.denseBody ? 24 : 48) / 2;
}
});
//
const onDragStart = (e, scope) => {
const currPageIndex = table.rows.findIndex((item) => {
return item[props.rowKeyName] === scope.row[props.rowKeyName];
});
const currPageStartIndex = scope.rowIndex - currPageIndex;
if (props.grid.props.pageable) {
table.dragRow = { row: { ...scope.row }, rowIndex: scope.rowIndex, currPageIndex: currPageIndex, currPageStartIndex };
} else {
table.dragRow = { row: { ...scope.row }, rowIndex: scope.rowIndex, currPageIndex: scope.rowIndex, currPageStartIndex };
}
e.dataTransfer.dropEffect = 'move';
};
const addDragTopStyle = (e) => {
if (e.target?.parentNode?.children) {
for (let i = 0; i < e.target.parentNode.children.length; i++) {
e.target.parentNode.children[i].style.borderTopWidth = '2px';
e.target.parentNode.children[i].style.borderTopStyle = 'dashed';
e.target.parentNode.children[i].style.borderTopColor = 'orange';
}
}
};
const removeDragTopStyle = (e) => {
if (e.target?.parentNode?.children) {
for (let i = 0; i < e.target.parentNode.children.length; i++) {
e.target.parentNode.children[i].style.borderTopWidth = '';
e.target.parentNode.children[i].style.borderTopStyle = '';
e.target.parentNode.children[i].style.borderTopColor = '';
}
}
};
const addDragBottomStyle = (e) => {
if (e.target?.parentNode?.children) {
for (let i = 0; i < e.target.parentNode.children.length; i++) {
e.target.parentNode.children[i].style.borderBottomWidth = '2px';
e.target.parentNode.children[i].style.borderBottomStyle = 'dashed';
e.target.parentNode.children[i].style.borderBottomColor = 'orange';
}
}
};
const removeDragBottomStyle = (e) => {
if (e.target?.parentNode?.children) {
for (let i = 0; i < e.target.parentNode.children.length; i++) {
e.target.parentNode.children[i].style.borderBottomWidth = '';
e.target.parentNode.children[i].style.borderBottomStyle = '';
e.target.parentNode.children[i].style.borderBottomColor = '';
}
}
};
//
const onDragEnter = (e, scope) => {
if (table.dragRow.rowIndex !== scope.rowIndex && table.dragRow.currPageStartIndex + e.target.parentNode.parentNode.children.length === scope.rowIndex + 1) {
//
addDragBottomStyle(e);
} else if (table.dragRow.rowIndex !== scope.rowIndex) {
addDragTopStyle(e);
}
};
//
const onDragLeave = (e) => {
removeDragTopStyle(e);
removeDragBottomStyle(e);
};
//
const onDragOver = (e, scope) => {
if (
e.offsetY >= gridTrMiddleHeightComputed.value &&
table.dragRow.rowIndex !== scope.rowIndex &&
table.dragRow.currPageStartIndex + e.target.parentNode.parentNode.children.length === scope.rowIndex + 1
) {
removeDragTopStyle(e);
addDragBottomStyle(e);
} else if (
e.offsetY < gridTrMiddleHeightComputed.value &&
table.dragRow.rowIndex !== scope.rowIndex &&
table.dragRow.currPageStartIndex + e.target.parentNode.parentNode.children.length === scope.rowIndex + 1
) {
removeDragBottomStyle(e);
addDragTopStyle(e);
}
e.preventDefault();
};
//
const onDrop = (e, scope) => {
e.preventDefault();
if (table.dragRow.rowIndex === scope.rowIndex) {
return;
}
const dragRow = table.dragRow.row;
const currPageStartIndex = table.dragRow.currPageStartIndex;
table.rows.splice(table.dragRow.currPageIndex, 1);
if (e.offsetY < gridTrMiddleHeightComputed.value && table.dragRow.rowIndex < scope.rowIndex) {
table.rows.splice(scope.rowIndex - currPageStartIndex - 1, 0, dragRow);
} else {
table.rows.splice(scope.rowIndex - currPageStartIndex, 0, dragRow);
}
removeDragTopStyle(e);
removeDragBottomStyle(e);
const updateData = <any>[];
table.rows.forEach((item, index) => {
if (!Tools.isEmpty(item)) {
item[props.grid.props.orderBy] = currPageStartIndex + index + 1;
updateData.push(toRaw(item));
}
});
if (typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable) {
// 访
props.grid.updates(updateData);
}
props.afterRowDraggable(updateData);
};
//
const allTickedStatus = () => {
// null
// false
// true
const ticked_ = <any>[];
table.rows.forEach((item) => {
if (item[table.tickedField]) {
ticked_.push(item);
}
});
if (ticked_.length === table.rows.length) {
table.allTicked = true;
} else if (ticked_.length > 0) {
table.allTicked = null;
} else {
table.allTicked = false;
}
};
const updateTicked = (evt: Event, row: any) => {
if (table.bodyEditStatus === 'none') {
props.getRow(table.rows, row[props.rowKeyName], false)[table.selectedField] = row[table.tickedField];
allTickedStatus();
if (props.grid.props.onUpdateTicked) {
props.grid.emit('updateTicked', evt, row);
}
} else {
props.getRow(table.rows, row[props.rowKeyName], false)[table.tickedField] = !props.getRow(table.rows, row[props.rowKeyName], false)[table.tickedField];
}
};
defineExpose({
allTickedStatus,
});
</script>
<style lang="css"></style>

44
io.sc.platform.core.frontend/src/platform/components/grid/GridConfig.vue

@ -77,7 +77,7 @@
</q-item-section>
</q-item>
<template v-if="!gridProps.tree">
<template v-if="!grid.props.tree">
<q-separator spaced />
<q-item :clickable="false" dense>
<q-item-section>
@ -122,41 +122,41 @@
<q-expansion-item label="紧凑模式">
<q-card>
<q-card-section>
<q-item v-ripple tag="label" dense :disable="denseDisableComputed">
<q-item v-ripple tag="label" dense>
<q-item-section side>
<q-checkbox v-model="table.dense" dense :disable="denseDisableComputed" @update:model-value="denseChange()" />
<q-checkbox v-model="table.dense" dense @update:model-value="denseChange()" />
</q-item-section>
<q-item-section>
<q-item-label>紧凑</q-item-label>
</q-item-section>
</q-item>
<q-item v-ripple tag="label" dense :disable="denseOtherDisableComputed">
<q-item v-ripple tag="label" dense>
<q-item-section side>
<q-checkbox v-model="table.denseToolbar" :disable="denseOtherDisableComputed" dense @update:model-value="denseChange" />
<q-checkbox v-model="table.denseToolbar" dense @update:model-value="denseChange" />
</q-item-section>
<q-item-section>
<q-item-label>按钮栏紧凑</q-item-label>
</q-item-section>
</q-item>
<q-item v-ripple tag="label" dense :disable="denseOtherDisableComputed">
<q-item v-ripple tag="label" dense>
<q-item-section side>
<q-checkbox v-model="table.denseHeader" :disable="denseOtherDisableComputed" dense @update:model-value="denseChange" />
<q-checkbox v-model="table.denseHeader" dense @update:model-value="denseChange" />
</q-item-section>
<q-item-section>
<q-item-label>列头紧凑</q-item-label>
</q-item-section>
</q-item>
<q-item v-ripple tag="label" dense :disable="denseOtherDisableComputed">
<q-item v-ripple tag="label" dense>
<q-item-section side>
<q-checkbox v-model="table.denseBody" :disable="denseOtherDisableComputed" dense @update:model-value="denseChange" />
<q-checkbox v-model="table.denseBody" dense @update:model-value="denseChange" />
</q-item-section>
<q-item-section>
<q-item-label>内容紧凑</q-item-label>
</q-item-section>
</q-item>
<q-item v-ripple tag="label" dense :disable="denseOtherDisableComputed">
<q-item v-ripple tag="label" dense>
<q-item-section side>
<q-checkbox v-model="table.denseBottom" :disable="denseOtherDisableComputed" dense @update:model-value="denseChange" />
<q-checkbox v-model="table.denseBottom" dense @update:model-value="denseChange" />
</q-item-section>
<q-item-section>
<q-item-label>分页栏紧凑</q-item-label>
@ -217,7 +217,7 @@
</q-list>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch, inject } from 'vue';
import { inject } from 'vue';
const props = defineProps({
scope: {
type: Object,
@ -225,12 +225,6 @@ const props = defineProps({
return {};
},
},
gridProps: {
type: Object,
default: () => {
return {};
},
},
moreColumnTitleArray: {
//
type: Array,
@ -259,7 +253,6 @@ const stickyOptions = [
{ label: '固定9列', value: 9 },
{ label: '固定10列', value: 10 },
];
const sticky = ref(0);
const showColumn = (name) => {
if (props.moreColumnTitleArray.length > 0) {
@ -280,17 +273,4 @@ const showColumn = (name) => {
const denseChange = () => {
props.grid.stickyHeaderColumn(0);
};
const denseDisableComputed = computed(() => {
if (table.denseToolbar || table.denseHeader || table.denseBody || table.denseBottom) {
return true;
}
return false;
});
const denseOtherDisableComputed = computed(() => {
if (table.dense) {
return true;
}
return false;
});
</script>

324
io.sc.platform.core.frontend/src/platform/components/grid/GridEditToolbar.vue

@ -0,0 +1,324 @@
<template>
<q-tr v-if="showRowEditButtonComputed">
<q-td :colspan="props.noDataTrColspan">
<div class="editButton text-center">
<w-toolbar
:dense="true"
align="center"
:grid="props.grid"
:buttons="[
{
label: '保存',
name: 'save',
icon: 'save',
color: 'primary',
outline: false,
click: async (args) => {
save(args);
},
},
{
label: '取消',
name: 'cancel',
icon: 'close',
color: 'blue-grey',
outline: false,
click: (args) => {
if (table.bodyEditStatus === 'rowEdit') {
props.setOldValue(args.selected);
} else if (table.bodyEditStatus === 'rowsEdit') {
props.grid.getRows().forEach((item) => {
props.setOldValue(item);
});
}
table.bodyEditStatus = 'none';
},
},
]"
></w-toolbar>
</div>
</q-td>
</q-tr>
</template>
<script setup lang="ts">
import { computed, inject, ref, toRaw } from 'vue';
import { Tools, NotifyManager, noErrorAxios, t } from '@/platform';
const props = defineProps({
grid: {
//
type: Object,
default: () => {
return {};
},
},
url: {
// url
type: Object,
default: () => {
return {};
},
},
rowKeyName: {
type: String,
default: '',
},
row: {
type: Object,
default: () => {
return {};
},
},
getRow: {
type: Function,
default: () => {},
},
getRowComponentRefs: {
type: Function,
default: () => {},
},
setOldValue: {
type: Function,
default: () => {},
},
noDataTrColspan: {
type: Number,
default: () => {
return 0;
},
},
});
const table = inject('table');
const validate = async (refs) => {
let result = true;
for (let i = 0; i < refs.length; i++) {
const component = refs[i].getComponentRef();
if (!Tools.isEmpty(refs[i].getComponentOneRef)) {
const componentOne = refs[i].getComponentOneRef();
if (!Tools.isEmpty(componentOne) && !Tools.isEmpty(componentOne.validate)) {
const componentOneValidateResult = await componentOne.validate();
if (!componentOneValidateResult) {
result = false;
break;
}
}
}
if (props.grid.props.tree && !Tools.isEmpty(component)) {
const keys = Object.keys(component);
for (let k = 0; k < keys.length; k++) {
if (!Tools.isEmpty(component[keys[k]]?.validate)) {
const treeComponentValidateResult = await component[keys[k]].validate();
if (!treeComponentValidateResult) {
result = false;
break;
}
}
}
} else if (!Tools.isEmpty(component.validate)) {
const componentValidateResult = await component.validate();
if (!componentValidateResult) {
result = false;
break;
}
}
}
return result;
};
const rowSave = (args) => {
let data = args.selected['_rowOldValue'];
let submitFlag = true;
let localeUpdateFlag = false;
let url = '';
//
props.grid.emit('beforeEditorDataSubmit', data, (handlerRequestParams: any | boolean, localeUpdate: boolean = false) => {
if (typeof handlerRequestParams === 'boolean' && handlerRequestParams === false) {
submitFlag = false;
} else {
data = handlerRequestParams;
}
localeUpdateFlag = localeUpdate;
});
if (localeUpdateFlag && submitFlag) {
// 访
props.grid.replaceRow(data);
table.bodyEditStatus = 'none';
} else {
if (submitFlag) {
data = { ...args.selected, ...data };
if (!Tools.isEmpty(props.url.editDataUrl)) {
url = props.url.editDataUrl + '/' + args.selected[props.grid.props.primaryKey];
} else {
url = props.url.dataUrl + '/' + args.selected[props.grid.props.primaryKey];
}
const requestParams = {
method: 'PUT',
headers: { 'content-type': 'application/json;charset=utf-8;' },
data: data,
url: url,
};
noErrorAxios(requestParams)
.then((resp) => {
props.grid.emit('afterEditorDataSubmit', resp.data);
NotifyManager.info(t('tip.operationSuccess'));
if (props.grid.props.refreshData || !props.grid.props.tree) {
props.grid.refresh();
} else if (resp.data) {
props.grid.replaceRow(data);
}
// 退
table.bodyEditStatus = 'none';
})
.catch((error) => {
const response = error?.response;
const status = response?.status;
const data = response?.data;
if (data?.code === 1001) {
NotifyManager.error('服务器验证未通过');
} else {
//
if (status === 500) {
NotifyManager.error(t(data?.errorMessageI18nKey));
} else {
NotifyManager.error(t(status));
}
}
});
}
}
};
//
const checkDataModified = (row) => {
const keys = Object.keys(row['_rowOldValue']);
return keys.some((key) => row[key] !== row['_rowOldValue'][key]);
};
const treeDataPush = (arr) => {
const data = <any>[];
if (arr && arr.length > 0) {
arr.forEach((item) => {
if (checkDataModified(item)) {
data.push(item['_rowOldValue']);
}
const childrenData = treeDataPush(item.children);
if (childrenData.length > 0) {
data.push(...childrenData);
}
});
}
return data;
};
const rowsSave = (args) => {
let data = <any>[];
const rows = args.grid.getRows();
const isTree = props.grid.props.tree;
rows.forEach((item) => {
if (checkDataModified(item)) {
data.push(item['_rowOldValue']);
}
if (isTree && item.children) {
const childrenData = treeDataPush(item.children);
if (childrenData.length > 0) {
data.push(...childrenData);
}
}
});
let submitFlag = true;
let localeUpdateFlag = false;
//
props.grid.emit('beforeEditorDataSubmit', data, (handlerRequestParams: any | boolean, localeUpdate: boolean = false) => {
if (typeof handlerRequestParams === 'boolean' && handlerRequestParams === false) {
submitFlag = false;
} else {
data = handlerRequestParams;
}
localeUpdateFlag = localeUpdate;
});
if (localeUpdateFlag && submitFlag) {
// 访
data.forEach((item) => {
props.grid.replaceRow(item);
});
table.bodyEditStatus = 'none';
} else {
if (submitFlag) {
props.grid.updates(data, (callbackData) => {
NotifyManager.info(t('tip.operationSuccess'));
if (props.grid.props.refreshData || !props.grid.props.tree) {
props.grid.refresh();
} else if (!Tools.isEmpty(callbackData)) {
callbackData.forEach((item) => {
props.grid.replaceRow(item);
});
}
// 退
table.bodyEditStatus = 'none';
});
}
}
};
const save = async (args) => {
const refs = props.getRowComponentRefs(table.bodyEditStatus === 'rowEdit' ? args.selected[props.rowKeyName] : []);
const result = await validate(refs);
if (!result) {
NotifyManager.error('验证未通过');
} else {
if (table.bodyEditStatus === 'rowEdit') {
rowSave(args);
} else if (table.bodyEditStatus === 'rowsEdit') {
rowsSave(args);
}
}
};
const showRowEditButtonComputed = computed(() => {
if (table.bodyEditStatus === 'rowEdit' && isSelectedRowComputed.value) {
return true;
} else if (table.bodyEditStatus === 'rowsEdit' && table.rows.length > 0 && isLastRowComputed.value) {
return true;
} else {
return false;
}
});
const checkLastRow = (row) => {
if (props.grid.props.tree && row['expand'] && !Tools.isEmpty(row.children) && row.children.length > 0) {
const childrenLastRow = row.children[row.children.length - 1];
if (childrenLastRow['expand'] && !Tools.isEmpty(childrenLastRow.children) && childrenLastRow.children.length > 0) {
return checkLastRow(childrenLastRow);
} else {
return childrenLastRow[props.rowKeyName] === props.row[props.rowKeyName];
}
} else {
return row[props.rowKeyName] === props.row[props.rowKeyName];
}
};
const isLastRowComputed = computed(() => {
const lastRow = table.rows[table.rows.length - 1];
return checkLastRow(lastRow);
});
const isSelectedRowComputed = computed(() => {
const selected = props.grid.getSelectedRow();
if (!Tools.isEmpty(selected)) {
return props.row[props.rowKeyName] === props.grid.getSelectedRow()[props.rowKeyName];
}
return false;
});
defineExpose({});
</script>
<style lang="css">
.editButton {
position: sticky;
background-color: white;
left: 45%;
width: 150px;
}
</style>

227
io.sc.platform.core.frontend/src/platform/components/grid/GridEditor.vue

@ -0,0 +1,227 @@
<template>
<w-dialog ref="dialogRef" :title="dialog.dialogTitle" v-bind="props.grid.props.editor.dialog" :buttons="dialogButtonsComputed">
<w-form ref="dialogFormRef" v-bind="props.grid.props.editor.form" class="pt-1.5 px-1.5"></w-form>
</w-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, inject, computed } from 'vue';
import { t, Tools, noErrorAxios, NotifyManager } from '@/platform';
const dialogRef = ref();
const dialogFormRef = ref();
const props = defineProps({
grid: {
//
type: Object,
default: () => {
return {};
},
},
url: {
// url
type: Object,
default: () => {
return {};
},
},
request: {
type: Function,
default: () => {},
},
setRowDataExtraProperty: {
type: Function,
default: () => {},
},
getRow: {
type: Function,
default: () => {},
},
});
const table = inject('table');
const dialogButtonsComputed = computed(() => {
if (props.grid.props.editor?.dialog?.buttons) {
return [...props.grid.props.editor.dialog.buttons, ...dialog.dialogButtons];
}
return dialog.dialogButtons;
});
const save = async () => {
dialog.dialogButtons[0].loading = true;
const formStatus = dialogFormRef.value.getStatus();
const validate = await dialogFormRef.value.validate();
if (validate) {
let dialogFormData = dialogFormRef.value.getData();
const selected = props.grid.getSelectedRow();
const primaryKey = selected[props.grid.props.primaryKey];
if (formStatus === 'edit' && selected) {
dialogFormData[props.grid.props.primaryKey] = primaryKey;
}
let submitFlag = true;
let closeDialog = true;
props.grid.emit('beforeEditorDataSubmit', dialogFormData, (handlerRequestParams: any | boolean, closeFlag: boolean = true) => {
if (typeof handlerRequestParams === 'boolean' && handlerRequestParams === false) {
submitFlag = false;
} else {
dialogFormData = handlerRequestParams;
}
closeDialog = closeFlag;
});
if (submitFlag) {
if (formStatus === 'addTop') {
dialogFormData[props.grid.props.foreignKey] = null;
} else if (formStatus === 'addChild') {
dialogFormData[props.grid.props.foreignKey] = primaryKey;
} else if (formStatus === 'edit' && primaryKey) {
dialogFormData[props.grid.props.foreignKey] = primaryKey;
} else if (formStatus === 'clone' && primaryKey) {
dialogFormData[props.grid.props.foreignKey] = selected[props.grid.props.foreignKey];
}
if (formStatus === 'edit') {
//
dialogFormData = { ...selected, ...dialogFormData };
}
let requestParams = {
method: getMethod(formStatus),
headers: { 'content-type': 'application/json;charset=utf-8;' },
data: dialogFormData,
url: getUrl(formStatus, selected),
};
dialog.dialogButtons[0].loading = false;
noErrorAxios(requestParams)
.then((resp) => {
dialog.dialogButtons[0].loading = false;
props.grid.emit('afterEditorDataSubmit', resp.data);
NotifyManager.info(t('tip.operationSuccess'));
if (closeDialog) {
dialogRef.value.hide();
}
if (props.grid.props.refreshData || !props.grid.props.tree) {
props.grid.refresh();
} else if (resp.data && (formStatus === 'add' || formStatus === 'clone' || formStatus === 'addTop' || formStatus === 'addChild')) {
addData(resp.data);
} else if (resp.data) {
updateData(resp.data);
}
})
.catch((error) => {
const response = error?.response;
const status = response?.status;
const data = response?.data;
if (data?.code === 1001) {
//
if (error.response.data.data) {
dialogFormRef.value.setValidationErrors(error.response.data.data);
}
} else {
//
if (status === 500) {
NotifyManager.error(t(data?.errorMessageI18nKey));
} else {
NotifyManager.error(t(status));
}
}
dialog.dialogButtons[0].loading = false;
});
} else {
dialog.dialogButtons[0].loading = false;
if (closeDialog) {
dialogRef.value.hide();
}
}
} else {
dialog.dialogButtons[0].loading = false;
}
};
const dialog = reactive({
dialogTitle: t('action.addNew'),
dialogButtons: [
{
icon: 'beenhere',
labelI18nKey: 'action.submit',
label: t('action.submit'),
loading: false,
click: () => {
save();
},
},
],
});
//
const addTreeRow = (row) => {
if (Tools.isEmpty(row[props.grid.props.foreignKey])) {
table.rows.push(row);
} else {
const parent = props.getRow(table.rows, row[props.grid.props.foreignKey], true);
if (parent) {
if (parent['children'] && Array.isArray(parent['children'])) {
parent['children'].push(row);
} else {
parent['children'] = [row];
}
}
}
};
const addData = (rowData) => {
if (props.grid.props.tree) {
addTreeRow(rowData);
props.setRowDataExtraProperty(table.rows);
} else {
props.grid.addRow(rowData, false);
}
};
const updateData = (rowData) => {
const selected = props.grid.getSelectedRow();
rowData[props.grid.props.primaryKey] = selected[props.grid.props.primaryKey];
rowData[props.grid.props.selectedField] = true;
if (selected['children']) {
rowData['children'] = selected['children'];
}
props.grid.replaceRow(rowData);
};
const getMethod = (formStatus: string) => {
if (formStatus === 'add' || formStatus === 'clone' || formStatus === 'addTop' || formStatus === 'addChild') {
return 'POST';
} else {
return 'PUT';
}
};
const getUrl = (formStatus: string, selected: any) => {
if (formStatus === 'add' || formStatus === 'clone' || formStatus === 'addTop' || formStatus === 'addChild') {
if (!Tools.isEmpty(props.url.addDataUrl)) {
return props.url.addDataUrl;
} else {
return props.url.dataUrl;
}
} else {
if (!Tools.isEmpty(props.url.editDataUrl)) {
return props.url.editDataUrl + '/' + selected[props.grid.props.primaryKey];
} else {
return props.url.dataUrl + '/' + selected[props.grid.props.primaryKey];
}
}
};
const resetButtonLabel = () => {
dialog.dialogButtons[0].label = t(dialog.dialogButtons[0].labelI18nKey);
};
const getDialog = () => {
return dialogRef.value;
};
const getForm = () => {
return dialogFormRef.value;
};
defineExpose({
resetButtonLabel,
getDialog,
getForm,
});
</script>
<style lang="css"></style>

539
io.sc.platform.core.frontend/src/platform/components/grid/GridHeader.vue

@ -0,0 +1,539 @@
<template>
<template v-if="columnTitleState.columnTitleRowNum > 1">
<q-tr v-for="(r, rIndex) in columnTitleState.columnTitleArr" :key="rIndex">
<q-th
v-if="rIndex === 0 && props.selection === 'multiple' && table.checkboxSelection && !props.grid.props.tree"
:rowspan="columnTitleState.columnTitleRowNum"
:style="moreColumnTitleTableSelectionStyle"
>
<q-checkbox v-model="table.allTicked" flat :dense="props.denseHeader" @update:model-value="allTickedUpdateFun" />
</q-th>
<q-th
v-else-if="rIndex === 0 && table.checkboxSelection && !props.grid.props.tree"
:rowspan="columnTitleState.columnTitleRowNum"
:style="moreColumnTitleTableSelectionStyle"
></q-th>
<q-th
v-if="rIndex === 0 && table.sortNo && !props.grid.props.tree"
:rowspan="columnTitleState.columnTitleRowNum"
:style="moreColumnTitleTableSortNoStyle"
>
{{ $t('rownum') }}
</q-th>
<q-th
v-for="c in r"
:key="c.name"
:rowspan="c.rowspan"
:colspan="c.colspan"
:style="thStyleHandler(c, props.scope)"
:class="c.classes"
:props="titleScopeHandler(c, props.scope)"
style="font-weight: bold"
:title="c.title"
>
<span v-dompurify-html="Tools.isUndefinedOrNull(c.label) ? '' : c.label"></span>
</q-th>
</q-tr>
<q-tr v-if="table.rows.length === 0" :style="props.noDataTrHeightStyle" class="noDataTr">
<q-td :colspan="props.noDataTrColspan" align="center" valian="middle"><q-icon size="2em" name="info" />{{ $t('tip.noData') }}</q-td>
</q-tr>
</template>
<template v-else>
<q-tr :props="scope">
<q-th
v-if="props.selection === 'multiple' && table.checkboxSelection && !props.grid.props.tree"
:style="props.grid.props.tree ? '' : 'padding: 0; min-width: 50px;width: 50px;max-width:50px'"
>
<q-checkbox v-model="table.allTicked" flat :dense="props.denseHeader" @update:model-value="allTickedUpdateFun"
/></q-th>
<q-th
v-else-if="table.checkboxSelection && !props.grid.props.tree"
:style="props.grid.props.tree ? '' : 'padding: 0; min-width: 50px;width: 50px;max-width:50px'"
></q-th>
<template v-for="col in scope.cols" :key="col.name">
<q-th
:props="scope"
:style="col.style + (col.name === '_sortNo_' ? 'padding: 0; min-width: 50px;width: 50px;max-width:50px' : '')"
:class="col.classes"
style="font-weight: bold"
:title="col.title"
>
<span v-dompurify-html="Tools.isUndefinedOrNull(col.label) ? '' : col.label"></span>
</q-th>
</template>
</q-tr>
<q-tr v-if="table.rows.length === 0" :style="props.noDataTrHeightStyle" class="noDataTr">
<q-td :colspan="props.noDataTrColspan" align="center" valian="middle"><q-icon size="2em" name="info" />{{ $t('tip.noData') }}</q-td>
</q-tr>
</template>
</template>
<script setup lang="ts">
import { Tools } from '@/platform';
import { computed, inject, reactive } from 'vue';
const props = defineProps({
grid: {
//
type: Object,
default: () => {
return {};
},
},
scope: {
//
type: Object,
default: () => {
return {};
},
},
selection: {
type: String,
default: '',
},
denseHeader: {
type: Boolean,
default: false,
},
rawColumns: {
type: Array,
default: () => {
return [];
},
},
tableColumns: {
type: Array,
default: () => {
return [];
},
},
excludeColumnNum: {
type: Number,
default: () => {
return 0;
},
},
noDataTrHeightStyle: {
type: Object,
default: () => {
return {};
},
},
noDataTrColspan: {
type: Number,
default: () => {
return 0;
},
},
});
const table = inject('table');
//
const columnTitleState = reactive({
columnTitleRowNum: 1, //
columnTitleArr: <any>[], //
});
//
type MoreColumnTitleType = {
name: string; // name
title: string; // title()
label: string; // label
parentLevel: number; //
childrenLevel: number; //
rowspan: number; //
colspan: number; //
rowIndex: number; //
style: any; //
classes: any; // classes
parents: any; // name
};
// map
let moreColumnTitleMap = new Map<string, MoreColumnTitleType>();
let allColumnMap = new Map();
const moreColumnTitleTableSelectionStyle = computed(() => {
if (table.stickyNum > 0) {
if (props.grid.props.tree) {
return 'z-index: 3;position: sticky;left: 0px;';
} else {
return 'z-index: 3;position: sticky;left: 0px;padding: 0; width: 50px;min-width:50px;max-width:50px;';
}
}
return 'padding: 0; width: 50px;min-width:50px;max-width:50px;';
});
const moreColumnTitleTableSortNoStyle = computed(() => {
if (table.checkboxSelection && table.sortNo && table.stickyNum > 0) {
return 'z-index: 3;position: sticky;left: var(--columnWidth-1-1);width: 50px;min-width:50px;max-width:50px;';
} else if (table.sortNo && table.stickyNum > 0) {
return 'z-index: 3;position: sticky;left: 0px;width: 50px;min-width:50px;max-width:50px;';
}
return 'width: 50px;min-width:50px;max-width:50px;';
});
const allTickedUpdateFun = (value, evt) => {
if (table.bodyEditStatus === 'none') {
if (value) {
table.rows.forEach((item) => {
item[table.tickedField] = true;
item[table.selectedField] = true;
});
} else {
table.rows.forEach((item) => {
item[table.tickedField] = false;
item[table.selectedField] = false;
});
}
} else if (table.bodyEditStatus === 'rowEdit') {
table.allTicked = null;
} else if (table.bodyEditStatus === 'rowsEdit') {
table.allTicked = false;
}
};
const handlerStickyChildrenColumn = (item, columns) => {
columns.push(item);
if (item.columns && item.columns.length > 0) {
item.columns.forEach((children) => {
handlerStickyChildrenColumn(children, columns);
});
}
};
const getStickyColumn = () => {
const columns = props.rawColumns.filter((item, index) => {
return index < table.stickyNum;
});
const arr = [];
columns.forEach((item) => {
handlerStickyChildrenColumn(item, arr);
});
return arr;
};
//
const getMoreRowColumnTitleIndex = (name: any) => {
let trIndex = -1;
let tdIndex = -1;
for (let tr = 0; tr < columnTitleState.columnTitleArr.length; tr++) {
const tdArr = columnTitleState.columnTitleArr[tr];
let flag = false;
for (let td = 0; td < tdArr.length; td++) {
if (name === tdArr[td].name) {
trIndex = tr + 1;
tdIndex = td + 1;
flag = true;
break;
}
}
if (flag) {
break;
}
}
return { trIndex: trIndex, tdIndex: tdIndex };
};
const thStickyLastNameComputed = computed(() => {
let result = <any>[];
const stickyColumnArr = getStickyColumn();
const lastColumn = getMoreRowColumnTitleIndex(stickyColumnArr[stickyColumnArr.length - 1]['name']);
if (lastColumn.trIndex === 1) {
// 1
result = [stickyColumnArr[stickyColumnArr.length - 1]];
} else {
const map = new Map();
stickyColumnArr.forEach((item) => {
const trtdIndex = getMoreRowColumnTitleIndex(item['name']);
if (map.has(trtdIndex.trIndex) && map.get(trtdIndex.trIndex)[0] < trtdIndex.tdIndex) {
map.set(trtdIndex.trIndex, [trtdIndex.tdIndex, item]);
} else if (!map.has(trtdIndex.trIndex)) {
map.set(trtdIndex.trIndex, [trtdIndex.tdIndex, item]);
}
});
for (let key of map.keys()) {
result.push(map.get(key)[1]);
}
}
return result;
});
const thStyleHandler = (c: any, scope: any) => {
let style = '';
if (!Tools.isEmpty(c.style)) {
if (c.style.substr(-1) !== ';') {
style = c.style + ';';
}
style = c.style;
}
const stickyColumnArr = getStickyColumn();
if (
table.stickyNum > 0 &&
stickyColumnArr.findIndex((item: any) => {
return item.name === c.name;
}) > -1
) {
const stickyThArr = <any>[];
const trtdIndex = getMoreRowColumnTitleIndex(c.name);
if (c.parents && c.parents.length > 0) {
//
// parenttdIndex
for (let tr = 0; tr < trtdIndex.trIndex; tr++) {
const tdArr = columnTitleState.columnTitleArr[tr];
for (let td = 0; td < trtdIndex.tdIndex - 1; td++) {
if (tdArr[td] && tdArr[td].parents && tdArr[td].parents.length > 0) {
const result =
tdArr[td].parents.length === c.parents.length &&
tdArr[td].parents.every((a) => c.parents.some((b) => a === b)) &&
c.parents.every((_b) => tdArr[td].parents.some((_a) => _a === _b));
if (result) {
if (tr === 0) {
stickyThArr.push({ trIndex: tr + 1, tdIndex: td + props.excludeColumnNum + 1 });
} else {
stickyThArr.push({ trIndex: tr + 1, tdIndex: td + 1 });
}
}
}
}
}
c.parents.forEach((parent) => {
const parentTrtdIndex = getMoreRowColumnTitleIndex(parent);
if (moreColumnTitleMap.get(parent)!.parents && moreColumnTitleMap.get(parent)!.parents.length > 0) {
const tdArr = columnTitleState.columnTitleArr[parentTrtdIndex.trIndex - 1];
for (let td = 0; td < parentTrtdIndex.tdIndex - 1; td++) {
const result =
tdArr[td].parents.length === moreColumnTitleMap.get(parent)!.parents.length &&
tdArr[td].parents.every((a) => moreColumnTitleMap.get(parent)!.parents.some((b) => a === b)) &&
moreColumnTitleMap.get(parent)!.parents.every((_b) => tdArr[td].parents.some((_a) => _a === _b));
if (result) {
stickyThArr.push({ trIndex: parentTrtdIndex.trIndex, tdIndex: td + 1 });
}
}
} else {
const tdArr = columnTitleState.columnTitleArr[parentTrtdIndex.trIndex - 1];
for (let td = 0; td < parentTrtdIndex.tdIndex - 1; td++) {
if (
tdArr[td].parents &&
tdArr[td].parents.length > 0 &&
tdArr[td].parents.findIndex((item) => {
return item === parent;
}) > -1
) {
stickyThArr.push({ trIndex: parentTrtdIndex.trIndex, tdIndex: td + props.excludeColumnNum + 1 });
} else {
stickyThArr.push({ trIndex: parentTrtdIndex.trIndex, tdIndex: td + props.excludeColumnNum + 1 });
}
}
}
});
if (trtdIndex.tdIndex === 1 && stickyThArr.length === 0) {
stickyThArr.push({ trIndex: 0, tdIndex: 0 });
}
} else {
if (trtdIndex.tdIndex === 1) {
if (props.excludeColumnNum === 2) {
return thStickyLastNameComputed.value.findIndex((item) => {
return item.name === c.name;
}) > -1
? (style += 'z-index: 3;position: sticky;left: calc(var(--columnWidth-1-1) + var(--columnWidth-1-2));')
: (style += 'z-index: 3;position: sticky;left: calc(var(--columnWidth-1-1) + var(--columnWidth-1-2));');
} else if (props.excludeColumnNum === 1) {
return thStickyLastNameComputed.value.findIndex((item) => {
return item.name === c.name;
}) > -1
? (style += 'z-index: 3;position: sticky;left: var(--columnWidth-1-1);')
: (style += 'z-index: 3;position: sticky;left: var(--columnWidth-1-1);');
} else {
return thStickyLastNameComputed.value.findIndex((item) => {
return item.name === c.name;
}) > -1
? (style += 'z-index: 3;position: sticky;left: 0px;')
: (style += 'z-index: 3;position: sticky;left: 0px;');
}
} else {
for (let i = 1; i < trtdIndex.tdIndex; i++) {
stickyThArr.push({ trIndex: 1, tdIndex: i + props.excludeColumnNum });
}
}
}
if (props.excludeColumnNum === 2) {
stickyThArr.push({ trIndex: 1, tdIndex: 1 });
stickyThArr.push({ trIndex: 1, tdIndex: 2 });
} else if (props.excludeColumnNum === 1) {
stickyThArr.push({ trIndex: 1, tdIndex: 1 });
}
if (stickyThArr && stickyThArr.length > 0) {
let left = '';
stickyThArr.forEach((item) => {
left += '+ var(--columnWidth-' + item.trIndex + '-' + item.tdIndex + ') ';
});
if (left) {
style += 'z-index: 3;position: sticky;left: calc(' + left.substring(1) + ')' + ';';
}
}
}
return style;
};
const titleScopeHandler = (column: any, scope: any) => {
if (props.tableColumns?.length > 0) {
const i = props.tableColumns.findIndex((item: any) => item['name'] === column.name);
if (i > -1) {
return scope;
}
}
return undefined;
};
// map
const columnToMap = (column: any) => {
if (Tools.isEmpty(column.name)) {
column.name = Tools.uuid();
}
if (Tools.isEmpty(column.label)) {
column.label = column.name;
}
if (column && column.columns && column.columns.length > 0) {
allColumnMap.set(column.name, column);
moreColumnTitleMap.set(column.name, {
name: column.name,
label: column.label,
title: column.title,
parentLevel: 0,
childrenLevel: 0,
rowspan: 0,
colspan: 0,
rowIndex: 0,
style: column.style,
classes: column.classes,
parents: [],
});
column.columns.forEach((item) => {
columnToMap(item);
});
} else {
allColumnMap.set(column.name, column);
moreColumnTitleMap.set(column.name, {
name: column.name,
label: column.label,
title: column.title,
parentLevel: 0,
childrenLevel: 0,
rowspan: 0,
colspan: 0,
rowIndex: 0,
style: column.style,
classes: column.classes,
parents: [],
});
}
};
let tmpColspan = 0;
const deepArr = [];
const getChildrenLevel = (column, deep, deepArr) => {
if (column && column.columns && column.columns.length > 0) {
deep++;
column.columns.forEach((item) => {
getChildrenLevel(item, deep, deepArr);
});
} else if (column) {
// deep++;
deepArr.push(deep);
tmpColspan += 1;
}
};
// ,
function findParents(arrData: any, name: any) {
if (arrData.length == 0) return;
for (let i = 0; i < arrData.length; i++) {
if (arrData[i].name == name) {
return [];
} else {
if (arrData[i].columns) {
const res = findParents(arrData[i].columns, name);
if (res !== undefined) {
return res.concat(arrData[i].name).reverse();
}
}
}
}
}
const handlerMoreRowColumnTitle = () => {
moreColumnTitleMap = new Map<string, MoreColumnTitleType>();
allColumnMap = new Map();
props.rawColumns.forEach((tableColumn: any) => {
columnToMap(tableColumn);
});
let maxColumnChildrenLevel = 0;
for (let key of allColumnMap.keys()) {
// childrenLevel
let tmpChildrenLevel = 0;
getChildrenLevel(allColumnMap.get(key), 0, deepArr);
tmpChildrenLevel = Math.max(...deepArr);
if (tmpChildrenLevel > maxColumnChildrenLevel) {
maxColumnChildrenLevel = tmpChildrenLevel;
}
deepArr.splice(0, deepArr.length);
moreColumnTitleMap.get(key)!.childrenLevel = tmpChildrenLevel;
// colspan
moreColumnTitleMap.get(key)!.colspan = tmpColspan;
tmpColspan = 0;
// parent
const parent = findParents(props.rawColumns, key);
moreColumnTitleMap.get(key)!.parents = parent;
// parentLevel
moreColumnTitleMap.get(key)!.parentLevel = parent.length;
// rowIndex
moreColumnTitleMap.get(key)!.rowIndex = parent.length;
}
if (maxColumnChildrenLevel > 0) {
// = + 1
columnTitleState.columnTitleRowNum = maxColumnChildrenLevel + 1;
}
const map = new Map<number, [any]>();
for (let key of moreColumnTitleMap.keys()) {
const value: any = moreColumnTitleMap.get(key);
// rowspan
if (value.parentLevel === 0 && value.childrenLevel === 0) {
value.rowspan = columnTitleState.columnTitleRowNum;
} else if (value.parentLevel === 0) {
value.rowspan = 1;
} else {
// - -
value.rowspan = columnTitleState.columnTitleRowNum - value.parentLevel - value.childrenLevel;
}
if (map.has(value.rowIndex)) {
(map.get(value.rowIndex) as any).push(value);
} else {
map.set(value.rowIndex, [value]);
}
}
const arr = Array.from(map);
columnTitleState.columnTitleArr = [];
arr.sort((a, b) => a[0] - b[0]);
arr.forEach((item) => {
columnTitleState.columnTitleArr.push(item[1]);
});
};
const getColumnTitleState = () => {
return columnTitleState;
};
const getMoreColumnTitleMap = () => {
return moreColumnTitleMap;
};
defineExpose({
handlerMoreRowColumnTitle,
getColumnTitleState,
getMoreColumnTitleMap,
});
</script>
<style lang="css"></style>

73
io.sc.platform.core.frontend/src/platform/components/grid/GridPagination.vue

@ -0,0 +1,73 @@
<template>
<template v-if="props.grid.props.pageable && !props.grid.props.tree">
<template v-if="props.state.refHeightWidth.middleWidth > 600">
<q-pagination
v-model="page"
:boundary-links="props.state.pagination.config.boundaryLinks"
:boundary-numbers="props.state.pagination.config.boundaryNumbers"
:direction-links="props.state.pagination.config.directionLinks"
:ellipses="props.state.pagination.config.ellipses"
:max-pages="props.state.pagination.config.maxPages"
:min="1"
:max="props.scope.pagesNumber"
:size="props.denseBottom ? '10px' : ''"
@update:model-value="pageChange"
/>
</template>
<template v-else>
<q-pagination
v-model="page"
:boundary-links="props.state.pagination.config.boundaryLinks"
:boundary-numbers="props.state.pagination.config.boundaryNumbers"
:direction-links="props.state.pagination.config.directionLinks"
:ellipses="props.state.pagination.config.ellipses"
:max-pages="3"
:min="1"
:max="props.scope.pagesNumber"
:size="props.denseBottom ? '10px' : ''"
@update:model-value="pageChange"
/>
</template>
<span>{{ $t('tip.pagenation.totalRecord', { count: props.state.pagination.rowsNumber }) }}</span>
</template>
<template v-else> {{ $t('tip.pagenation.totalRecord', { count: props.state.pagination.rowsNumber }) }} </template>
</template>
<script setup lang="ts">
const page = defineModel({ type: Number, default: 1 });
const props = defineProps({
grid: {
//
type: Object,
default: () => {
return {};
},
},
scope: {
//
type: Object,
default: () => {
return {};
},
},
state: {
type: Object,
default: () => {
return {};
},
},
denseBottom: {
type: Boolean,
default: false,
},
request: {
type: Function,
default: () => {},
},
});
const pageChange = (value) => {
page.value = value;
props.request(props.state);
};
</script>
<style lang="css"></style>

77
io.sc.platform.core.frontend/src/platform/components/grid/GridTd.vue

@ -0,0 +1,77 @@
<template>
<q-td :key="col.name" :props="scope" :title="col.classes?.indexOf('truncate') > -1 && !Tools.isEmpty(value) && typeof value !== 'object' ? value : ''">
<template v-if="col.name === '_sortNo_'">
{{ scope.rowIndex + 1 }}
</template>
<template v-if="!Tools.isEmpty(col.type) && ((props.isSelectedRow && table.bodyEditStatus === 'rowEdit') || table.bodyEditStatus === 'rowsEdit')">
<component
:is="col.type"
ref="componentRef"
v-bind="col.attrs"
v-model="props.getRow(table.rows, scope.row[props.rowKeyName], false)['_rowOldValue'][col.name]"
bg-color="light-green-1"
></component>
</template>
<template v-else>
<template v-if="!Tools.isEmpty(value) && typeof value === 'object' && value.componentType && value.bindModelValue">
<component :is="value.componentType" v-bind="value.attrs" v-model="props.getRow(table.rows, scope.row[props.rowKeyName], false)[col.name]"></component>
</template>
<template v-else-if="!Tools.isEmpty(value) && typeof value === 'object' && value.componentType">
<component :is="value.componentType" v-bind="value.attrs"></component>
</template>
<template v-else>
<span v-dompurify-html="Tools.isUndefinedOrNull(value) ? '' : value"></span>
</template>
</template>
</q-td>
</template>
<script setup lang="ts">
import { inject, computed, ref } from 'vue';
import { Tools } from '@/platform';
const componentRef = ref();
const props = defineProps({
grid: {
type: Object,
default: () => {},
},
getRow: {
type: Function,
default: () => {},
},
rowKeyName: {
type: String,
default: '',
},
scope: {
type: Object,
default: () => {
return {};
},
},
col: {
type: Object,
default: () => {
return {};
},
},
value: {
type: [Object, String, Number, Boolean],
default: '',
},
isSelectedRow: {
type: Boolean,
default: false,
},
});
const table = inject('table');
const getComponentRef = () => {
return componentRef.value;
};
defineExpose({
getComponentRef,
});
</script>
<style lang="css"></style>

654
io.sc.platform.core.frontend/src/platform/components/grid/GridTop.vue

@ -0,0 +1,654 @@
<template>
<div class="col">
<w-form ref="formRef" v-bind="props.grid.props.queryFormAttrs" :fields="queryFormFieldsComputed" :cols-num="props.grid.props.queryFormColsNum"></w-form>
<div
v-if="props.grid.props.title || buttons_.length > 0 || props.grid.props.configButton || fields.length > 0"
class="flex flex-nowrap items-end"
:class="fields.length > 0 ? 'pt-2.5' : ''"
>
<div class="flex-none">{{ $t(props.grid.props.title ? props.grid.props.title : '') }}</div>
<div class="flex-1">
<w-toolbar
ref="toolbarRef"
:dense="denseToolbarComputed"
v-bind="props.grid.props.toolbarConfigure"
:buttons="toolbarButtonsComputed"
:grid="props.grid"
></w-toolbar>
</div>
<div v-if="props.grid.props.configButton" class="flex-none pl-1">
<q-btn round dense :size="denseToolbarComputed ? '13px' : undefined" icon="manage_accounts" unelevated outline>
<q-popup-proxy v-model="table.gridConfig">
<GridConfig :scope="props.scope" :more-column-title-array="props.moreColumnTitleArray" :grid="props.grid"></GridConfig>
</q-popup-proxy>
</q-btn>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, inject, ref, reactive, nextTick, onBeforeMount, toRaw } from 'vue';
import { useQuasar, exportFile } from 'quasar';
import { axios, Tools, t, NotifyManager } from '@/platform';
import GridConfig from './GridConfig.vue';
const $q = useQuasar();
const formRef = ref();
const toolbarRef = ref();
const localeFlag = ref(false);
const fields = ref(<any>[]);
const buttons_ = ref(<any>[]);
const moreQueryStatus = ref(false); //
const props = defineProps({
grid: {
//
type: Object,
default: () => {
return {};
},
},
scope: {
//
type: Object,
default: () => {
return {};
},
},
moreColumnTitleArray: {
//
type: Array,
default: () => {
return [];
},
},
buildQueryCriterias: {
//
type: Function,
default: () => {},
},
columns: {
//
type: Array,
default: () => {
return [];
},
},
url: {
// url
type: Object,
default: () => {
return {};
},
},
});
const table = inject('table');
const queryFormFieldsComputed = computed(() => {
localeFlag.value;
return fields.value;
});
const toolbarButtonsComputed = computed(() => {
localeFlag.value;
return buttons_.value;
});
const denseToolbarComputed = computed(() => {
if (table.denseToolbar) {
return true;
} else if (table.dense !== false) {
return true;
} else {
return false;
}
});
const screenCols = { xs: 1, sm: 2, md: 3, lg: 4, xl: 6 };
const queryFormColsNumComputed = computed(() => {
if (typeof props.grid.props.queryFormColsNum === 'number' && props.grid.props.queryFormColsNum > 0) {
return props.grid.props.queryFormColsNum;
} else if (typeof props.grid.props.queryFormColsNum === 'object') {
const screen = { ...screenCols, ...props.grid.props.queryFormColsNum };
return screen[$q.screen.name];
}
return screenCols[$q.screen.name];
});
// form
const handlerQueryFormShowField = () => {
fields.value = [];
if (moreQueryStatus.value) {
props.grid.props.queryFormFields.forEach((item: any) => {
fields.value.push(item);
item.showIf = () => {
return true;
};
});
} else {
//
const rowColsNum = queryFormColsNumComputed.value * (props.grid.props.queryFormRowNum || 1);
let currRowColsNum = 0;
props.grid.props.queryFormFields.forEach((item: any) => {
if (Tools.hasOwnProperty(item, 'colSpan')) {
currRowColsNum += item.colSpan;
} else {
currRowColsNum += 1;
}
if (currRowColsNum <= rowColsNum) {
fields.value.push(item);
item.showIf = (form) => {
return true;
};
} else {
item.showIf = (form) => {
return false;
};
}
});
}
};
const edit = (selected) => {
if (!selected) {
NotifyManager.warn(t('action.edit.tip'));
} else {
props.grid.getEditorDialog().show();
nextTick(() => {
props.grid.getEditorDialog().setTitle(t('action.edit'));
props.grid.getEditorForm().setStatus('edit');
props.grid.getEditorForm().setData(selected);
props.grid.emit('afterEditorOpen', selected);
});
}
};
const clone = (selected) => {
if (!selected) {
NotifyManager.warn(t('action.copy.tip'));
} else {
selected[props.grid.props.primaryKey] = undefined;
props.grid.getEditorDialog().show();
nextTick(() => {
props.grid.getEditorDialog().setTitle(t('action.copy'));
props.grid.getEditorForm().setStatus('clone');
props.grid.getEditorForm().setData(selected);
props.grid.emit('afterEditorOpen', selected);
});
}
};
const remove = () => {
const ids = <any>[];
const tickedRows = props.grid.getTickedRows();
const selectedRows = props.grid.getSelectedRows();
if (tickedRows?.length > 0) {
tickedRows.forEach((item) => {
ids.push(item[props.grid.props.primaryKey]);
});
} else if (selectedRows?.length > 0) {
selectedRows.forEach((item) => {
ids.push(item[props.grid.props.primaryKey]);
});
}
let requestParams: any = {
method: 'DELETE',
url: props.url.removeDataUrl || props.url.dataUrl,
data: ids,
};
axios(requestParams)
.then((resp) => {
props.grid.emit('afterRemove', resp?.data);
NotifyManager.info(t('tip.operationSuccess'));
if (props.grid.props.refreshData || !props.grid.props.tree) {
props.grid.refresh();
} else {
props.grid.removeRows(resp?.data);
}
})
.catch((error) => {
console.error(error);
console.info('==========error==========', error);
});
};
const getExportData = async () => {
let resultData = <any>[];
const reqParams: any = { pageable: false };
let urlSearchParams = props.buildQueryCriterias(reqParams);
const resp = await axios.get(props.url.fetchDataUrl || props.url.dataUrl, { params: urlSearchParams });
if (resp && resp.data) {
const responseData = resp.data;
if (Array.isArray(responseData)) {
resultData = responseData;
} else if (typeof responseData === 'object' && responseData.content) {
resultData = responseData.content;
}
}
return resultData;
};
const wrapCsvValue = (val, formatFn, row) => {
let formatted = formatFn !== void 0 ? formatFn(val, row) : val;
formatted = formatted === void 0 || formatted === null ? '' : String(formatted);
formatted = formatted.split('"').join('""');
/**
* Excel accepts \n and \r in strings, but some other CSV parsers do not
* Uncomment the next two lines to escape new lines
*/
// .split('\n').join('\\n')
// .split('\r').join('\\r')
return `"${formatted}"`;
};
const resetDefaultValues = () => {
let requestParams: any = {
method: 'POST',
url: props.url.dataUrl + '/resetDefaultValues',
};
axios(requestParams)
.then((resp) => {
NotifyManager.info(t('tip.operationSuccess'));
props.grid.refresh();
})
.catch((error) => {
console.error(error);
});
};
const showLoading = (msg: string = '正在处理,请稍等...') => {
$q.loading.show({
message: msg,
boxClass: 'bg-grey-2 text-grey-9',
spinnerColor: 'primary',
});
};
const hideLoading = () => {
$q.loading.hide();
};
const buttonObj = reactive({
separator: 'separator',
query: {
name: 'query',
icon: 'search',
labelI18nKey: 'action.query',
label: t('action.query'),
click: () => {
props.grid.refresh();
},
},
moreQuery: {
name: 'moreQuery',
icon: 'zoom_in',
labelI18nKey: 'action.moreQueryConditions',
label: t('action.moreQueryConditions'),
enableIf: () => {
if (props.grid.props.queryFormFields.length <= fields.value.length && !moreQueryStatus.value) {
return false;
} else {
return true;
}
},
click: () => {
moreQueryStatus.value = !moreQueryStatus.value;
handlerQueryFormShowField();
},
},
reset: {
name: 'reset',
icon: 'restart_alt',
labelI18nKey: 'action.reset',
label: t('action.reset'),
click: () => {
formRef.value.reset();
},
},
refresh: {
name: 'refresh',
icon: 'loop',
labelI18nKey: 'action.refresh',
label: t('action.refresh'),
click: () => {
props.grid.refresh();
},
},
add: {
name: 'add',
icon: 'add',
labelI18nKey: 'action.addNew',
label: t('action.addNew'),
click: () => {
props.grid.getEditorDialog().show();
nextTick(() => {
props.grid.getEditorDialog().setTitle(t('action.addNew'));
props.grid.getEditorForm().setStatus('add');
props.grid.emit('afterEditorOpen');
});
},
},
edit: {
name: 'edit',
icon: 'edit',
labelI18nKey: 'action.edit',
label: t('action.edit'),
enableIf: (args) => {
if (args.selected) {
return true;
}
return false;
},
click: (args) => {
edit(args.selected);
},
},
rowEdit: {
name: 'rowEdit',
icon: 'border_color',
labelI18nKey: 'action.edit',
label: t('action.edit'),
enableIf: (args) => {
if (args.selected) {
return true;
}
return false;
},
click: (args) => {
table.bodyEditStatus = 'rowEdit';
},
},
rowsEdit: {
name: 'rowsEdit',
icon: 'app_registration',
labelI18nKey: 'action.edit',
label: t('action.edit'),
click: (args) => {
table.bodyEditStatus = 'rowsEdit';
//
props.grid.cleanSelected();
props.grid.cleanTicked();
table.allTicked = false;
},
},
clone: {
name: 'clone',
icon: 'content_copy',
labelI18nKey: 'action.copy',
label: t('action.copy'),
enableIf: (args) => {
if (args.selected) {
return true;
}
return false;
},
click: (args) => {
clone(args.selected);
},
},
remove: {
name: 'remove',
icon: 'delete',
labelI18nKey: 'action.remove',
label: t('action.remove'),
enableIf: (args) => {
if (args.ticked) {
return true;
} else if (args.selected) {
return true;
}
return false;
},
click: (tips: boolean = true) => {
if (!tips) {
remove();
} else {
$q.dialog({
title: t('confirm'),
message: t('action.remove.tip'),
cancel: { noCaps: true },
ok: { noCaps: true },
persistent: true,
}).onOk(() => {
remove();
});
}
},
},
view: {
name: 'view',
icon: 'visibility',
labelI18nKey: 'action.view',
label: t('action.view'),
enableIf: (args) => {
if (args.selected) {
return true;
}
return false;
},
click: () => {
props.grid.view();
},
},
export: {
name: 'export',
icon: 'file_download',
labelI18nKey: 'action.export',
label: t('action.export'),
click: async () => {
showLoading();
let exportData = props.grid.getRows();
// url
if (!Tools.isEmpty(props.grid.props.fetchDataUrl) || !Tools.isEmpty(props.grid.props.dataUrl)) {
const fetchResult = await getExportData();
if (fetchResult && fetchResult.length > 0) {
exportData = fetchResult;
}
}
const content = [props.columns.map((col) => wrapCsvValue(col.label))]
.concat(
exportData.map((row) =>
props.columns
.map((col) => wrapCsvValue(typeof col.field === 'function' ? col.field(row) : row[col.field === void 0 ? col.name : col.field], col.format, row))
.join(','),
),
)
.join('\r\n');
const status = exportFile('table-export.csv', content, {
encoding: 'utf-8',
mimeType: 'text/csv',
byteOrderMark: '\uFEFF', //
});
if (status !== true) {
NotifyManager.error(t('action.export.failed'));
}
hideLoading();
},
},
addTop: {
name: 'addTop',
icon: 'add',
labelI18nKey: 'action.addTop',
label: t('action.addTop'),
click: () => {
props.grid.getEditorDialog().show();
nextTick(() => {
props.grid.getEditorDialog().setTitle(t('action.addTop'));
props.grid.getEditorForm().setStatus('addTop');
props.grid.emit('afterEditorOpen');
});
},
},
addChild: {
name: 'addChild',
icon: 'playlist_add',
labelI18nKey: 'action.addChild',
label: t('action.addChild'),
enableIf: (args) => {
if (args.selected) {
return true;
}
return false;
},
click: () => {
props.grid.getEditorDialog().show();
nextTick(() => {
props.grid.getEditorDialog().setTitle(t('action.addChild'));
props.grid.getEditorForm().setStatus('addChild');
props.grid.emit('afterEditorOpen');
});
},
},
expand: {
name: 'expand',
icon: (args) => {
return table.treeExpand ? 'expand_less' : 'expand_more';
},
label: (args) => {
return table.treeExpand ? t('action.collapseAll') : t('action.expandAll');
},
click: () => {
props.grid.expandFun(table.rows, table.treeExpand);
table.treeExpand = !table.treeExpand;
},
},
resetDefaultValues: {
name: 'resetDefaultValues',
icon: 'bi-copy',
labelI18nKey: 'action.resetDefaultValues',
label: t('action.resetDefaultValues'),
click: (tips: boolean = true) => {
if (!tips) {
resetDefaultValues();
} else {
$q.dialog({
title: t('confirm'),
message: t('action.resetDefaultValues.tip'),
cancel: { noCaps: true },
ok: { noCaps: true },
persistent: true,
}).onOk(() => {
resetDefaultValues();
});
}
},
},
});
// toobar
const handleChildrenBtn = (arr, moreQueryShow) => {
const tempArr = <any>[];
for (let i = 0; i < arr.length; i++) {
const btn = arr[i];
if (Array.isArray(btn) && btn.length > 0) {
const handleResult = handleChildrenBtn(btn, moreQueryShow);
if (handleResult && handleResult.length > 0) {
tempArr.push(handleResult);
}
} else if (typeof btn === 'string' && buttonObj[btn]) {
if (btn === buttonObj.query.name && i === 0) {
// QBtnDropdown
// ['query', 'reset']
tempArr.push(buttonObj[btn]);
tempArr.push(buttonObj[buttonObj.moreQuery.name]);
} else if (btn === buttonObj.query.name) {
tempArr.push([buttonObj[btn], buttonObj[buttonObj.moreQuery.name]]);
} else {
tempArr.push(buttonObj[btn]);
}
} else if (typeof btn === 'object' && btn.extend && buttonObj[btn.extend]) {
tempArr.push({ ...buttonObj[btn.extend], ...btn, _click: buttonObj[btn.extend].click });
} else {
tempArr.push(btn);
}
}
return tempArr;
};
const handleToolbarActions = () => {
buttons_.value.splice(0, buttons_.value.length);
//
let moreQueryShow = false;
const rowColsNum = queryFormColsNumComputed.value * (props.grid.props.queryFormRowNum || 1);
let currRowColsNum = 0;
let showQueryFormFieldNum = 0;
props.grid.props.queryFormFields.forEach((item: any) => {
if (Tools.hasOwnProperty(item, 'colSpan')) {
currRowColsNum += item.colSpan;
} else {
currRowColsNum += 1;
}
if (currRowColsNum <= rowColsNum) {
showQueryFormFieldNum += 1;
}
});
if (showQueryFormFieldNum < props.grid.props.queryFormFields.length) {
moreQueryShow = true;
}
props.grid.props.toolbarActions.forEach((btn: any, index) => {
if (typeof btn === 'string' && buttonObj[btn]) {
if (btn === buttonObj.query.name && moreQueryShow) {
buttons_.value.push([buttonObj[btn], buttonObj[buttonObj.moreQuery.name]]);
} else {
buttons_.value.push(buttonObj[btn]);
}
} else if (Array.isArray(btn) && btn.length > 0) {
buttons_.value.push(handleChildrenBtn(btn, moreQueryShow));
} else if (typeof btn === 'object' && btn.extend && buttonObj[btn.extend]) {
//
buttons_.value.push({ ...buttonObj[btn.extend], ...btn, _click: buttonObj[btn.extend].click });
} else {
buttons_.value.push(btn);
}
});
if (buttons_.value.length > 0 && buttons_.value[buttons_.value.length - 1] !== 'separator' && props.grid.props.configButton) {
buttons_.value.push(buttonObj.separator);
}
};
const setLocaleFlag = () => {
localeFlag.value = !localeFlag.value;
};
const resetLabel = () => {
Object.keys(buttonObj).forEach((btn) => {
if (typeof buttonObj[btn] === 'object' && buttonObj[btn].labelI18nKey) {
buttonObj[btn].label = t(buttonObj[btn].labelI18nKey);
}
});
};
const buttonClick = (arr) => {
arr.forEach((button) => {
if (typeof button === 'object' && !Tools.isEmpty(button.click) && props.grid.props.dbClickOperation === button.name) {
toolbarRef.value.buttonClick(button);
} else if (Array.isArray(button) && button.length > 0) {
buttonClick(button);
}
});
};
const dbClickOperation = (row) => {
if (!Tools.isEmpty(row) && props.grid.props.dbClickOperation === buttonObj.expand.name) {
row['expand'] = Tools.isEmpty(row['expand']) ? true : !row['expand'];
} else {
buttonClick(buttons_.value);
}
};
const getQueryForm = () => {
return formRef.value;
};
onBeforeMount(() => {
handleToolbarActions();
});
defineExpose({
setLocaleFlag,
edit,
handlerQueryFormShowField,
handleToolbarActions,
resetLabel,
dbClickOperation,
getQueryForm,
});
</script>
<style lang="css"></style>

100
io.sc.platform.core.frontend/src/platform/components/grid/GridView.vue

@ -0,0 +1,100 @@
<template>
<w-drawer ref="drawerRef" :title="$t('action.view')" v-bind="props.grid.props.viewer.drawer">
<div class="p-2.5">
<w-info-panel ref="infoRef" v-bind="props.grid.props.viewer.panel" :info="infoArray"></w-info-panel>
</div>
</w-drawer>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { t, Tools, NotifyManager } from '@/platform';
const drawerRef = ref();
const infoRef = ref();
const props = defineProps({
grid: {
//
type: Object,
default: () => {
return {};
},
},
tableColumnsMap: {
type: Map,
default: () => {
return new Map();
},
},
});
const infoArray = ref(<any>[]);
const view = () => {
const selected = props.grid.getSelectedRow();
if (!selected) {
NotifyManager.warn(t('action.view.tip'));
} else {
infoArray.value = [];
if (props.grid.props.viewer.panel.fields && props.grid.props.viewer.panel.fields.length > 0) {
for (let item of props.grid.props.viewer.panel.fields) {
if (item.format) {
let value = selected[item.name];
try {
value = item.format(selected[item.name], selected[0]);
} catch (error) {
console.error('format error!');
}
infoArray.value.push({ label: item.label, value: value, originalValue: selected[item.name] });
} else {
let value = null;
if (props.tableColumnsMap.get(item.name) && !Tools.isEmpty(props.tableColumnsMap.get(item.name).format)) {
value = selected[item.name];
try {
value = props.tableColumnsMap.get(item.name).format(selected[item.name], selected);
} catch (error) {
console.error('format error!');
}
} else {
value = selected[item.name];
}
infoArray.value.push({ label: item.label, value: value, originalValue: selected[item.name] });
}
}
} else {
for (let item of props.tableColumnsMap) {
if (item[1].format) {
let value = selected[item[0]];
try {
value = item[1].format(selected[item[0]], selected);
} catch (error) {
console.error('format error!');
}
infoArray.value.push({ label: item[1].label, value: value, originalValue: selected[item.name] });
} else {
infoArray.value.push({
label: item[1].label,
value: selected[item[0]],
originalValue: selected[item.name],
});
}
}
}
drawerRef.value.show();
}
};
const getViewerDrawer = () => {
return drawerRef.value;
};
const getInfoPanel = () => {
return infoRef.value;
};
defineExpose({
getViewerDrawer,
getInfoPanel,
view,
});
</script>
<style lang="css"></style>

201
io.sc.platform.core.frontend/src/platform/components/grid/TreeGridRow.vue

@ -3,7 +3,9 @@
ref="trRef"
:class="row[table.selectedField] ? 'selected ' : ''"
:draggable="
(typeof gridProps.draggable === 'boolean' && gridProps.draggable) || (typeof gridProps.draggable === 'string' && gridProps.draggable === 'local')
((typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable) ||
(typeof props.grid.props.draggable === 'string' && props.grid.props.draggable === 'local')) &&
table.bodyEditStatus === 'none'
? true
: false
"
@ -34,7 +36,7 @@
<!--选择框-->
<q-checkbox
v-if="table.checkboxSelection"
v-model="getRow(table.rows, row[props.rowKey], false)[table.tickedField]"
v-model="props.getRow(table.rows, row[props.rowKey], false)[table.tickedField]"
flat
dense
@dblclick.stop="() => {}"
@ -45,6 +47,18 @@
<q-icon v-else-if="typeof iconComputed === 'object'" size="20px" v-bind="iconComputed" class="px-1"></q-icon>
<span v-else class="px-1"></span>
<template v-if="cols[0]">
<template
v-if="!Tools.isEmpty(cols[0]['type']) && ((isSelectedRowComputed && table.bodyEditStatus === 'rowEdit') || table.bodyEditStatus === 'rowsEdit')"
>
<component
:is="cols[0]['type']"
ref="componentOneRef"
v-bind="cols[0]['attrs']"
v-model="props.getRow(table.rows, props.row[props.rowKey], false)['_rowOldValue'][cols[0]['name']]"
bg-color="light-green-1"
></component>
</template>
<template v-else>
<template v-if="cols[0].value && typeof cols[0].value === 'object' && cols[0].value.componentType">
<component :is="cols[0].value.componentType" v-bind="cols[0].value.attrs"></component>
</template>
@ -52,6 +66,7 @@
<span v-dompurify-html="cols[0].value || ''"></span>
</template>
</template>
</template>
</div>
</q-td>
<template v-for="(col, index) in cols" :key="col.name">
@ -61,8 +76,22 @@
:title="col.classes?.indexOf('truncate') > -1 && col.value && typeof col.value !== 'object' ? col.value : ''"
:style="col.style"
>
<template v-if="!Tools.isEmpty(col['type']) && ((isSelectedRowComputed && table.bodyEditStatus === 'rowEdit') || table.bodyEditStatus === 'rowsEdit')">
<component
:is="col['type']"
:ref="(el) => setComponentRef(el, props.row, col)"
v-bind="col['attrs']"
v-model="props.getRow(table.rows, props.row[props.rowKey], false)['_rowOldValue'][col['name']]"
bg-color="light-green-1"
></component>
</template>
<template v-else>
<template v-if="col.value && typeof col.value === 'object' && col.value.componentType && col.value.bindModelValue">
<component :is="col.value.componentType" v-bind="col.value.attrs" v-model="getRow(table.rows, row[props.rowKey], false)[col.name]"></component>
<component
:is="col.value.componentType"
v-bind="col.value.attrs"
v-model="props.getRow(table.rows, row[props.rowKey], false)[col.name]"
></component>
</template>
<template v-else-if="col.value && typeof col.value === 'object' && col.value.componentType">
<component :is="col.value.componentType" v-bind="col.value.attrs"></component>
@ -70,10 +99,20 @@
<template v-else>
<span v-dompurify-html="!Tools.isEmpty(col.value) ? col.value : ''"></span>
</template>
</template>
</q-td>
</template>
</q-tr>
<div></div>
<GridEditToolbar
:grid="props.grid"
:url="props.url"
:row-key-name="props.rowKey"
:row="props.row"
:get-row="props.getRow"
:get-row-component-refs="props.getRowComponentRefs"
:set-old-value="props.setOldValue"
:no-data-tr-colspan="props.noDataTrColspan"
></GridEditToolbar>
<template v-for="child in row.children" :key="child[rowKey]">
<TreeGridRow
v-if="row.expand"
@ -81,21 +120,28 @@
:row="child"
:cols="childColsHandler(child)"
:level="props.level + 1"
:grid-props="gridProps"
:row-key="props.rowKey"
:grid="props.grid"
:grid-row-click="props.gridRowClick"
:grid-row-db-click="gridRowDbClick"
:after-row-draggable="props.afterRowDraggable"
:get-row="props.getRow"
:url="props.url"
:get-row-component-refs="props.getRowComponentRefs"
:set-old-value="props.setOldValue"
:no-data-tr-colspan="props.noDataTrColspan"
></TreeGridRow>
</template>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch, inject, toRaw, nextTick } from 'vue';
import { Tools } from '@/platform';
import { ref, computed, inject, toRaw } from 'vue';
import { Tools, NotifyManager } from '@/platform';
import GridEditToolbar from './GridEditToolbar.vue';
const trRef = ref();
const tdDivRef = ref();
const componentOneRef = ref();
const componentRef = ref({});
const props = defineProps({
level: { type: Number, default: 0 },
columnsMap: {
@ -116,12 +162,6 @@ const props = defineProps({
return [];
},
},
gridProps: {
type: Object,
default: () => {
return {};
},
},
rowKey: { type: String, default: '_rowKey_' },
grid: {
type: Object,
@ -129,6 +169,10 @@ const props = defineProps({
return {};
},
},
getRow: {
type: Function,
default: () => {},
},
gridRowClick: {
type: Function,
default: () => {},
@ -141,6 +185,27 @@ const props = defineProps({
type: Function,
default: () => {},
},
url: {
// url
type: Object,
default: () => {
return {};
},
},
getRowComponentRefs: {
type: Function,
default: () => {},
},
setOldValue: {
type: Function,
default: () => {},
},
noDataTrColspan: {
type: Number,
default: () => {
return 0;
},
},
});
const table = inject('table');
@ -170,14 +235,22 @@ const style = {
},
};
const isSelectedRowComputed = computed(() => {
const selected = props.grid.getSelectedRow();
if (!Tools.isEmpty(selected)) {
return props.row[props.rowKey] === props.grid.getSelectedRow()[props.rowKey];
}
return false;
});
const iconComputed = computed(() => {
if (!Tools.isEmpty(props.row['_dragIcon_'])) {
return {
name: props.row['_dragIcon_'],
color: style.icon.drag.color,
};
} else if (props.gridProps.treeIcon) {
return props.gridProps.treeIcon(props.row);
} else if (props.grid.props.treeIcon) {
return props.grid.props.treeIcon(props.row);
} else {
if (props.row.children && props.row.children.length > 0) {
return {
@ -193,40 +266,30 @@ const iconComputed = computed(() => {
}
});
// key
const getRow = (arr, key, parent) => {
let result = undefined;
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
if (parent ? item[props.gridProps.primaryKey] === key : item[props.rowKey] === key) {
result = item;
break;
} else if (item.children && item.children.length > 0) {
const temp = getRow(item.children, key, parent);
if (temp) {
result = temp;
}
}
}
return result;
};
// /
const expandFun = (row) => {
if (table.bodyEditStatus === 'none') {
row.expand = !row.expand;
} else {
NotifyManager.info('请先保存或取消编辑状态');
}
};
// checkbox
const selectedFun = (value, row, event) => {
if (table.bodyEditStatus === 'none') {
if (value) {
getRow(table.rows, row[props.rowKey], false)[table.tickedField] = true;
props.getRow(table.rows, row[props.rowKey], false)[table.tickedField] = true;
} else {
getRow(table.rows, row[props.rowKey], false)[table.tickedField] = false;
props.getRow(table.rows, row[props.rowKey], false)[table.tickedField] = false;
}
selectedChildren(row, value);
selectedParent(row, value);
if (props.gridProps.onUpdateTicked) {
props.gridProps.onUpdateTicked(event, row);
if (props.grid.props.onUpdateTicked) {
props.grid.props.onUpdateTicked(event, row);
}
} else {
props.getRow(table.rows, row[props.rowKey], false)[table.tickedField] = !props.getRow(table.rows, row[props.rowKey], false)[table.tickedField];
}
};
@ -243,7 +306,7 @@ const selectedChildren = (row, value) => {
//
const selectedParent = (row, value) => {
if (row.parent) {
const parent = getRow(table.rows, row.parent, true);
const parent = props.getRow(table.rows, row.parent, true);
if (parent) {
if (value && childrenSelectedStatus(parent).allSelected) {
parent[table.tickedField] = true;
@ -377,7 +440,7 @@ const removeDragBottomStyle = (e) => {
const setDragIcon = (arr, key: string = '') => {
for (let i = 0; i < arr.length; i++) {
if (arr[i].children && arr[i].children.length > 0) {
if (!Tools.isEmpty(key) && arr[i][props.gridProps.primaryKey] === key) {
if (!Tools.isEmpty(key) && arr[i][props.grid.props.primaryKey] === key) {
if (Tools.isEmpty(arr[i]['_dragIcon_']) || arr[i]['_dragIcon_'] !== style.icon.drag.name) {
arr[i]['_dragIcon_'] = style.icon.drag.name;
}
@ -404,13 +467,13 @@ const canDrag = (dragRecords, targetParentKey) => {
while (!Tools.isEmpty(parentKey)) {
if (
dragRecords.findIndex((item) => {
return item[props.gridProps.primaryKey] === parentKey;
return item[props.grid.props.primaryKey] === parentKey;
}) > -1
) {
result = false;
parentKey = null;
} else {
parentKey = getRow(table.rows, parentKey, true)[props.gridProps.foreignKey];
parentKey = props.getRow(table.rows, parentKey, true)[props.grid.props.foreignKey];
}
}
return result;
@ -436,13 +499,13 @@ const dragRecordsContains = (dataRow) => {
//
const isLastNode = (dataRow) => {
if (Tools.isEmpty(dataRow[props.gridProps.foreignKey])) {
if (table.rows[table.rows.length - 1][props.gridProps.primaryKey] === dataRow[props.gridProps.primaryKey]) {
if (Tools.isEmpty(dataRow[props.grid.props.foreignKey])) {
if (table.rows[table.rows.length - 1][props.grid.props.primaryKey] === dataRow[props.grid.props.primaryKey]) {
return true;
}
} else {
const parent = getRow(table.rows, dataRow[props.gridProps.foreignKey], true);
if (parent.children[parent.children.length - 1][props.gridProps.primaryKey] === dataRow[props.gridProps.primaryKey]) {
const parent = props.getRow(table.rows, dataRow[props.grid.props.foreignKey], true);
if (parent.children[parent.children.length - 1][props.grid.props.primaryKey] === dataRow[props.grid.props.primaryKey]) {
return true;
}
}
@ -474,7 +537,7 @@ const onDragLeave = (e, dataRow) => {
*/
const onDragOver = (e, dataRow) => {
e.preventDefault();
if (!canDrag(table.dragRecords, dataRow[props.gridProps.foreignKey])) {
if (!canDrag(table.dragRecords, dataRow[props.grid.props.foreignKey])) {
removeDragTopStyle(e);
removeDragBottomStyle(e);
setDragIcon(table.rows);
@ -487,8 +550,8 @@ const onDragOver = (e, dataRow) => {
removeDragTopStyle(e);
addDragBottomStyle(e);
}
if (!Tools.isUndefinedOrNull(dataRow[props.gridProps.foreignKey])) {
setDragIcon(table.rows, dataRow[props.gridProps.foreignKey]);
if (!Tools.isUndefinedOrNull(dataRow[props.grid.props.foreignKey])) {
setDragIcon(table.rows, dataRow[props.grid.props.foreignKey]);
} else {
setDragIcon(table.rows);
}
@ -520,7 +583,7 @@ const updateOrderData = <any>[];
//
const setOrder = (arr) => {
arr.forEach((item, index) => {
item[props.gridProps.orderBy] = index + 1;
item[props.grid.props.orderBy] = index + 1;
//
updateOrderData.push(toRaw(item));
});
@ -529,20 +592,20 @@ const setOrder = (arr) => {
//
const addRecord = (e, arr, addData, targetData, dragIndex, targetIndex) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i][props.gridProps.primaryKey] === targetData[props.gridProps.foreignKey]) {
if (arr[i][props.grid.props.primaryKey] === targetData[props.grid.props.foreignKey]) {
if (
e.offsetY <= gridTrMiddleHeightComputed.value &&
isTrue(dragIndex, targetIndex) &&
addData[props.gridProps.foreignKey] === targetData[props.gridProps.foreignKey]
addData[props.grid.props.foreignKey] === targetData[props.grid.props.foreignKey]
) {
arr[i].children.splice(targetIndex - 1, 0, addData);
} else if (e.offsetY > gridTrMiddleHeightComputed.value && addData[props.gridProps.foreignKey] !== targetData[props.gridProps.foreignKey]) {
} else if (e.offsetY > gridTrMiddleHeightComputed.value && addData[props.grid.props.foreignKey] !== targetData[props.grid.props.foreignKey]) {
arr[i].children.splice(arr[i].children.length, 0, addData);
} else {
arr[i].children.splice(targetIndex, 0, addData);
}
//
addData[props.gridProps.foreignKey] = arr[i][props.gridProps.primaryKey];
addData[props.grid.props.foreignKey] = arr[i][props.grid.props.primaryKey];
//
setOrder(arr[i].children);
break;
@ -565,14 +628,14 @@ const resetOrderDataHandler = (e, dragRecords, targetData, targetIndex) => {
dragRecords.forEach((item) => {
const itemIndex = removeRecord(table.rows, item);
// 2
if (Tools.isEmpty(targetData[props.gridProps.foreignKey])) {
if (Tools.isEmpty(targetData[props.grid.props.foreignKey])) {
// 3使splice-11
if (e.offsetY <= gridTrMiddleHeightComputed.value && Tools.isEmpty(item[props.gridProps.foreignKey]) && isTrue(itemIndex, targetIndex)) {
if (e.offsetY <= gridTrMiddleHeightComputed.value && Tools.isEmpty(item[props.grid.props.foreignKey]) && isTrue(itemIndex, targetIndex)) {
table.rows.splice(targetIndex - 1, 0, item);
} else {
table.rows.splice(targetIndex, 0, item);
}
item[props.gridProps.foreignKey] = null;
item[props.grid.props.foreignKey] = null;
setOrder(table.rows);
//
updateOrderData.push(...toRaw(table.rows));
@ -613,7 +676,7 @@ const onDrop = (e, dataRow) => {
resetOrder(e, table.dragRecords, table.rows, dataRow);
//
if (typeof props.gridProps.draggable === 'boolean' && props.gridProps.draggable && updateOrderData?.length > 0) {
if (typeof props.grid.props.draggable === 'boolean' && props.grid.props.draggable && updateOrderData?.length > 0) {
props.grid.updates(updateOrderData);
}
@ -621,17 +684,37 @@ const onDrop = (e, dataRow) => {
};
const click = (evt, row, rowIndex) => {
if (table.bodyEditStatus === 'none') {
if (!evt.ctrlKey) {
props.grid.cleanSelected();
}
row[table.selectedField] = true;
if (props.gridProps.onRowClick) {
props.gridProps.onRowClick(evt, row, rowIndex);
if (props.grid.props.onRowClick) {
props.grid.props.onRowClick(evt, row, rowIndex);
}
}
};
const dbClick = (evt, row, rowIndex) => {
props.gridRowDbClick(evt, row, rowIndex);
};
const setComponentRef = (el, row, col) => {
if (el && !Tools.isEmpty(col.type)) {
componentRef.value[row[props.rowKey] + '_' + col.name] = el;
}
};
const getComponentOneRef = () => {
return componentOneRef.value;
};
const getComponentRef = () => {
return componentRef.value;
};
defineExpose({
getComponentRef,
getComponentOneRef,
});
</script>
<style lang="css">

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

File diff suppressed because it is too large

39
io.sc.platform.core.frontend/src/platform/components/grid/WTreeGrid.vue

@ -1,39 +0,0 @@
<template>
<q-table :binary-state-sort="true" column-sort-order="ad" :v-bind="attrs">
<template #top>
<div class="row">
<div class="col">{{ attrs.title }}</div>
<div class="col items-end">
<q-btn label="dksfj"></q-btn>
</div>
</div>
</template>
</q-table>
</template>
<script setup lang="ts">
import { useAttrs } from 'vue';
import { useI18n } from 'vue-i18n';
import { Tools } from '@/platform/utils/Tools';
const attrs = useAttrs();
const { t } = useI18n();
for (const column of attrs.columns) {
if (Tools.isUndefinedOrNull(column.label)) {
column.label = t(column.name);
}
if (Tools.isUndefinedOrNull(column.field)) {
column.field = column.name;
}
if (Tools.isUndefinedOrNull(column.align)) {
column.align = 'left';
}
if (Tools.isUndefinedOrNull(column.sortable)) {
column.sortable = true;
}
if (Tools.isUndefinedOrNull(column.sortOrder)) {
column.sortOrder = 'da';
}
}
</script>

645
io.sc.platform.core.frontend/src/platform/components/grid/css/grid.css

@ -0,0 +1,645 @@
.w-grid .q-table__top {
padding: var(--tableTopPadding) var(--tableTopPadding);
}
.w-grid .q-table__middle .q-table th {
padding: var(--tableHeaderPadding) 8px;
border-left-width: 0px;
border-right-width: 1px;
border-top-width: 0px;
border-bottom-width: 1px;
}
.w-grid .q-table__middle .q-table th:last-child {
border-right-width: 0px;
}
.w-grid .q-table__middle .q-table td {
height: var(--tableBodyHeight);
padding: var(--tableBodyPadding) 8px;
border-left-width: 0px;
border-right-width: 1px;
border-top-width: 0px;
border-bottom-width: 1px;
}
.w-grid .q-table__middle .q-table td:last-child {
border-right-width: 0px;
}
.w-grid .q-table__bottom {
min-height: var(--tableBottomHeight);
border-color: rgba(0, 0, 0, 0.12);
border-style: solid;
border-top-width: 0px;
border-left-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
}
.w-grid .q-table__control .q-field__control {
min-height: var(--tableBottomButtonHeight) !important;
}
.w-grid .q-table__control .q-field__control q-field__append {
height: var(--tableBottomButtonHeight) !important;
}
.w-grid .q-table__control .q-field__control-container .q-field__native {
min-height: var(--tableBottomButtonHeight) !important;
padding: 0 !important;
}
.w-grid .q-table__control .q-field__control .q-field__marginal {
height: var(--tableBottomButtonHeight) !important;
}
.w-grid .q-table__card .q-table__middle {
border-color: rgba(0, 0, 0, 0.12);
border-style: solid;
border-left-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
}
.sticky-header-column-table thead tr:not(.noDataTr) {
height: var(--tableColumnTitleHeight) !important;
}
/** 表格所有th固定、设置默认index、背景设置 */
.sticky-header-column-table tr th {
position: sticky;
z-index: 2;
background: var(--tableHeadBgColor);
}
/** 固定表头后,修改top距离 */
.sticky-header-column-table thead {
position: sticky;
z-index: 2;
top: 0;
}
.sticky-header-column-table-tr-1-1 tr:first-child th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-1-2 tr:first-child th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-1-2-rb tr:first-child th:nth-child(2) {
border-right-width: 1px;
}
.sticky-header-column-table-tr-1-3 tr:first-child th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-1-4 tr:first-child th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-1-5 tr:first-child th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-1-6 tr:first-child th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-1-7 tr:first-child th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-1-8 tr:first-child th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-1-9 tr:first-child th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-1-10 tr:first-child th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-tr-2-1 tr:nth-child(2) th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-2-2 tr:nth-child(2) th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-2-3 tr:nth-child(2) th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-2-4 tr:nth-child(2) th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-2-5 tr:nth-child(2) th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-2-6 tr:nth-child(2) th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-2-7 tr:nth-child(2) th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-2-8 tr:nth-child(2) th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-2-9 tr:nth-child(2) th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-2-10 tr:nth-child(2) th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-tr-3-1 tr:nth-child(3) th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-3-2 tr:nth-child(3) th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-3-3 tr:nth-child(3) th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-3-4 tr:nth-child(3) th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-3-5 tr:nth-child(3) th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-3-6 tr:nth-child(3) th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-3-7 tr:nth-child(3) th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-3-8 tr:nth-child(3) th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-3-9 tr:nth-child(3) th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-3-10 tr:nth-child(3) th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-tr-4-1 tr:nth-child(4) th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-4-2 tr:nth-child(4) th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-4-3 tr:nth-child(4) th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-4-4 tr:nth-child(4) th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-4-5 tr:nth-child(4) th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-4-6 tr:nth-child(4) th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-4-7 tr:nth-child(4) th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-4-8 tr:nth-child(4) th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-4-9 tr:nth-child(4) th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-4-10 tr:nth-child(4) th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-tr-5-1 tr:nth-child(5) th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-5-2 tr:nth-child(5) th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-5-3 tr:nth-child(5) th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-5-4 tr:nth-child(5) th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-5-5 tr:nth-child(5) th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-5-6 tr:nth-child(5) th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-5-7 tr:nth-child(5) th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-5-8 tr:nth-child(5) th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-5-9 tr:nth-child(5) th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-5-10 tr:nth-child(5) th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-tr-6-1 tr:nth-child(6) th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-6-2 tr:nth-child(6) th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-6-3 tr:nth-child(6) th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-6-4 tr:nth-child(6) th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-6-5 tr:nth-child(6) th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-6-6 tr:nth-child(6) th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-6-7 tr:nth-child(6) th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-6-8 tr:nth-child(6) th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-6-9 tr:nth-child(6) th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-6-10 tr:nth-child(6) th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-tr-7-1 tr:nth-child(7) th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-7-2 tr:nth-child(7) th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-7-3 tr:nth-child(7) th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-7-4 tr:nth-child(7) th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-7-5 tr:nth-child(7) th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-7-6 tr:nth-child(7) th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-7-7 tr:nth-child(7) th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-7-8 tr:nth-child(7) th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-7-9 tr:nth-child(7) th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-7-10 tr:nth-child(7) th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-tr-8-1 tr:nth-child(8) th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-8-2 tr:nth-child(8) th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-8-3 tr:nth-child(8) th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-8-4 tr:nth-child(8) th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-8-5 tr:nth-child(8) th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-8-6 tr:nth-child(8) th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-8-7 tr:nth-child(8) th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-8-8 tr:nth-child(8) th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-8-9 tr:nth-child(8) th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-8-10 tr:nth-child(8) th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-tr-9-1 tr:nth-child(9) th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-9-2 tr:nth-child(9) th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-9-3 tr:nth-child(9) th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-9-4 tr:nth-child(9) th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-9-5 tr:nth-child(9) th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-9-6 tr:nth-child(9) th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-9-7 tr:nth-child(9) th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-9-8 tr:nth-child(9) th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-9-9 tr:nth-child(9) th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-9-10 tr:nth-child(9) th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-tr-10-1 tr:nth-child(10) th:first-child {
z-index: 3;
position: sticky;
left: 0px;
}
.sticky-header-column-table-tr-10-2 tr:nth-child(10) th:nth-child(2) {
z-index: 3;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-tr-10-3 tr:nth-child(10) th:nth-child(3) {
z-index: 3;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-tr-10-4 tr:nth-child(10) th:nth-child(4) {
z-index: 3;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-tr-10-5 tr:nth-child(10) th:nth-child(5) {
z-index: 3;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-tr-10-6 tr:nth-child(10) th:nth-child(6) {
z-index: 3;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-tr-10-7 tr:nth-child(10) th:nth-child(7) {
z-index: 3;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-tr-10-8 tr:nth-child(10) th:nth-child(8) {
z-index: 3;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-tr-10-9 tr:nth-child(10) th:nth-child(9) {
z-index: 3;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-tr-10-10 tr:nth-child(10) th:nth-child(10) {
z-index: 3;
position: sticky;
left: var(--column9Width);
}
.sticky-header-column-table-td-1 td:first-child {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: 0px;
}
.sticky-header-column-table-td-2 td:nth-child(2) {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: var(--column1Width);
}
.sticky-header-column-table-td-3 td:nth-child(3) {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: var(--column2Width);
}
.sticky-header-column-table-td-4 td:nth-child(4) {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: var(--column3Width);
}
.sticky-header-column-table-td-5 td:nth-child(5) {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: var(--column4Width);
}
.sticky-header-column-table-td-6 td:nth-child(6) {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: var(--column5Width);
}
.sticky-header-column-table-td-7 td:nth-child(7) {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: var(--column6Width);
}
.sticky-header-column-table-td-8 td:nth-child(8) {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: var(--column7Width);
}
.sticky-header-column-table-td-9 td:nth-child(9) {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: var(--column8Width);
}
.sticky-header-column-table-td-10 td:nth-child(10) {
background-color: var(--stickyBgColor);
z-index: 1;
position: sticky;
left: var(--column9Width);
}

59
io.sc.platform.core.frontend/src/platform/components/grid/ts/grid.ts

@ -0,0 +1,59 @@
import { Tools, t, componentRegistryName } from '@/platform';
// 列样式处理
const columnStyle = (item: any) => {
let style = '';
if (Tools.hasOwnProperty(item, 'style')) {
style = item.style;
}
if (Tools.hasOwnProperty(item, 'width')) {
if (typeof item.width === 'number') {
item.style = `min-width: ` + item.width + `px; width: ` + item.width + `px;max-width: ` + item.width + `px;` + style;
} else {
item.style = `min-width: ` + item.width + `; width: ` + item.width + `;max-width: ` + item.width + `;` + style;
}
delete item.width;
if (Tools.hasOwnProperty(item, 'classes')) {
item.classes = item.classes + ' truncate';
} else {
item.classes = 'truncate';
}
}
};
// 孩子列处理
const childrenHandler = (item: any, gridColumns: any) => {
if (item.columns && item.columns.length > 0) {
item.columns.forEach((column) => {
childrenHandler(column, gridColumns);
});
} else {
columnStyle(item);
// 替换行编辑类型为注册名
if (!Tools.isEmpty(item.type)) {
item.type = componentRegistryName(item.type);
}
const col = {
...{ align: 'left', label: item.name, field: item.name, name: item.name, sortable: true, hidden: false },
...item,
};
if (Tools.isEmpty(col.name)) {
col.name = Tools.uuid();
}
gridColumns.push(col);
}
};
// 列的默认属性
export const columnDefaultProps = (columns: any, sortNo: boolean = true) => {
const gridColumns = <any>[];
if (columns && columns.length > 0) {
gridColumns.push({ name: '_sortNo_', align: 'center', label: t('rownum'), field: '_sortNo_', hidden: sortNo });
columns.forEach((item: any) => {
childrenHandler(item, gridColumns);
});
return gridColumns;
}
return [];
};

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

@ -161,16 +161,6 @@ export { OptionComeFromEnum } from './utils';
export { FormComponentValidateEnum } from './utils';
export { OperatorTypeEnum } from './utils';
export type { CriteriaType } from './utils';
export { PlatformNotifyTypeEnum } from './utils';
export { platformNotify } from './utils';
export { isEmpty } from './utils';
export { extractDialogProps } from './utils';
export { extractFormProps } from './utils';
export { extractFormItemComponentProps } from './utils';
export { extractTableProps } from './utils';
export { extractTableColumnsProps } from './utils';
export { getQueryFormColsNumberByScreen } from './utils';
export { arrayToMap } from './utils';
export { arrayToMap, componentRegistryName } from './utils';
export { FormValidators } from './utils';

4
io.sc.platform.core.frontend/src/platform/components/toolbar/WToolbar.vue

@ -480,6 +480,10 @@ const buttonClick = async (button) => {
}
}
};
defineExpose({
buttonClick,
});
</script>
<style lang="css">

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

@ -1,4 +1,4 @@
import { QVueGlobals } from 'quasar';
import { Tools } from '@/platform';
/**
* icon使material icons
@ -148,39 +148,52 @@ export type CriteriaType = {
};
/**
*
* key转map
* @param key
* @param array
*/
export enum PlatformNotifyTypeEnum {
= 'positive',
= 'negative',
= 'warning',
= 'info',
= 'ongoing',
export function arrayToMap(key, array) {
const map = new Map();
array.forEach((item) => {
if (item.name !== '_sortNo_') {
map.set(item[key], item);
}
/**
*
* @param message
* @param type PlatformNotifyTypeEnum PlatformNotifyTypeEnum.
*/
export function platformNotify($q: QVueGlobals, message: string, type?: PlatformNotifyTypeEnum) {
$q.notify({
message: message,
position: 'top',
type: type ?? PlatformNotifyTypeEnum.,
actions: [{ label: '知道了', handler: () => {} }],
timeout: 3000,
});
return map;
}
/**
* (Form元素)
* @param obj
* @returns
*
*/
const component = {
checkbox: 'w-checkbox',
cron: 'w-cron',
'color-input': 'w-color-input',
'color-input-palette': 'w-color-input-palette',
'code-mirror': 'w-code-mirror',
position: 'w-position',
date: 'w-date',
icon: 'w-icon',
number: 'w-number',
select: 'w-select',
'tree-select': 'w-tree-select',
text: 'w-text',
textarea: 'w-textarea',
'text-btn': 'w-text-btn',
password: 'w-password',
'option-group': 'w-option-group',
file: 'w-file',
expression: 'w-expression',
math: 'w-math',
};
/**
*
* @param name
*/
export function isEmpty(obj) {
if (typeof obj === 'undefined' || obj === null || obj === '') {
return true;
} else {
return false;
export function componentRegistryName(name: string) {
const tempName = name.replace(/([A-Z])/g, '-$1').toLowerCase();
if (!Tools.isEmpty(component[tempName])) {
return component[tempName];
}
return name;
}

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

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

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

@ -6,16 +6,6 @@ export { OptionComeFromEnum } from './commUtil';
export { FormComponentValidateEnum } from './commUtil';
export { OperatorTypeEnum } from './commUtil';
export type { CriteriaType } from './commUtil';
export { PlatformNotifyTypeEnum } from './commUtil';
export { platformNotify } from './commUtil';
export { isEmpty } from './commUtil';
export { extractDialogProps } from './componentComm';
export { extractFormProps } from './componentComm';
export { extractFormItemComponentProps } from './componentComm';
export { extractTableProps } from './componentComm';
export { extractTableColumnsProps } from './componentComm';
export { getQueryFormColsNumberByScreen } from './componentComm';
export { arrayToMap } from './componentComm';
export { arrayToMap, componentRegistryName } from './commUtil';
export { FormValidators } from './FormValidators';

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

@ -167,14 +167,4 @@ export { OptionComeFromEnum } from './components';
export { FormComponentValidateEnum } from './components';
export { OperatorTypeEnum } from './components';
export type { CriteriaType } from './components';
export { PlatformNotifyTypeEnum } from './components';
export { platformNotify } from './components';
export { isEmpty } from './components';
export { extractDialogProps } from './components';
export { extractFormProps } from './components';
export { extractFormItemComponentProps } from './components';
export { extractTableProps } from './components';
export { extractTableColumnsProps } from './components';
export { getQueryFormColsNumberByScreen } from './components';
export { arrayToMap } from './components';
export { arrayToMap, componentRegistryName } from './components';

54
io.sc.platform.core.frontend/src/views/likm/Grid.vue

@ -109,18 +109,41 @@
:data-url="Environment.apiContextPath('/api/system/application')"
:sort-by="['order']"
:query-form-cols-num="3"
db-click-operation="rowEdit"
: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']"
:toolbar-actions="[
'query',
'refresh',
'separator',
'rowEdit',
'rowsEdit',
'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() },
{ name: 'order', label: $t('order'), type: 'number', attrs: { required: true } },
{ name: 'code', label: $t('code'), type: 'text', attrs: { required: true } },
{
name: 'name',
label: $t('name'),
type: 'text',
format: (val, row) => {
return val;
},
},
{ width: 80, name: 'enable', label: $t('status'), format: Formater.enableTag(), type: 'checkbox' },
{ width: 120, name: 'lastModifier', label: $t('lastModifier') },
{ width: 120, name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.dateOnly() },
]"
@ -159,12 +182,21 @@
],
},
}"
@row-click="(evt, row, index) => {}"
@row-click="
(evt, row, index) => {
// console.info('rowclick');
}
"
@before-request-data="() => {}"
@after-row-draggable="
(grid, updateDatas) => {
console.info('grid=====', grid);
console.info('updateDatas======', updateDatas);
// console.info('grid=====', grid);
// console.info('updateDatas======', updateDatas);
}
"
@after-editor-open="
() => {
console.info('打开窗口');
}
"
>
@ -178,6 +210,12 @@ import { axios, Environment, EnumTools, Options, Formater } from '@/platform';
import EnableIcon from '@/platform/components/grid/EnableIcon.vue';
import { IconEnum } from '@/platform/enums';
// :query-criteria="{
// operator: 'equals',
// fieldName: 'code',
// value: 'A',
// }"
const dialogRef = ref();
const gridRef = ref();
const grid2 = ref();

18
io.sc.platform.core.frontend/src/views/likm/GridForamt.vue

@ -0,0 +1,18 @@
<template>
<template v-if="props.value && typeof props.value === 'object' && props.value.componentType">
<component :is="props.value.componentType" v-bind="props.value.attrs"></component>
</template>
<template v-else-if="props.value">
{{ props.value }}
{{ props.value }}
</template>
</template>
<script setup lang="ts">
const props = defineProps({
value: {
type: [Object, String, Number, Boolean],
default: '',
},
});
</script>
<style lang="css"></style>

801
io.sc.platform.core.frontend/src/views/likm/QuasarGrid.vue

@ -1,752 +1,69 @@
<!-- <template>
<q-splitter :model-value="65" class="w-full h-full">
<template #before>
<div class="px-1">
<w-grid
ref="userGridRef"
:title="$t('system.user.grid.title')"
selection="multiple"
:query-form-fields="[
{ name: 'loginName', label: $t('loginName'), type: 'text' },
{ name: 'userName', label: $t('userName'), type: 'text' },
{ name: 'enable', label: $t('isEnable'), type: 'select', options: Options.yesNo() },
{ name: 'dataComeFrom', label: $t('dataComeFrom'), type: 'select', options: Options.enum(DataComeFromEnum) },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'query',
'refresh',
'separator',
'add',
'clone',
'edit',
'remove',
'separator',
{
name: 'setPassword',
label: t('system.user.action.setPassword'),
icon: 'bi-shield-check',
enableIf: function (selecteds) {
return selecteds.length > 0;
},
click: function (selecteds) {
setPasswordDialogRef.open('setPassword', selecteds);
},
},
{
name: 'setAllPassword',
label: t('system.user.action.setAllPassword'),
icon: 'bi-shield',
enableIf: function (selecteds) {
return true;
},
click: function () {
setPasswordDialogRef.open('setAllPassword');
},
},
'separator',
{
name: 'resetPassword',
label: t('system.user.action.resetPassword'),
icon: 'bi-shield-fill-check',
enableIf: function (selecteds) {
return selecteds.length > 0;
},
click: function (selecteds) {
DialogManager.confirm(t('system.user.confirm.resetPassword'), () => {
const userIds = Tools.extractProperties(selecteds, 'id');
axios.post(Environment.apiContextPath('/api/system/user/resetPassword'), userIds).then(() => {
NotifyManager.info(t('operationSuccess'));
});
});
},
},
{
name: 'resetAllPassword',
label: t('system.user.action.resetAllPassword'),
icon: 'bi-shield-fill',
enableIf: function (selecteds) {
return true;
},
click: function () {
DialogManager.confirm(t('system.user.confirm.resetAllPassword'), () => {
axios.post(Environment.apiContextPath('/api/system/user/resetAllPassword')).then(() => {
setPasswordDialogRef.value.hide();
NotifyManager.info(t('operationSuccess'));
});
});
},
},
'separator',
'view',
'export',
]"
:data-url="Environment.apiContextPath('/api/system/user')"
row-key="id"
:columns="[
{ name: 'loginName', label: t('loginName') },
{ name: 'userName', label: t('userName') },
{
name: 'status',
label: t('status'),
format: (value, row) => {
return {
componentType: UserStatusTag,
attrs: row,
};
},
},
{ name: 'dataComeFrom', label: t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) },
{ name: 'lastModifier', label: t('lastModifier') },
{ name: 'lastModifyDate', label: t('lastModifyDate'), format: Formater.dateOnly() },
]"
:editor="{
dialog: {
width: '600px',
height: '610px',
},
form: {
colsNum: 4,
fields: [
{ name: 'loginName', label: t('loginName'), type: 'text', required: true, colspan: 4 },
{ name: 'userName', label: t('userName'), type: 'text', required: true, colspan: 4 },
{ name: 'description', label: t('description'), type: 'textarea', rows: 1, colspan: 4 },
{ name: 'password', label: t('password'), type: 'password', colspan: 4 },
{
name: 'confirmPassword',
label: t('confirmPassword'),
type: 'password',
colspan: 4,
rules: [
(value) => {
return Tools.stringEquals(userGridRef.getAddEditFormRef().value.getData().password, value)
? true
: t('passwordAndConfirmPasswordMustEqual');
},
],
},
{ name: 'mobile', label: t('mobile'), type: 'text', colsFirst: true, colspan: 4 },
{ name: 'phone', label: t('phone'), type: 'text', colsFirst: true, colspan: 4 },
{ name: 'email', label: t('email'), type: 'text', colsFirst: true, colspan: 4 },
{ name: 'weixin', label: t('weixin'), type: 'text', colsFirst: true, colspan: 4 },
{ name: 'qq', label: t('qq'), type: 'text', colsFirst: true, colspan: 4 },
{ name: 'enable', label: t('enable'), type: 'checkbox', defaultValue: true },
{ name: 'accountExpired', label: t('accountExpired'), type: 'checkbox', defaultValue: false },
{ name: 'accountLocked', label: t('accountLocked'), type: 'checkbox', defaultValue: false },
{ name: 'credentialsExpired', label: t('credentialsExpired'), type: 'checkbox', defaultValue: false },
],
},
}"
: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: Formater.yesNo() },
{ name: 'accountExpired', label: t('accountExpired'), format: Formater.yesNo() },
{ name: 'accountLocked', label: t('accountLocked'), format: Formater.yesNo() },
{ name: 'credentialsExpired', label: t('credentialsExpired'), format: Formater.yesNo() },
{ 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'), 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) => {
currentSelectedUserId = row.id;
roleQueryUrl = Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + currentSelectedUserId;
orgQueryUrl = Environment.apiContextPath('/api/system/org/listAllOrgsWithSelectedStatusByUser?userId=') + currentSelectedUserId;
roleGridRef?.refresh();
orgTreeGridRef?.refresh();
// if (roleGridRef) {
// roleGridRef.setFetchDataUrl(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + row.id);
// }
// if (orgTreeGridRef) {
// orgTreeGridRef.setFetchDataUrl(Environment.apiContextPath('/api/system/org/listAllOrgsWithSelectedStatusByUser?userId=') + row.id);
// orgTreeGridRef.refresh();
// }
}
"
></w-grid>
</div>
</template>
<template #after>
<div class="px-1">
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0">
<q-tab name="role" icon="bi-people" :label="$t('role')" />
<q-tab name="org" icon="bi-diagram-3" :label="$t('org')" />
</q-tabs>
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive class="">
<q-tab-panel name="role" class="p-0">
<w-grid
ref="roleGridRef"
:title="$t('system.role.grid.title')"
:data-url="roleQueryUrl"
:auto-fetch-data="false"
selection="multiple"
:full-screen-button="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'addRole',
label: $t('system.role.action.addRole'),
enableIf: () => {
if (userGridRef) {
return userGridRef.getSelectedRows().length > 0;
}
return false;
},
click: () => {
selectRoleDialog.open({ userId: userGridRef.getSelectedRows()[0].id, userGrid: userGridRef, roleGrid: roleGridRef });
},
},
{
name: 'addAllRole',
label: t('system.role.action.addAllRole'),
enableIf: () => {
if (userGridRef) {
return userGridRef.getSelectedRows().length > 0;
}
return false;
},
click: () => {
const selectedUser = userGridRef.getSelectedRows()[0];
DialogManager.confirm(
t('system.role.action.addAllRole.confirm', { userLoginName: selectedUser.loginName, userName: selectedUser.userName }),
() => {
axios
.post(Environment.apiContextPath('/api/system/user/addAllRoles'), {
one: selectedUser.id,
many: [],
})
.then((response) => {
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + selectedUser.id).then((response) => {
roleGridRef.replaceRows(response.data.content);
});
});
},
);
},
},
'separator',
{
name: 'removeRole',
label: t('system.role.action.removeRole'),
enableIf: () => {
if (userGridRef && roleGridRef) {
return userGridRef.getSelectedRows().length > 0 && roleGridRef.getSelectedRows().length > 0;
}
return false;
},
click: (selecteds) => {
const selectedUser = userGridRef.getSelectedRows()[0];
const roleIds = Tools.extractProperties(selecteds, 'id');
const messageKey = roleIds.length > 1 ? 'system.role.action.removeRole.confirms' : 'system.role.action.removeRole.confirm';
DialogManager.confirm(
t(messageKey, {
userLoginName: selectedUser.loginName,
userName: selectedUser.userName,
roleCode: selecteds[0].code,
roleName: selecteds[0].name,
counter: selecteds.length,
}),
() => {
axios
.post(Environment.apiContextPath('/api/system/user/removeRoles'), {
one: selectedUser.id,
many: roleIds,
})
.then((response) => {
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + selectedUser.id).then((response) => {
roleGridRef.replaceRows(response.data.content);
});
});
},
);
},
},
{
name: 'removeAllRole',
label: $t('system.role.action.removeAllRole'),
enableIf: () => {
if (userGridRef && roleGridRef) {
return userGridRef.getSelectedRows().length > 0 && roleGridRef.getRows().length > 0;
}
return false;
},
click: () => {
const selectedUser = userGridRef.getSelectedRows()[0];
DialogManager.confirm(
t('system.role.action.removeAllRole.confirm', { userLoginName: selectedUser.loginName, userName: selectedUser.userName }),
() => {
axios
.post(Environment.apiContextPath('/api/system/user/removeAllRoles'), {
one: selectedUser.id,
many: [],
})
.then((response) => {
axios.get(Environment.apiContextPath('/api/system/role/queryRolesByUser?userId=') + selectedUser.id).then((response) => {
roleGridRef.replaceRows(response.data.content);
});
});
},
);
},
},
'separator',
'view',
]"
:columns="[
{ width: 100, name: 'code', label: $t('code') },
{ width: 100, name: 'name', label: $t('name') },
{
width: 60,
name: 'status',
label: t('status'),
format: (value, row) => {
return {
componentType: RoleStatusTag,
attrs: row,
};
},
},
]"
: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.yesNo() },
{ 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') },
],
},
}"
></w-grid>
</q-tab-panel>
<q-tab-panel name="org" class="px-0">
<w-grid
ref="orgTreeGridRef"
:tree="true"
:title="$t('system.org.grid.title')"
:data-url="orgQueryUrl"
selection="multiple"
:full-screen-button="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'save',
label: $t('save'),
click: () => {},
},
'view',
]"
:pagination="{
sortBy: 'name',
descending: false,
reqPageStart: 0,
rowsPerPage: 0,
}"
:columns="[
{ width: 100, name: 'code', label: $t('code') },
{ width: 100, name: 'name', label: $t('name') },
{
width: 60,
name: 'status',
label: t('status'),
format: (value, row) => {
return {
componentType: RoleStatusTag,
attrs: row,
};
},
},
]"
: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.yesNo() },
{ 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') },
],
},
}"
></w-grid>
</q-tab-panel>
</q-tab-panels>
</div>
</template>
<SelectRoleDialog ref="selectRoleDialog"></SelectRoleDialog>
<SetPasswordDialog ref="setPasswordDialogRef"></SetPasswordDialog>
</q-splitter>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment, axios, EnumTools, NotifyManager, DialogManager, Formater, Options, Tools } from '@/platform';
import SelectRoleDialog from './SelectRoleDialog.vue';
import SetPasswordDialog from './SetPasswordDialog.vue';
import UserStatusTag from './UserStatusTag.vue';
import RoleStatusTag from './RoleStatusTag.vue';
import { nextTick } from 'vue';
const { t } = useI18n();
const userGridRef = ref();
const roleGridRef = ref();
const orgTreeGridRef = ref();
const selectRoleDialog = ref();
const selectedTabRef = ref('role');
const setPasswordDialogRef = ref();
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom');
const currentSelectedUserId = ref();
const roleQueryUrl = ref('');
const orgQueryUrl = ref('');
const orgConfigure = {
actions: [
{
name: 'save',
label: '保存',
click: () => {
axios
.post(Environment.apiContextPath('/api/system/user/updateOrgs'), {
one: userGridRef.value.getSelectedRows()[0].id,
many: orgTreeGridRef.value.getTicked(),
})
.then((response) => {});
},
},
],
};
</script> -->
<template>
<q-splitter :model-value="60" class="w-full h-full">
<template #before>
<div class="px-1">
<w-grid
ref="roleGridRef"
:title="$t('system.role.grid.title')"
:data-url="Environment.apiContextPath('/api/system/role')"
selection="multiple"
: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() },
{ name: 'dataComeFrom', label: $t('dataComeFrom'), type: 'select', options: Options.enum(DataComeFromEnum) },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'add', 'clone', 'edit', 'remove', 'separator', 'view', 'export']"
:columns="[
{ name: 'code', label: $t('code') },
{ name: 'name', label: $t('name') },
{ width: 80, name: 'status', label: $t('status'), format: Formater.enableTag() },
{ width: 100, name: 'dataComeFrom', label: $t('dataComeFrom'), format: Formater.enum(DataComeFromEnum) },
{ 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: '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.yesNo() },
{ 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) => {
currentSelectedRoleId = row.id;
userGridRef?.refresh();
menuTreeGridRef?.refresh();
}
"
>
</w-grid>
<div class="q-pa-md">
<q-table v-model:selected="selected" title="Treats" row-key="name" selection="multiple" :rows="rows" :columns="columns">
<template #body="scope">
<q-tr ref="trRef" class="selected" :props="scope">
<q-td class="text-center" style="padding: 0; width: 50px">
<q-checkbox v-model="scope.row['selected']" flat @update:model-value="updateTicked($event, scope.row)" />
</q-td>
<q-td v-for="col in scope.cols" :key="col.name" :props="scope">
<GridFormat :value="col.value"></GridFormat>
</q-td>
</q-tr>
</template>
</q-table>
</div>
</template>
<template #after>
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0" no-caps>
<q-tab name="menu" icon="bi-people" :label="$t('menu')" />
<q-tab name="user" icon="bi-diagram-3" :label="$t('user')" />
</q-tabs>
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive>
<q-tab-panel name="menu" class="px-0">
<w-grid
ref="menuTreeGridRef"
:tree="true"
:title="$t('system.org.grid.title')"
:data-url="Environment.apiContextPath('/api/system/menu/listAllMenusWithSelectedStatusByRole?roleId=') + currentSelectedRoleId"
selection="multiple"
:pageable="false"
:full-screen-button="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'save',
label: $t('save'),
click: () => {
axios
.post(Environment.apiContextPath('/api/system/role/updateMenus'), {
one: userGridRef.getSelectedRows()[0].id,
many: menuTreeGridRef.getTicked(),
})
.then((response) => {});
},
},
'view',
]"
:columns="[
{
width: 100,
name: 'titleI18nKey',
label: $t('name'),
format: (value, row) => {
return $t(value);
},
},
{ width: 60, 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'), format: Formater.yesNo() },
{ 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') },
],
},
}"
></w-grid>
</q-tab-panel>
<q-tab-panel name="user" class="px-0">
<w-grid
ref="userGridRef"
:title="$t('system.role.selectUser.grid.title')"
:fetch-data-url="Environment.apiContextPath('/api/system/user/queryUsersByRole?roleId=') + currentSelectedRoleId"
:auto-fetch-data="false"
selection="multiple"
:full-screen-button="false"
:toolbar-configure="{ noIcon: true }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'addUser',
label: $t('system.role.selectUser.grid.toolbar.addUser'),
enableIf: () => {
if (roleGridRef) {
return roleGridRef.getSelectedRows().length > 0;
}
return false;
},
click: () => {
selectUserDialog.open({ roleId: roleGridRef.getSelectedRows()[0].id, userGrid: userGridRef });
},
},
{
name: 'addAllUser',
label: $t('system.role.selectUser.grid.toolbar.addAllUser'),
enableIf: () => {
if (roleGridRef) {
return roleGridRef.getSelectedRows().length > 0;
}
return false;
},
click: () => {
const selectedRole = roleGridRef.getSelectedRows()[0];
DialogManager.confirm($t('system.role.selectUser.grid.toolbar.addAllUser.tip'), () => {
axios
.post(Environment.apiContextPath('/api/system/role/addAllUsers'), {
one: selectedRole.id,
many: [],
})
.then((response) => {
userGridRef?.refresh();
});
});
},
},
'separator',
{
name: 'removeUser',
label: $t('system.role.selectUser.grid.toolbar.removeUser'),
enableIf: () => {
if (roleGridRef && userGridRef) {
return roleGridRef.getSelectedRows().length > 0 && userGridRef.getSelectedRows().length > 0;
}
return false;
},
click: (selecteds) => {
const selectedRole = roleGridRef.getSelectedRows()[0];
const userIds = Tools.extractProperties(selecteds, 'id');
DialogManager.confirm($t('system.role.selectUser.grid.toolbar.removeUser.tip'), () => {
axios
.post(Environment.apiContextPath('/api/system/role/removeUsers'), {
one: selectedRole.id,
many: userIds,
})
.then((response) => {
userGridRef?.refresh();
});
});
},
},
{
name: 'removeAllUser',
label: $t('system.role.selectUser.grid.toolbar.removeAllUser'),
enableIf: () => {
if (roleGridRef) {
return roleGridRef.getSelectedRows().length > 0;
}
return false;
},
click: () => {
const selectedRole = roleGridRef.getSelectedRows()[0];
DialogManager.confirm($t('system.role.selectUser.grid.toolbar.removeAllUser.tip'), () => {
axios
.post(Environment.apiContextPath('/api/system/role/removeAllUsers'), {
one: selectedRole.id,
many: [],
})
.then((response) => {
userGridRef?.refresh();
});
});
},
},
'separator',
'view',
]"
: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>
</q-tab-panel>
</q-tab-panels>
</template>
<SelectUserDialog ref="selectUserDialog"></SelectUserDialog>
</q-splitter>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment, axios, DialogManager, Tools, EnumTools, Options, Formater } from '@/platform';
import SelectUserDialog from './SelectUserDialog.vue';
import UserStatusTag from './UserStatusTag.vue';
import { Tools } from '@/platform';
import GridFormat from './GridForamt.vue';
const { t } = useI18n();
const selected = ref([]);
const DataComeFromEnum = await EnumTools.fetch('io.sc.platform.orm.api.enums.DataComeFrom');
const roleGridRef = ref();
const userGridRef = ref();
const menuTreeGridRef = ref();
const selectUserDialog = ref();
const selectedTabRef = ref('user');
const currentSelectedRoleId = ref('');
const menuConfigure = {
actions: [
{
name: 'save',
label: '保存',
click: () => {
axios
.post(Environment.apiContextPath('/api/system/role/updateMenus'), {
one: roleGridRef.value.getSelectedRows()[0].id,
many: menuTreeGridRef.value.getTicked(),
})
.then((response) => {});
},
},
],
const updateTicked = (event, row) => {
row['selected'] = !row['selected'];
};
const columns = [
{
name: 'name',
required: true,
label: 'Dessert (100g serving)',
align: 'left',
field: (row) => row.name,
sortable: true,
},
{ name: 'calories', align: 'center', label: 'Calories', field: 'calories', sortable: true },
{
name: 'fat',
label: 'Fat (g)',
field: 'fat',
sortable: true,
format: (val, row) => {
console.info('format.val====', val);
return val;
},
},
{ name: 'carbs', label: 'Carbs (g)', field: 'carbs' },
{ name: 'protein', label: 'Protein (g)', field: 'protein' },
{ name: 'sodium', label: 'Sodium (mg)', field: 'sodium' },
{ name: 'calcium', label: 'Calcium (%)', field: 'calcium', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) },
{ name: 'iron', label: 'Iron (%)', field: 'iron', sortable: true, sort: (a, b) => parseInt(a, 10) - parseInt(b, 10) },
];
const rows = [
{
name: 'Frozen Yogurt',
calories: 159,
fat: 6.0,
carbs: 24,
protein: 4.0,
sodium: 87,
calcium: '14%',
iron: '1%',
selected: false,
},
];
</script>

32
io.sc.platform.core.frontend/src/views/likm/TreeGrid.vue

@ -8,6 +8,7 @@
tree
:tree-icon="(row) => {}"
:checkbox-selection="true"
db-click-operation="rowEdit"
:data-url="testGrid.dataUrl"
:fetch-data-url="testGrid.fetchDataUrl"
:columns="testGrid.tableColumns"
@ -59,29 +60,9 @@ const testGrid = {
'reset',
'refresh',
'separator',
{
name: 'custBtn',
extend: 'add',
icon: undefined,
label: '自定义按钮',
enableIf: (selected, grid) => {
if (selected && selected.length > 0) {
return true;
}
return false;
},
// beforeClick: (selected, context, grid) => {
// console.info('before');
// context.aaa = '111';
// },
click: (selected, context, _click, grid) => {
_click(selected);
},
afterClick: (selected, context, grid) => {
console.info('=grid==', grid.getEditorForm());
// gridRefs.addEditFormRef.setFieldValue('userName', '');
},
},
'rowEdit',
'rowsEdit',
'separator',
'addTop',
'addChild',
'expand',
@ -111,6 +92,7 @@ const testGrid = {
name: 'name',
label: '菜单名称',
// width: 500,
type: 'text',
format: (val, row) => {
return t(row.name);
},
@ -118,6 +100,10 @@ const testGrid = {
{
name: 'icon',
label: '图标',
type: 'icon',
attrs: {
required: true,
},
format: (val, row) => {
return {
componentType: 'q-icon',

178
io.sc.platform.core.frontend/template-project/src/views/testcase/math/MathEditorForm.vue

@ -1,178 +0,0 @@
<template>
<div style="height: 100%">
<w-grid
ref="gridRef"
:title="$t('re.resources.designer.processor.grid.title')"
dense-body
class="px-1"
hide-bottom
:config-button="false"
selection="multiple"
:checkbox-selection="true"
:tree="false"
:fetch-data-url="Environment.apiContextPath('/api/re/model/parameter/processor/findByParameterId?parameterId=' + parameterId)"
:data-url="Environment.apiContextPath('/api/re/model/parameter/processor')"
:pageable="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'refresh',
'separator',
{
extend: 'edit',
enableIf: (arg) => {
return arg.selected;
},
},
{
extend: 'remove',
enableIf: (arg) => {
return !readOnly && arg.selected;
},
},
'separator',
'view',
'separator',
'export',
]"
:columns="[
{ width: 80, name: 'enable', label: $t('isEnable'), align: 'center', sortable: false, format: Formater.enableTag() },
{ width: 60, name: 'order', label: $t('order'), sortable: false, align: 'right' },
{ width: 150, name: 'type', label: $t('type'), sortable: false, format: Formater.enum(Enums.ProcessorType) },
{
width: '100%',
name: 'content',
label: $t('re.resources.designer.processor.grid.entity.content'),
sortable: false,
format: (value, row) => {
const type = row.type;
if ('MATH_FORMULA' === type) {
return {
componentType: 'w-expression',
attrs: {
modelValue: row.mathFormula,
readOnly: true,
zoom: 2,
},
};
}
},
},
]"
:editor="{
dialog: {
width: '1024px',
},
form: {
colsNum: 1,
fields: [
{ name: 'parameter', label: 'parameter', type: 'text', defaultValue: parameterId, hidden: true },
{ name: 'id', label: $t('id'), type: 'text', hidden: true },
{ name: 'order', label: $t('order'), type: 'number', hidden: true },
{ name: 'type', label: $t('type'), type: 'text', hidden: true },
{ name: 'description', label: $t('description'), type: 'text', hidden: true },
{ name: 'enable', label: $t('enable'), type: 'checkbox', defaultValue: true, hidden: true },
{
name: 'mathFormula',
label: $t('re.resources.designer.processor.grid.entity.mathFormula'),
type: 'expression',
showIf: (arg) => {
return 'MATH_FORMULA' === arg.form.getFieldValue('type');
},
},
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'order', label: $t('order') },
{ name: 'id', label: $t('id'), primaryKey: true },
{ name: 'parameter', label: $t('parameter') },
{ name: 'description', label: $t('description') },
{ name: 'enable', label: $t('enable') },
{ name: 'type', label: $t('type') },
{ name: 'optionCode', label: $t('re.resources.designer.processor.grid.entity.optionCode') },
{ name: 'arithmetic', label: $t('re.resources.designer.processor.grid.entity.arithmetic') },
{ name: 'ternaryCondition', label: $t('re.resources.designer.processor.grid.entity.ternaryCondition') },
{ name: 'ternaryTrue', label: $t('re.resources.designer.processor.grid.entity.ternaryTrue') },
{ name: 'ternaryFalse', label: $t('re.resources.designer.processor.grid.entity.ternaryFalse') },
{ name: 'when', label: $t('re.resources.designer.processor.grid.entity.when') },
{ name: 'then', label: $t('re.resources.designer.processor.grid.entity.then') },
{ name: 'isWhenThenShorted', label: $t('re.resources.designer.processor.grid.entity.isWhenThenShorted') },
{ name: 'rule', label: $t('re.resources.designer.processor.grid.entity.rule') },
{ name: 'singleRule', label: $t('re.resources.designer.processor.grid.entity.singleRule') },
{ name: 'numberRange', label: $t('re.resources.designer.processor.grid.entity.numberRange') },
{ name: 'conditionRange', label: $t('re.resources.designer.processor.grid.entity.conditionRange') },
{ name: 'decisionTable2C', label: $t('re.resources.designer.processor.grid.entity.decisionTable2C') },
{ name: 'decisionTable', label: $t('re.resources.designer.processor.grid.entity.decisionTable') },
{ name: 'groovyScript', label: $t('re.resources.designer.processor.grid.entity.groovyScript') },
{ name: 'sqlDatasourceName', label: $t('re.resources.designer.processor.grid.entity.sqlDatasourceName') },
{ name: 'sql', label: $t('re.resources.designer.processor.grid.entity.sql') },
{ name: 'sqlParameterValues', label: $t('re.resources.designer.processor.grid.entity.sqlParameterValues') },
{ name: 'sqlFieldMapping', label: $t('re.resources.designer.processor.grid.entity.sqlFieldMapping') },
{ 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() },
],
},
}"
@before-editor-data-submit="
(data, callback) => {
console.log(data);
}
"
></w-grid>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { axios, Environment, Formater, Tools, EnumTools, Options } from '@/platform';
import { ComponentContainer } from '@univerjs/ui';
import { RowHeaderLayout } from '@univerjs/engine-render';
const props = defineProps({
fetchDataUrl: { type: String, default: '' },
dataUrl: { type: String, default: '' },
parameter: { type: Object, default: undefined },
readOnly: { type: Boolean, default: false },
});
const emit = defineEmits<{
(e: 'rowClick', evt: Event, row: any, index: number): void;
(e: 'beforeRequestData', requestParams: URLSearchParams | any, callback: any): void;
}>();
const gridRef = ref();
const autoCompletionOptionsRef = ref([]);
const optionOptionsRef = ref([]);
const decisionTreeDialogRef = ref();
const executionFlowDialogRef = ref();
const parameterId = '8c114166-aae3-4590-b63a-6daa64eb15ac';
const transfromContent = (xml) => {
const div = document.createElement('div');
div.textContent = xml;
const result = div.outerHTML;
div.parentNode?.removeChild(div);
return result;
};
const refresh = () => {
gridRef.value.refresh();
};
onMounted(() => {
gridRef.value.refresh();
});
defineExpose({
refresh,
});
const Enums = await EnumTools.fetch(['io.sc.engine.rule.core.enums.ProcessorType']);
</script>
Loading…
Cancel
Save