Merge branch 'main' into next

This commit is contained in:
mytharcher 2025-04-16 21:06:12 +08:00
commit 42a9d5a6cb
10 changed files with 88 additions and 7 deletions

View File

@ -821,6 +821,7 @@
"File size should not exceed {{size}}.": "文件大小不能超过 {{size}}", "File size should not exceed {{size}}.": "文件大小不能超过 {{size}}",
"File size exceeds the limit": "文件大小超过限制", "File size exceeds the limit": "文件大小超过限制",
"File type is not allowed": "文件类型不允许", "File type is not allowed": "文件类型不允许",
"Uploading": "上传中",
"Incomplete uploading files need to be resolved": "未完成上传的文件需要处理", "Incomplete uploading files need to be resolved": "未完成上传的文件需要处理",
"Default title for each record": "用作数据的默认标题", "Default title for each record": "用作数据的默认标题",
"If collection inherits, choose inherited collections as templates": "当前表有继承关系时,可选择继承链路上的表作为模板来源", "If collection inherits, choose inherited collections as templates": "当前表有继承关系时,可选择继承链路上的表作为模板来源",

View File

@ -42,6 +42,8 @@ function InputInner(props: NocoBaseInputProps) {
return <AntdInput {...others} onChange={handleChange} />; return <AntdInput {...others} onChange={handleChange} />;
} }
InputInner.Password = AntdInput.Password;
export const Input: ComposedInput = Object.assign( export const Input: ComposedInput = Object.assign(
connect( connect(
InputInner, InputInner,

View File

@ -799,7 +799,7 @@ export function useDesignable() {
return component; return component;
} }
const c = get(components, component); const c = get(components, component);
return c[LAZY_COMPONENT_KEY] ?? c; return c?.[LAZY_COMPONENT_KEY] ?? c;
}, },
[get], [get],
), ),

View File

@ -15,3 +15,4 @@ export * from './datetime-interface';
export * from './datetime-no-tz-interface'; export * from './datetime-no-tz-interface';
export * from './boolean-interface'; export * from './boolean-interface';
export * from './date-interface'; export * from './date-interface';
export * from './time-interface';

View File

@ -0,0 +1,26 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import dayjs from 'dayjs';
import { BaseInterface } from './base-interface';
export class TimeInterface extends BaseInterface {
toValue(value: any, ctx?: any) {
if (this.validate(value)) {
const result = dayjs.utc(value).format('HH:mm:ss');
return result;
}
return value;
}
validate(value) {
const result = dayjs(value).isValid();
return result;
}
}

View File

@ -16,6 +16,7 @@ import {
MultipleSelectInterface, MultipleSelectInterface,
PercentInterface, PercentInterface,
SelectInterface, SelectInterface,
TimeInterface,
} from './index'; } from './index';
import { ManyToOneInterface } from './many-to-one-interface'; import { ManyToOneInterface } from './many-to-one-interface';
import { ManyToManyInterface } from './many-to-many-interface'; import { ManyToManyInterface } from './many-to-many-interface';
@ -50,6 +51,7 @@ const interfaces = {
o2m: OneToManyInterface, o2m: OneToManyInterface,
m2o: ManyToOneInterface, m2o: ManyToOneInterface,
m2m: ManyToManyInterface, m2m: ManyToManyInterface,
time: TimeInterface,
}; };
export function registerInterfaces(db: Database) { export function registerInterfaces(db: Database) {

View File

@ -2155,4 +2155,53 @@ describe('xlsx importer', () => {
expect(await Post.repository.count()).toBe(1); expect(await Post.repository.count()).toBe(1);
}); });
it('should import time field successfully', async () => {
const TimeCollection = app.db.collection({
name: 'time_tests',
fields: [
{
type: 'time',
name: 'brithtime',
},
],
});
await app.db.sync();
const templateCreator = new TemplateCreator({
collection: TimeCollection,
explain: 'test',
columns: [
{
dataIndex: ['birthtime'],
defaultTitle: '出生时间',
},
],
});
const template = (await templateCreator.run({ returnXLSXWorkbook: true })) as XLSX.WorkBook;
const worksheet = template.Sheets[template.SheetNames[0]];
XLSX.utils.sheet_add_aoa(worksheet, [['12:12:12']], {
origin: 'A3',
});
const importer = new XlsxImporter({
collectionManager: app.mainDataSource.collectionManager,
collection: TimeCollection,
explain: 'test',
columns: [
{
dataIndex: ['brithtime'],
defaultTitle: '出生时间',
},
],
workbook: template,
});
await importer.run();
const count = await TimeCollection.repository.count();
expect(count).toBe(1);
});
}); });

