<script lang="tsx">
|
import type { FormInstance } from 'ant-design-vue';
|
|
import { computed, defineComponent, getCurrentInstance, inject, nextTick, onMounted, onUnmounted, provide, reactive, ref, unref, watch } from 'vue';
|
|
import { BasicHelp } from '@jnpf/ui';
|
import { buildUUID, formatToDate, getDateTimeUnit, getScriptFunc, getTimeUnit } from '@jnpf/utils';
|
|
import { useUserStore } from '@vben/stores';
|
|
import dayjs from 'dayjs';
|
import { cloneDeep, upperFirst } from 'lodash-es';
|
|
import { getDataInterfaceRes } from '#/api/systemData/dataInterface';
|
import { lockBillNumber } from '#/api/onlineDev/visualDev';
|
import { $t } from '#/locales';
|
import { useBaseStore, useGeneratorStore } from '#/store';
|
import { getParamList, onlineUtils } from '#/utils/jnpf';
|
|
import { buildAuditDisplayFields } from '../helper/auditDisplay';
|
import { dyOptionsList, vModelIgnoreList } from '../helper/config';
|
import { buildDisplayOnlySubmitData, isVirtualTable, normalizeVirtualFields } from '../helper/displayOnly';
|
import { getFormDataOptions } from '../helper/formDataOptions';
|
import { invoiceDetailIds } from '../helper/ocrMap';
|
import render from '../helper/render';
|
|
interface State {
|
auditSelectedValues: Record<string, any>;
|
formData: any;
|
formRules: any;
|
relations: any;
|
tableRefs: any;
|
options: any;
|
formConfCopy: any;
|
formIdObj: any;
|
}
|
|
export default defineComponent({
|
components: {
|
Render: render,
|
},
|
emits: ['review-status-change', 'review-visibility-change', 'submit'],
|
inheritAttrs: false,
|
name: 'Parser',
|
props: ['formConf', 'isPreview', 'isShortLink', 'modelId', 'params', 'requireReview', 'isOnlineUtilsOpen'],
|
|
setup(props, { expose, emit }) {
|
const generatorStore = useGeneratorStore();
|
const injectedOnlineUtils = inject('onlineUtils', null) as any;
|
provide(
|
'onlineUtilsOpen',
|
computed(() => !!props.isOnlineUtilsOpen),
|
);
|
const state = reactive<State>({
|
auditSelectedValues: {},
|
formData: {},
|
formRules: {},
|
relations: {},
|
tableRefs: {},
|
options: {},
|
formConfCopy: {},
|
formIdObj: {},
|
});
|
const isTableValid = ref(false);
|
const reviewVisible = ref(isReviewVisible());
|
const reviewPassed = ref(!isReviewRequired());
|
const formElRef = ref<FormInstance>();
|
// 每个表单生成不同name保证id不重复
|
const getFormName: string = `form-${buildUUID()}`;
|
const baseStore = useBaseStore();
|
const userStore = useUserStore();
|
state.formConfCopy = cloneDeep(props.formConf);
|
normalizeVirtualFields(state.formConfCopy.fields);
|
const layouts = {
|
colFormItem(element) {
|
// 多语言替换占位提示
|
if (element.placeholderI18nCode) element.placeholder = $t(element.placeholderI18nCode, element.placeholder);
|
|
const config = element.__config__;
|
const listeners = buildListeners(element);
|
const globalLabelWidth = props.formConf.labelWidth;
|
let labelCol = {};
|
if ((props.formConf.labelPosition !== 'top' && config.showLabel) || vModelIgnoreList.includes(config.jnpfKey)) {
|
let labelWidth = `${config.labelWidth || globalLabelWidth}px`;
|
if (!config.showLabel) labelWidth = '0px';
|
labelCol = { style: { width: labelWidth } };
|
}
|
if (['divider', 'groupTitle', 'link', 'text'].includes(config.jnpfKey)) {
|
if (element.contentI18nCode) element.content = $t(element.contentI18nCode, element.content);
|
if (element.helpMessageI18nCode) element.helpMessage = $t(element.helpMessageI18nCode, element.helpMessage);
|
}
|
if (config.jnpfKey === 'button' && element.buttonTextI18nCode) element.buttonText = $t(element.buttonTextI18nCode, element.buttonText);
|
if (config.jnpfKey === 'alert') {
|
if (element.titleI18nCode) element.title = $t(element.titleI18nCode, element.title);
|
if (element.descriptionI18nCode) element.description = $t(element.descriptionI18nCode, element.description);
|
if (element.closeTextI18nCode) element.closeText = $t(element.closeTextI18nCode, element.closeText);
|
}
|
const Item = (
|
<render
|
conf={element}
|
formData={state.formData}
|
key={config.renderKey}
|
onlineUtilsOpen={!!props.isOnlineUtilsOpen}
|
size={element.size ? element.size : props.formConf.size}
|
{...listeners}
|
ref={config.jnpfKey === 'table' ? element.__vModel__ : undefined}
|
relations={config.jnpfKey === 'table' ? state.relations : undefined}
|
/>
|
);
|
let basicHelp: any = null;
|
const label = config.labelI18nCode ? $t(config.labelI18nCode, config.label) : config.label;
|
const tipLabel = config.tipLabelI18nCode ? $t(config.tipLabelI18nCode, config.tipLabel) : config.tipLabel;
|
|
if (config.showLabel && label && tipLabel) basicHelp = <BasicHelp text={tipLabel} />;
|
const slots: any = {
|
label: () => {
|
if (!config.showLabel) return null;
|
return (
|
<span>
|
{label ? label + (props.formConf.labelSuffix || '') : ''}
|
{basicHelp}
|
</span>
|
);
|
},
|
};
|
const visibility = !config.visibility || (Array.isArray(config.visibility) && config.visibility.includes('pc'));
|
if (visibility && !config.noShow) {
|
return (
|
<a-col class={[...(config.className || []), 'ant-col-item']} span={config.span}>
|
<a-form-item
|
key={config.renderKey}
|
labelCol={labelCol}
|
name={element.__vModel__}
|
required={config.required && !config.isDisplayOnly}
|
v-slots={slots}>
|
{Item}
|
</a-form-item>
|
</a-col>
|
);
|
}
|
},
|
rowFormItem(element) {
|
const config = element.__config__;
|
const listeners = buildListeners(element);
|
const visibility = !config.visibility || (Array.isArray(config.visibility) && config.visibility.includes('pc'));
|
if (!visibility || config.noShow) return;
|
|
if (config.jnpfKey === 'tab') {
|
return (
|
<a-col class={props.formConf.formStyle ? '' : 'mb-[10px]'} span={config.span}>
|
<a-tabs size={props.formConf.size} tabPosition={element.tabPosition} type={element.type} v-model:activeKey={config.active} {...listeners}>
|
{config.children.map((item) => {
|
const child = renderChildren(item);
|
if (item.titleI18nCode) item.title = $t(item.titleI18nCode, item.title);
|
return (
|
<a-tab-pane forceRender key={item.name} tab={item.title}>
|
<a-row gutter={props.formConf.formStyle ? 0 : state.formConfCopy.gutter || 15}>{child}</a-row>
|
</a-tab-pane>
|
);
|
})}
|
</a-tabs>
|
</a-col>
|
);
|
}
|
|
if (config.jnpfKey === 'collapse') {
|
return (
|
<a-col class={props.formConf.formStyle ? '' : 'mb-[20px]'} span={config.span}>
|
<a-collapse accordion={element.accordion} expandIconPosition="end" ghost={true} v-model:activeKey={config.active} {...listeners}>
|
{config.children.map((item) => {
|
const child = renderChildren(item);
|
if (item.titleI18nCode) item.title = $t(item.titleI18nCode, item.title);
|
return (
|
<a-collapse-panel forceRender header={item.title} key={item.name}>
|
<a-row gutter={props.formConf.formStyle ? 0 : state.formConfCopy.gutter || 15}>{child}</a-row>
|
</a-collapse-panel>
|
);
|
})}
|
</a-collapse>
|
</a-col>
|
);
|
}
|
|
if (config.jnpfKey === 'steps') {
|
const isControlled = !!config.currentStepField;
|
if (isControlled) syncControlledStepActive(config);
|
const stepListeners = {
|
...listeners,
|
onChange: (current) =>
|
isControlled ? handleControlledStepChange(element, current, listeners) : handleUncontrolledStepChange(config, current, listeners),
|
};
|
return (
|
<a-col class={props.formConf.formStyle ? '' : 'mb-[10px]'} span={config.span}>
|
<a-row>
|
<a-steps
|
current={config.active}
|
size={props.formConf.size}
|
status={element.processStatus}
|
type={element.simple ? 'navigation' : 'default'}
|
{...stepListeners}>
|
{config.children.map((item, childIndex) => {
|
const slots: any = {};
|
if (item.icon) slots.icon = () => <span class={`${item.icon} custom-icon`}></span>;
|
if (item.titleI18nCode) item.title = $t(item.titleI18nCode, item.title);
|
return <a-step status={isControlled ? getControlledStepStatus(config, childIndex) : undefined} title={item.title} v-slots={slots} />;
|
})}
|
</a-steps>
|
{config.children.map((item, childIndex) => {
|
const child = renderChildren(
|
item,
|
isControlled && !isControlledStepEditable(config, childIndex),
|
isControlled && !isControlledStepReached(config, childIndex),
|
);
|
return (
|
<a-row
|
class="w-full !pt-[12px]"
|
gutter={props.formConf.formStyle ? 0 : state.formConfCopy.gutter || 15}
|
v-show={config.active === childIndex}>
|
{child}
|
</a-row>
|
);
|
})}
|
</a-row>
|
</a-col>
|
);
|
}
|
|
if (config.jnpfKey === 'tableGrid') {
|
return (
|
<a-col span={config.span}>
|
<table
|
class="table-grid-box"
|
style={{ '--borderType': config.borderType, '--borderColor': config.borderColor, '--borderWidth': `${config.borderWidth}px` }}>
|
<tbody>
|
{config.children.map((item) => {
|
return (
|
<tr>
|
{item.__config__.children.map((it) => {
|
const child = renderChildren(it);
|
if (it.__config__.merged) return '';
|
return (
|
<td
|
colspan={it.__config__.colspan || 1}
|
rowspan={it.__config__.rowspan || 1}
|
style={{ '--backgroundColor': it.__config__.backgroundColor }}>
|
<a-col>
|
<a-row gutter={state.formConfCopy.gutter || 15}>{child}</a-row>
|
</a-col>
|
</td>
|
);
|
})}
|
</tr>
|
);
|
})}
|
</tbody>
|
</table>
|
</a-col>
|
);
|
}
|
|
if (config.jnpfKey === 'table') {
|
if (!element.__config__.noShow) state.tableRefs[element.__vModel__] = null;
|
const param = { ...element, config: element };
|
return layouts.colFormItem(param);
|
}
|
|
const child = renderChildren(element);
|
|
if (config.jnpfKey === 'row') {
|
return (
|
<a-col span={config.span}>
|
<a-row gutter={props.formConf.formStyle ? 0 : state.formConfCopy.gutter || 15}>{child}</a-row>
|
</a-col>
|
);
|
}
|
|
if (config.jnpfKey === 'card') {
|
let basicHelp: any = null;
|
const header = element.headerI18nCode ? $t(element.headerI18nCode, element.header) : element.header;
|
const tipLabel = config.tipLabelI18nCode ? $t(config.tipLabelI18nCode, config.tipLabel) : config.tipLabel;
|
if (tipLabel) basicHelp = <BasicHelp text={tipLabel} />;
|
const cardSlots = {
|
title: () => {
|
if (!header) return null;
|
return (
|
<span>
|
{header}
|
{basicHelp}
|
</span>
|
);
|
},
|
};
|
return (
|
<a-col span={config.span}>
|
<a-card class="!mb-[20px]" hoverable={element.shadow === 'hover'} size={props.formConf.size} v-slots={cardSlots}>
|
<a-row gutter={props.formConf.formStyle ? 0 : state.formConfCopy.gutter || 15}>{child}</a-row>
|
</a-card>
|
</a-col>
|
);
|
}
|
|
return null;
|
},
|
};
|
|
const getParameter = computed(() => {
|
const oldFormData = state.formConfCopy.formData || {};
|
(state.formData as any).id = oldFormData.id || '';
|
(state.formData as any).flowId = oldFormData.flowId || '';
|
return {
|
formData: unref(state.formData),
|
setFormData,
|
setShowOrHide,
|
setRequired,
|
setDisabled,
|
onlineUtils: injectedOnlineUtils || onlineUtils,
|
params: props.params || {},
|
};
|
});
|
const getFormClass = computed(() => {
|
let className: string[] = ['dynamic-form', unref(getFormName)];
|
if (props.formConf.formStyle) className.push(props.formConf.formStyle);
|
if (props.formConf.className) className = [...className, ...props.formConf.className];
|
return className;
|
});
|
|
expose({ handleReview, handleSubmit, handleReset });
|
|
provide('parameter', unref(getParameter));
|
provide('formConf', props.formConf);
|
provide('formStyle', props.formConf.formStyle);
|
provide('isShortLink', props.isShortLink || false);
|
|
function renderFrom() {
|
const labelCol = { style: { width: `${state.formConfCopy.labelWidth}px` } };
|
return (
|
<a-row class={unref(getFormClass)}>
|
<a-form
|
class={props.formConf.className}
|
colon={false}
|
disabled={state.formConfCopy.disabled}
|
labelAlign={state.formConfCopy.labelPosition === 'right' ? 'right' : 'left'}
|
labelCol={labelCol}
|
layout={state.formConfCopy.labelPosition === 'top' ? 'vertical' : 'horizontal'}
|
model={state.formData}
|
name={unref(getFormName)}
|
ref={formElRef}
|
rules={state.formRules}
|
size={state.formConfCopy.size}>
|
<a-row gutter={props.formConf.formStyle ? 0 : state.formConfCopy.gutter || 15}>{renderFormItem(state.formConfCopy.fields)}</a-row>
|
</a-form>
|
</a-row>
|
);
|
}
|
function renderFormItem(elementList) {
|
return elementList.map((scheme) => {
|
const config = scheme.__config__;
|
const layout = layouts[config.layout];
|
if (layout) return layout(scheme);
|
return null;
|
});
|
}
|
function renderChildren(scheme, disabled = false, clearDefault = false) {
|
const config = scheme.__config__;
|
if (!Array.isArray(config.children)) return null;
|
return renderFormItem(disabled || clearDefault ? getDisabledChildren(config.children, clearDefault) : config.children);
|
}
|
function getDisabledChildren(children, clearDefault = false) {
|
return children.map((item) => {
|
const config = item.__config__;
|
if (!config) return item;
|
const newItem = { ...item, __config__: { ...config } };
|
if (clearDefault && newItem.__vModel__) {
|
newItem.__config__.defaultValue = getEmptyComponentValue(newItem);
|
newItem.__config__.__unreachedStep = true;
|
}
|
if (config.jnpfKey === 'table') {
|
newItem.disabled = true;
|
} else if ('readonly' in newItem) {
|
newItem.readonly = true;
|
} else if ('disabled' in newItem) {
|
newItem.disabled = true;
|
}
|
if (Array.isArray(config.children)) {
|
newItem.__config__.children = getDisabledChildren(config.children, clearDefault);
|
}
|
return newItem;
|
});
|
}
|
function buildListeners(scheme) {
|
const config = scheme.__config__;
|
const listeners: any = {};
|
listeners.onChange = (...arg) => {
|
if (scheme.__vModel__) {
|
state.auditSelectedValues[scheme.__vModel__] = {
|
option: arg.length > 1 ? arg[1] : arg[0],
|
value: arg[0],
|
};
|
}
|
};
|
if (scheme.on) {
|
// 响应 组件事件
|
Object.keys(scheme.on).forEach((key) => {
|
const str = scheme.on[key];
|
const func: any = getScriptFunc(str);
|
if (!func) return;
|
const eventName = `on${upperFirst(key)}`;
|
const captureListener = listeners[eventName];
|
listeners[eventName] = (...arg) => {
|
captureListener?.(...arg);
|
if (key === 'change') {
|
const data = arg.length > 1 ? arg[1] : arg[0];
|
if (['popupSelect', 'relationForm'].includes(config.jnpfKey)) setTransferFormData(data, config);
|
if (config.tag === 'JnpfOcr') handleOcrChange(data, config);
|
func({ data, ...unref(getParameter) });
|
handleRelation(scheme.__vModel__);
|
} else {
|
func({ data: arg[0], ...unref(getParameter) });
|
}
|
};
|
});
|
}
|
// 响应 render.ts 中的 buildVModel 中 emit('update:value', val);
|
listeners['onUpdate:value'] = (event) => {
|
if (config.__unreachedStep) {
|
delete state.formData[scheme.__vModel__];
|
return;
|
}
|
config.defaultValue = event;
|
state.formData[scheme.__vModel__] = event;
|
};
|
return listeners;
|
}
|
function getControlledStepValue(config) {
|
const value = Number(getControlledStepRawValue(config));
|
return Number.isFinite(value) ? Math.floor(value) : 1;
|
}
|
function getControlledStepRawValue(config) {
|
if (!config.currentStepField) return undefined;
|
if (Object.prototype.hasOwnProperty.call(state.formData, config.currentStepField)) return state.formData[config.currentStepField];
|
const item = getFieldByVModel(config.currentStepField);
|
return item?.__config__?.defaultValue;
|
}
|
function getControlledStepIndex(config) {
|
const total = config.children?.length || 0;
|
if (!total) return 0;
|
return Math.min(Math.max(getControlledStepValue(config), 1), total) - 1;
|
}
|
function isControlledStepAllFinished(config) {
|
const total = config.children?.length || 0;
|
return total > 0 && getControlledStepValue(config) > total;
|
}
|
function isControlledStepReached(config, index) {
|
if (isControlledStepAllFinished(config)) return true;
|
return index <= getControlledStepIndex(config);
|
}
|
function syncControlledStepActive(config) {
|
const value = getControlledStepRawValue(config);
|
if (config.__currentStepFieldValue === value && typeof config.active === 'number') return;
|
config.__currentStepFieldValue = value;
|
config.active = isControlledStepAllFinished(config) ? (config.children?.length || 1) - 1 : getControlledStepIndex(config);
|
if (initReachedControlledStepData(config)) rebuildFormRules();
|
}
|
function getControlledStepStatus(config, index) {
|
if (isControlledStepAllFinished(config)) return 'finish';
|
const current = getControlledStepIndex(config);
|
if (index < current) return 'finish';
|
if (index === current) return 'process';
|
return 'wait';
|
}
|
function isControlledStepEditable(config, index) {
|
return !isControlledStepAllFinished(config) && index === getControlledStepIndex(config);
|
}
|
function canSwitchControlledStep(config, targetIndex) {
|
if (isControlledStepAllFinished(config)) return true;
|
return targetIndex <= getControlledStepIndex(config);
|
}
|
function handleUncontrolledStepChange(config, current, listeners) {
|
config.active = current;
|
listeners.onChange?.(current);
|
}
|
function handleControlledStepChange(element, current, listeners) {
|
const config = element.__config__;
|
if (!canSwitchControlledStep(config, current)) {
|
syncControlledStepActive(config);
|
return;
|
}
|
config.active = current;
|
listeners.onChange?.(current);
|
}
|
// ocr控件赋值
|
function handleOcrChange(data, config) {
|
const transferList = config.transferList.filter((o) => o.formId);
|
if (!transferList?.length || !data) return;
|
const subTableObj: any = {};
|
for (const element of transferList) {
|
const formObj = state.formIdObj[element.formId];
|
if (formObj?.__vModel__) {
|
if (formObj?.__vModel__.includes('-')) {
|
const tableVModel = formObj?.__vModel__.split('-')[0];
|
const childVModel = formObj?.__vModel__.split('-')[1];
|
if (Object.prototype.hasOwnProperty.call(subTableObj, tableVModel)) {
|
const boo = subTableObj[tableVModel].includes(childVModel);
|
if (!boo) {
|
subTableObj[tableVModel].push({ ...element, childVModel });
|
}
|
} else {
|
subTableObj[tableVModel] = [{ ...element, childVModel }];
|
}
|
} else {
|
let value;
|
// 发票明细主表以,拼接
|
if (invoiceDetailIds.includes(element.id)) {
|
value = data.invoiceDetail.map((o) => o[element.id]).join(',');
|
} else {
|
value = element.supportJnpfKey.includes('datePicker') && formObj.jnpfKey != 'datePicker' ? formatToDate(data[element.id]) : data[element.id];
|
}
|
setFormData(formObj.__vModel__, value);
|
}
|
}
|
}
|
// 发票明细子表数据赋值;
|
for (const [key, value] of Object.entries(subTableObj)) {
|
const itemData = handlePickKeys(data.invoiceDetail, value);
|
unref(state.tableRefs[key]).tableRef && unref(state.tableRefs[key]).tableRef.addForSelect(itemData);
|
}
|
}
|
// 过滤子表数据key
|
function handlePickKeys(arr, keys) {
|
return arr.map((item) =>
|
keys.reduce((acc, cur) => {
|
if (cur.id in item) acc[cur.childVModel] = item[cur.id];
|
return acc;
|
}, {}),
|
);
|
}
|
function setTransferFormData(data, config) {
|
if (!config?.transferList?.length) return;
|
for (let index = 0; index < config.transferList.length; index++) {
|
const element = config.transferList[index];
|
setFormData(element.sourceValue, getTransferValue(element.sourceValue, data[element.targetField]));
|
}
|
}
|
function getTransferValue(prop, value) {
|
const component = getFormComponent(prop);
|
const config = component?.__config__;
|
if (!config) return value;
|
if (config.jnpfKey === 'datePicker') return getDatePickerValue(value, component.format);
|
if (config.jnpfKey === 'timePicker') return getTimePickerValue(value, component.format);
|
return value;
|
}
|
function getDatePickerValue(value, format) {
|
const timestamp = getDateTimestamp(value);
|
if (timestamp === null) return value;
|
return dayjs(timestamp).startOf(getDateTimeUnit(format)).valueOf();
|
}
|
function getTimePickerValue(value, format = 'HH:mm:ss') {
|
if (value === null || value === undefined || value === '') return value;
|
if (typeof value === 'string' && /^\d{1,2}:\d{1,2}(?::\d{1,2})?$/.test(value.trim())) return value;
|
const timestamp = getDateTimestamp(value);
|
if (timestamp === null) return value;
|
return dayjs(timestamp).format(format || 'HH:mm:ss');
|
}
|
function getDateTimestamp(value) {
|
if (value === null || value === undefined || value === '') return null;
|
if (typeof value === 'number') return Number.isNaN(value) ? null : value;
|
if (value instanceof Date) return dayjs(value).isValid() ? dayjs(value).valueOf() : null;
|
if (typeof value !== 'string') {
|
const date = dayjs(value);
|
return date.isValid() ? date.valueOf() : null;
|
}
|
const dateText = value.trim();
|
if (!dateText) return null;
|
if (/^\d+$/.test(dateText)) {
|
const timestamp = Number(dateText);
|
return dateText.length === 10 ? timestamp * 1000 : timestamp;
|
}
|
const parsedDate = parseDateText(dateText);
|
return parsedDate?.isValid() ? parsedDate.valueOf() : null;
|
}
|
function parseDateText(value) {
|
const match = value.replaceAll('/', '-').match(/^(\d{4})-(\d{1,2})(?:-(\d{1,2}))?(?:[ T](\d{1,2})(?::(\d{1,2})(?::(\d{1,2}))?)?)?/);
|
if (match) {
|
const [, year, month, day = '1', hour = '0', minute = '0', second = '0'] = match;
|
return dayjs(new Date(Number(year), Number(month) - 1, Number(day), Number(hour), Number(minute), Number(second)));
|
}
|
const date = dayjs(value);
|
if (date.isValid()) return date;
|
return dayjs(value.replace(' ', 'T'));
|
}
|
function handleRelation(field) {
|
if (!field) return;
|
const currRelations = state.relations;
|
for (const key in currRelations) {
|
if (key === field) {
|
for (let i = 0; i < currRelations[key].length; i++) {
|
const e = currRelations[key][i];
|
const vModel = e.realVModel || e.__vModel__;
|
const config = e.__config__;
|
const jnpfKey = config.jnpfKey;
|
let defaultValue: any = null;
|
if (
|
['cascader', 'checkbox'].includes(jnpfKey) ||
|
(['popupSelect', 'popupTableSelect', 'select', 'treeSelect', 'userSelect'].includes(jnpfKey) && e.multiple)
|
) {
|
defaultValue = [];
|
}
|
if (vModel.includes('-')) {
|
// 子表字段
|
const tableVModel = vModel.split('-')[0];
|
unref(state.tableRefs[tableVModel])?.tableRef && unref(state.tableRefs[tableVModel]).tableRef.handleRelationForParent(e, defaultValue);
|
} else {
|
setFormData(e.__vModel__, defaultValue);
|
if (e.opType === 'setOptions') {
|
const query = { paramList: getParamList(config.templateJson, state.formData) };
|
getDataInterfaceRes(config.propsUrl, query)
|
.then((res) => {
|
const realData = res.data;
|
setFieldOptions(e.__vModel__, realData);
|
setDefaultFirstOption(e, realData);
|
if (e.__config__.jnpfKey === 'checkbox') {
|
sessionStorage.setItem(`${e.__config__.jnpfKey}_${e.__config__.label}`, JSON.stringify(realData));
|
}
|
})
|
.catch(() => {
|
setFieldOptions(e.__vModel__, []);
|
});
|
}
|
if (e.opType === 'setUserOptions') {
|
const value = state.formData[e.relationField] || [];
|
comSet('ableRelationIds', e.__vModel__, Array.isArray(value) ? value : [value]);
|
}
|
if (e.opType === 'setStartTime') {
|
const value = state.formData[e.__config__.startRelationField] || null;
|
comSet('startTime', e.__vModel__, value);
|
}
|
if (e.opType === 'setEndTime') {
|
const value = state.formData[e.__config__.endRelationField] || null;
|
comSet('endTime', e.__vModel__, value);
|
}
|
}
|
}
|
}
|
}
|
}
|
function handleDefaultRelation(field) {
|
if (!field) return;
|
const currRelations = state.relations;
|
for (const key in currRelations) {
|
if (key === field) {
|
for (let i = 0; i < currRelations[key].length; i++) {
|
const e = currRelations[key][i];
|
const vModel = e.realVModel || e.__vModel__;
|
if (vModel.includes('-')) {
|
const tableVModel = vModel.split('-')[0];
|
unref(state.tableRefs[tableVModel])?.tableRef && unref(state.tableRefs[tableVModel]).tableRef.handleRelationForParent(e, '', true);
|
} else {
|
if (e.opType === 'setUserOptions') {
|
const value = state.formData[e.relationField] || [];
|
comSet('ableRelationIds', e.__vModel__, Array.isArray(value) ? value : [value]);
|
}
|
if (e.opType === 'setStartTime') {
|
const value = state.formData[e.__config__.startRelationField] || null;
|
comSet('startTime', e.__vModel__, value);
|
}
|
if (e.opType === 'setEndTime') {
|
const value = state.formData[e.__config__.endRelationField] || null;
|
comSet('endTime', e.__vModel__, value);
|
}
|
}
|
}
|
}
|
}
|
}
|
function rebuildFormRules() {
|
state.formRules = {};
|
buildRules(state.formConfCopy.fields);
|
}
|
function setFormData(prop, value, rowIndex?) {
|
if (!prop) return;
|
const isChildTable = prop.includes('.');
|
if (isChildTable) {
|
const [tableField, childField] = prop.split('.');
|
if (!tableField || !childField) return;
|
|
const updateTableFormData = () => {
|
const tableRef = unref(state.tableRefs[tableField])?.tableRef;
|
if (!tableRef) return false;
|
tableRef.setTableFormData(childField, value, rowIndex);
|
return true;
|
};
|
if (!updateTableFormData()) nextTick(updateTableFormData);
|
} else {
|
if (state.formData[prop] === value) return;
|
comSet('defaultValue', prop, value);
|
state.formData[prop] = value;
|
nextTick(() => {
|
handleRelation(prop);
|
});
|
}
|
}
|
function setShowOrHide(prop, value, rowIndex?) {
|
const newVal = !!value;
|
if (isReviewControlKey(prop)) {
|
setReviewVisibility(newVal);
|
return;
|
}
|
const isChildTable = prop.includes('.');
|
if (isChildTable) {
|
const [tableField, childField] = prop.split('.');
|
if (!tableField || !childField) return;
|
|
if (!Number.isInteger(rowIndex)) updateFormConf(tableField, childField, !newVal);
|
|
const updateTableShowOrHide = () => {
|
const tableRef = unref(state.tableRefs[tableField])?.tableRef;
|
tableRef?.setTableShowOrHide(childField, !newVal, rowIndex);
|
};
|
updateTableShowOrHide();
|
nextTick(updateTableShowOrHide);
|
} else {
|
comSet('noShow', prop, !newVal);
|
}
|
}
|
function isReviewVisible() {
|
return !!props.formConf.hasReviewBtn && !props.formConf.reviewBtnConfig?.noShow;
|
}
|
function isReviewRequired(visible = reviewVisible.value) {
|
return visible && !props.formConf.reviewBtnConfig?.biz_review_optional;
|
}
|
function isReviewControlKey(prop) {
|
return !!prop && prop === props.formConf.reviewBtnConfig?.controlKey;
|
}
|
function setReviewVisibility(visible) {
|
if (!props.formConf.hasReviewBtn) return;
|
reviewVisible.value = visible;
|
state.formConfCopy.reviewBtnConfig = state.formConfCopy.reviewBtnConfig || {};
|
state.formConfCopy.reviewBtnConfig.noShow = !visible;
|
reviewPassed.value = !isReviewRequired(visible);
|
emit('review-visibility-change', visible);
|
emit('review-status-change', reviewPassed.value);
|
}
|
function updateFormConf(table, prop, value) {
|
const loop = (list) => {
|
if (!list) return;
|
for (const data of list) {
|
if (data?.__vModel__ && data?.__vModel__ == table) {
|
for (let j = 0; j < data.__config__.children.length; j++) {
|
const item = data.__config__.children[j];
|
if (item.__vModel__ && item.__vModel__ == prop) item.__config__.noShow = value;
|
}
|
break;
|
}
|
if (data?.__config__?.children && Array.isArray(data.__config__.children)) {
|
loop(data.__config__.children);
|
}
|
}
|
};
|
loop(state.formConfCopy.fields);
|
}
|
function getFormComponent(prop) {
|
let component: any = null;
|
const loop = (list) => {
|
if (!list || component) return;
|
for (const item of list) {
|
const config = item?.__config__;
|
if (item?.__vModel__ && config) {
|
const realVModel = config.isSubTable ? `${config.parentVModel}-${item.__vModel__}` : item.__vModel__;
|
if (item.__vModel__ === prop || realVModel === prop || realVModel.replace('-', '.') === prop) {
|
component = item;
|
return;
|
}
|
}
|
if (config?.children && Array.isArray(config.children)) loop(config.children);
|
}
|
};
|
loop(state.formConfCopy.fields);
|
return component;
|
}
|
function setRequired(prop, value) {
|
const newVal = !!value;
|
const isChildTable = prop.includes('.');
|
if (!isChildTable) {
|
comSet('required', prop, newVal);
|
rebuildFormRules();
|
}
|
}
|
function setDisabled(prop, value, rowIndex?) {
|
const newVal = !!value;
|
const isChildTable = prop.includes('.');
|
if (isChildTable) {
|
const [tableField, childField] = prop.split('.');
|
if (!tableField || !childField) return;
|
|
// Keep the column config in sync so calls made during onLoad also
|
// affect rows created after the child table has mounted.
|
if (!Number.isInteger(rowIndex)) {
|
const component = getFormComponent(prop);
|
if (component) component.disabled = newVal;
|
}
|
|
const updateTableDisabled = () => {
|
const tableRef = unref(state.tableRefs[tableField])?.tableRef;
|
tableRef?.setTableDisabled(childField, newVal, rowIndex);
|
};
|
updateTableDisabled();
|
nextTick(updateTableDisabled);
|
} else {
|
comSet('disabled', prop, newVal);
|
}
|
}
|
function setFieldOptions(prop, value) {
|
const newVal = Array.isArray(value) ? value : [];
|
const isChildTable = prop.includes('.');
|
if (!isChildTable) {
|
comSet('options', prop, newVal);
|
}
|
}
|
function isEmptyValue(value) {
|
return value === null || value === undefined || value === '' || (Array.isArray(value) && value.length === 0);
|
}
|
function getEmptyComponentValue(cur) {
|
const jnpfKey = cur.__config__?.jnpfKey;
|
if (['cascader', 'checkbox'].includes(jnpfKey)) return [];
|
if (['popupSelect', 'popupTableSelect', 'select', 'treeSelect', 'userSelect'].includes(jnpfKey) && cur.multiple) return [];
|
return undefined;
|
}
|
function getCurrentDefaultValue(cur) {
|
const config = cur.__config__;
|
const userInfo: any = userStore.getUserInfo || {};
|
if (!config?.defaultCurrent) return config?.defaultValue;
|
if (config.jnpfKey === 'datePicker') return dayjs(new Date()).startOf(getDateTimeUnit(cur.format)).valueOf();
|
if (config.jnpfKey === 'timePicker') return dayjs(new Date()).format(cur.format || 'HH:mm:ss');
|
if (config.jnpfKey === 'organizeSelect' && userInfo?.organizeIds?.length) return cur.multiple ? userInfo.organizeIds : userInfo.organizeId;
|
if (config.jnpfKey === 'userSelect' && userInfo?.userId) return cur.multiple ? [userInfo.userId] : userInfo.userId;
|
if (config.jnpfKey === 'usersSelect' && userInfo?.userId) return [`${userInfo.userId}--user`];
|
if (config.jnpfKey === 'posSelect' && userInfo?.positionIds?.length) return cur.multiple ? userInfo.positionIds : userInfo.positionId;
|
if (config.jnpfKey === 'sign' && userInfo?.signImg) return userInfo.signImg;
|
return config.defaultValue;
|
}
|
function shouldSkipDefaultValueInit(cur) {
|
return !!cur.__config__?.__skipDefaultValueInit;
|
}
|
function getFieldByVModel(vModel) {
|
let target;
|
const loop = (list) => {
|
if (!Array.isArray(list) || target) return;
|
for (const item of list) {
|
if (item.__vModel__ === vModel) {
|
target = item;
|
break;
|
}
|
if (Array.isArray(item.__config__?.children) && item.__config__.jnpfKey !== 'table') loop(item.__config__.children);
|
if (target) break;
|
}
|
};
|
loop(state.formConfCopy.fields);
|
return target;
|
}
|
function isControlledStepsConfig(config) {
|
return config?.jnpfKey === 'steps' && !!config.currentStepField && Array.isArray(config.children);
|
}
|
function forEachReachedStepChild(config, callback) {
|
if (!isControlledStepsConfig(config)) return;
|
config.children.forEach((step, index) => {
|
if (!isControlledStepReached(config, index)) return;
|
callback(step);
|
});
|
}
|
function hasFieldInComponentList(list, vModel) {
|
if (!Array.isArray(list)) return false;
|
return list.some((item) => {
|
if (item.__vModel__ === vModel) return true;
|
if (Array.isArray(item.__config__?.children)) return hasFieldInComponentList(item.__config__.children, vModel);
|
return false;
|
});
|
}
|
function isUnreachedControlledStepField(vModel) {
|
let isUnreached = false;
|
const loop = (list) => {
|
if (!Array.isArray(list) || isUnreached) return;
|
for (const item of list) {
|
const config = item.__config__;
|
if (isControlledStepsConfig(config)) {
|
config.children.forEach((step, index) => {
|
if (!isControlledStepReached(config, index) && hasFieldInComponentList(step.__config__?.children || [], vModel)) isUnreached = true;
|
});
|
}
|
if (Array.isArray(config?.children)) loop(config.children);
|
if (isUnreached) break;
|
}
|
};
|
loop(state.formConfCopy.fields);
|
return isUnreached;
|
}
|
function getControlledStepInitKey(config) {
|
if (isControlledStepAllFinished(config)) return `finished-${config.children?.length || 0}`;
|
return String(getControlledStepIndex(config));
|
}
|
function initReachedControlledStepData(config) {
|
if (!isControlledStepsConfig(config)) return false;
|
const initKey = getControlledStepInitKey(config);
|
if (config.__initializedStepValue === initKey) return false;
|
config.__initializedStepValue = initKey;
|
forEachReachedStepChild(config, (step) => {
|
initFormDataList(step.__config__?.children || [], true);
|
buildRelations(step.__config__?.children || [], state.relations);
|
buildOptions(step.__config__?.children || []);
|
initDefaultRelationData(step.__config__?.children || []);
|
});
|
return true;
|
}
|
function getOptionValue(item, propsConfig) {
|
if (!item) return undefined;
|
const valueKey = propsConfig?.value || 'id';
|
return item[valueKey];
|
}
|
function setDefaultFirstOption(cur, options) {
|
const config = cur.__config__;
|
if (config.jnpfKey !== 'select' || !config.defaultFirst || !cur.__vModel__) return;
|
if (shouldSkipDefaultValueInit(cur)) return;
|
const list = Array.isArray(options) ? options : [];
|
if (!list.length || !isEmptyValue(state.formData[cur.__vModel__])) return;
|
const firstValue = getOptionValue(list[0], cur.props);
|
if (firstValue === undefined || firstValue === null || firstValue === '') return;
|
setFormData(cur.__vModel__, cur.multiple ? [firstValue] : firstValue);
|
}
|
function isComponentPropMatched(item, prop) {
|
return item.__vModel__ === prop || item.controlKey === prop || item.__config__?.formId === prop;
|
}
|
function comSet(field, prop, value) {
|
if (!prop) return;
|
const loop = (list) => {
|
for (const item of list) {
|
if (isComponentPropMatched(item, prop)) {
|
switch (field) {
|
case 'ableRelationIds': {
|
item[field] = value;
|
break;
|
}
|
case 'disabled': {
|
item[field] = value;
|
break;
|
}
|
case 'endTime': {
|
item[field] = value;
|
break;
|
}
|
case 'options': {
|
if (dyOptionsList.includes(item.__config__.jnpfKey)) item.options = value;
|
break;
|
}
|
case 'startTime': {
|
item[field] = value;
|
break;
|
}
|
default: {
|
item.__config__[field] = value;
|
break;
|
}
|
}
|
item.__config__.renderKey = `${Date.now()}${item.__vModel__ || item.controlKey || item.__config__?.formId || ''}`;
|
break;
|
}
|
if (item.__config__ && item.__config__.jnpfKey !== 'table' && item.__config__.children && Array.isArray(item.__config__.children)) {
|
loop(item.__config__.children);
|
}
|
}
|
};
|
loop(state.formConfCopy.fields);
|
}
|
function initCss() {
|
if (document.getElementById('customStyle')) document.getElementById('customStyle')?.remove();
|
const head: any = document.getElementsByTagName('head')[0];
|
const style = document.createElement('style');
|
style.type = 'text/css';
|
style.id = 'customStyle';
|
style.innerText = buildCSS(props.formConf.classJson);
|
head.append(style);
|
}
|
function buildCSS(str) {
|
str = str.trim();
|
let newStr = '';
|
const cut = str.split('}');
|
cut.forEach((item) => {
|
if (item) {
|
item = `.${unref(getFormName)} ${item}}`;
|
newStr += item;
|
}
|
});
|
return newStr;
|
}
|
function initFormData(componentList) {
|
generatorStore.setRelationData({});
|
initFormDataList(componentList);
|
}
|
function initFormDataList(componentList, onlyEmpty = false) {
|
componentList.forEach((cur) => {
|
const config = cur.__config__;
|
if (isControlledStepsConfig(config)) {
|
config.__initializedStepValue = getControlledStepInitKey(config);
|
forEachReachedStepChild(config, (step) => initFormDataList(step.__config__?.children || [], onlyEmpty));
|
return;
|
}
|
if (cur.__vModel__) {
|
if (shouldSkipDefaultValueInit(cur)) {
|
state.formData[cur.__vModel__] = config.defaultValue;
|
return;
|
}
|
const hasValue = Object.prototype.hasOwnProperty.call(state.formData, cur.__vModel__) && !isEmptyValue(state.formData[cur.__vModel__]);
|
if (onlyEmpty && hasValue) return;
|
const value = onlyEmpty && config.defaultCurrent ? getCurrentDefaultValue(cur) : config.defaultValue;
|
config.defaultValue = value;
|
state.formData[cur.__vModel__] = value;
|
}
|
if (cur.__config__.jnpfKey == 'table') return;
|
if (config.children) initFormDataList(config.children, onlyEmpty);
|
});
|
}
|
function initRelationForm(componentList) {
|
componentList.forEach((cur) => {
|
const config = cur.__config__;
|
if (config.jnpfKey == 'relationFormAttr' || config.jnpfKey == 'popupAttr') {
|
const relationKey = cur.relationField.split('_jnpfTable_')[0];
|
componentList.forEach((item) => {
|
const noVisibility = Array.isArray(item.__config__.visibility) && !item.__config__.visibility.includes('pc');
|
if (relationKey == item.__vModel__ && (noVisibility || !!item.__config__.noShow) && !cur.__vModel__) {
|
cur.__config__.noShow = true;
|
}
|
});
|
}
|
if (cur.__config__.children && cur.__config__.children.length) initRelationForm(cur.__config__.children);
|
});
|
}
|
function buildRules(componentList) {
|
componentList.forEach((cur) => {
|
const config = cloneDeep(cur.__config__);
|
if (isControlledStepsConfig(config)) {
|
forEachReachedStepChild(cur.__config__, (step) => buildRules(step.__config__?.children || []));
|
return;
|
}
|
if (config.isDisplayOnly) {
|
if (cur.__vModel__) delete state.formRules[cur.__vModel__];
|
return;
|
}
|
if (!Array.isArray(config.regList)) config.regList = [];
|
if (config.required) {
|
const label = config.labelI18nCode ? $t(config.labelI18nCode, config.label) : config.label;
|
const placeholder = cur.placeholderI18nCode ? $t(cur.placeholderI18nCode, cur.placeholder) : cur.placeholder;
|
const required: any = { required: config.required, message: placeholder };
|
if (Array.isArray(config.defaultValue)) {
|
required.type = 'array';
|
required.message = `${$t('sys.validate.arrayRequiredPrefix')}${label}`;
|
}
|
!required.message && (required.message = `${label}${$t('sys.validate.textRequiredSuffix')}`);
|
config.regList.push(required);
|
}
|
state.formRules[cur.__vModel__] = config.regList.map((item) => {
|
if (item.validatorType === 'customFunc') return buildValidateFuncRule(item, config, cur);
|
item.pattern && isRegExp(item.pattern) && (item.pattern = eval(item.pattern));
|
item.trigger = config.trigger || 'blur';
|
if (item.messageI18nCode) item.message = $t(item.messageI18nCode, item.message);
|
return item;
|
});
|
if (config.children && config.jnpfKey !== 'table') buildRules(config.children);
|
});
|
}
|
function buildValidateFuncRule(item, config, cur) {
|
const message = item.messageI18nCode ? $t(item.messageI18nCode, item.message) : item.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(item.validatorFunc);
|
if (!func) throw message || '验证函数配置错误';
|
let res;
|
try {
|
res = await func({ value, formData: state.formData, field: cur.__vModel__, item: cur, 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 buildOptions(componentList) {
|
componentList.forEach((cur) => {
|
const config = cur.__config__;
|
if (isControlledStepsConfig(config)) {
|
forEachReachedStepChild(config, (step) => buildOptions(step.__config__?.children || []));
|
return;
|
}
|
if (dyOptionsList.includes(config.jnpfKey)) {
|
if (config.dataType === 'dictionary' && config.dictionaryType) {
|
cur.options = [];
|
baseStore.getDicDataSelector(config.dictionaryType).then((res) => {
|
cur.options = res;
|
state.options[`${cur.__vModel__}Options`] = cur.options;
|
setDefaultFirstOption(cur, cur.options);
|
});
|
} else if (config.dataType === 'dynamic' && config.propsUrl) {
|
cur.options = [];
|
const query = { paramList: getParamList(config.templateJson, state.formData) };
|
getDataInterfaceRes(config.propsUrl, query)
|
.then((res) => {
|
cur.options = Array.isArray(res.data) ? res.data : [];
|
state.options[`${cur.__vModel__}Options`] = cur.options;
|
setDefaultFirstOption(cur, cur.options);
|
})
|
.catch(() => {
|
cur.options = [];
|
state.options[`${cur.__vModel__}Options`] = [];
|
});
|
} else if (config.dataType === 'formData') {
|
cur.options = getFormDataOptions(config, state.formData);
|
state.options[`${cur.__vModel__}Options`] = cur.options;
|
setDefaultFirstOption(cur, cur.options);
|
} else {
|
state.options[`${cur.__vModel__}Options`] = cur.options;
|
setDefaultFirstOption(cur, cur.options);
|
}
|
}
|
if (config.children && config.jnpfKey !== 'table') buildOptions(config.children);
|
});
|
}
|
function refreshFormDataOptions(componentList) {
|
componentList.forEach((cur) => {
|
const config = cur.__config__;
|
if (config.dataType === 'formData' && dyOptionsList.includes(config.jnpfKey)) {
|
cur.options = getFormDataOptions(config, state.formData);
|
state.options[`${cur.__vModel__}Options`] = cur.options;
|
}
|
if (config.children && config.jnpfKey !== 'table') refreshFormDataOptions(config.children);
|
});
|
}
|
function buildRelations(componentList, relations) {
|
componentList.forEach((cur) => {
|
const config = cur.__config__;
|
if (isControlledStepsConfig(config)) {
|
forEachReachedStepChild(config, (step) => buildRelations(step.__config__?.children || [], relations));
|
return;
|
}
|
if (dyOptionsList.includes(config.jnpfKey) && config.dataType === 'dynamic' && config.templateJson && config.templateJson.length) {
|
for (let i = 0; i < config.templateJson.length; i++) {
|
const e = config.templateJson[i];
|
if (e.relationField && e.sourceType == 1) {
|
const item = {
|
...cur,
|
realVModel: cur.__config__.isSubTable ? `${cur.__config__.parentVModel}-${cur.__vModel__}` : cur.__vModel__,
|
opType: 'setOptions',
|
};
|
if (Object.prototype.hasOwnProperty.call(relations, e.relationField)) {
|
const boo = relations[e.relationField].some((o) => o.realVModel === cur.realVModel);
|
if (!boo) {
|
relations[e.relationField].push(item);
|
}
|
} else {
|
relations[e.relationField] = [item];
|
}
|
}
|
}
|
}
|
if (config.jnpfKey === 'userSelect' && ['group', 'org', 'pos', 'role'].includes(cur.selectType) && cur.relationField) {
|
const item = {
|
...cur,
|
realVModel: cur.__config__.isSubTable ? `${cur.__config__.parentVModel}-${cur.__vModel__}` : cur.__vModel__,
|
opType: 'setUserOptions',
|
};
|
if (Object.prototype.hasOwnProperty.call(relations, cur.relationField)) {
|
const boo = relations[cur.relationField].some((o) => o.realVModel === cur.realVModel);
|
if (!boo) relations[cur.relationField].push(item);
|
} else {
|
relations[cur.relationField] = [item];
|
}
|
}
|
if (config.jnpfKey === 'popupSelect' && cur.templateJson && cur.templateJson.length) {
|
for (let i = 0; i < cur.templateJson.length; i++) {
|
const e = cur.templateJson[i];
|
if (e.relationField && e.sourceType == 1) {
|
const item = {
|
...cur,
|
realVModel: cur.__config__.isSubTable ? `${cur.__config__.parentVModel}-${cur.__vModel__}` : cur.__vModel__,
|
opType: 'setPopupOptions',
|
};
|
if (Object.prototype.hasOwnProperty.call(relations, e.relationField)) {
|
const boo = relations[e.relationField].some((o) => o.realVModel === cur.realVModel);
|
if (!boo) {
|
relations[e.relationField].push(item);
|
}
|
} else {
|
relations[e.relationField] = [item];
|
}
|
}
|
}
|
}
|
if (config.jnpfKey === 'datePicker') {
|
const currDate = cur.__config__.defaultCurrent && cur.__config__.defaultValue ? cur.__config__.defaultValue : Date.now();
|
if (config.startTimeRule) {
|
if (config.startTimeType == 1) cur.startTime = config.startTimeValue;
|
if (config.startTimeType == 2 && config.startRelationField) {
|
const item = {
|
...cur,
|
realVModel: cur.__config__.isSubTable ? `${cur.__config__.parentVModel}-${cur.__vModel__}` : cur.__vModel__,
|
opType: 'setStartTime',
|
};
|
if (Object.prototype.hasOwnProperty.call(relations, cur.__config__.startRelationField)) {
|
const boo = relations[cur.__config__.startRelationField].some((o) => o.realVModel === cur.realVModel);
|
if (!boo) relations[cur.__config__.startRelationField].push(item);
|
} else {
|
relations[cur.__config__.startRelationField] = [item];
|
}
|
}
|
if (config.startTimeType == 3) cur.startTime = currDate;
|
if (config.startTimeType == 4 || config.startTimeType == 5) {
|
const type = getTimeUnit(config.startTimeTarget);
|
const method = config.startTimeType == 4 ? 'subtract' : 'add';
|
const startTime = dayjs()[method](config.startTimeValue, type);
|
let realStartTime = startTime.startOf(getDateTimeUnit(cur.format)).valueOf();
|
if (config.startTimeTarget == 4) realStartTime = startTime.startOf('minute').valueOf();
|
if (config.startTimeTarget == 5) realStartTime = startTime.startOf('second').valueOf();
|
if (config.startTimeTarget == 6) realStartTime = startTime.valueOf();
|
cur.startTime = realStartTime;
|
}
|
}
|
if (config.endTimeRule) {
|
if (config.endTimeType == 1) cur.endTime = config.endTimeValue;
|
if (config.endTimeType == 2 && config.endRelationField) {
|
const item = {
|
...cur,
|
realVModel: cur.__config__.isSubTable ? `${cur.__config__.parentVModel}-${cur.__vModel__}` : cur.__vModel__,
|
opType: 'setEndTime',
|
};
|
if (Object.prototype.hasOwnProperty.call(relations, cur.__config__.endRelationField)) {
|
const boo = relations[cur.__config__.endRelationField].some((o) => o.realVModel === cur.realVModel);
|
if (!boo) relations[cur.__config__.endRelationField].push(item);
|
} else {
|
relations[cur.__config__.endRelationField] = [item];
|
}
|
}
|
if (config.endTimeType == 3) cur.endTime = currDate;
|
if (config.endTimeType == 4 || config.endTimeType == 5) {
|
const type = getTimeUnit(config.endTimeTarget);
|
const method = config.endTimeType == 4 ? 'subtract' : 'add';
|
const endTime = dayjs()[method](config.endTimeValue, type);
|
let realEndTime = endTime.endOf(getDateTimeUnit(cur.format)).valueOf();
|
if (config.endTimeTarget == 4) realEndTime = endTime.endOf('minute').valueOf();
|
if (config.endTimeTarget == 5) realEndTime = endTime.endOf('second').valueOf();
|
if (config.endTimeTarget == 6) realEndTime = endTime.valueOf();
|
cur.endTime = realEndTime;
|
}
|
}
|
}
|
if (config.jnpfKey === 'timePicker') {
|
const currTime = cur.__config__.defaultCurrent && cur.__config__.defaultValue ? cur.__config__.defaultValue : dayjs().format(cur.format);
|
if (config.startTimeRule) {
|
if (config.startTimeType == 1) cur.startTime = config.startTimeValue || null;
|
if (config.startTimeType == 2 && config.startRelationField) {
|
const item = {
|
...cur,
|
realVModel: cur.__config__.isSubTable ? `${cur.__config__.parentVModel}-${cur.__vModel__}` : cur.__vModel__,
|
opType: 'setStartTime',
|
};
|
if (Object.prototype.hasOwnProperty.call(relations, cur.__config__.startRelationField)) {
|
const boo = relations[cur.__config__.startRelationField].some((o) => o.realVModel === cur.realVModel);
|
if (!boo) relations[cur.__config__.startRelationField].push(item);
|
} else {
|
relations[cur.__config__.startRelationField] = [item];
|
}
|
}
|
if (config.startTimeType == 3) cur.startTime = currTime;
|
if (config.startTimeType == 4 || config.startTimeType == 5) {
|
const type = getTimeUnit(config.startTimeTarget + 3);
|
const method = config.startTimeType == 4 ? 'subtract' : 'add';
|
const startTime = dayjs()[method](config.startTimeValue, type).format(cur.format);
|
cur.startTime = startTime;
|
}
|
}
|
if (config.endTimeRule) {
|
if (config.endTimeType == 1) cur.endTime = config.endTimeValue || null;
|
if (config.endTimeType == 2 && config.endRelationField) {
|
const item = {
|
...cur,
|
realVModel: cur.__config__.isSubTable ? `${cur.__config__.parentVModel}-${cur.__vModel__}` : cur.__vModel__,
|
opType: 'setEndTime',
|
};
|
if (Object.prototype.hasOwnProperty.call(relations, cur.__config__.endRelationField)) {
|
const boo = relations[cur.__config__.endRelationField].some((o) => o.realVModel === cur.realVModel);
|
if (!boo) relations[cur.__config__.endRelationField].push(item);
|
} else {
|
relations[cur.__config__.endRelationField] = [item];
|
}
|
}
|
if (config.endTimeType == 3) cur.endTime = currTime;
|
if (config.endTimeType == 4 || config.endTimeType == 5) {
|
const type = getTimeUnit(config.endTimeTarget + 3);
|
const method = config.endTimeType == 4 ? 'subtract' : 'add';
|
const endTime = dayjs()[method](config.endTimeValue, type).format(cur.format);
|
cur.endTime = endTime;
|
}
|
}
|
}
|
if (config.children) buildRelations(config.children, relations);
|
});
|
}
|
function initDefaultRelationData(componentList) {
|
componentList.forEach((cur) => {
|
const config = cur.__config__;
|
if (isControlledStepsConfig(config)) {
|
forEachReachedStepChild(config, (step) => initDefaultRelationData(step.__config__?.children || []));
|
return;
|
}
|
handleDefaultRelation(cur.__vModel__);
|
if (cur.__config__.children) initDefaultRelationData(cur.__config__.children);
|
});
|
}
|
async function initLockedBillNumbers(componentList) {
|
if (props.isPreview || props.isShortLink || !props.modelId || state.formConfCopy.formData?.id) return;
|
const fields: any[] = [];
|
const loop = (list) => {
|
if (!Array.isArray(list)) return;
|
for (const item of list) {
|
const config = item?.__config__;
|
if (!config) continue;
|
if (config.jnpfKey === 'billRule' && config.lockAndShow && item.__vModel__ && !config.isSubTable) fields.push(item);
|
if (config.jnpfKey !== 'table') loop(config.children);
|
}
|
};
|
loop(componentList);
|
await Promise.all(
|
fields.map(async (field) => {
|
if (!isEmptyValue(state.formData[field.__vModel__])) return;
|
const res = await lockBillNumber(props.modelId, {
|
field: field.__vModel__,
|
data: state.formData,
|
onlineUtilsOpen: !!props.isOnlineUtilsOpen,
|
});
|
if (res?.data?.number) setFormData(field.__vModel__, res.data.number);
|
}),
|
);
|
}
|
function buildFormIdObj(componentList) {
|
state.formIdObj = {};
|
const loop = (list) => {
|
if (!list) return;
|
for (const data of list) {
|
if (data?.__vModel__ && data.__config__) {
|
const isSubTable = data.__config__.isSubTable;
|
const __vModel__ = isSubTable ? `${data.__config__.parentVModel}-${data.__vModel__}` : data.__vModel__;
|
state.formIdObj[data.__config__.formId] = { __vModel__, jnpfKey: data.__config__.jnpfKey };
|
}
|
if (data?.__config__?.children && Array.isArray(data.__config__.children)) loop(data.__config__.children);
|
}
|
};
|
loop(componentList);
|
}
|
function onLoad() {
|
if (!state.formConfCopy || !state.formConfCopy.funcs || !state.formConfCopy.funcs.onLoad) return;
|
const onLoadFunc: any = getScriptFunc(state.formConfCopy.funcs.onLoad);
|
if (!onLoadFunc) return;
|
onLoadFunc(unref(getParameter));
|
}
|
function beforeSubmit() {
|
if (!state.formConfCopy || !state.formConfCopy.funcs || !state.formConfCopy.funcs.beforeSubmit) return Promise.resolve();
|
const func: any = getScriptFunc(state.formConfCopy.funcs.beforeSubmit);
|
if (!func) return Promise.resolve();
|
return func(unref(getParameter));
|
}
|
function getButtonText(type: 'confirm' | 'review') {
|
const isConfirm = type === 'confirm';
|
const text = isConfirm ? props.formConf.confirmButtonText : props.formConf.reviewButtonText;
|
const i18nCode = isConfirm ? props.formConf.confirmButtonTextI18nCode : props.formConf.reviewButtonTextI18nCode;
|
const fallback = isConfirm ? 'common.okText' : 'common.reviewText';
|
return i18nCode ? $t(i18nCode, text) : text || $t(fallback);
|
}
|
function getSignMetaData(type: 'confirm' | 'review') {
|
return {
|
biz_button: getButtonText(type),
|
biz_data: [buildDisplayOnlySubmitData(state.formConfCopy.fields, state.formData)],
|
biz_form_id: props.modelId ? String(props.modelId) : '',
|
biz_module: '',
|
biz_title: '',
|
is_biz_form: true,
|
is_review_button: type === 'review',
|
};
|
}
|
function confirmSign() {
|
const confirmConfig = props.formConf.confirmBtnConfig;
|
if (!confirmConfig?.biz_sign_enabled) return Promise.resolve(true);
|
const utils = injectedOnlineUtils || onlineUtils;
|
return new Promise<boolean>((resolve) => {
|
utils.sign({
|
isFaceToFace: false,
|
metaData: getSignMetaData('confirm'),
|
onCancel: () => resolve(false),
|
onSubmit: (signData) => {
|
if (confirmConfig.biz_sign_field) setFormData(confirmConfig.biz_sign_field, signData?.biz_sign);
|
resolve(true);
|
},
|
});
|
});
|
}
|
function afterSubmit() {
|
if (!state.formConfCopy || !state.formConfCopy.funcs || !state.formConfCopy.funcs.afterSubmit) return;
|
const func: any = getScriptFunc(state.formConfCopy.funcs.afterSubmit);
|
if (!func) return;
|
func(unref(getParameter));
|
}
|
async function handleReset() {
|
generatorStore.setRelationData({});
|
state.formConfCopy = cloneDeep(props.formConf);
|
normalizeVirtualFields(state.formConfCopy.fields);
|
reviewVisible.value = isReviewVisible();
|
reviewPassed.value = !isReviewRequired();
|
emit('review-visibility-change', reviewVisible.value);
|
emit('review-status-change', reviewPassed.value);
|
Object.keys(state.tableRefs).forEach((vModel) => {
|
unref(state.tableRefs[vModel]).tableRef && unref(state.tableRefs[vModel]).tableRef.resetTable();
|
});
|
nextTick(() => {
|
formElRef.value?.resetFields();
|
init();
|
});
|
}
|
function handleReview() {
|
const reviewConfig = props.formConf.reviewBtnConfig;
|
if (!reviewVisible.value || !reviewConfig?.biz_sign_enabled) return;
|
const utils = injectedOnlineUtils || onlineUtils;
|
utils.sign({
|
allowMyself: !!reviewConfig.biz_allow_myself,
|
isFaceToFace: true,
|
metaData: getSignMetaData('review'),
|
onSubmit: (signData) => {
|
if (reviewConfig.biz_sign_field) setFormData(reviewConfig.biz_sign_field, signData?.biz_sign);
|
if (reviewConfig.biz_user_id_field) setFormData(reviewConfig.biz_user_id_field, signData?.biz_user_id);
|
state.formConfCopy.disabled = true;
|
lockFormFields(state.formConfCopy.fields);
|
reviewPassed.value = true;
|
emit('review-status-change', true);
|
},
|
});
|
}
|
function lockFormFields(fields) {
|
if (!Array.isArray(fields)) return;
|
fields.forEach((field) => {
|
if (!field?.__config__) return;
|
if (field.__vModel__) field.disabled = true;
|
lockFormFields(field.__config__.children);
|
});
|
}
|
function checkTableData() {
|
let valid = true;
|
Object.keys(state.tableRefs).forEach((vModel) => {
|
if (isUnreachedControlledStepField(vModel)) return;
|
// The complete virtual table is removed from persistence data, so
|
// inherited database-field rules must not block the form submission.
|
if (isVirtualTable(getFieldByVModel(vModel))) return;
|
if (unref(state.tableRefs[vModel])?.tableRef) {
|
const res = unref(state.tableRefs[vModel]).tableRef.submit(); // 返回false或表单数据
|
res ? (state.formData[vModel] = res) : (valid = false);
|
}
|
});
|
return valid;
|
}
|
async function handleSubmit(isSave = false) {
|
if (!isSave && props.requireReview !== false && isReviewRequired() && !reviewPassed.value) return false;
|
isTableValid.value = checkTableData();
|
if (!isTableValid.value) return false;
|
try {
|
await formElRef.value?.validate();
|
} catch {
|
// 验证失败,Ant Design Vue 已经显示了错误信息
|
return false;
|
}
|
// 暂存不触发提交前置(beforeSubmit)
|
if (!isSave) {
|
try {
|
await beforeSubmit();
|
} catch {
|
// beforeSubmit 失败,阻止提交
|
return false;
|
}
|
const signed = await confirmSign();
|
if (!signed) return false;
|
}
|
await submit();
|
return true;
|
}
|
function getAuditDisplayFields(formData = state.formData) {
|
return buildAuditDisplayFields(state.formConfCopy.fields, { ...state.formData, ...formData }, state.auditSelectedValues, generatorStore.getRelationData);
|
}
|
async function submit() {
|
emit(
|
'submit',
|
buildDisplayOnlySubmitData(state.formConfCopy.fields, state.formData),
|
afterSubmit,
|
unref(getParameter),
|
getAuditDisplayFields(),
|
getAuditDisplayFields,
|
);
|
}
|
function init() {
|
initCss();
|
initFormData(state.formConfCopy.fields);
|
initRelationForm(state.formConfCopy.fields);
|
buildRules(state.formConfCopy.fields);
|
buildOptions(state.formConfCopy.fields);
|
buildRelations(state.formConfCopy.fields, state.relations);
|
buildFormIdObj(state.formConfCopy.fields);
|
initDefaultRelationData(state.formConfCopy.fields);
|
nextTick(() => {
|
onLoad();
|
});
|
initLockedBillNumbers(state.formConfCopy.fields).catch(() => undefined);
|
}
|
|
onMounted(() => {
|
const instance = getCurrentInstance();
|
state.tableRefs = instance?.refs;
|
});
|
watch(
|
() => state.formData,
|
() => refreshFormDataOptions(state.formConfCopy.fields),
|
{ deep: true },
|
);
|
onUnmounted(() => {
|
if (document.getElementById('customStyle')) document.getElementById('customStyle')?.remove();
|
});
|
|
init();
|
|
return () => {
|
return renderFrom();
|
};
|
},
|
});
|
</script>
|