chore: add prettier config

This commit is contained in:
chenos 2021-10-14 00:08:16 +08:00
parent d80c875d5e
commit f199df96aa
76 changed files with 593 additions and 453 deletions

8
.prettierignore Normal file
View File

@ -0,0 +1,8 @@
**/*.md
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test

11
.prettierrc Normal file
View File

@ -0,0 +1,11 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}

View File

@ -9,12 +9,10 @@ export class ClientSDK {
request(url: string, options?: RequestOptionsInit): RequestMethod { request(url: string, options?: RequestOptionsInit): RequestMethod {
console.log('this.options.request', this.options.request); console.log('this.options.request', this.options.request);
return this.options.request(url, options||{}); return this.options.request(url, options || {});
} }
resource(name) { resource(name) {}
}
} }
export default ClientSDK; export default ClientSDK;

View File

@ -1,4 +1,4 @@
import React, { createContext } from 'react' import React, { createContext } from 'react';
// import { ConfigProvider as AntdConfigProvider } from 'antd'; // import { ConfigProvider as AntdConfigProvider } from 'antd';
// import enUS from 'antd/lib/locale/en_US'; // import enUS from 'antd/lib/locale/en_US';
// import zhCN from 'antd/lib/locale/zh_CN'; // import zhCN from 'antd/lib/locale/zh_CN';
@ -11,9 +11,5 @@ const ConfigContext = createContext<any>(null);
export function ConfigProvider(props: any) { export function ConfigProvider(props: any) {
const { client } = props; const { client } = props;
return ( return <ClientProvider client={client}>{props.children}</ClientProvider>;
<ClientProvider client={client}> }
{props.children}
</ClientProvider>
)
};

View File

@ -146,7 +146,7 @@ export function SortableItem(props: SortableItemProps) {
previewRef.current = el; previewRef.current = el;
setDroppableNodeRef(el); setDroppableNodeRef(el);
// if (draggable) { // if (draggable) {
// setDraggableNodeRef(el); // setDraggableNodeRef(el);
// } // }
}} }}
> >

View File

@ -81,9 +81,12 @@ const useActionPermissionResource = ({ onSuccess }) => {
console.log('RoleContext', role); console.log('RoleContext', role);
// const { props } = useTable(); // const { props } = useTable();
const ctx = useContext(TableRowContext); const ctx = useContext(TableRowContext);
const resource = useResourceRequest({ const resource = useResourceRequest(
resourceName: 'action_permissions', {
}, ActionPermissionResource); resourceName: 'action_permissions',
},
ActionPermissionResource,
);
const service = useRequest( const service = useRequest(
(params?: any) => { (params?: any) => {
return resource.list({ return resource.list({
@ -593,7 +596,11 @@ function CreateFieldButton() {
option.children.length > 0 && ( option.children.length > 0 && (
<Menu.SubMenu key={groupIndex} title={option.label}> <Menu.SubMenu key={groupIndex} title={option.label}>
{option.children.map((item) => ( {option.children.map((item) => (
<Menu.Item disabled={item.disabled} style={{ minWidth: 120 }} key={item.name}> <Menu.Item
disabled={item.disabled}
style={{ minWidth: 120 }}
key={item.name}
>
{item.title} {item.title}
</Menu.Item> </Menu.Item>
))} ))}

View File

@ -51,7 +51,7 @@ const schema: ISchema = {
type: 'void', type: 'void',
title: `系统配置`, title: `系统配置`,
'x-component': 'Menu.Action', 'x-component': 'Menu.Action',
"x-component-props": { 'x-component-props': {
icon: 'SettingOutlined', icon: 'SettingOutlined',
}, },
properties: { properties: {

View File

@ -22,15 +22,12 @@ export const MenuPermissionTable = observer((props) => {
const role = useContext(RoleContext); const role = useContext(RoleContext);
const [allUiSchemaKyes, setAllUiSchemaKyes] = useState([]); const [allUiSchemaKyes, setAllUiSchemaKyes] = useState([]);
const [uiSchemaKyes, setUiSchemaKeys] = useState([]); const [uiSchemaKyes, setUiSchemaKeys] = useState([]);
const { data, loading } = useRequest( const { data, loading } = useRequest('ui_schemas:getMenuItems', {
'ui_schemas:getMenuItems', formatResult: (data) => data?.data,
{ onSuccess(data) {
formatResult: (data) => data?.data, setAllUiSchemaKyes(getKeys(data));
onSuccess(data) {
setAllUiSchemaKyes(getKeys(data));
},
}, },
); });
console.log('allUiSchemaKyes', allUiSchemaKyes); console.log('allUiSchemaKyes', allUiSchemaKyes);
const resource = useResourceRequest({ const resource = useResourceRequest({
associatedName: 'roles', associatedName: 'roles',

View File

@ -72,9 +72,12 @@ const useActionPermissionResource = ({ onSuccess }) => {
console.log('RoleContext', role); console.log('RoleContext', role);
// const { props } = useTable(); // const { props } = useTable();
const ctx = useContext(TableRowContext); const ctx = useContext(TableRowContext);
const resource = useResourceRequest({ const resource = useResourceRequest(
resourceName: 'action_permissions', {
}, ActionPermissionResource); resourceName: 'action_permissions',
},
ActionPermissionResource,
);
const service = useRequest( const service = useRequest(
(params?: any) => { (params?: any) => {
return resource.list({ return resource.list({
@ -292,7 +295,7 @@ const schema: ISchema = {
icon: 'DeleteOutlined', icon: 'DeleteOutlined',
confirm: { confirm: {
title: '删除数据', title: '删除数据',
content: '删除后无法恢复,确定要删除吗?' content: '删除后无法恢复,确定要删除吗?',
}, },
useAction: '{{ Table.useTableDestroyAction }}', useAction: '{{ Table.useTableDestroyAction }}',
}, },
@ -467,7 +470,7 @@ const schema: ISchema = {
type: 'link', type: 'link',
confirm: { confirm: {
title: '删除数据', title: '删除数据',
content: '删除后无法恢复,确定要删除吗?' content: '删除后无法恢复,确定要删除吗?',
}, },
useAction: '{{ Table.useTableDestroyAction }}', useAction: '{{ Table.useTableDestroyAction }}',
}, },

View File

@ -64,7 +64,9 @@ export const UserInfo = () => {
</Menu.Item> </Menu.Item>
<Menu.Item> <Menu.Item>
<div style={{ display: 'flex', justifyContent: 'space-between' }}> <div style={{ display: 'flex', justifyContent: 'space-between' }}>
<span style={{ marginRight: 16, display: 'inline-block' }}></span> <span style={{ marginRight: 16, display: 'inline-block' }}>
</span>
<Select <Select
className={'roles-select'} className={'roles-select'}
bordered={false} bordered={false}
@ -82,7 +84,9 @@ export const UserInfo = () => {
</Menu.Item> </Menu.Item>
<Menu.Item> <Menu.Item>
<div style={{ display: 'flex', justifyContent: 'space-between' }}> <div style={{ display: 'flex', justifyContent: 'space-between' }}>
<span style={{ marginRight: 16, display: 'inline-block' }}></span> <span style={{ marginRight: 16, display: 'inline-block' }}>
</span>
<Select <Select
className={'roles-select'} className={'roles-select'}
bordered={false} bordered={false}

View File

@ -36,7 +36,7 @@ import {
} from '../../constate'; } from '../../constate';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { Permissions } from './Permissions'; import { Permissions } from './Permissions';
import { Collections } from './Collections' import { Collections } from './Collections';
import { More } from './More'; import { More } from './More';
import { UserInfo } from './UserInfo'; import { UserInfo } from './UserInfo';
import { import {
@ -215,7 +215,7 @@ export function AdminLayout({ route, ...others }: any) {
}, },
); );
const first: any = Object.values(data?.properties||{}).shift(); const first: any = Object.values(data?.properties || {}).shift();
const findMenuLinkProperties = (schema: Schema): Schema[] => { const findMenuLinkProperties = (schema: Schema): Schema[] => {
if (!schema) { if (!schema) {
@ -232,12 +232,11 @@ export function AdminLayout({ route, ...others }: any) {
}, []); }, []);
}; };
if (loading) { if (loading) {
return <Spin size={'large'} className={'nb-spin-center'} />; return <Spin size={'large'} className={'nb-spin-center'} />;
} }
const f = findMenuLinkProperties(new Schema(first||{})).shift(); const f = findMenuLinkProperties(new Schema(first || {})).shift();
if (f?.['key'] && !match.params.name) { if (f?.['key'] && !match.params.name) {
return <Redirect to={`/admin/${f?.['key']}`} />; return <Redirect to={`/admin/${f?.['key']}`} />;

View File

@ -75,7 +75,8 @@
.user-info { .user-info {
height: 46px; height: 46px;
color: #fff; color: #fff;
&:hover, &:focus { &:hover,
&:focus {
color: #fff; color: #fff;
} }
} }
@ -95,7 +96,8 @@
} }
.site-header { .site-header {
.ant-menu.ant-menu-dark .ant-menu-item-selected, .ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected { .ant-menu.ant-menu-dark .ant-menu-item-selected,
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected {
background-color: rgba(255, 255, 255, 0.1); background-color: rgba(255, 255, 255, 0.1);
} }
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover { .ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover {
@ -105,11 +107,11 @@
color: rgba(255, 255, 255, 0.65) !important; color: rgba(255, 255, 255, 0.65) !important;
&.nb-designable-toggle:hover { &.nb-designable-toggle:hover {
color: #fff !important; color: #fff !important;
background-color: #F18B62 !important background-color: #f18b62 !important;
} }
} }
.ant-btn:hover { .ant-btn:hover {
color: #fff !important; color: #fff !important;
background-color: rgba(255, 255, 255, 0.1) !important; background-color: rgba(255, 255, 255, 0.1) !important;
} }
} }

View File

@ -11,7 +11,7 @@ const RouteSwitch = createRouteSwitch({
components: { components: {
Home: (props) => { Home: (props) => {
console.log({ props }); console.log({ props });
return <div>Home {props.children}</div> return <div>Home {props.children}</div>;
}, },
Login: () => <div>Login</div>, Login: () => <div>Login</div>,
}, },

View File

@ -22,7 +22,7 @@ export interface RouteProps {
strict?: boolean; strict?: boolean;
sensitive?: boolean; sensitive?: boolean;
component?: any; component?: any;
routes?: RouteProps[], routes?: RouteProps[];
[key: string]: any; [key: string]: any;
} }

View File

@ -44,7 +44,7 @@ export function ClientProvider(props) {
export function useResourceRequest(options, ResourceClass?: any) { export function useResourceRequest(options, ResourceClass?: any) {
const Cls = ResourceClass || Resource; const Cls = ResourceClass || Resource;
const { request } = useClient(); const { request } = useClient();
return Cls.make(options, request);; return Cls.make(options, request);
} }
export function useClient() { export function useClient() {

View File

@ -1,27 +1,32 @@
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import constate from 'constate'; import constate from 'constate';
const [CollectionsProvider, useCollectionsContext] = constate<any, any, any>(() => { const [CollectionsProvider, useCollectionsContext] = constate<any, any, any>(
const result = useRequest('collections:findAll', { () => {
formatResult: (result) => result?.data, const result = useRequest('collections:findAll', {
}); formatResult: (result) => result?.data,
return { });
...result, collections: result.data || [], return {
findCollection(name) { ...result,
return result?.data?.find((item) => item.name === name); collections: result.data || [],
}, findCollection(name) {
async loadCollections(field: any) { return result?.data?.find((item) => item.name === name);
return result?.data?.map((item: any) => ({ },
label: item.title, async loadCollections(field: any) {
value: item.name, return result?.data?.map((item: any) => ({
})); label: item.title,
}, value: item.name,
getFieldsByCollection(collectionName) { }));
const collection = result?.data?.find((item) => item.name === collectionName); },
return collection?.generalFields; getFieldsByCollection(collectionName) {
}, const collection = result?.data?.find(
}; (item) => item.name === collectionName,
}); );
return collection?.generalFields;
},
};
},
);
export { CollectionsProvider, useCollectionsContext }; export { CollectionsProvider, useCollectionsContext };

View File

@ -1,4 +1,4 @@
import { useCookieState } from "ahooks"; import { useCookieState } from 'ahooks';
import constate from 'constate'; import constate from 'constate';
const [DesignableSwitchProvider, useDesignableSwitchContext] = constate(() => { const [DesignableSwitchProvider, useDesignableSwitchContext] = constate(() => {
@ -8,8 +8,8 @@ const [DesignableSwitchProvider, useDesignableSwitchContext] = constate(() => {
designable: active === 'true', designable: active === 'true',
setDesignable(value) { setDesignable(value) {
setActive(value ? 'true' : 'false'); setActive(value ? 'true' : 'false');
} },
} };
}); });
export { DesignableSwitchProvider, useDesignableSwitchContext }; export { DesignableSwitchProvider, useDesignableSwitchContext };

View File

@ -1,5 +1,5 @@
import { createContext } from "react"; import { createContext } from 'react';
import { Schema } from "@formily/react"; import { Schema } from '@formily/react';
export const VisibleContext = createContext<any>([]); export const VisibleContext = createContext<any>([]);
export const BlockSchemaContext = createContext<Schema>(null); export const BlockSchemaContext = createContext<Schema>(null);

View File

@ -1,9 +1,7 @@
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import { Spin } from 'antd'; import { Spin } from 'antd';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { import { MemoryRouter as Router } from 'react-router-dom';
MemoryRouter as Router,
} from 'react-router-dom';
import { import {
createRouteSwitch, createRouteSwitch,
RouteRedirectProps, RouteRedirectProps,
@ -11,7 +9,7 @@ import {
AuthLayout, AuthLayout,
RouteSchemaRenderer, RouteSchemaRenderer,
ConfigProvider, ConfigProvider,
ClientSDK ClientSDK,
} from '../'; } from '../';
import { UseRequestProvider } from 'ahooks'; import { UseRequestProvider } from 'ahooks';
import { extend } from 'umi-request'; import { extend } from 'umi-request';
@ -53,7 +51,7 @@ const App = () => {
}); });
if (loading) { if (loading) {
return <Spin size={'large'} className={'nb-spin-center'} /> return <Spin size={'large'} className={'nb-spin-center'} />;
} }
return ( return (
@ -71,4 +69,4 @@ export default () => {
<App /> <App />
</ConfigProvider> </ConfigProvider>
); );
} };

View File

@ -1 +1 @@
export default {} export default {};

View File

@ -1 +1 @@
export default {} export default {};

View File

@ -28,13 +28,12 @@ export interface ListOptions {
} }
export class Resource { export class Resource {
public options: ResourceOptions; public options: ResourceOptions;
public request: RequestMethod; public request: RequestMethod;
constructor(options: string | ResourceOptions, request?: any) { constructor(options: string | ResourceOptions, request?: any) {
if (typeof options === 'string') { if (typeof options === 'string') {
this.options = { resourceName: options } this.options = { resourceName: options };
} else { } else {
this.options = options; this.options = options;
} }
@ -54,7 +53,14 @@ export class Resource {
} }
list(options: ListOptions = {}) { list(options: ListOptions = {}) {
const { defaultAppends = [], appends = [], defaultFilter, filter, pageSize, ...others } = options; const {
defaultAppends = [],
appends = [],
defaultFilter,
filter,
pageSize,
...others
} = options;
const { associatedKey, associatedName, resourceName } = this.options; const { associatedKey, associatedName, resourceName } = this.options;
let url = `${resourceName}:list`; let url = `${resourceName}:list`;
if (associatedName && associatedKey) { if (associatedName && associatedKey) {
@ -63,7 +69,9 @@ export class Resource {
return this.request(url, { return this.request(url, {
method: 'get', method: 'get',
params: { params: {
filter: decodeURIComponent(JSON.stringify({ and: [defaultFilter, filter].filter(Boolean) })), filter: decodeURIComponent(
JSON.stringify({ and: [defaultFilter, filter].filter(Boolean) }),
),
'fields[appends]': defaultAppends.concat(appends).join(','), 'fields[appends]': defaultAppends.concat(appends).join(','),
perPage: pageSize, perPage: pageSize,
...others, ...others,
@ -90,7 +98,7 @@ export class Resource {
const { associatedKey, associatedName, resourceName } = this.options; const { associatedKey, associatedName, resourceName } = this.options;
let url = `${resourceName}:create`; let url = `${resourceName}:create`;
if (associatedKey && associatedName) { if (associatedKey && associatedName) {
url = `${associatedName}/${associatedKey}/${url}` url = `${associatedName}/${associatedKey}/${url}`;
} }
return this.request(url, { return this.request(url, {
method: 'post', method: 'post',
@ -101,9 +109,11 @@ export class Resource {
save(values: any, options: SaveOptions = {}) { save(values: any, options: SaveOptions = {}) {
const resourceKey = options.resourceKey || this.options.resourceKey; const resourceKey = options.resourceKey || this.options.resourceKey;
const { associatedKey, associatedName, resourceName } = this.options; const { associatedKey, associatedName, resourceName } = this.options;
let url = `${resourceName}:${resourceKey ? `update/${resourceKey}` : 'create'}`; let url = `${resourceName}:${
resourceKey ? `update/${resourceKey}` : 'create'
}`;
if (associatedKey && associatedName) { if (associatedKey && associatedName) {
url = `${associatedName}/${associatedKey}/${url}` url = `${associatedName}/${associatedKey}/${url}`;
} }
return this.request(url, { return this.request(url, {
method: 'post', method: 'post',
@ -122,9 +132,13 @@ export class Resource {
...others, ...others,
}, },
parseResponse: false, parseResponse: false,
responseType: 'blob' responseType: 'blob',
}).then(async (response: Response) => { }).then(async (response: Response) => {
const filename = decodeURI(response.headers.get('Content-Disposition').replace('attachment; filename=', '')); const filename = decodeURI(
response.headers
.get('Content-Disposition')
.replace('attachment; filename=', ''),
);
// ReadableStream // ReadableStream
let res = new Response(response.body); let res = new Response(response.body);
let blob = await res.blob(); let blob = await res.blob();
@ -151,7 +165,7 @@ export class Resource {
return this.request(url, { return this.request(url, {
method: 'get', method: 'get',
params: { params: {
filter filter,
}, },
}); });
} }
@ -165,7 +179,10 @@ export class Resource {
}); });
} }
static make(options: null | string | Resource | ResourceOptions, request?: any): Resource | null { static make(
options: null | string | Resource | ResourceOptions,
request?: any,
): Resource | null {
if (typeof options === 'string') { if (typeof options === 'string') {
return new this({ resourceName: options }, request); return new this({ resourceName: options }, request);
} }

View File

@ -74,14 +74,13 @@
} }
&[disabled] { &[disabled] {
color: #00000040; color: #00000040;
background-color:#fff; background-color: #fff;
cursor:not-allowed; cursor: not-allowed;
} }
} }
} }
} }
.designable-bar-actions { .designable-bar-actions {
.ant-btn { .ant-btn {
border: 0; border: 0;
@ -106,4 +105,4 @@
right: -12px !important; right: -12px !important;
} }
} }
} }

View File

@ -1566,7 +1566,10 @@ AddNew.FormItem = observer((props: any) => {
const values = await FormDialog(`添加字段`, () => { const values = await FormDialog(`添加字段`, () => {
return ( return (
<FormLayout layout={'vertical'}> <FormLayout layout={'vertical'}>
<SchemaField scope={{ loadCollections }} schema={item} /> <SchemaField
scope={{ loadCollections }}
schema={item}
/>
</FormLayout> </FormLayout>
); );
}).open({ }).open({

View File

@ -7,7 +7,11 @@ import {
getSchemaPath, getSchemaPath,
useDesignable, useDesignable,
} from '../../components/schema-renderer'; } from '../../components/schema-renderer';
import { useClient, DisplayedMapProvider, useDisplayedMapContext } from '../../constate'; import {
useClient,
DisplayedMapProvider,
useDisplayedMapContext,
} from '../../constate';
import cls from 'classnames'; import cls from 'classnames';
import { Button, Dropdown, Menu, Space } from 'antd'; import { Button, Dropdown, Menu, Space } from 'antd';
import SwitchMenuItem from '../../components/SwitchMenuItem'; import SwitchMenuItem from '../../components/SwitchMenuItem';

View File

@ -1,4 +1,4 @@
const now = new Date() const now = new Date();
export default [ export default [
{ {
@ -177,4 +177,4 @@ export default [
start: new Date(2015, 3, 14, 18, 30, 0), start: new Date(2015, 3, 14, 18, 30, 0),
end: new Date(2015, 3, 14, 20, 0, 0), end: new Date(2015, 3, 14, 20, 0, 0),
}, },
] ];

View File

@ -32,4 +32,4 @@
} }
} }
} }
} }

View File

@ -209,7 +209,9 @@ export const Calendar: any = observer((props: any) => {
<BigCalendar <BigCalendar
popup popup
selectable selectable
events={Array.isArray(field.value.slice()) ? field.value.slice() : []} events={
Array.isArray(field.value.slice()) ? field.value.slice() : []
}
views={['month', 'week', 'day']} views={['month', 'week', 'day']}
step={60} step={60}
showMultiDayTimes showMultiDayTimes

View File

@ -230,7 +230,7 @@ button.rbc-input::-moz-focus-inner {
box-shadow: none; box-shadow: none;
margin: 0; margin: 0;
padding: 2px 5px; padding: 2px 5px;
background-color: rgba(240, 240, 240, .65); background-color: rgba(240, 240, 240, 0.65);
border-radius: 2px; border-radius: 2px;
// color: #1890ff; // color: #1890ff;
cursor: pointer; cursor: pointer;

View File

@ -128,6 +128,10 @@ const loadChinaRegionData = (
export default () => { export default () => {
return ( return (
<SchemaRenderer debug scope={{ loadChinaRegions, loadChinaRegionData }} schema={schema} /> <SchemaRenderer
debug
scope={{ loadChinaRegions, loadChinaRegionData }}
schema={schema}
/>
); );
}; };

View File

@ -7,7 +7,10 @@ export type ReactG2PlotProps<O> = {
readonly config: O; readonly config: O;
}; };
export default forwardRef(function<O = any>(props: ReactG2PlotProps<O>, ref: any) { export default forwardRef(function <O = any>(
props: ReactG2PlotProps<O>,
ref: any,
) {
const { className, plot, config } = props; const { className, plot, config } = props;
const containerRef = useRef(undefined); const containerRef = useRef(undefined);

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react';
import { connect, mapProps, mapReadPretty } from '@formily/react' import { connect, mapProps, mapReadPretty } from '@formily/react';
import { Tag, Select } from 'antd' import { Tag, Select } from 'antd';
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons';
const colors = { const colors = {
red: '薄暮', red: '薄暮',
@ -22,13 +22,13 @@ export const ColorSelect = connect(
(props) => { (props) => {
return ( return (
<Select {...props}> <Select {...props}>
{Object.keys(colors).map(color => ( {Object.keys(colors).map((color) => (
<Select.Option value={color}> <Select.Option value={color}>
<Tag color={color}>{colors[color]}</Tag> <Tag color={color}>{colors[color]}</Tag>
</Select.Option> </Select.Option>
))} ))}
</Select> </Select>
) );
}, },
mapProps((props, field) => { mapProps((props, field) => {
return { return {
@ -42,17 +42,15 @@ export const ColorSelect = connect(
)} )}
</span> </span>
), ),
} };
}), }),
mapReadPretty((props) => { mapReadPretty((props) => {
const { value } = props; const { value } = props;
if (!colors[value]) { if (!colors[value]) {
return null; return null;
} }
return ( return <Tag color={value}>{colors[value]}</Tag>;
<Tag color={value}>{colors[value]}</Tag> }),
); );
})
)
export default ColorSelect export default ColorSelect;

View File

@ -40,5 +40,5 @@ export default observer(() => {
<div> <div>
<SchemaRenderer form={form} schema={schema} /> <SchemaRenderer form={form} schema={schema} />
</div> </div>
) );
}) });

View File

@ -16,7 +16,7 @@ const schema: ISchema = {
{ {
name: 'test2', name: 'test2',
title: '数据表 2', title: '数据表 2',
} },
], ],
properties: { properties: {
title: { title: {
@ -31,7 +31,7 @@ const schema: ISchema = {
title: '数据表标识', title: '数据表标识',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Input', 'x-component': 'Input',
"x-read-pretty": true, 'x-read-pretty': true,
}, },
fields: { fields: {
type: 'array', type: 'array',
@ -39,8 +39,8 @@ const schema: ISchema = {
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'DatabaseField', 'x-component': 'DatabaseField',
default: [], default: [],
} },
} },
}; };
const form = createForm(); const form = createForm();

View File

@ -42,10 +42,7 @@ import Modal from 'antd/lib/modal/Modal';
import { clone, cloneDeep, get } from 'lodash'; import { clone, cloneDeep, get } from 'lodash';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import { import { createOrUpdateCollection, deleteCollection } from '..';
createOrUpdateCollection,
deleteCollection,
} from '..';
import { useCollectionsContext } from '../../constate/Collections'; import { useCollectionsContext } from '../../constate/Collections';
import { import {
DragHandle, DragHandle,
@ -185,7 +182,11 @@ export const DatabaseCollection = observer((props) => {
<Input.Search <Input.Search
size={'middle'} size={'middle'}
placeholder={'填写数据表名称'} placeholder={'填写数据表名称'}
enterButton={<><PlusOutlined /> </>} enterButton={
<>
<PlusOutlined />
</>
}
value={newValue} value={newValue}
onChange={(e) => { onChange={(e) => {
setNewValue(e.target.value); setNewValue(e.target.value);

View File

@ -21,14 +21,14 @@ const groupLabels = {};
export function getDefaultFields() { export function getDefaultFields() {
const defaults = ['createdAt', 'updatedAt', 'createdBy', 'updatedBy']; const defaults = ['createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
return defaults.map(key => { return defaults.map((key) => {
return { return {
interface: key, interface: key,
key: uid(), key: uid(),
name: uid(), name: uid(),
privilege: 'undelete', privilege: 'undelete',
...cloneDeep(interfaces.get(key)?.default), ...cloneDeep(interfaces.get(key)?.default),
} };
}); });
} }
@ -55,19 +55,21 @@ registerGroupLabel('relation', '关系类型');
registerGroupLabel('systemInfo', '系统信息'); registerGroupLabel('systemInfo', '系统信息');
registerGroupLabel('others', '其他类型'); registerGroupLabel('others', '其他类型');
export const options = Object.keys(groupLabels).map(groupName => { export const options = Object.keys(groupLabels).map((groupName) => {
return { return {
label: groupLabels[groupName], label: groupLabels[groupName],
children: Object.keys(fields[groupName] || {}).map((type) => { children: Object.keys(fields[groupName] || {})
return { .map((type) => {
name: type, return {
...fields[groupName][type], name: type,
}; ...fields[groupName][type],
}).sort((a, b) => a.order - b.order), };
} })
.sort((a, b) => a.order - b.order),
};
}); });
export const isAssociation = (field) => { export const isAssociation = (field) => {
const options = interfaces.get(field.interface); const options = interfaces.get(field.interface);
return options?.isAssociation; return options?.isAssociation;
} };

View File

@ -40,7 +40,7 @@ export const percent: FieldOptions = {
{ value: '0.001', label: '1.000' }, { value: '0.001', label: '1.000' },
{ value: '0.0001', label: '1.0000' }, { value: '0.0001', label: '1.0000' },
{ value: '0.00001', label: '1.00000' }, { value: '0.00001', label: '1.00000' },
] ],
}, },
}, },
operations: number.operations, operations: number.operations,

View File

@ -17,7 +17,7 @@ export const phone: FieldOptions = {
// title, // title,
'x-component': 'Input', 'x-component': 'Input',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
"x-validator": 'phone', 'x-validator': 'phone',
'x-designable-bar': 'Input.DesignableBar', 'x-designable-bar': 'Input.DesignableBar',
}, },
}, },

View File

@ -34,13 +34,17 @@ export const select: FieldOptions = {
{ {
label: '包含', label: '包含',
value: 'in', value: 'in',
schema: { 'x-component': 'Select', 'x-component-props': { mode: 'tags' } }, schema: {
'x-component': 'Select',
'x-component-props': { mode: 'tags' },
},
}, },
{ {
label: '不包含', label: '不包含',
value: 'notIn', value: 'notIn',
schema: { schema: {
'x-component': 'Select', 'x-component-props': { mode: 'tags' }, 'x-component': 'Select',
'x-component-props': { mode: 'tags' },
}, },
}, },
{ label: '非空', value: '$notNull', noValue: true }, { label: '非空', value: '$notNull', noValue: true },

View File

@ -33,7 +33,7 @@ export const subTable: FieldOptions = {
}, },
properties: { properties: {
...defaultProps, ...defaultProps,
'children': { children: {
type: 'array', type: 'array',
title: '子表格字段', title: '子表格字段',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',

View File

@ -50,4 +50,4 @@
right: 16px; right: 16px;
top: 12px; top: 12px;
} }
} }

View File

@ -1,66 +1,72 @@
import moment from 'moment' import moment from 'moment';
import { connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react' import {
import { DatePicker as AntdDatePicker } from 'antd' connect,
mapProps,
mapReadPretty,
useField,
useFieldSchema,
} from '@formily/react';
import { DatePicker as AntdDatePicker } from 'antd';
import { import {
DatePickerProps as AntdDatePickerProps, DatePickerProps as AntdDatePickerProps,
RangePickerProps, RangePickerProps,
} from 'antd/lib/date-picker' } from 'antd/lib/date-picker';
import { Display } from '../display' import { Display } from '../display';
import { formatMomentValue, momentable } from '@formily/antd/esm/__builtins__' import { formatMomentValue, momentable } from '@formily/antd/esm/__builtins__';
type DatePickerProps<PickerProps> = Exclude< type DatePickerProps<PickerProps> = Exclude<
PickerProps, PickerProps,
'value' | 'onChange' 'value' | 'onChange'
> & { > & {
value: string value: string;
onChange: (value: string | string[]) => void onChange: (value: string | string[]) => void;
} };
type ComposedDatePicker = React.FC<AntdDatePickerProps> & { type ComposedDatePicker = React.FC<AntdDatePickerProps> & {
RangePicker?: React.FC<RangePickerProps> RangePicker?: React.FC<RangePickerProps>;
} };
const mapDateFormat = function () { const mapDateFormat = function () {
const getDefaultFormat = (props: DatePickerProps<AntdDatePickerProps>) => { const getDefaultFormat = (props: DatePickerProps<AntdDatePickerProps>) => {
if (props['picker'] === 'month') { if (props['picker'] === 'month') {
return 'YYYY-MM' return 'YYYY-MM';
} else if (props['picker'] === 'quarter') { } else if (props['picker'] === 'quarter') {
return 'YYYY-\\QQ' return 'YYYY-\\QQ';
} else if (props['picker'] === 'year') { } else if (props['picker'] === 'year') {
return 'YYYY' return 'YYYY';
} else if (props['picker'] === 'week') { } else if (props['picker'] === 'week') {
return 'YYYY-wo' return 'YYYY-wo';
} }
return props['showTime'] ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD' return props['showTime'] ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD';
} };
return (props: any) => { return (props: any) => {
const field = useField(); const field = useField();
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const format = props['format'] || getDefaultFormat(props) const format = props['format'] || getDefaultFormat(props);
const onChange = props.onChange const onChange = props.onChange;
return { return {
...props, ...props,
format: format, format: format,
value: momentable(props.value, format === 'YYYY-wo' ? 'YYYY-w' : format), value: momentable(props.value, format === 'YYYY-wo' ? 'YYYY-w' : format),
onChange: (value: moment.Moment | moment.Moment[]) => { onChange: (value: moment.Moment | moment.Moment[]) => {
if (onChange) { if (onChange) {
onChange(formatMomentValue(value, format)) onChange(formatMomentValue(value, format));
} }
}, },
} };
} };
} };
export const DatePicker: ComposedDatePicker = connect( export const DatePicker: ComposedDatePicker = connect(
AntdDatePicker, AntdDatePicker,
mapProps(mapDateFormat()), mapProps(mapDateFormat()),
mapReadPretty(Display.DatePicker) mapReadPretty(Display.DatePicker),
) );
DatePicker.RangePicker = connect( DatePicker.RangePicker = connect(
AntdDatePicker.RangePicker, AntdDatePicker.RangePicker,
mapProps(mapDateFormat()), mapProps(mapDateFormat()),
mapReadPretty(Display.DateRangePicker) mapReadPretty(Display.DateRangePicker),
) );
export default DatePicker export default DatePicker;

View File

@ -1,16 +1,13 @@
import React from 'react'; import React from 'react';
import { observer, useFieldSchema } from '@formily/react'; import { observer, useFieldSchema } from '@formily/react';
import { import { DragDropManagerProvider } from './../../components/drag-and-drop';
DragDropManagerProvider,
} from './../../components/drag-and-drop';
export const DragAndDrop = observer((props) => { export const DragAndDrop = observer((props) => {
const schema = useFieldSchema(); const schema = useFieldSchema();
console.log('DragAndDrop') console.log('DragAndDrop');
return ( return (
<DragDropManagerProvider uid={schema.name}> <DragDropManagerProvider uid={schema.name}>
<div className={'nb-dnd'}>{props.children}</div> <div className={'nb-dnd'}>{props.children}</div>
</DragDropManagerProvider> </DragDropManagerProvider>
) );
}); });

View File

@ -171,7 +171,9 @@ export const FilterItem = (props) => {
[], [],
); );
const columnEnum: any = [...columns.values()].map((column) => column.toJSON()); const columnEnum: any = [...columns.values()].map((column) =>
column.toJSON(),
);
return ( return (
<FormProvider form={form}> <FormProvider form={form}>

View File

@ -40,4 +40,4 @@
} }
} }
} }
} }

View File

@ -42,4 +42,4 @@
} }
} }
} }
} }

View File

@ -14,7 +14,7 @@ const schema: ISchema = {
type: 'void', type: 'void',
name: uid(), name: uid(),
'x-component': 'Grid', 'x-component': 'Grid',
"x-component-props": { 'x-component-props': {
addNewComponent: 'AddNew.CardItem', addNewComponent: 'AddNew.CardItem',
}, },
properties: { properties: {
@ -186,7 +186,5 @@ const schema: ISchema = {
}; };
export default () => { export default () => {
return ( return <SchemaRenderer components={{ Grid }} schema={schema} />;
<SchemaRenderer components={{ Grid }} schema={schema} />
);
}; };

View File

@ -101,7 +101,7 @@ body.dragging {
.nb-block-item { .nb-block-item {
position: relative; position: relative;
&.isDragging { &.isDragging {
opacity: .3; opacity: 0.3;
} }
&.isOver::after { &.isOver::after {
content: ''; content: '';

View File

@ -1,10 +1,15 @@
import React from 'react'; import React from 'react';
import { ISchema as IFormilySchema, observer, Schema, useField } from '@formily/react'; import {
ISchema as IFormilySchema,
observer,
Schema,
useField,
} from '@formily/react';
import { extend } from 'umi-request'; import { extend } from 'umi-request';
import './designable-bar/style.less'; import './designable-bar/style.less';
export type FormilyISchema = IFormilySchema export type FormilyISchema = IFormilySchema;
export interface ISchema extends IFormilySchema { export interface ISchema extends IFormilySchema {
[key: string]: any; [key: string]: any;

View File

@ -24,4 +24,4 @@
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
} }
} }
} }

View File

@ -1,7 +1,14 @@
import React from 'react' import React from 'react';
import { connect, mapProps, mapReadPretty, observer, useField, useFieldSchema } from '@formily/react' import {
import { Input as AntdInput } from 'antd' connect,
import { InputProps, TextAreaProps } from 'antd/lib/input' mapProps,
mapReadPretty,
observer,
useField,
useFieldSchema,
} from '@formily/react';
import { Input as AntdInput } from 'antd';
import { InputProps, TextAreaProps } from 'antd/lib/input';
import { Display } from '../display'; import { Display } from '../display';
import { DesignableBar } from './DesignableBar'; import { DesignableBar } from './DesignableBar';
import { Dropdown, Menu, Space } from 'antd'; import { Dropdown, Menu, Space } from 'antd';
@ -17,10 +24,10 @@ import { isGridRowOrCol } from '../grid';
import { DragHandle } from '../../components/Sortable'; import { DragHandle } from '../../components/Sortable';
type ComposedInput = React.FC<InputProps> & { type ComposedInput = React.FC<InputProps> & {
TextArea?: React.FC<TextAreaProps> TextArea?: React.FC<TextAreaProps>;
URL?: React.FC<InputProps> URL?: React.FC<InputProps>;
DesignableBar?: React.FC<any> DesignableBar?: React.FC<any>;
} };
export const Input: ComposedInput = connect( export const Input: ComposedInput = connect(
AntdInput, AntdInput,
@ -36,12 +43,12 @@ export const Input: ComposedInput = connect(
)} )}
</span> </span>
), ),
} };
}), }),
mapReadPretty(Display.Input) mapReadPretty(Display.Input),
) );
Input.TextArea = connect(AntdInput.TextArea, mapReadPretty(Display.TextArea)) Input.TextArea = connect(AntdInput.TextArea, mapReadPretty(Display.TextArea));
Input.URL = connect(AntdInput, mapReadPretty(Display.URL)) Input.URL = connect(AntdInput, mapReadPretty(Display.URL));
export default Input export default Input;

View File

@ -11,12 +11,7 @@ import {
useForm, useForm,
RecursionField, RecursionField,
} from '@formily/react'; } from '@formily/react';
import { import { useSchemaPath, SchemaField, useDesignable, ISchema } from '../';
useSchemaPath,
SchemaField,
useDesignable,
ISchema,
} from '../';
import get from 'lodash/get'; import get from 'lodash/get';
import { Button, Dropdown, Menu, Space } from 'antd'; import { Button, Dropdown, Menu, Space } from 'antd';
import { MenuOutlined, DragOutlined } from '@ant-design/icons'; import { MenuOutlined, DragOutlined } from '@ant-design/icons';

View File

@ -208,5 +208,11 @@ const schema: ISchema = {
}; };
export default () => { export default () => {
return <SchemaRenderer scope={{ Kanban }} components={{ Kanban }} schema={schema} />; return (
<SchemaRenderer
scope={{ Kanban }}
components={{ Kanban }}
schema={schema}
/>
);
}; };

View File

@ -29,7 +29,11 @@ import { useState } from 'react';
import { CSS } from '@dnd-kit/utilities'; import { CSS } from '@dnd-kit/utilities';
import cls from 'classnames'; import cls from 'classnames';
import './style.less'; import './style.less';
import { CollectionProvider, useCollectionContext, useResourceRequest } from '../../constate'; import {
CollectionProvider,
useCollectionContext,
useResourceRequest,
} from '../../constate';
import { Resource } from '../../resource'; import { Resource } from '../../resource';
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import { Action } from '../action'; import { Action } from '../action';

View File

@ -26,7 +26,7 @@
.nb-kanban-item { .nb-kanban-item {
margin-bottom: 12px; margin-bottom: 12px;
&.isDragging { &.isDragging {
opacity: .2; opacity: 0.2;
} }
.ant-formily-item-control-content-component { .ant-formily-item-control-content-component {
@ -51,7 +51,8 @@
.nb-kanban-drag-overlay { .nb-kanban-drag-overlay {
.isDragging { .isDragging {
opacity: 1 !important; opacity: 1 !important;
box-shadow: 0 1px 2px -2px rgb(0 0 0 / 16%), 0 3px 6px 0 rgb(0 0 0 / 12%), 0 5px 12px 4px rgb(0 0 0 / 9%); box-shadow: 0 1px 2px -2px rgb(0 0 0 / 16%), 0 3px 6px 0 rgb(0 0 0 / 12%),
0 5px 12px 4px rgb(0 0 0 / 9%);
} }
.designable-bar { .designable-bar {
display: none !important; display: none !important;
@ -61,7 +62,7 @@
.nb-kanban-item { .nb-kanban-item {
position: relative; position: relative;
// padding: 0; // padding: 0;
.nb-block-item { .nb-block-item {
&:last-child { &:last-child {
.ant-formily-item { .ant-formily-item {
@ -69,10 +70,11 @@
} }
} }
} }
.nb-grid-block, .ant-formily-item { .nb-grid-block,
.ant-formily-item {
margin-bottom: 12px !important; margin-bottom: 12px !important;
} }
.ant-formily-layout { .ant-formily-layout {
&:hover { &:hover {
> .designable-bar { > .designable-bar {
@ -132,7 +134,8 @@
.ant-upload-list-picture-card .ant-upload-list-item-name { .ant-upload-list-picture-card .ant-upload-list-item-name {
display: none; display: none;
} }
.ant-upload-list-picture .ant-upload-list-item, .ant-upload-list-picture-card .ant-upload-list-item { .ant-upload-list-picture .ant-upload-list-item,
.ant-upload-list-picture-card .ant-upload-list-item {
padding: 1px; padding: 1px;
} }
} }

View File

@ -1,3 +1,3 @@
.nb-markdown > *:last-child { .nb-markdown > *:last-child {
margin-bottom: 0; margin-bottom: 0;
} }

View File

@ -29,7 +29,7 @@ const schema: ISchema = {
title: `链接`, title: `链接`,
'x-designable-bar': 'Menu.DesignableBar', 'x-designable-bar': 'Menu.DesignableBar',
'x-component': 'Menu.Link', 'x-component': 'Menu.Link',
"x-component-props": { 'x-component-props': {
to: '/abc/def', to: '/abc/def',
}, },
}, },

View File

@ -86,11 +86,7 @@ export default () => {
return ( return (
<Layout> <Layout>
<Layout.Header> <Layout.Header>
<SchemaRenderer <SchemaRenderer debug={true} scope={{ sideMenuRef }} schema={schema} />
debug={true}
scope={{ sideMenuRef }}
schema={schema}
/>
</Layout.Header> </Layout.Header>
<Layout> <Layout>
<Layout.Sider theme={'light'} ref={sideMenuRef}></Layout.Sider> <Layout.Sider theme={'light'} ref={sideMenuRef}></Layout.Sider>

View File

@ -126,7 +126,7 @@
height: 100%; height: 100%;
width: 100%; width: 100%;
background-color: #f18b62; background-color: #f18b62;
opacity: .5; opacity: 0.5;
} }
.droppable:not(.isDragging).isOver::after { .droppable:not(.isDragging).isOver::after {
content: ''; content: '';
@ -151,7 +151,7 @@
height: 100%; height: 100%;
width: 100%; width: 100%;
background-color: #f18b62; background-color: #f18b62;
opacity: .3; opacity: 0.3;
} }
.droppable:not(.isDragging).isOver::after { .droppable:not(.isDragging).isOver::after {
content: ''; content: '';

View File

@ -13,9 +13,7 @@ export const Page = observer((props) => {
<title>{documentTitle}</title> <title>{documentTitle}</title>
</Helmet> </Helmet>
<AntdPageHeader ghost={false} title={pageTitle} {...others} /> <AntdPageHeader ghost={false} title={pageTitle} {...others} />
<div style={{margin: 24}}> <div style={{ margin: 24 }}>{children}</div>
{children}
</div>
</> </>
); );
}); });

View File

@ -1,164 +1,164 @@
import React, { Fragment } from 'react' import React, { Fragment } from 'react';
import { isFn } from '@formily/shared' import { isFn } from '@formily/shared';
type ReactRenderPropsChildren<T = any> = type ReactRenderPropsChildren<T = any> =
| React.ReactNode | React.ReactNode
| ((props: T) => React.ReactElement) | ((props: T) => React.ReactElement);
interface IPasswordStrengthProps { interface IPasswordStrengthProps {
value?: React.ReactText value?: React.ReactText;
children?: ReactRenderPropsChildren<number> children?: ReactRenderPropsChildren<number>;
} }
const isNum = function (c) { const isNum = function (c) {
return c >= 48 && c <= 57 return c >= 48 && c <= 57;
} };
const isLower = function (c) { const isLower = function (c) {
return c >= 97 && c <= 122 return c >= 97 && c <= 122;
} };
const isUpper = function (c) { const isUpper = function (c) {
return c >= 65 && c <= 90 return c >= 65 && c <= 90;
} };
const isSymbol = function (c) { const isSymbol = function (c) {
return !(isLower(c) || isUpper(c) || isNum(c)) return !(isLower(c) || isUpper(c) || isNum(c));
} };
const isLetter = function (c) { const isLetter = function (c) {
return isLower(c) || isUpper(c) return isLower(c) || isUpper(c);
} };
const getStrength = (val) => { const getStrength = (val) => {
if (!val) return 0 if (!val) return 0;
let num = 0 let num = 0;
let lower = 0 let lower = 0;
let upper = 0 let upper = 0;
let symbol = 0 let symbol = 0;
let MNS = 0 let MNS = 0;
let rep = 0 let rep = 0;
let repC = 0 let repC = 0;
let consecutive = 0 let consecutive = 0;
let sequential = 0 let sequential = 0;
const len = () => num + lower + upper + symbol const len = () => num + lower + upper + symbol;
const callme = () => { const callme = () => {
let re = num > 0 ? 1 : 0 let re = num > 0 ? 1 : 0;
re += lower > 0 ? 1 : 0 re += lower > 0 ? 1 : 0;
re += upper > 0 ? 1 : 0 re += upper > 0 ? 1 : 0;
re += symbol > 0 ? 1 : 0 re += symbol > 0 ? 1 : 0;
if (re > 2 && len() >= 8) { if (re > 2 && len() >= 8) {
return re + 1 return re + 1;
} else { } else {
return 0 return 0;
} }
} };
for (let i = 0; i < val.length; i++) { for (let i = 0; i < val.length; i++) {
const c = val.charCodeAt(i) const c = val.charCodeAt(i);
if (isNum(c)) { if (isNum(c)) {
num++ num++;
if (i !== 0 && i !== val.length - 1) { if (i !== 0 && i !== val.length - 1) {
MNS++ MNS++;
} }
if (i > 0 && isNum(val.charCodeAt(i - 1))) { if (i > 0 && isNum(val.charCodeAt(i - 1))) {
consecutive++ consecutive++;
} }
} else if (isLower(c)) { } else if (isLower(c)) {
lower++ lower++;
if (i > 0 && isLower(val.charCodeAt(i - 1))) { if (i > 0 && isLower(val.charCodeAt(i - 1))) {
consecutive++ consecutive++;
} }
} else if (isUpper(c)) { } else if (isUpper(c)) {
upper++ upper++;
if (i > 0 && isUpper(val.charCodeAt(i - 1))) { if (i > 0 && isUpper(val.charCodeAt(i - 1))) {
consecutive++ consecutive++;
} }
} else { } else {
symbol++ symbol++;
if (i !== 0 && i !== val.length - 1) { if (i !== 0 && i !== val.length - 1) {
MNS++ MNS++;
} }
} }
let exists = false let exists = false;
for (let j = 0; j < val.length; j++) { for (let j = 0; j < val.length; j++) {
if (val[i] === val[j] && i !== j) { if (val[i] === val[j] && i !== j) {
exists = true exists = true;
repC += Math.abs(val.length / (j - i)) repC += Math.abs(val.length / (j - i));
} }
} }
if (exists) { if (exists) {
rep++ rep++;
const unique = val.length - rep const unique = val.length - rep;
repC = unique ? Math.ceil(repC / unique) : Math.ceil(repC) repC = unique ? Math.ceil(repC / unique) : Math.ceil(repC);
} }
if (i > 1) { if (i > 1) {
const last1 = val.charCodeAt(i - 1) const last1 = val.charCodeAt(i - 1);
const last2 = val.charCodeAt(i - 2) const last2 = val.charCodeAt(i - 2);
if (isLetter(c)) { if (isLetter(c)) {
if (isLetter(last1) && isLetter(last2)) { if (isLetter(last1) && isLetter(last2)) {
const v = val.toLowerCase() const v = val.toLowerCase();
const vi = v.charCodeAt(i) const vi = v.charCodeAt(i);
const vi1 = v.charCodeAt(i - 1) const vi1 = v.charCodeAt(i - 1);
const vi2 = v.charCodeAt(i - 2) const vi2 = v.charCodeAt(i - 2);
if (vi - vi1 === vi1 - vi2 && Math.abs(vi - vi1) === 1) { if (vi - vi1 === vi1 - vi2 && Math.abs(vi - vi1) === 1) {
sequential++ sequential++;
} }
} }
} else if (isNum(c)) { } else if (isNum(c)) {
if (isNum(last1) && isNum(last2)) { if (isNum(last1) && isNum(last2)) {
if (c - last1 === last1 - last2 && Math.abs(c - last1) === 1) { if (c - last1 === last1 - last2 && Math.abs(c - last1) === 1) {
sequential++ sequential++;
} }
} }
} else { } else {
if (isSymbol(last1) && isSymbol(last2)) { if (isSymbol(last1) && isSymbol(last2)) {
if (c - last1 === last1 - last2 && Math.abs(c - last1) === 1) { if (c - last1 === last1 - last2 && Math.abs(c - last1) === 1) {
sequential++ sequential++;
} }
} }
} }
} }
} }
let sum = 0 let sum = 0;
const length = len() const length = len();
sum += 4 * length sum += 4 * length;
if (lower > 0) { if (lower > 0) {
sum += 2 * (length - lower) sum += 2 * (length - lower);
} }
if (upper > 0) { if (upper > 0) {
sum += 2 * (length - upper) sum += 2 * (length - upper);
} }
if (num !== length) { if (num !== length) {
sum += 4 * num sum += 4 * num;
} }
sum += 6 * symbol sum += 6 * symbol;
sum += 2 * MNS sum += 2 * MNS;
sum += 2 * callme() sum += 2 * callme();
if (length === lower + upper) { if (length === lower + upper) {
sum -= length sum -= length;
} }
if (length === num) { if (length === num) {
sum -= num sum -= num;
} }
sum -= repC sum -= repC;
sum -= 2 * consecutive sum -= 2 * consecutive;
sum -= 3 * sequential sum -= 3 * sequential;
sum = sum < 0 ? 0 : sum sum = sum < 0 ? 0 : sum;
sum = sum > 100 ? 100 : sum sum = sum > 100 ? 100 : sum;
if (sum >= 80) { if (sum >= 80) {
return 100 return 100;
} else if (sum >= 60) { } else if (sum >= 60) {
return 80 return 80;
} else if (sum >= 40) { } else if (sum >= 40) {
return 60 return 60;
} else if (sum >= 20) { } else if (sum >= 20) {
return 40 return 40;
} else { } else {
return 20 return 20;
} }
} };
export const PasswordStrength: React.FC<IPasswordStrengthProps> = (props) => { export const PasswordStrength: React.FC<IPasswordStrengthProps> = (props) => {
if (isFn(props.children)) { if (isFn(props.children)) {
return props.children(getStrength(String(props.value))) return props.children(getStrength(String(props.value)));
} else { } else {
return <Fragment>{props.children}</Fragment> return <Fragment>{props.children}</Fragment>;
} }
} };

View File

@ -1,23 +1,29 @@
import React from 'react'; import React from 'react';
import { connect, mapProps, mapReadPretty, SchemaOptionsContext, useField } from '@formily/react' import {
import { Radio as AntdRadio, Tag } from 'antd' connect,
import { RadioProps, RadioGroupProps } from 'antd/lib/radio' mapProps,
mapReadPretty,
SchemaOptionsContext,
useField,
} from '@formily/react';
import { Radio as AntdRadio, Tag } from 'antd';
import { RadioProps, RadioGroupProps } from 'antd/lib/radio';
import { isValid } from '@formily/shared'; import { isValid } from '@formily/shared';
type ComposedRadio = React.FC<RadioProps> & { type ComposedRadio = React.FC<RadioProps> & {
Group?: React.FC<RadioGroupProps> Group?: React.FC<RadioGroupProps>;
__ANT_RADIO?: boolean __ANT_RADIO?: boolean;
} };
export const Radio: ComposedRadio = connect( export const Radio: ComposedRadio = connect(
AntdRadio, AntdRadio,
mapProps({ mapProps({
value: 'checked', value: 'checked',
onInput: 'onChange', onInput: 'onChange',
}) }),
) );
Radio.__ANT_RADIO = true Radio.__ANT_RADIO = true;
Radio.Group = connect( Radio.Group = connect(
AntdRadio.Group, AntdRadio.Group,
@ -31,17 +37,19 @@ Radio.Group = connect(
const { options = [], value } = props; const { options = [], value } = props;
const field = useField<any>(); const field = useField<any>();
const dataSource = field.dataSource || []; const dataSource = field.dataSource || [];
console.log({dataSource}) console.log({ dataSource });
return ( return (
<div> <div>
{dataSource {dataSource
.filter((option) => option.value === value) .filter((option) => option.value === value)
.map((option, key) => ( .map((option, key) => (
<Tag key={key} color={option.color}>{option.label}</Tag> <Tag key={key} color={option.color}>
{option.label}
</Tag>
))} ))}
</div> </div>
); );
}), }),
) );
export default Radio export default Radio;

View File

@ -25,7 +25,11 @@ import { BlockSchemaContext, VisibleContext } from '../../context';
import { SchemaRenderer } from '../../components/schema-renderer'; import { SchemaRenderer } from '../../components/schema-renderer';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { CollectionFieldContext } from '../table'; import { CollectionFieldContext } from '../table';
import { CollectionProvider, useCollectionContext, useResourceRequest } from '../../constate'; import {
CollectionProvider,
useCollectionContext,
useResourceRequest,
} from '../../constate';
import { Resource } from '../../resource'; import { Resource } from '../../resource';
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import constate from 'constate'; import constate from 'constate';
@ -267,11 +271,13 @@ Select.useSelect = () => {
export const useSelectedRowKeys = () => { export const useSelectedRowKeys = () => {
const { selectedRows } = useContext(SelectedRowsContext); const { selectedRows } = useContext(SelectedRowsContext);
const [selectedRowKeys, setSelectedRowKeys] = useState<any>(selectedRows.map((row) => row.id)); const [selectedRowKeys, setSelectedRowKeys] = useState<any>(
selectedRows.map((row) => row.id),
);
useEffect(() => { useEffect(() => {
setSelectedRowKeys(selectedRows.map((row) => row.id)); setSelectedRowKeys(selectedRows.map((row) => row.id));
}, [selectedRows]); }, [selectedRows]);
console.log('useSelectedRowKeys', selectedRows) console.log('useSelectedRowKeys', selectedRows);
return { selectedRowKeys, setSelectedRowKeys }; return { selectedRowKeys, setSelectedRowKeys };
}; };
@ -322,7 +328,7 @@ Select.Drawer = connect(
}; };
} }
const [selectedRows, setSelectedRows] = useState(toArr(field.value)); const [selectedRows, setSelectedRows] = useState(toArr(field.value));
console.log('useSelectedRowKeys.toArr', toArr(field.value)) console.log('useSelectedRowKeys.toArr', toArr(field.value));
useEffect(() => { useEffect(() => {
setSelectedRows(toArr(field.value)); setSelectedRows(toArr(field.value));
}, [field.value]); }, [field.value]);

View File

@ -11,11 +11,7 @@ import { cloneDeep, cloneDeepWith, findIndex, forIn, range, set } from 'lodash';
import React, { Fragment, useEffect, useState } from 'react'; import React, { Fragment, useEffect, useState } from 'react';
import { useContext } from 'react'; import { useContext } from 'react';
import { createContext } from 'react'; import { createContext } from 'react';
import { import { useDesignable, createCollectionField, ISchema } from '..';
useDesignable,
createCollectionField,
ISchema,
} from '..';
import { uid, merge } from '@formily/shared'; import { uid, merge } from '@formily/shared';
import useRequest from '@ahooksjs/use-request'; import useRequest from '@ahooksjs/use-request';
import { BaseResult } from '@ahooksjs/use-request/lib/types'; import { BaseResult } from '@ahooksjs/use-request/lib/types';
@ -279,7 +275,7 @@ const useTableIndex = () => {
const { pagination, props } = useTable(); const { pagination, props } = useTable();
const ctx = useContext(TableRowContext); const ctx = useContext(TableRowContext);
const { pageSize, page = 1 } = pagination; const { pageSize, page = 1 } = pagination;
console.log({pageSize, page}, ctx.index); console.log({ pageSize, page }, ctx.index);
return ctx.index + (page - 1) * pageSize; return ctx.index + (page - 1) * pageSize;
if (pagination && !props.clientSidePagination) { if (pagination && !props.clientSidePagination) {
const { pageSize, page = 1 } = pagination; const { pageSize, page = 1 } = pagination;

View File

@ -186,13 +186,14 @@ td.nb-table-operation {
.ant-formily-item-feedback-layout-popover { .ant-formily-item-feedback-layout-popover {
margin-bottom: 0; margin-bottom: 0;
} }
.ant-formily-item-control .ant-formily-item-control-content .ant-formily-item-control-content-component { .ant-formily-item-control
.ant-formily-item-control-content
.ant-formily-item-control-content-component {
min-height: inherit; min-height: inherit;
line-height: inherit; line-height: inherit;
} }
} }
.ant-dropdown-menu-item { .ant-dropdown-menu-item {
&:hover { &:hover {
.designable-bar { .designable-bar {
@ -238,7 +239,6 @@ td.nb-table-operation {
justify-content: space-between; justify-content: space-between;
} }
.field-interface-attachment { .field-interface-attachment {
margin-top: -13px; margin-top: -13px;
margin-bottom: -13px; margin-bottom: -13px;
@ -253,7 +253,7 @@ td.nb-table-operation {
height: 100%; height: 100%;
width: 100%; width: 100%;
background-color: #f18b62; background-color: #f18b62;
opacity: .3; opacity: 0.3;
} }
&.droppable:not(.isDragging).isOver::after { &.droppable:not(.isDragging).isOver::after {
content: ''; content: '';
@ -278,7 +278,7 @@ td.nb-table-operation {
height: 100%; height: 100%;
width: 100%; width: 100%;
background-color: #f18b62; background-color: #f18b62;
opacity: .3; opacity: 0.3;
} }
.droppable:not(.isDragging).isOver::after { .droppable:not(.isDragging).isOver::after {
content: ''; content: '';
@ -289,4 +289,4 @@ td.nb-table-operation {
width: 2px; width: 2px;
background-color: #f18b62; background-color: #f18b62;
} }
} }

View File

@ -39,7 +39,6 @@
} }
} }
.ant-tabs-tab:first-child { .ant-tabs-tab:first-child {
.nb-tab-pane { .nb-tab-pane {
.designable-bar { .designable-bar {
@ -91,7 +90,7 @@
height: 100%; height: 100%;
left: -16px; left: -16px;
background-color: #f18b62; background-color: #f18b62;
opacity: .3; opacity: 0.3;
} }
.droppable:not(.isDragging).isOver::after { .droppable:not(.isDragging).isOver::after {
content: ''; content: '';
@ -102,4 +101,4 @@
width: 2px; width: 2px;
background-color: #f18b62; background-color: #f18b62;
} }
} }

View File

@ -1,44 +1,44 @@
import moment from 'moment' import moment from 'moment';
import { connect, mapProps, mapReadPretty } from '@formily/react' import { connect, mapProps, mapReadPretty } from '@formily/react';
import { TimePicker as AntdTimePicker } from 'antd' import { TimePicker as AntdTimePicker } from 'antd';
import { import {
TimePickerProps as AntdTimePickerProps, TimePickerProps as AntdTimePickerProps,
TimeRangePickerProps, TimeRangePickerProps,
} from 'antd/lib/time-picker' } from 'antd/lib/time-picker';
import { Display } from '../display' import { Display } from '../display';
import { formatMomentValue, momentable } from '@formily/antd/esm/__builtins__' import { formatMomentValue, momentable } from '@formily/antd/esm/__builtins__';
type ComposedTimePicker = React.FC<AntdTimePickerProps> & { type ComposedTimePicker = React.FC<AntdTimePickerProps> & {
RangePicker?: React.FC<TimeRangePickerProps> RangePicker?: React.FC<TimeRangePickerProps>;
} };
const mapTimeFormat = function () { const mapTimeFormat = function () {
return (props: any) => { return (props: any) => {
const format = props['format'] || 'HH:mm:ss' const format = props['format'] || 'HH:mm:ss';
const onChange = props.onChange const onChange = props.onChange;
return { return {
...props, ...props,
format, format,
value: momentable(props.value, format), value: momentable(props.value, format),
onChange: (value: moment.Moment | moment.Moment[]) => { onChange: (value: moment.Moment | moment.Moment[]) => {
if (onChange) { if (onChange) {
onChange(formatMomentValue(value, format)) onChange(formatMomentValue(value, format));
} }
}, },
} };
} };
} };
export const TimePicker: ComposedTimePicker = connect( export const TimePicker: ComposedTimePicker = connect(
AntdTimePicker, AntdTimePicker,
mapProps(mapTimeFormat()), mapProps(mapTimeFormat()),
mapReadPretty(Display.TimePicker) mapReadPretty(Display.TimePicker),
) );
TimePicker.RangePicker = connect( TimePicker.RangePicker = connect(
AntdTimePicker.RangePicker, AntdTimePicker.RangePicker,
mapProps(mapTimeFormat()), mapProps(mapTimeFormat()),
mapReadPretty(Display.TimeRangePicker) mapReadPretty(Display.TimeRangePicker),
) );
export default TimePicker export default TimePicker;

View File

@ -1,8 +1,8 @@
import React from 'react' import React from 'react';
import { connect, mapReadPretty, mapProps } from '@formily/react' import { connect, mapReadPretty, mapProps } from '@formily/react';
import { TreeSelect as AntdTreeSelect } from 'antd' import { TreeSelect as AntdTreeSelect } from 'antd';
import { Display } from '../display' import { Display } from '../display';
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons';
export const TreeSelect = connect( export const TreeSelect = connect(
AntdTreeSelect, AntdTreeSelect,
mapProps( mapProps(
@ -18,10 +18,10 @@ export const TreeSelect = connect(
) : ( ) : (
props.suffixIcon props.suffixIcon
), ),
} };
} },
), ),
mapReadPretty(Display.TreeSelect) mapReadPretty(Display.TreeSelect),
) );
export default TreeSelect export default TreeSelect;

View File

@ -49,7 +49,7 @@ const schema = {
value: '{{$self.value}}', value: '{{$self.value}}',
}, },
}, },
} },
], ],
}, },
read: { read: {

View File

@ -1,62 +1,62 @@
export const UPLOAD_PLACEHOLDER = [ export const UPLOAD_PLACEHOLDER = [
{ {
ext: /\.docx?$/i, ext: /\.docx?$/i,
icon: '//img.alicdn.com/tfs/TB1n8jfr1uSBuNjy1XcXXcYjFXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1n8jfr1uSBuNjy1XcXXcYjFXa-200-200.png',
}, },
{ {
ext: /\.pptx?$/i, ext: /\.pptx?$/i,
icon: '//img.alicdn.com/tfs/TB1ItgWr_tYBeNjy1XdXXXXyVXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1ItgWr_tYBeNjy1XdXXXXyVXa-200-200.png',
}, },
{ {
ext: /\.jpe?g$/i, ext: /\.jpe?g$/i,
icon: '//img.alicdn.com/tfs/TB1wrT5r9BYBeNjy0FeXXbnmFXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1wrT5r9BYBeNjy0FeXXbnmFXa-200-200.png',
}, },
{ {
ext: /\.pdf$/i, ext: /\.pdf$/i,
icon: '//img.alicdn.com/tfs/TB1GwD8r9BYBeNjy0FeXXbnmFXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1GwD8r9BYBeNjy0FeXXbnmFXa-200-200.png',
}, },
{ {
ext: /\.png$/i, ext: /\.png$/i,
icon: '//img.alicdn.com/tfs/TB1BHT5r9BYBeNjy0FeXXbnmFXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1BHT5r9BYBeNjy0FeXXbnmFXa-200-200.png',
}, },
{ {
ext: /\.eps$/i, ext: /\.eps$/i,
icon: '//img.alicdn.com/tfs/TB1G_iGrVOWBuNjy0FiXXXFxVXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1G_iGrVOWBuNjy0FiXXXFxVXa-200-200.png',
}, },
{ {
ext: /\.ai$/i, ext: /\.ai$/i,
icon: '//img.alicdn.com/tfs/TB1B2cVr_tYBeNjy1XdXXXXyVXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1B2cVr_tYBeNjy1XdXXXXyVXa-200-200.png',
}, },
{ {
ext: /\.gif$/i, ext: /\.gif$/i,
icon: '//img.alicdn.com/tfs/TB1DTiGrVOWBuNjy0FiXXXFxVXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1DTiGrVOWBuNjy0FiXXXFxVXa-200-200.png',
}, },
{ {
ext: /\.svg$/i, ext: /\.svg$/i,
icon: '//img.alicdn.com/tfs/TB1uUm9rY9YBuNjy0FgXXcxcXXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1uUm9rY9YBuNjy0FgXXcxcXXa-200-200.png',
}, },
{ {
ext: /\.xlsx?$/i, ext: /\.xlsx?$/i,
icon: '//img.alicdn.com/tfs/TB1any1r1OSBuNjy0FdXXbDnVXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1any1r1OSBuNjy0FdXXbDnVXa-200-200.png',
}, },
{ {
ext: /\.psd?$/i, ext: /\.psd?$/i,
icon: '//img.alicdn.com/tfs/TB1_nu1r1OSBuNjy0FdXXbDnVXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1_nu1r1OSBuNjy0FdXXbDnVXa-200-200.png',
}, },
{ {
ext: /\.(wav|aif|aiff|au|mp1|mp2|mp3|ra|rm|ram|mid|rmi)$/i, ext: /\.(wav|aif|aiff|au|mp1|mp2|mp3|ra|rm|ram|mid|rmi)$/i,
icon: '//img.alicdn.com/tfs/TB1jPvwr49YBuNjy0FfXXXIsVXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1jPvwr49YBuNjy0FfXXXIsVXa-200-200.png',
}, },
{ {
ext: /\.(avi|wmv|mpg|mpeg|vob|dat|3gp|mp4|mkv|rm|rmvb|mov|flv)$/i, ext: /\.(avi|wmv|mpg|mpeg|vob|dat|3gp|mp4|mkv|rm|rmvb|mov|flv)$/i,
icon: '//img.alicdn.com/tfs/TB1FrT5r9BYBeNjy0FeXXbnmFXa-200-200.png' icon: '//img.alicdn.com/tfs/TB1FrT5r9BYBeNjy0FeXXbnmFXa-200-200.png',
}, },
{ {
ext: /\.(zip|rar|arj|z|gz|iso|jar|ace|tar|uue|dmg|pkg|lzh|cab)$/i, ext: /\.(zip|rar|arj|z|gz|iso|jar|ace|tar|uue|dmg|pkg|lzh|cab)$/i,
icon: '//img.alicdn.com/tfs/TB10jmfr29TBuNjy0FcXXbeiFXa-200-200.png' icon: '//img.alicdn.com/tfs/TB10jmfr29TBuNjy0FcXXbeiFXa-200-200.png',
}, },
{ {
ext: /\.[^.]+$/i, ext: /\.[^.]+$/i,
icon: '//img.alicdn.com/tfs/TB10.R4r3mTBuNjy1XbXXaMrVXa-200-200.png' icon: '//img.alicdn.com/tfs/TB10.R4r3mTBuNjy1XbXXaMrVXa-200-200.png',
} },
] ];

View File

@ -28,7 +28,9 @@
font-size: 13px; font-size: 13px;
color: #636363; color: #636363;
} }
.ant-upload-list-picture-card .ant-upload-list-item:hover .ant-upload-list-item-info::before { .ant-upload-list-picture-card
.ant-upload-list-item:hover
.ant-upload-list-item-info::before {
display: none; display: none;
} }
.ant-upload-list-picture-card .ant-upload-list-item-progress { .ant-upload-list-picture-card .ant-upload-list-item-progress {
@ -36,7 +38,7 @@
pointer-events: none; pointer-events: none;
} }
.ant-btn { .ant-btn {
background: rgba(0,0,0,.5); background: rgba(0, 0, 0, 0.5);
// .anticon { // .anticon {
// color: #1890ff; // color: #1890ff;
// } // }
@ -55,7 +57,8 @@
.ant-upload-list-picture-card .ant-upload-list-item-name { .ant-upload-list-picture-card .ant-upload-list-item-name {
display: none; display: none;
} }
.ant-upload-list-picture .ant-upload-list-item, .ant-upload-list-picture-card .ant-upload-list-item { .ant-upload-list-picture .ant-upload-list-item,
.ant-upload-list-picture-card .ant-upload-list-item {
padding: 1px; padding: 1px;
} }
} }

View File

@ -96,7 +96,7 @@ describe('user fields', () => {
target: 'users', target: 'users',
foreignKey: 'updated_by_id', foreignKey: 'updated_by_id',
}, },
] ],
}); });
await db.sync(); await db.sync();
@ -106,14 +106,19 @@ describe('user fields', () => {
// 用户1 操作 // 用户1 操作
const user1 = await User.create(); const user1 = await User.create();
const postWithUser = await Post.create({}, { context: { state: { currentUser: user1 } } }); const postWithUser = await Post.create(
{},
{ context: { state: { currentUser: user1 } } },
);
const post = await Post.findOne(Post.parseApiJson({ const post = await Post.findOne(
filter: { Post.parseApiJson({
id: postWithUser.id, filter: {
}, id: postWithUser.id,
fields: ['createdBy1', 'updatedBy1', 'createdBy2', 'updatedBy2'], },
})); fields: ['createdBy1', 'updatedBy1', 'createdBy2', 'updatedBy2'],
}),
);
expect(post.createdBy1.id).toBe(user1.id); expect(post.createdBy1.id).toBe(user1.id);
expect(post.updatedBy1.id).toBe(user1.id); expect(post.updatedBy1.id).toBe(user1.id);
@ -122,14 +127,19 @@ describe('user fields', () => {
// 换个用户 // 换个用户
const user2 = await User.create(); const user2 = await User.create();
await postWithUser.update({ title: 'title1' }, { context: { state: { currentUser: user2 } } }); await postWithUser.update(
{ title: 'title1' },
{ context: { state: { currentUser: user2 } } },
);
const post2 = await Post.findOne(Post.parseApiJson({ const post2 = await Post.findOne(
filter: { Post.parseApiJson({
id: postWithUser.id, filter: {
}, id: postWithUser.id,
fields: ['createdBy1', 'updatedBy1', 'createdBy2', 'updatedBy2'], },
})); fields: ['createdBy1', 'updatedBy1', 'createdBy2', 'updatedBy2'],
}),
);
expect(post2.createdBy1.id).toBe(user1.id); expect(post2.createdBy1.id).toBe(user1.id);
expect(post2.createdBy2.id).toBe(user1.id); expect(post2.createdBy2.id).toBe(user1.id);
@ -151,13 +161,19 @@ describe('user fields', () => {
expect(postWithoutUser.created_by_id).toBe(null); expect(postWithoutUser.created_by_id).toBe(null);
expect(postWithoutUser.updated_by_id).toBe(null); expect(postWithoutUser.updated_by_id).toBe(null);
// @ts-ignore // @ts-ignore
const postWithUser = await Post.create({}, { context: { state: { currentUser } } }); const postWithUser = await Post.create(
{},
{ context: { state: { currentUser } } },
);
expect(postWithUser.created_by_id).toBe(currentUser.id); expect(postWithUser.created_by_id).toBe(currentUser.id);
expect(postWithUser.updated_by_id).toBe(currentUser.id); expect(postWithUser.updated_by_id).toBe(currentUser.id);
// 更新数据 createdBy 数据不变 // 更新数据 createdBy 数据不变
// @ts-ignore // @ts-ignore
await postWithUser.update({ title: 'title1' }, { context: { state: { currentUser: user2 } } }); await postWithUser.update(
{ title: 'title1' },
{ context: { state: { currentUser: user2 } } },
);
expect(postWithUser.created_by_id).toBe(currentUser.id); expect(postWithUser.created_by_id).toBe(currentUser.id);
expect(postWithUser.updated_by_id).toBe(user2.id); expect(postWithUser.updated_by_id).toBe(user2.id);
}); });
@ -170,11 +186,14 @@ describe('user fields', () => {
const user2 = await User.create(); const user2 = await User.create();
const Post = db.getModel('posts'); const Post = db.getModel('posts');
const post = await Post.create({ const post = await Post.create(
created_by_id: user1.id, {
updated_by_id: user1.id, created_by_id: user1.id,
// @ts-ignore updated_by_id: user1.id,
}, { context: { state: { currentUser: user2 } } }); // @ts-ignore
},
{ context: { state: { currentUser: user2 } } },
);
expect(post.created_by_id).toBe(user1.id); expect(post.created_by_id).toBe(user1.id);
expect(post.updated_by_id).toBe(user1.id); expect(post.updated_by_id).toBe(user1.id);
}); });
@ -189,9 +208,9 @@ describe('user fields', () => {
fields: [ fields: [
{ {
type: 'string', type: 'string',
name: 'title' name: 'title',
} },
] ],
}); });
await db.sync(); await db.sync();
const User = db.getModel('users'); const User = db.getModel('users');
@ -201,7 +220,10 @@ describe('user fields', () => {
const post = await Post.create(); const post = await Post.create();
expect(post.updated_by_id).toBe(null); expect(post.updated_by_id).toBe(null);
// @ts-ignore // @ts-ignore
await post.update({ title: 'title' }, { context: { state: { currentUser } } }) await post.update(
{ title: 'title' },
{ context: { state: { currentUser } } },
);
expect(post.updated_by_id).toBe(currentUser.id); expect(post.updated_by_id).toBe(currentUser.id);
}); });
@ -212,9 +234,9 @@ describe('user fields', () => {
fields: [ fields: [
{ {
type: 'string', type: 'string',
name: 'title' name: 'title',
} },
] ],
}); });
await db.sync(); await db.sync();
const User = db.getModel('users'); const User = db.getModel('users');
@ -223,15 +245,21 @@ describe('user fields', () => {
const Post = db.getModel('posts'); const Post = db.getModel('posts');
let context = { state: { currentUser: user2 } }; let context = { state: { currentUser: user2 } };
const post = await Post.create({ const post = await Post.create(
updated_by_id: user1.id, {
}, { context }); updated_by_id: user1.id,
},
{ context },
);
expect(post.updated_by_id).toBe(user1.id); expect(post.updated_by_id).toBe(user1.id);
await post.update({ title: 'title' }, { context }); await post.update({ title: 'title' }, { context });
expect(post.updated_by_id).toBe(user2.id); expect(post.updated_by_id).toBe(user2.id);
await post.update({ title: 'title', updated_by_id: user1.id }, { context }); await post.update(
{ title: 'title', updated_by_id: user1.id },
{ context },
);
expect(post.updated_by_id).toBe(user1.id); expect(post.updated_by_id).toBe(user1.id);
// 不同用户更新数据 // 不同用户更新数据
@ -252,9 +280,9 @@ describe('user fields', () => {
fields: [ fields: [
{ {
type: 'string', type: 'string',
name: 'title' name: 'title',
} },
] ],
}); });
await db.sync(); await db.sync();
const User = db.getModel('users'); const User = db.getModel('users');
@ -263,18 +291,20 @@ describe('user fields', () => {
const Post = db.getModel('posts'); const Post = db.getModel('posts');
let context = { state: { currentUser: user2 } }; let context = { state: { currentUser: user2 } };
await Post.bulkCreate([ await Post.bulkCreate([{ title: 'title1' }, { title: 'title2' }]);
{ title: 'title1' },
{ title: 'title2' },
]);
await Post.update({ title: 'title3' }, { await Post.update(
where: { title: 'title1' }, { title: 'title3' },
context {
}); where: { title: 'title1' },
context,
},
);
const posts = await Post.findAll({ order: [['id', 'ASC']] }); const posts = await Post.findAll({ order: [['id', 'ASC']] });
expect(posts.map(({ title, updated_by_id }) => ({ title, updated_by_id }))).toEqual([ expect(
posts.map(({ title, updated_by_id }) => ({ title, updated_by_id })),
).toEqual([
{ title: 'title3', updated_by_id: 2 }, { title: 'title3', updated_by_id: 2 },
{ title: 'title2', updated_by_id: null }, { title: 'title2', updated_by_id: null },
]); ]);

View File

@ -62,7 +62,9 @@ export async function register(ctx: Context, next: Next) {
} }
export async function lostpassword(ctx: Context, next: Next) { export async function lostpassword(ctx: Context, next: Next) {
const { values: { email } } = ctx.action.params; const {
values: { email },
} = ctx.action.params;
if (!email) { if (!email) {
ctx.throw(401, '请填写邮箱账号'); ctx.throw(401, '请填写邮箱账号');
} }
@ -82,7 +84,9 @@ export async function lostpassword(ctx: Context, next: Next) {
} }
export async function resetpassword(ctx: Context, next: Next) { export async function resetpassword(ctx: Context, next: Next) {
const { values: { email, password, reset_token } } = ctx.action.params; const {
values: { email, password, reset_token },
} = ctx.action.params;
const User = ctx.db.getModel('users'); const User = ctx.db.getModel('users');
const user = await User.findOne({ const user = await User.findOne({
where: { where: {

View File

@ -2,13 +2,12 @@ import { BelongsToOptions, BELONGSTO, FieldContext } from '@nocobase/database';
import { setUserValue } from './utils'; import { setUserValue } from './utils';
export interface CreatedByOptions extends Omit<BelongsToOptions, 'type'> { export interface CreatedByOptions extends Omit<BelongsToOptions, 'type'> {
type: 'createdBy' | 'createdby' type: 'createdBy' | 'createdby';
} }
export default class CreatedBy extends BELONGSTO { export default class CreatedBy extends BELONGSTO {
static beforeBulkCreateHook(this: CreatedBy, models, { context }) { static beforeBulkCreateHook(this: CreatedBy, models, { context }) {
models.forEach(model => { models.forEach((model) => {
setUserValue.call(this, model, { context }); setUserValue.call(this, model, { context });
}); });
} }
@ -22,7 +21,10 @@ export default class CreatedBy extends BELONGSTO {
const { sourceTable, database } = context; const { sourceTable, database } = context;
const name = sourceTable.getName(); const name = sourceTable.getName();
database.on(`${name}.beforeCreate`, setUserValue.bind(this)); database.on(`${name}.beforeCreate`, setUserValue.bind(this));
database.on(`${name}.beforeBulkCreate`, CreatedBy.beforeBulkCreateHook.bind(this)); database.on(
`${name}.beforeBulkCreate`,
CreatedBy.beforeBulkCreateHook.bind(this),
);
} }
public getDataType(): Function { public getDataType(): Function {

View File

@ -2,18 +2,20 @@ import { BelongsToOptions, BELONGSTO, FieldContext } from '@nocobase/database';
import { setUserValue } from './utils'; import { setUserValue } from './utils';
export interface UpdatedByOptions extends Omit<BelongsToOptions, 'type'> { export interface UpdatedByOptions extends Omit<BelongsToOptions, 'type'> {
type: 'updatedBy' | 'updatedby' type: 'updatedBy' | 'updatedby';
} }
export default class UpdatedBy extends BELONGSTO { export default class UpdatedBy extends BELONGSTO {
static beforeBulkCreateHook(this: UpdatedBy, models, { context }) { static beforeBulkCreateHook(this: UpdatedBy, models, { context }) {
models.forEach(model => { models.forEach((model) => {
setUserValue.call(this, model, { context }); setUserValue.call(this, model, { context });
}); });
} }
static beforeBulkUpdateHook(this: UpdatedBy, { attributes, fields, context }) { static beforeBulkUpdateHook(
this: UpdatedBy,
{ attributes, fields, context },
) {
if (!context) { if (!context) {
return; return;
} }
@ -22,7 +24,9 @@ export default class UpdatedBy extends BELONGSTO {
return; return;
} }
fields.push(this.options.foreignKey); fields.push(this.options.foreignKey);
attributes[this.options.foreignKey] = currentUser.get(this.options.targetKey); attributes[this.options.foreignKey] = currentUser.get(
this.options.targetKey,
);
} }
constructor({ type, ...options }: UpdatedByOptions, context: FieldContext) { constructor({ type, ...options }: UpdatedByOptions, context: FieldContext) {
@ -36,9 +40,15 @@ export default class UpdatedBy extends BELONGSTO {
const { sourceTable, database } = context; const { sourceTable, database } = context;
const name = sourceTable.getName(); const name = sourceTable.getName();
database.on(`${name}.beforeCreate`, setUserValue.bind(this)); database.on(`${name}.beforeCreate`, setUserValue.bind(this));
database.on(`${name}.beforeBulkCreate`, UpdatedBy.beforeBulkCreateHook.bind(this)); database.on(
`${name}.beforeBulkCreate`,
UpdatedBy.beforeBulkCreateHook.bind(this),
);
database.on(`${name}.beforeUpdate`, setUserValue.bind(this)); database.on(`${name}.beforeUpdate`, setUserValue.bind(this));
database.on(`${name}.beforeBulkUpdate`, UpdatedBy.beforeBulkUpdateHook.bind(this)); database.on(
`${name}.beforeBulkUpdate`,
UpdatedBy.beforeBulkUpdateHook.bind(this),
);
} }
public getDataType(): Function { public getDataType(): Function {

View File

@ -1,4 +1,4 @@
import { CreatedBy, UpdatedBy } from "."; import { CreatedBy, UpdatedBy } from '.';
export function setUserValue(this: CreatedBy | UpdatedBy, model, { context }) { export function setUserValue(this: CreatedBy | UpdatedBy, model, { context }) {
const { foreignKey } = this.options; const { foreignKey } = this.options;
@ -8,7 +8,7 @@ export function setUserValue(this: CreatedBy | UpdatedBy, model, { context }) {
return; return;
} }
const changed = model.changed(); const changed = model.changed();
if (Array.isArray(changed) && changed.find(key => key === foreignKey)) { if (Array.isArray(changed) && changed.find((key) => key === foreignKey)) {
return; return;
} }
} }