2025-07-11 15:04:22 +08:00

300 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2025 Tencent. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { toRaw } from 'vue';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import { cloneDeep } from 'lodash-es';
import {
ChildConfig,
ContainerCommonConfig,
DaterangeConfig,
FilterFunction,
FormConfig,
FormState,
FormValue,
HtmlField,
Rule,
TabPaneConfig,
TypeFunction,
} from '../schema';
interface DefaultItem {
defaultValue: any;
type: string;
filter: string;
multiple: boolean;
}
const isTableSelect = (type?: string | TypeFunction) =>
typeof type === 'string' && ['table-select', 'tableSelect'].includes(type);
const asyncLoadConfig = (value: FormValue, initValue: FormValue, { asyncLoad, name, type }: HtmlField) => {
// 富文本配置了异步加载
if (type === 'html' && typeof asyncLoad === 'object' && typeof name !== 'undefined') {
asyncLoad.name = name;
value.asyncLoad = typeof initValue.asyncLoad === 'object' ? initValue.asyncLoad : asyncLoad;
}
};
const isMultipleValue = (type?: string | TypeFunction) =>
typeof type === 'string' &&
['checkbox-group', 'checkboxGroup', 'table', 'cascader', 'group-list', 'groupList'].includes(type);
const initItemsValue = (
mForm: FormState | undefined,
value: FormValue,
initValue: FormValue,
{ items, name, extensible }: any,
) => {
if (Array.isArray(initValue[name])) {
value[name] = initValue[name].map((v: any, index: number) => createValues(mForm, items, v, value[name]?.[index]));
} else {
value[name] = createValues(mForm, items, initValue[name], value[name]);
if (extensible) {
value[name] = Object.assign({}, initValue[name], value[name]);
}
}
};
const setValue = (mForm: FormState | undefined, value: FormValue, initValue: FormValue, item: any) => {
const { items, name, type, checkbox } = item;
// 值是数组, 有可能也有items配置所以不能放到getDefaultValue里赋值
if (isMultipleValue(type) || (type === 'tab' && item.dynamic)) {
value[name] = initValue[name] || [];
}
// 有子项继续递归,没有的话有初始值用初始值,没有初始值用默认值
if (items) {
initItemsValue(mForm, value, initValue, item);
} else {
value[name] = getDefaultValue(mForm, item as DefaultItem);
}
// 如果fieldset配置checkboxcheckbox的值保存在value中
if (type === 'fieldset' && checkbox) {
if (typeof value[name] === 'object') {
value[name].value = typeof initValue[name] === 'object' ? initValue[name].value || 0 : 0;
}
}
};
const initValueItem = function (
mForm: FormState | undefined,
item: ChildConfig | TabPaneConfig,
initValue: FormValue,
value: FormValue,
) {
const { items } = item as ContainerCommonConfig;
const { names } = item as DaterangeConfig;
const { type, name } = item as ChildConfig;
if (isTableSelect(type) && name) {
value[name] = initValue[name] || '';
return value;
}
asyncLoadConfig(value, initValue, item as HtmlField);
// 这种情况比较多,提前结束
if (name && !items && typeof initValue[name] !== 'undefined') {
if (typeof value[name] === 'undefined') {
if (type === 'number') {
value[name] = Number(initValue[name]);
} else {
value[name] = typeof initValue[name] === 'object' ? cloneDeep(initValue[name]) : initValue[name];
}
}
return value;
}
if (names) {
return names.forEach((n: string) => (value[n] = initValue[n] || ''));
}
if (!name) {
// 没有配置name直接跳过
return createValues(mForm, items, initValue, value);
}
setValue(mForm, value, initValue, item);
return value;
};
export const createValues = function (
mForm: FormState | undefined,
config: FormConfig | TabPaneConfig[] = [],
initValue: FormValue = {},
value: FormValue = {},
) {
if (Array.isArray(config)) {
config.forEach((item: ChildConfig | TabPaneConfig) => {
initValueItem(mForm, item, initValue, value);
});
}
return value;
};
const getDefaultValue = function (mForm: FormState | undefined, { defaultValue, type, filter, multiple }: DefaultItem) {
if (typeof defaultValue === 'function') {
return defaultValue(mForm);
}
// 如果直接设置为undefined在解析成js对象时会丢失这个配置所以用'undefined'代替
if (defaultValue === 'undefined') {
return undefined;
}
if (typeof defaultValue !== 'undefined') {
return defaultValue;
}
if (type === 'number' || filter === 'number') {
return 0;
}
if (['switch', 'checkbox'].includes(type)) {
return false;
}
if (multiple || type === 'number-range') {
return [];
}
return '';
};
export const filterFunction = <T = any>(
mForm: FormState | undefined,
config: T | FilterFunction<T> | undefined,
props: any,
) => {
if (typeof config === 'function') {
return (config as FilterFunction<T>)(mForm, {
values: mForm?.initValues || {},
model: props.model,
parent: mForm?.parentValues || {},
formValue: mForm?.values || props.model,
prop: props.prop,
config: props.config,
index: props.index,
});
}
return config;
};
export const display = function (mForm: FormState | undefined, config: any, props: any) {
if (config === 'expand') {
return config;
}
if (typeof config === 'function') {
return filterFunction(mForm, config, props);
}
if (config === false) {
return false;
}
return true;
};
export const getRules = function (mForm: FormState | undefined, rules: Rule[] | Rule = [], props: any) {
rules = cloneDeep(rules);
if (typeof rules === 'object' && !Array.isArray(rules)) {
rules = [rules];
}
return rules.map((item) => {
if (typeof item.validator === 'function') {
const fnc = item.validator;
(item as any).validator = (rule: any, value: any, callback: Function, source: any, options: any) =>
fnc(
{
rule,
value: props.config.names ? props.model : value,
callback,
source,
options,
},
{
values: mForm?.initValues || {},
model: props.model,
parent: mForm?.parentValues || {},
formValue: mForm?.values || props.model,
prop: props.prop,
config: props.config,
},
mForm,
);
}
return item;
});
};
export const initValue = async (
mForm: FormState | undefined,
{ initValues, config }: { initValues: FormValue; config: FormConfig },
) => {
if (!Array.isArray(config)) throw new Error('config应该为数组');
let valuesTmp = createValues(mForm, config, toRaw(initValues), {});
const [firstForm] = config as [ContainerCommonConfig];
if (firstForm && typeof firstForm.onInitValue === 'function') {
valuesTmp = await firstForm.onInitValue(mForm, {
formValue: valuesTmp,
initValue: initValues,
});
}
return valuesTmp || {};
};
export const datetimeFormatter = (
v: string | Date,
defaultValue = '-',
format = 'YYYY-MM-DD HH:mm:ss',
): string | number => {
if (v) {
let time: string | number;
if (['x', 'timestamp'].includes(format)) {
time = dayjs(v).valueOf();
} else if ((typeof v === 'string' && v.includes('Z')) || v.constructor === Date) {
dayjs.extend(utc);
// UTC字符串时间或Date对象格式化为北京时间
time = dayjs(v).utcOffset(8).format(format);
} else {
time = dayjs(v).format(format);
}
if (time !== 'Invalid Date') {
return time;
}
return defaultValue;
}
return defaultValue;
};