mirror of
https://gitee.com/orangeform/orange-admin.git
synced 2026-01-17 18:46:36 +08:00
commit:升级到vue3,更新最近工作流技术栈,支持sa-token
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div class="active-widget-menu">
|
||||
<el-icon v-if="clone != null" @click.stop="onCopy"><CopyDocument /></el-icon>
|
||||
<el-icon style="margin-left: 3px" @click.stop="onDelete"><Delete /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CopyDocument, Delete } from '@element-plus/icons-vue';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const emit = defineEmits<{
|
||||
copy: [ANY_OBJECT];
|
||||
delete: [ANY_OBJECT];
|
||||
}>();
|
||||
const props = defineProps<{
|
||||
widget: ANY_OBJECT;
|
||||
clone?: (widget: ANY_OBJECT) => ANY_OBJECT | null;
|
||||
}>();
|
||||
|
||||
const cloneWidget = (widget: ANY_OBJECT) => {
|
||||
if (props.clone && typeof props.clone === 'function') {
|
||||
return props.clone(widget);
|
||||
}
|
||||
console.warn('not found clone method');
|
||||
return null;
|
||||
};
|
||||
const onCopy = () => {
|
||||
const widget = cloneWidget(props.widget);
|
||||
if (widget) {
|
||||
emit('copy', widget);
|
||||
}
|
||||
};
|
||||
const onDelete = () => {
|
||||
emit('delete', props.widget);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.active-widget-menu {
|
||||
position: absolute;
|
||||
right: -1px;
|
||||
bottom: -1px;
|
||||
z-index: 1000;
|
||||
height: 20px;
|
||||
padding: 0 5px;
|
||||
color: white;
|
||||
background: $color-primary;
|
||||
border-radius: 2px 0 0;
|
||||
line-height: 20px;
|
||||
i {
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
262
OrangeFormsOpen-VUE3/src/online/components/OnlineBaseCard.vue
Normal file
262
OrangeFormsOpen-VUE3/src/online/components/OnlineBaseCard.vue
Normal file
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<el-card
|
||||
class="online-base-card form-card base-card"
|
||||
:shadow="widget.props.shadow"
|
||||
:body-style="{
|
||||
padding: (widget.props.padding == null ? 15 : widget.props.padding) + 'px',
|
||||
}"
|
||||
:style="{
|
||||
'margin-bottom':
|
||||
(widget.props.paddingBottom || (widget.props.basicInfo || {}).paddingBottom || 0) + 'px',
|
||||
}"
|
||||
>
|
||||
<template v-slot:header>
|
||||
<div class="base-card-header table-draggable">
|
||||
<span>{{ widget.showName }}</span>
|
||||
<div class="base-card-operation"></div>
|
||||
</div>
|
||||
</template>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-row :gutter="form().gutter">
|
||||
<VueDraggable
|
||||
draggable=".custom-widget-item"
|
||||
v-model="childWidgetList"
|
||||
group="componentsGroup"
|
||||
:style="getDrableBoxStyle"
|
||||
style="position: relative; overflow: hidden; width: 100%"
|
||||
:disabled="!isEdit"
|
||||
:move="onDragMove"
|
||||
>
|
||||
<template v-if="childWidgetList.length > 0">
|
||||
<el-col
|
||||
class="custom-widget-item"
|
||||
:class="{ active: isEdit && form().isActive(subWidget) }"
|
||||
v-for="subWidget in childWidgetList"
|
||||
:key="subWidget.variableName"
|
||||
:span="subWidget.props.span"
|
||||
>
|
||||
<div
|
||||
class="widget-item"
|
||||
:class="{ active: isEdit && form().isActive(subWidget) }"
|
||||
v-if="form().getWidgetVisible(subWidget)"
|
||||
>
|
||||
<div
|
||||
v-if="subWidget.widgetType === SysCustomWidgetType.Table"
|
||||
:style="getTableStyle(subWidget)"
|
||||
style="margin-bottom: 18px"
|
||||
>
|
||||
<OnlineCardTable
|
||||
:widget="subWidget"
|
||||
:value="form().getTableData(subWidget)"
|
||||
@input="(dataList:ANY_OBJECT[]) => form().setTableData(subWidget, dataList)"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Block"
|
||||
:style="getBlockStyle(subWidget)"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineCustomBlock
|
||||
v-model:value="subWidget.childWidgetList"
|
||||
:isEdit="isEdit"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Card"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineBaseCard
|
||||
:widget="subWidget"
|
||||
:isEdit="isEdit"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Tabs"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineCustomTabs
|
||||
:widget="subWidget"
|
||||
:isEdit="isEdit"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Text"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineCustomWidget
|
||||
:ref="subWidget.variableName"
|
||||
:widget="subWidget"
|
||||
:isEdit="isEdit"
|
||||
:value="getWidgetValue(subWidget) || subWidget.props.text"
|
||||
:style="{
|
||||
'margin-bottom': (subWidget.props.paddingBottom || 0) + 'px',
|
||||
}"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Image"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineCustomWidget
|
||||
:ref="subWidget.variableName"
|
||||
:widget="subWidget"
|
||||
:isEdit="isEdit"
|
||||
:value="getWidgetValue(subWidget)"
|
||||
:src="subWidget.props.src"
|
||||
:style="{
|
||||
'margin-bottom': (subWidget.props.paddingBottom || 0) + 'px',
|
||||
}"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
</div>
|
||||
<el-form-item
|
||||
v-else
|
||||
:label="subWidget.showName"
|
||||
:prop="subWidget.propString"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineCustomWidget
|
||||
:widget="subWidget"
|
||||
:value="getWidgetValue(subWidget)"
|
||||
@input="(val:ANY_OBJECT) => onValueChange(subWidget, val)"
|
||||
@change="(val:ANY_OBJECT|null, dictData:ANY_OBJECT|null) => onWidgetValueChange(subWidget, val, dictData)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<ActiveWidgetMenu
|
||||
v-if="isEdit && form().isActive(subWidget)"
|
||||
:widget="subWidget"
|
||||
:clone="form().cloneWidget"
|
||||
@copy="onCopyWidget"
|
||||
@delete="onDeleteWidget(subWidget)"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</template>
|
||||
<div v-else-if="isEdit" class="info">
|
||||
<div style="width: 100px; height: 100px">
|
||||
<el-icon><UploadFilled /></el-icon>
|
||||
</div>
|
||||
<span>请拖入组件进行编辑</span>
|
||||
</div>
|
||||
</VueDraggable>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'OnlineBaseCard',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { UploadFilled } from '@element-plus/icons-vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { SysCustomWidgetType } from '@/common/staticDict';
|
||||
import OnlineCustomBlock from '@/online/components/OnlineCustomBlock.vue';
|
||||
import OnlineCardTable from './OnlineCardTable.vue';
|
||||
import OnlineCustomWidget from './OnlineCustomWidget.vue';
|
||||
import ActiveWidgetMenu from './ActiveWidgetMenu.vue';
|
||||
import { WidgetProps, WidgetEmit } from './types/widget';
|
||||
import { useWidget } from './hooks/widget';
|
||||
import OnlineCustomTabs from './OnlineCustomTabs.vue';
|
||||
|
||||
const emit = defineEmits<WidgetEmit>();
|
||||
|
||||
interface CardProps extends WidgetProps {
|
||||
// 是否显示边框
|
||||
showBorder?: boolean;
|
||||
height?: string;
|
||||
}
|
||||
const props = withDefaults(defineProps<CardProps>(), {
|
||||
value: () => [],
|
||||
isEdit: false,
|
||||
showBorder: true,
|
||||
});
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCustomBaseCard: form not injected');
|
||||
return { isEdit: false } as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const { childWidgetList, onWidgetClick, onDeleteWidget, onCopyWidget } = useWidget(props, emit);
|
||||
|
||||
const getDrableBoxStyle = computed(() => {
|
||||
let tempHeight = props.height;
|
||||
if (props.height == null || props.height === '') {
|
||||
tempHeight = props.isEdit && props.widget.childWidgetList.length <= 0 ? '150px' : '0px';
|
||||
}
|
||||
return {
|
||||
'min-height': tempHeight,
|
||||
};
|
||||
});
|
||||
|
||||
const getTableStyle = (widget: ANY_OBJECT) => {
|
||||
if (widget.widgetType !== SysCustomWidgetType.Table) return;
|
||||
return {};
|
||||
};
|
||||
const getBlockStyle = (widget: ANY_OBJECT) => {
|
||||
return {
|
||||
'margin-bottom': (widget.props.paddingBottom || 0) + 'px',
|
||||
padding: props.isEdit ? '5px' : undefined,
|
||||
border: props.isEdit ? '1px solid #e8eaec' : undefined,
|
||||
};
|
||||
};
|
||||
|
||||
const getWidgetValue = (widget: ANY_OBJECT) => {
|
||||
return form().getWidgetValue(widget);
|
||||
};
|
||||
|
||||
const onDragMove = (e: ANY_OBJECT) => {
|
||||
// 容器组件不能改变位置
|
||||
let widgetType = e.relatedContext.element ? e.relatedContext.element.widgetType : undefined;
|
||||
return widgetType !== SysCustomWidgetType.Block && widgetType !== SysCustomWidgetType.Card;
|
||||
};
|
||||
|
||||
const onValueChange = (widget: ANY_OBJECT, value: ANY_OBJECT) => {
|
||||
return form().onValueChange(widget, value);
|
||||
};
|
||||
const onWidgetValueChange = (
|
||||
widget: ANY_OBJECT,
|
||||
value: ANY_OBJECT | null,
|
||||
dictData: ANY_OBJECT | null,
|
||||
) => {
|
||||
return form().onWidgetValueChange(widget, value, dictData);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.info {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
flex-direction: column;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.info div {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
font-size: 60px;
|
||||
text-align: center;
|
||||
border: 1px dashed #d9dbdd;
|
||||
border-radius: 6px;
|
||||
line-height: 100px;
|
||||
}
|
||||
.info span {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
217
OrangeFormsOpen-VUE3/src/online/components/OnlineCardTable.vue
Normal file
217
OrangeFormsOpen-VUE3/src/online/components/OnlineCardTable.vue
Normal file
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<el-card class="online-card-table base-card" shadow="never" :body-style="{ padding: '0px' }">
|
||||
<el-row>
|
||||
<el-col
|
||||
:span="24"
|
||||
:style="{
|
||||
height: widget.props.height != null ? widget.props.height - 53 + 'px' : undefined,
|
||||
}"
|
||||
>
|
||||
<OnlineCustomTable
|
||||
:dataList="tableWidget.dataList"
|
||||
:widget="widget"
|
||||
:height="widget.props.height ? widget.props.height - 53 : 200"
|
||||
border="default"
|
||||
:multiSelect="batchDelete"
|
||||
:operationList="widget.operationList"
|
||||
:getTableIndex="tableWidget.getTableIndex"
|
||||
:sortChange="tableWidget.onSortChange"
|
||||
:onSelectChange="onSelectRowChange"
|
||||
@operationClick="onOperationClick"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { useTable } from '@/common/hooks/useTable';
|
||||
import { TableOptions } from '@/common/types/pagination';
|
||||
import { OnlineFormEventType, SysCustomWidgetOperationType } from '@/common/staticDict';
|
||||
import { findItemFromList } from '@/common/utils';
|
||||
import OnlineCustomTable from './OnlineCustomTable.vue';
|
||||
|
||||
const emit = defineEmits<{ input: [ANY_OBJECT[]] }>();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
value: Array<ANY_OBJECT>;
|
||||
widget: ANY_OBJECT;
|
||||
}>(),
|
||||
{ value: () => [], isEdit: false, showBorder: true },
|
||||
);
|
||||
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCardTable: form not injected');
|
||||
return { isEdit: false } as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const selectRows = ref<ANY_OBJECT[]>([]);
|
||||
const batchDelete = ref(false);
|
||||
|
||||
const loadTableData = () => {
|
||||
return Promise.resolve({
|
||||
dataList: props.value,
|
||||
totalCount: props.value.length,
|
||||
});
|
||||
};
|
||||
const loadTableDataVerify = () => {
|
||||
return true;
|
||||
};
|
||||
const tableOptions: TableOptions<ANY_OBJECT> = {
|
||||
loadTableData: loadTableData,
|
||||
verifyTableParameter: loadTableDataVerify,
|
||||
};
|
||||
const tableWidget = reactive(useTable(tableOptions));
|
||||
|
||||
const refresh = () => {
|
||||
tableWidget.refreshTable(true, 1);
|
||||
};
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
refresh();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
const handlerEditOperate = (row: ANY_OBJECT | null, res: ANY_OBJECT) => {
|
||||
if (props.widget.relation != null) {
|
||||
if (row == null) {
|
||||
console.log('新增记录', res, props, tableWidget);
|
||||
// 新增记录
|
||||
row = res[props.widget.relation.variableName];
|
||||
onTableDataListChange([
|
||||
...tableWidget.dataList,
|
||||
{
|
||||
...row,
|
||||
__cascade_add_id__: new Date().getTime(),
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
console.log('更新记录', res, props, tableWidget);
|
||||
// 更新记录
|
||||
// TODO 为什么这里要重新赋值
|
||||
//row = res[props.widget.relation.variableName];
|
||||
onTableDataListChange(
|
||||
tableWidget.dataList.map((item: ANY_OBJECT) => {
|
||||
if (row != null && row.__cascade_add_id__ != null) {
|
||||
return row.__cascade_add_id__ === item.__cascade_add_id__ ? row : item;
|
||||
} else {
|
||||
return row != null &&
|
||||
row[props.widget.primaryColumnName] === item[props.widget.primaryColumnName]
|
||||
? row
|
||||
: item;
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
const onSelectRowChange = (rows: ANY_OBJECT[]) => {
|
||||
selectRows.value = rows;
|
||||
};
|
||||
const onOperationClick = (operation: ANY_OBJECT, row: ANY_OBJECT | null) => {
|
||||
if (operation.type === SysCustomWidgetOperationType.BATCH_DELETE) {
|
||||
onBatchDelete(operation);
|
||||
} else if (operation.type === SysCustomWidgetOperationType.DELETE && row != null) {
|
||||
onDeleteRow(row);
|
||||
} else {
|
||||
console.log('OnlineCardTable onOperationClick -> form', operation, form());
|
||||
form().handlerOperation(operation, {
|
||||
isEdit: form().isEdit,
|
||||
saveData: false,
|
||||
widget: props.widget,
|
||||
rowData: row,
|
||||
callback: (res: ANY_OBJECT) => {
|
||||
handlerEditOperate(row, res);
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
const onBatchDelete = (operation: ANY_OBJECT) => {
|
||||
console.log('onBatchDelete operation', operation);
|
||||
if (selectRows.value.length <= 0) {
|
||||
ElMessage.error('请选择要批量删除的数据!');
|
||||
return;
|
||||
}
|
||||
ElMessageBox.confirm('是否删除选中数据?', '', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
onTableDataListChange(
|
||||
tableWidget.dataList.filter(row => {
|
||||
// 通过主键查找
|
||||
let temp = findItemFromList(
|
||||
selectRows.value,
|
||||
row[props.widget.primaryColumnName],
|
||||
props.widget.primaryColumnName,
|
||||
);
|
||||
// 通过新增临时主键查找
|
||||
if (temp == null && row.__cascade_add_id__ != null) {
|
||||
temp = findItemFromList(selectRows.value, row.__cascade_add_id__, '__cascade_add_id__');
|
||||
}
|
||||
return temp == null;
|
||||
}),
|
||||
);
|
||||
});
|
||||
};
|
||||
const onDeleteRow = (data: ANY_OBJECT) => {
|
||||
ElMessageBox.confirm('是否删除当前数据?', '', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
onTableDataListChange(
|
||||
tableWidget.dataList.filter(row => {
|
||||
if (data.__cascade_add_id__ != null) {
|
||||
return data.__cascade_add_id__ !== row.__cascade_add_id__;
|
||||
} else {
|
||||
return data[props.widget.primaryColumnName] !== row[props.widget.primaryColumnName];
|
||||
}
|
||||
}),
|
||||
);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
const onTableDataListChange = (dataList: ANY_OBJECT[]) => {
|
||||
emit('input', dataList);
|
||||
};
|
||||
const refreshData = (data: ANY_OBJECT) => {
|
||||
if (data.path === 'thirdOnlineEditForm/' + props.widget.variableName) {
|
||||
handlerEditOperate(data.rowData, data.data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
//let widget = props.widget;
|
||||
//widget.widgetImpl = getCurrentInstance();
|
||||
window.addEventListener(
|
||||
'message',
|
||||
event => {
|
||||
if (event.data.type === 'refreshData') {
|
||||
refreshData(event.data.data);
|
||||
}
|
||||
},
|
||||
false,
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.base-card :deep(.el-card__header) {
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
.online-card-table :deep(.vxe-table--border-line) {
|
||||
border: none !important;
|
||||
}
|
||||
</style>
|
||||
325
OrangeFormsOpen-VUE3/src/online/components/OnlineCustomBlock.vue
Normal file
325
OrangeFormsOpen-VUE3/src/online/components/OnlineCustomBlock.vue
Normal file
@@ -0,0 +1,325 @@
|
||||
<template>
|
||||
<el-row class="online-custom-block" :gutter="0">
|
||||
<el-col :span="24">
|
||||
<el-row :gutter="form().gutter">
|
||||
<VueDraggable
|
||||
class="custom-block-draggable"
|
||||
:class="form().mode === 'pc' ? 'el-row' : ''"
|
||||
draggable=".custom-widget-item"
|
||||
v-model="values"
|
||||
group="componentsGroup"
|
||||
ghostClass="ghost"
|
||||
chosenClass="chosen"
|
||||
:style="getDrableBoxStyle"
|
||||
style="position: relative; display: contents; overflow: hidden; width: 100%"
|
||||
:disabled="!isEdit"
|
||||
:move="onDragMove"
|
||||
@add="onDragAdd"
|
||||
>
|
||||
<template v-if="Array.isArray(value) && value.length > 0">
|
||||
<el-col
|
||||
class="custom-widget-item"
|
||||
:class="{ active: isEdit && form().isActive(subWidget) }"
|
||||
v-for="subWidget in value"
|
||||
:key="subWidget.variableName"
|
||||
:span="subWidget.props.span || (subWidget.props.basicInfo || {}).span"
|
||||
>
|
||||
<div
|
||||
class="widget-item"
|
||||
:class="{ active: isEdit && form().isActive(subWidget) }"
|
||||
v-if="form().getWidgetVisible(subWidget)"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<div
|
||||
v-if="subWidget.widgetType === SysCustomWidgetType.Table"
|
||||
:style="getTableStyle(subWidget)"
|
||||
>
|
||||
<OnlineCardTable
|
||||
:widget="subWidget"
|
||||
:ref="subWidget.variableName"
|
||||
:value="form().getTableData(subWidget)"
|
||||
@input="(dataList:ANY_OBJECT[]) => form().setTableData(subWidget, dataList)"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Block"
|
||||
:style="getBlockStyle(subWidget)"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineCustomBlock
|
||||
:ref="subWidget.variableName"
|
||||
v-model:value="subWidget.childWidgetList"
|
||||
:isEdit="isEdit"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Card"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineBaseCard
|
||||
:ref="subWidget.variableName"
|
||||
:widget="subWidget"
|
||||
:isEdit="isEdit"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Tabs"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineCustomTabs
|
||||
:ref="subWidget.variableName"
|
||||
:widget="subWidget"
|
||||
:isEdit="isEdit"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
</div>
|
||||
<OnlineCustomWidget
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Text"
|
||||
:ref="subWidget.variableName"
|
||||
:widget="subWidget"
|
||||
:isEdit="isEdit"
|
||||
:value="getWidgetValue(subWidget) || subWidget.props.text"
|
||||
:style="{
|
||||
'margin-bottom': (subWidget.props.paddingBottom || 0) + 'px',
|
||||
}"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
<OnlineCustomWidget
|
||||
v-else-if="subWidget.widgetType === SysCustomWidgetType.Image"
|
||||
:ref="subWidget.variableName"
|
||||
:widget="subWidget"
|
||||
:isEdit="isEdit"
|
||||
:value="getWidgetValue(subWidget)"
|
||||
:src="subWidget.props.src"
|
||||
:style="{
|
||||
'margin-bottom': (subWidget.props.paddingBottom || 0) + 'px',
|
||||
}"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
<component
|
||||
:is="form().mode === 'pc' ? ElFormItem : 'div'"
|
||||
v-else
|
||||
:label="subWidget.showName"
|
||||
inset
|
||||
:prop="subWidget.propString"
|
||||
:class="{
|
||||
'rich-input': subWidget.widgetType === SysCustomWidgetType.RichEditor,
|
||||
}"
|
||||
:label-width="
|
||||
subWidget.showName == null || subWidget.showName === ''
|
||||
? isEdit
|
||||
? '0px'
|
||||
: '0px'
|
||||
: undefined
|
||||
"
|
||||
@click.stop="onWidgetClick(subWidget)"
|
||||
>
|
||||
<OnlineCustomWidget
|
||||
:widget="subWidget"
|
||||
:ref="subWidget.variableName"
|
||||
:value="getWidgetValue(subWidget)"
|
||||
@input="val => onValueChange(subWidget, val)"
|
||||
@change="(val: ANY_OBJECT|undefined, detail: ANY_OBJECT|null) => onWidgetValueChange(subWidget, val, detail)"
|
||||
/>
|
||||
</component>
|
||||
<ActiveWidgetMenu
|
||||
v-if="isEdit && form().isActive(subWidget)"
|
||||
:widget="subWidget"
|
||||
:clone="form().cloneWidget"
|
||||
@copy="onCopyWidget"
|
||||
@delete="onDeleteWidget(subWidget)"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</template>
|
||||
<div v-else-if="isEdit" class="info mover">
|
||||
<div style="width: 100px; height: 100px">
|
||||
<el-icon><UploadFilled /></el-icon>
|
||||
</div>
|
||||
<span>请拖入组件进行编辑</span>
|
||||
</div>
|
||||
</VueDraggable>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { UploadFilled } from '@element-plus/icons-vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
import { ElMessageBox, ElFormItem } from 'element-plus';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { SysCustomWidgetType } from '@/common/staticDict';
|
||||
import ActiveWidgetMenu from './ActiveWidgetMenu.vue';
|
||||
import OnlineCustomWidget from './OnlineCustomWidget.vue';
|
||||
import OnlineCustomTabs from './OnlineCustomTabs.vue';
|
||||
import OnlineBaseCard from './OnlineBaseCard.vue';
|
||||
import OnlineCardTable from './OnlineCardTable.vue';
|
||||
|
||||
interface IEmit {
|
||||
(event: 'widgetClick', value: ANY_OBJECT | null): void;
|
||||
(event: 'dragAdd', value: ANY_OBJECT): void;
|
||||
(event: 'update:value', value: ANY_OBJECT | ANY_OBJECT[]): void;
|
||||
}
|
||||
const emit = defineEmits<IEmit>();
|
||||
|
||||
interface IProps {
|
||||
// v-model:value 调用者必须使用这种方式赋值,才能被更新
|
||||
value: Array<ANY_OBJECT>;
|
||||
// 是否显示边框
|
||||
showBorder?: boolean;
|
||||
isEdit?: boolean;
|
||||
height?: string;
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
value: () => [],
|
||||
isEdit: false,
|
||||
showBorder: true,
|
||||
});
|
||||
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCustomBlock: form not injected');
|
||||
return { isEdit: false } as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const getDrableBoxStyle = computed(() => {
|
||||
let tempHeight = props.height;
|
||||
if (props.height == null || props.height === '') {
|
||||
tempHeight = props.isEdit && props.value.length <= 0 ? '150px' : '0px';
|
||||
}
|
||||
return {
|
||||
'min-height': tempHeight,
|
||||
};
|
||||
});
|
||||
const getTableStyle = (widget: ANY_OBJECT) => {
|
||||
if (widget.widgetType !== SysCustomWidgetType.Table) return;
|
||||
return {
|
||||
'margin-bottom': (widget.props.paddingBottom || 0) + 'px',
|
||||
};
|
||||
};
|
||||
const getBlockStyle = (widget: ANY_OBJECT) => {
|
||||
return {
|
||||
'margin-bottom':
|
||||
(widget.props.paddingBottom || (widget.props.basicInfo || {}).paddingBottom || 0) + 'px',
|
||||
padding: props.isEdit ? '5px' : undefined,
|
||||
border: props.isEdit ? '1px solid #e8eaec' : undefined,
|
||||
};
|
||||
};
|
||||
const getChartStyle = (widget: ANY_OBJECT) => {
|
||||
return {
|
||||
'margin-bottom':
|
||||
(widget.props.paddingBottom || (widget.props.basicInfo || {}).paddingBottom || 0) + 'px',
|
||||
};
|
||||
};
|
||||
|
||||
const values = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(val: Array<ANY_OBJECT>) {
|
||||
console.log('block values>>>>>>>>>>>>', val);
|
||||
emit('update:value', val);
|
||||
},
|
||||
});
|
||||
|
||||
const onWidgetClick = (widget: ANY_OBJECT | null = null) => {
|
||||
console.log('block block block onWidgetClick', widget);
|
||||
emit('widgetClick', widget);
|
||||
};
|
||||
const onDragAdd = (e: DragEvent) => {
|
||||
console.log('block onDragAdd', e);
|
||||
emit('dragAdd', { list: props.value, dragEvent: e });
|
||||
};
|
||||
const onDragMove = (e: ANY_OBJECT) => {
|
||||
console.log('block dragMove', e);
|
||||
// 容器组件不能改变位置
|
||||
let widgetType = e.relatedContext.element ? e.relatedContext.element.widgetType : undefined;
|
||||
return widgetType !== SysCustomWidgetType.Block && widgetType !== SysCustomWidgetType.Card;
|
||||
};
|
||||
const onCopyWidget = (widget: ANY_OBJECT) => {
|
||||
emit('update:value', [...props.value, widget]);
|
||||
};
|
||||
const onDeleteWidget = (widget: ANY_OBJECT) => {
|
||||
ElMessageBox.confirm('是否删除此组件?', '', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
emit(
|
||||
'update:value',
|
||||
props.value.filter(item => item !== widget),
|
||||
);
|
||||
onWidgetClick(null);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
|
||||
const getWidgetValue = (widget: ANY_OBJECT) => {
|
||||
return form().getWidgetValue(widget);
|
||||
};
|
||||
const onValueChange = (
|
||||
widget: ANY_OBJECT,
|
||||
value: string | boolean | Date | number | ANY_OBJECT | Array<ANY_OBJECT> | undefined | null,
|
||||
) => {
|
||||
console.log('[[[ block value change ]]]', value, typeof value);
|
||||
|
||||
if (value instanceof Event) {
|
||||
console.log('block onValueChange', value);
|
||||
if (value.target instanceof HTMLInputElement) {
|
||||
return form().onValueChange(widget, value.target.value);
|
||||
}
|
||||
}
|
||||
return form().onValueChange(widget, value);
|
||||
};
|
||||
const onWidgetValueChange = (
|
||||
widget: ANY_OBJECT,
|
||||
value: ANY_OBJECT | null | undefined,
|
||||
detail: ANY_OBJECT | null,
|
||||
) => {
|
||||
console.log('block onWidgetValueChange>>>>>>>>>>>>>>', value, widget, form().onWidgetValueChange);
|
||||
return form().onWidgetValueChange(widget, value, detail);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
console.log('Block Block Block => form', form());
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ghost {
|
||||
height: 30px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.info {
|
||||
// position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
flex-direction: column;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.info div {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
font-size: 60px;
|
||||
text-align: center;
|
||||
border: 1px dashed #d9dbdd;
|
||||
border-radius: 6px;
|
||||
line-height: 100px;
|
||||
}
|
||||
.info span {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
142
OrangeFormsOpen-VUE3/src/online/components/OnlineCustomImage.vue
Normal file
142
OrangeFormsOpen-VUE3/src/online/components/OnlineCustomImage.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<el-row :justify="align">
|
||||
<img :src="imageUrl" :style="getStyle" />
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { EpPropMergeType } from 'element-plus/es/utils';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { useUpload } from '@/common/hooks/useUpload';
|
||||
import { API_CONTEXT } from '@/api/config';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
widget: ANY_OBJECT | null;
|
||||
value?: string;
|
||||
src?: string;
|
||||
fit?: string;
|
||||
align?:
|
||||
| EpPropMergeType<
|
||||
StringConstructor,
|
||||
'center' | 'space-around' | 'space-between' | 'space-evenly' | 'end' | 'start',
|
||||
unknown
|
||||
>
|
||||
| undefined;
|
||||
width?: string;
|
||||
height?: string;
|
||||
radius?: number;
|
||||
round?: boolean;
|
||||
}>(),
|
||||
{
|
||||
align: 'start',
|
||||
radius: 5,
|
||||
round: false,
|
||||
},
|
||||
);
|
||||
|
||||
const { parseUploadData, getUploadFileUrl } = useUpload();
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCustomImage: form not injected');
|
||||
return { isEdit: false } as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const fileList = ref<ANY_OBJECT[]>([]);
|
||||
|
||||
const getStyle = computed<ANY_OBJECT>(() => {
|
||||
let temp = props.round ? '50%' : props.radius + 'px';
|
||||
return {
|
||||
width: props.width != null ? props.width : '200px',
|
||||
height: props.height != null ? props.height : '200px',
|
||||
'object-fit': props.fit,
|
||||
'border-radius': temp,
|
||||
};
|
||||
});
|
||||
const buildFlowParam = computed(() => {
|
||||
let flowParam: ANY_OBJECT = {};
|
||||
let flowData = form().flowData;
|
||||
if (flowData) {
|
||||
if (flowData.processDefinitionKey)
|
||||
flowParam.processDefinitionKey = flowData.processDefinitionKey;
|
||||
if (flowData.processInstanceId) flowParam.processInstanceId = flowData.processInstanceId;
|
||||
if (flowData.taskId) flowParam.taskId = flowData.taskId;
|
||||
}
|
||||
|
||||
return flowParam;
|
||||
});
|
||||
const imageUrl = computed(() => {
|
||||
console.log('imageUrl', fileList, props.src);
|
||||
if (Array.isArray(fileList.value) && fileList.value.length > 0) {
|
||||
return fileList.value[0].url;
|
||||
} else {
|
||||
return isBase64(props.src) ? props.src : getDownloadUrl.value;
|
||||
}
|
||||
});
|
||||
const getDownloadUrl = computed(() => {
|
||||
if (props.value) {
|
||||
//console.log('getDownloadUrl 1', props);
|
||||
if (props.widget?.relation) {
|
||||
return (
|
||||
'admin/online/onlineOperation/downloadOneToManyRelation/' +
|
||||
(props.widget.datasource || {}).variableName
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
'admin/online/onlineOperation/downloadDatasource/' +
|
||||
(props.widget?.datasource || {}).variableName
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let imgUrl;
|
||||
try {
|
||||
imgUrl = props.src ? JSON.parse(props.src) : undefined;
|
||||
if (imgUrl) {
|
||||
imgUrl = getUploadFileUrl(imgUrl, { filename: imgUrl.filename });
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
imgUrl = null;
|
||||
}
|
||||
//console.log('getDownloadUrl 2', imgUrl);
|
||||
return imgUrl;
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(newValue: string | undefined) => {
|
||||
console.log('CustomImage.value change', newValue);
|
||||
setTimeout(() => {
|
||||
fileList.value = [];
|
||||
if (newValue) {
|
||||
let downloadParams: ANY_OBJECT = {
|
||||
...buildFlowParam.value,
|
||||
datasourceId: (props.widget?.datasource || {}).datasourceId,
|
||||
fieldName: props.widget?.column?.columnName,
|
||||
asImage: true,
|
||||
dataId: form().getPrimaryData(props.widget) || '',
|
||||
};
|
||||
if (props.widget?.relation) downloadParams.relationId = props.widget.relation.relationId;
|
||||
let temp = JSON.parse(newValue);
|
||||
temp = Array.isArray(temp)
|
||||
? temp.map(item => {
|
||||
return {
|
||||
...item,
|
||||
downloadUri: getDownloadUrl.value,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
fileList.value = parseUploadData(JSON.stringify(temp), downloadParams);
|
||||
}
|
||||
}, 30);
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
function isBase64(src: string | undefined) {
|
||||
return src && /^data:image\/\w+;base64,/.test(src);
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<div class="custom-label">
|
||||
<span v-if="isText"> {{ showText }} </span>
|
||||
<div v-if="isHtml" v-html="showText" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SysCustomWidgetType } from '@/common/staticDict';
|
||||
import { SysOnlineFieldKind } from '@/common/staticDict/online';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const props = defineProps<{
|
||||
value?: number | string | boolean | Array<ANY_OBJECT>;
|
||||
widget: ANY_OBJECT;
|
||||
}>();
|
||||
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCustomLabel: form not injected');
|
||||
return { isEdit: false };
|
||||
});
|
||||
|
||||
const isText = computed(() => {
|
||||
return (
|
||||
[
|
||||
SysCustomWidgetType.Label,
|
||||
SysCustomWidgetType.Input,
|
||||
SysCustomWidgetType.NumberInput,
|
||||
SysCustomWidgetType.NumberRange,
|
||||
SysCustomWidgetType.Slider,
|
||||
SysCustomWidgetType.Radio,
|
||||
SysCustomWidgetType.CheckBox,
|
||||
SysCustomWidgetType.Switch,
|
||||
SysCustomWidgetType.Select,
|
||||
SysCustomWidgetType.Cascader,
|
||||
SysCustomWidgetType.Date,
|
||||
SysCustomWidgetType.DateRange,
|
||||
SysCustomWidgetType.UserSelect,
|
||||
SysCustomWidgetType.DeptSelect,
|
||||
SysCustomWidgetType.DataSelect,
|
||||
].indexOf(props.widget.widgetType) !== -1
|
||||
);
|
||||
});
|
||||
const isHtml = computed(() => {
|
||||
return (
|
||||
(props.widget.widgetType === SysCustomWidgetType.RichEditor ||
|
||||
props.widget.widgetType === SysCustomWidgetType.Label) &&
|
||||
props.widget.column &&
|
||||
props.widget.column.fieldKind === SysOnlineFieldKind.RICH_TEXT
|
||||
);
|
||||
});
|
||||
const showText = computed(() => {
|
||||
// console.log('OnlineCustomLabel.showText', props, form());
|
||||
switch (props.widget.widgetType) {
|
||||
case SysCustomWidgetType.Label:
|
||||
case SysCustomWidgetType.Input:
|
||||
case SysCustomWidgetType.NumberInput:
|
||||
case SysCustomWidgetType.Slider:
|
||||
case SysCustomWidgetType.Date:
|
||||
case SysCustomWidgetType.RichEditor:
|
||||
case SysCustomWidgetType.Radio:
|
||||
case SysCustomWidgetType.CheckBox:
|
||||
case SysCustomWidgetType.Select:
|
||||
case SysCustomWidgetType.Cascader:
|
||||
case SysCustomWidgetType.UserSelect:
|
||||
case SysCustomWidgetType.DeptSelect:
|
||||
case SysCustomWidgetType.DataSelect:
|
||||
return !props.value
|
||||
? form().isEdit
|
||||
? 'XXXXXXXXXX'
|
||||
: undefined
|
||||
: Array.isArray(props.value)
|
||||
? props.value.join(',')
|
||||
: props.value;
|
||||
case SysCustomWidgetType.NumberRange:
|
||||
case SysCustomWidgetType.DateRange:
|
||||
return Array.isArray(props.value) && props.value.length > 1
|
||||
? props.value[0] + ' 至 ' + props.value[1]
|
||||
: form().isEdit
|
||||
? 'XXXXX 至 XXXXX'
|
||||
: undefined;
|
||||
case SysCustomWidgetType.Switch:
|
||||
return props.value ? '是' : '否';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
567
OrangeFormsOpen-VUE3/src/online/components/OnlineCustomTable.vue
Normal file
567
OrangeFormsOpen-VUE3/src/online/components/OnlineCustomTable.vue
Normal file
@@ -0,0 +1,567 @@
|
||||
<template>
|
||||
<table-box
|
||||
ref="table"
|
||||
style="height: 100%"
|
||||
:data="dataList"
|
||||
:key="tableKey"
|
||||
show-overflow="title"
|
||||
show-header-overflow="title"
|
||||
class="draggable-widget page-table"
|
||||
header-cell-class-name="table-header-gray"
|
||||
:hasImageColumn="hasImageColumn"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
:keep-source="rowEdit"
|
||||
:edit-config="{
|
||||
trigger: 'manual',
|
||||
mode: 'row',
|
||||
enabled: rowEdit,
|
||||
showIcon: false,
|
||||
autoClear: false,
|
||||
showStatus: true,
|
||||
}"
|
||||
:edit-closed="onSaveRowData"
|
||||
:seq-config="{ seqMethod }"
|
||||
:hasExtend="hasExtend"
|
||||
@sort-change="onSortChange"
|
||||
@checkbox-select-change="onCheckBoxChange"
|
||||
@radio-select-change="onRadioSelectChange"
|
||||
:sort-config="{ remote: remoteSort }"
|
||||
@refresh="onRefresh"
|
||||
>
|
||||
<template
|
||||
v-slot:operator
|
||||
v-if="
|
||||
operationList.filter(row => {
|
||||
return row.enabled && !row.rowOperation;
|
||||
}).length > 0 && !form().readOnly
|
||||
"
|
||||
>
|
||||
<el-button
|
||||
class="table-operation"
|
||||
v-if="operationVisible(SysCustomWidgetOperationType.BATCH_DELETE)"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
:type="getOperation(SysCustomWidgetOperationType.BATCH_DELETE).btnType"
|
||||
:plain="getOperation(SysCustomWidgetOperationType.BATCH_DELETE).plain"
|
||||
:disabled="operationDisabled(SysCustomWidgetOperationType.BATCH_DELETE)"
|
||||
@click="onOperationClick(getOperation(SysCustomWidgetOperationType.BATCH_DELETE))"
|
||||
:icon="Delete"
|
||||
>{{ getOperation(SysCustomWidgetOperationType.BATCH_DELETE).name || '批量删除' }}</el-button
|
||||
>
|
||||
<el-button
|
||||
class="table-operation"
|
||||
v-if="operationVisible(SysCustomWidgetOperationType.EXPORT)"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
:type="getOperation(SysCustomWidgetOperationType.EXPORT).btnType"
|
||||
:plain="getOperation(SysCustomWidgetOperationType.EXPORT).plain"
|
||||
:disabled="operationDisabled(SysCustomWidgetOperationType.EXPORT)"
|
||||
@click="onOperationClick(getOperation(SysCustomWidgetOperationType.EXPORT))"
|
||||
:icon="Download"
|
||||
>{{ getOperation(SysCustomWidgetOperationType.EXPORT).name || '导出' }}</el-button
|
||||
>
|
||||
<el-button
|
||||
class="table-operation"
|
||||
v-if="operationVisible(SysCustomWidgetOperationType.PRINT)"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
:type="getOperation(SysCustomWidgetOperationType.PRINT).btnType"
|
||||
:plain="getOperation(SysCustomWidgetOperationType.PRINT).plain"
|
||||
:disabled="operationDisabled(SysCustomWidgetOperationType.PRINT)"
|
||||
@click="onOperationClick(getOperation(SysCustomWidgetOperationType.PRINT))"
|
||||
>{{ getOperation(SysCustomWidgetOperationType.PRINT).name || '打印' }}</el-button
|
||||
>
|
||||
<el-button
|
||||
class="table-operation"
|
||||
v-if="operationVisible(SysCustomWidgetOperationType.ADD)"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
:type="getOperation(SysCustomWidgetOperationType.ADD).btnType"
|
||||
:plain="getOperation(SysCustomWidgetOperationType.ADD).plain"
|
||||
:disabled="operationDisabled(SysCustomWidgetOperationType.ADD)"
|
||||
@click="onOperationClick(getOperation(SysCustomWidgetOperationType.ADD))"
|
||||
:icon="Plus"
|
||||
>{{ getOperation(SysCustomWidgetOperationType.ADD).name || '新建' }}</el-button
|
||||
>
|
||||
</template>
|
||||
<vxe-column v-if="hasBatchOperation && !form().readOnly" type="checkbox" :width="40" />
|
||||
<vxe-column v-if="singleSelect" type="radio" align="center" :width="50" />
|
||||
<vxe-column v-if="tableColumnList.length > 0" type="seq" title="序号" :width="50" />
|
||||
<template v-for="tableColumn in tableColumnList" :key="tableColumn.column?.columnId">
|
||||
<!-- Boolean类型字段 -->
|
||||
<vxe-column
|
||||
v-if="tableColumn.column && tableColumn.column.objectFieldType === 'Boolean'"
|
||||
:title="tableColumn.showName"
|
||||
:width="tableColumn.columnWidth"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
:type="getObjectValue(row, tableColumn.showFieldName) ? 'success' : 'danger'"
|
||||
>
|
||||
{{ getObjectValue(row, tableColumn.showFieldName) ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<!-- 图片类型字段 -->
|
||||
<vxe-column
|
||||
v-else-if="
|
||||
tableColumn.column && tableColumn.column.fieldKind === SysOnlineFieldKind.UPLOAD_IMAGE
|
||||
"
|
||||
:title="tableColumn.showName"
|
||||
:width="tableColumn.columnWidth"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-image
|
||||
v-for="item in parseTableUploadData(tableColumn, row)"
|
||||
:preview-src-list="getTablePictureList(tableColumn, row)"
|
||||
class="table-cell-image"
|
||||
:key="item.url"
|
||||
:src="item.url"
|
||||
fit="fill"
|
||||
>
|
||||
<template v-slot:error>
|
||||
<div class="table-cell-image">
|
||||
<el-icon><Picture /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<!-- 文件下载类型字段 -->
|
||||
<vxe-column
|
||||
v-else-if="tableColumn.column && tableColumn.column.fieldKind === SysOnlineFieldKind.UPLOAD"
|
||||
:title="tableColumn.showName"
|
||||
:width="tableColumn.columnWidth"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<a
|
||||
v-for="item in parseTableUploadData(tableColumn, row)"
|
||||
:key="item.url"
|
||||
href="javascript:void(0);"
|
||||
@click="downloadFile(item.url, item.name)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<!-- 其他类型 -->
|
||||
<vxe-column
|
||||
v-else
|
||||
:title="tableColumn.showName"
|
||||
:field="tableColumn.showFieldName"
|
||||
:width="tableColumn.columnWidth"
|
||||
:sortable="tableColumn.sortable"
|
||||
/>
|
||||
</template>
|
||||
<vxe-column
|
||||
title="操作"
|
||||
:width="widget.props.operationColumnWidth || 160"
|
||||
fixed="right"
|
||||
:show-overflow="false"
|
||||
v-if="(rowEdit || tableOperationList.length > 0) && tableColumnList.length > 0"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-for="operation in tableOperationList"
|
||||
:key="operation.id"
|
||||
v-show="form().checkOperationVisible(operation, row)"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
link
|
||||
:class="operation.btnClass"
|
||||
:disabled="
|
||||
!form().checkOperationPermCode(operation) ||
|
||||
form().checkOperationDisabled(operation, row)
|
||||
"
|
||||
@click="onOperationClick(operation, row)"
|
||||
>
|
||||
{{ operation.name }}
|
||||
</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<template v-slot:empty>
|
||||
<div class="table-empty unified-font">
|
||||
<img src="@/assets/img/empty.png" />
|
||||
<span>暂无数据</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:pagination>
|
||||
<slot name="pagination" />
|
||||
</template>
|
||||
</table-box>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { VxeColumn } from 'vxe-table';
|
||||
import { Picture, Delete, Download, Plus } from '@element-plus/icons-vue';
|
||||
import TableBox from '@/components/TableBox/index.vue';
|
||||
import { useDownload } from '@/common/hooks/useDownload';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { findItemFromList, getObjectValue } from '@/common/utils';
|
||||
import { SysCustomWidgetOperationType } from '@/common/staticDict';
|
||||
import { SysOnlineFieldKind } from '@/common/staticDict/online';
|
||||
import { useUpload } from '@/common/hooks/useUpload';
|
||||
import { SortInfo } from '@/common/types/sortinfo';
|
||||
import { API_CONTEXT } from '@/api/config';
|
||||
|
||||
const { downloadFile } = useDownload();
|
||||
const { parseUploadData } = useUpload();
|
||||
|
||||
const emit = defineEmits<{
|
||||
delete: [ANY_OBJECT];
|
||||
operationClick: [ANY_OBJECT, ANY_OBJECT | null];
|
||||
refresh: [];
|
||||
}>();
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
dataList?: Array<ANY_OBJECT>;
|
||||
height?: string | number;
|
||||
border?: string;
|
||||
// 是否支持行内编辑
|
||||
rowEdit?: boolean;
|
||||
// 是否支持多选
|
||||
multiSelect?: boolean;
|
||||
// 是否支持单选
|
||||
singleSelect?: boolean;
|
||||
// 表格操作列表
|
||||
operationList?: Array<ANY_OBJECT>;
|
||||
widget: ANY_OBJECT;
|
||||
// 获取行序号
|
||||
getTableIndex?: (value: number) => number;
|
||||
// 排序改变
|
||||
sortChange?: (value: SortInfo) => void;
|
||||
// 多选选中改变
|
||||
onSelectChange?: (values: Array<ANY_OBJECT>) => void;
|
||||
// 单选中改变
|
||||
onRadioChange?: (value: ANY_OBJECT) => void;
|
||||
}>(),
|
||||
{
|
||||
dataList: () => [],
|
||||
height: 'auto',
|
||||
border: 'full',
|
||||
rowEdit: false,
|
||||
multiSelect: false,
|
||||
singleSelect: false,
|
||||
operationList: () => [],
|
||||
},
|
||||
);
|
||||
|
||||
const table = ref<ANY_OBJECT>();
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCustomTable: form not injected');
|
||||
return { isEdit: false } as ANY_OBJECT;
|
||||
});
|
||||
import { useLayoutStore } from '@/store';
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
const slots = useSlots();
|
||||
|
||||
// const editInfo = reactive<ANY_OBJECT>({
|
||||
// editRow: undefined,
|
||||
// });
|
||||
const sortInfo = ref<SortInfo | null>(null);
|
||||
|
||||
const buildFlowParam = computed(() => {
|
||||
let flowParam: ANY_OBJECT = {};
|
||||
let flowData = form().flowData;
|
||||
if (flowData) {
|
||||
if (flowData.processDefinitionKey)
|
||||
flowParam.processDefinitionKey = flowData.processDefinitionKey;
|
||||
if (flowData.processInstanceId) flowParam.processInstanceId = flowData.processInstanceId;
|
||||
if (flowData.taskId) flowParam.taskId = flowData.taskId;
|
||||
}
|
||||
|
||||
return flowParam;
|
||||
});
|
||||
const tableColumnList = computed(() => {
|
||||
console.log('>>> ===', props.widget.props.tableColumnList);
|
||||
let tempList =
|
||||
props.widget && props.widget.props && Array.isArray(props.widget.props.tableColumnList)
|
||||
? props.widget.props.tableColumnList
|
||||
: [];
|
||||
const res: ANY_OBJECT[] = [];
|
||||
for (const tempItem of tempList) {
|
||||
const item = { ...tempItem };
|
||||
if (item.fieldType === 0 || item.fieldType == null) {
|
||||
// 绑定表字段
|
||||
if (item.column) item.showFieldName = item.column.columnName;
|
||||
if (props.widget.relation == null && item.relation != null) {
|
||||
item.showFieldName = item.relation.variableName + '.' + item.showFieldName;
|
||||
}
|
||||
if (item.column && item.column.dictInfo) {
|
||||
item.showFieldName = item.showFieldName + 'DictMap.name';
|
||||
}
|
||||
} else {
|
||||
// 自定义字段
|
||||
item.showFieldName = item.customFieldName;
|
||||
}
|
||||
res.push(item);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
const tableOperationList = computed(() => {
|
||||
return props.operationList.filter(item => {
|
||||
let temp = item.enabled && item.rowOperation;
|
||||
if (temp && form().readOnly) {
|
||||
temp = temp && item.readOnly;
|
||||
}
|
||||
return temp;
|
||||
});
|
||||
});
|
||||
const hasBatchOperation = computed(() => {
|
||||
let batchDeleteOperation = findItemFromList(
|
||||
props.operationList,
|
||||
SysCustomWidgetOperationType.BATCH_DELETE,
|
||||
'type',
|
||||
);
|
||||
let printOperation = findItemFromList(
|
||||
props.operationList,
|
||||
SysCustomWidgetOperationType.PRINT,
|
||||
'type',
|
||||
);
|
||||
return (
|
||||
(batchDeleteOperation != null && batchDeleteOperation.enabled) ||
|
||||
(printOperation != null && printOperation.enabled && !printOperation.rowOperation)
|
||||
);
|
||||
});
|
||||
const hasImageColumn = computed(() => {
|
||||
return (
|
||||
tableColumnList.value.filter((tableColumn: ANY_OBJECT) => {
|
||||
return tableColumn.column && tableColumn.column.fieldKind === SysOnlineFieldKind.UPLOAD_IMAGE;
|
||||
}).length > 0
|
||||
);
|
||||
});
|
||||
const tableKey = computed(() => {
|
||||
return (props.widget || {}).variableName + new Date().getTime() + tableColumnList.value.length;
|
||||
});
|
||||
const remoteSort = computed(() => {
|
||||
return props.widget ? (props.widget.props || {}).paged : false;
|
||||
});
|
||||
const hasExtend = computed(() => {
|
||||
return (
|
||||
(props.operationList.filter(row => {
|
||||
return row.enabled && !row.rowOperation;
|
||||
}).length > 0 &&
|
||||
!form().readOnly) ||
|
||||
(slots.operator && slots.operator()) != null
|
||||
);
|
||||
});
|
||||
|
||||
const onRefresh = () => {
|
||||
emit('refresh');
|
||||
};
|
||||
const hasOperator = (type: string) => {
|
||||
let temp = getOperation(type);
|
||||
return temp && temp.enabled;
|
||||
};
|
||||
const getOperation = (type: string) => {
|
||||
return findItemFromList(props.operationList, type, 'type') || {};
|
||||
};
|
||||
const operationVisible = (type: string) => {
|
||||
let operation = getOperation(type);
|
||||
if (!operation) return false;
|
||||
return !form().readOnly && hasOperator(type) && form().checkOperationVisible(operation);
|
||||
};
|
||||
const operationDisabled = (type: string) => {
|
||||
let operation = getOperation(type);
|
||||
return form().checkOperationDisabled(operation) || !form().checkOperationPermCode(operation);
|
||||
};
|
||||
const seqMethod = (data: ANY_OBJECT) => {
|
||||
if (props.getTableIndex) {
|
||||
return props.getTableIndex(data.seq - 1);
|
||||
} else {
|
||||
return data.seq;
|
||||
}
|
||||
};
|
||||
const onSortChange = (data: ANY_OBJECT) => {
|
||||
if (!props.widget.props.paged) return;
|
||||
let fieldName = data.property.replace('DictMap.name', '');
|
||||
let order = data.order;
|
||||
if (order == null) {
|
||||
fieldName = undefined;
|
||||
}
|
||||
if (order === 'asc') order = 'ascending';
|
||||
if (
|
||||
sortInfo.value != null &&
|
||||
sortInfo.value?.prop === fieldName &&
|
||||
sortInfo.value?.order === order
|
||||
) {
|
||||
return;
|
||||
}
|
||||
sortInfo.value = {
|
||||
prop: fieldName,
|
||||
order: order,
|
||||
};
|
||||
if (props.sortChange) {
|
||||
props.sortChange(sortInfo.value);
|
||||
}
|
||||
};
|
||||
const onCheckBoxChange = () => {
|
||||
if (table.value && typeof props.onSelectChange === 'function') {
|
||||
let selectRows = table.value.getTableImpl().getCheckboxRecords(true);
|
||||
props.onSelectChange(selectRows);
|
||||
}
|
||||
};
|
||||
const onRadioSelectChange = () => {
|
||||
if (table.value && typeof props.onRadioChange === 'function') {
|
||||
let selectRow = table.value.getTableImpl().getRadioRecord();
|
||||
props.onRadioChange(selectRow);
|
||||
}
|
||||
};
|
||||
// const setSelectedRow = (rowNum: number) => {
|
||||
// table.value.getTableImpl().setRadioRow(props.dataList[rowNum]);
|
||||
// nextTick(onRadioSelectChange);
|
||||
// };
|
||||
// 取消行内编辑
|
||||
// const cancelRowEvent = (row: ANY_OBJECT) => {
|
||||
// if (form().isEdit) return;
|
||||
// table.value
|
||||
// .getTableImpl()
|
||||
// .clearActived()
|
||||
// .then(() => {
|
||||
// // 还原行数据
|
||||
// table.value.getTableImpl().revertData(row);
|
||||
// editInfo.editRow = undefined;
|
||||
// })
|
||||
// .catch(e => {
|
||||
// console.warn(e);
|
||||
// });
|
||||
// };
|
||||
// 启动行内编辑
|
||||
// const editRowEvent = (row: ANY_OBJECT) => {
|
||||
// if (form().isEdit) return;
|
||||
// table.value.getTableImpl().setEditRow(row);
|
||||
// editInfo.editRow = row;
|
||||
// };
|
||||
// 保存行内编辑数据
|
||||
// const saveRowEvent = (row: ANY_OBJECT) => {
|
||||
// if (form().isEdit) return;
|
||||
// table.value
|
||||
// .getTableImpl()
|
||||
// .clearActived()
|
||||
// .then(() => {
|
||||
// table.value.getTableImpl().reloadRow(row);
|
||||
// editInfo.editRow = undefined;
|
||||
// });
|
||||
// };
|
||||
const onSaveRowData = ({ row }: { row: ANY_OBJECT }) => {
|
||||
console.log(row);
|
||||
};
|
||||
const onOperationClick = (operation: ANY_OBJECT, row: ANY_OBJECT | null = null) => {
|
||||
emit('operationClick', operation, row);
|
||||
};
|
||||
const refreshColumn = () => {
|
||||
nextTick(() => {
|
||||
if (table.value) table.value.getTableImpl().refreshColumn();
|
||||
});
|
||||
};
|
||||
const getDownloadUrl = (tableColumn: ANY_OBJECT) => {
|
||||
let downloadUrl = null;
|
||||
if (form().flowData != null) {
|
||||
downloadUrl = API_CONTEXT + '/flow/flowOnlineOperation/download';
|
||||
} else {
|
||||
if (tableColumn.relationId) {
|
||||
downloadUrl =
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/downloadOneToManyRelation/' +
|
||||
(props.widget.datasource || {}).variableName;
|
||||
} else {
|
||||
downloadUrl =
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/downloadDatasource/' +
|
||||
(props.widget.datasource || {}).variableName;
|
||||
}
|
||||
}
|
||||
|
||||
return downloadUrl;
|
||||
};
|
||||
const parseTableUploadData = (tableColumn: ANY_OBJECT, row: ANY_OBJECT) => {
|
||||
let jsonData = getObjectValue(row, tableColumn.showFieldName);
|
||||
console.log('parseTableUploadData', tableColumn, row, jsonData);
|
||||
if (!jsonData) return [];
|
||||
let downloadParams: ANY_OBJECT = {
|
||||
...buildFlowParam.value,
|
||||
datasourceId: props.widget.datasource.datasourceId,
|
||||
relationId: tableColumn.relationId,
|
||||
fieldName: tableColumn.column?.columnName,
|
||||
asImage: tableColumn.column?.fieldKind === SysOnlineFieldKind.UPLOAD_IMAGE,
|
||||
};
|
||||
|
||||
if (props.widget.primaryColumnName != null) {
|
||||
downloadParams.dataId = row[props.widget.primaryColumnName] || '';
|
||||
}
|
||||
|
||||
let downloadUrl = getDownloadUrl(tableColumn);
|
||||
|
||||
console.log('parseTableUploadData downloadUrl', downloadUrl);
|
||||
console.log('parseTableUploadData jsonData.toString()', jsonData.toString());
|
||||
let temp = JSON.parse(jsonData.toString());
|
||||
temp = Array.isArray(temp)
|
||||
? temp.map(item => {
|
||||
return {
|
||||
...item,
|
||||
downloadUri: downloadUrl,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
return parseUploadData(JSON.stringify(temp), downloadParams);
|
||||
};
|
||||
const getTablePictureList = (tableColumn: ANY_OBJECT, row: ANY_OBJECT) => {
|
||||
let temp = parseTableUploadData(tableColumn, row);
|
||||
if (Array.isArray(temp)) {
|
||||
return temp.map(item => item.url);
|
||||
}
|
||||
};
|
||||
const formatListData = (data: ANY_OBJECT) => {
|
||||
Object.keys(data).forEach(key => {
|
||||
let subData = data[key];
|
||||
if (typeof subData === 'object' && key.indexOf('DictMap') === -1) {
|
||||
formatListData(subData);
|
||||
} else {
|
||||
// 如果是多选字典字段,那么把选中的字典值拼接成DictMap去显示
|
||||
if (key.indexOf('DictMapList') !== -1 && Array.isArray(data[key])) {
|
||||
let newKey = key.replace('DictMapList', 'DictMap');
|
||||
data[newKey] = {
|
||||
id: data[key.replace('DictMapList', '')],
|
||||
name: data[key].map((subItem: ANY_OBJECT) => subItem.name).join(','),
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.dataList,
|
||||
() => {
|
||||
if (Array.isArray(props.dataList)) {
|
||||
props.dataList.forEach(item => {
|
||||
formatListData(item);
|
||||
});
|
||||
//console.log('OnlineCumstomTable.dataList', props.dataList);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => tableColumnList.value,
|
||||
() => {
|
||||
refreshColumn();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => props.widget.props.operationColumnWidth,
|
||||
() => {
|
||||
refreshColumn();
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.table-operation {
|
||||
display: inline-block;
|
||||
}
|
||||
.table-operation + .table-operation {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div
|
||||
class="table-draggable"
|
||||
:style="{
|
||||
'margin-bottom':
|
||||
(widget.props.paddingBottom || (widget.props.basicInfo || {}).paddingBottom || 0) + 'px',
|
||||
}"
|
||||
>
|
||||
<el-tabs v-if="childWidgetList.length > 0" v-model="activePanel" :type="widget.props.type">
|
||||
<el-tab-pane
|
||||
v-for="subWidget in childWidgetList"
|
||||
:key="subWidget.variableName"
|
||||
:label="subWidget.showName"
|
||||
:name="subWidget.variableName"
|
||||
:lazy="true"
|
||||
>
|
||||
<OnlineCustomBlock
|
||||
v-model:value="subWidget.childWidgetList"
|
||||
:isEdit="isEdit"
|
||||
@widgetClick="onWidgetClick"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div
|
||||
v-if="isEdit && (widget.childWidgetList || []).length <= 0"
|
||||
class="info"
|
||||
style="border: 1px solid #e8eaec"
|
||||
>
|
||||
<div style="width: 100px; height: 100px">
|
||||
<el-icon><UploadFilled /></el-icon>
|
||||
</div>
|
||||
<span>请添加标签页</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { UploadFilled } from '@element-plus/icons-vue';
|
||||
import OnlineCustomBlock from '@/online/components/OnlineCustomBlock.vue';
|
||||
import { WidgetProps, WidgetEmit } from './types/widget';
|
||||
import { useWidget } from './hooks/widget';
|
||||
|
||||
const emit = defineEmits<WidgetEmit>();
|
||||
const props = withDefaults(defineProps<WidgetProps>(), { isEdit: false });
|
||||
const activePanel = ref();
|
||||
|
||||
// const form = inject('form', () => {
|
||||
// return { isEdit: false } as ANY_OBJECT;
|
||||
// });
|
||||
|
||||
const { childWidgetList, onWidgetClick } = useWidget(props, emit);
|
||||
|
||||
// TODO 监听到变化之后,行为是否妥当
|
||||
watch(
|
||||
() => props.widget.childWidgetList,
|
||||
() => {
|
||||
if (Array.isArray(props.widget.childWidgetList) && props.widget.childWidgetList.length > 0) {
|
||||
activePanel.value = props.widget.childWidgetList[0].variableName;
|
||||
}
|
||||
},
|
||||
{
|
||||
// 不能使用深度监听,否则会导致组件属性变化之后,tabs会重置选中状态
|
||||
//deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
color: #999;
|
||||
}
|
||||
.info div {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
font-size: 60px;
|
||||
text-align: center;
|
||||
border: 1px dashed #d9dbdd;
|
||||
border-radius: 6px;
|
||||
line-height: 100px;
|
||||
}
|
||||
.info span {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div
|
||||
class="online-custom-text"
|
||||
:style="{
|
||||
background: bgColor,
|
||||
height: height ? height + 'px' : undefined,
|
||||
'justify-content': valign,
|
||||
padding: padding + 'px',
|
||||
}"
|
||||
>
|
||||
<div :style="getStyle">{{ value }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { StyleValue } from 'vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
value?: number | string | Date;
|
||||
align?: string;
|
||||
valign?: string;
|
||||
bgColor?: string;
|
||||
height?: number;
|
||||
textIndent?: number;
|
||||
fontSize?: number;
|
||||
padding?: number;
|
||||
fontColor?: string;
|
||||
fontBold?: boolean;
|
||||
fontItalic?: boolean;
|
||||
}>(),
|
||||
{
|
||||
value: '',
|
||||
align: 'left',
|
||||
valign: 'center',
|
||||
height: 25,
|
||||
textIndent: 0,
|
||||
fontSize: 14,
|
||||
padding: 2,
|
||||
fontColor: '#383838',
|
||||
fontBold: false,
|
||||
fontItalic: false,
|
||||
},
|
||||
);
|
||||
|
||||
const getStyle = computed<StyleValue>(() => {
|
||||
return {
|
||||
width: '100%',
|
||||
'text-indent': props.textIndent + 'em',
|
||||
'text-align': props.align,
|
||||
'max-height': props.height ? props.height + 'px' : undefined,
|
||||
'line-height': 1.5,
|
||||
'font-size': props.fontSize + 'px',
|
||||
color: props.fontColor,
|
||||
'font-weight': props.fontBold ? 600 : 400,
|
||||
'font-style': props.fontItalic ? 'italic' : undefined,
|
||||
overflow: 'hidden',
|
||||
'word-break': 'break-word',
|
||||
} as StyleValue;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.online-custom-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
||||
167
OrangeFormsOpen-VUE3/src/online/components/OnlineCustomTree.vue
Normal file
167
OrangeFormsOpen-VUE3/src/online/components/OnlineCustomTree.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<el-tree
|
||||
class="online-custom-tree"
|
||||
ref="tree"
|
||||
:data="treeDataList"
|
||||
node-key="id"
|
||||
:show-checkbox="multiple"
|
||||
:highlight-current="true"
|
||||
:default-expand-all="true"
|
||||
:auto-expand-parent="true"
|
||||
:expand-on-click-node="false"
|
||||
@check-change="onSelectChange"
|
||||
@node-click="onNodeClick"
|
||||
>
|
||||
<template v-slot="{ data }">
|
||||
<el-row class="node-item" justify="space-between" align="middle">
|
||||
<div class="text">{{ data.name }}</div>
|
||||
</el-row>
|
||||
</template>
|
||||
</el-tree>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, defineProps, defineEmits, watch, computed, nextTick, inject } from 'vue';
|
||||
import { treeDataTranslate, findItemFromList } from '@/common/utils';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
value?: number | string | ANY_OBJECT[];
|
||||
widget: ANY_OBJECT;
|
||||
multiple?: boolean;
|
||||
dataList?: ANY_OBJECT[];
|
||||
filter?: ANY_OBJECT;
|
||||
}>(),
|
||||
{
|
||||
multiple: false,
|
||||
dataList: () => [],
|
||||
},
|
||||
);
|
||||
const tree = ref();
|
||||
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCustomTree: form not injected');
|
||||
return { isEdit: false } as ANY_OBJECT;
|
||||
});
|
||||
// 左树右表布局,左侧过滤条件
|
||||
const leftFilterObject = computed(() => {
|
||||
return form().filter;
|
||||
});
|
||||
const treeDataList = computed(() => {
|
||||
let tempList = (props.dataList || []).filter(item => {
|
||||
item.children = null;
|
||||
return (
|
||||
leftFilterObject.value == null ||
|
||||
leftFilterObject.value.name == null ||
|
||||
item.name.indexOf(leftFilterObject.value.name) !== -1
|
||||
);
|
||||
});
|
||||
let temp = treeDataTranslate(tempList, 'id', 'parentId');
|
||||
console.log('temp', temp);
|
||||
if (props.multiple) {
|
||||
return temp;
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
id: '',
|
||||
name: '全部',
|
||||
},
|
||||
...temp,
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
const onNodeClick = () => {
|
||||
console.log('onNodeClick');
|
||||
if (!props.multiple) onSelectChange();
|
||||
};
|
||||
const emit = defineEmits<{
|
||||
'update:value': [number | string | ANY_OBJECT[] | undefined];
|
||||
change: [number | string | ANY_OBJECT[] | undefined, ANY_OBJECT | null];
|
||||
}>();
|
||||
const onValueChange = () => {
|
||||
let temp = props.value;
|
||||
if (tree.value) {
|
||||
if (props.multiple) {
|
||||
temp = tree.value.getCheckedKeys();
|
||||
} else {
|
||||
temp = tree.value.getCurrentKey();
|
||||
}
|
||||
}
|
||||
console.log('onValueChange', temp);
|
||||
emit('update:value', temp);
|
||||
let dictData = props.multiple
|
||||
? null
|
||||
: findItemFromList(props.dataList, temp as string | number, 'id');
|
||||
emit('change', temp, dictData);
|
||||
};
|
||||
const onSelectChange = () => {
|
||||
console.log('onSelectChange');
|
||||
nextTick(() => {
|
||||
onValueChange();
|
||||
});
|
||||
};
|
||||
const setTreeSelectNode = () => {
|
||||
if (tree.value) {
|
||||
if (props.multiple) {
|
||||
tree.value.setCheckedKeys(props.value || []);
|
||||
} else {
|
||||
tree.value.setCurrentKey(props.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
setTreeSelectNode();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => props.dataList,
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
setTreeSelectNode();
|
||||
}, 50);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.online-custom-tree :deep(.el-tree-node__content) {
|
||||
height: 100%;
|
||||
}
|
||||
.online-custom-tree :deep(.el-tree-node__expand-icon) {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
}
|
||||
.online-custom-tree :deep(.el-tree-node__expand-icon.is-leaf) {
|
||||
color: transparent;
|
||||
cursor: default;
|
||||
}
|
||||
.node-item {
|
||||
min-width: 100px;
|
||||
padding: 12px 0;
|
||||
margin-right: 15px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.node-item .text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.online-custom-tree .is-current > .el-tree-node__content {
|
||||
color: $color-primary;
|
||||
background: $color-primary-light-9 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<div class="online-custom-upload">
|
||||
<el-upload
|
||||
v-if="!readOnly"
|
||||
:class="{
|
||||
'upload-image-item': isImage,
|
||||
'upload-image-multi': maxFileCount !== 1,
|
||||
}"
|
||||
:name="widget.props.fileFieldName"
|
||||
:headers="getUploadHeaders"
|
||||
:action="getActionUrl"
|
||||
:data="uploadData"
|
||||
:on-success="onUploadSuccess"
|
||||
:on-remove="onRemoveFile"
|
||||
:on-error="onUploadError"
|
||||
:on-exceed="onUploadLimit"
|
||||
:limit="maxFileCount"
|
||||
:show-file-list="maxFileCount !== 1 || !isImage"
|
||||
:list-type="getUploadListType"
|
||||
:file-list="getUploadFileList"
|
||||
:disabled="getDisabledStatus()"
|
||||
>
|
||||
<!-- 上传图片 -->
|
||||
<template v-if="isImage && maxFileCount === 1">
|
||||
<div v-if="getUploadFileList && getUploadFileList[0] != null" style="position: relative">
|
||||
<img class="upload-image-show" :src="getUploadFileList[0].url" />
|
||||
<el-icon class="upload-img-del" @click.stop="onRemoveFile(null, null)"><Close /></el-icon>
|
||||
</div>
|
||||
<el-icon v-else class="upload-image-item"><Plus /></el-icon>
|
||||
</template>
|
||||
<!-- 上传文件 -->
|
||||
<template v-else-if="!isImage">
|
||||
<el-button :size="layoutStore.defaultFormItemSize" type="primary">点击上传</el-button>
|
||||
</template>
|
||||
</el-upload>
|
||||
<template v-else>
|
||||
<template v-if="isImage">
|
||||
<el-image
|
||||
v-for="item in uploadWidgetImpl.fileList"
|
||||
:preview-src-list="(uploadWidgetImpl.fileList || []).map((imgItem:ANY_OBJECT) => imgItem.url)"
|
||||
class="table-cell-image"
|
||||
:key="item.url"
|
||||
:src="item.url"
|
||||
fit="fill"
|
||||
>
|
||||
</el-image>
|
||||
</template>
|
||||
<a
|
||||
v-else
|
||||
v-for="item in uploadWidgetImpl.fileList"
|
||||
:key="item.url"
|
||||
href="javascript:void(0);"
|
||||
@click="item.url && downloadFile(item.url, item.name)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { UploadFile, ElMessage } from 'element-plus';
|
||||
import { Plus, Close } from '@element-plus/icons-vue';
|
||||
import { useDownload } from '@/common/hooks/useDownload';
|
||||
import { useUpload } from '@/common/hooks/useUpload';
|
||||
import { useUploadWidget } from '@/common/hooks/useUploadWidget';
|
||||
import { OnlineFormEventType } from '@/common/staticDict';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { SysOnlineFieldKind } from '@/common/staticDict/online';
|
||||
import { API_CONTEXT } from '@/api/config';
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:value': [string | undefined];
|
||||
'update:modelValue': [string | undefined];
|
||||
}>();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{ value?: string; widget: ANY_OBJECT; readOnly?: boolean }>(),
|
||||
{
|
||||
readOnly: false,
|
||||
},
|
||||
);
|
||||
|
||||
console.log('OnlineCustomUpload props ', props);
|
||||
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCustomUpload: form not injected');
|
||||
return { isEdit: false } as ANY_OBJECT;
|
||||
});
|
||||
import { useLayoutStore } from '@/store';
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
const { downloadFile } = useDownload();
|
||||
const { getUploadHeaders, getUploadActionUrl, parseUploadData, fileListToJson } = useUpload();
|
||||
|
||||
const maxFileCount = computed(() => {
|
||||
console.log('maxFileCount < column', props.widget.column);
|
||||
return props.widget.column ? props.widget.column.maxFileCount : 1;
|
||||
});
|
||||
const buildFlowParam = computed(() => {
|
||||
let flowParam: ANY_OBJECT = {};
|
||||
let flowData = form().flowData;
|
||||
if (flowData) {
|
||||
if (flowData.processDefinitionKey)
|
||||
flowParam.processDefinitionKey = flowData.processDefinitionKey;
|
||||
if (flowData.processInstanceId) flowParam.processInstanceId = flowData.processInstanceId;
|
||||
if (flowData.taskId) flowParam.taskId = flowData.taskId;
|
||||
}
|
||||
|
||||
return flowParam;
|
||||
});
|
||||
const getActionUrl = computed(() => {
|
||||
if (props.widget.props.actionUrl == null || props.widget.props.actionUrl === '') {
|
||||
if (props.widget.relation) {
|
||||
return getUploadActionUrl(
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/uploadOneToManyRelation/' +
|
||||
(props.widget.datasource || {}).variableName,
|
||||
);
|
||||
} else {
|
||||
return getUploadActionUrl(
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/uploadDatasource/' +
|
||||
(props.widget.datasource || {}).variableName,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return getUploadActionUrl(props.widget.props.actionUrl);
|
||||
}
|
||||
});
|
||||
const getDownloadUrl = computed(() => {
|
||||
if (props.widget.props.downloadUrl == null || props.widget.props.downloadUrl === '') {
|
||||
if (props.widget.relation) {
|
||||
return (
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/downloadOneToManyRelation/' +
|
||||
(props.widget.datasource || {}).variableName
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/downloadDatasource/' +
|
||||
(props.widget.datasource || {}).variableName
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return props.widget.props.downloadUrl;
|
||||
}
|
||||
});
|
||||
|
||||
const uploadData = ref<ANY_OBJECT>({});
|
||||
// const getUploadData = computed(() => {
|
||||
// //console.log('getUploadData 2', uploadData.value);
|
||||
// return uploadData.value;
|
||||
// });
|
||||
const getUploadListType = computed(() => {
|
||||
if (maxFileCount.value !== 1 && isImage.value) {
|
||||
return 'picture-card';
|
||||
}
|
||||
return 'text';
|
||||
});
|
||||
const getUploadFileList = computed(() => {
|
||||
return uploadWidgetImpl ? uploadWidgetImpl.fileList : [];
|
||||
});
|
||||
|
||||
const isImage = ref(false);
|
||||
const uploadWidgetImpl = reactive(
|
||||
useUploadWidget(props.widget.column ? props.widget.column.maxFileCount : 0),
|
||||
);
|
||||
|
||||
const getDisabledStatus = () => {
|
||||
if (form().isEdit) return true;
|
||||
return props.widget.props.disabled;
|
||||
};
|
||||
|
||||
const onValueChange = () => {
|
||||
// TODO 没找到widgetConfig的定义
|
||||
const json = fileListToJson(uploadWidgetImpl.fileList);
|
||||
emit('update:value', json);
|
||||
emit('update:modelValue', json);
|
||||
};
|
||||
const onUploadSuccess = (response: ANY_OBJECT, file: UploadFile, fileList: UploadFile[]) => {
|
||||
if (response.success) {
|
||||
//file.filename = response.data.filename;
|
||||
if (file.raw) file.url = URL.createObjectURL(file.raw);
|
||||
uploadWidgetImpl.onFileChange(file, fileList);
|
||||
onValueChange();
|
||||
} else {
|
||||
ElMessage.error(response.message);
|
||||
}
|
||||
};
|
||||
const onRemoveFile = (file: UploadFile | null, fileList: UploadFile[] | null) => {
|
||||
uploadWidgetImpl.onFileChange(file, fileList);
|
||||
onValueChange();
|
||||
};
|
||||
const onUploadError = () => {
|
||||
ElMessage.error('文件上传失败');
|
||||
};
|
||||
const onUploadLimit = () => {
|
||||
if (maxFileCount.value != null && maxFileCount.value > 0) {
|
||||
ElMessage.error('已经超出最大上传个数限制');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
console.log('OnlineCustomUpload onMounted', props.widget, props.widget.column);
|
||||
//let widget = props.widget;
|
||||
//widget.widgetImpl = getCurrentInstance();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.widget,
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
let column = props.widget.bindData?.column || props.widget.column;
|
||||
isImage.value = column ? column.fieldKind === SysOnlineFieldKind.UPLOAD_IMAGE : false;
|
||||
console.log('watch widget OnlineCustomUpload >>>>>>>>>>', column, isImage.value);
|
||||
|
||||
let temp: ANY_OBJECT = {
|
||||
...buildFlowParam.value,
|
||||
datasourceId: (props.widget.datasource || {}).datasourceId,
|
||||
asImage: isImage.value,
|
||||
fieldName: (props.widget.column || {}).columnName,
|
||||
};
|
||||
// console.log(
|
||||
// 'getUploadData',
|
||||
// props.widget?.datasource ? { ...props.widget.datasource } : 'undddefined',
|
||||
// temp,
|
||||
// );
|
||||
if ((props.widget.relation || {}).relationId)
|
||||
temp.relationId = (props.widget.relation || {}).relationId;
|
||||
let flowData = form().flowData;
|
||||
if (flowData && flowData.processDefinitionKey)
|
||||
temp.processDefinitionKey = flowData.processDefinitionKey;
|
||||
uploadData.value = temp;
|
||||
}, 30);
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
newValue => {
|
||||
console.log('OnlineCustomUpload watch value', newValue);
|
||||
if (!newValue) return;
|
||||
setTimeout(() => {
|
||||
uploadWidgetImpl.fileList = [];
|
||||
if (newValue != null) {
|
||||
let downloadParams: ANY_OBJECT = {
|
||||
...buildFlowParam.value,
|
||||
datasourceId: (props.widget.datasource || {}).datasourceId,
|
||||
fieldName: props.widget.column.columnName,
|
||||
asImage: isImage.value,
|
||||
dataId: form().getPrimaryData(props.widget) || '',
|
||||
};
|
||||
if (props.widget.relation) downloadParams.relationId = props.widget.relation.relationId;
|
||||
let temp = JSON.parse(newValue);
|
||||
temp = Array.isArray(temp)
|
||||
? temp.map(item => {
|
||||
return {
|
||||
...item,
|
||||
downloadUri: getDownloadUrl.value,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
uploadWidgetImpl.fileList = parseUploadData(JSON.stringify(temp), downloadParams);
|
||||
}
|
||||
}, 30);
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -0,0 +1,579 @@
|
||||
<template>
|
||||
<component
|
||||
v-bind="getWidgetProps"
|
||||
:ref="widget.variableName"
|
||||
:is="getComponent"
|
||||
:style="getWidgetStyle"
|
||||
:disabled="getDisabledStatus()"
|
||||
:widget="widget"
|
||||
v-model="bindValue"
|
||||
:value="bindValue"
|
||||
@change="onValueChange"
|
||||
:change="onValueChange"
|
||||
@widgetClick="onWidgetClick"
|
||||
>
|
||||
<template v-if="form().mode === 'pc'" v-slot="scope">
|
||||
<template v-if="widget.widgetType === SysCustomWidgetType.Radio">
|
||||
<el-radio v-for="item in getAllDropdownData" :key="item.id" :value="item.id">
|
||||
{{ item.name }}
|
||||
</el-radio>
|
||||
</template>
|
||||
<template
|
||||
v-else-if="
|
||||
widget.widgetType === SysCustomWidgetType.Date ||
|
||||
widget.widgetType === SysCustomWidgetType.DateRange
|
||||
"
|
||||
>
|
||||
<div class="el-date-table-cell">
|
||||
<span class="el-date-table-cell__text">{{ scope.text }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="widget.widgetType === SysCustomWidgetType.CheckBox">
|
||||
<el-checkbox v-for="item in getAllDropdownData" :key="item.id" :label="item.id">
|
||||
{{ item.name }}
|
||||
</el-checkbox>
|
||||
</template>
|
||||
<template v-else-if="widget.widgetType === SysCustomWidgetType.Select">
|
||||
<el-option
|
||||
v-for="item in getAllDropdownData"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</template>
|
||||
<template v-if="widget.widgetType === SysCustomWidgetType.Link">
|
||||
<span>{{ widget.props.showText || widget.showName }}</span>
|
||||
</template>
|
||||
</template>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
ElCascader,
|
||||
ElCheckboxGroup,
|
||||
ElDatePicker,
|
||||
ElInput,
|
||||
ElInputNumber,
|
||||
ElLink,
|
||||
ElRadioGroup,
|
||||
ElSelect,
|
||||
ElSwitch,
|
||||
} from 'element-plus';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { OnlineFormEventType, SysCustomWidgetType, SysOnlineFormType } from '@/common/staticDict';
|
||||
import { SysOnlineColumnFilterType, SysOnlineFieldKind } from '@/common/staticDict/online';
|
||||
import {
|
||||
treeDataTranslate,
|
||||
findTreeNode,
|
||||
findItemFromList,
|
||||
findTreeNodePath,
|
||||
} from '@/common/utils';
|
||||
import RichEditor from '@/components/RichEditor/index.vue';
|
||||
import UserSelect from '@/components/UserSelect/index.vue';
|
||||
import DeptSelect from '@/components/DeptSelect/index.vue';
|
||||
import InputNumberRange from '@/components/InputNumberRange/index.vue';
|
||||
import OnlineCustomLabel from './OnlineCustomLabel.vue';
|
||||
import OnlineCustomUpload from './OnlineCustomUpload.vue';
|
||||
import OnlineCustomTree from './OnlineCustomTree.vue';
|
||||
import OnlineCustomText from './OnlineCustomText.vue';
|
||||
import OnlineCustomImage from './OnlineCustomImage.vue';
|
||||
import { WidgetEmit, WidgetProps } from './types/widget';
|
||||
import { useWidget } from './hooks/widget';
|
||||
|
||||
type ValueType = string | boolean | Date | number | ANY_OBJECT | Array<ANY_OBJECT>;
|
||||
|
||||
interface IEmit extends WidgetEmit {
|
||||
(event: 'change', value: ANY_OBJECT | undefined, params: ANY_OBJECT | null): void;
|
||||
(event: 'update:value', value: ValueType | undefined): void;
|
||||
(event: 'update:modelValue', value: ValueType | undefined): void;
|
||||
(event: 'update:widget', value: ANY_OBJECT): void;
|
||||
(event: 'input', value: ValueType | undefined): void;
|
||||
}
|
||||
const emit = defineEmits<IEmit>();
|
||||
|
||||
interface IProps extends WidgetProps {
|
||||
value?: ValueType;
|
||||
widget: ANY_OBJECT;
|
||||
}
|
||||
const pps = withDefaults(defineProps<IProps>(), {});
|
||||
|
||||
console.log('widget pps', pps);
|
||||
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCustomWidget: form not injected');
|
||||
return { isEdit: false } as ANY_OBJECT;
|
||||
});
|
||||
const parentWidget = inject<ANY_OBJECT | null>('parentWidget', null);
|
||||
|
||||
const { propsWidget, onWidgetClick } = useWidget(pps, emit);
|
||||
|
||||
const dictDataList = ref<ANY_OBJECT[]>([]);
|
||||
const tempValue = ref();
|
||||
|
||||
const multiSelect = computed(() => {
|
||||
if (
|
||||
[
|
||||
SysCustomWidgetType.Select,
|
||||
SysCustomWidgetType.CheckBox,
|
||||
SysCustomWidgetType.Cascader,
|
||||
SysCustomWidgetType.Tree,
|
||||
].indexOf(pps.widget.widgetType) === -1
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (pps.widget.widgetType === SysCustomWidgetType.CheckBox) return true;
|
||||
if (
|
||||
form().formType === SysOnlineFormType.QUERY ||
|
||||
form().formType === SysOnlineFormType.ADVANCE_QUERY
|
||||
) {
|
||||
return (
|
||||
pps.widget.column &&
|
||||
pps.widget.column.filterType === SysOnlineColumnFilterType.MULTI_SELECT_FILTER
|
||||
);
|
||||
} else if (form().formType === SysOnlineFormType.REPORT) {
|
||||
return SysCustomWidgetType.CheckBox === pps.widget.widgetType;
|
||||
} else {
|
||||
return pps.widget.column && pps.widget.column.fieldKind === SysOnlineFieldKind.MULTI_SELECT;
|
||||
}
|
||||
});
|
||||
const isMobileFilter = computed(() => {
|
||||
return (
|
||||
[
|
||||
SysCustomWidgetType.MobileRadioFilter,
|
||||
SysCustomWidgetType.MobileCheckBoxFilter,
|
||||
SysCustomWidgetType.MobileInputFilter,
|
||||
SysCustomWidgetType.MobileDateRangeFilter,
|
||||
SysCustomWidgetType.MobileNumberRangeFilter,
|
||||
SysCustomWidgetType.MobileSwitchFilter,
|
||||
].indexOf(pps.widget.widgetType) !== -1
|
||||
);
|
||||
});
|
||||
const getAllDropdownData = computed(() => {
|
||||
console.log('widget getAllDropdownData', pps.widget.props.supportAll, dictDataList);
|
||||
if (pps.widget.props.supportAll) {
|
||||
return [
|
||||
{
|
||||
id: '',
|
||||
name: '全部',
|
||||
},
|
||||
...dictDataList.value,
|
||||
];
|
||||
} else {
|
||||
return dictDataList.value;
|
||||
}
|
||||
});
|
||||
const getWidgetStyle = computed(() => {
|
||||
return {
|
||||
width: pps.widget.widgetType !== SysCustomWidgetType.Link ? '100%' : undefined,
|
||||
};
|
||||
});
|
||||
const getComponent = computed(() => {
|
||||
console.log(
|
||||
'widget getComponent',
|
||||
pps.widget.widgetType,
|
||||
SysCustomWidgetType.getValue(pps.widget.widgetType),
|
||||
);
|
||||
if (
|
||||
[
|
||||
SysCustomWidgetType.Text,
|
||||
SysCustomWidgetType.Image,
|
||||
SysCustomWidgetType.Upload,
|
||||
SysCustomWidgetType.Link,
|
||||
].indexOf(pps.widget.widgetType) === -1 &&
|
||||
form().readOnly
|
||||
) {
|
||||
return OnlineCustomLabel;
|
||||
}
|
||||
let mode = form().mode;
|
||||
console.log('widget getComponent mode', mode);
|
||||
|
||||
switch (pps.widget.widgetType) {
|
||||
case SysCustomWidgetType.Label:
|
||||
return OnlineCustomLabel;
|
||||
case SysCustomWidgetType.Input:
|
||||
return ElInput;
|
||||
case SysCustomWidgetType.NumberInput:
|
||||
return ElInputNumber;
|
||||
case SysCustomWidgetType.NumberRange:
|
||||
return InputNumberRange;
|
||||
case SysCustomWidgetType.Switch:
|
||||
return ElSwitch;
|
||||
case SysCustomWidgetType.Radio:
|
||||
return ElRadioGroup;
|
||||
case SysCustomWidgetType.CheckBox:
|
||||
return ElCheckboxGroup;
|
||||
case SysCustomWidgetType.Select:
|
||||
return ElSelect;
|
||||
case SysCustomWidgetType.Cascader:
|
||||
return ElCascader;
|
||||
case SysCustomWidgetType.Date:
|
||||
return ElDatePicker;
|
||||
case SysCustomWidgetType.DateRange:
|
||||
return ElDatePicker;
|
||||
case SysCustomWidgetType.Upload:
|
||||
return OnlineCustomUpload;
|
||||
case SysCustomWidgetType.RichEditor:
|
||||
return RichEditor;
|
||||
case SysCustomWidgetType.Link:
|
||||
return ElLink;
|
||||
case SysCustomWidgetType.UserSelect:
|
||||
return UserSelect;
|
||||
case SysCustomWidgetType.DeptSelect:
|
||||
return DeptSelect;
|
||||
case SysCustomWidgetType.Tree:
|
||||
return OnlineCustomTree;
|
||||
case SysCustomWidgetType.Text:
|
||||
return OnlineCustomText;
|
||||
case SysCustomWidgetType.Image:
|
||||
return OnlineCustomImage;
|
||||
default:
|
||||
console.warn('widget getComponent 未知类型');
|
||||
return 'div';
|
||||
}
|
||||
});
|
||||
const getLinkHerf = computed(() => {
|
||||
let temp = pps.widget.widgetType === SysCustomWidgetType.Link ? pps.widget.props.href : undefined;
|
||||
return temp;
|
||||
});
|
||||
const isDictWidget = computed(() => {
|
||||
return (
|
||||
[
|
||||
SysCustomWidgetType.Select,
|
||||
SysCustomWidgetType.CheckBox,
|
||||
SysCustomWidgetType.Radio,
|
||||
SysCustomWidgetType.Cascader,
|
||||
SysCustomWidgetType.Tree,
|
||||
SysCustomWidgetType.MobileCheckBoxFilter,
|
||||
SysCustomWidgetType.MobileRadioFilter,
|
||||
].indexOf(pps.widget.widgetType) !== -1
|
||||
);
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const bindValue = computed<string | number | boolean | any[] | ANY_OBJECT | Date | undefined>({
|
||||
get() {
|
||||
console.log('widget bind props.value >>', pps.value);
|
||||
let tempValue = pps.value === undefined ? '' : pps.value;
|
||||
if (isDictWidget.value) tempValue = tempValue == null ? '' : tempValue + '';
|
||||
if (multiSelect.value && pps.value && typeof tempValue === 'string') {
|
||||
tempValue = tempValue.split(',');
|
||||
if (Array.isArray(tempValue)) {
|
||||
tempValue = tempValue.filter(item => {
|
||||
return item != null && item !== '';
|
||||
});
|
||||
}
|
||||
}
|
||||
if (pps.widget.widgetType === SysCustomWidgetType.CheckBox) {
|
||||
return tempValue || [];
|
||||
} else if (pps.widget.widgetType === SysCustomWidgetType.Cascader) {
|
||||
if (multiSelect.value) {
|
||||
// 多选
|
||||
if (Array.isArray(tempValue)) {
|
||||
return tempValue
|
||||
.map(item => {
|
||||
let temp = findTreeNodePath(dictDataList.value, item);
|
||||
if (Array.isArray(temp) && temp.length > 0) return temp;
|
||||
return null;
|
||||
})
|
||||
.filter(item => item != null);
|
||||
} else {
|
||||
let temp = findTreeNodePath(dictDataList.value, tempValue.toString());
|
||||
return temp || [];
|
||||
}
|
||||
} else {
|
||||
// 单选
|
||||
let temp = findTreeNodePath(dictDataList.value, tempValue.toString());
|
||||
return temp.length > 0 ? temp : tempValue;
|
||||
}
|
||||
} else if (pps.widget.widgetType === SysCustomWidgetType.NumberInput) {
|
||||
return tempValue as number;
|
||||
} else {
|
||||
return tempValue;
|
||||
}
|
||||
},
|
||||
set(val) {
|
||||
console.log('widget .......bindValue..........', val, typeof val);
|
||||
onValueInput(val as ANY_OBJECT | undefined);
|
||||
},
|
||||
});
|
||||
const isUploadImage = computed(() => {
|
||||
if (pps.widget.widgetType !== SysCustomWidgetType.Upload) return false;
|
||||
let column = pps.widget.bindData.column || pps.widget.column;
|
||||
return column ? column.fieldKind === SysOnlineFieldKind.UPLOAD_IMAGE : false;
|
||||
});
|
||||
const showRightIcon = computed(() => {
|
||||
return (
|
||||
[
|
||||
SysCustomWidgetType.Select,
|
||||
SysCustomWidgetType.Cascader,
|
||||
SysCustomWidgetType.Date,
|
||||
SysCustomWidgetType.UserSelect,
|
||||
SysCustomWidgetType.DeptSelect,
|
||||
SysCustomWidgetType.Calendar,
|
||||
].indexOf(pps.widget.widgetType) !== -1
|
||||
);
|
||||
});
|
||||
|
||||
const getWidgetProps = computed(() => {
|
||||
let props = {
|
||||
...(pps.widget.props || {}),
|
||||
};
|
||||
// 日期组件,根据类型设置format
|
||||
if (
|
||||
pps.widget.widgetType === SysCustomWidgetType.Date ||
|
||||
pps.widget.widgetType === SysCustomWidgetType.DateRange
|
||||
) {
|
||||
props['value-format'] = 'YYYY-MM-DD HH:mm:ss';
|
||||
}
|
||||
console.log('widget props', SysCustomWidgetType.getValue(pps.widget.widgetType), props);
|
||||
return {
|
||||
...props,
|
||||
clearable: true,
|
||||
filterable: true,
|
||||
readOnly:
|
||||
pps.widget.widgetType === SysCustomWidgetType.Upload
|
||||
? form().readOnly || props.readOnly
|
||||
: undefined,
|
||||
options:
|
||||
pps.widget.widgetType === SysCustomWidgetType.Cascader ? dictDataList.value : undefined,
|
||||
props:
|
||||
pps.widget.widgetType === SysCustomWidgetType.Cascader
|
||||
? {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
multiple: multiSelect.value,
|
||||
checkStrictly: true,
|
||||
}
|
||||
: undefined,
|
||||
operationList: pps.widget.operationList,
|
||||
multiple: multiSelect.value,
|
||||
'collapse-tags': multiSelect.value,
|
||||
dataList: pps.widget.widgetType === SysCustomWidgetType.Tree ? dictDataList.value : undefined,
|
||||
dictDataList: isMobileFilter.value ? getAllDropdownData.value : undefined,
|
||||
href: getLinkHerf.value,
|
||||
widget: pps.widget,
|
||||
};
|
||||
});
|
||||
|
||||
const getDisabledStatus = () => {
|
||||
return pps.widget.props.disabled;
|
||||
};
|
||||
|
||||
const parseValue = (val: ValueType): ANY_OBJECT => {
|
||||
if (pps.widget.widgetType === SysCustomWidgetType.Cascader) {
|
||||
if (multiSelect.value && Array.isArray(val)) {
|
||||
return val
|
||||
.map((item: ANY_OBJECT) => {
|
||||
return item[item.length - 1];
|
||||
})
|
||||
.filter((item: ANY_OBJECT) => item != null);
|
||||
} else {
|
||||
return Array.isArray(val) ? val[val.length - 1] : undefined;
|
||||
}
|
||||
} else {
|
||||
return val as ANY_OBJECT;
|
||||
}
|
||||
};
|
||||
const onValueInput = (val: ANY_OBJECT | undefined) => {
|
||||
let tempValue: ValueType | undefined = undefined;
|
||||
if (val) {
|
||||
console.log('widget typeof val', typeof val, val instanceof InputEvent, val instanceof Event);
|
||||
if (val instanceof InputEvent) {
|
||||
console.warn('widget input value is InputEvent');
|
||||
return;
|
||||
} else if (val instanceof Event) {
|
||||
console.log('wiget >>>>>>> value >>>>>>', val, val.target instanceof HTMLInputElement);
|
||||
if (val.target instanceof HTMLInputElement) {
|
||||
tempValue = val.target.value;
|
||||
}
|
||||
} else {
|
||||
tempValue = parseValue(val);
|
||||
}
|
||||
|
||||
if (multiSelect.value && Array.isArray(tempValue) /*&& tempValue.length > 0*/) {
|
||||
tempValue = tempValue.join(',') + ',';
|
||||
}
|
||||
}
|
||||
console.log('widget update:value', tempValue);
|
||||
emit('update:value', tempValue);
|
||||
emit('update:modelValue', tempValue);
|
||||
// ElDatePicker(DateRange)有了这个事件才能更新显示
|
||||
emit('input', tempValue);
|
||||
};
|
||||
const onValueChange = (
|
||||
val: ANY_OBJECT | undefined,
|
||||
selectRow: ANY_OBJECT | undefined = undefined,
|
||||
) => {
|
||||
let tempVal: ValueType | undefined = undefined;
|
||||
let dictData = null;
|
||||
|
||||
console.log('widget onValueChange >>>', val);
|
||||
if (val) {
|
||||
tempVal = parseValue(val);
|
||||
if (multiSelect.value) {
|
||||
dictData = val
|
||||
.map((item: string) => {
|
||||
if (pps.widget.widgetType === SysCustomWidgetType.Cascader) {
|
||||
if (Array.isArray(item)) {
|
||||
item = item[item.length - 1];
|
||||
}
|
||||
return findTreeNode(dictDataList.value, item, 'id', 'children');
|
||||
} else {
|
||||
return findItemFromList(dictDataList.value, item, 'id');
|
||||
}
|
||||
})
|
||||
.filter((item: ANY_OBJECT) => item != null);
|
||||
} else {
|
||||
let id = val.toString();
|
||||
if (pps.widget.widgetType === SysCustomWidgetType.Cascader) {
|
||||
if (Array.isArray(val)) {
|
||||
val = val[val.length - 1];
|
||||
}
|
||||
dictData = findTreeNode(dictDataList.value, id, 'id', 'children');
|
||||
} else {
|
||||
dictData = findItemFromList(dictDataList.value, id, 'id');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 这个似乎没有起到什么作用
|
||||
emit('change', tempVal, {
|
||||
dictData: dictData,
|
||||
selectRow: selectRow,
|
||||
});
|
||||
onValueInput(tempVal);
|
||||
};
|
||||
|
||||
const loadDropdownData = () => {
|
||||
if (pps.widget == null || !isDictWidget.value) {
|
||||
return;
|
||||
}
|
||||
dictDataList.value = [];
|
||||
setTimeout(() => {
|
||||
let dictInfo = (pps.widget.props.dictInfo || {}).dict;
|
||||
console.log('widget OnlineCustomWidget loadDropdownData', dictInfo, pps);
|
||||
if (dictInfo && form().getDictDataList) {
|
||||
let dictCall;
|
||||
if (form().pageCode != null) {
|
||||
// 报表字典
|
||||
dictCall = form().getDictDataList(dictInfo, form().getDropdownParams(pps.widget));
|
||||
} else {
|
||||
// 在线表单字典
|
||||
dictCall = form().getDictDataList(dictInfo, form().getDropdownParams(pps.widget));
|
||||
}
|
||||
dictCall
|
||||
.then((res: ANY_OBJECT[]) => {
|
||||
console.log('OnlineCustomWidget loadDropdownData', res);
|
||||
res.forEach((item: ANY_OBJECT) => {
|
||||
item.id = item.id + '';
|
||||
if (item.parentId) item.parentId = item.parentId + '';
|
||||
});
|
||||
// 级联组件将列表转换成树
|
||||
if (pps.widget.widgetType === SysCustomWidgetType.Cascader) {
|
||||
res = treeDataTranslate(res, 'id', 'parentId');
|
||||
}
|
||||
dictDataList.value = res;
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
}, 30);
|
||||
};
|
||||
|
||||
const getHtml = () => {
|
||||
console.log('widget call getHtml()');
|
||||
const refs = (getCurrentInstance()?.refs || {}) as ANY_OBJECT;
|
||||
console.log('refs', refs);
|
||||
if (pps.widget.widgetType === SysCustomWidgetType.RichEditor) {
|
||||
return refs[pps.widget.variableName] ? refs[pps.widget.variableName].getHtml() : undefined;
|
||||
}
|
||||
};
|
||||
const reset = () => {
|
||||
console.log('widget call reset()');
|
||||
onValueInput(undefined);
|
||||
onValueChange(undefined);
|
||||
nextTick(() => {
|
||||
loadDropdownData();
|
||||
});
|
||||
};
|
||||
const refresh = () => {
|
||||
const refs = (getCurrentInstance()?.refs || {}) as ANY_OBJECT;
|
||||
console.log('widget call refresh() refs:', refs);
|
||||
if (
|
||||
refs[pps.widget.variableName] &&
|
||||
typeof refs[pps.widget.variableName].refresh === 'function'
|
||||
) {
|
||||
refs[pps.widget.variableName].refresh();
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
getHtml,
|
||||
reset,
|
||||
refresh,
|
||||
});
|
||||
|
||||
watch(
|
||||
() => pps.widget,
|
||||
() => {
|
||||
console.log('props widget change', pps.widget);
|
||||
if (pps.widget) loadDropdownData();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
// watch(
|
||||
// () => pps.widget.props.dictInfo,
|
||||
// () => {
|
||||
// if (pps.widget) loadDropdownData();
|
||||
// },
|
||||
// {
|
||||
// deep: true,
|
||||
// immediate: true,
|
||||
// },
|
||||
// );
|
||||
// 如果父组件为数据表格或者列表组件,那么子组件绑定表必须跟父组件一致
|
||||
watch(
|
||||
() => parentWidget,
|
||||
(newValue, oldValue) => {
|
||||
const widget = { ...propsWidget.value };
|
||||
if (parentWidget != null && propsWidget.value) {
|
||||
// 如果绑定的数据表改变了,修改子组件绑定的数据表
|
||||
if (parentWidget.bindData.tableId !== propsWidget.value.bindData.tableId) {
|
||||
widget.props.bindData = {
|
||||
...parentWidget.bindData,
|
||||
};
|
||||
widget.showName = undefined;
|
||||
if (widget.widgetType === SysCustomWidgetType.Text) {
|
||||
widget.props.text = '文本内容';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (newValue == null && oldValue != null) {
|
||||
widget.bindData = {
|
||||
dataType: 0,
|
||||
tableId: undefined,
|
||||
table: undefined,
|
||||
columnId: undefined,
|
||||
column: undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
propsWidget.value = widget;
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
console.log('getComponent', getComponent.value, getWidgetProps.value);
|
||||
//propsWidget.value.widgetImpl = getCurrentInstance();
|
||||
//propsWidget.value.parent = parentWidget;
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,496 @@
|
||||
<template>
|
||||
<vxe-table
|
||||
ref="table"
|
||||
:key="tableKey"
|
||||
:data="dataList"
|
||||
:height="height"
|
||||
show-overflow="title"
|
||||
show-header-overflow="title"
|
||||
header-cell-class-name="table-header-gray"
|
||||
:keep-source="false"
|
||||
:row-config="{ height: rowHeight, isHover: true }"
|
||||
:seq-config="{ seqMethod }"
|
||||
@sort-change="onSortChange"
|
||||
:sort-config="{ remote: remoteSort }"
|
||||
>
|
||||
<vxe-column v-if="tableColumnList.length > 0" type="seq" title="序号" :width="60" />
|
||||
<vxe-column title="工单编号" show-overflow="tooltip" field="workOrderCode" :width="200" />
|
||||
<template v-for="tableColumn in tableColumnList" :key="tableColumn.id">
|
||||
<!-- Boolean类型字段 -->
|
||||
<vxe-column
|
||||
v-if="tableColumn.column && tableColumn.column.objectFieldType === 'Boolean'"
|
||||
:title="tableColumn.showName"
|
||||
:width="tableColumn.columnWidth"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
:type="getObjectValue(row, tableColumn.showFieldName) ? 'success' : 'danger'"
|
||||
>
|
||||
{{ getObjectValue(row, tableColumn.showFieldName) ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<!-- 图片类型字段 -->
|
||||
<vxe-column
|
||||
v-else-if="
|
||||
tableColumn.column && tableColumn.column.fieldKind === SysOnlineFieldKind.UPLOAD_IMAGE
|
||||
"
|
||||
:title="tableColumn.showName"
|
||||
:width="tableColumn.columnWidth"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-image
|
||||
v-for="item in parseTableUploadData(tableColumn, row)"
|
||||
:preview-src-list="getTablePictureList(tableColumn, row)"
|
||||
class="table-cell-image"
|
||||
:key="item.url"
|
||||
:src="item.url"
|
||||
fit="fill"
|
||||
>
|
||||
<template v-slot:error>
|
||||
<div class="table-cell-image">
|
||||
<el-icon><Picture /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<!-- 文件下载类型字段 -->
|
||||
<vxe-column
|
||||
v-else-if="tableColumn.column && tableColumn.column.fieldKind === SysOnlineFieldKind.UPLOAD"
|
||||
:title="tableColumn.showName"
|
||||
:width="tableColumn.columnWidth"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<a
|
||||
v-for="item in parseTableUploadData(tableColumn, row)"
|
||||
:key="item.url"
|
||||
href="javascript:void(0);"
|
||||
@click="downloadFile(item.url, item.name)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<!-- 其他类型 -->
|
||||
<vxe-column
|
||||
v-else
|
||||
:title="tableColumn.showName"
|
||||
:field="tableColumn.showFieldName"
|
||||
:width="tableColumn.columnWidth"
|
||||
:sortable="tableColumn.sortable"
|
||||
/>
|
||||
</template>
|
||||
<vxe-column title="当前任务" field="runtimeTaskInfo.taskName" :min-width="100" />
|
||||
<vxe-column title="流程创建时间" field="createTime" :min-width="180" />
|
||||
<vxe-column title="流程状态" field="latestApprovalStatusDictMap.name" :min-width="100" />
|
||||
<vxe-column title="工单状态" field="flowStatusShowName" :min-width="100" />
|
||||
<vxe-column title="操作" :width="160" fixed="right" :show-overflow="false">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
link
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
v-if="getPrintOperation != null"
|
||||
:class="getPrintOperation.btnClass"
|
||||
@click.stop="onPrint(getPrintOperation, row)"
|
||||
>
|
||||
{{ getPrintOperation.name || '打印' }}
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
v-if="(row.initTaskInfo || {}).taskKey !== (row.runtimeTaskInfo || {}).taskKey"
|
||||
@click.stop="onViewWorkOrder(row)"
|
||||
>
|
||||
详情
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
v-if="(row.initTaskInfo || {}).taskKey === (row.runtimeTaskInfo || {}).taskKey"
|
||||
@click.stop="onHandlerWorkOrder(row)"
|
||||
>
|
||||
办理
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
@click.stop="onHandlerRemindClick(row)"
|
||||
>
|
||||
催办
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
:size="layoutStore.defaultFormItemSize"
|
||||
@click.stop="onCancelWorkOrder(row)"
|
||||
>
|
||||
撤销
|
||||
</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<template v-slot:empty>
|
||||
<div class="table-empty unified-font">
|
||||
<img src="@/assets/img/empty.png" />
|
||||
<span>暂无数据</span>
|
||||
</div>
|
||||
</template>
|
||||
</vxe-table>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Picture } from '@element-plus/icons-vue';
|
||||
import { VxeTable, VxeColumn } from 'vxe-table';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { SortInfo } from '@/common/types/sortinfo';
|
||||
import { SysOnlineFieldKind } from '@/common/staticDict/online';
|
||||
import { findItemFromList, getObjectValue } from '@/common/utils';
|
||||
import { SysCustomWidgetOperationType } from '@/common/staticDict';
|
||||
import widgetData from '@/online/config/index';
|
||||
import { downloadBlob, post } from '@/common/http/request';
|
||||
import { useDownload } from '@/common/hooks/useDownload';
|
||||
import { useUpload } from '@/common/hooks/useUpload';
|
||||
import { API_CONTEXT } from '@/api/config';
|
||||
|
||||
const emit = defineEmits<{
|
||||
viewWorkOrder: [ANY_OBJECT, ANY_OBJECT | null];
|
||||
handlerWorkOrder: [ANY_OBJECT, ANY_OBJECT | null];
|
||||
handlerRemind: [ANY_OBJECT, ANY_OBJECT | null];
|
||||
cancelWorkOrder: [ANY_OBJECT, ANY_OBJECT | null];
|
||||
}>();
|
||||
|
||||
interface IProps {
|
||||
widget: ANY_OBJECT;
|
||||
dataList?: ANY_OBJECT[];
|
||||
height?: number | string;
|
||||
border?: string;
|
||||
// 是否支持行内编辑
|
||||
rowEdit?: boolean;
|
||||
// 是否支持多选
|
||||
multiSelect?: boolean;
|
||||
// 表格操作列表
|
||||
operationList?: ANY_OBJECT[];
|
||||
// 获取行序号
|
||||
getTableIndex?: (value: number) => number;
|
||||
// 排序改变
|
||||
sortChange?: (value: SortInfo) => void;
|
||||
// 多选选中改变
|
||||
onSelectChange?: (values: Array<ANY_OBJECT>) => void;
|
||||
// 单选中改变
|
||||
onRadioChange?: (value: ANY_OBJECT) => void;
|
||||
}
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
isEdit: false,
|
||||
dataList: () => [],
|
||||
height: 'auto',
|
||||
border: 'full',
|
||||
rowEdit: false,
|
||||
multiSelect: false,
|
||||
operationList: () => [],
|
||||
});
|
||||
|
||||
import { useLayoutStore } from '@/store';
|
||||
const layoutStore = useLayoutStore();
|
||||
const form = inject('form', () => {
|
||||
console.error('OnlineCustomWorkFlowTable: form not injected');
|
||||
return { isEdit: false } as ANY_OBJECT;
|
||||
});
|
||||
const { downloadFile } = useDownload();
|
||||
const { parseUploadData } = useUpload();
|
||||
|
||||
const table = ref();
|
||||
const sortInfo = ref<SortInfo | null>();
|
||||
const tableColumnList = computed(() => {
|
||||
let tempList =
|
||||
props.widget && props.widget.props && Array.isArray(props.widget.props.tableColumnList)
|
||||
? props.widget.props.tableColumnList
|
||||
: [];
|
||||
tempList.forEach((item: ANY_OBJECT) => {
|
||||
if (item.fieldType === 0 || item.fieldType == null) {
|
||||
// 绑定表字段
|
||||
item.showFieldName =
|
||||
'masterData.' +
|
||||
(item.relation ? item.relation.variableName : '') +
|
||||
(item.column || {}).columnName;
|
||||
if ((item.column || {}).dictInfo) {
|
||||
item.showFieldName = item.showFieldName + 'DictMap.name';
|
||||
}
|
||||
} else {
|
||||
// 自定义字段
|
||||
item.showFieldName = item.customFieldName;
|
||||
}
|
||||
});
|
||||
return tempList;
|
||||
});
|
||||
const hasImageColumn = computed(() => {
|
||||
return (
|
||||
tableColumnList.value.filter((tableColumn: ANY_OBJECT) => {
|
||||
return tableColumn.column && tableColumn.column.fieldKind === SysOnlineFieldKind.UPLOAD_IMAGE;
|
||||
}).length > 0
|
||||
);
|
||||
});
|
||||
const rowHeight = computed(() => {
|
||||
return hasImageColumn.value ? 80 : 35;
|
||||
});
|
||||
const tableKey = computed(() => {
|
||||
return (props.widget || {}).variableName + new Date().getTime() + tableColumnList.value.length;
|
||||
});
|
||||
const remoteSort = computed(() => {
|
||||
return false;
|
||||
});
|
||||
const getPrintOperation = computed(() => {
|
||||
let operation = findItemFromList(
|
||||
form().operationList,
|
||||
SysCustomWidgetOperationType.PRINT,
|
||||
'type',
|
||||
);
|
||||
return operation && operation.enabled ? operation : null;
|
||||
});
|
||||
const buildFlowParam = computed(() => {
|
||||
let flowParam: ANY_OBJECT = {};
|
||||
let flowData = form().flowData;
|
||||
if (flowData) {
|
||||
if (flowData.processDefinitionKey)
|
||||
flowParam.processDefinitionKey = flowData.processDefinitionKey;
|
||||
if (flowData.processInstanceId) flowParam.processInstanceId = flowData.processInstanceId;
|
||||
if (flowData.taskId) flowParam.taskId = flowData.taskId;
|
||||
}
|
||||
|
||||
return flowParam;
|
||||
});
|
||||
|
||||
const seqMethod = (data: ANY_OBJECT) => {
|
||||
if (props.getTableIndex) {
|
||||
return props.getTableIndex(data.seq - 1);
|
||||
} else {
|
||||
return data.seq;
|
||||
}
|
||||
};
|
||||
const onSortChange = (data: ANY_OBJECT) => {
|
||||
if (!props.widget.props.paged) return;
|
||||
let fieldName = data.property.replace('DictMap.name', '');
|
||||
let order = data.order;
|
||||
if (order == null) {
|
||||
fieldName = undefined;
|
||||
}
|
||||
if (order === 'asc') order = 'ascending';
|
||||
if (
|
||||
sortInfo.value != null &&
|
||||
sortInfo.value.prop === fieldName &&
|
||||
sortInfo.value.order === order
|
||||
) {
|
||||
return;
|
||||
}
|
||||
sortInfo.value = {
|
||||
prop: fieldName,
|
||||
order: order,
|
||||
};
|
||||
if (props.sortChange) {
|
||||
props.sortChange(sortInfo.value);
|
||||
}
|
||||
};
|
||||
const onViewWorkOrder = (row: ANY_OBJECT) => {
|
||||
emit('viewWorkOrder', row, widgetData.getWidgetAttribute(props.widget.widgetType));
|
||||
};
|
||||
const onHandlerWorkOrder = (row: ANY_OBJECT) => {
|
||||
emit('handlerWorkOrder', row, widgetData.getWidgetAttribute(props.widget.widgetType));
|
||||
};
|
||||
const onHandlerRemindClick = (row: ANY_OBJECT) => {
|
||||
emit('handlerRemind', row, widgetData.getWidgetAttribute(props.widget.widgetType));
|
||||
};
|
||||
const onCancelWorkOrder = (row: ANY_OBJECT) => {
|
||||
emit('cancelWorkOrder', row, widgetData.getWidgetAttribute(props.widget.widgetType));
|
||||
};
|
||||
const refreshColumn = () => {
|
||||
nextTick(() => {
|
||||
if (table.value) table.value.refreshColumn();
|
||||
});
|
||||
};
|
||||
const getDownloadUrl = (tableColumn: ANY_OBJECT) => {
|
||||
let downloadUrl = null;
|
||||
if (form().flowData != null) {
|
||||
downloadUrl = API_CONTEXT + '/flow/flowOnlineOperation/download';
|
||||
} else {
|
||||
if (tableColumn.relationId) {
|
||||
downloadUrl =
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/downloadOneToManyRelation/' +
|
||||
(props.widget.datasource || {}).variableName;
|
||||
} else {
|
||||
downloadUrl =
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/downloadDatasource/' +
|
||||
(props.widget.datasource || {}).variableName;
|
||||
}
|
||||
}
|
||||
|
||||
return downloadUrl;
|
||||
};
|
||||
const parseTableUploadData = (tableColumn: ANY_OBJECT, row: ANY_OBJECT) => {
|
||||
let jsonData = getObjectValue(row, tableColumn.showFieldName);
|
||||
if (jsonData == null) return [];
|
||||
let downloadParams: ANY_OBJECT = {
|
||||
...buildFlowParam.value,
|
||||
datasourceId: props.widget.datasource.datasourceId,
|
||||
relationId: tableColumn.relationId,
|
||||
fieldName: tableColumn.column.columnName,
|
||||
asImage: tableColumn.column.fieldKind === SysOnlineFieldKind.UPLOAD_IMAGE,
|
||||
};
|
||||
|
||||
if (props.widget.primaryColumnName != null) {
|
||||
downloadParams.dataId = row[props.widget.primaryColumnName] || '';
|
||||
}
|
||||
|
||||
let downloadUrl = getDownloadUrl(tableColumn);
|
||||
|
||||
let temp = JSON.parse(jsonData.toString());
|
||||
temp = Array.isArray(temp)
|
||||
? temp.map(item => {
|
||||
return {
|
||||
...item,
|
||||
downloadUri: downloadUrl,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
return parseUploadData(JSON.stringify(temp), downloadParams);
|
||||
};
|
||||
const getTablePictureList = (tableColumn: ANY_OBJECT, row: ANY_OBJECT) => {
|
||||
let temp = parseTableUploadData(tableColumn, row);
|
||||
if (Array.isArray(temp)) {
|
||||
return temp.map(item => item.url);
|
||||
}
|
||||
};
|
||||
const getPrintParamItem = (row: ANY_OBJECT, printParamList: ANY_OBJECT[]) => {
|
||||
let param;
|
||||
if (Array.isArray(printParamList)) {
|
||||
param = printParamList
|
||||
.map(item => {
|
||||
let columnId = item.paramValue;
|
||||
if (columnId != null) {
|
||||
let column = form().columnMap.get(columnId);
|
||||
let value;
|
||||
if (column == null) {
|
||||
value = row[item.paramValue];
|
||||
} else {
|
||||
value = (row.masterData || {})[column.columnName];
|
||||
}
|
||||
if (item.paramName != null && value != null) {
|
||||
return {
|
||||
paramName: item.paramName,
|
||||
paramValue: value,
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(item => item != null);
|
||||
}
|
||||
|
||||
return param;
|
||||
};
|
||||
const onPrint = (operation: ANY_OBJECT, row: ANY_OBJECT) => {
|
||||
if (operation == null || row == null || row.processDefinitionKey == null) return;
|
||||
let printParam;
|
||||
let temp = getPrintParamItem(row, operation.printParamList);
|
||||
printParam = temp ? [temp] : [];
|
||||
|
||||
let params = {
|
||||
printId: operation.printTemplateId,
|
||||
printParams: printParam,
|
||||
};
|
||||
post<string>(
|
||||
API_CONTEXT + '/flow/flowOnlineOperation/printWorkOrder/' + row.processDefinitionKey,
|
||||
params,
|
||||
)
|
||||
.then(res => {
|
||||
let downloadUrl = res.data;
|
||||
downloadBlob(downloadUrl, {})
|
||||
.then((blobData: Blob) => {
|
||||
let pdfUrl = window.URL.createObjectURL(blobData);
|
||||
window.open('./lib/pdfjs/web/viewer.html?file=' + pdfUrl);
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
ElMessage.error(e);
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
const formatListData = (data: ANY_OBJECT) => {
|
||||
Object.keys(data).forEach(key => {
|
||||
let subData = data[key];
|
||||
if (typeof subData === 'object' && key.indexOf('DictMap') === -1) {
|
||||
formatListData(subData);
|
||||
} else {
|
||||
// 如果是多选字典字段,那么把选中的字典值拼接成DictMap去显示
|
||||
if (key.indexOf('DictMapList') !== -1 && Array.isArray(data[key])) {
|
||||
let newKey = key.replace('DictMapList', 'DictMap');
|
||||
data[newKey] = {
|
||||
id: data[key.replace('DictMapList', '')],
|
||||
name: data[key].map((subItem: ANY_OBJECT) => subItem.name).join(', '),
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.dataList,
|
||||
newVal => {
|
||||
if (newVal) {
|
||||
newVal.forEach(item => {
|
||||
formatListData(item.masterData);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => tableColumnList.value,
|
||||
() => {
|
||||
refreshColumn();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
// watch(
|
||||
// () => props.widget,
|
||||
// newVal => {
|
||||
// if (newVal) {
|
||||
// newVal.widgetImpl = getCurrentInstance();
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// deep: true,
|
||||
// immediate: true,
|
||||
// },
|
||||
// );
|
||||
|
||||
watch(
|
||||
() => props.widget,
|
||||
() => {
|
||||
// if (newVal) {
|
||||
// newVal.widgetImpl = getCurrentInstance();
|
||||
// }
|
||||
refreshColumn();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -0,0 +1,264 @@
|
||||
<template>
|
||||
<el-collapse-item :title="attributeItem.name" class="attribute-collapse">
|
||||
<template #title>
|
||||
<el-row class="attribute-item-title">
|
||||
<span style="padding: 0 16px">{{ attributeItem.name }}</span>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-input
|
||||
v-if="inputWidgetType === SysCustomWidgetType.Input"
|
||||
size="default"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
v-model="valStr"
|
||||
@input="onValueChange"
|
||||
v-bind="attributeProps"
|
||||
@change="$emit('change')"
|
||||
/>
|
||||
<el-row v-if="inputWidgetType === SysCustomWidgetType.NumberInput" type="flex">
|
||||
<el-input-number
|
||||
size="default"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
controls-position="right"
|
||||
:min="attributeItem.min"
|
||||
:max="attributeItem.max"
|
||||
v-model="valNum"
|
||||
@input="onValueChange"
|
||||
v-bind="attributeProps"
|
||||
@change="$emit('change')"
|
||||
/>
|
||||
</el-row>
|
||||
<el-row v-if="inputWidgetType === SysCustomWidgetType.Radio" type="flex" align="middle">
|
||||
<el-radio-group
|
||||
size="default"
|
||||
v-model="valNum"
|
||||
v-bind="attributeProps"
|
||||
@change="onValueChange"
|
||||
>
|
||||
<el-radio-button v-for="item in dropdownData" :key="item.id" :value="item.id">
|
||||
{{ item.name }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-row>
|
||||
<el-slider
|
||||
v-if="inputWidgetType === SysCustomWidgetType.Slider"
|
||||
style="width: 95%; margin-left: 5px"
|
||||
size="default"
|
||||
:min="attributeItem.min"
|
||||
:max="attributeItem.max"
|
||||
v-model="valNum"
|
||||
@input="onValueChange"
|
||||
v-bind="attributeProps"
|
||||
@change="$emit('change')"
|
||||
/>
|
||||
<el-row v-if="inputWidgetType === SysCustomWidgetType.Switch" type="flex" align="middle">
|
||||
<el-select
|
||||
size="default"
|
||||
style="width: 100%"
|
||||
v-model="valBool"
|
||||
@input="onValueChange"
|
||||
v-bind="attributeProps"
|
||||
@change="$emit('change')"
|
||||
placeholder=""
|
||||
>
|
||||
<el-option label="是" :value="true" />
|
||||
<el-option label="否" :value="false" />
|
||||
</el-select>
|
||||
<!--
|
||||
<el-switch size="default"
|
||||
:value="value" @input="onValueChange"
|
||||
@change="$emit('change')"
|
||||
/>
|
||||
-->
|
||||
</el-row>
|
||||
<el-select
|
||||
v-if="inputWidgetType === SysCustomWidgetType.Select"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
size="default"
|
||||
v-model="valNum"
|
||||
v-bind="attributeProps"
|
||||
@change="onValueChange"
|
||||
placeholder=""
|
||||
>
|
||||
<el-option v-for="item in dropdownData" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
<el-color-picker
|
||||
v-if="inputWidgetType === SysCustomWidgetType.ColorPicker"
|
||||
size="default"
|
||||
v-model="valStr"
|
||||
@input="onValueChange"
|
||||
v-bind="attributeProps"
|
||||
@change="$emit('change')"
|
||||
/>
|
||||
<component
|
||||
v-if="attributeItem.customComponent"
|
||||
:is="components[attributeItem.customComponent.component]"
|
||||
style="width: 100%"
|
||||
v-bind="attributeProps"
|
||||
v-model:value="val"
|
||||
@input="onValueChange"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Arrayable } from 'element-plus/es/utils';
|
||||
import { findItemFromList } from '@/common/utils';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { SysCustomWidgetType } from '@/common/staticDict';
|
||||
import OnlineTableColumnSetting from '../components/OnlineTableColumnSetting/index.vue';
|
||||
import CustomWidgetDictSetting from '../components/CustomWidgetDictSetting/index.vue';
|
||||
import OnlineTabPanelSetting from '../components/OnlineTabPanelSetting/index.vue';
|
||||
import OnlineImageUrlInput from '../components/OnlineImageUrlInput.vue';
|
||||
|
||||
const components: ANY_OBJECT = {
|
||||
CustomWidgetDictSetting,
|
||||
OnlineTabPanelSetting,
|
||||
OnlineImageUrlInput,
|
||||
};
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:value': [string | number | Arrayable<number> | boolean | null | undefined];
|
||||
input: [string | number | Arrayable<number> | null | undefined];
|
||||
change: [];
|
||||
}>();
|
||||
const Props = defineProps<{
|
||||
value?: string | number | boolean | ANY_OBJECT;
|
||||
attributeItem: ANY_OBJECT;
|
||||
}>();
|
||||
|
||||
console.log('AttributeCollapse editWidgetAttribute.props', Props);
|
||||
|
||||
const formConfig = inject('formConfig', () => {
|
||||
console.error('editWidgetAttribute: formConfig not injected');
|
||||
return {} as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const dropdownData = ref<ANY_OBJECT[]>([]);
|
||||
const attributeProps = ref<ANY_OBJECT>({});
|
||||
|
||||
const val = computed({
|
||||
get() {
|
||||
return Props.value;
|
||||
},
|
||||
set(value) {
|
||||
console.log('val change', value);
|
||||
},
|
||||
});
|
||||
const valStr = computed({
|
||||
get() {
|
||||
return Props.value as string;
|
||||
},
|
||||
set(value) {
|
||||
console.log('val change str', value);
|
||||
},
|
||||
});
|
||||
const valBool = computed({
|
||||
get() {
|
||||
return Props.value as boolean;
|
||||
},
|
||||
set(value) {
|
||||
console.log('val change boolean', value);
|
||||
},
|
||||
});
|
||||
const valNum = computed({
|
||||
get() {
|
||||
return Props.value as number;
|
||||
},
|
||||
set(value) {
|
||||
console.log('val change number', value);
|
||||
},
|
||||
});
|
||||
const inputWidgetType = computed(() => {
|
||||
return Props.attributeItem.widgetType;
|
||||
});
|
||||
const currentWidget = computed(() => {
|
||||
return formConfig().currentWidget;
|
||||
});
|
||||
const isWidgetDictSelect = computed(() => {
|
||||
if (currentWidget.value == null) return false;
|
||||
let temp =
|
||||
[
|
||||
SysCustomWidgetType.Select,
|
||||
SysCustomWidgetType.Cascader,
|
||||
SysCustomWidgetType.Radio,
|
||||
SysCustomWidgetType.CheckBox,
|
||||
].indexOf(currentWidget.value.widgetType) !== -1;
|
||||
return temp && currentWidget.value && Props.attributeItem.attributeKey === 'dictId';
|
||||
});
|
||||
|
||||
const onValueChange = (val: string | number | Arrayable<number> | null | undefined) => {
|
||||
console.log('AttributeCollapse editWidgetAttribute.onValueChange', typeof val, val);
|
||||
if (isWidgetDictSelect.value) {
|
||||
currentWidget.value.dictInfo = findItemFromList(formConfig().dictList, val as string, 'id');
|
||||
}
|
||||
if (val && typeof val === 'object') {
|
||||
emit('input', (val as ANY_OBJECT).target?.value);
|
||||
} else {
|
||||
emit('input', val);
|
||||
}
|
||||
|
||||
if (Props.attributeItem.customComponent) emit('change');
|
||||
};
|
||||
const loadDropdownData = () => {
|
||||
dropdownData.value = [];
|
||||
if (typeof Props.attributeItem.dropdownList === 'function') {
|
||||
if (isWidgetDictSelect.value) {
|
||||
dropdownData.value = Props.attributeItem.dropdownList(formConfig());
|
||||
} else {
|
||||
dropdownData.value = Props.attributeItem.dropdownList();
|
||||
}
|
||||
} else {
|
||||
dropdownData.value = Array.isArray(Props.attributeItem.dropdownList)
|
||||
? Props.attributeItem.dropdownList
|
||||
: [];
|
||||
}
|
||||
if ((dropdownData.value || []).length === 1) onValueChange(dropdownData.value[0].id);
|
||||
};
|
||||
const getProps = () => {
|
||||
let props: ANY_OBJECT = {};
|
||||
if (Props.attributeItem.customComponent) {
|
||||
props = Props.attributeItem.customComponent.props || {};
|
||||
} else {
|
||||
props = Props.attributeItem.props || {};
|
||||
}
|
||||
props.disabled = Props.attributeItem.disabled || props.disabled;
|
||||
attributeProps.value = Object.keys(props).reduce((retObj: ANY_OBJECT, key: string) => {
|
||||
let value = props[key];
|
||||
if (typeof value === 'function') value = value(formConfig());
|
||||
retObj[key] = value;
|
||||
return retObj;
|
||||
}, {});
|
||||
console.log('>>> attributeProps', attributeProps.value);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => Props.attributeItem,
|
||||
() => {
|
||||
loadDropdownData();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => currentWidget.value,
|
||||
() => {
|
||||
loadDropdownData();
|
||||
getProps();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.attribute-collapse :deep(.el-textarea__inner) {
|
||||
min-height: 100px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<el-collapse style="border: none" :accordion="true" class="unified-font" :modelValue="undefined">
|
||||
<slot />
|
||||
<EditWidgetAttribute
|
||||
v-for="attributeItem in attributeList"
|
||||
:key="attributeItem.attributeKey"
|
||||
v-model:value="val[attributeItem.attributeKey]"
|
||||
:attributeItem="attributeItem"
|
||||
/>
|
||||
</el-collapse>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import EditWidgetAttribute from './editWidgetAttribute.vue';
|
||||
|
||||
const props = defineProps<{ widget: ANY_OBJECT; value?: ANY_OBJECT }>();
|
||||
const formConfig = inject('formConfig', () => {
|
||||
console.error('AttributeCollapse: formConfig not injected');
|
||||
return {} as ANY_OBJECT;
|
||||
});
|
||||
const attributeList = ref<ANY_OBJECT[]>([]);
|
||||
|
||||
const val = computed<ANY_OBJECT>({
|
||||
get() {
|
||||
console.log('AttributeCollapse value', props.value, currentWidget.value.props);
|
||||
//return props.value || {};
|
||||
return currentWidget.value.props || {};
|
||||
},
|
||||
set(val) {
|
||||
console.log('AttributeCollapse value change', val);
|
||||
},
|
||||
});
|
||||
const currentWidget = computed(() => {
|
||||
return formConfig().currentWidget || {};
|
||||
});
|
||||
const getWidgetAttributeConfig = computed(() => {
|
||||
// props.widget的变化滞后
|
||||
// console.log(
|
||||
// 'AttributeCollapse getWidgetAttributeConfig widget',
|
||||
// props.widget,
|
||||
// currentWidget.value,
|
||||
// );
|
||||
return (formConfig().getWidgetAttribute(currentWidget.value.widgetType) || {}).attribute;
|
||||
});
|
||||
const getAttributeItemValue = (attributeItem: ANY_OBJECT) => {
|
||||
if (typeof attributeItem === 'function') {
|
||||
return attributeItem(formConfig());
|
||||
} else {
|
||||
return attributeItem;
|
||||
}
|
||||
};
|
||||
const buildAttributeList = () => {
|
||||
const values: ANY_OBJECT[] = [];
|
||||
const config: ANY_OBJECT = getWidgetAttributeConfig.value;
|
||||
console.log('AttributeCollapse getWidgetAttributeConfig', config);
|
||||
if (config) {
|
||||
Object.keys(config).forEach(attributeKey => {
|
||||
let attributeItem = config[attributeKey];
|
||||
if (attributeItem != null) {
|
||||
let temp = Object.keys(attributeItem).reduce(
|
||||
(retObj: ANY_OBJECT, subKey: string) => {
|
||||
retObj[subKey] = getAttributeItemValue(attributeItem[subKey]);
|
||||
return retObj;
|
||||
},
|
||||
{
|
||||
attributeKey: attributeKey,
|
||||
},
|
||||
);
|
||||
if (temp.visible == null || temp.visible) values.push(temp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
attributeList.value = values;
|
||||
console.log('AttributeCollapse attributeList', attributeList);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => currentWidget.value,
|
||||
() => {
|
||||
console.log('AttributeCollapse watch widget props', currentWidget.value, {
|
||||
...currentWidget.value,
|
||||
});
|
||||
buildAttributeList();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -0,0 +1,270 @@
|
||||
<template>
|
||||
<el-form-item :label="attributeItem.name" class="widget-attribute-item">
|
||||
<el-input
|
||||
v-if="inputWidgetType === SysCustomWidgetType.Input"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
v-model="valStr"
|
||||
@input="onValueChange"
|
||||
v-bind="attributeProps"
|
||||
@change="$emit('change')"
|
||||
/>
|
||||
<el-row v-if="inputWidgetType === SysCustomWidgetType.NumberInput">
|
||||
<el-input-number
|
||||
clearable
|
||||
style="width: 100%"
|
||||
controls-position="right"
|
||||
:min="attributeItem.min"
|
||||
:max="attributeItem.max"
|
||||
v-model="valNum"
|
||||
@input="onValueChange"
|
||||
v-bind="attributeProps"
|
||||
@change="$emit('change')"
|
||||
/>
|
||||
</el-row>
|
||||
<el-row v-if="inputWidgetType === SysCustomWidgetType.Radio" align="middle">
|
||||
<el-radio-group
|
||||
size="default"
|
||||
v-model="valStr"
|
||||
v-bind="attributeProps"
|
||||
@change="onValueChange"
|
||||
>
|
||||
<el-radio-button v-for="item in dropdownData" :key="item.id" :value="item.id">{{
|
||||
item.name
|
||||
}}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-row>
|
||||
<el-slider
|
||||
v-if="inputWidgetType === SysCustomWidgetType.Slider"
|
||||
style="width: 95%; margin-left: 5px"
|
||||
:min="attributeItem.min"
|
||||
:max="attributeItem.max"
|
||||
v-model="valNum"
|
||||
@input="onValueChange"
|
||||
v-bind="attributeProps"
|
||||
/>
|
||||
<el-row v-if="inputWidgetType === SysCustomWidgetType.Switch" align="middle">
|
||||
<el-select
|
||||
style="width: 100%"
|
||||
v-model="valBool"
|
||||
v-bind="attributeProps"
|
||||
placeholder=""
|
||||
@change="onValueChange"
|
||||
>
|
||||
<el-option label="是" :value="true" />
|
||||
<el-option label="否" :value="false" />
|
||||
</el-select>
|
||||
<!--
|
||||
<el-switch
|
||||
:value="value" @input="onValueChange"
|
||||
/>
|
||||
-->
|
||||
</el-row>
|
||||
<el-select
|
||||
v-if="inputWidgetType === SysCustomWidgetType.Select"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
v-model="valNum"
|
||||
@input="onValueChange"
|
||||
v-bind="attributeProps"
|
||||
placeholder=""
|
||||
@change="onValueChange"
|
||||
>
|
||||
<el-option v-for="item in dropdownData" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
<el-color-picker
|
||||
v-if="inputWidgetType === SysCustomWidgetType.ColorPicker"
|
||||
size="default"
|
||||
v-model="valStr"
|
||||
v-bind="attributeProps"
|
||||
@change="onValueChange"
|
||||
/>
|
||||
<component
|
||||
v-if="attributeItem.customComponent"
|
||||
:is="components[attributeItem.customComponent.component]"
|
||||
style="width: 100%"
|
||||
v-bind="attributeProps"
|
||||
v-model:value="val"
|
||||
@change="onValueChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Arrayable } from 'element-plus/es/utils';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { findItemFromList } from '@/common/utils';
|
||||
import { SysCustomWidgetType } from '@/common/staticDict/index';
|
||||
import OnlineTableColumnSetting from '../components/OnlineTableColumnSetting/index.vue';
|
||||
import CustomWidgetDictSetting from '../components/CustomWidgetDictSetting/index.vue';
|
||||
import OnlineTabPanelSetting from '../components/OnlineTabPanelSetting/index.vue';
|
||||
import OnlineImageUrlInput from '../components/OnlineImageUrlInput.vue';
|
||||
|
||||
const components: ANY_OBJECT = {
|
||||
OnlineTableColumnSetting,
|
||||
CustomWidgetDictSetting,
|
||||
OnlineTabPanelSetting,
|
||||
OnlineImageUrlInput,
|
||||
};
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:value': [ANY_OBJECT | string | number | Arrayable<number> | boolean | null | undefined];
|
||||
input: [ANY_OBJECT | string | number | Arrayable<number> | boolean | null | undefined];
|
||||
change: [];
|
||||
}>();
|
||||
const props = defineProps<{
|
||||
value?: string | number | Arrayable<number> | boolean | ANY_OBJECT | null;
|
||||
attributeItem: ANY_OBJECT;
|
||||
}>();
|
||||
console.log('>>> >>> attributeItem', props.attributeItem);
|
||||
const formConfig = inject('formConfig', () => {
|
||||
console.error('editWidgetAttribute: formConfig not injected');
|
||||
return {} as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const dropdownData = ref<ANY_OBJECT[]>([]);
|
||||
const attributeProps = ref<ANY_OBJECT>({});
|
||||
|
||||
const val = computed({
|
||||
get() {
|
||||
console.log('get val', props.value);
|
||||
return props.value;
|
||||
},
|
||||
set(value) {
|
||||
console.log('val change', value);
|
||||
onValueChange(value);
|
||||
},
|
||||
});
|
||||
const valStr = computed({
|
||||
get() {
|
||||
console.log('get val as string', props.value);
|
||||
return props.value as string;
|
||||
},
|
||||
set(value) {
|
||||
console.log('val change str', value);
|
||||
onValueChange(value);
|
||||
},
|
||||
});
|
||||
const valBool = computed({
|
||||
get() {
|
||||
console.log('get val as boolean', props.value, typeof props.value);
|
||||
return props.value as boolean;
|
||||
},
|
||||
set(value) {
|
||||
console.log('val change boolean', value);
|
||||
onValueChange(value);
|
||||
},
|
||||
});
|
||||
const valNum = computed({
|
||||
get() {
|
||||
console.log('get val as number', props.value);
|
||||
return props.value as number;
|
||||
},
|
||||
set(value) {
|
||||
console.log('val change number', value);
|
||||
onValueChange(value);
|
||||
},
|
||||
});
|
||||
|
||||
const currentWidget = computed(() => {
|
||||
return formConfig().currentWidget;
|
||||
});
|
||||
const inputWidgetType = computed(() => {
|
||||
return props.attributeItem.widgetType;
|
||||
});
|
||||
const isWidgetDictSelect = computed(() => {
|
||||
if (currentWidget.value == null) return false;
|
||||
let temp =
|
||||
[
|
||||
SysCustomWidgetType.Select,
|
||||
SysCustomWidgetType.Cascader,
|
||||
SysCustomWidgetType.Radio,
|
||||
SysCustomWidgetType.CheckBox,
|
||||
].indexOf(currentWidget.value.widgetType) !== -1;
|
||||
return temp && currentWidget.value && props.attributeItem.attributeKey === 'dictId';
|
||||
});
|
||||
|
||||
const onValueChange = (
|
||||
val: string | number | Arrayable<number> | boolean | ANY_OBJECT | null | undefined,
|
||||
) => {
|
||||
if (isWidgetDictSelect.value) {
|
||||
console.log('isWidgetDictSelect', isWidgetDictSelect.value);
|
||||
currentWidget.value.dictInfo = findItemFromList(formConfig().dictList, val as string, 'id');
|
||||
console.log('currentWidget.dictInfo', currentWidget.value.dictInfo);
|
||||
}
|
||||
console.log('onValueChange val', val, typeof val);
|
||||
//emit('input', val);
|
||||
emit('update:value', val);
|
||||
if (props.attributeItem.customComponent) emit('change');
|
||||
};
|
||||
const loadDropdownData = () => {
|
||||
dropdownData.value = [];
|
||||
if (typeof props.attributeItem.dropdownList === 'function') {
|
||||
if (isWidgetDictSelect.value) {
|
||||
dropdownData.value = props.attributeItem.dropdownList(formConfig());
|
||||
} else {
|
||||
dropdownData.value = props.attributeItem.dropdownList();
|
||||
}
|
||||
} else {
|
||||
dropdownData.value = Array.isArray(props.attributeItem.dropdownList)
|
||||
? props.attributeItem.dropdownList
|
||||
: [];
|
||||
}
|
||||
//console.log('dropdownData', dropdownData.value);
|
||||
if ((dropdownData.value || []).length === 1) onValueChange(dropdownData.value[0].id);
|
||||
};
|
||||
const getProps = () => {
|
||||
let pps: ANY_OBJECT = {};
|
||||
if (props.attributeItem.customComponent) {
|
||||
pps = props.attributeItem.customComponent.props || {};
|
||||
} else {
|
||||
pps = props.attributeItem.props || {};
|
||||
}
|
||||
pps.disabled = props.attributeItem.disabled || pps.disabled;
|
||||
attributeProps.value = Object.keys(pps).reduce((retObj: ANY_OBJECT, key: string) => {
|
||||
let value = pps[key];
|
||||
if (typeof value === 'function') value = value(formConfig());
|
||||
retObj[key] = value;
|
||||
return retObj;
|
||||
}, {});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
console.log('..........', props.value);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.attributeItem,
|
||||
() => {
|
||||
loadDropdownData();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => currentWidget.value,
|
||||
() => {
|
||||
loadDropdownData();
|
||||
getProps();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.widget-attribute-item :deep(.el-textarea__inner) {
|
||||
min-height: 100px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<el-form
|
||||
class="custom-widget-attribute"
|
||||
label-position="top"
|
||||
label-width="115px"
|
||||
size="default"
|
||||
@submit.prevent
|
||||
>
|
||||
<EditWidgetAttribute
|
||||
v-for="attributeItem in attributeList"
|
||||
:key="attributeItem.attributeKey"
|
||||
v-model:value="modelValue[attributeItem.attributeKey]"
|
||||
:attributeItem="attributeItem"
|
||||
/>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import EditWidgetAttribute from './editWidgetAttribute.vue';
|
||||
|
||||
const emit = defineEmits<{ 'update:value': [ANY_OBJECT] }>();
|
||||
const props = defineProps<{ value: ANY_OBJECT }>();
|
||||
|
||||
const formConfig = inject('formConfig', () => {
|
||||
console.error('AttributeForm: formConfig not injected');
|
||||
return {} as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const attributeList = ref<ANY_OBJECT[]>([]);
|
||||
const modelValue = computed({
|
||||
get() {
|
||||
return props.value || {};
|
||||
},
|
||||
set(val) {
|
||||
console.log('AttributeForm value change', val);
|
||||
emit('update:value', props.value);
|
||||
},
|
||||
});
|
||||
const currentWidget = computed(() => {
|
||||
return formConfig().currentWidget;
|
||||
});
|
||||
const getWidgetAttributeConfig = computed(() => {
|
||||
return (formConfig().getWidgetAttribute(currentWidget.value?.widgetType) || {}).attribute;
|
||||
});
|
||||
|
||||
const getAttributeItemValue = (attributeItem: ANY_OBJECT) => {
|
||||
if (typeof attributeItem === 'function') {
|
||||
return attributeItem(formConfig());
|
||||
} else {
|
||||
return attributeItem;
|
||||
}
|
||||
};
|
||||
const buildAttributeList = () => {
|
||||
const list: ANY_OBJECT[] = [];
|
||||
if (getWidgetAttributeConfig.value != null) {
|
||||
Object.keys(getWidgetAttributeConfig.value).forEach(attributeKey => {
|
||||
let attributeItem = getWidgetAttributeConfig.value[attributeKey];
|
||||
if (attributeItem != null) {
|
||||
let temp = Object.keys(attributeItem).reduce(
|
||||
(retObj: ANY_OBJECT, subKey: string) => {
|
||||
retObj[subKey] = getAttributeItemValue(attributeItem[subKey]);
|
||||
return retObj;
|
||||
},
|
||||
{
|
||||
attributeKey: attributeKey,
|
||||
},
|
||||
);
|
||||
if (temp.visible == null || temp.visible) list.push(temp);
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log('AttributeForm attributeList', list);
|
||||
attributeList.value = list;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => currentWidget.value,
|
||||
() => {
|
||||
buildAttributeList();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<div class="form-single-fragment third-party-dlg" style="position: relative">
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="formData"
|
||||
class="full-width-input form-box"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
:size="formItemSize"
|
||||
label-position="right"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="参数名称" prop="dictParamName">
|
||||
<el-select v-model="formData.dictParamName" placeholder="" :disabled="rowData != null">
|
||||
<el-option
|
||||
v-for="item in dialogParams.paramList"
|
||||
:key="item.dictParamName"
|
||||
:label="item.dictParamName"
|
||||
:value="item.dictParamName"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="参数值类型" prop="dictValueType">
|
||||
<el-select
|
||||
class="input-item"
|
||||
v-model="formData.dictValueType"
|
||||
:clearable="true"
|
||||
placeholder="参数值类型"
|
||||
@change="onDictValueTypeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in SysOnlineParamValueType.getList()"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formData.dictValueType === SysOnlineParamValueType.TABLE_COLUMN">
|
||||
<el-form-item label="参数值" prop="dictValue">
|
||||
<el-select
|
||||
class="input-item"
|
||||
v-model="formData.dictValue"
|
||||
key="TABLE_COLUMN"
|
||||
:clearable="true"
|
||||
placeholder="参数值"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in dialogParams.columnList"
|
||||
:key="item.columnId"
|
||||
:label="item.objectFieldName"
|
||||
:value="item.columnId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formData.dictValueType === SysOnlineParamValueType.STATIC_DICT">
|
||||
<el-form-item label="参数值" prop="dictValue">
|
||||
<el-cascader
|
||||
v-model="formData.dictValue"
|
||||
:options="staticData as CascaderOption[]"
|
||||
:props="staticPops"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formData.dictValueType === SysOnlineParamValueType.INPUT_VALUE">
|
||||
<el-form-item label="参数值" prop="dictValue">
|
||||
<el-input v-model="formData.dictValue" placeholder="请输入参数值" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-row class="no-scroll menu-box" type="flex" justify="end" style="margin-top: 15px">
|
||||
<el-button :size="formItemSize" :plain="true" @click="onCancel"> 取消 </el-button>
|
||||
<el-button type="primary" :size="formItemSize" @click="onSubmit"> 保存 </el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CascaderOption, ElMessage } from 'element-plus';
|
||||
import combinedDict from '@/common/staticDict/combined';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { DialogProp } from '@/components/Dialog/types';
|
||||
import { SysOnlineParamValueType } from '@/common/staticDict/online';
|
||||
import { useThirdParty } from '@/components/thirdParty/hooks';
|
||||
import { ThirdProps } from '@/components/thirdParty/types';
|
||||
import { useLayoutStore } from '@/store';
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
interface IProps extends ThirdProps {
|
||||
rowData: ANY_OBJECT;
|
||||
paramList: ANY_OBJECT[];
|
||||
columnList: ANY_OBJECT[];
|
||||
// 当使用Dialog.show弹出组件时,须定义该prop属性,以便对dialog进行回调
|
||||
dialog?: DialogProp<ANY_OBJECT>;
|
||||
}
|
||||
|
||||
const StaticDict = { ...combinedDict };
|
||||
|
||||
const props = defineProps<IProps>();
|
||||
const formItemSize = computed(() => {
|
||||
return layoutStore.defaultFormItemSize || thirdParams.value.defaultFormItemSize?.value;
|
||||
});
|
||||
|
||||
const { thirdParams, onCloseThirdDialog } = useThirdParty(props);
|
||||
|
||||
const form = ref();
|
||||
const formData = ref<ANY_OBJECT>({
|
||||
dictParamName: undefined,
|
||||
dictValue: undefined,
|
||||
dictValueType: undefined,
|
||||
});
|
||||
const staticPops: ANY_OBJECT = {
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
};
|
||||
const staticData = ref<(ANY_OBJECT | undefined)[]>([]);
|
||||
const rules: ANY_OBJECT = {
|
||||
dictParamName: [{ required: true, message: '请选择参数', trigger: 'blur' }],
|
||||
dictValueType: [{ required: true, message: '请选择参数值类型', trigger: 'blur' }],
|
||||
dictValue: [{ required: true, message: '请选择参数值', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
const dialogParams = computed(() => {
|
||||
return {
|
||||
rowData: props.rowData || thirdParams.value.rowData,
|
||||
paramList: props.paramList || thirdParams.value.paramList,
|
||||
columnList: props.columnList || thirdParams.value.columnList,
|
||||
};
|
||||
});
|
||||
|
||||
const onCancel = () => {
|
||||
if (props.dialog) {
|
||||
props.dialog.cancel();
|
||||
} else {
|
||||
onCloseThirdDialog(false);
|
||||
}
|
||||
};
|
||||
const onSubmit = () => {
|
||||
form.value.validate((valid: boolean) => {
|
||||
if (!valid) return;
|
||||
if (
|
||||
formData.value.dictValueType === SysOnlineParamValueType.STATIC_DICT &&
|
||||
formData.value.dictValue.length !== 2
|
||||
) {
|
||||
ElMessage.error('静态字典类型的参数值必须选择静态字典的值!');
|
||||
return;
|
||||
}
|
||||
if (props.dialog) {
|
||||
props.dialog.submit(formData.value);
|
||||
} else {
|
||||
onCloseThirdDialog(true, dialogParams.value.rowData, formData.value);
|
||||
}
|
||||
});
|
||||
};
|
||||
const onDictValueTypeChange = () => {
|
||||
formData.value.dictValue = undefined;
|
||||
form.value.clearValidate();
|
||||
};
|
||||
const loadStaticData = () => {
|
||||
const dictList: ANY_OBJECT = StaticDict;
|
||||
staticData.value = Object.keys(dictList)
|
||||
.map((key: string) => {
|
||||
if (key === 'DictionaryBase') return undefined;
|
||||
let dictItem = dictList[key];
|
||||
return {
|
||||
id: key,
|
||||
name: dictItem.showName,
|
||||
children: dictItem.getList(),
|
||||
} as ANY_OBJECT;
|
||||
})
|
||||
.filter(item => !!item);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
formData.value = {
|
||||
...formData.value,
|
||||
...dialogParams.value.rowData,
|
||||
};
|
||||
loadStaticData();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,223 @@
|
||||
<template>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-select
|
||||
v-model="dictId"
|
||||
clearable
|
||||
placeholder=""
|
||||
style="width: 100%"
|
||||
@change="onDictChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in validDictList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col v-if="dictParamList && dictParamList.length > 0" :span="24" style="margin-top: 10px">
|
||||
<MultiItemBox
|
||||
:data="(value || {}).paramList"
|
||||
addText="添加字典过滤参数"
|
||||
:maxCount="dictParamList ? dictParamList.length : 0"
|
||||
@add="onEditDictParamValue()"
|
||||
@edit="onEditDictParamValue"
|
||||
@delete="onRemoveDictParamValue"
|
||||
:prop="{
|
||||
label: 'dictParamName',
|
||||
value: 'dictParamName',
|
||||
}"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import MultiItemBox from '@/components/MultiItemBox/index.vue';
|
||||
import { findItemFromList } from '@/common/utils';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import { SysCustomWidgetBindDataType, SysOnlineFormType } from '@/common/staticDict';
|
||||
import { SysOnlineColumnFilterType } from '@/common/staticDict/online';
|
||||
import EditDictParamValue from './editDictParamValue.vue';
|
||||
|
||||
const props = withDefaults(defineProps<{ value?: ANY_OBJECT }>(), {
|
||||
value: () => {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
|
||||
const formConfig = inject('formConfig', () => {
|
||||
console.error('CustomWidgetDictSetting: formConfig not injected');
|
||||
return {} as ANY_OBJECT;
|
||||
});
|
||||
console.log('>>> >>> dictSetting', formConfig());
|
||||
const validDictList = ref<ANY_OBJECT[]>([]);
|
||||
const currentWidget = computed(() => {
|
||||
return formConfig().currentWidget;
|
||||
});
|
||||
const allDictList = computed(() => {
|
||||
return formConfig().dictList;
|
||||
});
|
||||
const currentDictInfo = computed(() => {
|
||||
return findItemFromList(allDictList.value, props.value.dictId, 'id');
|
||||
});
|
||||
const dictParamList = computed(() => {
|
||||
return currentDictInfo.value ? (currentDictInfo.value.dictData || {}).paramList : undefined;
|
||||
});
|
||||
const dictId = computed({
|
||||
get() {
|
||||
return props.value.dictId;
|
||||
},
|
||||
set(val) {
|
||||
onDictChange(val);
|
||||
},
|
||||
});
|
||||
|
||||
const refreshData = (data: ANY_OBJECT) => {
|
||||
if (data.path === 'thirdEditDictParamValue' && data.isSuccess) {
|
||||
handlerEditOperate(data.rowData, data.data);
|
||||
}
|
||||
};
|
||||
defineExpose({ refreshData });
|
||||
|
||||
const onDictChange = (val: ANY_OBJECT) => {
|
||||
emitChange({
|
||||
dictId: val,
|
||||
paramList: [],
|
||||
});
|
||||
};
|
||||
const getValidDictList = () => {
|
||||
validDictList.value = [];
|
||||
if (currentWidget.value == null || !Array.isArray(allDictList.value)) return;
|
||||
if (currentWidget.value.bindData.dataType === SysCustomWidgetBindDataType.Column) {
|
||||
if (
|
||||
currentWidget.value.bindData.column != null &&
|
||||
currentWidget.value.bindData.column.dictId != null
|
||||
) {
|
||||
validDictList.value = (allDictList.value || []).filter(
|
||||
item => item.id === currentWidget.value.bindData.column.dictId,
|
||||
);
|
||||
}
|
||||
} else if (currentWidget.value.bindData.dataType === SysCustomWidgetBindDataType.Custom) {
|
||||
validDictList.value = allDictList.value;
|
||||
}
|
||||
};
|
||||
const emit = defineEmits<{ 'update:value': [ANY_OBJECT] }>();
|
||||
const emitChange = (info: ANY_OBJECT) => {
|
||||
nextTick(() => {
|
||||
emit('update:value', {
|
||||
...info,
|
||||
dict: findItemFromList(allDictList.value, (info || {}).dictId, 'id'),
|
||||
});
|
||||
});
|
||||
};
|
||||
const handlerEditOperate = (row: ANY_OBJECT | null, res: ANY_OBJECT) => {
|
||||
if (!row) {
|
||||
emitChange({
|
||||
dictId: props.value.dictId,
|
||||
paramList: [...props.value.paramList, res],
|
||||
});
|
||||
} else {
|
||||
emitChange({
|
||||
dictId: props.value.dictId,
|
||||
paramList: props.value.paramList.map((item: ANY_OBJECT) => {
|
||||
return item.dictParamName === row.dictParamName ? res : item;
|
||||
}),
|
||||
});
|
||||
}
|
||||
};
|
||||
const onEditDictParamValue = (row: ANY_OBJECT | null = null) => {
|
||||
let validParamList = (dictParamList.value || []).filter((item: ANY_OBJECT) => {
|
||||
let usedParamList = props.value.paramList;
|
||||
let temp = findItemFromList(usedParamList, item.dictParamName, 'dictParamName');
|
||||
return temp == null;
|
||||
});
|
||||
let columnList = [];
|
||||
// 报表表单从组件中获取数据,其他表单从数据源字段中获取数据
|
||||
if (formConfig().form.pageCode != null) {
|
||||
columnList = (formConfig().allWidgetList || []).map((widget: ANY_OBJECT) => {
|
||||
return {
|
||||
columnId: widget.widgetId,
|
||||
objectFieldName: widget.showName,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
columnList = formConfig().getMasterTable.columnList.filter((item: ANY_OBJECT) => {
|
||||
return (
|
||||
formConfig().form.formType !== SysOnlineFormType.QUERY ||
|
||||
item.filterType !== SysOnlineColumnFilterType.NONE
|
||||
);
|
||||
});
|
||||
}
|
||||
Dialog.show<ANY_OBJECT>(
|
||||
row ? '编辑参数' : '添加参数',
|
||||
EditDictParamValue,
|
||||
{
|
||||
area: '600px',
|
||||
},
|
||||
{
|
||||
rowData: row,
|
||||
paramList: validParamList,
|
||||
columnList: columnList,
|
||||
path: 'thirdEditDictParamValue',
|
||||
},
|
||||
{
|
||||
width: '600px',
|
||||
height: '400px',
|
||||
pathName: '/thirdParty/thirdEditDictParamValue',
|
||||
},
|
||||
)
|
||||
.then(res => {
|
||||
handlerEditOperate(row, res);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
const onRemoveDictParamValue = (row: ANY_OBJECT) => {
|
||||
ElMessageBox.confirm('是否删除此参数?', '', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
emitChange({
|
||||
dictId: props.value.dictId,
|
||||
paramList: props.value.paramList.filter(
|
||||
(item: ANY_OBJECT) => item.dictParamName !== row.dictParamName,
|
||||
),
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
|
||||
watch(
|
||||
() => currentWidget.value,
|
||||
() => {
|
||||
getValidDictList();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => validDictList.value,
|
||||
() => {
|
||||
if (validDictList.value.length === 1 && !props.value.dictId) {
|
||||
emitChange({
|
||||
dictId: validDictList.value[0].id,
|
||||
paramList: [],
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<el-form
|
||||
label-position="top"
|
||||
size="default"
|
||||
v-if="pagerSetting"
|
||||
style="padding: 10px 16px 0"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item class="view-attribute-item" label="是否显示">
|
||||
<el-switch v-model="pagerSetting.show" />
|
||||
</el-form-item>
|
||||
<el-form-item class="view-attribute-item" label="尺寸">
|
||||
<el-select v-model="pagerSetting.size" placeholder="">
|
||||
<el-option label="默认" value="default" />
|
||||
<el-option label="小" value="small" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="view-attribute-item" label="样式">
|
||||
<el-select v-model="pagerSetting.background" placeholder="">
|
||||
<el-option label="按钮" value="1" />
|
||||
<el-option label="文字" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="view-attribute-item" label="对齐方式">
|
||||
<el-radio-group v-model="pagerSetting.align">
|
||||
<el-radio-button value="left">居左</el-radio-button>
|
||||
<el-radio-button value="center">居中</el-radio-button>
|
||||
<el-radio-button value="right">居右</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const props = withDefaults(defineProps<{ fieldName?: string }>(), { fieldName: 'pagerSetting' });
|
||||
const formConfig = inject('formConfig', () => {
|
||||
console.error('PivotTableTotalSetting: formConfig not injected');
|
||||
return {} as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const widget = computed(() => {
|
||||
return formConfig().currentWidget;
|
||||
});
|
||||
const pagerSetting = computed(() => {
|
||||
let pps = (widget.value || {}).props;
|
||||
if (pps) {
|
||||
return pps[props.fieldName];
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<div class="form-single-fragment third-party-dlg" style="position: relative">
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="formData"
|
||||
class="full-width-input form-box"
|
||||
:rules="rules"
|
||||
style="width: 100%"
|
||||
label-width="100px"
|
||||
:size="formItemSize"
|
||||
label-position="right"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="字段数据表" prop="tableId">
|
||||
<el-select
|
||||
class="input-item"
|
||||
v-model="formData.tableId"
|
||||
:disabled="dialogParams.rowData != null"
|
||||
:clearable="true"
|
||||
placeholder="字段数据表"
|
||||
@change="onTableChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(table, index) in dialogParams.tableList"
|
||||
:key="table.tableId"
|
||||
:label="table.tableName"
|
||||
:value="table.tableId"
|
||||
>
|
||||
<el-row type="flex" justify="space-between" align="middle">
|
||||
<span>{{ table.tableName }}</span>
|
||||
<el-tag
|
||||
:type="table.relationType == null ? 'success' : 'primary'"
|
||||
style="margin-left: 30px"
|
||||
:size="formItemSize"
|
||||
effect="dark"
|
||||
>
|
||||
{{ table.relationType == null || index === 0 ? '主表' : '一对一关联' }}
|
||||
</el-tag>
|
||||
</el-row>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="绑定字段" prop="columnId">
|
||||
<el-select
|
||||
class="input-item"
|
||||
v-model="formData.columnId"
|
||||
:disabled="dialogParams.rowData != null"
|
||||
:clearable="true"
|
||||
placeholder="绑定字段"
|
||||
@change="onColumnChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="column in getTableColumnList"
|
||||
:key="column.columnId"
|
||||
:label="column.columnName"
|
||||
:value="column.columnId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="显示名" prop="showName">
|
||||
<el-input v-model="formData.showName" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-row class="no-scroll menu-box" type="flex" justify="end">
|
||||
<el-button type="primary" :size="formItemSize" :plain="true" @click="onCancel">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" :size="formItemSize" @click="onSubmit"> 保存 </el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { findItemFromList } from '@/common/utils';
|
||||
import { DialogProp } from '@/components/Dialog/types';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { useThirdParty } from '@/components/thirdParty/hooks';
|
||||
import { ThirdProps } from '@/components/thirdParty/types';
|
||||
import { useLayoutStore } from '@/store';
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
interface IProps extends ThirdProps {
|
||||
rowData?: ANY_OBJECT;
|
||||
tableList?: ANY_OBJECT[];
|
||||
usedColumnList?: ANY_OBJECT[];
|
||||
// 当使用Dialog.show弹出组件时,须定义该prop属性,以便对dialog进行回调
|
||||
dialog?: DialogProp<ANY_OBJECT>;
|
||||
}
|
||||
const props = defineProps<IProps>();
|
||||
const formItemSize = computed(() => {
|
||||
return layoutStore.defaultFormItemSize || thirdParams.value.defaultFormItemSize?.value;
|
||||
});
|
||||
|
||||
const { thirdParams, onCloseThirdDialog } = useThirdParty(props);
|
||||
|
||||
const form = ref();
|
||||
const formData = ref<ANY_OBJECT>({
|
||||
id: undefined,
|
||||
tableId: undefined,
|
||||
columnId: undefined,
|
||||
showName: undefined,
|
||||
});
|
||||
const oldColumnId = ref<string>();
|
||||
const rules: ANY_OBJECT = {
|
||||
showName: [{ required: true, message: '显示名不能为空', trigger: 'blur' }],
|
||||
tableId: [{ required: true, message: '数据表不能为空', trigger: 'blur' }],
|
||||
columnId: [{ required: true, message: '绑定字段不能为空', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
const dialogParams = computed(() => {
|
||||
return {
|
||||
rowData: props.rowData || thirdParams.value.rowData,
|
||||
tableList: props.tableList || thirdParams.value.tableList,
|
||||
usedColumnList: props.usedColumnList || thirdParams.value.usedColumnList || [],
|
||||
};
|
||||
});
|
||||
const getCurrentTable = computed(() => {
|
||||
return findItemFromList(dialogParams.value.tableList, formData.value.tableId, 'tableId');
|
||||
});
|
||||
const getTableColumnList = computed(() => {
|
||||
if (getCurrentTable.value != null) {
|
||||
return getCurrentTable.value.columnList.filter((item: ANY_OBJECT) => {
|
||||
return (
|
||||
dialogParams.value.usedColumnList.indexOf(item.columnId) === -1 ||
|
||||
oldColumnId.value === item.columnId
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
const onCancel = () => {
|
||||
if (props.dialog) {
|
||||
props.dialog.cancel();
|
||||
} else {
|
||||
onCloseThirdDialog(false);
|
||||
}
|
||||
};
|
||||
const onSubmit = () => {
|
||||
form.value.validate((valid: boolean) => {
|
||||
if (!valid) return;
|
||||
if (!valid) return;
|
||||
if (formData.value.id == null) formData.value.id = new Date().getTime();
|
||||
formData.value.relationId =
|
||||
(getCurrentTable.value || {}).relationType == null ? undefined : getCurrentTable.value?.id;
|
||||
if (props.dialog) {
|
||||
props.dialog?.submit(formData.value);
|
||||
} else {
|
||||
onCloseThirdDialog(true, dialogParams.value.rowData, formData.value);
|
||||
}
|
||||
});
|
||||
};
|
||||
const onTableChange = () => {
|
||||
formData.value.columnId = undefined;
|
||||
};
|
||||
const onColumnChange = () => {
|
||||
let column = findItemFromList(getTableColumnList.value, formData.value.columnId, 'columnId');
|
||||
formData.value.showName = column ? column.columnComment : undefined;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (dialogParams.value.rowData != null) {
|
||||
formData.value = {
|
||||
...formData.value,
|
||||
...dialogParams.value.rowData,
|
||||
};
|
||||
oldColumnId.value = formData.value.columnId;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<MultiItemBox
|
||||
:data="value"
|
||||
addText="添加排序字段"
|
||||
:supportSort="true"
|
||||
@add="onEditTableColumn()"
|
||||
@edit="onEditTableColumn"
|
||||
@delete="onRemoveTableColumn"
|
||||
:prop="{
|
||||
label: 'showName',
|
||||
value: 'id',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import MultiItemBox from '@/components/MultiItemBox/index.vue';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import { SysOnlineFormType } from '@/common/staticDict';
|
||||
import EditCustomListOrder from './editCustomListOrder.vue';
|
||||
|
||||
const emit = defineEmits<{ 'update:value': [ANY_OBJECT[]] }>();
|
||||
const props = withDefaults(defineProps<{ value: ANY_OBJECT[] }>(), {});
|
||||
const formConfig = inject('formConfig', () => {
|
||||
console.error('OnlineCustomListOrderSetting: formConfig not injected');
|
||||
return {} as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const handlerEditOperate = (row: ANY_OBJECT | null, res: ANY_OBJECT) => {
|
||||
let tempList: ANY_OBJECT[] = [];
|
||||
if (row == null) {
|
||||
tempList = props.value || [];
|
||||
tempList.push(res);
|
||||
} else {
|
||||
tempList = (props.value || []).map(item => {
|
||||
return item.columnId === res.id ? res : item;
|
||||
});
|
||||
}
|
||||
emit('update:value', tempList);
|
||||
};
|
||||
const onEditTableColumn = (row: ANY_OBJECT | null = null) => {
|
||||
let tableList = formConfig().getTableWidgetTableList;
|
||||
// 非查询页面只能从组件绑定的表中选择
|
||||
if (formConfig().form.formType !== SysOnlineFormType.QUERY) {
|
||||
tableList = (tableList || []).filter((table: ANY_OBJECT) => {
|
||||
return table.tableId === formConfig().currentWidget.bindData.tableId;
|
||||
});
|
||||
}
|
||||
Dialog.show<ANY_OBJECT>(
|
||||
row ? '编辑排序字段' : '添加排序字段',
|
||||
EditCustomListOrder,
|
||||
{
|
||||
area: '500px',
|
||||
},
|
||||
{
|
||||
rowData: row,
|
||||
tableList: tableList,
|
||||
usedColumnList: props.value.map(item => item.columnId),
|
||||
path: 'thirdEditOnlineListOrder',
|
||||
},
|
||||
{
|
||||
width: '500px',
|
||||
height: '500px',
|
||||
pathName: '/thirdParty/thirdEditOnlineListOrder',
|
||||
},
|
||||
)
|
||||
.then(res => {
|
||||
handlerEditOperate(row, res);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
const onRemoveTableColumn = (row: ANY_OBJECT) => {
|
||||
ElMessageBox.confirm('是否删除此排序字段?', '', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
emit(
|
||||
'update:value',
|
||||
(props.value || []).filter(item => item !== row),
|
||||
);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
|
||||
const refreshData = (data: ANY_OBJECT) => {
|
||||
if (data.path === 'thirdEditOnlineListOrder' && data.isSuccess) {
|
||||
handlerEditOperate(data.rowData, data.data);
|
||||
}
|
||||
};
|
||||
defineExpose({ refreshData });
|
||||
</script>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-input :value="value" :size="size" :disabled="disabled">
|
||||
<template #append>
|
||||
<el-button :icon="Upload" @click="onSelect" :disabled="disabled"> </el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<input
|
||||
type="file"
|
||||
ref="fileSelect"
|
||||
v-show="false"
|
||||
accept="image/*"
|
||||
@change.stop="onSelectImageChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Upload } from '@element-plus/icons-vue';
|
||||
import { useUpload } from '@/common/hooks/useUpload';
|
||||
import { API_CONTEXT } from '@/api/config';
|
||||
|
||||
const { getUploadActionUrl, fetchUpload } = useUpload();
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
value: string;
|
||||
size?: '' | 'default' | 'small' | 'large';
|
||||
disabled?: boolean;
|
||||
}>(),
|
||||
{
|
||||
size: 'small',
|
||||
disabled: false,
|
||||
},
|
||||
);
|
||||
|
||||
const fileSelect = ref();
|
||||
|
||||
const onSelect = () => {
|
||||
fileSelect.value.click();
|
||||
};
|
||||
const onSelectImageChange = (e: Event) => {
|
||||
const el = e.target as HTMLInputElement;
|
||||
if (el && el.files) {
|
||||
console.log('files', el.files);
|
||||
let file = el.files[0];
|
||||
if (file != null) {
|
||||
let uploadUrl = getUploadActionUrl(API_CONTEXT + '/commonext/util/uploadImage');
|
||||
fetchUpload(uploadUrl, {
|
||||
uploadFile: file,
|
||||
})
|
||||
.then(res => {
|
||||
//console.log('upload file', res);
|
||||
onValueChange(JSON.stringify(res));
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
console.warn(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const emit = defineEmits<{ 'update:value': [string] }>();
|
||||
const onValueChange = (val: string) => {
|
||||
//console.log('image url change', val);
|
||||
emit('update:value', val);
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div class="form-single-fragment third-party-dlg" style="position: relative">
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="formData"
|
||||
class="full-width-input form-box"
|
||||
:rules="rules"
|
||||
style="width: 100%"
|
||||
label-width="100px"
|
||||
:size="formItemSize"
|
||||
label-position="right"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item label="显示名称" prop="name">
|
||||
<el-input v-model="formData.name" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="最小值">
|
||||
<el-input v-model="formData.min" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="最大值">
|
||||
<el-input v-model="formData.max" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row class="no-scroll menu-box" type="flex" justify="end">
|
||||
<el-button type="primary" :size="formItemSize" :plain="true" @click="onCancel">
|
||||
取消
|
||||
</el-button>
|
||||
<el-button type="primary" :size="formItemSize" @click="onSubmit"> 保存 </el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DialogProp } from '@/components/Dialog/types';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { useThirdParty } from '@/components/thirdParty/hooks';
|
||||
import { ThirdProps } from '@/components/thirdParty/types';
|
||||
import { useLayoutStore } from '@/store';
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
interface IProps extends ThirdProps {
|
||||
rowData?: ANY_OBJECT;
|
||||
// 当使用Dialog.show弹出组件时,须定义该prop属性,以便对dialog进行回调
|
||||
dialog?: DialogProp<ANY_OBJECT>;
|
||||
}
|
||||
const props = defineProps<IProps>();
|
||||
const formItemSize = computed(() => {
|
||||
return layoutStore.defaultFormItemSize || thirdParams.value.defaultFormItemSize?.value;
|
||||
});
|
||||
|
||||
const { thirdParams, onCloseThirdDialog } = useThirdParty(props);
|
||||
|
||||
const form = ref();
|
||||
const formData = ref<ANY_OBJECT>({
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
});
|
||||
const rules: ANY_OBJECT = {
|
||||
name: [{ required: true, message: '请输入显示名称', trugger: 'change' }],
|
||||
};
|
||||
|
||||
const dialogParams = computed(() => {
|
||||
return {
|
||||
rowData: props.rowData || thirdParams.value.rowData,
|
||||
};
|
||||
});
|
||||
|
||||
const onCancel = () => {
|
||||
if (props.dialog) {
|
||||
props.dialog.cancel();
|
||||
} else {
|
||||
onCloseThirdDialog(false);
|
||||
}
|
||||
};
|
||||
const onSubmit = () => {
|
||||
form.value.validate((valid: boolean) => {
|
||||
if (!valid) return;
|
||||
// 生成唯一ID
|
||||
if (formData.value.id == null) formData.value.id = new Date().getTime();
|
||||
if (props.dialog) {
|
||||
props.dialog?.submit(formData.value);
|
||||
} else {
|
||||
onCloseThirdDialog(true, dialogParams.value.rowData, formData.value);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (dialogParams.value.rowData != null) {
|
||||
formData.value = {
|
||||
...formData.value,
|
||||
...dialogParams.value.rowData,
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<MultiItemBox
|
||||
:data="value"
|
||||
addText="添加快捷选项"
|
||||
:supportSort="true"
|
||||
@add="onEditTableColumn()"
|
||||
@edit="onEditTableColumn"
|
||||
@delete="onRemoveTableColumn"
|
||||
:prop="{
|
||||
label: 'name',
|
||||
value: 'id',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import MultiItemBox from '@/components/MultiItemBox/index.vue';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import EditNumberRangeQuick from './editNumberRangeQuick.vue';
|
||||
|
||||
const emit = defineEmits<{ 'update:value': [ANY_OBJECT[]] }>();
|
||||
const props = withDefaults(defineProps<{ value: ANY_OBJECT[] }>(), {});
|
||||
|
||||
const handlerEditOperate = (row: ANY_OBJECT | null, res: ANY_OBJECT) => {
|
||||
let tempList: ANY_OBJECT[] = [];
|
||||
if (row == null) {
|
||||
tempList = props.value || [];
|
||||
tempList.push(res);
|
||||
} else {
|
||||
tempList = (props.value || []).map(item => {
|
||||
return item.id === res.id ? res : item;
|
||||
});
|
||||
}
|
||||
emit('update:value', tempList);
|
||||
};
|
||||
const onEditTableColumn = (row: ANY_OBJECT | null = null) => {
|
||||
Dialog.show<ANY_OBJECT>(
|
||||
row ? '编辑快捷选项' : '添加快捷选项',
|
||||
EditNumberRangeQuick,
|
||||
{
|
||||
area: '500px',
|
||||
},
|
||||
{
|
||||
rowData: row,
|
||||
path: 'thirdEditOnlineMobileNumberRangeQuick',
|
||||
},
|
||||
{
|
||||
width: '500px',
|
||||
height: '500px',
|
||||
pathName: '/thirdParty/thirdEditOnlineMobileNumberRangeQuick',
|
||||
},
|
||||
)
|
||||
.then(res => {
|
||||
handlerEditOperate(row, res);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
const onRemoveTableColumn = (row: ANY_OBJECT) => {
|
||||
ElMessageBox.confirm('是否删除此快捷选项?', '', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
emit(
|
||||
'update:value',
|
||||
(props.value || []).filter(item => item !== row),
|
||||
);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
const refreshData = (data: ANY_OBJECT) => {
|
||||
if (data.path === 'thirdEditOnlineMobileNumberRangeQuick' && data.isSuccess) {
|
||||
handlerEditOperate(data.rowData, data.data);
|
||||
}
|
||||
};
|
||||
defineExpose({ refreshData });
|
||||
</script>
|
||||
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div class="form-single-fragment third-party-dlg" style="position: relative">
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="formData"
|
||||
class="full-width-input form-box"
|
||||
:rules="rules"
|
||||
style="width: 100%"
|
||||
label-width="100px"
|
||||
:size="formItemSize"
|
||||
label-position="right"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="标签显示名" prop="showName">
|
||||
<el-input v-model="formData.showName" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="标签标识" prop="variableName">
|
||||
<el-input v-model="formData.variableName" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-row class="no-scroll menu-box" type="flex" justify="end">
|
||||
<el-button :size="formItemSize" :plain="true" @click="onCancel"> 取消 </el-button>
|
||||
<el-button type="primary" :size="formItemSize" @click="onSubmit"> 保存 </el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DialogProp } from '@/components/Dialog/types';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { useThirdParty } from '@/components/thirdParty/hooks';
|
||||
import { ThirdProps } from '@/components/thirdParty/types';
|
||||
import { useLayoutStore } from '@/store';
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
interface IProps extends ThirdProps {
|
||||
rowData?: ANY_OBJECT;
|
||||
tabPanelList?: ANY_OBJECT[];
|
||||
// 当使用Dialog.show弹出组件时,须定义该prop属性,以便对dialog进行回调
|
||||
dialog?: DialogProp<ANY_OBJECT | ANY_OBJECT[] | undefined>;
|
||||
}
|
||||
const props = defineProps<IProps>();
|
||||
const formItemSize = computed(() => {
|
||||
return layoutStore.defaultFormItemSize || thirdParams.value.defaultFormItemSize?.value;
|
||||
});
|
||||
|
||||
const { thirdParams, onCloseThirdDialog } = useThirdParty(props);
|
||||
|
||||
const form = ref();
|
||||
const formData = ref<ANY_OBJECT>({
|
||||
showName: undefined,
|
||||
variableName: undefined,
|
||||
});
|
||||
|
||||
function func(param: ANY_OBJECT | null = null) {
|
||||
// empty
|
||||
}
|
||||
|
||||
const checkVarialeName = (rule: ANY_OBJECT | null, value: ANY_OBJECT, callback: typeof func) => {
|
||||
if (Array.isArray(dialogParams.value.tabPanelList)) {
|
||||
if (dialogParams.value.tabPanelList.indexOf(value) !== -1) {
|
||||
callback(new Error('标签页标识不能重复'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
const rules: ANY_OBJECT = {
|
||||
showName: [{ required: true, message: '标签页显示名不能为空', trigger: 'blur' }],
|
||||
variableName: [
|
||||
{ required: true, message: '标签页标识不能为空', trigger: 'blur' },
|
||||
{
|
||||
validator: checkVarialeName,
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const dialogParams = computed(() => {
|
||||
return {
|
||||
rowData: props.rowData || thirdParams.value.rowData,
|
||||
tabPanelList: props.tabPanelList || thirdParams.value.tabPanelList,
|
||||
};
|
||||
});
|
||||
|
||||
const onCancel = () => {
|
||||
if (props.dialog) {
|
||||
props.dialog.cancel();
|
||||
} else {
|
||||
onCloseThirdDialog(false);
|
||||
}
|
||||
};
|
||||
const onSubmit = () => {
|
||||
form.value.validate((valid: boolean) => {
|
||||
if (!valid) return;
|
||||
if (props.dialog) {
|
||||
props.dialog.submit(formData.value);
|
||||
} else {
|
||||
onCloseThirdDialog(true, dialogParams.value.rowData, formData.value);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (dialogParams.value.rowData != null) {
|
||||
formData.value = {
|
||||
...formData.value,
|
||||
...dialogParams.value.rowData,
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<MultiItemBox
|
||||
:data="(formConfig().currentWidget || {}).childWidgetList"
|
||||
addText="添加标签页"
|
||||
@add="onEditTabPanel()"
|
||||
@edit="onEditTabPanel"
|
||||
@delete="onRemoveTabPanel"
|
||||
:prop="{
|
||||
label: 'showName',
|
||||
value: 'variableName',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import MultiItemBox from '@/components/MultiItemBox/index.vue';
|
||||
import blockConfig from '@/online/config/customBlock';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import EditOnlineTabPanel from './editOnlineTabPanel.vue';
|
||||
|
||||
const formConfig = inject('formConfig', () => {
|
||||
console.error('editWidgetAttribute: formConfig not injected');
|
||||
return {} as ANY_OBJECT;
|
||||
});
|
||||
|
||||
// TODO refreshData
|
||||
|
||||
const handlerEditOperate = (row: ANY_OBJECT | null, res: ANY_OBJECT) => {
|
||||
if (row == null) {
|
||||
res = createTabPanel(res);
|
||||
formConfig().currentWidget.childWidgetList.push(res);
|
||||
} else {
|
||||
formConfig().currentWidget.childWidgetList = formConfig().currentWidget.childWidgetList.map(
|
||||
(item: ANY_OBJECT) => {
|
||||
return item.variableName === row.variableName ? res : item;
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
const onEditTabPanel = (row: ANY_OBJECT | null = null) => {
|
||||
Dialog.show<ANY_OBJECT>(
|
||||
row ? '编辑标签页' : '添加标签页',
|
||||
EditOnlineTabPanel,
|
||||
{
|
||||
area: '600px',
|
||||
},
|
||||
{
|
||||
rowData: row,
|
||||
tabPanelList: (formConfig().currentWidget.childWidgetList || [])
|
||||
.filter((item: ANY_OBJECT) => {
|
||||
return row != null ? item.variableName !== row.variableName : true;
|
||||
})
|
||||
.map((item: ANY_OBJECT) => item.variableName),
|
||||
path: 'thirdEditOnlineTabPanel',
|
||||
},
|
||||
{
|
||||
width: '600px',
|
||||
height: '500px',
|
||||
pathName: '/thirdParty/thirdEditOnlineTabPanel',
|
||||
},
|
||||
)
|
||||
.then(res => {
|
||||
handlerEditOperate(row, res);
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
};
|
||||
const onRemoveTabPanel = (row: ANY_OBJECT) => {
|
||||
ElMessageBox.confirm('是否删除此标签页?', '', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
formConfig().currentWidget.childWidgetList =
|
||||
formConfig().currentWidget.childWidgetList.filter((item: ANY_OBJECT) => {
|
||||
return item.variableName !== row.variableName;
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
const createTabPanel = (res: ANY_OBJECT) => {
|
||||
let temp = formConfig().getWidgetObject(blockConfig);
|
||||
temp.showName = res.showName;
|
||||
temp.variableName = res.variableName;
|
||||
temp.relation = undefined;
|
||||
temp.datasource = undefined;
|
||||
temp.column = undefined;
|
||||
|
||||
return temp;
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<div class="form-single-fragment third-party-dlg">
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="formData"
|
||||
class="full-width-input form-box"
|
||||
:rules="rules"
|
||||
style="width: 100%"
|
||||
label-width="100px"
|
||||
:size="formItemSize"
|
||||
label-position="right"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="绑定类型">
|
||||
<el-radio-group
|
||||
v-model="formData.fieldType"
|
||||
:disabled="dialogParams.rowData != null"
|
||||
@change="onBindTypeChange"
|
||||
>
|
||||
<el-radio-button :value="0">表字段</el-radio-button>
|
||||
<el-radio-button :value="1">自定义</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formData.fieldType === 1">
|
||||
<el-form-item label="字段名" prop="customFieldName">
|
||||
<el-input v-model="formData.customFieldName" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formData.fieldType === 0">
|
||||
<el-form-item label="字段数据表" prop="tableId">
|
||||
<el-select
|
||||
class="input-item"
|
||||
v-model="formData.tableId"
|
||||
:disabled="dialogParams.rowData != null"
|
||||
:clearable="true"
|
||||
placeholder="字段数据表"
|
||||
@change="onTableChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(table, index) in dialogParams.tableList"
|
||||
:key="table.tableId"
|
||||
:label="table.tableName"
|
||||
:value="table.tableId"
|
||||
>
|
||||
<el-row type="flex" justify="space-between" align="middle">
|
||||
<span>{{ table.tableName }}</span>
|
||||
<el-tag
|
||||
:type="table.relationType == null ? 'success' : 'primary'"
|
||||
style="margin-left: 30px"
|
||||
:size="formItemSize"
|
||||
effect="dark"
|
||||
>
|
||||
{{ table.relationType == null || index === 0 ? '主表' : '一对一关联' }}
|
||||
</el-tag>
|
||||
</el-row>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="formData.fieldType === 0">
|
||||
<el-form-item label="绑定列字段" prop="columnId">
|
||||
<el-select
|
||||
class="input-item"
|
||||
v-model="formData.columnId"
|
||||
:disabled="dialogParams.rowData != null"
|
||||
:clearable="true"
|
||||
placeholder="字段数据表"
|
||||
@change="onColumnChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="column in getTableColumnList"
|
||||
:key="column.columnId"
|
||||
:label="column.columnName"
|
||||
:value="column.columnId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="表格列名" prop="showName">
|
||||
<el-input
|
||||
class="input-item"
|
||||
v-model="formData.showName"
|
||||
:clearable="true"
|
||||
placeholder="表格列名"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="表格列宽">
|
||||
<el-input-number
|
||||
class="input-item"
|
||||
v-model="formData.columnWidth"
|
||||
placeholder="表格列宽"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="支持排序">
|
||||
<el-switch v-model="formData.sortable" :disabled="formData.fieldType == 1" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<el-row class="no-scroll menu-box" type="flex" justify="end">
|
||||
<el-button :size="formItemSize" :plain="true" @click="onCancel"> 取消 </el-button>
|
||||
<el-button type="primary" :size="formItemSize" @click="onSubmit"> 保存 </el-button>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { findItemFromList } from '@/common/utils';
|
||||
import { DialogProp } from '@/components/Dialog/types';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { useThirdParty } from '@/components/thirdParty/hooks';
|
||||
import { ThirdProps } from '@/components/thirdParty/types';
|
||||
import { useLayoutStore } from '@/store';
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
interface IProps extends ThirdProps {
|
||||
rowData?: ANY_OBJECT;
|
||||
tableList?: ANY_OBJECT[];
|
||||
usedColumnList?: ANY_OBJECT[];
|
||||
// 当使用Dialog.show弹出组件时,须定义该prop属性,以便对dialog进行回调
|
||||
dialog?: DialogProp<ANY_OBJECT>;
|
||||
}
|
||||
const props = defineProps<IProps>();
|
||||
const formItemSize = computed(() => {
|
||||
return layoutStore.defaultFormItemSize || thirdParams.value.defaultFormItemSize?.value;
|
||||
});
|
||||
|
||||
const { thirdParams, onCloseThirdDialog } = useThirdParty(props);
|
||||
|
||||
const form = ref();
|
||||
const formData = ref<ANY_OBJECT>({
|
||||
columnId: undefined,
|
||||
tableId: undefined,
|
||||
showName: undefined,
|
||||
sortable: false,
|
||||
columnWidth: undefined,
|
||||
fieldType: 0,
|
||||
customFieldName: undefined,
|
||||
});
|
||||
const oldColumnId = ref<string>();
|
||||
const rules: ANY_OBJECT = {
|
||||
showName: [{ required: true, message: '表格列名不能为空', trigger: 'blur' }],
|
||||
tableId: [{ required: true, message: '表格列绑定数据表不能为空', trigger: 'blur' }],
|
||||
columnId: [{ required: true, message: '表格列绑定字段不能为空', trigger: 'blur' }],
|
||||
customFieldName: [{ required: true, message: '自定义字段名不能为空', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
const dialogParams = computed(() => {
|
||||
return {
|
||||
rowData: props.rowData || thirdParams.value.rowData,
|
||||
tableList: props.tableList || thirdParams.value.tableList || [],
|
||||
usedColumnList: props.usedColumnList || thirdParams.value.usedColumnList || [],
|
||||
};
|
||||
});
|
||||
const getCurrentTable = computed(() => {
|
||||
return findItemFromList(dialogParams.value.tableList, formData.value.tableId, 'tableId');
|
||||
});
|
||||
const getTableColumnList = computed(() => {
|
||||
if (getCurrentTable.value != null) {
|
||||
return getCurrentTable.value.columnList.filter((item: ANY_OBJECT) => {
|
||||
return (
|
||||
dialogParams.value.usedColumnList.indexOf(item.columnId) === -1 ||
|
||||
oldColumnId.value === item.columnId
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
const onCancel = () => {
|
||||
if (props.dialog) {
|
||||
props.dialog.cancel();
|
||||
} else {
|
||||
onCloseThirdDialog(false);
|
||||
}
|
||||
};
|
||||
const onSubmit = () => {
|
||||
form.value.validate((valid: boolean) => {
|
||||
if (!valid) return;
|
||||
formData.value.table = getCurrentTable.value;
|
||||
formData.value.relationId =
|
||||
(getCurrentTable.value || {}).relationType == null ? undefined : getCurrentTable.value?.id;
|
||||
if (props.dialog) {
|
||||
props.dialog?.submit(formData.value);
|
||||
} else {
|
||||
onCloseThirdDialog(true, dialogParams.value.rowData, formData.value);
|
||||
}
|
||||
});
|
||||
};
|
||||
const onTableChange = () => {
|
||||
formData.value.columnId = undefined;
|
||||
};
|
||||
const onColumnChange = () => {
|
||||
formData.value.column = findItemFromList(
|
||||
getTableColumnList.value,
|
||||
formData.value.columnId,
|
||||
'columnId',
|
||||
);
|
||||
formData.value.showName = formData.value.column ? formData.value.column.columnComment : undefined;
|
||||
};
|
||||
const onBindTypeChange = () => {
|
||||
formData.value.customFieldName = undefined;
|
||||
formData.value.tableId = undefined;
|
||||
formData.value.columnId = undefined;
|
||||
formData.value.sortable = false;
|
||||
if (form.value) form.value.clearValidate();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (dialogParams.value.rowData != null) {
|
||||
formData.value = {
|
||||
...formData.value,
|
||||
...dialogParams.value.rowData,
|
||||
};
|
||||
oldColumnId.value = formData.value.columnId;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<MultiItemList
|
||||
:data="value"
|
||||
label="表格字段"
|
||||
:supportSort="true"
|
||||
@add="onEditTableColumn()"
|
||||
@edit="onEditTableColumn"
|
||||
@delete="onRemoveTableColumn"
|
||||
:prop="{
|
||||
label: 'showName',
|
||||
value: 'columnId',
|
||||
}"
|
||||
>
|
||||
</MultiItemList>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import MultiItemList from '@/components/MultiItemList/index.vue';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import { SysOnlineFormType } from '@/common/staticDict';
|
||||
import EditOnlineTableColumn from './editOnlineTableColumn.vue';
|
||||
|
||||
const emit = defineEmits<{ 'update:value': [ANY_OBJECT[]] }>();
|
||||
const props = withDefaults(defineProps<{ value: ANY_OBJECT[] }>(), {});
|
||||
const formConfig = inject('formConfig', () => {
|
||||
console.error('OnlineTableColumnSetting: formConfig not injected');
|
||||
return {} as ANY_OBJECT;
|
||||
});
|
||||
|
||||
const handlerEditOperate = (row: ANY_OBJECT | null, res: ANY_OBJECT) => {
|
||||
let tempList: ANY_OBJECT[] = [];
|
||||
if (row == null) {
|
||||
tempList = props.value || [];
|
||||
tempList.push(res);
|
||||
} else {
|
||||
tempList = (props.value || []).map(item => {
|
||||
return item.columnId === res.columnId ? res : item;
|
||||
});
|
||||
}
|
||||
emit('update:value', tempList);
|
||||
};
|
||||
const onEditTableColumn = (row: ANY_OBJECT | null = null) => {
|
||||
let tableList = formConfig().getTableWidgetTableList;
|
||||
// 非查询页面只能从组件绑定的表中选择
|
||||
if (formConfig().form.formType !== SysOnlineFormType.QUERY) {
|
||||
tableList = (tableList || []).filter((table: ANY_OBJECT) => {
|
||||
return table.tableId === formConfig().currentWidget.bindData.tableId;
|
||||
});
|
||||
}
|
||||
Dialog.show<ANY_OBJECT>(
|
||||
row ? '编辑字段' : '添加字段',
|
||||
EditOnlineTableColumn,
|
||||
{
|
||||
area: '600px',
|
||||
},
|
||||
{
|
||||
rowData: row,
|
||||
tableList: tableList,
|
||||
usedColumnList: props.value.map(item => item.columnId),
|
||||
|
||||
path: 'thirdEditOnlineTableColumn',
|
||||
},
|
||||
{
|
||||
width: '600px',
|
||||
height: '500px',
|
||||
pathName: '/thirdParty/thirdEditOnlineTableColumn',
|
||||
},
|
||||
)
|
||||
.then(res => {
|
||||
handlerEditOperate(row, res);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
const onRemoveTableColumn = (row: ANY_OBJECT) => {
|
||||
ElMessageBox.confirm('是否删除此表格列?', '', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
emit(
|
||||
'update:value',
|
||||
(props.value || []).filter(item => item !== row),
|
||||
);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
|
||||
const refreshData = (data: ANY_OBJECT) => {
|
||||
if (data.path === 'thirdEditOnlineTableColumn' && data.isSuccess) {
|
||||
handlerEditOperate(data.rowData, data.data);
|
||||
}
|
||||
};
|
||||
defineExpose({ refreshData });
|
||||
</script>
|
||||
52
OrangeFormsOpen-VUE3/src/online/components/hooks/widget.ts
Normal file
52
OrangeFormsOpen-VUE3/src/online/components/hooks/widget.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { WidgetProps, WidgetEmit } from '../types/widget';
|
||||
|
||||
export const useWidget = (props: WidgetProps, emit: WidgetEmit) => {
|
||||
const propsWidget = computed<ANY_OBJECT>({
|
||||
get() {
|
||||
return props.widget;
|
||||
},
|
||||
set(value: ANY_OBJECT) {
|
||||
console.log('widget change', value);
|
||||
emit('update:widget', value);
|
||||
},
|
||||
});
|
||||
const childWidgetList = computed<ANY_OBJECT[]>({
|
||||
get() {
|
||||
return props.widget.childWidgetList || [];
|
||||
},
|
||||
set(values: ANY_OBJECT[]) {
|
||||
console.log('childWidgetList change', values);
|
||||
const widget = props.widget;
|
||||
widget.childWidgetList = values;
|
||||
emit('update:widget', widget);
|
||||
},
|
||||
});
|
||||
|
||||
const onWidgetClick = (widget: ANY_OBJECT | null = null) => {
|
||||
emit('widgetClick', widget);
|
||||
};
|
||||
|
||||
const onDeleteWidget = (widget: ANY_OBJECT) => {
|
||||
ElMessageBox.confirm('是否删除此组件?', '', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
childWidgetList.value = childWidgetList.value.filter((item: ANY_OBJECT) => item !== widget);
|
||||
onWidgetClick(null);
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn(e);
|
||||
});
|
||||
};
|
||||
|
||||
const onCopyWidget = (widget: ANY_OBJECT) => {
|
||||
const childWidgetList = props.widget.childWidgetList;
|
||||
childWidgetList.push(widget);
|
||||
};
|
||||
|
||||
return { propsWidget, childWidgetList, onWidgetClick, onDeleteWidget, onCopyWidget };
|
||||
};
|
||||
11
OrangeFormsOpen-VUE3/src/online/components/types/widget.ts
Normal file
11
OrangeFormsOpen-VUE3/src/online/components/types/widget.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
export interface WidgetProps {
|
||||
widget: ANY_OBJECT;
|
||||
isEdit?: boolean;
|
||||
}
|
||||
|
||||
export interface WidgetEmit {
|
||||
(event: 'widgetClick', value: ANY_OBJECT | null): void;
|
||||
(event: 'update:widget', value: ANY_OBJECT | ANY_OBJECT[]): void;
|
||||
}
|
||||
54
OrangeFormsOpen-VUE3/src/online/config/baseCard.ts
Normal file
54
OrangeFormsOpen-VUE3/src/online/config/baseCard.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { SysCustomWidgetType, OnlineFormEventType } from '@/common/staticDict/index';
|
||||
|
||||
const card = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
shadow: {
|
||||
name: '阴影显示',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
value: 'never',
|
||||
dropdownList: [
|
||||
{
|
||||
id: 'never',
|
||||
name: '不显示',
|
||||
},
|
||||
{
|
||||
id: 'hover',
|
||||
name: '悬浮显示',
|
||||
},
|
||||
{
|
||||
id: 'always',
|
||||
name: '一直显示',
|
||||
},
|
||||
],
|
||||
},
|
||||
padding: {
|
||||
name: '内部边距',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 20,
|
||||
min: 0,
|
||||
},
|
||||
paddingBottom: {
|
||||
name: '底部距离',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 0,
|
||||
min: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const baseCardConfig = {
|
||||
widgetType: SysCustomWidgetType.Card,
|
||||
icon: 'online-icon icon-card3',
|
||||
attribute: card,
|
||||
allowEventList: [OnlineFormEventType.VISIBLE],
|
||||
operationList: [],
|
||||
supportBindTable: false,
|
||||
supportBindColumn: false,
|
||||
};
|
||||
|
||||
export default baseCardConfig;
|
||||
80
OrangeFormsOpen-VUE3/src/online/config/cascader.ts
Normal file
80
OrangeFormsOpen-VUE3/src/online/config/cascader.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const cascader = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
placeholder: {
|
||||
name: '占位文本',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
dictInfo: {
|
||||
name: '下拉字典',
|
||||
value: {},
|
||||
customComponent: {
|
||||
component: 'CustomWidgetDictSetting',
|
||||
},
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const cascaderConfig = {
|
||||
widgetType: SysCustomWidgetType.Cascader,
|
||||
icon: 'online-icon icon-cascader',
|
||||
attribute: cascader,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
OnlineFormEventType.DROPDOWN_CHANGE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default cascaderConfig;
|
||||
75
OrangeFormsOpen-VUE3/src/online/config/checkbox.ts
Normal file
75
OrangeFormsOpen-VUE3/src/online/config/checkbox.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const checkbox = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
dictInfo: {
|
||||
name: '下拉字典',
|
||||
value: {},
|
||||
customComponent: {
|
||||
component: 'CustomWidgetDictSetting',
|
||||
},
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const checkboxConfig = {
|
||||
widgetType: SysCustomWidgetType.CheckBox,
|
||||
icon: 'online-icon icon-checkbox',
|
||||
attribute: checkbox,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
OnlineFormEventType.DROPDOWN_CHANGE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default checkboxConfig;
|
||||
28
OrangeFormsOpen-VUE3/src/online/config/customBlock.ts
Normal file
28
OrangeFormsOpen-VUE3/src/online/config/customBlock.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { SysCustomWidgetType, OnlineFormEventType } from '@/common/staticDict/index';
|
||||
|
||||
const block = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
paddingBottom: {
|
||||
name: '底部距离',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 0,
|
||||
min: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const customBlockConfig = {
|
||||
widgetType: SysCustomWidgetType.Block,
|
||||
icon: 'online-icon icon-block',
|
||||
attribute: block,
|
||||
allowEventList: [OnlineFormEventType.VISIBLE],
|
||||
supportBindTable: false,
|
||||
supportBindColumn: false,
|
||||
};
|
||||
|
||||
export default customBlockConfig;
|
||||
100
OrangeFormsOpen-VUE3/src/online/config/date.ts
Normal file
100
OrangeFormsOpen-VUE3/src/online/config/date.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const date = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
placeholder: {
|
||||
name: '占位文本',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
type: {
|
||||
name: '显示类型',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
dropdownList: [
|
||||
{
|
||||
id: 'date',
|
||||
name: '日',
|
||||
},
|
||||
{
|
||||
id: 'week',
|
||||
name: '周',
|
||||
},
|
||||
{
|
||||
id: 'month',
|
||||
name: '月',
|
||||
},
|
||||
{
|
||||
id: 'year',
|
||||
name: '年',
|
||||
},
|
||||
{
|
||||
id: 'datetime',
|
||||
name: '时间',
|
||||
},
|
||||
],
|
||||
value: 'date',
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const dateConfig = {
|
||||
widgetType: SysCustomWidgetType.Date,
|
||||
icon: 'online-icon icon-date',
|
||||
attribute: date,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
OnlineFormEventType.DISABLED_DATE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default dateConfig;
|
||||
97
OrangeFormsOpen-VUE3/src/online/config/dateRange.ts
Normal file
97
OrangeFormsOpen-VUE3/src/online/config/dateRange.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const dateRange = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
'start-placeholder': {
|
||||
name: '开始日期提示',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
'end-placeholder': {
|
||||
name: '结束日期提示',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
type: {
|
||||
name: '显示类型',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
dropdownList: [
|
||||
{
|
||||
id: 'daterange',
|
||||
name: '日',
|
||||
},
|
||||
{
|
||||
id: 'monthrange',
|
||||
name: '月',
|
||||
},
|
||||
{
|
||||
id: 'datetimerange',
|
||||
name: '时间',
|
||||
},
|
||||
],
|
||||
value: 'daterange',
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const dateRangeConfig = {
|
||||
widgetType: SysCustomWidgetType.DateRange,
|
||||
icon: 'online-icon icon-date-range',
|
||||
attribute: dateRange,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
OnlineFormEventType.DISABLED_DATE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default dateRangeConfig;
|
||||
72
OrangeFormsOpen-VUE3/src/online/config/deptSelect.ts
Normal file
72
OrangeFormsOpen-VUE3/src/online/config/deptSelect.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const deptSelect = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
placeholder: {
|
||||
name: '占位文本',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const deptSelectConfig = {
|
||||
widgetType: SysCustomWidgetType.DeptSelect,
|
||||
icon: 'online-icon icon-dept',
|
||||
attribute: deptSelect,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default deptSelectConfig;
|
||||
118
OrangeFormsOpen-VUE3/src/online/config/image.ts
Normal file
118
OrangeFormsOpen-VUE3/src/online/config/image.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
OnlineFormEventType,
|
||||
SysCustomWidgetBindDataType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const image = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
fit: {
|
||||
name: '裁切方式',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
value: 'fill',
|
||||
dropdownList: [
|
||||
{
|
||||
id: 'fill',
|
||||
name: 'fill',
|
||||
},
|
||||
{
|
||||
id: 'contain',
|
||||
name: 'contain',
|
||||
},
|
||||
{
|
||||
id: 'cover',
|
||||
name: 'cover',
|
||||
},
|
||||
{
|
||||
id: 'none',
|
||||
name: 'none',
|
||||
},
|
||||
{
|
||||
id: 'scale-down',
|
||||
name: 'scale-down',
|
||||
},
|
||||
],
|
||||
},
|
||||
align: {
|
||||
name: '图片位置',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
value: 'start',
|
||||
dropdownList: [
|
||||
{
|
||||
id: 'start',
|
||||
name: '左侧',
|
||||
},
|
||||
{
|
||||
id: 'center',
|
||||
name: '居中',
|
||||
},
|
||||
{
|
||||
id: 'end',
|
||||
name: '右侧',
|
||||
},
|
||||
],
|
||||
},
|
||||
width: {
|
||||
name: '图片宽度',
|
||||
value: '100px',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
},
|
||||
height: {
|
||||
name: '图片高度',
|
||||
value: '100px',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
},
|
||||
radius: {
|
||||
name: '圆角宽度',
|
||||
value: 3,
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
min: 0,
|
||||
},
|
||||
round: {
|
||||
name: '圆形图片',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
},
|
||||
src: {
|
||||
name: '图片地址',
|
||||
value: '',
|
||||
customComponent: {
|
||||
component: 'OnlineImageUrlInput',
|
||||
props: {
|
||||
disabled: function (formConfig: ANY_OBJECT) {
|
||||
// 表单为非报表,并且绑定在字段上,那么图片不可输入
|
||||
return (
|
||||
formConfig &&
|
||||
formConfig.currentWidget &&
|
||||
formConfig.currentWidget.bindData?.dataType !== SysCustomWidgetBindDataType.Fixed &&
|
||||
formConfig.form?.pageCode == null
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
paddingBottom: {
|
||||
name: '底部距离',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 0,
|
||||
min: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const imageConfig = {
|
||||
widgetType: SysCustomWidgetType.Image,
|
||||
icon: 'online-icon icon-image',
|
||||
attribute: image,
|
||||
allowEventList: [OnlineFormEventType.VISIBLE],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default imageConfig;
|
||||
282
OrangeFormsOpen-VUE3/src/online/config/index.ts
Normal file
282
OrangeFormsOpen-VUE3/src/online/config/index.ts
Normal file
@@ -0,0 +1,282 @@
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { SysCustomWidgetType } from '@/common/staticDict/index';
|
||||
import blockConfig from './customBlock';
|
||||
import baseCardConfig from './baseCard';
|
||||
import tabsConfig from './tabs';
|
||||
import textConfig from './text';
|
||||
import imageConfig from './image';
|
||||
import labelConfig from './label';
|
||||
import inputConfig from './input';
|
||||
import numberInputConfig from './numberInput';
|
||||
import numberRangeConfig from './numberRange';
|
||||
import switchConfig from './switch';
|
||||
import radioConfig from './radio';
|
||||
import checkboxConfig from './checkbox';
|
||||
import selectConfig from './select';
|
||||
import cascaderConfig from './cascader';
|
||||
import dateConfig from './date';
|
||||
import dateRangeConfig from './dateRange';
|
||||
import userSelectConfig from './userSelect';
|
||||
import deptSelectConfig from './deptSelect';
|
||||
import uploadConfig from './upload';
|
||||
import richEditorConfig from './richEditor';
|
||||
import tableConfig from './table';
|
||||
import linkConfig from './link';
|
||||
import treeConfig from './tree';
|
||||
|
||||
const formWidgetGroupList: ANY_OBJECT = {
|
||||
pc: [
|
||||
{
|
||||
id: 'layout',
|
||||
groupName: '布局组件',
|
||||
widgetList: [blockConfig, baseCardConfig, tabsConfig, textConfig, imageConfig],
|
||||
},
|
||||
{
|
||||
id: 'filter',
|
||||
groupName: '过滤组件',
|
||||
widgetList: [
|
||||
labelConfig,
|
||||
inputConfig,
|
||||
numberInputConfig,
|
||||
numberRangeConfig,
|
||||
switchConfig,
|
||||
radioConfig,
|
||||
checkboxConfig,
|
||||
selectConfig,
|
||||
cascaderConfig,
|
||||
dateConfig,
|
||||
dateRangeConfig,
|
||||
userSelectConfig,
|
||||
deptSelectConfig,
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'base',
|
||||
groupName: '基础组件',
|
||||
widgetList: [
|
||||
labelConfig,
|
||||
inputConfig,
|
||||
numberInputConfig,
|
||||
numberRangeConfig,
|
||||
switchConfig,
|
||||
radioConfig,
|
||||
checkboxConfig,
|
||||
selectConfig,
|
||||
cascaderConfig,
|
||||
dateConfig,
|
||||
dateRangeConfig,
|
||||
uploadConfig,
|
||||
richEditorConfig,
|
||||
tableConfig,
|
||||
linkConfig,
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'advance',
|
||||
groupName: '高级组件',
|
||||
widgetList: [userSelectConfig, deptSelectConfig],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function getDefaultVariableName(widgetType: number) {
|
||||
const tempTime = new Date().getTime();
|
||||
switch (widgetType) {
|
||||
case SysCustomWidgetType.Label:
|
||||
return 'label' + tempTime;
|
||||
case SysCustomWidgetType.Input:
|
||||
return 'input' + tempTime;
|
||||
case SysCustomWidgetType.NumberInput:
|
||||
return 'numberInput' + tempTime;
|
||||
case SysCustomWidgetType.NumberRange:
|
||||
return 'numberRange' + tempTime;
|
||||
case SysCustomWidgetType.Switch:
|
||||
return 'switch' + tempTime;
|
||||
case SysCustomWidgetType.Slider:
|
||||
return 'slider' + tempTime;
|
||||
case SysCustomWidgetType.Radio:
|
||||
return 'radio' + tempTime;
|
||||
case SysCustomWidgetType.CheckBox:
|
||||
return 'checkBox' + tempTime;
|
||||
case SysCustomWidgetType.Select:
|
||||
return 'select' + tempTime;
|
||||
case SysCustomWidgetType.Cascader:
|
||||
return 'cascader' + tempTime;
|
||||
case SysCustomWidgetType.Date:
|
||||
return 'date' + tempTime;
|
||||
case SysCustomWidgetType.DateRange:
|
||||
return 'dateRange' + tempTime;
|
||||
case SysCustomWidgetType.Upload:
|
||||
return 'upload' + tempTime;
|
||||
case SysCustomWidgetType.RichEditor:
|
||||
return 'richEditor' + tempTime;
|
||||
case SysCustomWidgetType.Divider:
|
||||
return 'divider' + tempTime;
|
||||
case SysCustomWidgetType.Text:
|
||||
return 'text' + tempTime;
|
||||
case SysCustomWidgetType.Image:
|
||||
return 'image' + tempTime;
|
||||
case SysCustomWidgetType.ImageCard:
|
||||
return 'imageCard' + tempTime;
|
||||
case SysCustomWidgetType.Table:
|
||||
return 'table' + tempTime;
|
||||
case SysCustomWidgetType.PivotTable:
|
||||
return 'pivotTable' + tempTime;
|
||||
case SysCustomWidgetType.LineChart:
|
||||
return 'lineChart' + tempTime;
|
||||
case SysCustomWidgetType.BarChart:
|
||||
return 'barChart' + tempTime;
|
||||
case SysCustomWidgetType.PieChart:
|
||||
return 'pieChart' + tempTime;
|
||||
case SysCustomWidgetType.ScatterChart:
|
||||
return 'scatterChart' + tempTime;
|
||||
case SysCustomWidgetType.Block:
|
||||
return 'block' + tempTime;
|
||||
case SysCustomWidgetType.Link:
|
||||
return 'link' + tempTime;
|
||||
case SysCustomWidgetType.UserSelect:
|
||||
return 'userSelect' + tempTime;
|
||||
case SysCustomWidgetType.DeptSelect:
|
||||
return 'deptSelect' + tempTime;
|
||||
case SysCustomWidgetType.DataSelect:
|
||||
return 'dataSelect' + tempTime;
|
||||
case SysCustomWidgetType.Card:
|
||||
return 'baseCard' + tempTime;
|
||||
case SysCustomWidgetType.Tabs:
|
||||
return 'tabs' + tempTime;
|
||||
case SysCustomWidgetType.Tree:
|
||||
return 'tree' + tempTime;
|
||||
case SysCustomWidgetType.TableContainer:
|
||||
return 'tableContainer' + tempTime;
|
||||
case SysCustomWidgetType.List:
|
||||
return 'baseList' + tempTime;
|
||||
case SysCustomWidgetType.Rate:
|
||||
return 'rate' + tempTime;
|
||||
case SysCustomWidgetType.Stepper:
|
||||
return 'stepper' + tempTime;
|
||||
case SysCustomWidgetType.Calendar:
|
||||
return 'calendar' + tempTime;
|
||||
case SysCustomWidgetType.CellGroup:
|
||||
return 'group' + tempTime;
|
||||
case SysCustomWidgetType.MobileRadioFilter:
|
||||
return 'mbileRadioFilter' + tempTime;
|
||||
case SysCustomWidgetType.MobileCheckBoxFilter:
|
||||
return 'mobileCheckBoxFilter' + tempTime;
|
||||
case SysCustomWidgetType.MobileInputFilter:
|
||||
return 'mobileInputFilter' + tempTime;
|
||||
case SysCustomWidgetType.MobileSwitchFilter:
|
||||
return 'mobileSwitchFilter' + tempTime;
|
||||
case SysCustomWidgetType.MobileDateRangeFilter:
|
||||
return 'mobileDateRangeFilter' + tempTime;
|
||||
case SysCustomWidgetType.MobileNumberRangeFilter:
|
||||
return 'mobileNumberRangeFilter' + tempTime;
|
||||
}
|
||||
}
|
||||
|
||||
function getWidgetAttribute(widgetType: number): ANY_OBJECT | null {
|
||||
switch (widgetType) {
|
||||
case SysCustomWidgetType.Label:
|
||||
return labelConfig;
|
||||
case SysCustomWidgetType.Text:
|
||||
return textConfig;
|
||||
case SysCustomWidgetType.Image:
|
||||
return imageConfig;
|
||||
case SysCustomWidgetType.Input:
|
||||
return inputConfig;
|
||||
case SysCustomWidgetType.NumberInput:
|
||||
return numberInputConfig;
|
||||
case SysCustomWidgetType.NumberRange:
|
||||
return numberRangeConfig;
|
||||
case SysCustomWidgetType.Switch:
|
||||
return switchConfig;
|
||||
case SysCustomWidgetType.Radio:
|
||||
return radioConfig;
|
||||
case SysCustomWidgetType.CheckBox:
|
||||
return checkboxConfig;
|
||||
case SysCustomWidgetType.Select:
|
||||
return selectConfig;
|
||||
case SysCustomWidgetType.Cascader:
|
||||
return cascaderConfig;
|
||||
case SysCustomWidgetType.Date:
|
||||
return dateConfig;
|
||||
case SysCustomWidgetType.DateRange:
|
||||
return dateRangeConfig;
|
||||
case SysCustomWidgetType.Upload:
|
||||
return uploadConfig;
|
||||
case SysCustomWidgetType.RichEditor:
|
||||
return richEditorConfig;
|
||||
case SysCustomWidgetType.Table:
|
||||
return tableConfig;
|
||||
case SysCustomWidgetType.Block:
|
||||
return blockConfig;
|
||||
case SysCustomWidgetType.Link:
|
||||
return linkConfig;
|
||||
case SysCustomWidgetType.UserSelect:
|
||||
return userSelectConfig;
|
||||
case SysCustomWidgetType.DeptSelect:
|
||||
return deptSelectConfig;
|
||||
case SysCustomWidgetType.Card:
|
||||
return baseCardConfig;
|
||||
case SysCustomWidgetType.Tabs:
|
||||
return tabsConfig;
|
||||
case SysCustomWidgetType.Tree:
|
||||
return treeConfig;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getWidgetObject(widget: ANY_OBJECT): ANY_OBJECT {
|
||||
const temp = {
|
||||
// ...widget,
|
||||
widgetType: widget.widgetType,
|
||||
bindData: {
|
||||
//...bindDataConfig,
|
||||
defaultValue: {
|
||||
//...bindDataConfig.defaultValue,
|
||||
},
|
||||
},
|
||||
operationList: widget.operationList
|
||||
? JSON.parse(JSON.stringify(widget.operationList))
|
||||
: undefined,
|
||||
showName: SysCustomWidgetType.getValue(widget.widgetType),
|
||||
variableName: getDefaultVariableName(widget.widgetType),
|
||||
props: Object.keys(widget.attribute).reduce((retObj: ANY_OBJECT, key) => {
|
||||
let tempValue;
|
||||
if (typeof widget.attribute[key].value === 'function') {
|
||||
tempValue = widget.attribute[key].value();
|
||||
} else {
|
||||
tempValue = widget.attribute[key].value;
|
||||
}
|
||||
if (Array.isArray(tempValue) || tempValue instanceof Object) {
|
||||
retObj[key] = JSON.parse(JSON.stringify(tempValue));
|
||||
} else {
|
||||
retObj[key] = tempValue;
|
||||
}
|
||||
return retObj;
|
||||
}, {}),
|
||||
eventList: [],
|
||||
childWidgetList: [],
|
||||
style: {},
|
||||
supportOperation: widget.supportOperation == null ? false : widget.supportOperation,
|
||||
};
|
||||
return temp;
|
||||
}
|
||||
|
||||
function supportBindTable(widget: ANY_OBJECT) {
|
||||
const widgetInfo = getWidgetAttribute(widget.widgetType);
|
||||
return widgetInfo ? widgetInfo.supportBindTable : false;
|
||||
}
|
||||
|
||||
function supportBindColumn(widget: ANY_OBJECT) {
|
||||
const widgetInfo = getWidgetAttribute(widget.widgetType);
|
||||
return widgetInfo ? widgetInfo.supportBindColumn : false;
|
||||
}
|
||||
|
||||
export default {
|
||||
formWidgetGroupList,
|
||||
getWidgetObject,
|
||||
getWidgetAttribute,
|
||||
supportBindTable,
|
||||
supportBindColumn,
|
||||
};
|
||||
129
OrangeFormsOpen-VUE3/src/online/config/input.ts
Normal file
129
OrangeFormsOpen-VUE3/src/online/config/input.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const input = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return (
|
||||
formConfig &&
|
||||
formConfig.form.formType !== SysOnlineFormType.QUERY &&
|
||||
formConfig.activeMode === 'pc'
|
||||
);
|
||||
},
|
||||
disabled: false,
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
type: {
|
||||
name: '输入框类型',
|
||||
value: 'text',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
dropdownList: function (formConfig: ANY_OBJECT) {
|
||||
return [
|
||||
{
|
||||
id: 'text',
|
||||
name: '单行文本',
|
||||
},
|
||||
{
|
||||
id: 'textarea',
|
||||
name: '多行文本',
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
placeholder: {
|
||||
name: '占位文本',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
'show-password': {
|
||||
name: '是否密码',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '是',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '否',
|
||||
},
|
||||
],
|
||||
},
|
||||
'show-word-limit': {
|
||||
name: '是否显示字数统计',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
maxlength: {
|
||||
name: '最大字符数',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: undefined,
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const inputConfig = {
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
icon: 'online-icon icon-input',
|
||||
attribute: input,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default inputConfig;
|
||||
30
OrangeFormsOpen-VUE3/src/online/config/label.ts
Normal file
30
OrangeFormsOpen-VUE3/src/online/config/label.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const label = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
};
|
||||
|
||||
const labelConfig = {
|
||||
widgetType: SysCustomWidgetType.Label,
|
||||
icon: 'online-icon icon-text',
|
||||
attribute: label,
|
||||
allowEventList: [OnlineFormEventType.VISIBLE],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default labelConfig;
|
||||
105
OrangeFormsOpen-VUE3/src/online/config/link.ts
Normal file
105
OrangeFormsOpen-VUE3/src/online/config/link.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const input = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
disabled: false,
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
type: {
|
||||
name: '显示类型',
|
||||
value: 'primary',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
dropdownList: [
|
||||
{
|
||||
id: 'primary',
|
||||
name: 'primary',
|
||||
},
|
||||
{
|
||||
id: 'success',
|
||||
name: 'success',
|
||||
},
|
||||
{
|
||||
id: 'warning',
|
||||
name: 'warning',
|
||||
},
|
||||
{
|
||||
id: 'danger',
|
||||
name: 'danger',
|
||||
},
|
||||
{
|
||||
id: 'info',
|
||||
name: 'info',
|
||||
},
|
||||
],
|
||||
},
|
||||
href: {
|
||||
name: '链接地址',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: undefined,
|
||||
},
|
||||
showText: {
|
||||
name: '链接显示',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: undefined,
|
||||
},
|
||||
underline: {
|
||||
name: '下划线',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '下划线',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '无下划线',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const linkConfig = {
|
||||
widgetType: SysCustomWidgetType.Link,
|
||||
icon: 'online-icon icon-link',
|
||||
attribute: input,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.LINK_HERF,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
],
|
||||
supportBindTable: false,
|
||||
supportBindColumn: false,
|
||||
};
|
||||
|
||||
export default linkConfig;
|
||||
122
OrangeFormsOpen-VUE3/src/online/config/numberInput.ts
Normal file
122
OrangeFormsOpen-VUE3/src/online/config/numberInput.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const numberInput = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
placeholder: {
|
||||
name: '占位文本',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
min: {
|
||||
name: '最小值',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: undefined,
|
||||
},
|
||||
max: {
|
||||
name: '最大值',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: undefined,
|
||||
},
|
||||
step: {
|
||||
name: '步长',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 1,
|
||||
},
|
||||
precision: {
|
||||
name: '精度',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: undefined,
|
||||
},
|
||||
controls: {
|
||||
name: '控制按钮',
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
value: true,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '显示',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '隐藏',
|
||||
},
|
||||
],
|
||||
},
|
||||
'controls-position': {
|
||||
name: '按钮位置',
|
||||
widgetType: SysCustomWidgetType.Radio,
|
||||
value: undefined,
|
||||
dropdownList: [
|
||||
{
|
||||
id: undefined,
|
||||
name: '默认',
|
||||
},
|
||||
{
|
||||
id: 'right',
|
||||
name: '右侧',
|
||||
},
|
||||
],
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const numberInputConfig = {
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
icon: 'online-icon icon-input-number',
|
||||
attribute: numberInput,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default numberInputConfig;
|
||||
77
OrangeFormsOpen-VUE3/src/online/config/numberRange.ts
Normal file
77
OrangeFormsOpen-VUE3/src/online/config/numberRange.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const numberRange = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
'start-placeholder': {
|
||||
name: '最小值提示',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
'end-placeholder': {
|
||||
name: '最大值提示',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const numberRangeConfig = {
|
||||
widgetType: SysCustomWidgetType.NumberRange,
|
||||
icon: 'online-icon icon-number-range',
|
||||
attribute: numberRange,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default numberRangeConfig;
|
||||
88
OrangeFormsOpen-VUE3/src/online/config/radio.ts
Normal file
88
OrangeFormsOpen-VUE3/src/online/config/radio.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
|
||||
const radio = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
dictInfo: {
|
||||
name: '下拉字典',
|
||||
value: {},
|
||||
customComponent: {
|
||||
component: 'CustomWidgetDictSetting',
|
||||
},
|
||||
},
|
||||
supportAll: {
|
||||
name: '全部选项',
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '显示',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '隐藏',
|
||||
},
|
||||
],
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const radioConfig = {
|
||||
widgetType: SysCustomWidgetType.Radio,
|
||||
icon: 'online-icon icon-radio',
|
||||
attribute: radio,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default radioConfig;
|
||||
45
OrangeFormsOpen-VUE3/src/online/config/richEditor.ts
Normal file
45
OrangeFormsOpen-VUE3/src/online/config/richEditor.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const richEditor = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 24,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const richEditorConfig = {
|
||||
widgetType: SysCustomWidgetType.RichEditor,
|
||||
icon: 'online-icon icon-richeditor',
|
||||
attribute: richEditor,
|
||||
eventList: [OnlineFormEventType.VISIBLE],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default richEditorConfig;
|
||||
80
OrangeFormsOpen-VUE3/src/online/config/select.ts
Normal file
80
OrangeFormsOpen-VUE3/src/online/config/select.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const select = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
placeholder: {
|
||||
name: '占位文本',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
dictInfo: {
|
||||
name: '下拉字典',
|
||||
value: {},
|
||||
customComponent: {
|
||||
component: 'CustomWidgetDictSetting',
|
||||
},
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const selectConfig = {
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
icon: 'online-icon icon-select',
|
||||
attribute: select,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
OnlineFormEventType.DROPDOWN_CHANGE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default selectConfig;
|
||||
77
OrangeFormsOpen-VUE3/src/online/config/switch.ts
Normal file
77
OrangeFormsOpen-VUE3/src/online/config/switch.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const switchAttribute = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
'active-color': {
|
||||
name: '打开背景色',
|
||||
widgetType: SysCustomWidgetType.ColorPicker,
|
||||
value: '#1989fa',
|
||||
},
|
||||
'inactive-color': {
|
||||
name: '关闭背景色',
|
||||
widgetType: SysCustomWidgetType.ColorPicker,
|
||||
value: '#E8E8E8',
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const switchConfig = {
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
icon: 'online-icon icon-switch',
|
||||
attribute: switchAttribute,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default switchConfig;
|
||||
155
OrangeFormsOpen-VUE3/src/online/config/table.ts
Normal file
155
OrangeFormsOpen-VUE3/src/online/config/table.ts
Normal file
@@ -0,0 +1,155 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
SysCustomWidgetOperationType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const table = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 24,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
height: {
|
||||
name: '表格高度',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 300,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 100,
|
||||
},
|
||||
paddingBottom: {
|
||||
name: '底部距离',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 0,
|
||||
min: 0,
|
||||
},
|
||||
paged: {
|
||||
name: '支持分页',
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
value: true,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType === SysOnlineFormType.QUERY;
|
||||
},
|
||||
},
|
||||
pageSize: {
|
||||
name: '每页条数',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
value: 10,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType === SysOnlineFormType.QUERY;
|
||||
},
|
||||
dropdownList: [
|
||||
{
|
||||
id: 10,
|
||||
name: 10,
|
||||
},
|
||||
{
|
||||
id: 20,
|
||||
name: 20,
|
||||
},
|
||||
{
|
||||
id: 50,
|
||||
name: 50,
|
||||
},
|
||||
{
|
||||
id: 100,
|
||||
name: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
operationColumnWidth: {
|
||||
name: '操作列宽度',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 160,
|
||||
},
|
||||
tableColumnList: {
|
||||
name: '表格字段',
|
||||
showLabel: false,
|
||||
value: [],
|
||||
customComponent: {
|
||||
component: 'OnlineTableColumnSetting',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const tableConfig = {
|
||||
widgetType: SysCustomWidgetType.Table,
|
||||
icon: 'online-icon icon-table',
|
||||
attribute: table,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.VISIBLE,
|
||||
OnlineFormEventType.BEFORE_LOAD_TABLE_DATA,
|
||||
OnlineFormEventType.AFTER_LOAD_TABLE_DATA,
|
||||
],
|
||||
operationList: [
|
||||
{
|
||||
id: 1,
|
||||
type: SysCustomWidgetOperationType.BATCH_DELETE,
|
||||
name: SysCustomWidgetOperationType.getValue(SysCustomWidgetOperationType.BATCH_DELETE),
|
||||
enabled: false,
|
||||
builtin: true,
|
||||
rowOperation: false,
|
||||
btnType: 'danger',
|
||||
plain: true,
|
||||
formId: undefined,
|
||||
readOnly: false,
|
||||
showOrder: 0,
|
||||
eventList: [],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: SysCustomWidgetOperationType.ADD,
|
||||
name: SysCustomWidgetOperationType.getValue(SysCustomWidgetOperationType.ADD),
|
||||
enabled: false,
|
||||
builtin: true,
|
||||
rowOperation: false,
|
||||
btnType: 'primary',
|
||||
plain: false,
|
||||
formId: undefined,
|
||||
readOnly: false,
|
||||
showOrder: 1,
|
||||
eventList: [],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: SysCustomWidgetOperationType.EDIT,
|
||||
name: SysCustomWidgetOperationType.getValue(SysCustomWidgetOperationType.EDIT),
|
||||
enabled: false,
|
||||
builtin: true,
|
||||
rowOperation: true,
|
||||
btnClass: 'table-btn success',
|
||||
formId: undefined,
|
||||
readOnly: false,
|
||||
showOrder: 10,
|
||||
eventList: [],
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
type: SysCustomWidgetOperationType.DELETE,
|
||||
name: SysCustomWidgetOperationType.getValue(SysCustomWidgetOperationType.DELETE),
|
||||
enabled: false,
|
||||
builtin: true,
|
||||
rowOperation: true,
|
||||
btnClass: 'table-btn delete',
|
||||
formId: undefined,
|
||||
readOnly: false,
|
||||
showOrder: 15,
|
||||
eventList: [],
|
||||
},
|
||||
],
|
||||
supportOperate: true,
|
||||
supportBindTable: true,
|
||||
supportBindColumn: false,
|
||||
supportOperation: true,
|
||||
};
|
||||
|
||||
export default tableConfig;
|
||||
51
OrangeFormsOpen-VUE3/src/online/config/tabs.ts
Normal file
51
OrangeFormsOpen-VUE3/src/online/config/tabs.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { SysCustomWidgetType, OnlineFormEventType } from '@/common/staticDict/index';
|
||||
|
||||
const tabs = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 24,
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
type: {
|
||||
name: '风格类型',
|
||||
widgetType: SysCustomWidgetType.Radio,
|
||||
value: undefined,
|
||||
dropdownList: [
|
||||
{
|
||||
id: undefined,
|
||||
name: '默认',
|
||||
},
|
||||
{
|
||||
id: 'border-card',
|
||||
name: '卡片',
|
||||
},
|
||||
],
|
||||
},
|
||||
paddingBottom: {
|
||||
name: '底部距离',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 0,
|
||||
min: 0,
|
||||
},
|
||||
tabPanelList: {
|
||||
name: '标签页设置',
|
||||
value: [],
|
||||
customComponent: {
|
||||
component: 'OnlineTabPanelSetting',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const tabsConfig = {
|
||||
widgetType: SysCustomWidgetType.Tabs,
|
||||
icon: 'online-icon icon-tabs2',
|
||||
attribute: tabs,
|
||||
allowEventList: [OnlineFormEventType.VISIBLE],
|
||||
supportOperate: false,
|
||||
supportBindTable: false,
|
||||
supportBindColumn: false,
|
||||
};
|
||||
|
||||
export default tabsConfig;
|
||||
132
OrangeFormsOpen-VUE3/src/online/config/text.ts
Normal file
132
OrangeFormsOpen-VUE3/src/online/config/text.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
OnlineFormEventType,
|
||||
SysCustomWidgetBindDataType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const text = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
padding: {
|
||||
name: '内部边距',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 2,
|
||||
min: 0,
|
||||
},
|
||||
paddingBottom: {
|
||||
name: '底部距离',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 0,
|
||||
min: 0,
|
||||
},
|
||||
height: {
|
||||
name: '组件高度',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 25,
|
||||
min: 0,
|
||||
},
|
||||
textIndent: {
|
||||
name: '首行缩进',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 0,
|
||||
min: 0,
|
||||
},
|
||||
align: {
|
||||
name: '水平对齐',
|
||||
value: 'left',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
dropdownList: [
|
||||
{
|
||||
id: 'left',
|
||||
name: '左对齐',
|
||||
},
|
||||
{
|
||||
id: 'center',
|
||||
name: '居中',
|
||||
},
|
||||
{
|
||||
id: 'right',
|
||||
name: '右对齐',
|
||||
},
|
||||
],
|
||||
},
|
||||
valign: {
|
||||
name: '垂直对齐',
|
||||
value: 'center',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
dropdownList: [
|
||||
{
|
||||
id: 'flex-start',
|
||||
name: '顶部',
|
||||
},
|
||||
{
|
||||
id: 'center',
|
||||
name: '居中',
|
||||
},
|
||||
{
|
||||
id: 'flex-end',
|
||||
name: '底部',
|
||||
},
|
||||
],
|
||||
},
|
||||
fontSize: {
|
||||
name: '字号',
|
||||
value: 14,
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
min: 10,
|
||||
max: 50,
|
||||
},
|
||||
fontColor: {
|
||||
name: '字体颜色',
|
||||
widgetType: SysCustomWidgetType.ColorPicker,
|
||||
value: '#383838',
|
||||
},
|
||||
bgColor: {
|
||||
name: '背景色',
|
||||
widgetType: SysCustomWidgetType.ColorPicker,
|
||||
value: undefined,
|
||||
},
|
||||
fontBold: {
|
||||
name: '粗体',
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
value: false,
|
||||
},
|
||||
fontItalic: {
|
||||
name: '斜体',
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
value: false,
|
||||
},
|
||||
text: {
|
||||
name: '内容',
|
||||
value: '文本内容',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
props: {
|
||||
type: 'textarea',
|
||||
disabled: function (formConfig: ANY_OBJECT) {
|
||||
// 表单为非报表,并且绑定在字段上,那么内容不可输入
|
||||
return (
|
||||
formConfig &&
|
||||
formConfig.currentWidget?.bindData?.dataType !== SysCustomWidgetBindDataType.Fixed &&
|
||||
formConfig.form?.pageCode == null
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const textConfig = {
|
||||
widgetType: SysCustomWidgetType.Text,
|
||||
icon: 'online-icon icon-text',
|
||||
attribute: text,
|
||||
allowEventList: [OnlineFormEventType.VISIBLE],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default textConfig;
|
||||
83
OrangeFormsOpen-VUE3/src/online/config/tree.ts
Normal file
83
OrangeFormsOpen-VUE3/src/online/config/tree.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const tree = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 24,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
height: {
|
||||
name: '组件高度',
|
||||
widgetType: SysCustomWidgetType.NumberInput,
|
||||
value: 300,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 100,
|
||||
},
|
||||
dictInfo: {
|
||||
name: '下拉字典',
|
||||
value: {},
|
||||
customComponent: {
|
||||
component: 'CustomWidgetDictSetting',
|
||||
},
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const treeConfig = {
|
||||
widgetType: SysCustomWidgetType.Tree,
|
||||
icon: 'online-icon icon-table',
|
||||
attribute: tree,
|
||||
allowEventList: [OnlineFormEventType.VISIBLE],
|
||||
supportOperate: false,
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default treeConfig;
|
||||
134
OrangeFormsOpen-VUE3/src/online/config/upload.ts
Normal file
134
OrangeFormsOpen-VUE3/src/online/config/upload.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
import { API_CONTEXT } from '@/api/config';
|
||||
|
||||
const upload = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
fileFieldName: {
|
||||
name: '文件字段名',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: 'uploadFile',
|
||||
},
|
||||
actionUrl: {
|
||||
name: '上传地址',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: function (formConfig: ANY_OBJECT) {
|
||||
if (formConfig == null) return;
|
||||
const form = formConfig.form;
|
||||
const widget = formConfig.currentWidget;
|
||||
if (form == null || widget == null || widget.datasource == null) return '';
|
||||
if (
|
||||
form.formType === SysOnlineFormType.FLOW ||
|
||||
form.formType === SysOnlineFormType.FLOW_SLAVE_EDIT
|
||||
) {
|
||||
return API_CONTEXT + '/flow/flowOnlineOperation/upload';
|
||||
} else {
|
||||
return (
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/' +
|
||||
(widget.relation ? 'uploadOneToManyRelation/' : 'uploadDatasource/') +
|
||||
widget.datasource.variableName
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
downloadUrl: {
|
||||
name: '下载地址',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: function (formConfig: ANY_OBJECT) {
|
||||
if (formConfig == null) return;
|
||||
const form = formConfig.form;
|
||||
const widget = formConfig.currentWidget;
|
||||
if (form == null || widget == null || widget.datasource == null) return '';
|
||||
if (
|
||||
form.formType === SysOnlineFormType.FLOW ||
|
||||
form.formType === SysOnlineFormType.FLOW_SLAVE_EDIT
|
||||
) {
|
||||
return API_CONTEXT + '/flow/flowOnlineOperation/download';
|
||||
} else {
|
||||
return (
|
||||
API_CONTEXT +
|
||||
'/online/onlineOperation/' +
|
||||
(widget.relation ? 'downloadOneToManyRelation/' : 'downloadDatasource/') +
|
||||
widget.datasource.variableName
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
readOnly: {
|
||||
name: '是否只读',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '是',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '否',
|
||||
},
|
||||
],
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const uploadConfig = {
|
||||
widgetType: SysCustomWidgetType.Upload,
|
||||
icon: 'online-icon icon-upload',
|
||||
attribute: upload,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default uploadConfig;
|
||||
72
OrangeFormsOpen-VUE3/src/online/config/userSelect.ts
Normal file
72
OrangeFormsOpen-VUE3/src/online/config/userSelect.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import {
|
||||
SysCustomWidgetType,
|
||||
SysOnlineFormType,
|
||||
OnlineFormEventType,
|
||||
} from '@/common/staticDict/index';
|
||||
import { ANY_OBJECT } from '@/types/generic';
|
||||
|
||||
const userSelect = {
|
||||
span: {
|
||||
name: '组件宽度',
|
||||
widgetType: SysCustomWidgetType.Slider,
|
||||
value: 12,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
min: 1,
|
||||
max: 24,
|
||||
},
|
||||
placeholder: {
|
||||
name: '占位文本',
|
||||
widgetType: SysCustomWidgetType.Input,
|
||||
value: '',
|
||||
},
|
||||
required: {
|
||||
name: '是否必填',
|
||||
value: false,
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: true,
|
||||
name: '必填',
|
||||
},
|
||||
{
|
||||
id: false,
|
||||
name: '非必填',
|
||||
},
|
||||
],
|
||||
},
|
||||
disabled: {
|
||||
name: '是否禁用',
|
||||
value: false,
|
||||
visible: function (formConfig: ANY_OBJECT) {
|
||||
return formConfig && formConfig.form.formType !== SysOnlineFormType.QUERY;
|
||||
},
|
||||
widgetType: SysCustomWidgetType.Switch,
|
||||
dropdownList: [
|
||||
{
|
||||
id: false,
|
||||
name: '启用',
|
||||
},
|
||||
{
|
||||
id: true,
|
||||
name: '禁用',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const userSelectConfig = {
|
||||
widgetType: SysCustomWidgetType.UserSelect,
|
||||
icon: 'online-icon icon-user',
|
||||
attribute: userSelect,
|
||||
allowEventList: [
|
||||
OnlineFormEventType.CHANGE,
|
||||
OnlineFormEventType.DISABLE,
|
||||
OnlineFormEventType.VISIBLE,
|
||||
],
|
||||
supportBindTable: true,
|
||||
supportBindColumn: true,
|
||||
};
|
||||
|
||||
export default userSelectConfig;
|
||||
32
OrangeFormsOpen-VUE3/src/online/config/workOrderList.ts
Normal file
32
OrangeFormsOpen-VUE3/src/online/config/workOrderList.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { SysCustomWidgetType, OnlineFormEventType } from '@/common/staticDict/index';
|
||||
|
||||
const workOrderList = {
|
||||
card: {
|
||||
name: '显示组件',
|
||||
widgetType: SysCustomWidgetType.Select,
|
||||
value: SysCustomWidgetType.ImageCard,
|
||||
dropdownList: [
|
||||
{
|
||||
id: SysCustomWidgetType.ImageCard,
|
||||
name: SysCustomWidgetType.getValue(SysCustomWidgetType.ImageCard),
|
||||
},
|
||||
],
|
||||
props: {
|
||||
clearable: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const workOrderListConfig = {
|
||||
widgetType: SysCustomWidgetType.WorkOrderList,
|
||||
icon: 'online-icon icon-card',
|
||||
attribute: workOrderList,
|
||||
allowEventList: [OnlineFormEventType.VISIBLE],
|
||||
operationList: [],
|
||||
supportOperate: false,
|
||||
supportBindTable: true,
|
||||
supportBindColumn: false,
|
||||
supportOperation: false,
|
||||
};
|
||||
|
||||
export default workOrderListConfig;
|
||||
Reference in New Issue
Block a user