@chl1860/dynamic-form-vue3
Version:
Vue3 + TypeScript + Ant Design Vue 动态表单组件
1,788 lines • 71.5 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
import { reactive, ref, markRaw, computed, watch, nextTick, defineComponent, resolveComponent, createBlock, openBlock, inject, withCtx, createElementBlock, Fragment, renderList, createTextVNode, toDisplayString, normalizeClass, createCommentVNode, createElementVNode, normalizeStyle, createVNode, unref, resolveDynamicComponent, mergeProps, toHandlers, provide, onMounted, createSlots, withDirectives, vModelText } from "vue";
import { QuestionCircleOutlined, ExclamationCircleOutlined, DownOutlined } from "@ant-design/icons-vue";
function getByPath(obj, path) {
if (!obj || !path) return void 0;
const keys = path.split(".");
let current = obj;
for (const key of keys) {
if (current == null || typeof current !== "object") {
return void 0;
}
current = current[key];
}
return current;
}
function setByPath(obj, path, value) {
if (!obj || !path) return;
const keys = path.split(".");
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== "object") {
current[key] = {};
}
current = current[key];
}
const lastKey = keys[keys.length - 1];
current[lastKey] = value;
}
function deleteByPath(obj, path) {
if (!obj || !path) return;
const keys = path.split(".");
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== "object") {
return;
}
current = current[key];
}
const lastKey = keys[keys.length - 1];
delete current[lastKey];
}
function hasPath(obj, path) {
return getByPath(obj, path) !== void 0;
}
function getAllPaths(obj, prefix = "") {
const result = {};
if (obj == null || typeof obj !== "object") {
return result;
}
for (const key in obj) {
const value = obj[key];
const fullPath = prefix ? `${prefix}.${key}` : key;
if (value && typeof value === "object" && !Array.isArray(value)) {
Object.assign(result, getAllPaths(value, fullPath));
} else {
result[fullPath] = value;
}
}
return result;
}
const globalComponents = reactive(/* @__PURE__ */ new Map());
const globalComponentsVersion = ref(0);
function createComponentRegistry() {
const components = reactive(/* @__PURE__ */ new Map());
const localVersion = ref(0);
return {
register(type, component) {
components.set(type, markRaw(component));
localVersion.value++;
},
get(type) {
localVersion.value;
globalComponentsVersion.value;
return components.get(type) || globalComponents.get(type);
},
has(type) {
localVersion.value;
globalComponentsVersion.value;
return components.has(type) || globalComponents.has(type);
},
unregister(type) {
components.delete(type);
localVersion.value++;
},
clear() {
components.clear();
localVersion.value++;
},
getAll() {
localVersion.value;
globalComponentsVersion.value;
const allComponents = {};
globalComponents.forEach((component, type) => {
allComponents[type] = component;
});
components.forEach((component, type) => {
allComponents[type] = component;
});
return allComponents;
}
};
}
const globalComponentRegistry = {
/**
* 注册全局自定义字段组件
* @param type 字段类型
* @param component Vue 组件
*/
register(type, component) {
globalComponents.set(type, markRaw(component));
globalComponentsVersion.value++;
},
/**
* 获取全局注册的组件
* @param type 字段类型
*/
get(type) {
globalComponentsVersion.value;
return globalComponents.get(type);
},
/**
* 检查是否存在指定类型的组件
* @param type 字段类型
*/
has(type) {
globalComponentsVersion.value;
return globalComponents.has(type);
},
/**
* 取消注册全局组件
* @param type 字段类型
*/
unregister(type) {
globalComponents.delete(type);
globalComponentsVersion.value++;
},
/**
* 清空所有全局组件
*/
clear() {
globalComponents.clear();
globalComponentsVersion.value++;
},
/**
* 获取所有全局注册的组件
*/
getAll() {
globalComponentsVersion.value;
const result = {};
globalComponents.forEach((component, type) => {
result[type] = component;
});
return result;
},
/**
* 批量注册组件
* @param components 组件映射表
*/
registerBatch(components) {
Object.entries(components).forEach(([type, component]) => {
this.register(type, component);
});
}
};
const SimpleFormPlugin = {
install(app, options = {}) {
app.config.globalProperties.$simpleFormRegistry = globalComponentRegistry;
if (options.components) {
globalComponentRegistry.registerBatch(options.components);
}
app.provide("simpleFormRegistry", globalComponentRegistry);
}
};
function useSimpleForm(schema, initialData = {}) {
const formData = reactive(__spreadValues({}, initialData));
const errors = ref({});
const asyncStates = reactive({});
const fieldOptionsCache = reactive({});
const componentRegistry = createComponentRegistry();
const getValue = (path) => {
return getByPath(formData, path);
};
const setValue = (path, value) => {
setByPath(formData, path, value);
if (errors.value[path]) {
delete errors.value[path];
}
};
const getFieldConfig = (fieldName) => {
const findField = (fields) => {
for (const field of fields) {
if (field.name === fieldName) {
return field;
}
if (field.type === "group" && field.children) {
const found = findField(field.children);
if (found) return found;
}
}
return null;
};
return findField(schema.fields);
};
const validateField = (path) => {
const fieldConfig = getFieldConfig(path.split(".").pop() || path);
if (!fieldConfig || !fieldConfig.rules) return true;
const value = getValue(path);
for (const rule of fieldConfig.rules) {
if (rule.required && (value === void 0 || value === null || value === "")) {
errors.value[path] = rule.message || `${fieldConfig.label} is required`;
return false;
}
if (rule.validator) {
const result = rule.validator(value, formData);
if (result !== true) {
errors.value[path] = typeof result === "string" ? result : rule.message || "Invalid value";
return false;
}
}
}
delete errors.value[path];
return true;
};
const validateForm = () => {
const allPaths = getAllPaths(formData);
let isValid = true;
for (const path in allPaths) {
if (!validateField(path)) {
isValid = false;
}
}
const validateRequiredFields = (fields, prefix = "") => {
var _a;
for (const field of fields) {
if (field.type === "group" && field.children) {
validateRequiredFields(field.children, `${field.name}.`);
} else {
const fieldPath = prefix + field.name;
if ((_a = field.rules) == null ? void 0 : _a.some((rule) => rule.required)) {
if (!validateField(fieldPath)) {
isValid = false;
}
}
}
}
};
validateRequiredFields(schema.fields);
return isValid;
};
const resetForm = () => {
Object.keys(formData).forEach((key) => {
delete formData[key];
});
Object.assign(formData, __spreadValues({}, initialData));
errors.value = {};
};
const formValues = computed(() => __spreadValues({}, formData));
const hasErrors = computed(() => Object.keys(errors.value).length > 0);
const getFieldError = (path) => {
return errors.value[path];
};
const initializeAsync = () => __async(this, null, function* () {
if (!schema.asyncInitializer) return;
const initKey = "__init__";
asyncStates[initKey] = { loading: true };
try {
const asyncData = yield schema.asyncInitializer();
if (asyncData && typeof asyncData === "object") {
Object.assign(formData, asyncData);
}
asyncStates[initKey] = { loading: false };
yield nextTick();
yield triggerAsyncLinkageForInitialization();
} catch (error) {
asyncStates[initKey] = {
loading: false,
error: error instanceof Error ? error.message : "初始化失败"
};
}
});
const triggerAsyncLinkageForInitialization = () => __async(this, null, function* () {
var _a;
for (const field of schema.fields) {
if (((_a = field.linkage) == null ? void 0 : _a.asyncOptionsLoader) && field.linkage.dependsOn) {
const dependentValue = getByPath(formData, field.linkage.dependsOn);
if (dependentValue !== void 0) {
yield loadFieldOptions(field.name, dependentValue);
}
}
}
});
const loadFieldOptions = (fieldName, dependentValue) => __async(this, null, function* () {
var _a;
const fieldConfig = getFieldConfig(fieldName);
if (!((_a = fieldConfig == null ? void 0 : fieldConfig.linkage) == null ? void 0 : _a.asyncOptionsLoader)) return [];
const cacheKey = `${fieldName}_${dependentValue}`;
asyncStates[cacheKey] = { loading: true };
try {
const options = yield fieldConfig.linkage.asyncOptionsLoader(dependentValue, formData);
fieldOptionsCache[cacheKey] = options;
asyncStates[cacheKey] = { loading: false };
return options;
} catch (error) {
asyncStates[cacheKey] = {
loading: false,
error: error instanceof Error ? error.message : "加载选项失败"
};
return [];
}
});
const getFieldOptions = (fieldName, dependentValue) => {
var _a, _b;
const fieldConfig = getFieldConfig(fieldName);
if (!fieldConfig) return [];
if (((_a = fieldConfig.linkage) == null ? void 0 : _a.asyncOptionsLoader) && dependentValue !== void 0) {
const cacheKey = `${fieldName}_${dependentValue}`;
return fieldOptionsCache[cacheKey] || [];
}
if (((_b = fieldConfig.linkage) == null ? void 0 : _b.optionsMap) && dependentValue !== void 0) {
return fieldConfig.linkage.optionsMap[dependentValue] || [];
}
return fieldConfig.options || [];
};
const getAsyncState = (key) => {
return asyncStates[key] || { loading: false };
};
const validateFieldAsync = (path) => __async(this, null, function* () {
const fieldConfig = getFieldConfig(path.split(".").pop() || path);
if (!fieldConfig || !fieldConfig.rules) return true;
const value = getValue(path);
if (!validateField(path)) return false;
for (const rule of fieldConfig.rules) {
if (rule.asyncValidator) {
const validationKey = `${path}_validation`;
asyncStates[validationKey] = { loading: true };
try {
const result = yield rule.asyncValidator(value, formData);
asyncStates[validationKey] = { loading: false };
if (result !== true) {
errors.value[path] = typeof result === "string" ? result : rule.message || "Invalid value";
return false;
}
} catch (error) {
asyncStates[validationKey] = {
loading: false,
error: error instanceof Error ? error.message : "验证失败"
};
errors.value[path] = rule.message || "验证失败";
return false;
}
}
}
delete errors.value[path];
return true;
});
const setupFieldWatchers = () => {
const fieldsWithDependencies = schema.fields.filter((field) => {
var _a;
return (_a = field.linkage) == null ? void 0 : _a.dependsOn;
});
fieldsWithDependencies.forEach((field) => {
var _a;
if ((_a = field.linkage) == null ? void 0 : _a.dependsOn) {
watch(
() => getByPath(formData, field.linkage.dependsOn),
(newValue, oldValue) => __async(this, null, function* () {
var _a2, _b;
if (newValue !== oldValue) {
const shouldReset = ((_a2 = field.linkage) == null ? void 0 : _a2.resetOnChange) !== false;
if (shouldReset) {
const initialValue = getInitialValue(field);
setValue(field.name, initialValue);
}
if (((_b = field.linkage) == null ? void 0 : _b.asyncOptionsLoader) && newValue !== void 0) {
const cacheKey = `${field.name}_${newValue}`;
const hasCache = fieldOptionsCache[cacheKey] && fieldOptionsCache[cacheKey].length > 0;
if (!hasCache) {
yield loadFieldOptions(field.name, newValue);
}
}
}
}),
{ immediate: false }
// 不在初始化时立即触发
);
}
});
};
setupFieldWatchers();
const getInitialValue = (field) => {
switch (field.type) {
case "input":
case "text":
case "textarea":
return "";
case "select":
case "radio":
return void 0;
case "checkbox":
return false;
case "number":
return void 0;
case "date":
return void 0;
default:
return void 0;
}
};
return {
formData,
formValues,
errors: computed(() => errors.value),
hasErrors,
getValue,
setValue,
getFieldConfig,
validateField,
validateFieldAsync,
validateForm,
resetForm,
getFieldError,
// 异步功能
initializeAsync,
loadFieldOptions,
getFieldOptions,
getAsyncState,
asyncStates: computed(() => asyncStates),
fieldOptionsCache: computed(() => fieldOptionsCache),
// 组件注册功能
componentRegistry,
// Schema 配置
schema
};
}
const _sfc_main$7 = /* @__PURE__ */ defineComponent({
__name: "SimpleInput",
props: {
field: {},
value: {},
disabled: { type: Boolean }
},
emits: ["update:value", "blur", "focus"],
setup(__props, { emit: __emit }) {
const emit = __emit;
const handleChange = (value) => {
emit("update:value", value);
};
const handleBlur = () => {
emit("blur");
};
const handleFocus = () => {
emit("focus");
};
return (_ctx, _cache) => {
var _a, _b, _c;
const _component_a_input = resolveComponent("a-input");
return openBlock(), createBlock(_component_a_input, {
value: _ctx.value,
placeholder: _ctx.field.placeholder,
disabled: _ctx.disabled,
size: (_a = _ctx.field.props) == null ? void 0 : _a.size,
"allow-clear": (_b = _ctx.field.props) == null ? void 0 : _b.allowClear,
"max-length": (_c = _ctx.field.props) == null ? void 0 : _c.maxLength,
"onUpdate:value": handleChange,
onBlur: handleBlur,
onFocus: handleFocus
}, null, 8, ["value", "placeholder", "disabled", "size", "allow-clear", "max-length"]);
};
}
});
const _sfc_main$6 = /* @__PURE__ */ defineComponent({
__name: "SimpleSelect",
props: {
field: {},
value: {},
disabled: { type: Boolean },
loading: { type: Boolean }
},
emits: ["update:value", "blur", "focus"],
setup(__props, { emit: __emit }) {
const props = __props;
const emit = __emit;
const formContext = inject("formContext");
const currentOptions = computed(() => {
var _a;
if (((_a = props.field.linkage) == null ? void 0 : _a.dependsOn) && formContext) {
const dependentValue = formContext.getValue(props.field.linkage.dependsOn);
if (props.field.linkage.asyncOptionsLoader && dependentValue !== void 0) {
return formContext.getFieldOptions(props.field.name, dependentValue);
}
if (props.field.linkage.optionsMap && dependentValue !== void 0) {
return props.field.linkage.optionsMap[dependentValue] || [];
}
}
return props.field.options || [];
});
const isLoadingOptions = computed(() => {
var _a;
if (!((_a = props.field.linkage) == null ? void 0 : _a.dependsOn) || !formContext) return false;
const dependentValue = formContext.getValue(props.field.linkage.dependsOn);
if (props.field.linkage.asyncOptionsLoader && dependentValue !== void 0) {
const cacheKey = `${props.field.name}_${dependentValue}`;
return formContext.getAsyncState(cacheKey).loading;
}
return false;
});
const handleChange = (value) => {
emit("update:value", value);
};
const handleBlur = () => {
emit("blur");
};
const handleFocus = () => {
emit("focus");
};
return (_ctx, _cache) => {
var _a, _b, _c, _d, _e;
const _component_a_select_option = resolveComponent("a-select-option");
const _component_a_select = resolveComponent("a-select");
return openBlock(), createBlock(_component_a_select, {
value: _ctx.value,
placeholder: _ctx.field.placeholder,
disabled: _ctx.disabled,
loading: _ctx.loading || isLoadingOptions.value,
"allow-clear": (_a = _ctx.field.props) == null ? void 0 : _a.allowClear,
"show-search": (_b = _ctx.field.props) == null ? void 0 : _b.showSearch,
"filter-option": (_c = _ctx.field.props) == null ? void 0 : _c.filterOption,
mode: (_d = _ctx.field.props) == null ? void 0 : _d.mode,
size: (_e = _ctx.field.props) == null ? void 0 : _e.size,
"onUpdate:value": handleChange,
onBlur: handleBlur,
onFocus: handleFocus
}, {
default: withCtx(() => [
(openBlock(true), createElementBlock(Fragment, null, renderList(currentOptions.value, (option) => {
return openBlock(), createBlock(_component_a_select_option, {
key: option.value,
value: option.value,
disabled: option.disabled
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(option.label), 1)
]),
_: 2
}, 1032, ["value", "disabled"]);
}), 128))
]),
_: 1
}, 8, ["value", "placeholder", "disabled", "loading", "allow-clear", "show-search", "filter-option", "mode", "size"]);
};
}
});
const _sfc_main$5 = /* @__PURE__ */ defineComponent({
__name: "SimpleRadio",
props: {
field: {},
value: {},
disabled: { type: Boolean }
},
emits: ["update:value"],
setup(__props, { emit: __emit }) {
const props = __props;
const emit = __emit;
const formContext = inject("formContext");
const currentOptions = computed(() => {
var _a;
if (((_a = props.field.linkage) == null ? void 0 : _a.dependsOn) && formContext) {
const dependentValue = formContext.getValue(props.field.linkage.dependsOn);
if (props.field.linkage.optionsMap && dependentValue !== void 0) {
return props.field.linkage.optionsMap[dependentValue] || [];
}
}
return props.field.options || [];
});
const handleChange = (value) => {
emit("update:value", value);
};
return (_ctx, _cache) => {
var _a, _b;
const _component_a_radio = resolveComponent("a-radio");
const _component_a_radio_group = resolveComponent("a-radio-group");
return openBlock(), createBlock(_component_a_radio_group, {
value: _ctx.value,
disabled: _ctx.disabled,
size: (_a = _ctx.field.props) == null ? void 0 : _a.size,
direction: ((_b = _ctx.field.props) == null ? void 0 : _b.direction) || "horizontal",
"onUpdate:value": handleChange
}, {
default: withCtx(() => [
(openBlock(true), createElementBlock(Fragment, null, renderList(currentOptions.value, (option) => {
return openBlock(), createBlock(_component_a_radio, {
key: option.value,
value: option.value,
disabled: option.disabled
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(option.label), 1)
]),
_: 2
}, 1032, ["value", "disabled"]);
}), 128))
]),
_: 1
}, 8, ["value", "disabled", "size", "direction"]);
};
}
});
const _hoisted_1$4 = {
key: 0,
class: "simple-group-header"
};
const _hoisted_2$4 = {
key: 0,
class: "simple-group-title"
};
const _hoisted_3$3 = {
key: 1,
class: "simple-group-description"
};
const _sfc_main$4 = /* @__PURE__ */ defineComponent({
__name: "SimpleGroup",
props: {
field: {},
path: {}
},
setup(__props) {
const props = __props;
const formContext = inject("formContext");
const layoutClass = computed(() => {
return props.field.layout === "horizontal" ? "simple-group-horizontal" : "simple-group-vertical";
});
const getChildPath = (childName) => {
return props.path ? `${props.path}.${childName}` : childName;
};
const visibleChildren = computed(() => {
if (!props.field.children) return [];
return props.field.children.filter((child) => {
var _a;
if (!((_a = child.linkage) == null ? void 0 : _a.visibleWhen)) return true;
const childPath = getChildPath(child.name);
const value = formContext == null ? void 0 : formContext.getValue(childPath);
return child.linkage.visibleWhen(value, formContext == null ? void 0 : formContext.formData);
});
});
return (_ctx, _cache) => {
var _a, _b;
return openBlock(), createElementBlock("div", {
class: normalizeClass(["simple-group", { "simple-group-bordered": _ctx.field.bordered }])
}, [
_ctx.field.label || ((_a = _ctx.field.props) == null ? void 0 : _a.description) ? (openBlock(), createElementBlock("div", _hoisted_1$4, [
_ctx.field.label ? (openBlock(), createElementBlock("h4", _hoisted_2$4, toDisplayString(_ctx.field.label), 1)) : createCommentVNode("", true),
((_b = _ctx.field.props) == null ? void 0 : _b.description) ? (openBlock(), createElementBlock("p", _hoisted_3$3, toDisplayString(_ctx.field.props.description), 1)) : createCommentVNode("", true)
])) : createCommentVNode("", true),
createElementVNode("div", {
class: normalizeClass(["simple-group-content", layoutClass.value])
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(visibleChildren.value, (childField) => {
return openBlock(), createBlock(SimpleFormItem, {
key: childField.name,
field: childField,
path: getChildPath(childField.name)
}, null, 8, ["field", "path"]);
}), 128))
], 2)
], 2);
};
}
});
const _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const SimpleGroup = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-f4248fd8"]]);
const _hoisted_1$3 = { class: "simple-form-item-control" };
const _hoisted_2$3 = {
key: 9,
class: "unsupported-field"
};
const _hoisted_3$2 = { class: "error-title" };
const _hoisted_4$2 = { class: "error-details" };
const _hoisted_5$1 = { class: "debug-info" };
const _hoisted_6 = { key: 2 };
const _hoisted_7 = { class: "simple-form-item-control" };
const _hoisted_8 = {
key: 9,
class: "unsupported-field"
};
const _hoisted_9 = { class: "error-title" };
const _hoisted_10 = { class: "error-details" };
const _hoisted_11 = { class: "debug-info" };
const _hoisted_12 = {
key: 2,
class: "simple-form-item-validating"
};
const _hoisted_13 = {
key: 3,
class: "simple-form-item-error-message"
};
const _sfc_main$3 = /* @__PURE__ */ defineComponent({
__name: "SimpleFormItem",
props: {
field: {},
path: {}
},
setup(__props) {
const props = __props;
const fieldAsGroup = computed(() => props.field);
const formContext = inject("formContext");
const injectedFormLayout = inject("formLayout", null);
const fieldPath = computed(() => {
return props.path || props.field.name;
});
const fieldValue = computed(() => {
return formContext == null ? void 0 : formContext.getValue(fieldPath.value);
});
const isRequired = computed(() => {
var _a;
return ((_a = props.field.rules) == null ? void 0 : _a.some((rule) => rule.required)) || false;
});
const isDisabled = computed(() => {
var _a;
if (!((_a = props.field.linkage) == null ? void 0 : _a.disabledWhen)) return false;
return props.field.linkage.disabledWhen(fieldValue.value, formContext == null ? void 0 : formContext.formData);
});
const hasError = computed(() => {
return !!(formContext == null ? void 0 : formContext.getFieldError(fieldPath.value));
});
const errorMessage = computed(() => {
return formContext == null ? void 0 : formContext.getFieldError(fieldPath.value);
});
const handleValueChange = (value) => {
formContext == null ? void 0 : formContext.setValue(fieldPath.value, value);
};
const handleBlur = () => __async(this, null, function* () {
var _a;
formContext == null ? void 0 : formContext.validateField(fieldPath.value);
const fieldConfig = formContext == null ? void 0 : formContext.getFieldConfig(props.field.name);
if ((_a = fieldConfig == null ? void 0 : fieldConfig.rules) == null ? void 0 : _a.some((rule) => rule.asyncValidator)) {
yield formContext == null ? void 0 : formContext.validateFieldAsync(fieldPath.value);
}
});
const isValidating = computed(() => {
const validationKey = `${fieldPath.value}_validation`;
return (formContext == null ? void 0 : formContext.getAsyncState(validationKey).loading) || false;
});
const customComponent = computed(() => {
if (props.field.component) {
console.log(`字段 ${props.field.name} 使用内联组件:`, props.field.component);
return markRaw(props.field.component);
}
const registeredComponent = formContext == null ? void 0 : formContext.componentRegistry.get(props.field.type);
if (registeredComponent) {
console.log(`字段 ${props.field.name} 找到注册组件:`, props.field.type);
} else {
console.warn(`字段 ${props.field.name} 未找到对应的组件:`, props.field.type);
console.log("当前已注册的组件:", formContext == null ? void 0 : formContext.componentRegistry.getAll());
}
return registeredComponent;
});
const mergedComponentProps = computed(() => {
const baseProps = __spreadValues({
placeholder: props.field.placeholder
}, props.field.props);
if (props.field.componentProps) {
Object.assign(baseProps, props.field.componentProps);
}
return baseProps;
});
const customComponentEvents = computed(() => {
return {};
});
const handleFocus = () => {
};
const getTooltipTitle = computed(() => {
var _a;
if (typeof props.field.tooltip === "string") {
return props.field.tooltip;
}
return ((_a = props.field.tooltip) == null ? void 0 : _a.title) || "";
});
const getTooltipPlacement = computed(() => {
var _a;
if (typeof props.field.tooltip === "string") {
return "top";
}
return ((_a = props.field.tooltip) == null ? void 0 : _a.placement) || "top";
});
const getTooltipColor = computed(() => {
var _a;
if (typeof props.field.tooltip === "string") {
return void 0;
}
return (_a = props.field.tooltip) == null ? void 0 : _a.color;
});
const getTooltipOverlayClassName = computed(() => {
var _a;
if (typeof props.field.tooltip === "string") {
return void 0;
}
return (_a = props.field.tooltip) == null ? void 0 : _a.overlayClassName;
});
const getTooltipOverlayStyle = computed(() => {
var _a;
if (typeof props.field.tooltip === "string") {
return void 0;
}
return (_a = props.field.tooltip) == null ? void 0 : _a.overlayStyle;
});
const fieldLayout = computed(() => props.field.layout || {});
const formLayout = computed(() => {
var _a;
return (injectedFormLayout == null ? void 0 : injectedFormLayout.value) || ((_a = formContext == null ? void 0 : formContext.schema) == null ? void 0 : _a.layout) || {};
});
const isInlineLayout = computed(() => (formLayout.value.type || "vertical") === "inline");
const formItemGutter = computed(() => {
const gutter = formLayout.value.gutter;
if (Array.isArray(gutter)) {
return gutter;
}
return gutter ? [gutter, gutter] : [8, 8];
});
const useRowLayout = computed(() => {
const layoutType = formLayout.value.type || "vertical";
if (layoutType === "horizontal" || layoutType === "grid") {
return true;
}
const hasFieldLayoutCols = typeof fieldLayout.value === "object" && (fieldLayout.value.labelCol || fieldLayout.value.wrapperCol);
const hasFormLayoutCols = formLayout.value.labelCol || formLayout.value.wrapperCol;
return hasFieldLayoutCols || hasFormLayoutCols;
});
const formItemClasses = computed(() => {
const classes = [];
const layoutType = formLayout.value.type || "vertical";
classes.push(`simple-form-item-${layoutType}`);
if (hasError.value) {
classes.push("simple-form-item-error");
}
if (typeof fieldLayout.value === "object" && fieldLayout.value.className) {
classes.push(fieldLayout.value.className);
}
return classes;
});
const formItemStyle = computed(() => {
return typeof fieldLayout.value === "object" && fieldLayout.value.style || {};
});
const labelClasses = computed(() => {
const classes = [];
const labelAlign = formLayout.value.labelAlign;
if (labelAlign) {
classes.push(`label-${labelAlign}`);
}
return classes;
});
const labelColSpan = computed(() => {
var _a, _b;
const fieldLayoutCol = typeof fieldLayout.value === "object" ? (_a = fieldLayout.value.labelCol) == null ? void 0 : _a.span : void 0;
const formLayoutCol = (_b = formLayout.value.labelCol) == null ? void 0 : _b.span;
const layoutType = formLayout.value.type || "vertical";
let defaultSpan = 6;
if (layoutType === "horizontal") {
defaultSpan = 6;
}
return fieldLayoutCol || formLayoutCol || defaultSpan;
});
const labelColOffset = computed(() => {
var _a, _b;
const fieldLayoutOffset = typeof fieldLayout.value === "object" ? (_a = fieldLayout.value.labelCol) == null ? void 0 : _a.offset : void 0;
return fieldLayoutOffset || ((_b = formLayout.value.labelCol) == null ? void 0 : _b.offset) || 0;
});
const wrapperColSpan = computed(() => {
var _a, _b;
const fieldLayoutSpan = typeof fieldLayout.value === "object" ? (_a = fieldLayout.value.wrapperCol) == null ? void 0 : _a.span : void 0;
const formLayoutSpan = (_b = formLayout.value.wrapperCol) == null ? void 0 : _b.span;
const layoutType = formLayout.value.type || "vertical";
if (fieldLayoutSpan || formLayoutSpan) {
return fieldLayoutSpan || formLayoutSpan;
}
const labelSpan = labelColSpan.value;
const labelOffset = labelColOffset.value;
if (layoutType === "horizontal") {
return 24 - labelSpan - labelOffset;
}
return 24 - labelSpan - labelOffset;
});
const wrapperColOffset = computed(() => {
var _a, _b;
const fieldLayoutOffset = typeof fieldLayout.value === "object" ? (_a = fieldLayout.value.wrapperCol) == null ? void 0 : _a.offset : void 0;
return fieldLayoutOffset || ((_b = formLayout.value.wrapperCol) == null ? void 0 : _b.offset) || 0;
});
return (_ctx, _cache) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
const _component_a_tooltip = resolveComponent("a-tooltip");
const _component_a_col = resolveComponent("a-col");
const _component_a_input_number = resolveComponent("a-input-number");
const _component_a_textarea = resolveComponent("a-textarea");
const _component_a_checkbox = resolveComponent("a-checkbox");
const _component_a_date_picker = resolveComponent("a-date-picker");
const _component_a_row = resolveComponent("a-row");
const _component_a_spin = resolveComponent("a-spin");
return openBlock(), createElementBlock("div", {
class: normalizeClass(["simple-form-item", formItemClasses.value]),
style: normalizeStyle(formItemStyle.value)
}, [
useRowLayout.value ? (openBlock(), createBlock(_component_a_row, {
key: 0,
gutter: formItemGutter.value
}, {
default: withCtx(() => [
_ctx.field.label ? (openBlock(), createBlock(_component_a_col, {
key: 0,
span: labelColSpan.value,
offset: labelColOffset.value,
class: "simple-form-item-label-col"
}, {
default: withCtx(() => [
createElementVNode("div", {
class: normalizeClass(["simple-form-item-label", labelClasses.value])
}, [
createElementVNode("span", {
class: normalizeClass({ required: isRequired.value })
}, toDisplayString(_ctx.field.label), 3),
_ctx.field.tooltip ? (openBlock(), createBlock(_component_a_tooltip, {
key: 0,
title: getTooltipTitle.value,
placement: getTooltipPlacement.value,
color: getTooltipColor.value,
"overlay-class-name": getTooltipOverlayClassName.value,
"overlay-style": getTooltipOverlayStyle.value
}, {
default: withCtx(() => [
createVNode(unref(QuestionCircleOutlined), { class: "field-tooltip-icon" })
]),
_: 1
}, 8, ["title", "placement", "color", "overlay-class-name", "overlay-style"])) : createCommentVNode("", true)
], 2)
]),
_: 1
}, 8, ["span", "offset"])) : createCommentVNode("", true),
createVNode(_component_a_col, {
span: wrapperColSpan.value,
offset: wrapperColOffset.value,
class: "simple-form-item-control-col"
}, {
default: withCtx(() => {
var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2;
return [
createElementVNode("div", _hoisted_1$3, [
_ctx.field.type === "group" ? (openBlock(), createBlock(SimpleGroup, {
key: 0,
field: fieldAsGroup.value,
path: _ctx.path || ""
}, null, 8, ["field", "path"])) : _ctx.field.type === "input" || _ctx.field.type === "text" ? (openBlock(), createBlock(_sfc_main$7, {
key: 1,
field: _ctx.field,
value: fieldValue.value,
disabled: isDisabled.value,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["field", "value", "disabled"])) : _ctx.field.type === "select" ? (openBlock(), createBlock(_sfc_main$6, {
key: 2,
field: _ctx.field,
value: fieldValue.value,
disabled: isDisabled.value,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["field", "value", "disabled"])) : _ctx.field.type === "radio" ? (openBlock(), createBlock(_sfc_main$5, {
key: 3,
field: _ctx.field,
value: fieldValue.value,
disabled: isDisabled.value,
"onUpdate:value": handleValueChange
}, null, 8, ["field", "value", "disabled"])) : _ctx.field.type === "number" ? (openBlock(), createBlock(_component_a_input_number, {
key: 4,
value: fieldValue.value,
placeholder: _ctx.field.placeholder,
disabled: isDisabled.value,
min: (_a2 = _ctx.field.props) == null ? void 0 : _a2.min,
max: (_b2 = _ctx.field.props) == null ? void 0 : _b2.max,
step: (_c2 = _ctx.field.props) == null ? void 0 : _c2.step,
precision: (_d2 = _ctx.field.props) == null ? void 0 : _d2.precision,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["value", "placeholder", "disabled", "min", "max", "step", "precision"])) : _ctx.field.type === "textarea" ? (openBlock(), createBlock(_component_a_textarea, {
key: 5,
value: fieldValue.value,
placeholder: _ctx.field.placeholder,
disabled: isDisabled.value,
rows: ((_e2 = _ctx.field.props) == null ? void 0 : _e2.rows) || 4,
"max-length": (_f2 = _ctx.field.props) == null ? void 0 : _f2.maxLength,
"show-count": (_g2 = _ctx.field.props) == null ? void 0 : _g2.showCount,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["value", "placeholder", "disabled", "rows", "max-length", "show-count"])) : _ctx.field.type === "checkbox" ? (openBlock(), createBlock(_component_a_checkbox, {
key: 6,
checked: fieldValue.value,
disabled: isDisabled.value,
"onUpdate:checked": handleValueChange
}, {
default: withCtx(() => {
var _a3;
return [
createTextVNode(toDisplayString((_a3 = _ctx.field.props) == null ? void 0 : _a3.label), 1)
];
}),
_: 1
}, 8, ["checked", "disabled"])) : _ctx.field.type === "date" ? (openBlock(), createBlock(_component_a_date_picker, {
key: 7,
value: fieldValue.value,
placeholder: _ctx.field.placeholder,
disabled: isDisabled.value,
format: (_h2 = _ctx.field.props) == null ? void 0 : _h2.format,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["value", "placeholder", "disabled", "format"])) : customComponent.value ? (openBlock(), createBlock(resolveDynamicComponent(customComponent.value), mergeProps({
key: 8,
value: fieldValue.value,
field: _ctx.field,
disabled: isDisabled.value
}, mergedComponentProps.value, {
"onUpdate:value": handleValueChange,
onBlur: handleBlur,
onFocus: handleFocus
}, toHandlers(customComponentEvents.value)), null, 16, ["value", "field", "disabled"])) : (openBlock(), createElementBlock("div", _hoisted_2$3, [
createElementVNode("div", _hoisted_3$2, [
createVNode(unref(ExclamationCircleOutlined)),
createTextVNode(" 不支持的字段类型: " + toDisplayString(_ctx.field.type), 1)
]),
createElementVNode("div", _hoisted_4$2, [
createElementVNode("p", null, "字段名: " + toDisplayString(_ctx.field.name), 1),
_cache[1] || (_cache[1] = createElementVNode("p", null, "可能的解决方案:", -1)),
_cache[2] || (_cache[2] = createElementVNode("ul", null, [
createElementVNode("li", null, "检查字段类型是否拼写正确"),
createElementVNode("li", null, "确保自定义组件已正确注册"),
createElementVNode("li", null, "使用 component 属性直接指定组件"),
createElementVNode("li", null, "联系开发者添加对该字段类型的支持")
], -1)),
createElementVNode("div", _hoisted_5$1, [
createElementVNode("details", null, [
_cache[0] || (_cache[0] = createElementVNode("summary", null, "调试信息", -1)),
createElementVNode("p", null, "已注册的组件类型: " + toDisplayString(Object.keys(((_i2 = unref(formContext)) == null ? void 0 : _i2.componentRegistry.getAll()) || {}).join(", ") || "无"), 1),
createElementVNode("p", null, "字段配置: " + toDisplayString(JSON.stringify(_ctx.field, null, 2)), 1)
])
])
])
]))
])
];
}),
_: 1
}, 8, ["span", "offset"])
]),
_: 1
}, 8, ["gutter"])) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
_ctx.field.label || isInlineLayout.value ? (openBlock(), createElementBlock("div", {
key: 0,
class: normalizeClass(["simple-form-item-label", labelClasses.value])
}, [
_ctx.field.label ? (openBlock(), createElementBlock("span", {
key: 0,
class: normalizeClass({ required: isRequired.value })
}, toDisplayString(_ctx.field.label), 3)) : createCommentVNode("", true),
_ctx.field.tooltip ? (openBlock(), createBlock(_component_a_tooltip, {
key: 1,
title: getTooltipTitle.value,
placement: getTooltipPlacement.value,
color: getTooltipColor.value,
"overlay-class-name": getTooltipOverlayClassName.value,
"overlay-style": getTooltipOverlayStyle.value
}, {
default: withCtx(() => [
createVNode(unref(QuestionCircleOutlined), { class: "field-tooltip-icon" })
]),
_: 1
}, 8, ["title", "placement", "color", "overlay-class-name", "overlay-style"])) : !_ctx.field.label ? (openBlock(), createElementBlock("span", _hoisted_6, " ")) : createCommentVNode("", true)
], 2)) : createCommentVNode("", true),
createElementVNode("div", _hoisted_7, [
_ctx.field.type === "group" ? (openBlock(), createBlock(SimpleGroup, {
key: 0,
field: fieldAsGroup.value,
path: _ctx.path || ""
}, null, 8, ["field", "path"])) : _ctx.field.type === "input" || _ctx.field.type === "text" ? (openBlock(), createBlock(_sfc_main$7, {
key: 1,
field: _ctx.field,
value: fieldValue.value,
disabled: isDisabled.value,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["field", "value", "disabled"])) : _ctx.field.type === "select" ? (openBlock(), createBlock(_sfc_main$6, {
key: 2,
field: _ctx.field,
value: fieldValue.value,
disabled: isDisabled.value,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["field", "value", "disabled"])) : _ctx.field.type === "radio" ? (openBlock(), createBlock(_sfc_main$5, {
key: 3,
field: _ctx.field,
value: fieldValue.value,
disabled: isDisabled.value,
"onUpdate:value": handleValueChange
}, null, 8, ["field", "value", "disabled"])) : _ctx.field.type === "number" ? (openBlock(), createBlock(_component_a_input_number, {
key: 4,
value: fieldValue.value,
placeholder: _ctx.field.placeholder,
disabled: isDisabled.value,
min: (_a = _ctx.field.props) == null ? void 0 : _a.min,
max: (_b = _ctx.field.props) == null ? void 0 : _b.max,
step: (_c = _ctx.field.props) == null ? void 0 : _c.step,
precision: (_d = _ctx.field.props) == null ? void 0 : _d.precision,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["value", "placeholder", "disabled", "min", "max", "step", "precision"])) : _ctx.field.type === "textarea" ? (openBlock(), createBlock(_component_a_textarea, {
key: 5,
value: fieldValue.value,
placeholder: _ctx.field.placeholder,
disabled: isDisabled.value,
rows: ((_e = _ctx.field.props) == null ? void 0 : _e.rows) || 4,
"max-length": (_f = _ctx.field.props) == null ? void 0 : _f.maxLength,
"show-count": (_g = _ctx.field.props) == null ? void 0 : _g.showCount,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["value", "placeholder", "disabled", "rows", "max-length", "show-count"])) : _ctx.field.type === "checkbox" ? (openBlock(), createBlock(_component_a_checkbox, {
key: 6,
checked: fieldValue.value,
disabled: isDisabled.value,
"onUpdate:checked": handleValueChange
}, {
default: withCtx(() => {
var _a2;
return [
createTextVNode(toDisplayString((_a2 = _ctx.field.props) == null ? void 0 : _a2.label), 1)
];
}),
_: 1
}, 8, ["checked", "disabled"])) : _ctx.field.type === "date" ? (openBlock(), createBlock(_component_a_date_picker, {
key: 7,
value: fieldValue.value,
placeholder: _ctx.field.placeholder,
disabled: isDisabled.value,
format: (_h = _ctx.field.props) == null ? void 0 : _h.format,
"onUpdate:value": handleValueChange,
onBlur: handleBlur
}, null, 8, ["value", "placeholder", "disabled", "format"])) : customComponent.value ? (openBlock(), createBlock(resolveDynamicComponent(customComponent.value), mergeProps({
key: 8,
value: fieldValue.value,
field: _ctx.field,
disabled: isDisabled.value
}, mergedComponentProps.value, {
"onUpdate:value": handleValueChange,
onBlur: handleBlur,
onFocus: handleFocus
}, toHandlers(customComponentEvents.value)), null, 16, ["value", "field", "disabled"])) : (openBlock(), createElementBlock("div", _hoisted_8, [
createElementVNode("div", _hoisted_9, [
createVNode(unref(ExclamationCircleOutlined)),
createTextVNode(" 不支持的字段类型: " + toDisplayString(_ctx.field.type), 1)
]),
createElementVNode("div", _hoisted_10, [
createElementVNode("p", null, "字段名: " + toDisplayString(_ctx.field.name), 1),
_cache[4] || (_cache[4] = createElementVNode("p", null, "可能的解决方案:", -1)),
_cache[5] || (_cache[5] = createElementVNode("ul", null, [
createElementVNode("li", null, "检查字段类型是否拼写正确"),
createElementVNode("li", null, "确保自定义组件已正确注册"),
createElementVNode("li", null, "使用 component 属性直接指定组件"),
createElementVNode("li", null, "联系开发者添加对该字段类型的支持")
], -1)),
createElementVNode("div", _hoisted_11, [
createElementVNode("details", null, [
_cache[3] || (_cache[3] = createElementVNode("summary", null, "调试信息", -1)),
createElementVNode("p", null, "已注册的组件类型: " + toDisplayString(Object.keys(((_i = unref(formContext)) == null ? void 0 : _i.componentRegistry.getAll()) || {}).join(", ") || "无"), 1),
createElementVNode("p", null, "字段配置: " + toDisplayString(JSON.stringify(_ctx.field, null, 2)), 1)
])
])
])
]))
])
], 64)),
isValidating.value ? (openBlock(), createElementBlock("div", _hoisted_12, [
createVNode(_component_a_spin, { size: "small" }),
_cache[6] || (_cache[6] = createTextVNode(" 验证中... ", -1))
])) : hasError.value ? (openBlock(), createElementBlock("div", _hoisted_13, toDisplayString(errorMessage.value), 1)) : createCommentVNode("", true)
], 6);
};
}
});
const SimpleFormItem = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-91a77669"]]);
const _hoisted_1$2 = {
key: 0,
class: "simple-form-actions inline-actions"
};
const _hoisted_2$2 = {
key: 2,
class: "simple-form-actions"
};
const _sfc_main$2 = /* @__PURE__ */ defineComponent({
__name: "SimpleForm",
props: {
schema: {},
modelValue: {},
showActions: { type: Boolean, default: true },
showReset: { type: Boolean, default: true },
submitText: { default: "提交" },
resetText: { default: "重置" },
submitting: { type: Boolean, default: false },
validateOnChange: { type: Boolean, default: true }
},
emits: ["update:modelValue", "submit", "reset", "change", "validate"],
setup(__props, { expose: __expose, emit: __emit }) {
const props = __props;
const emit = __emit;
const formContext = useSimpleForm(props.schema, props.modelValue);
const formLayout = computed(() => props.schema.layout || {});
provide("formContext", formContext);
provide("formLayout", formLayout);
const visibleFields = computed(() => {
return props.schema.fields.filter((field) => {
var _a;
if (!((_a = field.linkage) == null ? void 0 : _a.visibleWhen)) return true;
const dependentValue = field.linkage.dependsOn ? formContext.getValue(field.linkage.dependsOn) : void 0;
return field.linkage.visibleWhen(dependentValue, formContext.formData);
});
});
const isGridLayout = computed(() => {
const layoutType = formLayout.value.type;
return layoutType === "horizontal" || layoutType === "grid";
});
const formLayoutClasses = computed(() => {
const classes = [];
const layoutType = formLayout.value.type || "vertical";
classes.push(`simple-form-${layoutType}`);
if (formLayout.value.labelAlign) {
classes.push(`simple-form-label-${formLayout.value.labelAlign}`);
}
return classes;
});
const fieldsContainerClass = computed(() => {
const layoutType = formLayout.value.type || "vertical";
return `simple-form-fields simple-form-fields-${layoutType}`;
});
const isInlineLayout = computed(() => (formLayout.value.type || "vertical") === "inline");
const gutterConfig = computed(() => {
const gutter = formLayout.value.gutter;
if (Array.isArray(gutter)) {
return gutter;
}
return gutter ? [gutter, gutter] : [16, 16];
});
const submitButtonConfig = computed(() => {
const defaultConfig = {
text: props.submitText,
type: "primary",
size: "middle",
loading: false,
disabled: false,
htmlType: "submit"
};
if (props.schema.submitButton) {
return __spreadValues(__spreadValues({}, defaultConfig), props.schema.submitButton);
}
return defaultConfig;
});
const getFieldSpan = (field) => {
var _a, _b;
if ((_a = field.layout) == null ? void 0 : _a.span) return field.layout.span;
const cols = formLayout.value.cols || formLayout.value.columns;
if (cols) {
const baseSpan = Math.floor(24 / cols);
const colSpan = ((_b = field.layout) == null ? void 0 : _b.colSpan) || 1;
return baseSpan * colSpan;
}
return 24;
};
const getFieldOffset = (field) => {
var _a;
return ((_a = field.layout) == null ? void 0 : _a.offset) || 0;
};
const getResponsiveSpan = (breakpoint, field) => {
const breakpoints = formLayout.value.breakpoints;
if (breakpoints && breakpoints[breakpoint]) {
return Math.floor(24 / breakpoints[breakpoint]);
}
return void 0;
};
const getFieldItemClass = (field) => {
var _a;
const classes = [];
if ((_a = field.layout) == null ? void 0 : _a.className) {
classes.push(field.layout.className);
}
return classes.join(" ");
};
const getFieldItemStyle = (field) => {
var _a;
return ((_a = field.layout) == null ? void 0 : _a.style) || {};
};
const getFieldsContainerStyle = () => {
const layoutType = formLayout.value.type || "vertical";
const gutter = gutterConfig.value;
const [horizontalGutter, verticalGutter] = Array.isArray(gutter) ? gutter : [gutter, gutter];
const styles = {};
if (layoutType === "vertical" && verticalGutter > 0) {
styles.gap = `${verticalGutter}px`;
styles.display = "flex";
styles.flexDirection = "column";
} else if (layoutType === "inline" && horizontalGutter > 0) {
styles.gap = `${horizontalGutter}px`;
styles.display = "flex";
styles.flexWrap = "wrap";
styles.alignItems = "center";
}
return styles;
};
watch(
() => formContext.formValues.value,
(newValue) => {
emit("update:modelValue", newValue);
emit("change", newValue);
if (props.validateOnChange) {
const isValid = formContext.validateForm();
emit("validate", isValid, formContext.errors.value);
}
},
{ deep: true }
);
watch(
() => props.modelValue,
(newValue) => {
if (newValue && JSON.stringify(newValue) !== JSON.stringify(formContext.formValues.value)) {
Object.keys(formContext.formData).forEach((key) => {
delete formContext.formData[key];
});
Object.assign(formContext.formData, newValue);
}
},
{ deep: true }
);
const handleSubmit = () => {
const isValid = formContext.validateForm();
if (isValid) {
emit("submit", formContext.formValues.value);
} else {
emit("validate", false, formContext.errors.value);
}
};
const handleReset = () => {
formContext.resetForm();
emit("reset");
};
onMounted(() => __async(this, null, function* () {
yield formContext.initializeAsync();
}));
__expose({
validate: formContext.validateForm,
validateAsync: formContext.validateFieldAsync,
reset: formContext.resetForm,
setFieldValue: formContext.setValue,
getFieldValue: formContext.getValue,
formData: formContext.formValues,
getAsyncState: formContext.getAsyncState,
initializeAsync: formContext.initializeAsync,
// 组件注册功能
registerComponent: formContext.componentRegistry.register,
unregisterComponent: formContext.componentRegistry.unregister,
getComponent: formContext.componentRegistry.get,
hasComponent: formContext.componentRegistry.has,
getAllComponents: formContext.componentRegistry.getAll,
clearComponents: formContext.componentRegistry.clear
});
return (_ctx, _cache) => {
var _a, _b;
const _component_a_col = resolveComponent("a-col");
const _component_a_row = resolveComponent("a-row");
const _component_a_button = resolveComponent("a-button");
return openBlock(), createElementBlock("div", {
class: normalizeClass(["simple-form", formLayoutClasses.value])
}, [
isGridLayout.value ? (openBlock(), createBlock(_component_a_row, {
key: 0,
gutter: gutterConfig.value
}, {
default: withCtx(() => [
(openBlock(true), createElementBlock(Fragment, null, renderList(visibleFields.value, (field) => {
return openBlock(), createBlock(_component_a_col, {
key: field.name,
span: getFieldSpan(field),
offset: getFieldOffset(field),
xs: getResponsiveSpan("xs"),
sm: getResponsiveSpan("sm"),
md: getResponsiveSpan("md"),
lg: getResponsiveSpan("lg"),
xl: getResponsiveSpan("xl"),
xxl: getResponsiveSpan("xxl")
}, {
default: withCtx(() => [
createVNode(SimpleFormItem, { field }, null, 8, ["field"])
]),
_: 2
}, 1032, ["span", "offset", "xs", "sm", "md", "lg", "xl", "xxl"]);
}), 128))
]),
_: 1
}, 8, ["gutter"])) : (openBlock(), createElementBlock("div", {
key: 1,
class: normalizeClass(fieldsContainerClass.value),
style: normalizeStyle(getFieldsContainerStyle())
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(visibleFields.value, (field) => {
return openBlock(), createBlock(SimpleFormItem, {
key: field.name,
field,
class: normalizeClass(getFieldItemClass(field)),
style: normalizeStyle(getFieldItemStyle(field))
}, null, 8, ["field", "class", "style"]);
}), 128)),
_ctx.showActions && isInlineLayout.value ? (openBlock(), createElementBlock("div", _hoisted_1$2, [
createVNode(_component_a_button, {
type: submitButtonConfig.value.type,
size: submitButtonConfig.value.size,
loading: _ctx.submitting || submitButtonConfig.value.loading,
disabled: submitButtonConfig.value.disabled,
"html-type": submitButtonConfig.value.htmlType,
onClick: handleSubmit
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(submitButtonConfig.value.text), 1)
]),
_: 1
}, 8, ["type", "size", "loading", "disabled", "html-type"]),
_ctx.showReset && !((_a = _ctx.schema.extraButtons) == null ? void 0 : _a.length) ? (openBlock(), createBlock(_component_a_button, {
key: 0,
onClick: handleReset
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.resetText), 1)
]),
_: 1
})) : createCommentVNode("", true),
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.schema.extraButtons, (button, index2) => {
return openBlock(), createBlock(_component_a_button, {
key: `inline-extra-button-${index2}`,
type: button.type,
size: button.size,
loading: button.loading,
disabled: button.disabled,
onClick: button.onClick
}, createSlots({
default: withCtx(() => [
createTextVNode(" " + toDisplayString(button.text), 1)
]),
_: 2
}, [
button.icon ? {
name: "icon",
fn: withCtx(() => [
button.icon === "down" ? (openBlock(), createBlock(unref(DownOutlined), { key: 0 })) : createCommentVNode("", true)
]),
key: "0"
} : void 0
]), 1032, ["type", "size", "loading", "disabled", "onClick"]);
}), 128))
])) : createCommentVNode("", true)
], 6)),
_ctx.showActions && !isInlineLayout.value ? (openBlock(), createElementBlock("div", _hoisted_2$2, [
createVNode(_component_a_button, {
type: submitButtonConfig.value.type,
size: submitButtonConfig.value.size,
loading: _ctx.submitting || submitButtonConfig.value.loading,
disabled: submitButtonConfig.value.disabled,
"html-type": submitButtonConfig.value.htmlType,
onClick: handleSubmit
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(submitButtonConfig.value.text), 1)
]),
_: 1
}, 8, ["type", "size", "loading", "disabled", "html-type"]),
_ctx.showReset && !((_b = _ctx.schema.extraButtons) == null ? void 0 : _b.length) ? (openBlock(), createBlock(_component_a_button, {
key: 0,
onClick: handleReset
}, {
default: withCtx(() => [
createTextVNode(toDisplayString(_ctx.resetText), 1)
]),
_: 1
})) : createCommentVNode("", true),
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.schema.extraButtons, (button, index2) => {
return openBlock(), createBlock(_component_a_button, {
key: `extra-button-${index2}`,
type: button.type,
size: button.size,
loading: button.loading,
disabled: button.disabled,
onClick: button.onClick
}, createSlots({
default: withCtx(() => [
createTextVNode(" " + toDisplayString(button.text), 1)
]),
_: 2
}, [
button.icon ? {
name: "icon",
fn: withCtx(() => [
button.icon === "down" ? (openBlock(), createBlock(unref(DownOutlined), { key: 0 })) : createCommentVNode("", true)
]),
key: "0"
} : void 0
]), 1032, ["type", "size", "loading", "disabled", "onClick"]);
}), 128))
])) : createCommentVNode("", true)
], 2);
};
}
});
const SimpleForm = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-3cfaf46c"]]);
const _hoisted_1$1 = { class: "custom-rating-field" };
const _hoisted_2$1 = { class: "rating-stars" };
const _hoisted_3$1 = ["onClick", "onMouseenter"];
const _hoisted_4$1 = {
key: 0,
class: "rating-text"
};
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
__name: "CustomRatingField",
props: {
value: { default: 0 },
field: {},
disabled: { type: Boolean, default: false },
maxStars: { default: 5 },
showText: { type: Boolean, default: true },
textLabels: { default: () => ["很差", "较差", "一般", "较好", "很好"] }
},
emits: ["update:value", "blur", "focus"],
setup(__props, { emit: __emit }) {
const props = __props;
const emit = __emit;
const currentValue = ref(props.value || 0);
const hoverValue = ref(0);
watch(
() => props.value,
(newValue) => {
currentValue.value = newValue || 0;
}
);
computed(() => {
return hoverValue.value || currentValue.value;
});
const handleStarClick = (star) => {
currentValue.value = star;
emit("update:value", star);
emit("blur");
};
const handleStarHover = (star) => {
hoverValue.value = star;
};
const handleStarLeave = () => {
hoverValue.value = 0;
};
const getRatingText = (rating) => {
if (rating === 0) return "未评分";
const index2 = Math.min(rating - 1, props.textLabels.length - 1);
return props.textLabels[index2] || `${rating}星`;
};
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", _hoisted_1$1, [
createElementVNode("div", _hoisted_2$1, [
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.maxStars, (star) => {
return openBlock(), createElementBlock("span", {
key: star,
class: normalizeClass(["star", { active: star <= currentValue.value, disabled: _ctx.disabled }]),
onClick: ($event) => !_ctx.disabled && handleStarClick(star),
onMouseenter: ($event) => !_ctx.disabled && handleStarHover(star),
onMouseleave: _cache[0] || (_cache[0] = ($event) => !_ctx.disabled && handleStarLeave())
}, " ★ ", 42, _hoisted_3$1);
}), 128))
]),
_ctx.showText ? (openBlock(), createElementBlock("div", _hoisted_4$1, toDisplayString(getRatingText(currentValue.value)), 1)) : createCommentVNode("", true)
]);
};
}
});
const CustomRatingField = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-24777e9b"]]);
const _hoisted_1 = { class: "custom-color-picker" };
const _hoisted_2 = {
key: 0,
class: "placeholder"
};
const _hoisted_3 = ["disabled"];
const _hoisted_4 = {
key: 1,
class: "preset-colors"
};
const _hoisted_5 = ["onClick"];
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "CustomColorPicker",
props: {
value: { default: "" },
field: {},
disabled: { type: Boolean, default: false },
showInput: { type: Boolean, default: true },
showPresetColors: { type: Boolean, default: true },
presetColors: { default: () => [
"#ff4d4f",
"#fa541c",
"#fa8c16",
"#faad14",
"#fadb14",
"#a0d911",
"#52c41a",
"#13c2c2",
"#1890ff",
"#2f54eb",
"#722ed1",
"#eb2f96",
"#f5222d",
"#fa8c16",
"#fadb14"
] }
},
emits: ["update:value", "blur", "focus"],
setup(__props, { emit: __emit }) {
const props = __props;
const emit = __emit;
const currentColor = ref(props.value || "");
watch(
() => props.value,
(newValue) => {
currentColor.value = newValue || "";
}
);
const handleColorChange = (event) => {
const target = event.target;
currentColor.value = target.value;
emit("update:value", target.value);
};
const selectPresetColor = (color) => {
currentColor.value = color;
emit("update:value", color);
emit("blur");
};
const togglePicker = () => {
const colorInput = document.querySelector(".color-input");
if (colorInput) {
colorInput.click();
}
};
const handleBlur = () => {
emit("blur");
};
const handleFocus = () => {
emit("focus");
};
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", _hoisted_1, [
createElementVNode("div", {
class: "color-display",
style: normalizeStyle({ backgroundColor: currentColor.value }),
onClick: _cache[0] || (_cache[0] = ($event) => !_ctx.disabled && togglePicker)
}, [
!currentColor.value ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(_ctx.field.placeholder || "选择颜色"), 1)) : createCommentVNode("", true)
], 4),
_ctx.showInput ? withDirectives((openBlock(), createElementBlock("input", {
key: 0,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => currentColor.value = $event),
type: "color",
disabled: _ctx.disabled,
class: "color-input",
onChange: handleColorChange,
onBlur: handleBlur,
onFocus: handleFocus
}, null, 40, _hoisted_3)), [
[vModelText, currentColor.value]
]) : createCommentVNode("", true),
_ctx.showPresetColors ? (openBlock(), createElementBlock("div", _hoisted_4, [
(openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.presetColors, (color) => {
return openBlock(), createElementBlock("div", {
key: color,
class: normalizeClass(["preset-color", { active: currentColor.value === color, disabled: _ctx.disabled }]),
style: normalizeStyle({ backgroundColor: color }),
onClick: ($event) => !_ctx.disabled && selectPresetColor(color)
}, null, 14, _hoisted_5);
}), 128))
])) : createCommentVNode("", true)
]);
};
}
});
const CustomColorPicker = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f46e8b99"]]);
const install = (app, options = {}) => {
const { componentPrefix = "Simple", customComponents } = options;
app.component(`${componentPrefix}Form`, SimpleForm);
SimpleFormPlugin.install(app, { components: customComponents });
app.config.globalProperties.$dynamicForm = {
version: "2.0.0",
debug: options.debug || false,
architecture: "simplified",
customComponentsEnabled: true
};
app.provide("dynamicFormGlobalConfig", options);
};
const index = {
install,
version: "2.0.0",
architecture: "simplified"
};
const createFormSchema = (fields, options = {}) => {
return __spreadValues({
fields
}, options);
};
const createFieldConfig = (config) => {
return __spreadValues({
name: "",
type: "input",
label: "",
required: false,
placeholder: "",
options: [],
rules: []
}, config);
};
const VERSION_INFO = {
current: "2.0.0",
architecture: "simplified"
};
export {
CustomColorPicker,
CustomRatingField,
SimpleForm,
SimpleFormItem,
SimpleFormPlugin,
SimpleGroup,
_sfc_main$7 as SimpleInput,
_sfc_main$5 as SimpleRadio,
_sfc_main$6 as SimpleSelect,
VERSION_INFO,
createComponentRegistry,
createFieldConfig,
createFormSchema,
index as default,
deleteByPath,
getAllPaths,
getByPath,
globalComponentRegistry,
hasPath,
install,
setByPath,
useSimpleForm
};