<script lang="ts" setup>
|
import type { TableProps } from 'ant-design-vue';
|
|
import { computed, inject, nextTick, onMounted, reactive, ref, toRefs, unref, watch } from 'vue';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { buildUUID, getDateTimeUnit, getScriptFunc, isUnDef, thousandsFormat } from '@jnpf/utils';
|
|
import { useUserStore } from '@vben/stores';
|
|
import { CaretRightOutlined } from '@ant-design/icons-vue';
|
import { Form } from 'ant-design-vue';
|
import dayjs from 'dayjs';
|
import { cloneDeep } from 'lodash-es';
|
|
import { getDataInterfaceRes } from '#/api/systemData/dataInterface';
|
import { dyOptionsList, systemComponentsList } from '#/components/FormGenerator/src/helper/config';
|
import { getFormDataOptions } from '#/components/FormGenerator/src/helper/formDataOptions';
|
import { getRealProps } from '#/components/FormGenerator/src/helper/transform';
|
import { $t } from '#/locales';
|
import { useBaseStore } from '#/store';
|
import { onlineUtils } from '#/utils/jnpf';
|
|
import SelectModal from './components/SelectModal.vue';
|
import { createInputTableRowClickHandler, getInputTableCellInteractionAttrs } from './helpers/rowSelection';
|
|
interface State {
|
tableFormData: any[];
|
dataSource: any[];
|
rowConfig: any[];
|
activeRowIndex: number;
|
isAddRow: boolean;
|
dataInterfaceInfo: any[];
|
selectedRowKeys: any[];
|
selectedRows: any[];
|
actionConfig: any;
|
defaultRowData: any;
|
outerActiveKey: number[];
|
innerActiveKey: string[];
|
currentPage: number;
|
pageSize: number;
|
}
|
|
defineOptions({ inheritAttrs: false, name: 'JnpfInputTable' });
|
const props = defineProps({
|
config: { type: Object, default: () => {} },
|
value: { type: Array, default: () => [] },
|
formData: Object,
|
relations: Object,
|
vModel: String,
|
disabled: { type: Boolean, default: false },
|
});
|
const emit = defineEmits(['update:value', 'change']);
|
const { createMessage, createConfirm } = useMessage();
|
const baseStore = useBaseStore();
|
const userStore = useUserStore();
|
const formItemContext = Form.useInjectFormItemContext();
|
const parameter: any = inject('parameter');
|
const formConf: any = inject('formConf');
|
const formStyle: string | undefined = inject('formStyle');
|
const isShortLink: boolean | undefined = inject('isShortLink');
|
const state = reactive<State>({
|
tableFormData: [],
|
dataSource: [],
|
rowConfig: [],
|
activeRowIndex: 0,
|
isAddRow: true,
|
dataInterfaceInfo: [],
|
selectedRowKeys: [],
|
selectedRows: [],
|
actionConfig: {},
|
defaultRowData: {},
|
outerActiveKey: [0],
|
innerActiveKey: [],
|
currentPage: 1,
|
pageSize: 10,
|
});
|
const { tableFormData, dataSource, actionConfig, rowConfig } = toRefs(state);
|
const selectModal = ref(null);
|
const tableRef = ref(null);
|
|
defineExpose({
|
handleRelationForParent,
|
submit,
|
setTableFormData,
|
setTableShowOrHide,
|
setTableDisabled,
|
resetTable,
|
addForSelect,
|
});
|
|
const getHasPage = computed(() => props.config.layoutType !== 'list' && !!props.config.hasPage);
|
const getPagination = computed<any>(() => {
|
if (!unref(getHasPage)) return false;
|
return {
|
size: 'small',
|
defaultPageSize: props.config.pageSize || 10,
|
showTotal: (total) => $t('component.table.total', { total }),
|
showSizeChanger: true,
|
pageSizeOptions: ['10', '20', '30', '50'],
|
showQuickJumper: true,
|
};
|
});
|
const getActiveRowIndex = computed(() => ((state.currentPage || 1) - 1) * state.pageSize + (state.activeRowIndex || 0));
|
const getTitle = computed(() => {
|
const config = props.config.__config__;
|
return config.labelI18nCode ? $t(config.labelI18nCode, config.label) : config.label;
|
});
|
const getHelpMessage = computed(() => {
|
const config = props.config.__config__;
|
return config.tipLabelI18nCode ? $t(config.tipLabelI18nCode, config.tipLabel) : config.tipLabel;
|
});
|
const childRelations = computed(() => {
|
const obj = {};
|
for (const key in props.relations) {
|
if (key.includes('-')) {
|
const tableVModel = key.split('-')[0];
|
if (tableVModel === props.vModel) {
|
const newKey: any = key.split('-')[1];
|
obj[newKey] = props.relations[key];
|
}
|
}
|
}
|
return obj;
|
});
|
const getColumnBtnsList = computed(() => {
|
if (!props.config?.columnBtnsList?.length) return [];
|
return props.config.columnBtnsList.filter((o) => o.show);
|
});
|
const getFooterBtnsList = computed(() => {
|
if (!props.config?.footerBtnsList?.length) return [];
|
let list = props.config.footerBtnsList.filter((o) => o.show);
|
if (unref(isShortLink)) list = list.filter((o) => ['add', 'batchRemove'].includes(o.value));
|
if (props.config.layoutType === 'list') list = list.filter((o) => o.value == 'add' || (o.value != 'batchRemove' && o.actionType !== 2));
|
return list;
|
});
|
const getHasBatchBtn = computed(() => unref(getFooterBtnsList).some((o) => o.value == 'batchRemove' || o.actionType === 2));
|
const customRow = createInputTableRowClickHandler<Recordable, string>({
|
getRowKey: (row) => row.jnpfId,
|
getSelectedRowKeys: () => state.selectedRowKeys,
|
getSelectedRows: () => state.selectedRows,
|
isEnabled: () => !!unref(getHasBatchBtn),
|
isRowReadonly: (row) => getRowReadonly(getRowIndexByKey(row.jnpfId)),
|
updateSelection: (selection) => {
|
state.selectedRowKeys = selection.selectedRowKeys;
|
state.selectedRows = selection.selectedRows;
|
},
|
});
|
const getActionWidth = computed(() => unref(getColumnBtnsList).length * 50);
|
const getColumns = computed(() => {
|
const noColumn = {
|
width: 50,
|
title: $t('component.table.index'),
|
dataIndex: 'index',
|
key: 'index',
|
align: 'center',
|
customRender: ({ index }) => index + 1,
|
fixed: 'left',
|
};
|
const actionColumn = { title: $t('component.table.action'), dataIndex: 'action', key: 'action', width: unref(getActionWidth), fixed: 'right' };
|
const list = state.rowConfig
|
.map((o) => ({
|
...o,
|
dataIndex: o.__vModel__,
|
key: o.__vModel__,
|
width: o.__config__.columnWidth,
|
title: o.__config__.labelI18nCode ? $t(o.__config__.labelI18nCode, o.__config__.label) : o.__config__.label,
|
tipLabel: o.__config__.tipLabelI18nCode ? $t(o.__config__.tipLabelI18nCode, o.__config__.tipLabel) : o.__config__.tipLabel,
|
align: o.__config__.tableAlign || 'left',
|
fixed: o.__config__.tableFixed == 'left' || o.__config__.tableFixed == 'right' ? o.__config__.tableFixed : false,
|
customCell: () => ({ class: 'align-top' }),
|
}))
|
.filter((o) => !getTableColumnNoShow(o.__vModel__));
|
let columnList = list;
|
if (props.config.layoutType === 'list') return columnList;
|
let complexHeaderList: any[] = props.config.__config__.complexHeaderList || [];
|
if (complexHeaderList.length) {
|
const childColumns: any[] = [];
|
const firstChildColumns: string[] = [];
|
for (const e of complexHeaderList) {
|
e.title = e.fullNameI18nCode ? $t(e.fullNameI18nCode, e.fullName) : e.fullName;
|
e.children = [];
|
e.jnpfKey = 'complexHeader';
|
if (e.childColumns?.length) {
|
childColumns.push(...e.childColumns);
|
for (let k = 0; k < e.childColumns.length; k++) {
|
const item = e.childColumns[k];
|
for (const o of list) {
|
if (o.__vModel__ == item && o.__config__.tableFixed !== 'left' && o.__config__.tableFixed !== 'right') e.children.push({ ...o });
|
}
|
}
|
}
|
if (e.children.length) firstChildColumns.push(e.children[0].__vModel__);
|
}
|
complexHeaderList = complexHeaderList.filter((o) => o.children.length);
|
const newList: any[] = [];
|
for (const e of list) {
|
if (!childColumns.includes(e.__vModel__) || e.__config__?.tableFixed === 'left' || e.__config__?.tableFixed === 'right') {
|
newList.push(e);
|
} else {
|
if (firstChildColumns.includes(e.__vModel__)) {
|
const item = complexHeaderList.find((o) => o.childColumns.includes(e.__vModel__));
|
newList.push(item);
|
}
|
}
|
}
|
columnList = newList;
|
}
|
const columns = props.disabled || !unref(getActionWidth) ? [noColumn, ...columnList] : [noColumn, ...columnList, actionColumn];
|
const leftFixedList = columns.filter((o) => o.fixed === 'left');
|
const rightFixedList = columns.filter((o) => o.fixed === 'right');
|
const noFixedList = columns.filter((o) => o.fixed !== 'left' && o.fixed !== 'right');
|
return [...leftFixedList, ...noFixedList, ...rightFixedList];
|
});
|
const getSummaryColumn = computed(() => {
|
const defaultColumns = unref(getColumns);
|
const columns: any[] = [];
|
for (const e of defaultColumns) {
|
if (e.jnpfKey === 'table' || e.jnpfKey === 'complexHeader') {
|
if (e.children?.length) columns.push(...e.children);
|
} else {
|
columns.push(e);
|
}
|
if (e.fixed && e.children?.length) {
|
for (let j = 0; j < e.children.length; j++) {
|
e.children[j].fixed = e.fixed;
|
}
|
}
|
}
|
return columns.filter((o) => o?.key != 'index' && o?.key != 'action');
|
});
|
const getColumnSum = computed(() => {
|
const list = unref(getSummaryColumn);
|
const sums: any[] = [];
|
const isSummary = (key) => props.config.summaryField.includes(key);
|
const useThousands = (key) => list.some((o) => o.__vModel__ === key && o.thousands);
|
const rowConfig = list.filter((o) => !o.__config__.noShow && (!o.__config__.visibility || o.__config__.visibility.includes('pc')));
|
rowConfig.forEach((column, index) => {
|
let sumVal = state.dataSource.reduce((sum, d) => sum + getCmpValOfRow(d, column.__vModel__), 0);
|
if (!isSummary(column.__vModel__)) sumVal = '';
|
sumVal = Number.isNaN(sumVal) ? '' : sumVal;
|
const realVal = sumVal && !Number.isInteger(sumVal) ? Number(sumVal).toFixed(2) : sumVal;
|
sums[index] = useThousands(column.__vModel__) ? thousandsFormat(realVal) : realVal.toString();
|
});
|
if (unref(getHasBatchBtn)) sums.unshift('');
|
return sums;
|
});
|
const getRowSelection = computed(() => {
|
if (!unref(getHasBatchBtn)) return undefined;
|
const rowSelection: TableProps['rowSelection'] = {
|
selectedRowKeys: state.selectedRowKeys,
|
onChange: (selectedRowKeys: any[], selectedRows: any[]) => {
|
const rows = selectedRows || [];
|
const keys = selectedRowKeys || [];
|
const readonlyKeys = new Set(rows.filter((row) => getRowReadonly(getRowIndexByKey(row.jnpfId))).map((row) => row.jnpfId));
|
state.selectedRowKeys = keys.filter((key) => !readonlyKeys.has(key));
|
state.selectedRows = rows.filter((row) => !readonlyKeys.has(row.jnpfId));
|
},
|
columnWidth: 50,
|
getCheckboxProps: (record: any) => ({
|
disabled: getRowReadonly(getRowIndexByKey(record.jnpfId)),
|
}),
|
};
|
return rowSelection;
|
});
|
const getTableBindValues = computed(() => {
|
return {
|
columns: unref(getColumns),
|
rowSelection: unref(getRowSelection),
|
pagination: unref(getPagination),
|
size: 'small',
|
rowKey: 'jnpfId',
|
scroll: { x: 'max-content' },
|
bordered: formStyle === 'word-form' || !!props.config.__config__?.complexHeaderList?.length,
|
customRow: unref(getHasBatchBtn) ? customRow : undefined,
|
onChange: handleTableChange,
|
};
|
});
|
const getSystemField = computed(() => {
|
const systemList: any[] = [];
|
state.rowConfig.map((o) => systemComponentsList.includes(o.__config__.jnpfKey) && systemList.push(o.__vModel__));
|
return systemList;
|
});
|
|
function handleTableChange(pagination) {
|
state.currentPage = pagination.current;
|
state.pageSize = pagination.pageSize;
|
}
|
function buildOptions() {
|
state.rowConfig.forEach((cur, index) => {
|
const config = cur.__config__;
|
if (dyOptionsList.includes(config.jnpfKey)) {
|
if (config.dataType === 'dictionary' && config.dictionaryType) {
|
baseStore.getDicDataSelector(config.dictionaryType).then((res) => {
|
cur.options = res;
|
setDefaultFirstForDefaultRow(cur, cur.options);
|
});
|
}
|
if (config.dataType === 'dynamic' && config.propsUrl) {
|
const query = { paramList: config.templateJson ? getDefaultParamList(config.templateJson, props.formData) : [] };
|
const matchInfo = JSON.stringify({ id: config.propsUrl, query });
|
const item = { matchInfo, rowIndex: -1, colIndex: index };
|
state.dataInterfaceInfo.push(item);
|
getDataInterfaceRes(config.propsUrl, query).then((res) => {
|
cur.options = Array.isArray(res.data) ? res.data : [];
|
setDefaultFirstForDefaultRow(cur, cur.options);
|
});
|
}
|
if (config.dataType === 'formData') {
|
cur.options = getFormDataOptions(config, props.formData);
|
}
|
if (config.dataType === 'static') setDefaultFirstForDefaultRow(cur, cur.options);
|
}
|
});
|
}
|
function handleRelationForParent(e, defaultValue, notSetDefault) {
|
if (!state.tableFormData.length) return;
|
for (let i = 0; i < state.tableFormData.length; i++) {
|
const row: any[] = state.tableFormData[i];
|
for (const item of row) {
|
if (e.__vModel__ === item.__vModel__) {
|
if (!notSetDefault) state.dataSource[i][item.__vModel__] = defaultValue;
|
if (e.opType === 'setOptions') {
|
item.config.options = [];
|
const query = { paramList: getParamList(e.__config__.templateJson, props.formData, i) };
|
getDataInterfaceRes(e.__config__.propsUrl, query).then((res) => {
|
const realData = res.data;
|
item.config.options = Array.isArray(realData) ? realData : [];
|
setDefaultFirstForRow(i, item, item.config.options);
|
updateParentData();
|
});
|
}
|
if (e.opType === 'setUserOptions') {
|
const value = (props.formData as any)[e.relationField] || [];
|
item.config.ableRelationIds = Array.isArray(value) ? value : [value];
|
}
|
if (e.opType === 'setStartTime') {
|
const value = (props.formData as any)[e.__config__.startRelationField] || null;
|
item.config.startTime = value;
|
}
|
if (e.opType === 'setEndTime') {
|
const value = (props.formData as any)[e.__config__.endRelationField] || null;
|
item.config.endTime = value;
|
}
|
}
|
}
|
}
|
updateParentData();
|
}
|
function handleRelation(data, rowIndex) {
|
const currRelations = unref(childRelations);
|
for (const key in currRelations) {
|
if (key === data.__vModel__) {
|
for (let i = 0; i < currRelations[key].length; i++) {
|
const e = currRelations[key][i];
|
const config = e.__config__;
|
const jnpfKey = config.jnpfKey;
|
let defaultValue: any = null;
|
if (
|
['cascader', 'checkbox'].includes(jnpfKey) ||
|
(['organizeSelect', 'popupSelect', 'popupTableSelect', 'select', 'treeSelect', 'userSelect'].includes(jnpfKey) && e.multiple)
|
) {
|
defaultValue = [];
|
}
|
const row: any[] = state.tableFormData[rowIndex];
|
for (const item of row) {
|
if (e.__vModel__ === item.__vModel__) {
|
if (e.opType === 'setOptions') {
|
item.config.options = [];
|
const query = { paramList: getParamList(e.__config__.templateJson, props.formData, rowIndex) };
|
getDataInterfaceRes(e.__config__.propsUrl, query).then((res) => {
|
item.config.options = Array.isArray(res.data) ? res.data : [];
|
setDefaultFirstForRow(rowIndex, item, item.config.options);
|
updateParentData();
|
});
|
}
|
if (e.opType === 'setUserOptions') {
|
const value = getFieldVal(e.relationField, rowIndex) || [];
|
item.config.ableRelationIds = Array.isArray(value) ? value : [value];
|
}
|
if (e.opType === 'setStartTime') {
|
const value = getFieldVal(e.__config__.startRelationField, rowIndex) || null;
|
item.config.startTime = value;
|
}
|
if (e.opType === 'setEndTime') {
|
const value = getFieldVal(e.__config__.endRelationField, rowIndex) || null;
|
item.config.endTime = value;
|
}
|
if (state.dataSource[rowIndex][item.__vModel__] !== defaultValue) {
|
state.dataSource[rowIndex][item.__vModel__] = defaultValue;
|
nextTick(() => handleRelation(item, rowIndex));
|
}
|
}
|
}
|
}
|
}
|
}
|
updateParentData();
|
}
|
function buildRowAttr(rowIndex) {
|
const row: any[] = state.tableFormData[rowIndex];
|
for (const [i, element] of row.entries()) {
|
const cur = element.config;
|
const config = cur.__config__;
|
if (dyOptionsList.includes(config.jnpfKey)) {
|
if (config.dataType === 'dictionary' && config.dictionaryType) {
|
baseStore.getDicDataSelector(config.dictionaryType).then((res) => {
|
cur.options = res;
|
setDefaultFirstForRow(rowIndex, element, cur.options);
|
updateParentData();
|
});
|
}
|
if (config.dataType === 'dynamic' && config.propsUrl) {
|
if (cur.options?.length && (!config.templateJson || !config.templateJson.length || !hasTemplateJsonRelation(config.templateJson))) continue;
|
const query = { paramList: config.templateJson ? getParamList(config.templateJson, props.formData, rowIndex) : [] };
|
const matchInfo = JSON.stringify({ id: config.propsUrl, query });
|
const item = { matchInfo, rowIndex, colIndex: i };
|
const infoIndex = state.dataInterfaceInfo.findIndex((item) => item.matchInfo === matchInfo);
|
let useCacheOptions = false;
|
if (infoIndex === -1) {
|
state.dataInterfaceInfo.push(item);
|
} else {
|
const cacheOptions = getCacheOptions(infoIndex);
|
if (cacheOptions.length) {
|
cur.options = cacheOptions;
|
useCacheOptions = true;
|
setDefaultFirstForRow(rowIndex, element, cur.options);
|
}
|
}
|
if (!useCacheOptions) {
|
getDataInterfaceRes(config.propsUrl, query)
|
.then((res) => {
|
cur.options = Array.isArray(res.data) ? res.data : [];
|
setDefaultFirstForRow(rowIndex, element, cur.options);
|
updateParentData();
|
})
|
.catch(() => {
|
cur.options = [];
|
});
|
}
|
}
|
if (config.dataType === 'formData') {
|
cur.options = getFormDataOptions(config, props.formData);
|
}
|
if (config.dataType === 'static') setDefaultFirstForRow(rowIndex, element, cur.options);
|
}
|
if (config.jnpfKey === 'userSelect' && cur.relationField && cur.selectType !== 'all' && cur.selectType !== 'custom') {
|
const value = getFieldVal(cur.relationField, rowIndex) || [];
|
cur.ableRelationIds = Array.isArray(value) ? value : [value];
|
}
|
if (config.jnpfKey === 'datePicker' || config.jnpfKey === 'timePicker') {
|
if (config.startTimeRule && config.startTimeType == 2 && config.startRelationField) {
|
cur.startTime = getFieldVal(config.startRelationField, rowIndex) || null;
|
}
|
if (config.endTimeRule && config.endTimeType == 2 && config.endRelationField) {
|
cur.endTime = getFieldVal(config.endRelationField, rowIndex) || null;
|
}
|
}
|
}
|
}
|
function refreshFormDataOptions() {
|
state.rowConfig.forEach((column) => {
|
if (column.__config__?.dataType !== 'formData') return;
|
const options = getFormDataOptions(column.__config__, props.formData);
|
column.options = options;
|
state.tableFormData.forEach((row) => {
|
const cell = row.find((item) => item.__vModel__ === column.__vModel__);
|
if (cell) cell.config.options = options;
|
});
|
});
|
}
|
// 获取缓存options数据
|
function getCacheOptions(index) {
|
const item = state.dataInterfaceInfo[index];
|
return item.rowIndex === -1 ? state.rowConfig[item.colIndex].options || [] : state.tableFormData[item.rowIndex][item.colIndex].config.options || [];
|
}
|
function isEmptyValue(value) {
|
return value === null || value === undefined || value === '' || (Array.isArray(value) && value.length === 0);
|
}
|
function getOptionValue(item, propsConfig) {
|
if (!item) return undefined;
|
const valueKey = propsConfig?.value || 'id';
|
return item[valueKey];
|
}
|
function getDefaultFirstValue(cur, options) {
|
const config = cur.__config__;
|
if (config.jnpfKey !== 'select' || !config.defaultFirst) return undefined;
|
const list = Array.isArray(options) ? options : [];
|
const firstValue = getOptionValue(list[0], cur.props);
|
if (firstValue === undefined || firstValue === null || firstValue === '') return undefined;
|
return cur.multiple ? [firstValue] : firstValue;
|
}
|
function setDefaultFirstForDefaultRow(cur, options) {
|
if (!isEmptyValue(cur.__config__.defaultValue)) return;
|
const firstValue = getDefaultFirstValue(cur, options);
|
if (firstValue === undefined) return;
|
cur.__config__.defaultValue = firstValue;
|
state.defaultRowData[cur.__vModel__] = firstValue;
|
}
|
function setDefaultFirstForRow(rowIndex, item, options) {
|
if (!state.dataSource[rowIndex] || !isEmptyValue(state.dataSource[rowIndex][item.__vModel__])) return;
|
const firstValue = getDefaultFirstValue(item.config, options);
|
if (firstValue === undefined) return;
|
state.dataSource[rowIndex][item.__vModel__] = firstValue;
|
item.value = firstValue;
|
}
|
// 判断templateJson里是否有关联字段
|
function hasTemplateJsonRelation(templateJson) {
|
return templateJson.some((o) => o.relationField);
|
}
|
function getParamList(templateJson, formData, index) {
|
for (const element of templateJson) {
|
if (element.sourceType == 4 && element.relationField === '@formId') {
|
element.defaultValue = formData?.id || '';
|
}
|
if (element.relationField && element.sourceType == 1) {
|
if (element.relationField.includes('-')) {
|
const childVModel = element.relationField.split('-')[1];
|
element.defaultValue = state.dataSource[index][childVModel] || '';
|
} else {
|
element.defaultValue = formData[element.relationField] || '';
|
}
|
}
|
}
|
return templateJson;
|
}
|
function getDefaultParamList(templateJson, formData) {
|
for (const element of templateJson) {
|
if (element.sourceType == 4 && element.relationField === '@formId') {
|
element.defaultValue = formData?.id || '';
|
}
|
if (element.relationField && element.sourceType == 1) {
|
if (element.relationField.includes('-')) {
|
const childVModel = element.relationField.split('-')[1];
|
const list = state.rowConfig.filter((o) => o.__vModel__ === childVModel);
|
element.defaultValue = '';
|
if (list.length) element.defaultValue = list[0].__config__.defaultValue || '';
|
} else {
|
element.defaultValue = formData[element.relationField] || '';
|
}
|
}
|
}
|
return templateJson;
|
}
|
function getFieldVal(field, rowIndex) {
|
let val = '';
|
if (field.includes('-')) {
|
const childVModel = field.split('-')[1];
|
val = state.dataSource[rowIndex][childVModel] || '';
|
} else {
|
val = (props.formData as any)[field] || '';
|
}
|
return val;
|
}
|
function getRowIndexByKey(key) {
|
return state.dataSource.findIndex((row) => row.jnpfId === key);
|
}
|
function getFormData() {
|
return unref(parameter)?.formData || props.formData;
|
}
|
function getRowReadonly(rowIndex) {
|
if (props.disabled || !props.config?.useRowReadonly || rowIndex < 0) return false;
|
const func: any = getScriptFunc(props.config.rowReadonlyFunc);
|
if (!func) return false;
|
try {
|
const res = func({
|
row: state.dataSource[rowIndex] || {},
|
rowIndex,
|
formData: getFormData(),
|
onlineUtils,
|
});
|
return res === true;
|
} catch {
|
return false;
|
}
|
}
|
function clearAddRowFlag() {
|
nextTick(() => {
|
state.isAddRow = false;
|
});
|
}
|
function setTableFormData(prop, value, rowIndex?) {
|
const targetRowIndex = Number.isInteger(rowIndex) ? rowIndex : state.activeRowIndex;
|
const row = state.dataSource[targetRowIndex];
|
if (!row) return;
|
|
const item = state.rowConfig.find((o) => o.__vModel__ === prop);
|
const newValue = item ? getFieldValue(item, value) : value;
|
row[prop] = newValue;
|
|
const cell = state.tableFormData[targetRowIndex]?.find((element) => element.__vModel__ === prop);
|
if (cell) {
|
cell.value = newValue;
|
handleRelation(cell, targetRowIndex);
|
} else {
|
updateParentData();
|
}
|
}
|
function setTableDisabled(prop, value, rowIndex?) {
|
const disabled = !!value;
|
const setRowDisabled = (row: any[]) => {
|
if (!Array.isArray(row)) return;
|
const element = row.find((item) => item.__vModel__ === prop);
|
if (element) element.config.disabled = disabled;
|
};
|
|
if (Number.isInteger(rowIndex)) {
|
setRowDisabled(state.tableFormData[rowIndex]);
|
return;
|
}
|
|
const column = state.rowConfig.find((item) => item.__vModel__ === prop);
|
if (column) column.disabled = disabled;
|
state.tableFormData.forEach((row) => setRowDisabled(row));
|
}
|
function setTableShowOrHide(prop, value, rowIndex?) {
|
const noShow = !!value;
|
const setRowShowOrHide = (row: any[]) => {
|
if (!Array.isArray(row)) return;
|
const element = row.find((item) => item.__vModel__ === prop);
|
if (element) element.config.__config__.noShow = noShow;
|
};
|
|
if (Number.isInteger(rowIndex)) {
|
setRowShowOrHide(state.tableFormData[rowIndex]);
|
return;
|
}
|
|
const column = state.rowConfig.find((item) => item.__vModel__ === prop);
|
if (column) column.__config__.noShow = noShow;
|
state.tableFormData.forEach((row) => setRowShowOrHide(row));
|
}
|
function getTableCellNoShow(prop, rowIndex) {
|
const row = state.tableFormData[rowIndex];
|
if (!Array.isArray(row)) return true;
|
const config = row.find((item) => item.__vModel__ === prop)?.config?.__config__;
|
if (!config) return true;
|
const visibleOnPc = !config.visibility || (Array.isArray(config.visibility) && config.visibility.includes('pc'));
|
return !visibleOnPc || !!config.noShow;
|
}
|
function getTableColumnNoShow(prop) {
|
const column = state.rowConfig.find((item) => item.__vModel__ === prop);
|
const config = column?.__config__;
|
if (!config) return true;
|
const visibleOnPc = !config.visibility || (Array.isArray(config.visibility) && config.visibility.includes('pc'));
|
if (!visibleOnPc) return true;
|
if (!config.noShow) return false;
|
return !state.tableFormData.some((_, rowIndex) => !getTableCellNoShow(prop, rowIndex));
|
}
|
function onFormBlur(rowIndex, colIndex, e) {
|
if (getRowReadonly(rowIndex)) return;
|
const data: any = state.tableFormData[rowIndex][colIndex];
|
if (data && data.on && data.on.blur) {
|
const func: any = getScriptFunc(data.on.blur);
|
if (!func) return;
|
func({ data: e, rowIndex, rowData: state.dataSource[rowIndex] || {}, ...unref(parameter) });
|
}
|
}
|
function onFormDataChange(rowIndex, colIndex, val, row) {
|
if (getRowReadonly(rowIndex)) return;
|
if (state.isAddRow) return;
|
const data: any = state.tableFormData[rowIndex][colIndex] || {};
|
data.value = val;
|
state.activeRowIndex = rowIndex;
|
if (props.config.layoutType !== 'list') {
|
if (data.config?.__config__?.isDisplayOnly) {
|
clearCellValidation(data);
|
} else {
|
data.required && (data.valid = checkData(data));
|
data.regList && data.regList.length && (data.regValid = checkRegData(data, rowIndex));
|
}
|
}
|
updateParentData();
|
handleRelation(data, rowIndex);
|
if (data && data.on && data.on.change) {
|
const func: any = getScriptFunc(data.on.change);
|
if (!func) return;
|
const value = row || val;
|
func({ data: value, rowIndex, rowData: state.dataSource[rowIndex] || {}, ...unref(parameter) });
|
}
|
if (['popupSelect', 'relationForm'].includes(data.jnpfKey)) setTransferFormData(row, data.config.__config__);
|
}
|
function setTransferFormData(data, config) {
|
if (!config?.transferList?.length) return;
|
for (let index = 0; index < config.transferList.length; index++) {
|
const element = config.transferList[index];
|
if (element.sourceValue.includes('-')) element.sourceValue = element.sourceValue.split('-')[1];
|
state.dataSource[unref(getActiveRowIndex)][element.sourceValue] = data ? data[element.targetField] : undefined;
|
updateParentData();
|
}
|
}
|
/**
|
* 校验单个表单数据
|
* @param {CmpConfig} 组件配置对象
|
*/
|
function checkData({ value }) {
|
if (['', null, undefined].includes(value)) return false;
|
if (Array.isArray(value)) return value.length > 0;
|
return true;
|
}
|
function clearCellValidation(col) {
|
col.valid = true;
|
col.regValid = true;
|
col.regErrorText = '';
|
}
|
function checkRegData(col, rowIndex = state.activeRowIndex) {
|
let res = true;
|
const rowData = state.dataSource[rowIndex] || col.rowData || {};
|
for (let i = 0; i < col.regList.length; i++) {
|
const item = col.regList[i];
|
if (item.validatorType === 'customFunc') {
|
if (col.value === '' || col.value === null || col.value === undefined || (Array.isArray(col.value) && !col.value.length)) continue;
|
const func: any = getScriptFunc(item.validatorFunc);
|
const message = item.messageI18nCode ? $t(item.messageI18nCode, item.message) : item.message;
|
try {
|
const valid =
|
func &&
|
func({
|
value: col.value,
|
formData: unref(parameter)?.formData || props.formData,
|
field: col.__vModel__,
|
rowIndex,
|
rowData,
|
item: col.config,
|
config: col.config.__config__,
|
onlineUtils,
|
});
|
if (valid !== true) {
|
res = false;
|
col.regErrorText = typeof valid === 'string' ? valid : message || '校验失败';
|
break;
|
}
|
} catch (error: any) {
|
res = false;
|
col.regErrorText = (typeof error === 'string' ? error : error?.message) || message || '校验失败';
|
break;
|
}
|
continue;
|
}
|
if (item.pattern) {
|
const pattern = eval(item.pattern);
|
if (col.value && !pattern.test(col.value)) {
|
res = false;
|
col.regErrorText = item.messageI18nCode ? $t(item.messageI18nCode, item.message) : item.message;
|
break;
|
}
|
}
|
}
|
return res;
|
}
|
/**
|
* 校验表格数据必填项
|
*/
|
function submit() {
|
if (props.config.layoutType === 'list') return getDataSource();
|
let res = true;
|
const checkCol = (i, col) => {
|
col.value = state.dataSource[i][col.__vModel__];
|
const noShow = col.config.__config__.noShow;
|
const isDisplayOnly = col.config.__config__.isDisplayOnly;
|
if (isDisplayOnly) {
|
clearCellValidation(col);
|
return;
|
}
|
!noShow && col.required && !checkData(col) && (res = col.valid = false);
|
!noShow && col.regList && col.regList.length && !checkRegData(col, i) && (res = col.regValid = false);
|
};
|
state.tableFormData.forEach((row, i) => row.forEach(checkCol.bind(null, i)));
|
return res ? getDataSource() : false;
|
}
|
/**
|
* 根据formId获取完整组件配置
|
*/
|
function getConfById(formId, rowIndex) {
|
let item = state.tableFormData[rowIndex].find((t) => t.formId === formId).config;
|
const itemConfig = item.__config__;
|
const newObj: any = {};
|
item = getRealProps(item, itemConfig.jnpfKey);
|
for (const key in item) {
|
if (!['__config__', '__vModel__', 'on'].includes(key)) {
|
newObj[key] = item[key];
|
}
|
if (key === 'disabled') {
|
newObj[key] = props.disabled || item[key] || getRowReadonly(rowIndex);
|
}
|
if (key === 'placeholder' && item.placeholderI18nCode) {
|
newObj[key] = $t(item.placeholderI18nCode, item.placeholder);
|
}
|
}
|
if (['popupSelect', 'relationForm'].includes(itemConfig.jnpfKey)) {
|
newObj.field = `${props.config.__vModel__ + item.__vModel__}_jnpfRelation_${state.dataSource[rowIndex].jnpfId}`;
|
delete newObj.extraOptions;
|
}
|
if (['popupAttr', 'relationFormAttr'].includes(itemConfig.jnpfKey)) {
|
const prop = newObj.relationField.split('_jnpfTable_')[0];
|
newObj.relationField = `${props.config.__vModel__ + prop}_jnpfRelation_${state.dataSource[rowIndex].jnpfId}`;
|
}
|
if (getRowReadonly(rowIndex)) {
|
newObj.disabled = true;
|
if (Reflect.has(item, 'readonly')) newObj.readonly = true;
|
}
|
if (itemConfig.isDisplayOnly) {
|
if (Reflect.has(newObj, 'readonly')) newObj.readonly = true;
|
else newObj.disabled = true;
|
}
|
return newObj;
|
}
|
function getCellInteractionAttrs(formId, rowIndex) {
|
const controlProps = getConfById(formId, rowIndex);
|
const field = state.tableFormData[rowIndex].find((item) => item.formId === formId);
|
return getInputTableCellInteractionAttrs({
|
...controlProps,
|
disabledButClickable: field?.config?.__config__?.jnpfKey === 'relationForm',
|
});
|
}
|
function getLabelCol(config) {
|
const globalLabelWidth = unref(formConf).labelWidth;
|
let labelCol = {};
|
if (unref(formConf).labelPosition !== 'top' && config.showLabel) {
|
let labelWidth = `${config.labelWidth || globalLabelWidth}px`;
|
if (!config.showLabel) labelWidth = '0px';
|
labelCol = { style: { width: labelWidth } };
|
}
|
return labelCol;
|
}
|
function getFormItemRules(item) {
|
return buildFormItemRules(item);
|
}
|
function getRowFormItemRules(item, rowIndex) {
|
return buildFormItemRules(item, rowIndex);
|
}
|
function buildFormItemRules(item, rowIndex?) {
|
const config = item.__config__ || item;
|
if (config.isDisplayOnly) return [];
|
let rules: any[] = [];
|
const regList = Array.isArray(config.regList) ? [...config.regList] : [];
|
if (config.required) {
|
const required: any = { required: config.required, message: `${config.label}不能为空`, trigger: config.trigger || 'blur' };
|
if (Array.isArray(config.defaultValue)) {
|
required.type = 'array';
|
required.message = `请至少选择一个${config.label}`;
|
}
|
regList.push(required);
|
}
|
rules = regList.map((ruleItem) => {
|
const rule = { ...ruleItem };
|
if (rule.validatorType === 'customFunc') return buildValidateFuncRule(rule, config, item, rowIndex);
|
rule.pattern && isRegExp(rule.pattern) && (rule.pattern = eval(rule.pattern));
|
rule.trigger = config.trigger || 'blur';
|
return rule;
|
});
|
return rules;
|
}
|
function buildValidateFuncRule(ruleItem, config, item, rowIndex?) {
|
const message = ruleItem.messageI18nCode ? $t(ruleItem.messageI18nCode, ruleItem.message) : ruleItem.message;
|
return {
|
trigger: config.trigger || 'blur',
|
validator: async (_rule, value) => {
|
if (value === '' || value === null || value === undefined || (Array.isArray(value) && !value.length)) return;
|
const func: any = getScriptFunc(ruleItem.validatorFunc);
|
if (!func) throw message || '验证函数配置错误';
|
let res;
|
try {
|
const currentRowIndex = typeof rowIndex === 'number' ? rowIndex : state.activeRowIndex;
|
res = await func({
|
value,
|
formData: unref(parameter)?.formData || props.formData,
|
field: item.__vModel__,
|
rowIndex: currentRowIndex,
|
rowData: state.dataSource[currentRowIndex] || {},
|
item,
|
config,
|
onlineUtils,
|
});
|
} catch (error: any) {
|
throw (typeof error === 'string' ? error : error?.message) || message || '校验失败';
|
}
|
if (res === true) return;
|
throw typeof res === 'string' ? res : message || '校验失败';
|
},
|
};
|
}
|
function isRegExp(val) {
|
try {
|
return Object.prototype.toString.call(eval(val)) === '[object RegExp]';
|
} catch {
|
return false;
|
}
|
}
|
/**
|
* 获取默认行数据
|
*/
|
function getEmptyRow(val) {
|
return state.rowConfig.map((t: any) => ({
|
tag: t.__config__.tag,
|
formId: t.__config__.formId,
|
value: val ? (Reflect.has(val, t.__vModel__) ? getFieldValue(t, val[t.__vModel__]) : getDefaultEmptyValue(t)) : getFieldValue(t, t.__config__.defaultValue),
|
options: dyOptionsList.includes(t.__config__.jnpfKey) ? t.options : [],
|
valid: true,
|
regValid: true,
|
regErrorText: '',
|
on: t.on || {},
|
jnpfKey: t.__config__.jnpfKey,
|
__vModel__: t.__vModel__,
|
regList: t.__config__.regList || [],
|
required: t.__config__.required,
|
rowData: val || {},
|
config: t,
|
}));
|
}
|
function getDefaultEmptyValue(item) {
|
if (!item.__config__ || !item.__config__.jnpfKey) return undefined;
|
const jnpfKey = item.__config__.jnpfKey;
|
const list = ['checkbox', 'uploadFile', 'uploadImg', 'cascader', 'areaSelect'];
|
return list.includes(jnpfKey) || item.multiple ? [] : undefined;
|
}
|
function getFieldValue(item, value) {
|
const jnpfKey = item.__config__?.jnpfKey;
|
if (jnpfKey === 'checkbox' && typeof value === 'string') return value ? value.split(',') : [];
|
return cloneDeep(value);
|
}
|
function normalizeRowData(rowData) {
|
for (const item of state.rowConfig) {
|
if (!Reflect.has(rowData, item.__vModel__)) continue;
|
rowData[item.__vModel__] = getFieldValue(item, rowData[item.__vModel__]);
|
}
|
}
|
// 获取表格数据
|
function getDataSource() {
|
return state.dataSource;
|
}
|
// 更新父级数据 触发数字公式更新
|
function updateParentData() {
|
const newVal = getDataSource();
|
emit('update:value', newVal);
|
emit('change', newVal);
|
formItemContext.onFieldChange();
|
}
|
function columnBtnsHandle(item, index) {
|
if (getRowReadonly(index)) return;
|
if (item.value == 'remove') {
|
if (!getRemoveBtnEnabled(item, index)) return;
|
return removeRow(index, item.showConfirm);
|
}
|
if (item.value == 'copy') return copyRow(index);
|
}
|
function getRemoveBtnEnabled(item, rowIndex) {
|
if (getRowReadonly(rowIndex)) return false;
|
if (!item?.customStatus) return true;
|
const func: any = getScriptFunc(item.customStatusFunc);
|
if (!func) return true;
|
try {
|
const res = func({
|
row: state.dataSource[rowIndex] || {},
|
rowIndex,
|
formData: unref(parameter)?.formData || props.formData,
|
onlineUtils,
|
});
|
return res !== false;
|
} catch {
|
return true;
|
}
|
}
|
// 删除行
|
function removeRow(index, showConfirm = false) {
|
const handleRemove = () => {
|
state.tableFormData.splice(index, 1);
|
state.dataSource.splice(index, 1);
|
getRealCurrentPage();
|
nextTick(() => {
|
updateParentData();
|
});
|
};
|
if (!showConfirm) return handleRemove();
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: $t('common.delTip'),
|
onOk: handleRemove,
|
});
|
}
|
// 打开选择数据的弹出
|
function openSelectDialog() {
|
if (checkNumLimit()) return;
|
(unref(selectModal) as any)?.openSelectModal();
|
}
|
// 从弹窗选择数据
|
function addForSelect(data) {
|
let selectedData: any[] = cloneDeep(data);
|
if (props.config.isNumLimit) {
|
const remaining = (props.config.numLimit || 1000) - props.value.length;
|
if (remaining < selectedData.length) {
|
selectedData = selectedData.slice(0, remaining);
|
createMessage.warning(`${props.config.__config__.label}超出条数限制`);
|
}
|
}
|
selectedData.forEach((t) => copyData(cloneDeep({ ...state.defaultRowData, ...t })));
|
}
|
// 添加一行
|
function addRow(val?, isUpdate = true) {
|
if (isUpdate && checkNumLimit()) return;
|
state.isAddRow = true;
|
if (!val) updateRowConfig();
|
let rowData;
|
if (val) {
|
rowData = cloneDeep(val);
|
for (const o of state.rowConfig) {
|
if (!o.__config__?.defaultCurrent) continue;
|
const key = o.__vModel__;
|
const cur = rowData[key];
|
const isEmpty = cur === null || cur === undefined || cur === '' || (Array.isArray(cur) && cur.length === 0);
|
if (isEmpty) rowData[key] = state.defaultRowData[key];
|
}
|
} else {
|
rowData = cloneDeep(state.defaultRowData);
|
}
|
normalizeRowData(rowData);
|
const jnpfId = buildUUID();
|
rowData.jnpfId = jnpfId;
|
state.dataSource.push(rowData);
|
if (!Array.isArray(state.tableFormData)) state.tableFormData = [];
|
const rowIndex = state.tableFormData.length;
|
const item: any = cloneDeep(getEmptyRow(val));
|
item.jnpfId = jnpfId;
|
state.tableFormData.push(item);
|
buildRowAttr(rowIndex);
|
nextTick(() => {
|
if (isUpdate) {
|
if (props.config.layoutType === 'list' && props.config.defaultExpandAll) state.innerActiveKey.push(jnpfId);
|
updateParentData();
|
}
|
clearAddRowFlag();
|
});
|
}
|
// 复制一行
|
function copyRow(index) {
|
if (getRowReadonly(index)) return;
|
copyData(cloneDeep(state.dataSource[index]));
|
}
|
function copyData(data) {
|
const rowData = {};
|
for (const [key] of Object.entries(state.defaultRowData)) {
|
rowData[key] = !isUnDef(data[key]) && !unref(getSystemField).includes(key) ? data[key] : null;
|
}
|
addRow(rowData);
|
}
|
function footerBtnsHandle(item) {
|
if (item.value == 'add') {
|
if (item.actionType === 2) return handleAddAction(item);
|
return addRow();
|
}
|
if (item.value == 'batchRemove') return batchRemoveRow(item);
|
state.actionConfig = item.actionConfig;
|
if (item.actionType === 2) {
|
if (!state.selectedRowKeys.length) return createMessage.error($t('common.selectDataTip'));
|
// 执行动作
|
if (state.actionConfig.executeType == 2) handleScriptFunc();
|
if (state.actionConfig.executeType == 3) handleBatchInterface();
|
return;
|
}
|
// 选择数据
|
openSelectDialog();
|
}
|
function handleAddAction(item) {
|
if (checkNumLimit()) return;
|
state.actionConfig = item.actionConfig || {};
|
if (state.actionConfig.executeType == 2) return handleScriptFunc({ isAddButton: true });
|
if (state.actionConfig.executeType == 3) return handleAddInterface();
|
}
|
function handleScriptFunc(options: any = {}) {
|
const formParameter = unref(parameter) || {};
|
const scriptParameter = options.isAddButton
|
? {
|
...formParameter,
|
data: state.dataSource,
|
tableData: state.dataSource,
|
formData: formParameter.formData || props.formData,
|
addRow: (rowData?) => addRow(rowData),
|
onlineUtils: formParameter.onlineUtils || onlineUtils,
|
}
|
: { data: state.selectedRows, onlineUtils };
|
const func: any = getScriptFunc(state.actionConfig.executeFunc);
|
if (!func) return;
|
func(scriptParameter);
|
}
|
function handleAddInterface() {
|
const handlerInterface = () => {
|
const query = { paramList: getBatchParamList(state.actionConfig.executeTemplateJson, state.dataSource) || [] };
|
getDataInterfaceRes(state.actionConfig.executeInterfaceId, query).then((res) => {
|
createMessage.success(res.msg);
|
});
|
};
|
if (!state.actionConfig.executeUseConfirm) return handlerInterface();
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: state.actionConfig.executeConfirmTitle || '确认执行此操作?',
|
onOk: handlerInterface,
|
});
|
}
|
function getBatchParamList(templateJson, data?) {
|
if (!templateJson?.length) return [];
|
for (const e of templateJson) {
|
if (e.sourceType == 1 && data?.length) {
|
e.defaultValue = data.map((o) => o[e.relationField]);
|
}
|
}
|
return templateJson;
|
}
|
function handleBatchInterface() {
|
const handlerInterface = (data) => {
|
const query = { paramList: getBatchParamList(state.actionConfig.executeTemplateJson, data) || [] };
|
getDataInterfaceRes(state.actionConfig.executeInterfaceId, query).then((res) => {
|
createMessage.success(res.msg);
|
});
|
};
|
if (!state.actionConfig.executeUseConfirm) return handlerInterface(state.selectedRows);
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: state.actionConfig.executeConfirmTitle || '确认执行此操作?',
|
onOk: () => {
|
handlerInterface(state.selectedRows);
|
},
|
});
|
}
|
// 批量删除
|
function batchRemoveRow(item) {
|
if (!state.selectedRowKeys.length) return createMessage.error($t('common.selectDataTip'));
|
const selectedRowKeys = state.selectedRowKeys.filter((key) => !getRowReadonly(getRowIndexByKey(key)));
|
if (!selectedRowKeys.length) return createMessage.error($t('common.selectDataTip'));
|
const handleBatchRemove = () => {
|
state.tableFormData = state.tableFormData.filter((o) => !selectedRowKeys.includes(o.jnpfId));
|
state.dataSource = state.dataSource.filter((o) => !selectedRowKeys.includes(o.jnpfId));
|
getRealCurrentPage();
|
nextTick(() => {
|
state.selectedRowKeys = [];
|
updateParentData();
|
});
|
};
|
if (!item.showConfirm) return handleBatchRemove();
|
createConfirm({
|
iconType: 'warning',
|
title: $t('common.tipTitle'),
|
content: $t('common.delTip'),
|
onOk: handleBatchRemove,
|
});
|
}
|
function getCmpValOfRow(row, key) {
|
const isSummary = (key) => props.config.summaryField.includes(key);
|
if (!props.config.summaryField.length || !isSummary(key)) return 0;
|
const target = row[key];
|
if (!target) return 0;
|
const data = Number.isNaN(target) ? 0 : Number(target);
|
return data;
|
}
|
// 重置数据
|
function resetTable() {
|
state.dataSource = [];
|
state.tableFormData = [];
|
state.currentPage = 1;
|
}
|
function getSummaryCellAlign(index) {
|
if (!unref(getSummaryColumn).length) return;
|
if (unref(getHasBatchBtn)) index--;
|
return unref(getSummaryColumn)[index]?.align || 'left';
|
}
|
// 更新行配置
|
function updateRowConfig() {
|
const defaultRowData = {};
|
const currDate = new Date();
|
const userInfo = userStore.getUserInfo;
|
state.rowConfig = state.rowConfig.map((o) => {
|
if (o.__config__.defaultCurrent) {
|
if (o.__config__.jnpfKey === 'datePicker') {
|
o.__config__.defaultValue = dayjs(currDate).startOf(getDateTimeUnit(o.format)).valueOf();
|
}
|
if (o.__config__.jnpfKey === 'timePicker') {
|
o.__config__.defaultValue = dayjs(currDate).format(o.format || 'HH:mm:ss');
|
}
|
if (o.__config__.jnpfKey === 'organizeSelect' && userInfo?.organizeIds?.length) {
|
o.__config__.defaultValue = o.multiple ? userInfo.organizeIds : userInfo.organizeId;
|
}
|
if (o.__config__.jnpfKey === 'userSelect' && userInfo?.userId) {
|
o.__config__.defaultValue = o.multiple ? [userInfo.userId] : userInfo.userId;
|
}
|
if (o.__config__.jnpfKey === 'usersSelect' && userInfo?.userId) {
|
o.__config__.defaultValue = [`${userInfo?.userId}--user`];
|
}
|
if (o.__config__.jnpfKey === 'posSelect' && userInfo?.positionIds?.length) {
|
o.__config__.defaultValue = o.multiple ? userInfo.positionIds : userInfo.positionId;
|
}
|
if (o.__config__.jnpfKey === 'sign' && userInfo?.signImg) {
|
o.__config__.defaultValue = userInfo.signImg;
|
}
|
}
|
defaultRowData[o.__vModel__] = o.__config__.defaultValue;
|
if (o.__config__ && dyOptionsList.includes(o.__config__.jnpfKey) && o.__config__.dataType !== 'static') o.options = [];
|
if (props.config.layoutType === 'list') {
|
o.formItemRules = getFormItemRules(cloneDeep(o));
|
o.labelCol = getLabelCol(o.__config__);
|
o.title = o.__config__.labelI18nCode ? $t(o.__config__.labelI18nCode, o.__config__.label) : o.__config__.label;
|
o.tipLabel = o.__config__.tipLabelI18nCode ? $t(o.__config__.tipLabelI18nCode, o.__config__.tipLabel) : o.__config__.tipLabel;
|
}
|
return o;
|
});
|
state.defaultRowData = defaultRowData;
|
}
|
// 平铺布局时设置默认展开
|
function setActiveKey() {
|
if (props.config.layoutType !== 'list') return;
|
state.outerActiveKey = [0];
|
state.innerActiveKey = [];
|
if (!props.config.defaultExpandAll) return;
|
state.innerActiveKey = ['summary'];
|
if (!state.dataSource.length) return;
|
for (let i = 0; i < state.dataSource.length; i++) {
|
state.innerActiveKey.push(state.dataSource[i].jnpfId);
|
}
|
}
|
// 初始化
|
function init() {
|
resetTable();
|
state.rowConfig = props.config.__config__.children || [];
|
updateRowConfig();
|
buildOptions();
|
state.dataSource = [];
|
state.tableFormData = [];
|
if (props.value && Array.isArray(props.value) && props.value.length) {
|
props.value.forEach((t) => addRow(t, false));
|
}
|
nextTick(() => setActiveKey());
|
}
|
// 校验超出条数限制
|
function checkNumLimit() {
|
if (props.config.isNumLimit && props.value.length >= props.config.numLimit) {
|
createMessage.warning(`${props.config.__config__.label}超出条数限制`);
|
return true;
|
}
|
return false;
|
}
|
// 获取分页真实当前页码
|
function getRealCurrentPage() {
|
if (!props.config.hasPage) return;
|
const currentPage = Math.ceil(state.tableFormData.length / props.config.pageSize) || 1;
|
if (currentPage < state.currentPage) state.currentPage = currentPage;
|
}
|
// 获取分页真实下标index
|
function getRealIndex(index) {
|
return props.config.hasPage ? (state.currentPage - 1) * state.pageSize + index : index;
|
}
|
|
onMounted(() => {
|
init();
|
});
|
watch(
|
() => props.formData,
|
() => refreshFormDataOptions(),
|
{ deep: true },
|
);
|
</script>
|
|
<template>
|
<div class="jnpf-input-table">
|
<JnpfGroupTitle
|
:content="getTitle"
|
:help-message="getHelpMessage"
|
v-if="config.layoutType !== 'list' && config.__config__.showTitle && getTitle"
|
:bordered="false" />
|
<div class="jnpf-child-list" v-if="config.layoutType === 'list'">
|
<a-collapse expand-icon-position="end" :bordered="false" class="outer-collapse" v-model:active-key="state.outerActiveKey">
|
<a-collapse-panel force-render>
|
<template #header>
|
<span class="inline-block min-h-[22px]">{{ config.__config__.showTitle ? getTitle : '' }}</span>
|
<BasicHelp :text="getHelpMessage" v-if="config.__config__.showTitle && getTitle && getHelpMessage" />
|
</template>
|
<a-collapse :bordered="false" v-model:active-key="state.innerActiveKey">
|
<template #expandIcon="{ isActive }">
|
<CaretRightOutlined :rotate="isActive ? 90 : 0" />
|
</template>
|
<a-collapse-panel v-for="(record, index) in dataSource" :key="record.jnpfId" force-render>
|
<template #header>
|
<span class="inline-block min-h-[22px]">{{ config.__config__.showTitle ? getTitle : '' }}({{ index + 1 }})</span>
|
</template>
|
<template #extra v-if="!disabled">
|
<a-space v-if="getColumnBtnsList.length">
|
<a-button
|
class="!px-0"
|
type="link"
|
:color="item.value == 'remove' ? 'error' : ''"
|
:disabled="getRowReadonly(index) || (item.value == 'remove' && !getRemoveBtnEnabled(item, index))"
|
@click.stop="columnBtnsHandle(item, index)"
|
size="small"
|
v-for="item in getColumnBtnsList"
|
:key="item.value">
|
{{ item.labelI18nCode ? $t(item.labelI18nCode, item.label) : item.label }}
|
</a-button>
|
</a-space>
|
</template>
|
<a-row :gutter="formConf.formStyle ? 0 : formConf.gutter">
|
<template v-for="(column, cIndex) in rowConfig" :key="column.__config__.formId">
|
<a-col :span="column.__config__.span" v-if="!getTableCellNoShow(column.__vModel__, index)">
|
<a-form-item
|
:name="[vModel, index, column.__vModel__]"
|
:required="column.__config__.required && !column.__config__.isDisplayOnly"
|
:label-col="column.labelCol"
|
:rules="getRowFormItemRules(column, index)">
|
<template #label v-if="column.__config__.showLabel">
|
{{ column.title ? column.title + (column.__config__.labelSuffix || '') : '' }}
|
<BasicHelp :text="column.tipLabel" v-if="column.title && column.tipLabel" />
|
</template>
|
<component
|
:is="column.__config__.tag"
|
:row-index="index"
|
:table-v-model="config.__vModel__"
|
:component-v-model="column.__vModel__"
|
v-bind="getConfById(column.__config__.formId, index)"
|
v-model:value="record[column.__vModel__]"
|
:form-data="formData"
|
@blur="onFormBlur(index, cIndex, $event)"
|
@change="(val, data) => onFormDataChange(index, cIndex, val, data)" />
|
</a-form-item>
|
</a-col>
|
</template>
|
</a-row>
|
</a-collapse-panel>
|
<a-collapse-panel key="summary" v-if="tableFormData.length && config.showSummary">
|
<template #header>
|
<span class="inline-block min-h-[22px]">{{ $t('component.table.summary') }}</span>
|
</template>
|
<a-row :gutter="formConf.formStyle ? 0 : formConf.gutter">
|
<template v-for="(column, cIndex) in rowConfig" :key="column.__config__.formId">
|
<a-col
|
:span="column.__config__.span"
|
v-if="!getTableColumnNoShow(column.__vModel__) && column.__vModel__ && config.summaryField.includes(column.__vModel__)">
|
<a-form-item :label-col="column.labelCol">
|
<template #label v-if="column.__config__.showLabel">
|
{{ column.title ? column.title + (column.__config__.labelSuffix || '') : '' }}
|
<BasicHelp :text="column.tipLabel" v-if="column.title && column.tipLabel" />
|
</template>
|
<JnpfInput :value="getColumnSum[cIndex]" disabled :style="column.style" />
|
</a-form-item>
|
</a-col>
|
</template>
|
</a-row>
|
</a-collapse-panel>
|
</a-collapse>
|
<a-space class="input-table-footer-btn" v-if="!disabled && getFooterBtnsList.length">
|
<a-button
|
:type="item.btnType == 'text' ? 'link' : item.btnType"
|
:pre-icon="item.btnIcon"
|
@click="footerBtnsHandle(item)"
|
v-for="item in getFooterBtnsList"
|
:key="item.value">
|
{{ item.labelI18nCode ? $t(item.labelI18nCode, item.label) : item.label }}
|
</a-button>
|
</a-space>
|
</a-collapse-panel>
|
</a-collapse>
|
</div>
|
<a-table :data-source="dataSource" v-bind="getTableBindValues" ref="tableRef" v-else>
|
<template #headerCell="{ column }">
|
<span class="required-sign" v-if="column.__config__ && column.__config__.required && !column.__config__.isDisplayOnly">*</span>{{ column.title }}
|
<BasicHelp v-if="column.title && column.tipLabel" :text="column.tipLabel" />
|
</template>
|
<template #bodyCell="{ column, record, index }">
|
<template v-if="column.key === 'index'">{{ index + 1 }}</template>
|
<template v-for="(item, cIndex) in rowConfig">
|
<template v-if="column.key === item.__vModel__ && column.__config__.formId === item.__config__.formId">
|
<div
|
v-if="!getTableCellNoShow(item.__vModel__, getRealIndex(index))"
|
:key="item.__config__.formId"
|
v-bind="getCellInteractionAttrs(item.__config__.formId, getRealIndex(index))">
|
<component
|
:is="item.__config__.tag"
|
:row-index="getRealIndex(index)"
|
:table-v-model="config.__vModel__"
|
:component-v-model="item.__vModel__"
|
v-bind="getConfById(item.__config__.formId, getRealIndex(index))"
|
v-model:value="record[column.__vModel__]"
|
:form-data="formData"
|
@blur="onFormBlur(getRealIndex(index), cIndex, $event)"
|
@change="(val, data) => onFormDataChange(getRealIndex(index), cIndex, val, data)" />
|
<div class="error-tip required-sign" v-show="!column.__config__.isDisplayOnly && !tableFormData[getRealIndex(index)][cIndex].valid">
|
{{ column.title }}{{ $t('sys.validate.textRequiredSuffix') }}
|
</div>
|
<div
|
class="error-tip required-sign"
|
v-show="
|
!column.__config__.isDisplayOnly && tableFormData[getRealIndex(index)][cIndex].valid && !tableFormData[getRealIndex(index)][cIndex].regValid
|
">
|
{{ tableFormData[getRealIndex(index)][cIndex].regErrorText }}
|
</div>
|
</div>
|
</template>
|
</template>
|
<template v-if="column.key === 'action'">
|
<a-space v-if="getColumnBtnsList.length">
|
<a-button
|
class="action-btn"
|
type="link"
|
:color="item.value == 'remove' ? 'error' : ''"
|
:disabled="getRowReadonly(getRealIndex(index)) || (item.value == 'remove' && !getRemoveBtnEnabled(item, getRealIndex(index)))"
|
@click="columnBtnsHandle(item, getRealIndex(index))"
|
size="small"
|
v-for="item in getColumnBtnsList"
|
:key="item.value">
|
{{ item.labelI18nCode ? $t(item.labelI18nCode, item.label) : item.label }}
|
</a-button>
|
</a-space>
|
</template>
|
</template>
|
<template #summary v-if="tableFormData.length && config.showSummary">
|
<a-table-summary fixed>
|
<a-table-summary-row>
|
<a-table-summary-cell :index="0" align="center">{{ $t('component.table.summary') }}</a-table-summary-cell>
|
<a-table-summary-cell v-for="(item, index) in getColumnSum" :key="index" :index="index + 1" :align="getSummaryCellAlign(index)">
|
{{ item }}
|
</a-table-summary-cell>
|
<a-table-summary-cell :index="getColumnSum.length + 1" v-if="!disabled" />
|
</a-table-summary-row>
|
</a-table-summary>
|
</template>
|
</a-table>
|
<a-space class="input-table-footer-btn" v-if="config.layoutType !== 'list' && !disabled && getFooterBtnsList.length">
|
<a-button
|
:type="item.btnType == 'text' ? 'link' : item.btnType"
|
:pre-icon="item.btnIcon"
|
@click="footerBtnsHandle(item)"
|
v-for="item in getFooterBtnsList"
|
:key="item.value">
|
{{ item.labelI18nCode ? $t(item.labelI18nCode, item.label) : item.label }}
|
</a-button>
|
</a-space>
|
<SelectModal :config="actionConfig" :form-data="formData" ref="selectModal" @select="addForSelect" />
|
</div>
|
</template>
|
<style lang="scss" scoped>
|
.jnpf-input-table {
|
[data-input-table-click-through] {
|
pointer-events: none;
|
}
|
|
.error-tip {
|
font-size: 12px;
|
}
|
}
|
</style>
|