View File

@ -36,6 +36,7 @@ async function importXlsxAction(ctx: Context, next: Next) {
const workbook = XLSX.read(ctx.file.buffer, { const workbook = XLSX.read(ctx.file.buffer, {
type: 'buffer', type: 'buffer',
sheetRows: readLimit, sheetRows: readLimit,
cellDates: true,
}); });
const repository = ctx.getCurrentRepository() as Repository; const repository = ctx.getCurrentRepository() as Repository;

View File

@ -8,6 +8,7 @@
*/ */
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react'; import React, { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useField, useFieldSchema, useForm } from '@formily/react'; import { useField, useFieldSchema, useForm } from '@formily/react';
import { FormLayout } from '@formily/antd-v5'; import { FormLayout } from '@formily/antd-v5';
import { Button, Card, ConfigProvider, Descriptions, Space, Spin, Tag } from 'antd'; import { Button, Card, ConfigProvider, Descriptions, Space, Spin, Tag } from 'antd';
@ -47,7 +48,6 @@ import WorkflowPlugin, {
useAvailableUpstreams, useAvailableUpstreams,
useFlowContext, useFlowContext,
EXECUTION_STATUS, EXECUTION_STATUS,
JOB_STATUS,
WorkflowTitle, WorkflowTitle,
TASK_STATUS, TASK_STATUS,
usePopupRecordContext, usePopupRecordContext,
@ -56,8 +56,7 @@ import WorkflowPlugin, {
import { NAMESPACE, useLang } from '../locale'; import { NAMESPACE, useLang } from '../locale';
import { FormBlockProvider } from './instruction/FormBlockProvider'; import { FormBlockProvider } from './instruction/FormBlockProvider';
import { ManualFormType, manualFormTypes } from './instruction/SchemaConfig'; import { ManualFormType, manualFormTypes } from './instruction/SchemaConfig';
import { TaskStatusOptionsMap } from '../common/constants'; import { TaskStatusOptionsMap, TASK_STATUS } from '../common/constants';
import { useNavigate, useParams } from 'react-router-dom';
function TaskStatusColumn(props) { function TaskStatusColumn(props) {
const recordData = useCollectionRecordData(); const recordData = useCollectionRecordData();
@ -654,11 +653,11 @@ function TaskItem() {
const StatusFilterMap = { const StatusFilterMap = {
pending: { pending: {
status: JOB_STATUS.PENDING, status: TASK_STATUS.PENDING,
'execution.status': EXECUTION_STATUS.STARTED, 'execution.status': EXECUTION_STATUS.STARTED,
}, },
completed: { completed: {
status: JOB_STATUS.RESOLVED, status: [TASK_STATUS.RESOLVED, TASK_STATUS.REJECTED],
}, },
}; };

View File

@ -14,7 +14,7 @@ export const MANUAL_TASK_TYPE = 'manual';
export const TASK_STATUS = { export const TASK_STATUS = {
PENDING: 0, PENDING: 0,
RESOLVED: 1, RESOLVED: 1,
REJECTED: -1, REJECTED: -5,
}; };
export const TaskStatusOptions = [ export const TaskStatusOptions = [