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 {
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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,7 +36,7 @@ import {
} from '../../constate';
import { uid } from '@formily/shared';
import { Permissions } from './Permissions';
import { Collections } from './Collections'
import { Collections } from './Collections';
import { More } from './More';
import { UserInfo } from './UserInfo';
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[] => {
if (!schema) {
@ -232,12 +232,11 @@ export function AdminLayout({ route, ...others }: any) {
}, []);
};
if (loading) {
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) {
return <Redirect to={`/admin/${f?.['key']}`} />;

View File

@ -75,7 +75,8 @@
.user-info {
height: 46px;
color: #fff;
&:hover, &:focus {
&:hover,
&:focus {
color: #fff;
}
}
@ -95,7 +96,8 @@
}
.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);
}
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover {
@ -105,7 +107,7 @@
color: rgba(255, 255, 255, 0.65) !important;
&.nb-designable-toggle:hover {
color: #fff !important;
background-color: #F18B62 !important
background-color: #f18b62 !important;
}
}
.ant-btn:hover {

View File

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

View File

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

View File

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

View File

@ -1,12 +1,14 @@
import { useRequest } from 'ahooks';
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,
});
return {
...result, collections: result.data || [],
...result,
collections: result.data || [],
findCollection(name) {
return result?.data?.find((item) => item.name === name);
},
@ -17,11 +19,14 @@ const [CollectionsProvider, useCollectionsContext] = constate<any, any, any>(()
}));
},
getFieldsByCollection(collectionName) {
const collection = result?.data?.find((item) => item.name === collectionName);
const collection = result?.data?.find(
(item) => item.name === collectionName,
);
return collection?.generalFields;
},
};
});
},
);
export { CollectionsProvider, useCollectionsContext };

View File

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

View File

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

View File

