@tmagic/form 1.8.2 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ import { normalizeTimestampValue } from "../../utils/form.js";
1
2
  import { useAddField } from "../../utils/useAddField.js";
2
3
  import { createBlock, defineComponent, openBlock, unref } from "vue";
3
4
  import { TMagicDatePicker } from "@tmagic/design";
@@ -26,7 +27,7 @@ var Index_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComp
26
27
  const emit = __emit;
27
28
  useAddField(props.prop);
28
29
  const changeHandler = (v) => {
29
- emit("change", v);
30
+ emit("change", normalizeTimestampValue(v, props.config.valueFormat));
30
31
  };
31
32
  return (_ctx, _cache) => {
32
33
  return openBlock(), createBlock(unref(TMagicDatePicker), {
@@ -1,3 +1,4 @@
1
+ import { normalizeTimestampValue } from "../../utils/form.js";
1
2
  import { useAddField } from "../../utils/useAddField.js";
2
3
  import { createBlock, defineComponent, openBlock, unref } from "vue";
3
4
  import { TMagicDatePicker } from "@tmagic/design";
@@ -26,7 +27,7 @@ var Index_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComp
26
27
  const emit = __emit;
27
28
  useAddField(props.prop);
28
29
  const changeHandler = (v) => {
29
- emit("change", v);
30
+ emit("change", normalizeTimestampValue(v, props.config.valueFormat));
30
31
  };
31
32
  return (_ctx, _cache) => {
32
33
  return openBlock(), createBlock(unref(TMagicDatePicker), {
@@ -1,4 +1,4 @@
1
- import { datetimeFormatter } from "../utils/form.js";
1
+ import { datetimeFormatter, normalizeTimestampValue } from "../utils/form.js";
2
2
  import { useAddField } from "../utils/useAddField.js";
3
3
  import { createBlock, defineComponent, onUnmounted, openBlock, ref, unref, watch } from "vue";
4
4
  import { TMagicDatePicker } from "@tmagic/design";
@@ -28,22 +28,27 @@ var Daterange_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
28
28
  useAddField(props.prop);
29
29
  const { names } = props.config;
30
30
  const value = ref([]);
31
+ const rangeFormat = () => `${props.config.dateFormat || "YYYY/MM/DD"} ${props.config.timeFormat || "HH:mm:ss"}`;
32
+ /** `X` 的选择器值就是秒级数字,展示格式不能拿去代替 valueFormat。 */
33
+ const toPickerValue = (item) => {
34
+ if (!item) return void 0;
35
+ if (props.config.valueFormat === "X") return normalizeTimestampValue(item, "X");
36
+ return datetimeFormatter(item, "", rangeFormat());
37
+ };
31
38
  if (props.model !== void 0) {
32
39
  if (names?.length) {
33
40
  const unWatch = watch([() => props.model[names[0]], () => props.model[names[1]]], ([start, end], [preStart, preEnd]) => {
34
41
  if (!value.value) value.value = [];
35
- const format = `${props.config.dateFormat || "YYYY/MM/DD"} ${props.config.timeFormat || "HH:mm:ss"}`;
36
42
  if (!start || !end) value.value = [];
37
- if (start !== preStart) value.value[0] = datetimeFormatter(start, "", format);
38
- if (end !== preEnd) value.value[1] = datetimeFormatter(end, "", format);
43
+ if (start !== preStart) value.value[0] = toPickerValue(start);
44
+ if (end !== preEnd) value.value[1] = toPickerValue(end);
39
45
  }, { immediate: true });
40
46
  onUnmounted(() => {
41
47
  unWatch();
42
48
  });
43
49
  } else if (props.name && props.model[props.name]) {
44
50
  const unWatch = watch(() => props.model[props.name], (start, preStart) => {
45
- const format = `${props.config.dateFormat || "YYYY/MM/DD"} ${props.config.timeFormat || "HH:mm:ss"}`;
46
- if (start !== preStart) value.value = start.map((item) => item ? datetimeFormatter(item, "", format) : void 0);
51
+ if (start !== preStart) value.value = start.map((item) => toPickerValue(item));
47
52
  }, { immediate: true });
48
53
  onUnmounted(() => {
49
54
  unWatch();
@@ -51,15 +56,16 @@ var Daterange_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
51
56
  }
52
57
  }
53
58
  const changeHandler = (v) => {
54
- const value = v || [];
59
+ const normalized = normalizeTimestampValue(v, props.config.valueFormat);
60
+ const value = normalized || [];
55
61
  if (props.name) emit("change", value);
56
62
  else if (props.config.names?.length) {
57
63
  const newChangeRecords = [];
58
64
  props.config.names.forEach((item, index) => {
59
65
  if (!props.model) return;
60
- if (Array.isArray(v)) newChangeRecords.push({
66
+ if (Array.isArray(normalized)) newChangeRecords.push({
61
67
  propPath: props.prop ? `${props.prop}.${item}` : item,
62
- value: v[index]
68
+ value: normalized[index]
63
69
  });
64
70
  else newChangeRecords.push({
65
71
  propPath: props.prop ? `${props.prop}.${item}` : item,
@@ -1,3 +1,4 @@
1
+ import { normalizeTimestampValue } from "../utils/form.js";
1
2
  import { useAddField } from "../utils/useAddField.js";
2
3
  import { createBlock, defineComponent, openBlock, unref } from "vue";
3
4
  import { TMagicTimePicker } from "@tmagic/design";
@@ -26,7 +27,7 @@ var Time_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
26
27
  const emit = __emit;
27
28
  useAddField(props.prop);
28
29
  const changeHandler = (v) => {
29
- emit("change", v);
30
+ emit("change", normalizeTimestampValue(v, props.config.valueFormat));
30
31
  };
31
32
  return (_ctx, _cache) => {
32
33
  return openBlock(), createBlock(unref(TMagicTimePicker), {
@@ -1,4 +1,4 @@
1
- import { datetimeFormatter } from "../utils/form.js";
1
+ import { datetimeFormatter, normalizeTimestampValue } from "../utils/form.js";
2
2
  import { useAddField } from "../utils/useAddField.js";
3
3
  import { createBlock, defineComponent, onUnmounted, openBlock, ref, unref, watch } from "vue";
4
4
  import dayjs from "dayjs";
@@ -32,21 +32,26 @@ var Timerange_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
32
32
  const getFullDatetime = (item) => item ? `${dayjs().format("YYYY/MM/DD")} ${item}` : "";
33
33
  const getFormat = () => `YYYY/MM/DD ${props.config.valueFormat || "HH:mm:ss"}`;
34
34
  const timeFormatter = (time, format) => datetimeFormatter(getFullDatetime(time), "", format).substring(11);
35
+ /** `X` 的选择器值就是秒级数字,不能再拼成日期后截取。 */
36
+ const toPickerValue = (time) => {
37
+ if (!time) return void 0;
38
+ if (props.config.valueFormat === "X") return normalizeTimestampValue(time, "X");
39
+ return timeFormatter(time, getFormat());
40
+ };
35
41
  if (props.model !== void 0) {
36
42
  if (names?.length) {
37
43
  const unWatch = watch([() => props.model[names[0]], () => props.model[names[1]]], ([start, end], [preStart, preEnd]) => {
38
44
  if (!value.value) value.value = [];
39
- const format = getFormat();
40
45
  if (!start || !end) value.value = [];
41
- if (start !== preStart) value.value[0] = timeFormatter(start, format);
42
- if (end !== preEnd) value.value[1] = timeFormatter(end, format);
46
+ if (start !== preStart) value.value[0] = toPickerValue(start);
47
+ if (end !== preEnd) value.value[1] = toPickerValue(end);
43
48
  }, { immediate: true });
44
49
  onUnmounted(() => {
45
50
  unWatch();
46
51
  });
47
52
  } else if (props.name) {
48
53
  const unWatch = watch(() => props.model[props.name], (v = []) => {
49
- if (Array.isArray(v)) value.value = v.map((item) => item ? timeFormatter(item, getFormat()) : void 0);
54
+ if (Array.isArray(v)) value.value = v.map((item) => toPickerValue(item));
50
55
  else value.value = [];
51
56
  }, { immediate: true });
52
57
  onUnmounted(() => {
@@ -55,15 +60,16 @@ var Timerange_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
55
60
  }
56
61
  }
57
62
  const changeHandler = (v) => {
58
- const value = v || [];
63
+ const normalized = normalizeTimestampValue(v, props.config.valueFormat);
64
+ const value = normalized || [];
59
65
  if (props.name) emit("change", value);
60
66
  else if (props.config.names?.length) {
61
67
  const newChangeRecords = [];
62
68
  props.config.names.forEach((item, index) => {
63
69
  if (!props.model) return;
64
- if (Array.isArray(v)) newChangeRecords.push({
70
+ if (Array.isArray(normalized)) newChangeRecords.push({
65
71
  propPath: props.prop ? `${props.prop}.${item}` : item,
66
- value: v[index]
72
+ value: normalized[index]
67
73
  });
68
74
  else newChangeRecords.push({
69
75
  propPath: props.prop ? `${props.prop}.${item}` : item,
@@ -2,7 +2,7 @@ import { FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY } fro
2
2
  import { isLeafFieldType } from "./utils/fieldValueEffects.js";
3
3
  import { MAX_SUGGESTION_OPTIONS, clearTypeMatchRules, deleteTypeMatchRule, getTypeMatchRule, optionSuggestion, stringifyExampleValue, validateTypeMatch } from "./utils/typeMatch.js";
4
4
  import { createFormStateProxy, mergeFormContexts } from "./utils/formStateProxy.js";
5
- import { adaptFormValidator, appendProp, createFormStateBase, createObjectProp, createValues, datetimeFormatter, display, filterFunction, getDataByPage, getItemProp, getNativeRules, getRules, initValue, isValidName, resolveItemType, sortArray, sortChange } from "./utils/form.js";
5
+ import { adaptFormValidator, appendProp, createFormStateBase, createObjectProp, createValues, datetimeFormatter, display, filterFunction, getDataByPage, getItemProp, getNativeRules, getRules, initValue, isValidName, normalizeTimestampValue, resolveItemType, sortArray, sortChange } from "./utils/form.js";
6
6
  import { FieldInnerConfigError, applyMountValueEffects, collectValidatableFields, isFieldInnerConfigError } from "./utils/collectFields.js";
7
7
  import { formatValidateError, getTextByName } from "./utils/validateError.js";
8
8
  import { createHeadlessFormState, validateValues } from "./utils/validateValues.js";
@@ -10,4 +10,4 @@ import { submitForm, validateForm } from "./utils/submitHeadless.js";
10
10
  import { clearFields, getField, mergeFieldOptions, registerBuiltInFields, registerField, registerFields, unregisterField } from "./utils/registerField.js";
11
11
  import { builtInFields } from "./utils/builtInFields.js";
12
12
  export * from "@tmagic/form-schema";
13
- export { FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FieldInnerConfigError, MAX_SUGGESTION_OPTIONS, adaptFormValidator, appendProp, applyMountValueEffects, builtInFields, clearFields, clearTypeMatchRules, collectValidatableFields, createFormStateBase, createFormStateProxy, createHeadlessFormState, createObjectProp, createValues, datetimeFormatter, deleteTypeMatchRule, display, filterFunction, formatValidateError, getDataByPage, getField as getFormField, getItemProp, getNativeRules, getRules, getTextByName, getTypeMatchRule, initValue, isFieldInnerConfigError, isLeafFieldType, isValidName, mergeFieldOptions, mergeFormContexts, optionSuggestion, registerBuiltInFields, registerField, registerFields, resolveItemType, sortArray, sortChange, stringifyExampleValue, submitForm, unregisterField, validateForm, validateTypeMatch, validateValues };
13
+ export { FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FieldInnerConfigError, MAX_SUGGESTION_OPTIONS, adaptFormValidator, appendProp, applyMountValueEffects, builtInFields, clearFields, clearTypeMatchRules, collectValidatableFields, createFormStateBase, createFormStateProxy, createHeadlessFormState, createObjectProp, createValues, datetimeFormatter, deleteTypeMatchRule, display, filterFunction, formatValidateError, getDataByPage, getField as getFormField, getItemProp, getNativeRules, getRules, getTextByName, getTypeMatchRule, initValue, isFieldInnerConfigError, isLeafFieldType, isValidName, mergeFieldOptions, mergeFormContexts, normalizeTimestampValue, optionSuggestion, registerBuiltInFields, registerField, registerFields, resolveItemType, sortArray, sortChange, stringifyExampleValue, submitForm, unregisterField, validateForm, validateTypeMatch, validateValues };
package/dist/es/index.js CHANGED
@@ -2,7 +2,7 @@ import { FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY } fro
2
2
  import { isLeafFieldType } from "./utils/fieldValueEffects.js";
3
3
  import { MAX_SUGGESTION_OPTIONS, clearTypeMatchRules, deleteTypeMatchRule, getTypeMatchRule, optionSuggestion, stringifyExampleValue, validateTypeMatch } from "./utils/typeMatch.js";
4
4
  import { createFormStateProxy, mergeFormContexts } from "./utils/formStateProxy.js";
5
- import { adaptFormValidator, appendProp, createFormStateBase, createObjectProp, createValues, datetimeFormatter, display, filterFunction, getDataByPage, getItemProp, getNativeRules, getRules, initValue, isValidName, resolveItemType, sortArray, sortChange } from "./utils/form.js";
5
+ import { adaptFormValidator, appendProp, createFormStateBase, createObjectProp, createValues, datetimeFormatter, display, filterFunction, getDataByPage, getItemProp, getNativeRules, getRules, initValue, isValidName, normalizeTimestampValue, resolveItemType, sortArray, sortChange } from "./utils/form.js";
6
6
  import { FieldInnerConfigError, applyMountValueEffects, collectValidatableFields, isFieldInnerConfigError } from "./utils/collectFields.js";
7
7
  import { formatValidateError, getTextByName } from "./utils/validateError.js";
8
8
  import { createHeadlessFormState, validateValues } from "./utils/validateValues.js";
@@ -46,4 +46,4 @@ export * from "@tmagic/form-schema";
46
46
  //#region packages/form/src/index.ts
47
47
  var createForm = (config) => config;
48
48
  //#endregion
49
- export { FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FieldInnerConfigError, MAX_SUGGESTION_OPTIONS, Cascader_default as MCascader, Checkbox_default as MCheckbox, Index_default as MCheckboxGroup, ColorPicker_default as MColorPicker, Container_default as MContainer, Index_default$1 as MDate, Index_default$2 as MDateTime, Daterange_default as MDaterange, Index_default$3 as MDisplay, Index_default$4 as MDynamicField, Fieldset_default as MFieldset, FlexLayout_default as MFlexLayout, Form_default as MForm, FormBox_default as MFormBox, FormDialog_default as MFormDialog, FormDrawer_default as MFormDrawer, TableGroupList_default as MGroupList, Hidden_default as MHidden, Link_default as MLink, Number_default as MNumber, Index_default$5 as MNumberRange, Panel_default as MPanel, RadioGroup_default as MRadioGroup, Row_default as MRow, Select_default as MSelect, Switch_default as MSwitch, TableGroupList_default as MTable, TableGroupList_default as MTableGroupList, Tabs_default as MTabs, Text_default as MText, Textarea_default as MTextarea, Time_default as MTime, Timerange_default as MTimerange, adaptFormValidator, appendProp, applyMountValueEffects, builtInFields, clearFields, clearTypeMatchRules, collectValidatableFields, createForm, createFormStateBase, createFormStateProxy, createHeadlessFormState, createObjectProp, createValues, datetimeFormatter, plugin_default as default, deleteTypeMatchRule, display, filterFunction, formatValidateError, getDataByPage, getField as getFormField, getItemProp, getNativeRules, getRules, getTextByName, getTypeMatchRule, initValue, isFieldInnerConfigError, isLeafFieldType, isValidName, mergeFieldOptions, mergeFormContexts, optionSuggestion, registerBuiltInFields, registerField, registerFields, resolveItemType, sortArray, sortChange, stringifyExampleValue, stripTabItemsLazy, submitForm, unregisterField, useAddField, validateForm, validateTypeMatch, validateValues };
49
+ export { FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FieldInnerConfigError, MAX_SUGGESTION_OPTIONS, Cascader_default as MCascader, Checkbox_default as MCheckbox, Index_default as MCheckboxGroup, ColorPicker_default as MColorPicker, Container_default as MContainer, Index_default$1 as MDate, Index_default$2 as MDateTime, Daterange_default as MDaterange, Index_default$3 as MDisplay, Index_default$4 as MDynamicField, Fieldset_default as MFieldset, FlexLayout_default as MFlexLayout, Form_default as MForm, FormBox_default as MFormBox, FormDialog_default as MFormDialog, FormDrawer_default as MFormDrawer, TableGroupList_default as MGroupList, Hidden_default as MHidden, Link_default as MLink, Number_default as MNumber, Index_default$5 as MNumberRange, Panel_default as MPanel, RadioGroup_default as MRadioGroup, Row_default as MRow, Select_default as MSelect, Switch_default as MSwitch, TableGroupList_default as MTable, TableGroupList_default as MTableGroupList, Tabs_default as MTabs, Text_default as MText, Textarea_default as MTextarea, Time_default as MTime, Timerange_default as MTimerange, adaptFormValidator, appendProp, applyMountValueEffects, builtInFields, clearFields, clearTypeMatchRules, collectValidatableFields, createForm, createFormStateBase, createFormStateProxy, createHeadlessFormState, createObjectProp, createValues, datetimeFormatter, plugin_default as default, deleteTypeMatchRule, display, filterFunction, formatValidateError, getDataByPage, getField as getFormField, getItemProp, getNativeRules, getRules, getTextByName, getTypeMatchRule, initValue, isFieldInnerConfigError, isLeafFieldType, isValidName, mergeFieldOptions, mergeFormContexts, normalizeTimestampValue, optionSuggestion, registerBuiltInFields, registerField, registerFields, resolveItemType, sortArray, sortChange, stringifyExampleValue, stripTabItemsLazy, submitForm, unregisterField, useAddField, validateForm, validateTypeMatch, validateValues };
@@ -1,5 +1,5 @@
1
1
  import { getConfig } from "./config.js";
2
- import { createTypeMatchValidator } from "./typeMatch.js";
2
+ import { TIMESTAMP_VALUE_FORMATS, createTypeMatchValidator } from "./typeMatch.js";
3
3
  import { createFormStateProxy, mergeFormContexts } from "./formStateProxy.js";
4
4
  import { readonly, unref } from "vue";
5
5
  import { cloneDeep } from "lodash-es";
@@ -269,10 +269,33 @@ var initValue = async (mForm, { initValues, config }) => {
269
269
  });
270
270
  return valuesTmp || {};
271
271
  };
272
+ /**
273
+ * 把值收成 Unix 秒,无法解析时返回 undefined。
274
+ *
275
+ * 纯数字(含数字字符串)按已是秒处理:dayjs 会把数字当成毫秒,不能再过一遍。
276
+ * Date、ISO 和日期字符串则解析后取秒。
277
+ */
278
+ var toUnixSeconds = (v) => {
279
+ if (typeof v === "number") return Number.isFinite(v) ? Math.trunc(v) : void 0;
280
+ if (typeof v === "string" && /^-?\d+$/.test(v.trim())) return Math.trunc(Number(v));
281
+ const parsed = dayjs(v);
282
+ return parsed.isValid() ? parsed.unix() : void 0;
283
+ };
284
+ /**
285
+ * `valueFormat: 'X'` 时把选择器值收成秒级 number,其余格式原样返回。
286
+ * Element Plus 对 `X` 写出的是秒字符串(`x` 才会直接给毫秒数字);空值、无法解析的值原样返回。
287
+ */
288
+ var normalizeTimestampValue = (value, valueFormat) => {
289
+ if (valueFormat !== "X") return value;
290
+ if (Array.isArray(value)) return value.map((item) => normalizeTimestampValue(item, valueFormat));
291
+ if (value === null || value === void 0 || value === "") return value;
292
+ return toUnixSeconds(value) ?? value;
293
+ };
272
294
  var datetimeFormatter = (v, defaultValue = "-", format = "YYYY-MM-DD HH:mm:ss") => {
273
295
  if (v) {
274
296
  let time;
275
- if (["x", "timestamp"].includes(format)) time = dayjs(Number.isNaN(Number(v)) ? v : Number(v)).valueOf();
297
+ if (format === "X") time = toUnixSeconds(v) ?? "Invalid Date";
298
+ else if (TIMESTAMP_VALUE_FORMATS.has(format)) time = dayjs(Number.isNaN(Number(v)) ? v : Number(v)).valueOf();
276
299
  else if (typeof v === "string" && v.includes("Z") || v instanceof Date) {
277
300
  dayjs.extend(utc);
278
301
  time = dayjs(v).utcOffset(8).format(format);
@@ -307,4 +330,4 @@ var createObjectProp = (prop, key, name) => {
307
330
  return `${[...itemPath, key].join(".")}`;
308
331
  };
309
332
  //#endregion
310
- export { adaptFormValidator, appendProp, createFormStateBase, createFormStateProxy, createObjectProp, createValues, datetimeFormatter, display, filterFunction, getDataByPage, getItemProp, getNativeRules, getRules, initValue, isValidName, mergeFormContexts, resolveItemType, sortArray, sortChange };
333
+ export { adaptFormValidator, appendProp, createFormStateBase, createFormStateProxy, createObjectProp, createValues, datetimeFormatter, display, filterFunction, getDataByPage, getItemProp, getNativeRules, getRules, initValue, isValidName, mergeFormContexts, normalizeTimestampValue, resolveItemType, sortArray, sortChange };
@@ -86,7 +86,11 @@ var DATE_LIKE_DEFAULT_VALUE_FORMAT = {
86
86
  daterange: "YYYY/MM/DD HH:mm:ss",
87
87
  timerange: "HH:mm:ss"
88
88
  };
89
- var TIMESTAMP_VALUE_FORMATS = /* @__PURE__ */ new Set(["x", "timestamp"]);
89
+ var TIMESTAMP_VALUE_FORMATS = /* @__PURE__ */ new Set([
90
+ "x",
91
+ "X",
92
+ "timestamp"
93
+ ]);
90
94
  /**
91
95
  * 将值格式化为可读的参考示例字符串。
92
96
  */
@@ -179,23 +183,31 @@ var isEmptyArray = (value) => Array.isArray(value) && value.length === 0;
179
183
  var resolveDateValueFormat = (fieldType, config) => config.valueFormat || DATE_LIKE_DEFAULT_VALUE_FORMAT[fieldType] || "YYYY/MM/DD HH:mm:ss";
180
184
  var isTimestampValueFormat = (valueFormat) => TIMESTAMP_VALUE_FORMATS.has(valueFormat);
181
185
  var isValidDateValueByFormat = (value, valueFormat) => {
182
- if (isTimestampValueFormat(valueFormat)) return typeof value === "number" && !Number.isNaN(value);
186
+ if (isTimestampValueFormat(valueFormat)) {
187
+ if (typeof value !== "number") return false;
188
+ return valueFormat === "X" ? Number.isInteger(value) : !Number.isNaN(value);
189
+ }
183
190
  if (typeof value !== "string") return false;
184
191
  return dayjs(value, valueFormat, true).isValid();
185
192
  };
186
193
  /**
187
194
  * 生成单个日期类字段的参考示例值:时间戳格式给出当前时间戳,其余按 valueFormat 格式化当前时间。
188
195
  */
189
- var dateSuggestion = (valueFormat) => isTimestampValueFormat(valueFormat) ? `请参考以下示例值:${Date.now()}` : `请参考以下示例值:"${dayjs().format(valueFormat)}"`;
196
+ var timestampExample = (valueFormat) => valueFormat === "X" ? Math.floor(Date.now() / 1e3) : Date.now();
197
+ var dateSuggestion = (valueFormat) => isTimestampValueFormat(valueFormat) ? `请参考以下示例值:${timestampExample(valueFormat)}` : `请参考以下示例值:"${dayjs().format(valueFormat)}"`;
190
198
  /**
191
199
  * 生成日期范围类字段的参考示例值(长度为 2 的数组)。
192
200
  */
193
201
  var dateRangeSuggestion = (valueFormat) => {
194
- if (isTimestampValueFormat(valueFormat)) return `请参考以下示例值:[${Date.now()}, ${Date.now()}]`;
202
+ if (isTimestampValueFormat(valueFormat)) {
203
+ const example = timestampExample(valueFormat);
204
+ return `请参考以下示例值:[${example}, ${example}]`;
205
+ }
195
206
  const example = dayjs().format(valueFormat);
196
207
  return `请参考以下示例值:["${example}", "${example}"]`;
197
208
  };
198
- var dateValueFormatErrorMessage = (message, valueFormat) => defaultMessage(message, isTimestampValueFormat(valueFormat) ? "值类型应为时间戳数字" : `值格式应为 ${valueFormat}`, dateSuggestion(valueFormat));
209
+ var timestampTypeLabel = (valueFormat) => valueFormat === "X" ? "秒级时间戳数字" : "毫秒级时间戳数字";
210
+ var dateValueFormatErrorMessage = (message, valueFormat) => defaultMessage(message, isTimestampValueFormat(valueFormat) ? `值类型应为${timestampTypeLabel(valueFormat)}` : `值格式应为 ${valueFormat}`, dateSuggestion(valueFormat));
199
211
  var resolveToggleValues = (config) => {
200
212
  const filterIsNumber = config.filter === "number";
201
213
  const { activeValue: configActiveValue, inactiveValue: configInactiveValue } = config;
@@ -392,7 +404,7 @@ var validateBuiltinTypeMatch = (value, fieldType, mForm, props, message) => {
392
404
  if (fieldType === "daterange" || fieldType === "timerange") {
393
405
  if (config.names) return;
394
406
  const valueFormat = resolveDateValueFormat(fieldType, config);
395
- if (!Array.isArray(value) || value.length !== 2 || value.some((item) => !isValidDateValueByFormat(item, valueFormat))) return defaultMessage(message, isTimestampValueFormat(valueFormat) ? `${formatErrorValue(value)} 类型应为长度为 2 的时间戳数字数组` : `${formatErrorValue(value)} 格式应为长度为 2 的 ${valueFormat} 数组`, dateRangeSuggestion(valueFormat));
407
+ if (!Array.isArray(value) || value.length !== 2 || value.some((item) => !isValidDateValueByFormat(item, valueFormat))) return defaultMessage(message, isTimestampValueFormat(valueFormat) ? `${formatErrorValue(value)} 类型应为长度为 2 的${timestampTypeLabel(valueFormat)}数组` : `${formatErrorValue(value)} 格式应为长度为 2 的 ${valueFormat} 数组`, dateRangeSuggestion(valueFormat));
396
408
  return;
397
409
  }
398
410
  if (fieldType === "table" || fieldType === "group-list" || fieldType === "grouplist") {
@@ -529,4 +541,4 @@ var createTypeMatchValidator = (mForm, props, rule) => {
529
541
  };
530
542
  };
531
543
  //#endregion
532
- export { MAX_SUGGESTION_OPTIONS, clearTypeMatchRules, createTypeMatchValidator, deleteTypeMatchRule, getTypeMatchRule, optionSuggestion, registerTypeMatchRule, stringifyExampleValue, validateTypeMatch };
544
+ export { MAX_SUGGESTION_OPTIONS, TIMESTAMP_VALUE_FORMATS, clearTypeMatchRules, createTypeMatchValidator, deleteTypeMatchRule, getTypeMatchRule, optionSuggestion, registerTypeMatchRule, stringifyExampleValue, validateTypeMatch };
@@ -3,8 +3,9 @@ import { createFormStateBase, initValue } from "./form.js";
3
3
  import { applyMountValueEffects, collectValidatableFields } from "./collectFields.js";
4
4
  import { formatValidateError } from "./validateError.js";
5
5
  import { reactive } from "vue";
6
- import Schema from "async-validator";
6
+ import AsyncValidator from "async-validator";
7
7
  //#region packages/form/src/utils/validateValues.ts
8
+ var Schema = AsyncValidator.default ?? AsyncValidator;
8
9
  /**
9
10
  * 构造一个不依赖组件实例的 `formState`。
10
11
  *
@@ -2514,7 +2514,11 @@
2514
2514
  daterange: "YYYY/MM/DD HH:mm:ss",
2515
2515
  timerange: "HH:mm:ss"
2516
2516
  };
2517
- var TIMESTAMP_VALUE_FORMATS = /* @__PURE__ */ new Set(["x", "timestamp"]);
2517
+ var TIMESTAMP_VALUE_FORMATS = /* @__PURE__ */ new Set([
2518
+ "x",
2519
+ "X",
2520
+ "timestamp"
2521
+ ]);
2518
2522
  /**
2519
2523
  * 将值格式化为可读的参考示例字符串。
2520
2524
  */
@@ -2607,23 +2611,31 @@
2607
2611
  var resolveDateValueFormat = (fieldType, config) => config.valueFormat || DATE_LIKE_DEFAULT_VALUE_FORMAT[fieldType] || "YYYY/MM/DD HH:mm:ss";
2608
2612
  var isTimestampValueFormat = (valueFormat) => TIMESTAMP_VALUE_FORMATS.has(valueFormat);
2609
2613
  var isValidDateValueByFormat = (value, valueFormat) => {
2610
- if (isTimestampValueFormat(valueFormat)) return typeof value === "number" && !Number.isNaN(value);
2614
+ if (isTimestampValueFormat(valueFormat)) {
2615
+ if (typeof value !== "number") return false;
2616
+ return valueFormat === "X" ? Number.isInteger(value) : !Number.isNaN(value);
2617
+ }
2611
2618
  if (typeof value !== "string") return false;
2612
2619
  return (0, dayjs.default)(value, valueFormat, true).isValid();
2613
2620
  };
2614
2621
  /**
2615
2622
  * 生成单个日期类字段的参考示例值:时间戳格式给出当前时间戳,其余按 valueFormat 格式化当前时间。
2616
2623
  */
2617
- var dateSuggestion = (valueFormat) => isTimestampValueFormat(valueFormat) ? `请参考以下示例值:${Date.now()}` : `请参考以下示例值:"${(0, dayjs.default)().format(valueFormat)}"`;
2624
+ var timestampExample = (valueFormat) => valueFormat === "X" ? Math.floor(Date.now() / 1e3) : Date.now();
2625
+ var dateSuggestion = (valueFormat) => isTimestampValueFormat(valueFormat) ? `请参考以下示例值:${timestampExample(valueFormat)}` : `请参考以下示例值:"${(0, dayjs.default)().format(valueFormat)}"`;
2618
2626
  /**
2619
2627
  * 生成日期范围类字段的参考示例值(长度为 2 的数组)。
2620
2628
  */
2621
2629
  var dateRangeSuggestion = (valueFormat) => {
2622
- if (isTimestampValueFormat(valueFormat)) return `请参考以下示例值:[${Date.now()}, ${Date.now()}]`;
2630
+ if (isTimestampValueFormat(valueFormat)) {
2631
+ const example = timestampExample(valueFormat);
2632
+ return `请参考以下示例值:[${example}, ${example}]`;
2633
+ }
2623
2634
  const example = (0, dayjs.default)().format(valueFormat);
2624
2635
  return `请参考以下示例值:["${example}", "${example}"]`;
2625
2636
  };
2626
- var dateValueFormatErrorMessage = (message, valueFormat) => defaultMessage(message, isTimestampValueFormat(valueFormat) ? "值类型应为时间戳数字" : `值格式应为 ${valueFormat}`, dateSuggestion(valueFormat));
2637
+ var timestampTypeLabel = (valueFormat) => valueFormat === "X" ? "秒级时间戳数字" : "毫秒级时间戳数字";
2638
+ var dateValueFormatErrorMessage = (message, valueFormat) => defaultMessage(message, isTimestampValueFormat(valueFormat) ? `值类型应为${timestampTypeLabel(valueFormat)}` : `值格式应为 ${valueFormat}`, dateSuggestion(valueFormat));
2627
2639
  var resolveToggleValues = (config) => {
2628
2640
  const filterIsNumber = config.filter === "number";
2629
2641
  const { activeValue: configActiveValue, inactiveValue: configInactiveValue } = config;
@@ -2820,7 +2832,7 @@
2820
2832
  if (fieldType === "daterange" || fieldType === "timerange") {
2821
2833
  if (config.names) return;
2822
2834
  const valueFormat = resolveDateValueFormat(fieldType, config);
2823
- if (!Array.isArray(value) || value.length !== 2 || value.some((item) => !isValidDateValueByFormat(item, valueFormat))) return defaultMessage(message, isTimestampValueFormat(valueFormat) ? `${formatErrorValue(value)} 类型应为长度为 2 的时间戳数字数组` : `${formatErrorValue(value)} 格式应为长度为 2 的 ${valueFormat} 数组`, dateRangeSuggestion(valueFormat));
2835
+ if (!Array.isArray(value) || value.length !== 2 || value.some((item) => !isValidDateValueByFormat(item, valueFormat))) return defaultMessage(message, isTimestampValueFormat(valueFormat) ? `${formatErrorValue(value)} 类型应为长度为 2 的${timestampTypeLabel(valueFormat)}数组` : `${formatErrorValue(value)} 格式应为长度为 2 的 ${valueFormat} 数组`, dateRangeSuggestion(valueFormat));
2824
2836
  return;
2825
2837
  }
2826
2838
  if (fieldType === "table" || fieldType === "group-list" || fieldType === "grouplist") {
@@ -3328,10 +3340,33 @@
3328
3340
  });
3329
3341
  return valuesTmp || {};
3330
3342
  };
3343
+ /**
3344
+ * 把值收成 Unix 秒,无法解析时返回 undefined。
3345
+ *
3346
+ * 纯数字(含数字字符串)按已是秒处理:dayjs 会把数字当成毫秒,不能再过一遍。
3347
+ * Date、ISO 和日期字符串则解析后取秒。
3348
+ */
3349
+ var toUnixSeconds = (v) => {
3350
+ if (typeof v === "number") return Number.isFinite(v) ? Math.trunc(v) : void 0;
3351
+ if (typeof v === "string" && /^-?\d+$/.test(v.trim())) return Math.trunc(Number(v));
3352
+ const parsed = (0, dayjs.default)(v);
3353
+ return parsed.isValid() ? parsed.unix() : void 0;
3354
+ };
3355
+ /**
3356
+ * `valueFormat: 'X'` 时把选择器值收成秒级 number,其余格式原样返回。
3357
+ * Element Plus 对 `X` 写出的是秒字符串(`x` 才会直接给毫秒数字);空值、无法解析的值原样返回。
3358
+ */
3359
+ var normalizeTimestampValue = (value, valueFormat) => {
3360
+ if (valueFormat !== "X") return value;
3361
+ if (Array.isArray(value)) return value.map((item) => normalizeTimestampValue(item, valueFormat));
3362
+ if (value === null || value === void 0 || value === "") return value;
3363
+ return toUnixSeconds(value) ?? value;
3364
+ };
3331
3365
  var datetimeFormatter = (v, defaultValue = "-", format = "YYYY-MM-DD HH:mm:ss") => {
3332
3366
  if (v) {
3333
3367
  let time;
3334
- if (["x", "timestamp"].includes(format)) time = (0, dayjs.default)(Number.isNaN(Number(v)) ? v : Number(v)).valueOf();
3368
+ if (format === "X") time = toUnixSeconds(v) ?? "Invalid Date";
3369
+ else if (TIMESTAMP_VALUE_FORMATS.has(format)) time = (0, dayjs.default)(Number.isNaN(Number(v)) ? v : Number(v)).valueOf();
3335
3370
  else if (typeof v === "string" && v.includes("Z") || v instanceof Date) {
3336
3371
  dayjs.default.extend(dayjs_plugin_utc_js.default);
3337
3372
  time = (0, dayjs.default)(v).utcOffset(8).format(format);
@@ -4297,6 +4332,7 @@
4297
4332
  };
4298
4333
  //#endregion
4299
4334
  //#region packages/form/src/utils/validateValues.ts
4335
+ var Schema = async_validator.default.default ?? async_validator.default;
4300
4336
  /**
4301
4337
  * 构造一个不依赖组件实例的 `formState`。
4302
4338
  *
@@ -4349,7 +4385,7 @@
4349
4385
  if (!rules.length) return null;
4350
4386
  const value = getFieldValue(field.prop, values);
4351
4387
  try {
4352
- await new async_validator.default({ [field.prop]: rules }).validate({ [field.prop]: value }, { firstFields: true });
4388
+ await new Schema({ [field.prop]: rules }).validate({ [field.prop]: value }, { firstFields: true });
4353
4389
  return null;
4354
4390
  } catch (err) {
4355
4391
  if (err?.fields) return err.fields;
@@ -4490,6 +4526,7 @@
4490
4526
  exports.isValidName = isValidName;
4491
4527
  exports.mergeFieldOptions = mergeFieldOptions;
4492
4528
  exports.mergeFormContexts = mergeFormContexts;
4529
+ exports.normalizeTimestampValue = normalizeTimestampValue;
4493
4530
  exports.optionSuggestion = optionSuggestion;
4494
4531
  exports.registerBuiltInFields = registerBuiltInFields;
4495
4532
  exports.registerField = registerField;
@@ -2982,7 +2982,11 @@
2982
2982
  daterange: "YYYY/MM/DD HH:mm:ss",
2983
2983
  timerange: "HH:mm:ss"
2984
2984
  };
2985
- var TIMESTAMP_VALUE_FORMATS = /* @__PURE__ */ new Set(["x", "timestamp"]);
2985
+ var TIMESTAMP_VALUE_FORMATS = /* @__PURE__ */ new Set([
2986
+ "x",
2987
+ "X",
2988
+ "timestamp"
2989
+ ]);
2986
2990
  /**
2987
2991
  * 将值格式化为可读的参考示例字符串。
2988
2992
  */
@@ -3075,23 +3079,31 @@
3075
3079
  var resolveDateValueFormat = (fieldType, config) => config.valueFormat || DATE_LIKE_DEFAULT_VALUE_FORMAT[fieldType] || "YYYY/MM/DD HH:mm:ss";
3076
3080
  var isTimestampValueFormat = (valueFormat) => TIMESTAMP_VALUE_FORMATS.has(valueFormat);
3077
3081
  var isValidDateValueByFormat = (value, valueFormat) => {
3078
- if (isTimestampValueFormat(valueFormat)) return typeof value === "number" && !Number.isNaN(value);
3082
+ if (isTimestampValueFormat(valueFormat)) {
3083
+ if (typeof value !== "number") return false;
3084
+ return valueFormat === "X" ? Number.isInteger(value) : !Number.isNaN(value);
3085
+ }
3079
3086
  if (typeof value !== "string") return false;
3080
3087
  return (0, dayjs.default)(value, valueFormat, true).isValid();
3081
3088
  };
3082
3089
  /**
3083
3090
  * 生成单个日期类字段的参考示例值:时间戳格式给出当前时间戳,其余按 valueFormat 格式化当前时间。
3084
3091
  */
3085
- var dateSuggestion = (valueFormat) => isTimestampValueFormat(valueFormat) ? `请参考以下示例值:${Date.now()}` : `请参考以下示例值:"${(0, dayjs.default)().format(valueFormat)}"`;
3092
+ var timestampExample = (valueFormat) => valueFormat === "X" ? Math.floor(Date.now() / 1e3) : Date.now();
3093
+ var dateSuggestion = (valueFormat) => isTimestampValueFormat(valueFormat) ? `请参考以下示例值:${timestampExample(valueFormat)}` : `请参考以下示例值:"${(0, dayjs.default)().format(valueFormat)}"`;
3086
3094
  /**
3087
3095
  * 生成日期范围类字段的参考示例值(长度为 2 的数组)。
3088
3096
  */
3089
3097
  var dateRangeSuggestion = (valueFormat) => {
3090
- if (isTimestampValueFormat(valueFormat)) return `请参考以下示例值:[${Date.now()}, ${Date.now()}]`;
3098
+ if (isTimestampValueFormat(valueFormat)) {
3099
+ const example = timestampExample(valueFormat);
3100
+ return `请参考以下示例值:[${example}, ${example}]`;
3101
+ }
3091
3102
  const example = (0, dayjs.default)().format(valueFormat);
3092
3103
  return `请参考以下示例值:["${example}", "${example}"]`;
3093
3104
  };
3094
- var dateValueFormatErrorMessage = (message, valueFormat) => defaultMessage(message, isTimestampValueFormat(valueFormat) ? "值类型应为时间戳数字" : `值格式应为 ${valueFormat}`, dateSuggestion(valueFormat));
3105
+ var timestampTypeLabel = (valueFormat) => valueFormat === "X" ? "秒级时间戳数字" : "毫秒级时间戳数字";
3106
+ var dateValueFormatErrorMessage = (message, valueFormat) => defaultMessage(message, isTimestampValueFormat(valueFormat) ? `值类型应为${timestampTypeLabel(valueFormat)}` : `值格式应为 ${valueFormat}`, dateSuggestion(valueFormat));
3095
3107
  var resolveToggleValues = (config) => {
3096
3108
  const filterIsNumber = config.filter === "number";
3097
3109
  const { activeValue: configActiveValue, inactiveValue: configInactiveValue } = config;
@@ -3288,7 +3300,7 @@
3288
3300
  if (fieldType === "daterange" || fieldType === "timerange") {
3289
3301
  if (config.names) return;
3290
3302
  const valueFormat = resolveDateValueFormat(fieldType, config);
3291
- if (!Array.isArray(value) || value.length !== 2 || value.some((item) => !isValidDateValueByFormat(item, valueFormat))) return defaultMessage(message, isTimestampValueFormat(valueFormat) ? `${formatErrorValue(value)} 类型应为长度为 2 的时间戳数字数组` : `${formatErrorValue(value)} 格式应为长度为 2 的 ${valueFormat} 数组`, dateRangeSuggestion(valueFormat));
3303
+ if (!Array.isArray(value) || value.length !== 2 || value.some((item) => !isValidDateValueByFormat(item, valueFormat))) return defaultMessage(message, isTimestampValueFormat(valueFormat) ? `${formatErrorValue(value)} 类型应为长度为 2 的${timestampTypeLabel(valueFormat)}数组` : `${formatErrorValue(value)} 格式应为长度为 2 的 ${valueFormat} 数组`, dateRangeSuggestion(valueFormat));
3292
3304
  return;
3293
3305
  }
3294
3306
  if (fieldType === "table" || fieldType === "group-list" || fieldType === "grouplist") {
@@ -3796,10 +3808,33 @@
3796
3808
  });
3797
3809
  return valuesTmp || {};
3798
3810
  };
3811
+ /**
3812
+ * 把值收成 Unix 秒,无法解析时返回 undefined。
3813
+ *
3814
+ * 纯数字(含数字字符串)按已是秒处理:dayjs 会把数字当成毫秒,不能再过一遍。
3815
+ * Date、ISO 和日期字符串则解析后取秒。
3816
+ */
3817
+ var toUnixSeconds = (v) => {
3818
+ if (typeof v === "number") return Number.isFinite(v) ? Math.trunc(v) : void 0;
3819
+ if (typeof v === "string" && /^-?\d+$/.test(v.trim())) return Math.trunc(Number(v));
3820
+ const parsed = (0, dayjs.default)(v);
3821
+ return parsed.isValid() ? parsed.unix() : void 0;
3822
+ };
3823
+ /**
3824
+ * `valueFormat: 'X'` 时把选择器值收成秒级 number,其余格式原样返回。
3825
+ * Element Plus 对 `X` 写出的是秒字符串(`x` 才会直接给毫秒数字);空值、无法解析的值原样返回。
3826
+ */
3827
+ var normalizeTimestampValue = (value, valueFormat) => {
3828
+ if (valueFormat !== "X") return value;
3829
+ if (Array.isArray(value)) return value.map((item) => normalizeTimestampValue(item, valueFormat));
3830
+ if (value === null || value === void 0 || value === "") return value;
3831
+ return toUnixSeconds(value) ?? value;
3832
+ };
3799
3833
  var datetimeFormatter = (v, defaultValue = "-", format = "YYYY-MM-DD HH:mm:ss") => {
3800
3834
  if (v) {
3801
3835
  let time;
3802
- if (["x", "timestamp"].includes(format)) time = (0, dayjs.default)(Number.isNaN(Number(v)) ? v : Number(v)).valueOf();
3836
+ if (format === "X") time = toUnixSeconds(v) ?? "Invalid Date";
3837
+ else if (TIMESTAMP_VALUE_FORMATS.has(format)) time = (0, dayjs.default)(Number.isNaN(Number(v)) ? v : Number(v)).valueOf();
3803
3838
  else if (typeof v === "string" && v.includes("Z") || v instanceof Date) {
3804
3839
  dayjs.default.extend(dayjs_plugin_utc_js.default);
3805
3840
  time = (0, dayjs.default)(v).utcOffset(8).format(format);
@@ -4393,6 +4428,7 @@
4393
4428
  };
4394
4429
  //#endregion
4395
4430
  //#region packages/form/src/utils/validateValues.ts
4431
+ var Schema = async_validator.default.default ?? async_validator.default;
4396
4432
  /**
4397
4433
  * 构造一个不依赖组件实例的 `formState`。
4398
4434
  *
@@ -4445,7 +4481,7 @@
4445
4481
  if (!rules.length) return null;
4446
4482
  const value = getFieldValue(field.prop, values);
4447
4483
  try {
4448
- await new async_validator.default({ [field.prop]: rules }).validate({ [field.prop]: value }, { firstFields: true });
4484
+ await new Schema({ [field.prop]: rules }).validate({ [field.prop]: value }, { firstFields: true });
4449
4485
  return null;
4450
4486
  } catch (err) {
4451
4487
  if (err?.fields) return err.fields;
@@ -9025,7 +9061,7 @@
9025
9061
  const emit = __emit;
9026
9062
  useAddField(props.prop);
9027
9063
  const changeHandler = (v) => {
9028
- emit("change", v);
9064
+ emit("change", normalizeTimestampValue(v, props.config.valueFormat));
9029
9065
  };
9030
9066
  return (_ctx, _cache) => {
9031
9067
  return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicDatePicker), {
@@ -9074,7 +9110,7 @@
9074
9110
  const emit = __emit;
9075
9111
  useAddField(props.prop);
9076
9112
  const changeHandler = (v) => {
9077
- emit("change", v);
9113
+ emit("change", normalizeTimestampValue(v, props.config.valueFormat));
9078
9114
  };
9079
9115
  return (_ctx, _cache) => {
9080
9116
  return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicDatePicker), {
@@ -9126,7 +9162,7 @@
9126
9162
  const emit = __emit;
9127
9163
  useAddField(props.prop);
9128
9164
  const changeHandler = (v) => {
9129
- emit("change", v);
9165
+ emit("change", normalizeTimestampValue(v, props.config.valueFormat));
9130
9166
  };
9131
9167
  return (_ctx, _cache) => {
9132
9168
  return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicTimePicker), {
@@ -9293,22 +9329,27 @@
9293
9329
  useAddField(props.prop);
9294
9330
  const { names } = props.config;
9295
9331
  const value = (0, vue.ref)([]);
9332
+ const rangeFormat = () => `${props.config.dateFormat || "YYYY/MM/DD"} ${props.config.timeFormat || "HH:mm:ss"}`;
9333
+ /** `X` 的选择器值就是秒级数字,展示格式不能拿去代替 valueFormat。 */
9334
+ const toPickerValue = (item) => {
9335
+ if (!item) return void 0;
9336
+ if (props.config.valueFormat === "X") return normalizeTimestampValue(item, "X");
9337
+ return datetimeFormatter(item, "", rangeFormat());
9338
+ };
9296
9339
  if (props.model !== void 0) {
9297
9340
  if (names?.length) {
9298
9341
  const unWatch = (0, vue.watch)([() => props.model[names[0]], () => props.model[names[1]]], ([start, end], [preStart, preEnd]) => {
9299
9342
  if (!value.value) value.value = [];
9300
- const format = `${props.config.dateFormat || "YYYY/MM/DD"} ${props.config.timeFormat || "HH:mm:ss"}`;
9301
9343
  if (!start || !end) value.value = [];
9302
- if (start !== preStart) value.value[0] = datetimeFormatter(start, "", format);
9303
- if (end !== preEnd) value.value[1] = datetimeFormatter(end, "", format);
9344
+ if (start !== preStart) value.value[0] = toPickerValue(start);
9345
+ if (end !== preEnd) value.value[1] = toPickerValue(end);
9304
9346
  }, { immediate: true });
9305
9347
  (0, vue.onUnmounted)(() => {
9306
9348
  unWatch();
9307
9349
  });
9308
9350
  } else if (props.name && props.model[props.name]) {
9309
9351
  const unWatch = (0, vue.watch)(() => props.model[props.name], (start, preStart) => {
9310
- const format = `${props.config.dateFormat || "YYYY/MM/DD"} ${props.config.timeFormat || "HH:mm:ss"}`;
9311
- if (start !== preStart) value.value = start.map((item) => item ? datetimeFormatter(item, "", format) : void 0);
9352
+ if (start !== preStart) value.value = start.map((item) => toPickerValue(item));
9312
9353
  }, { immediate: true });
9313
9354
  (0, vue.onUnmounted)(() => {
9314
9355
  unWatch();
@@ -9316,15 +9357,16 @@
9316
9357
  }
9317
9358
  }
9318
9359
  const changeHandler = (v) => {
9319
- const value = v || [];
9360
+ const normalized = normalizeTimestampValue(v, props.config.valueFormat);
9361
+ const value = normalized || [];
9320
9362
  if (props.name) emit("change", value);
9321
9363
  else if (props.config.names?.length) {
9322
9364
  const newChangeRecords = [];
9323
9365
  props.config.names.forEach((item, index) => {
9324
9366
  if (!props.model) return;
9325
- if (Array.isArray(v)) newChangeRecords.push({
9367
+ if (Array.isArray(normalized)) newChangeRecords.push({
9326
9368
  propPath: props.prop ? `${props.prop}.${item}` : item,
9327
- value: v[index]
9369
+ value: normalized[index]
9328
9370
  });
9329
9371
  else newChangeRecords.push({
9330
9372
  propPath: props.prop ? `${props.prop}.${item}` : item,
@@ -9393,21 +9435,26 @@
9393
9435
  const getFullDatetime = (item) => item ? `${(0, dayjs.default)().format("YYYY/MM/DD")} ${item}` : "";
9394
9436
  const getFormat = () => `YYYY/MM/DD ${props.config.valueFormat || "HH:mm:ss"}`;
9395
9437
  const timeFormatter = (time, format) => datetimeFormatter(getFullDatetime(time), "", format).substring(11);
9438
+ /** `X` 的选择器值就是秒级数字,不能再拼成日期后截取。 */
9439
+ const toPickerValue = (time) => {
9440
+ if (!time) return void 0;
9441
+ if (props.config.valueFormat === "X") return normalizeTimestampValue(time, "X");
9442
+ return timeFormatter(time, getFormat());
9443
+ };
9396
9444
  if (props.model !== void 0) {
9397
9445
  if (names?.length) {
9398
9446
  const unWatch = (0, vue.watch)([() => props.model[names[0]], () => props.model[names[1]]], ([start, end], [preStart, preEnd]) => {
9399
9447
  if (!value.value) value.value = [];
9400
- const format = getFormat();
9401
9448
  if (!start || !end) value.value = [];
9402
- if (start !== preStart) value.value[0] = timeFormatter(start, format);
9403
- if (end !== preEnd) value.value[1] = timeFormatter(end, format);
9449
+ if (start !== preStart) value.value[0] = toPickerValue(start);
9450
+ if (end !== preEnd) value.value[1] = toPickerValue(end);
9404
9451
  }, { immediate: true });
9405
9452
  (0, vue.onUnmounted)(() => {
9406
9453
  unWatch();
9407
9454
  });
9408
9455
  } else if (props.name) {
9409
9456
  const unWatch = (0, vue.watch)(() => props.model[props.name], (v = []) => {
9410
- if (Array.isArray(v)) value.value = v.map((item) => item ? timeFormatter(item, getFormat()) : void 0);
9457
+ if (Array.isArray(v)) value.value = v.map((item) => toPickerValue(item));
9411
9458
  else value.value = [];
9412
9459
  }, { immediate: true });
9413
9460
  (0, vue.onUnmounted)(() => {
@@ -9416,15 +9463,16 @@
9416
9463
  }
9417
9464
  }
9418
9465
  const changeHandler = (v) => {
9419
- const value = v || [];
9466
+ const normalized = normalizeTimestampValue(v, props.config.valueFormat);
9467
+ const value = normalized || [];
9420
9468
  if (props.name) emit("change", value);
9421
9469
  else if (props.config.names?.length) {
9422
9470
  const newChangeRecords = [];
9423
9471
  props.config.names.forEach((item, index) => {
9424
9472
  if (!props.model) return;
9425
- if (Array.isArray(v)) newChangeRecords.push({
9473
+ if (Array.isArray(normalized)) newChangeRecords.push({
9426
9474
  propPath: props.prop ? `${props.prop}.${item}` : item,
9427
- value: v[index]
9475
+ value: normalized[index]
9428
9476
  });
9429
9477
  else newChangeRecords.push({
9430
9478
  propPath: props.prop ? `${props.prop}.${item}` : item,
@@ -10702,6 +10750,7 @@ install(app, opt = {}) {
10702
10750
  exports.isValidName = isValidName;
10703
10751
  exports.mergeFieldOptions = mergeFieldOptions;
10704
10752
  exports.mergeFormContexts = mergeFormContexts;
10753
+ exports.normalizeTimestampValue = normalizeTimestampValue;
10705
10754
  exports.optionSuggestion = optionSuggestion;
10706
10755
  exports.registerBuiltInFields = registerBuiltInFields;
10707
10756
  exports.registerField = registerField;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.2",
2
+ "version": "1.8.3",
3
3
  "name": "@tmagic/form",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -58,9 +58,9 @@
58
58
  "peerDependencies": {
59
59
  "typescript": "^6.0.3",
60
60
  "vue": "^3.5.43",
61
- "@tmagic/design": "1.8.2",
62
- "@tmagic/form-schema": "1.8.2",
63
- "@tmagic/utils": "1.8.2"
61
+ "@tmagic/design": "1.8.3",
62
+ "@tmagic/utils": "1.8.3",
63
+ "@tmagic/form-schema": "1.8.3"
64
64
  },
65
65
  "peerDependenciesMeta": {
66
66
  "typescript": {
@@ -15,6 +15,7 @@
15
15
  import { TMagicDatePicker } from '@tmagic/design';
16
16
 
17
17
  import type { DateConfig, FieldProps } from '@form/schema';
18
+ import { normalizeTimestampValue } from '@form/utils/form';
18
19
  import { useAddField } from '@form/utils/useAddField';
19
20
 
20
21
  defineOptions({
@@ -24,12 +25,12 @@ defineOptions({
24
25
  const props = defineProps<FieldProps<DateConfig>>();
25
26
 
26
27
  const emit = defineEmits<{
27
- change: [value: string];
28
+ change: [value: string | number | null];
28
29
  }>();
29
30
 
30
31
  useAddField(props.prop);
31
32
 
32
- const changeHandler = (v: string) => {
33
- emit('change', v);
33
+ const changeHandler = (v: string | number | null) => {
34
+ emit('change', normalizeTimestampValue(v, props.config.valueFormat));
34
35
  };
35
36
  </script>
@@ -17,6 +17,7 @@
17
17
  import { TMagicDatePicker } from '@tmagic/design';
18
18
 
19
19
  import type { DateTimeConfig, FieldProps } from '@form/schema';
20
+ import { normalizeTimestampValue } from '@form/utils/form';
20
21
  import { useAddField } from '@form/utils/useAddField';
21
22
 
22
23
  defineOptions({
@@ -26,12 +27,12 @@ defineOptions({
26
27
  const props = defineProps<FieldProps<DateTimeConfig>>();
27
28
 
28
29
  const emit = defineEmits<{
29
- change: [value: string];
30
+ change: [value: string | number | null];
30
31
  }>();
31
32
 
32
33
  useAddField(props.prop);
33
34
 
34
- const changeHandler = (v: string) => {
35
- emit('change', v);
35
+ const changeHandler = (v: string | number | null) => {
36
+ emit('change', normalizeTimestampValue(v, props.config.valueFormat));
36
37
  };
37
38
  </script>
@@ -23,7 +23,7 @@ import { onUnmounted, ref, watch } from 'vue';
23
23
  import { TMagicDatePicker } from '@tmagic/design';
24
24
 
25
25
  import type { ChangeRecord, DaterangeConfig, FieldProps } from '../schema';
26
- import { datetimeFormatter } from '../utils/form';
26
+ import { datetimeFormatter, normalizeTimestampValue } from '../utils/form';
27
27
  import { useAddField } from '../utils/useAddField';
28
28
 
29
29
  defineOptions({
@@ -37,7 +37,14 @@ const emit = defineEmits(['change']);
37
37
  useAddField(props.prop);
38
38
 
39
39
  const { names } = props.config;
40
- const value = ref<(Date | string | undefined)[] | null>([]);
40
+ const value = ref<(Date | string | number | undefined)[] | null>([]);
41
+ const rangeFormat = () => `${props.config.dateFormat || 'YYYY/MM/DD'} ${props.config.timeFormat || 'HH:mm:ss'}`;
42
+ /** `X` 的选择器值就是秒级数字,展示格式不能拿去代替 valueFormat。 */
43
+ const toPickerValue = (item: string | number | Date) => {
44
+ if (!item) return undefined;
45
+ if (props.config.valueFormat === 'X') return normalizeTimestampValue(item, 'X');
46
+ return datetimeFormatter(item, '', rangeFormat()) as string;
47
+ };
41
48
 
42
49
  if (props.model !== undefined) {
43
50
  if (names?.length) {
@@ -48,10 +55,9 @@ if (props.model !== undefined) {
48
55
  value.value = [];
49
56
  }
50
57
 
51
- const format = `${props.config.dateFormat || 'YYYY/MM/DD'} ${props.config.timeFormat || 'HH:mm:ss'}`;
52
58
  if (!start || !end) value.value = [];
53
- if (start !== preStart) value.value[0] = datetimeFormatter(start, '', format) as string;
54
- if (end !== preEnd) value.value[1] = datetimeFormatter(end, '', format) as string;
59
+ if (start !== preStart) value.value[0] = toPickerValue(start);
60
+ if (end !== preEnd) value.value[1] = toPickerValue(end);
55
61
  },
56
62
  {
57
63
  immediate: true,
@@ -65,12 +71,7 @@ if (props.model !== undefined) {
65
71
  const unWatch = watch(
66
72
  () => props.model[props.name],
67
73
  (start, preStart) => {
68
- const format = `${props.config.dateFormat || 'YYYY/MM/DD'} ${props.config.timeFormat || 'HH:mm:ss'}`;
69
-
70
- if (start !== preStart)
71
- value.value = start.map((item: string) =>
72
- item ? (datetimeFormatter(item, '', format) as string) : undefined,
73
- );
74
+ if (start !== preStart) value.value = start.map((item: string | number | Date) => toPickerValue(item));
74
75
  },
75
76
  {
76
77
  immediate: true,
@@ -82,8 +83,9 @@ if (props.model !== undefined) {
82
83
  }
83
84
  }
84
85
 
85
- const changeHandler = (v: Date[]) => {
86
- const value = v || [];
86
+ const changeHandler = (v: Array<Date | string | number> | null) => {
87
+ const normalized = normalizeTimestampValue(v, props.config.valueFormat);
88
+ const value = normalized || [];
87
89
 
88
90
  if (props.name) {
89
91
  emit('change', value);
@@ -94,10 +96,10 @@ const changeHandler = (v: Date[]) => {
94
96
  if (!props.model) {
95
97
  return;
96
98
  }
97
- if (Array.isArray(v)) {
99
+ if (Array.isArray(normalized)) {
98
100
  newChangeRecords.push({
99
101
  propPath: props.prop ? `${props.prop}.${item}` : item,
100
- value: v[index],
102
+ value: normalized[index],
101
103
  });
102
104
  } else {
103
105
  newChangeRecords.push({
@@ -14,6 +14,7 @@
14
14
  import { TMagicTimePicker } from '@tmagic/design';
15
15
 
16
16
  import type { FieldProps, TimeConfig } from '../schema';
17
+ import { normalizeTimestampValue } from '../utils/form';
17
18
  import { useAddField } from '../utils/useAddField';
18
19
 
19
20
  defineOptions({
@@ -23,12 +24,12 @@ defineOptions({
23
24
  const props = defineProps<FieldProps<TimeConfig>>();
24
25
 
25
26
  const emit = defineEmits<{
26
- change: [value: string];
27
+ change: [value: string | number | null];
27
28
  }>();
28
29
 
29
30
  useAddField(props.prop);
30
31
 
31
- const changeHandler = (v: string) => {
32
- emit('change', v);
32
+ const changeHandler = (v: string | number | null) => {
33
+ emit('change', normalizeTimestampValue(v, props.config.valueFormat));
33
34
  };
34
35
  </script>
@@ -22,7 +22,7 @@ import dayjs from 'dayjs';
22
22
  import { TMagicTimePicker } from '@tmagic/design';
23
23
 
24
24
  import type { ChangeRecord, FieldProps, TimerangeConfig } from '../schema';
25
- import { datetimeFormatter } from '../utils/form';
25
+ import { datetimeFormatter, normalizeTimestampValue } from '../utils/form';
26
26
  import { useAddField } from '../utils/useAddField';
27
27
 
28
28
  defineOptions({
@@ -36,12 +36,18 @@ const emit = defineEmits(['change']);
36
36
  useAddField(props.prop);
37
37
 
38
38
  const { names } = props.config;
39
- const value = ref<(Date | string | undefined)[] | null>([]);
39
+ const value = ref<(Date | string | number | undefined)[] | null>([]);
40
40
 
41
41
  const getFullDatetime = (item: string) => (item ? `${dayjs().format('YYYY/MM/DD')} ${item}` : '');
42
42
  const getFormat = () => `YYYY/MM/DD ${props.config.valueFormat || 'HH:mm:ss'}`;
43
43
  const timeFormatter = (time: string, format: string) =>
44
44
  (datetimeFormatter(getFullDatetime(time), '', format) as string).substring(11);
45
+ /** `X` 的选择器值就是秒级数字,不能再拼成日期后截取。 */
46
+ const toPickerValue = (time: string | number) => {
47
+ if (!time) return undefined;
48
+ if (props.config.valueFormat === 'X') return normalizeTimestampValue(time, 'X');
49
+ return timeFormatter(time as string, getFormat());
50
+ };
45
51
 
46
52
  if (props.model !== undefined) {
47
53
  if (names?.length) {
@@ -52,10 +58,9 @@ if (props.model !== undefined) {
52
58
  value.value = [];
53
59
  }
54
60
 
55
- const format = getFormat();
56
61
  if (!start || !end) value.value = [];
57
- if (start !== preStart) value.value[0] = timeFormatter(start, format);
58
- if (end !== preEnd) value.value[1] = timeFormatter(end, format);
62
+ if (start !== preStart) value.value[0] = toPickerValue(start);
63
+ if (end !== preEnd) value.value[1] = toPickerValue(end);
59
64
  },
60
65
  {
61
66
  immediate: true,
@@ -69,7 +74,7 @@ if (props.model !== undefined) {
69
74
  () => props.model[props.name],
70
75
  (v = []) => {
71
76
  if (Array.isArray(v)) {
72
- value.value = v.map((item: string) => (item ? timeFormatter(item, getFormat()) : undefined));
77
+ value.value = v.map((item: string | number) => toPickerValue(item));
73
78
  } else {
74
79
  value.value = [];
75
80
  }
@@ -84,8 +89,9 @@ if (props.model !== undefined) {
84
89
  }
85
90
  }
86
91
 
87
- const changeHandler = (v: Date[]) => {
88
- const value = v || [];
92
+ const changeHandler = (v: Array<Date | string | number> | null) => {
93
+ const normalized = normalizeTimestampValue(v, props.config.valueFormat);
94
+ const value = normalized || [];
89
95
 
90
96
  if (props.name) {
91
97
  emit('change', value);
@@ -96,10 +102,10 @@ const changeHandler = (v: Date[]) => {
96
102
  if (!props.model) {
97
103
  return;
98
104
  }
99
- if (Array.isArray(v)) {
105
+ if (Array.isArray(normalized)) {
100
106
  newChangeRecords.push({
101
107
  propPath: props.prop ? `${props.prop}.${item}` : item,
102
- value: v[index],
108
+ value: normalized[index],
103
109
  });
104
110
  } else {
105
111
  newChangeRecords.push({
package/src/utils/form.ts CHANGED
@@ -42,7 +42,7 @@ import type {
42
42
  } from '../schema';
43
43
 
44
44
  import { getConfig } from './config';
45
- import { createTypeMatchValidator } from './typeMatch';
45
+ import { createTypeMatchValidator, TIMESTAMP_VALUE_FORMATS } from './typeMatch';
46
46
 
47
47
  export { createFormStateProxy, mergeFormContexts } from './formStateProxy';
48
48
 
@@ -509,14 +509,44 @@ export const initValue = async (
509
509
  return valuesTmp || {};
510
510
  };
511
511
 
512
+ /**
513
+ * 把值收成 Unix 秒,无法解析时返回 undefined。
514
+ *
515
+ * 纯数字(含数字字符串)按已是秒处理:dayjs 会把数字当成毫秒,不能再过一遍。
516
+ * Date、ISO 和日期字符串则解析后取秒。
517
+ */
518
+ const toUnixSeconds = (v: string | Date | number): number | undefined => {
519
+ if (typeof v === 'number') {
520
+ return Number.isFinite(v) ? Math.trunc(v) : undefined;
521
+ }
522
+ if (typeof v === 'string' && /^-?\d+$/.test(v.trim())) {
523
+ return Math.trunc(Number(v));
524
+ }
525
+ const parsed = dayjs(v);
526
+ return parsed.isValid() ? parsed.unix() : undefined;
527
+ };
528
+
529
+ /**
530
+ * `valueFormat: 'X'` 时把选择器值收成秒级 number,其余格式原样返回。
531
+ * Element Plus 对 `X` 写出的是秒字符串(`x` 才会直接给毫秒数字);空值、无法解析的值原样返回。
532
+ */
533
+ export const normalizeTimestampValue = (value: any, valueFormat?: string): any => {
534
+ if (valueFormat !== 'X') return value;
535
+ if (Array.isArray(value)) return value.map((item) => normalizeTimestampValue(item, valueFormat));
536
+ if (value === null || value === undefined || value === '') return value;
537
+ return toUnixSeconds(value) ?? value;
538
+ };
539
+
512
540
  export const datetimeFormatter = (
513
- v: string | Date,
541
+ v: string | Date | number,
514
542
  defaultValue = '-',
515
543
  format = 'YYYY-MM-DD HH:mm:ss',
516
544
  ): string | number => {
517
545
  if (v) {
518
546
  let time: string | number;
519
- if (['x', 'timestamp'].includes(format)) {
547
+ if (format === 'X') {
548
+ time = toUnixSeconds(v) ?? 'Invalid Date';
549
+ } else if (TIMESTAMP_VALUE_FORMATS.has(format)) {
520
550
  time = dayjs(Number.isNaN(Number(v)) ? v : Number(v)).valueOf();
521
551
  } else if ((typeof v === 'string' && v.includes('Z')) || v instanceof Date) {
522
552
  // dayjs.extend 内部有防重复机制 (plugin.$i),无需额外判断
@@ -150,7 +150,7 @@ const DATE_LIKE_DEFAULT_VALUE_FORMAT: Record<string, string> = {
150
150
  timerange: 'HH:mm:ss',
151
151
  };
152
152
 
153
- const TIMESTAMP_VALUE_FORMATS = new Set(['x', 'timestamp']);
153
+ export const TIMESTAMP_VALUE_FORMATS = new Set(['x', 'X', 'timestamp']);
154
154
 
155
155
  /**
156
156
  * 将值格式化为可读的参考示例字符串。
@@ -281,7 +281,9 @@ const isTimestampValueFormat = (valueFormat: string) => TIMESTAMP_VALUE_FORMATS.
281
281
 
282
282
  const isValidDateValueByFormat = (value: any, valueFormat: string): boolean => {
283
283
  if (isTimestampValueFormat(valueFormat)) {
284
- return typeof value === 'number' && !Number.isNaN(value);
284
+ if (typeof value !== 'number') return false;
285
+ // 秒级时间戳必须是有限整数,毫秒级只排除 NaN
286
+ return valueFormat === 'X' ? Number.isInteger(value) : !Number.isNaN(value);
285
287
  }
286
288
  if (typeof value !== 'string') {
287
289
  return false;
@@ -293,9 +295,11 @@ const isValidDateValueByFormat = (value: any, valueFormat: string): boolean => {
293
295
  /**
294
296
  * 生成单个日期类字段的参考示例值:时间戳格式给出当前时间戳,其余按 valueFormat 格式化当前时间。
295
297
  */
298
+ const timestampExample = (valueFormat: string) => (valueFormat === 'X' ? Math.floor(Date.now() / 1000) : Date.now());
299
+
296
300
  const dateSuggestion = (valueFormat: string): string =>
297
301
  isTimestampValueFormat(valueFormat)
298
- ? `请参考以下示例值:${Date.now()}`
302
+ ? `请参考以下示例值:${timestampExample(valueFormat)}`
299
303
  : `请参考以下示例值:"${dayjs().format(valueFormat)}"`;
300
304
 
301
305
  /**
@@ -303,16 +307,19 @@ const dateSuggestion = (valueFormat: string): string =>
303
307
  */
304
308
  const dateRangeSuggestion = (valueFormat: string): string => {
305
309
  if (isTimestampValueFormat(valueFormat)) {
306
- return `请参考以下示例值:[${Date.now()}, ${Date.now()}]`;
310
+ const example = timestampExample(valueFormat);
311
+ return `请参考以下示例值:[${example}, ${example}]`;
307
312
  }
308
313
  const example = dayjs().format(valueFormat);
309
314
  return `请参考以下示例值:["${example}", "${example}"]`;
310
315
  };
311
316
 
317
+ const timestampTypeLabel = (valueFormat: string) => (valueFormat === 'X' ? '秒级时间戳数字' : '毫秒级时间戳数字');
318
+
312
319
  const dateValueFormatErrorMessage = (message: string | undefined, valueFormat: string) =>
313
320
  defaultMessage(
314
321
  message,
315
- isTimestampValueFormat(valueFormat) ? '值类型应为时间戳数字' : `值格式应为 ${valueFormat}`,
322
+ isTimestampValueFormat(valueFormat) ? `值类型应为${timestampTypeLabel(valueFormat)}` : `值格式应为 ${valueFormat}`,
316
323
  dateSuggestion(valueFormat),
317
324
  );
318
325
 
@@ -748,7 +755,7 @@ const validateBuiltinTypeMatch = (
748
755
  return defaultMessage(
749
756
  message,
750
757
  isTimestampValueFormat(valueFormat)
751
- ? `${formatErrorValue(value)} 类型应为长度为 2 的时间戳数字数组`
758
+ ? `${formatErrorValue(value)} 类型应为长度为 2 的${timestampTypeLabel(valueFormat)}数组`
752
759
  : `${formatErrorValue(value)} 格式应为长度为 2 的 ${valueFormat} 数组`,
753
760
  dateRangeSuggestion(valueFormat),
754
761
  );
@@ -17,7 +17,7 @@
17
17
  */
18
18
 
19
19
  import { reactive } from 'vue';
20
- import Schema from 'async-validator';
20
+ import AsyncValidator from 'async-validator';
21
21
 
22
22
  import type { FormConfig, FormContext, FormState, FormValue } from '../schema';
23
23
 
@@ -25,6 +25,10 @@ import { applyMountValueEffects, type CollectedField, collectValidatableFields }
25
25
  import { createFormStateBase, createFormStateProxy, initValue } from './form';
26
26
  import { formatValidateError } from './validateError';
27
27
 
28
+ // async-validator 是 CJS 包(`exports.default = Schema`)。原生 Node ESM 下默认导入拿到的是整个 `module.exports`,
29
+ // 需要再取一层 `.default`;打包器 / vitest 会自动处理互操作,此时 `.default` 不存在,直接用默认导入。
30
+ const Schema: typeof AsyncValidator = (AsyncValidator as any).default ?? AsyncValidator;
31
+
28
32
  // #region HeadlessFormStateOptions
29
33
  /** 构造无渲染 formState 所需的参数(与 MForm 的同名 props 对齐) */
30
34
  export interface HeadlessFormStateOptions {
@@ -153,7 +153,12 @@ export declare const initValue: (mForm: schema_d_exports.FormState | undefined,
153
153
  initValues: schema_d_exports.FormValue;
154
154
  config: schema_d_exports.FormConfig;
155
155
  }) => Promise<schema_d_exports.FormValue>;
156
- export declare const datetimeFormatter: (v: string | Date, defaultValue?: string, format?: string) => string | number;
156
+ /**
157
+ * `valueFormat: 'X'` 时把选择器值收成秒级 number,其余格式原样返回。
158
+ * Element Plus 对 `X` 写出的是秒字符串(`x` 才会直接给毫秒数字);空值、无法解析的值原样返回。
159
+ */
160
+ export declare const normalizeTimestampValue: (value: any, valueFormat?: string) => any;
161
+ export declare const datetimeFormatter: (v: string | Date | number, defaultValue?: string, format?: string) => string | number;
157
162
  export declare const getDataByPage: (data: any[] | undefined, pagecontext: number, pagesize: number) => any[];
158
163
  export declare const sortArray: (data: any[], newIndex: number, oldIndex: number, sortKey?: string) => any[];
159
164
  export declare const sortChange: (data: any[], { prop, order }: schema_d_exports.SortProp) => void;
@@ -676,7 +681,7 @@ export declare const submitForm: (options: SubmitFormOptions) => Promise<any>;
676
681
  */
677
682
  export declare const validateForm: (options: ValidateFormOptions) => Promise<string>;
678
683
  declare namespace headless_d_exports {
679
- export { ChangeRecord, CollectedField, ContainerChangeEventData, FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FieldInnerConfig, FieldInnerConfigContext, FieldInnerConfigError, FieldInnerConfigResult, FieldMountValueEffect, FieldMountValueEffectContext, FieldOptions, FormDiffConfig, FormLabelSlotProps, FormSlots, HeadlessFieldOptions, HeadlessFormStateOptions, MAX_SUGGESTION_OPTIONS, SubmitFormOptions, SubmitFormResult, TypeMatchValidateContext, TypeMatchValidator, ValidateError, ValidateFormOptions, ValidateValuesOptions, ValidateValuesResult, adaptFormValidator, appendProp, applyMountValueEffects, builtInFields, clearFields, clearTypeMatchRules, collectValidatableFields, createFormStateBase, createFormStateProxy, createHeadlessFormState, createObjectProp, createValues, datetimeFormatter, deleteTypeMatchRule, display, filterFunction, formatValidateError, getDataByPage, getField as getFormField, getItemProp, getNativeRules, getRules, getTextByName, getTypeMatchRule, initValue, isFieldInnerConfigError, isLeafFieldType, isValidName, mergeFieldOptions, mergeFormContexts, optionSuggestion, registerBuiltInFields, registerField, registerFields, resolveItemType, sortArray, sortChange, stringifyExampleValue, submitForm, unregisterField, validateForm, validateTypeMatch, validateValues };
684
+ export { ChangeRecord, CollectedField, ContainerChangeEventData, FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FieldInnerConfig, FieldInnerConfigContext, FieldInnerConfigError, FieldInnerConfigResult, FieldMountValueEffect, FieldMountValueEffectContext, FieldOptions, FormDiffConfig, FormLabelSlotProps, FormSlots, HeadlessFieldOptions, HeadlessFormStateOptions, MAX_SUGGESTION_OPTIONS, SubmitFormOptions, SubmitFormResult, TypeMatchValidateContext, TypeMatchValidator, ValidateError, ValidateFormOptions, ValidateValuesOptions, ValidateValuesResult, adaptFormValidator, appendProp, applyMountValueEffects, builtInFields, clearFields, clearTypeMatchRules, collectValidatableFields, createFormStateBase, createFormStateProxy, createHeadlessFormState, createObjectProp, createValues, datetimeFormatter, deleteTypeMatchRule, display, filterFunction, formatValidateError, getDataByPage, getField as getFormField, getItemProp, getNativeRules, getRules, getTextByName, getTypeMatchRule, initValue, isFieldInnerConfigError, isLeafFieldType, isValidName, mergeFieldOptions, mergeFormContexts, normalizeTimestampValue, optionSuggestion, registerBuiltInFields, registerField, registerFields, resolveItemType, sortArray, sortChange, stringifyExampleValue, submitForm, unregisterField, validateForm, validateTypeMatch, validateValues };
680
685
  }
681
686
  //#endregion
682
687
  export { type CollectedField, type FieldInnerConfig, type FieldInnerConfigContext, type FieldInnerConfigResult, type FieldMountValueEffect, type FieldMountValueEffectContext, type FieldOptions, type HeadlessFieldOptions, type HeadlessFormStateOptions, type SubmitFormOptions, type SubmitFormResult, type TypeMatchValidateContext, type TypeMatchValidator, type ValidateFormOptions, type ValidateValuesOptions, type ValidateValuesResult, getField as getFormField };
package/types/index.d.ts CHANGED
@@ -343,7 +343,12 @@ export declare const initValue: (mForm: schema_d_exports.FormState | undefined,
343
343
  initValues: schema_d_exports.FormValue;
344
344
  config: schema_d_exports.FormConfig;
345
345
  }) => Promise<schema_d_exports.FormValue>;
346
- export declare const datetimeFormatter: (v: string | Date, defaultValue?: string, format?: string) => string | number;
346
+ /**
347
+ * `valueFormat: 'X'` 时把选择器值收成秒级 number,其余格式原样返回。
348
+ * Element Plus 对 `X` 写出的是秒字符串(`x` 才会直接给毫秒数字);空值、无法解析的值原样返回。
349
+ */
350
+ export declare const normalizeTimestampValue: (value: any, valueFormat?: string) => any;
351
+ export declare const datetimeFormatter: (v: string | Date | number, defaultValue?: string, format?: string) => string | number;
347
352
  export declare const getDataByPage: (data: any[] | undefined, pagecontext: number, pagesize: number) => any[];
348
353
  export declare const sortArray: (data: any[], newIndex: number, oldIndex: number, sortKey?: string) => any[];
349
354
  export declare const sortChange: (data: any[], { prop, order }: schema_d_exports.SortProp) => void;
@@ -2160,27 +2165,27 @@ declare const _default$17: typeof __VLS_export$15;
2160
2165
  //#region temp/packages/form/src/fields/Date/Index.vue.d.ts
2161
2166
  type __VLS_Props$14 = schema_d_exports.FieldProps<schema_d_exports.DateConfig>;
2162
2167
  declare const __VLS_export$14: import("@vue/runtime-core").DefineComponent<__VLS_Props$14, {}, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {
2163
- change: (value: string) => any;
2168
+ change: (value: string | number | null) => any;
2164
2169
  }, string, import("@vue/runtime-core").PublicProps, Readonly<__VLS_Props$14> & Readonly<{
2165
- onChange?: ((value: string) => any) | undefined;
2170
+ onChange?: ((value: string | number | null) => any) | undefined;
2166
2171
  }>, {}, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, false, {}, any>;
2167
2172
  declare const _default$5: typeof __VLS_export$14;
2168
2173
  //#endregion
2169
2174
  //#region temp/packages/form/src/fields/DateTime/Index.vue.d.ts
2170
2175
  type __VLS_Props$13 = schema_d_exports.FieldProps<schema_d_exports.DateTimeConfig>;
2171
2176
  declare const __VLS_export$13: import("@vue/runtime-core").DefineComponent<__VLS_Props$13, {}, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {
2172
- change: (value: string) => any;
2177
+ change: (value: string | number | null) => any;
2173
2178
  }, string, import("@vue/runtime-core").PublicProps, Readonly<__VLS_Props$13> & Readonly<{
2174
- onChange?: ((value: string) => any) | undefined;
2179
+ onChange?: ((value: string | number | null) => any) | undefined;
2175
2180
  }>, {}, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, false, {}, any>;
2176
2181
  declare const _default$6: typeof __VLS_export$13;
2177
2182
  //#endregion
2178
2183
  //#region temp/packages/form/src/fields/Time.vue.d.ts
2179
2184
  type __VLS_Props$12 = schema_d_exports.FieldProps<schema_d_exports.TimeConfig>;
2180
2185
  declare const __VLS_export$12: import("@vue/runtime-core").DefineComponent<__VLS_Props$12, {}, {}, {}, {}, import("@vue/runtime-core").ComponentOptionsMixin, import("@vue/runtime-core").ComponentOptionsMixin, {
2181
- change: (value: string) => any;
2186
+ change: (value: string | number | null) => any;
2182
2187
  }, string, import("@vue/runtime-core").PublicProps, Readonly<__VLS_Props$12> & Readonly<{
2183
- onChange?: ((value: string) => any) | undefined;
2188
+ onChange?: ((value: string | number | null) => any) | undefined;
2184
2189
  }>, {}, {}, {}, {}, string, import("@vue/runtime-core").ComponentProvideOptions, false, {}, any>;
2185
2190
  declare const _default$29: typeof __VLS_export$12;
2186
2191
  //#endregion
@@ -2680,7 +2685,7 @@ declare const _default$31: {
2680
2685
  install(app: App, opt?: FormInstallOptions): void;
2681
2686
  };
2682
2687
  declare namespace index_d_exports {
2683
- export { ChangeRecord, CollectedField, ContainerChangeEventData, FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FieldInnerConfig, FieldInnerConfigContext, FieldInnerConfigError, FieldInnerConfigResult, FieldMountValueEffect, FieldMountValueEffectContext, FieldOptions, FormDiffConfig, FormInstallOptions, FormLabelSlotProps, FormSlots, HeadlessFieldOptions, HeadlessFormStateOptions, MAX_SUGGESTION_OPTIONS, _default as MCascader, _default$1 as MCheckbox, _default$2 as MCheckboxGroup, _default$3 as MColorPicker, _default$4 as MContainer, _default$5 as MDate, _default$6 as MDateTime, _default$7 as MDaterange, _default$8 as MDisplay, _default$9 as MDynamicField, _default$10 as MFieldset, _default$11 as MFlexLayout, _default$12 as MForm, _default$13 as MFormBox, _default$14 as MFormDialog, _default$15 as MFormDrawer, _default$16 as MGroupList, _default$17 as MHidden, _default$18 as MLink, _default$19 as MNumber, _default$20 as MNumberRange, _default$21 as MPanel, _default$22 as MRadioGroup, _default$23 as MRow, _default$24 as MSelect, _default$25 as MSwitch, _default$16 as MTable, _default$16 as MTableGroupList, _default$26 as MTabs, _default$27 as MText, _default$28 as MTextarea, _default$29 as MTime, _default$30 as MTimerange, SubmitFormOptions, SubmitFormResult, TypeMatchValidateContext, TypeMatchValidator, ValidateError, ValidateFormOptions, ValidateValuesOptions, ValidateValuesResult, adaptFormValidator, appendProp, applyMountValueEffects, builtInFields, clearFields, clearTypeMatchRules, collectValidatableFields, createForm, createFormStateBase, createFormStateProxy, createHeadlessFormState, createObjectProp, createValues, datetimeFormatter, _default$31 as default, deleteTypeMatchRule, display, filterFunction, formatValidateError, getDataByPage, getField as getFormField, getItemProp, getNativeRules, getRules, getTextByName, getTypeMatchRule, initValue, isFieldInnerConfigError, isLeafFieldType, isValidName, mergeFieldOptions, mergeFormContexts, optionSuggestion, registerBuiltInFields, registerField, registerFields, resolveItemType, sortArray, sortChange, stringifyExampleValue, stripTabItemsLazy, submitForm, unregisterField, useAddField, validateForm, validateTypeMatch, validateValues };
2688
+ export { ChangeRecord, CollectedField, ContainerChangeEventData, FORM_CONTEXT_KEY, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FieldInnerConfig, FieldInnerConfigContext, FieldInnerConfigError, FieldInnerConfigResult, FieldMountValueEffect, FieldMountValueEffectContext, FieldOptions, FormDiffConfig, FormInstallOptions, FormLabelSlotProps, FormSlots, HeadlessFieldOptions, HeadlessFormStateOptions, MAX_SUGGESTION_OPTIONS, _default as MCascader, _default$1 as MCheckbox, _default$2 as MCheckboxGroup, _default$3 as MColorPicker, _default$4 as MContainer, _default$5 as MDate, _default$6 as MDateTime, _default$7 as MDaterange, _default$8 as MDisplay, _default$9 as MDynamicField, _default$10 as MFieldset, _default$11 as MFlexLayout, _default$12 as MForm, _default$13 as MFormBox, _default$14 as MFormDialog, _default$15 as MFormDrawer, _default$16 as MGroupList, _default$17 as MHidden, _default$18 as MLink, _default$19 as MNumber, _default$20 as MNumberRange, _default$21 as MPanel, _default$22 as MRadioGroup, _default$23 as MRow, _default$24 as MSelect, _default$25 as MSwitch, _default$16 as MTable, _default$16 as MTableGroupList, _default$26 as MTabs, _default$27 as MText, _default$28 as MTextarea, _default$29 as MTime, _default$30 as MTimerange, SubmitFormOptions, SubmitFormResult, TypeMatchValidateContext, TypeMatchValidator, ValidateError, ValidateFormOptions, ValidateValuesOptions, ValidateValuesResult, adaptFormValidator, appendProp, applyMountValueEffects, builtInFields, clearFields, clearTypeMatchRules, collectValidatableFields, createForm, createFormStateBase, createFormStateProxy, createHeadlessFormState, createObjectProp, createValues, datetimeFormatter, _default$31 as default, deleteTypeMatchRule, display, filterFunction, formatValidateError, getDataByPage, getField as getFormField, getItemProp, getNativeRules, getRules, getTextByName, getTypeMatchRule, initValue, isFieldInnerConfigError, isLeafFieldType, isValidName, mergeFieldOptions, mergeFormContexts, normalizeTimestampValue, optionSuggestion, registerBuiltInFields, registerField, registerFields, resolveItemType, sortArray, sortChange, stringifyExampleValue, stripTabItemsLazy, submitForm, unregisterField, useAddField, validateForm, validateTypeMatch, validateValues };
2684
2689
  }
2685
2690
  export declare const createForm: <T extends [] = []>(config: schema_d_exports.FormConfig | T) => schema_d_exports.FormConfig | T;
2686
2691
  //#endregion