From c79b7297f2f79fa01b131153cc680593408c7476 Mon Sep 17 00:00:00 2001 From: chenos Date: Thu, 26 Dec 2024 14:23:51 +0800 Subject: [PATCH] fix: unix timestamp accuracy (#5931) * fix: unix timestamp accuracy * fix: unixTimestamp support int value * fix: tojson * fix(database): fix unix timestamp input value on number type * chore(database): remove only in test --------- Co-authored-by: katherinehhh Co-authored-by: mytharcher --- .../antd/unix-timestamp/UnixTimestamp.tsx | 38 +++++++++++++++++-- ....tests.ts => unix-timestamp-field.test.ts} | 23 +++++++++++ .../src/fields/unix-timestamp-field.ts | 11 ++++-- .../src/server/models/field.ts | 11 +++++- .../server/models/data-sources-field-model.ts | 13 ++++++- 5 files changed, 85 insertions(+), 11 deletions(-) rename packages/core/database/src/__tests__/fields/{unix-timestamp-field.tests.ts => unix-timestamp-field.test.ts} (78%) diff --git a/packages/core/client/src/schema-component/antd/unix-timestamp/UnixTimestamp.tsx b/packages/core/client/src/schema-component/antd/unix-timestamp/UnixTimestamp.tsx index d461338686..f678569aa5 100644 --- a/packages/core/client/src/schema-component/antd/unix-timestamp/UnixTimestamp.tsx +++ b/packages/core/client/src/schema-component/antd/unix-timestamp/UnixTimestamp.tsx @@ -7,22 +7,52 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import { connect, mapReadPretty } from '@formily/react'; -import React from 'react'; +import { connect, mapReadPretty, useField } from '@formily/react'; +import React, { useEffect, useMemo } from 'react'; import { DatePicker } from '../date-picker'; +const toValue = (value: any, accuracy) => { + if (value) { + return convertTimestampToDate(value, accuracy); + } + return null; +}; + +function convertTimestampToDate(timestamp, accuracy = 'second') { + // 如果是秒级时间戳,乘以1000转换为毫秒 + const timeInMilliseconds = accuracy === 'second' ? timestamp * 1000 : timestamp; + + // 创建Date对象并转为UTC时间 + const date = new Date(timeInMilliseconds); + + // 检查日期是否有效 + if (isNaN(date.getTime())) { + return 'Invalid timestamp'; + } + + return date.toUTCString(); // 返回 UTC 格式的日期 +} interface UnixTimestampProps { value?: any; onChange?: (value: number) => void; + accuracy?: 'millisecond' | 'second'; } export const UnixTimestamp = connect( (props: UnixTimestampProps) => { - const { value, onChange } = props; + const { value, onChange, accuracy } = props; + const targetValue = useMemo(() => { + if (typeof value === 'number') { + const v = toValue(value, accuracy); + return v; + } + return value; + }, [value]); + return ( { if (onChange) { onChange(v); diff --git a/packages/core/database/src/__tests__/fields/unix-timestamp-field.tests.ts b/packages/core/database/src/__tests__/fields/unix-timestamp-field.test.ts similarity index 78% rename from packages/core/database/src/__tests__/fields/unix-timestamp-field.tests.ts rename to packages/core/database/src/__tests__/fields/unix-timestamp-field.test.ts index d590653811..65b9068728 100644 --- a/packages/core/database/src/__tests__/fields/unix-timestamp-field.tests.ts +++ b/packages/core/database/src/__tests__/fields/unix-timestamp-field.test.ts @@ -68,6 +68,29 @@ describe('unix timestamp field', () => { expect(date).toBe('2021-01-01 00:00:00'); }); + it('number as second input should be kept as same', async () => { + const c1 = db.collection({ + name: 'test13', + fields: [ + { + name: 'date1', + type: 'unixTimestamp', + accuracy: 'second', + }, + ], + }); + + await db.sync(); + + const d = new Date(); + const second = Math.floor(d.getTime() / 1000); + + const instance = await c1.repository.create({ values: { date1: second } }); + const date1 = instance.get('date1'); + expect(date1 instanceof Date).toBe(true); + expect(date1.getTime()).toBe(second * 1000); + }); + describe('timezone', () => { test('custom', async () => { db.collection({ diff --git a/packages/core/database/src/fields/unix-timestamp-field.ts b/packages/core/database/src/fields/unix-timestamp-field.ts index f0169f2018..9dfb299b03 100644 --- a/packages/core/database/src/fields/unix-timestamp-field.ts +++ b/packages/core/database/src/fields/unix-timestamp-field.ts @@ -37,7 +37,7 @@ export class UnixTimestampField extends DateField { rationalNumber = 1; } - return Math.floor(new Date(val).getTime() / rationalNumber); + return Math.floor(typeof val === 'number' ? val : new Date(val).getTime() / rationalNumber); } additionalSequelizeOptions() { @@ -61,18 +61,21 @@ export class UnixTimestampField extends DateField { return { get() { const value = this.getDataValue(name); - if (value === null || value === undefined) { + if (value == null) { return value; } return new Date(value * rationalNumber); }, set(value) { - if (value === null || value === undefined) { + if (value == null) { this.setDataValue(name, value); } else { // date to unix timestamp - this.setDataValue(name, Math.floor(new Date(value).getTime() / rationalNumber)); + this.setDataValue( + name, + Math.floor(typeof value === 'number' ? value : new Date(value).getTime() / rationalNumber), + ); } }, }; diff --git a/packages/plugins/@nocobase/plugin-data-source-main/src/server/models/field.ts b/packages/plugins/@nocobase/plugin-data-source-main/src/server/models/field.ts index c530389d0e..42d0ed78e0 100644 --- a/packages/plugins/@nocobase/plugin-data-source-main/src/server/models/field.ts +++ b/packages/plugins/@nocobase/plugin-data-source-main/src/server/models/field.ts @@ -8,6 +8,7 @@ */ import Database, { Collection, MagicAttributeModel, SyncOptions, Transactionable } from '@nocobase/database'; +import _ from 'lodash'; interface LoadOptions extends Transactionable { // TODO @@ -42,7 +43,7 @@ export class FieldModel extends MagicAttributeModel { return collection.getField(name); } - const options = this.get(); + const options = this.toJSON(); const field = await (async () => { await new Promise((resolve) => setTimeout(resolve, 0)); @@ -202,4 +203,12 @@ export class FieldModel extends MagicAttributeModel { return this.db.getCollection(collectionName); } + + toJSON() { + const json = super.toJSON(); + if (json.interface === 'unixTimestamp' && json.accuracy) { + _.set(json, 'uiSchema.x-component-props.accuracy', json.accuracy); + } + return json; + } } diff --git a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/data-sources-field-model.ts b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/data-sources-field-model.ts index ce81a033f3..023c770130 100644 --- a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/data-sources-field-model.ts +++ b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/data-sources-field-model.ts @@ -9,6 +9,7 @@ import { MagicAttributeModel } from '@nocobase/database'; import { Application } from '@nocobase/server'; +import _ from 'lodash'; import { mergeOptions } from '../utils'; type LoadOptions = { @@ -19,7 +20,7 @@ export class DataSourcesFieldModel extends MagicAttributeModel { load(loadOptions: LoadOptions) { const { app } = loadOptions; - const options = this.get(); + const options = this.toJSON(); const { collectionName, name, dataSourceKey, field } = options; const dataSource = app.dataSourceManager.dataSources.get(dataSourceKey); const collection = dataSource.collectionManager.getCollection(collectionName); @@ -45,7 +46,7 @@ export class DataSourcesFieldModel extends MagicAttributeModel { unload(loadOptions: LoadOptions) { const { app } = loadOptions; - const options = this.get(); + const options = this.toJSON(); const { collectionName, name, dataSourceKey } = options; const dataSource = app.dataSourceManager.dataSources.get(dataSourceKey); if (!dataSource) { @@ -58,4 +59,12 @@ export class DataSourcesFieldModel extends MagicAttributeModel { collection.removeField(name); } + + toJSON() { + const json = super.toJSON(); + if (json.interface === 'unixTimestamp' && json.accuracy) { + _.set(json, 'uiSchema.x-component-props.accuracy', json.accuracy); + } + return json; + } }