@ -1,9 +1,7 @@
import { useRequest } from 'ahooks';
import { Spin } from 'antd';
import React, { useMemo } from 'react';
import {
MemoryRouter as Router,
} from 'react-router-dom';
import { MemoryRouter as Router } from 'react-router-dom';
import {
createRouteSwitch,
RouteRedirectProps,
@ -11,7 +9,7 @@ import {
AuthLayout,
RouteSchemaRenderer,
ConfigProvider,
ClientSDK
ClientSDK,
} from '../';
import { UseRequestProvider } from 'ahooks';
import { extend } from 'umi-request';
@ -53,7 +51,7 @@ const App = () => {
});
if (loading) {
return <Spin size={'large'} className={'nb-spin-center'} />
return <Spin size={'large'} className={'nb-spin-center'} />;
}
return (
@ -71,4 +69,4 @@ export default () => {
<App />
</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 {
public options: ResourceOptions;
public request: RequestMethod;
constructor(options: string | ResourceOptions, request?: any) {
if (typeof options === 'string') {
this.options = { resourceName: options }
this.options = { resourceName: options };
} else {
this.options = options;
}
@ -54,7 +53,14 @@ export class Resource {
}
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;
let url = `${resourceName}:list`;
if (associatedName && associatedKey) {
@ -63,7 +69,9 @@ export class Resource {
return this.request(url, {
method: 'get',
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(','),
perPage: pageSize,
...others,
@ -90,7 +98,7 @@ export class Resource {
const { associatedKey, associatedName, resourceName } = this.options;
let url = `${resourceName}:create`;
if (associatedKey && associatedName) {
url = `${associatedName}/${associatedKey}/${url}`
url = `${associatedName}/${associatedKey}/${url}`;
}
return this.request(url, {
method: 'post',
@ -101,9 +109,11 @@ export class Resource {
save(values: any, options: SaveOptions = {}) {
const resourceKey = options.resourceKey || this.options.resourceKey;
const { associatedKey, associatedName, resourceName } = this.options;
let url = `${resourceName}:${resourceKey ? `update/${resourceKey}` : 'create'}`;
let url = `${resourceName}:${
resourceKey ? `update/${resourceKey}` : 'create'
}`;
if (associatedKey && associatedName) {
url = `${associatedName}/${associatedKey}/${url}`
url = `${associatedName}/${associatedKey}/${url}`;
}
return this.request(url, {
method: 'post',
@ -122,9 +132,13 @@ export class Resource {
...others,
},
parseResponse: false,
responseType: 'blob'
responseType: 'blob',
}).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
let res = new Response(response.body);
let blob = await res.blob();
@ -151,7 +165,7 @@ export class Resource {
return this.request(url, {
method: 'get',
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') {
return new this({ resourceName: options }, request);
}

View File

@ -74,14 +74,13 @@
}
&[disabled] {
color: #00000040;
background-color:#fff;
cursor:not-allowed;
background-color: #fff;
cursor: not-allowed;
}
}
}
}
.designable-bar-actions {
.ant-btn {
border: 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -128,6 +128,10 @@ const loadChinaRegionData = (
export default () => {
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;
};
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 containerRef = useRef(undefined);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,66 +1,72 @@
import moment from 'moment'
import { connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react'
import { DatePicker as AntdDatePicker } from 'antd'
import moment from 'moment';
import {
connect,
mapProps,
mapReadPretty,
useField,
useFieldSchema,
} from '@formily/react';
import { DatePicker as AntdDatePicker } from 'antd';
import {
DatePickerProps as AntdDatePickerProps,
RangePickerProps,
} from 'antd/lib/date-picker'
import { Display } from '../display'
import { formatMomentValue, momentable } from '@formily/antd/esm/__builtins__'
} from 'antd/lib/date-picker';
import { Display } from '../display';
import { formatMomentValue, momentable } from '@formily/antd/esm/__builtins__';
type DatePickerProps<PickerProps> = Exclude<
PickerProps,
'value' | 'onChange'
> & {
value: string
onChange: (value: string | string[]) => void
}
value: string;
onChange: (value: string | string[]) => void;
};
type ComposedDatePicker = React.FC<AntdDatePickerProps> & {
RangePicker?: React.FC<RangePickerProps>
}
RangePicker?: React.FC<RangePickerProps>;
};
const mapDateFormat = function () {
const getDefaultFormat = (props: DatePickerProps<AntdDatePickerProps>) => {
if (props['picker'] === 'month') {
return 'YYYY-MM'
return 'YYYY-MM';
} else if (props['picker'] === 'quarter') {
return 'YYYY-\\QQ'
return 'YYYY-\\QQ';
} else if (props['picker'] === 'year') {
return 'YYYY'
return 'YYYY';
} else if (props['picker'] === 'week') {
return 'YYYY-wo'
}
return props['showTime'] ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'
return 'YYYY-wo';
}
return props['showTime'] ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD';
};
return (props: any) => {
const field = useField();
const fieldSchema = useFieldSchema();
const format = props['format'] || getDefaultFormat(props)
const onChange = props.onChange
const format = props['format'] || getDefaultFormat(props);
const onChange = props.onChange;
return {
...props,
format: format,
value: momentable(props.value, format === 'YYYY-wo' ? 'YYYY-w' : format),
onChange: (value: moment.Moment | moment.Moment[]) => {
if (onChange) {
onChange(formatMomentValue(value, format))
onChange(formatMomentValue(value, format));
}
},
}
}
}
};
};
};
export const DatePicker: ComposedDatePicker = connect(
AntdDatePicker,
mapProps(mapDateFormat()),
mapReadPretty(Display.DatePicker)
)
mapReadPretty(Display.DatePicker),
);
DatePicker.RangePicker = connect(
AntdDatePicker.RangePicker,
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 { observer, useFieldSchema } from '@formily/react';
import {
DragDropManagerProvider,
} from './../../components/drag-and-drop';
import { DragDropManagerProvider } from './../../components/drag-and-drop';
export const DragAndDrop = observer((props) => {
const schema = useFieldSchema();
console.log('DragAndDrop')
console.log('DragAndDrop');
return (
<DragDropManagerProvider uid={schema.name}>
<div className={'nb-dnd'}>{props.children}</div>
</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 (
<FormProvider form={form}>

View File

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

View File

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

View File

@ -1,10 +1,15 @@
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 './designable-bar/style.less';
export type FormilyISchema = IFormilySchema
export type FormilyISchema = IFormilySchema;
export interface ISchema extends IFormilySchema {
[key: string]: any;

View File

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

View File

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

View File

@ -208,5 +208,11 @@ const schema: ISchema = {
};
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 cls from 'classnames';
import './style.less';
import { CollectionProvider, useCollectionContext, useResourceRequest } from '../../constate';
import {
CollectionProvider,
useCollectionContext,
useResourceRequest,
} from '../../constate';
import { Resource } from '../../resource';
import { useRequest } from 'ahooks';
import { Action } from '../action';

View File

@ -26,7 +26,7 @@
.nb-kanban-item {
margin-bottom: 12px;
&.isDragging {
opacity: .2;
opacity: 0.2;
}
.ant-formily-item-control-content-component {
@ -51,7 +51,8 @@
.nb-kanban-drag-overlay {
.isDragging {
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 {
display: none !important;
@ -69,7 +70,8 @@
}
}
}
.nb-grid-block, .ant-formily-item {
.nb-grid-block,
.ant-formily-item {
margin-bottom: 12px !important;
}
@ -132,7 +134,8 @@
.ant-upload-list-picture-card .ant-upload-list-item-name {
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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,23 +1,29 @@
import React from 'react';
import { connect, mapProps, mapReadPretty, SchemaOptionsContext, useField } from '@formily/react'
import { Radio as AntdRadio, Tag } from 'antd'
import { RadioProps, RadioGroupProps } from 'antd/lib/radio'
import {
connect,
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';
type ComposedRadio = React.FC<RadioProps> & {
Group?: React.FC<RadioGroupProps>
__ANT_RADIO?: boolean
}
Group?: React.FC<RadioGroupProps>;
__ANT_RADIO?: boolean;
};
export const Radio: ComposedRadio = connect(
AntdRadio,
mapProps({
value: 'checked',
onInput: 'onChange',
})
)
}),
);
Radio.__ANT_RADIO = true
Radio.__ANT_RADIO = true;
Radio.Group = connect(
AntdRadio.Group,
@ -31,17 +37,19 @@ Radio.Group = connect(
const { options = [], value } = props;
const field = useField<any>();
const dataSource = field.dataSource || [];
console.log({dataSource})
console.log({ dataSource });
return (
<div>
{dataSource
.filter((option) => option.value === value)
.map((option, key) => (
<Tag key={key} color={option.color}>{option.label}</Tag>
<Tag key={key} color={option.color}>
{option.label}
</Tag>
))}
</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 { uid } from '@formily/shared';
import { CollectionFieldContext } from '../table';
import { CollectionProvider, useCollectionContext, useResourceRequest } from '../../constate';
import {
CollectionProvider,
useCollectionContext,
useResourceRequest,
} from '../../constate';
import { Resource } from '../../resource';
import { useRequest } from 'ahooks';
import constate from 'constate';
@ -267,11 +271,13 @@ Select.useSelect = () => {
export const useSelectedRowKeys = () => {
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(() => {
setSelectedRowKeys(selectedRows.map((row) => row.id));
}, [selectedRows]);
console.log('useSelectedRowKeys', selectedRows)
console.log('useSelectedRowKeys', selectedRows);
return { selectedRowKeys, setSelectedRowKeys };
};
@ -322,7 +328,7 @@ Select.Drawer = connect(
};
}
const [selectedRows, setSelectedRows] = useState(toArr(field.value));
console.log('useSelectedRowKeys.toArr', toArr(field.value))
console.log('useSelectedRowKeys.toArr', toArr(field.value));
useEffect(() => {
setSelectedRows(toArr(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 { useContext } from 'react';
import { createContext } from 'react';
import {
useDesignable,
createCollectionField,
ISchema,
} from '..';
import { useDesignable, createCollectionField, ISchema } from '..';
import { uid, merge } from '@formily/shared';
import useRequest from '@ahooksjs/use-request';
import { BaseResult } from '@ahooksjs/use-request/lib/types';
@ -279,7 +275,7 @@ const useTableIndex = () => {
const { pagination, props } = useTable();
const ctx = useContext(TableRowContext);
const { pageSize, page = 1 } = pagination;
console.log({pageSize, page}, ctx.index);
console.log({ pageSize, page }, ctx.index);
return ctx.index + (page - 1) * pageSize;
if (pagination && !props.clientSidePagination) {
const { pageSize, page = 1 } = pagination;

View File

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

View File

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

View File

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

View File

@ -1,62 +1,62 @@
export const UPLOAD_PLACEHOLDER = [
{
ext: /\.docx?$/i,
icon: '//img.alicdn.com/tfs/TB1n8jfr1uSBuNjy1XcXXcYjFXa-200-200.png'
icon: '//img.alicdn.com/tfs/TB1n8jfr1uSBuNjy1XcXXcYjFXa-200-200.png',
},
{
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,
icon: '//img.alicdn.com/tfs/TB1wrT5r9BYBeNjy0FeXXbnmFXa-200-200.png'
icon: '//img.alicdn.com/tfs/TB1wrT5r9BYBeNjy0FeXXbnmFXa-200-200.png',
},
{
ext: /\.pdf$/i,
icon: '//img.alicdn.com/tfs/TB1GwD8r9BYBeNjy0FeXXbnmFXa-200-200.png'
icon: '//img.alicdn.com/tfs/TB1GwD8r9BYBeNjy0FeXXbnmFXa-200-200.png',
},
{
ext: /\.png$/i,
icon: '//img.alicdn.com/tfs/TB1BHT5r9BYBeNjy0FeXXbnmFXa-200-200.png'
icon: '//img.alicdn.com/tfs/TB1BHT5r9BYBeNjy0FeXXbnmFXa-200-200.png',
},
{
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,
icon: '//img.alicdn.com/tfs/TB1B2cVr_tYBeNjy1XdXXXXyVXa-200-200.png'
icon: '//img.alicdn.com/tfs/TB1B2cVr_tYBeNjy1XdXXXXyVXa-200-200.png',
},
{
ext: /\.gif$/i,
icon: '//img.alicdn.com/tfs/TB1DTiGrVOWBuNjy0FiXXXFxVXa-200-200.png'
icon: '//img.alicdn.com/tfs/TB1DTiGrVOWBuNjy0FiXXXFxVXa-200-200.png',
},
{
ext: /\.svg$/i,
icon: '//img.alicdn.com/tfs/TB1uUm9rY9YBuNjy0FgXXcxcXXa-200-200.png'
icon: '//img.alicdn.com/tfs/TB1uUm9rY9YBuNjy0FgXXcxcXXa-200-200.png',
},
{
ext: /\.xlsx?$/i,
icon: '//img.alicdn.com/tfs/TB1any1r1OSBuNjy0FdXXbDnVXa-200-200.png'
icon: '//img.alicdn.com/tfs/TB1any1r1OSBuNjy0FdXXbDnVXa-200-200.png',
},
{
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,
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,
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,
icon: '//img.alicdn.com/tfs/TB10jmfr29TBuNjy0FcXXbeiFXa-200-200.png'
icon: '//img.alicdn.com/tfs/TB10jmfr29TBuNjy0FcXXbeiFXa-200-200.png',
},
{
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;
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;
}
.ant-upload-list-picture-card .ant-upload-list-item-progress {
@ -36,7 +38,7 @@
pointer-events: none;
}
.ant-btn {
background: rgba(0,0,0,.5);
background: rgba(0, 0, 0, 0.5);
// .anticon {
// color: #1890ff;
// }
@ -55,7 +57,8 @@
.ant-upload-list-picture-card .ant-upload-list-item-name {
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;
}
}

View File

@ -96,7 +96,7 @@ describe('user fields', () => {
target: 'users',
foreignKey: 'updated_by_id',
},
]
],
});
await db.sync();
@ -106,14 +106,19 @@ describe('user fields', () => {
// 用户1 操作
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(
Post.parseApiJson({
filter: {
id: postWithUser.id,
},
fields: ['createdBy1', 'updatedBy1', 'createdBy2', 'updatedBy2'],
}));
}),
);
expect(post.createdBy1.id).toBe(user1.id);
expect(post.updatedBy1.id).toBe(user1.id);
@ -122,14 +127,19 @@ describe('user fields', () => {
// 换个用户
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(
Post.parseApiJson({
filter: {
id: postWithUser.id,
},
fields: ['createdBy1', 'updatedBy1', 'createdBy2', 'updatedBy2'],
}));
}),
);
expect(post2.createdBy1.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.updated_by_id).toBe(null);
// @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.updated_by_id).toBe(currentUser.id);
// 更新数据 createdBy 数据不变
// @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.updated_by_id).toBe(user2.id);
});
@ -170,11 +186,14 @@ describe('user fields', () => {
const user2 = await User.create();
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,
// @ts-ignore
}, { context: { state: { currentUser: user2 } } });
},
{ context: { state: { currentUser: user2 } } },
);
expect(post.created_by_id).toBe(user1.id);
expect(post.updated_by_id).toBe(user1.id);
});
@ -189,9 +208,9 @@ describe('user fields', () => {
fields: [
{
type: 'string',
name: 'title'
}
]
name: 'title',
},
],
});
await db.sync();
const User = db.getModel('users');
@ -201,7 +220,10 @@ describe('user fields', () => {
const post = await Post.create();
expect(post.updated_by_id).toBe(null);
// @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);
});
@ -212,9 +234,9 @@ describe('user fields', () => {
fields: [
{
type: 'string',
name: 'title'
}
]
name: 'title',
},
],
});
await db.sync();
const User = db.getModel('users');
@ -223,15 +245,21 @@ describe('user fields', () => {
const Post = db.getModel('posts');
let context = { state: { currentUser: user2 } };
const post = await Post.create({
const post = await Post.create(
{
updated_by_id: user1.id,
}, { context });
},
{ context },
);
expect(post.updated_by_id).toBe(user1.id);
await post.update({ title: 'title' }, { context });
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);
// 不同用户更新数据
@ -252,9 +280,9 @@ describe('user fields', () => {
fields: [
{
type: 'string',
name: 'title'
}
]
name: 'title',
},
],
});
await db.sync();
const User = db.getModel('users');
@ -263,18 +291,20 @@ describe('user fields', () => {
const Post = db.getModel('posts');
let context = { state: { currentUser: user2 } };
await Post.bulkCreate([
{ title: 'title1' },
{ title: 'title2' },
]);
await Post.bulkCreate([{ title: 'title1' }, { title: 'title2' }]);
await Post.update({ title: 'title3' }, {
await Post.update(
{ title: 'title3' },
{
where: { title: 'title1' },
context
});
context,
},
);
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: '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) {
const { values: { email } } = ctx.action.params;
const {
values: { email },
} = ctx.action.params;
if (!email) {
ctx.throw(401, '请填写邮箱账号');
}
@ -82,7 +84,9 @@ export async function lostpassword(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 = await User.findOne({
where: {

View File

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

View File

@ -2,18 +2,20 @@ import { BelongsToOptions, BELONGSTO, FieldContext } from '@nocobase/database';
import { setUserValue } from './utils';
export interface UpdatedByOptions extends Omit<BelongsToOptions, 'type'> {
type: 'updatedBy' | 'updatedby'
type: 'updatedBy' | 'updatedby';
}
export default class UpdatedBy extends BELONGSTO {
static beforeBulkCreateHook(this: UpdatedBy, models, { context }) {
models.forEach(model => {
models.forEach((model) => {
setUserValue.call(this, model, { context });
});
}
static beforeBulkUpdateHook(this: UpdatedBy, { attributes, fields, context }) {
static beforeBulkUpdateHook(
this: UpdatedBy,
{ attributes, fields, context },
) {
if (!context) {
return;
}
@ -22,7 +24,9 @@ export default class UpdatedBy extends BELONGSTO {
return;
}
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) {
@ -36,9 +40,15 @@ export default class UpdatedBy extends BELONGSTO {
const { sourceTable, database } = context;
const name = sourceTable.getName();
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}.beforeBulkUpdate`, UpdatedBy.beforeBulkUpdateHook.bind(this));
database.on(
`${name}.beforeBulkUpdate`,
UpdatedBy.beforeBulkUpdateHook.bind(this),
);
}
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 }) {
const { foreignKey } = this.options;
@ -8,7 +8,7 @@ export function setUserValue(this: CreatedBy | UpdatedBy, model, { context }) {
return;
}
const changed = model.changed();
if (Array.isArray(changed) && changed.find(key => key === foreignKey)) {
if (Array.isArray(changed) && changed.find((key) => key === foreignKey)) {
return;
}
}