Skip to content

Commit

Permalink
feat: 新增记录接口
Browse files Browse the repository at this point in the history
  • Loading branch information
moonrailgun committed Jul 29, 2022
1 parent ef74a54 commit 04e2df8
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 35 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-fastify-form": "^1.0.1",
"react-fastify-form": "^1.0.2",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"reflect-metadata": "^0.1.13",
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions src/client/src/components/form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,31 @@ import React, { useMemo } from 'react';
import {
FastifyForm,
regField,
FastifyFormContainerComponent,
regFormContainer,
FastifyFormContainerProps,
} from 'react-fastify-form';
import { Form, Button } from '@arco-design/web-react';

import { FastifyFormText } from './types/Text';
import { FastifyFormTextArea } from './types/TextArea';
import { FastifyFormPassword } from './types/Password';
import { FastifyFormSelect } from './types/Select';
import { FastifyFormCheckbox } from './types/Checkbox';
import { FastifyFormCustom } from './types/Custom';
import { FastifyFormNumber } from './types/Number';

regField('text', FastifyFormText);
regField('textarea', FastifyFormTextArea);
regField('password', FastifyFormPassword);
regField('number', FastifyFormNumber);
regField('select', FastifyFormSelect);
regField('checkbox', FastifyFormCheckbox);
regField('custom', FastifyFormCustom);

const FastifyFormContainer: FastifyFormContainerComponent = React.memo(
const FastifyFormContainer: React.FC<FastifyFormContainerProps> = React.memo(
(props) => {
const layout = props.layout;
const hiddenSubmit: boolean = props.extraProps?.hiddenSubmit ?? false;

const submitButtonRender = useMemo(() => {
return (
<Form.Item
Expand Down Expand Up @@ -61,7 +64,7 @@ const FastifyFormContainer: FastifyFormContainerComponent = React.memo(
wrapperCol={layout === 'vertical' ? { xs: 24 } : { sm: 24, md: 16 }}
>
{props.children}
{submitButtonRender}
{!hiddenSubmit && submitButtonRender}
</Form>
);
}
Expand Down
29 changes: 29 additions & 0 deletions src/client/src/components/form/types/Number.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { Form, InputNumber } from '@arco-design/web-react';
import type { FastifyFormFieldComponent } from 'react-fastify-form';
import { getValidateStatus } from '../utils';

export const FastifyFormNumber: FastifyFormFieldComponent = React.memo(
(props) => {
const { name, label, value, onChange, error, maxLength, placeholder } =
props;

return (
<Form.Item
label={label}
validateStatus={getValidateStatus(error)}
help={error}
>
<InputNumber
name={name}
size="large"
maxLength={maxLength}
placeholder={placeholder}
value={value}
onChange={(val) => onChange(val)}
/>
</Form.Item>
);
}
);
FastifyFormNumber.displayName = 'FastifyFormNumber';
35 changes: 24 additions & 11 deletions src/client/src/components/table/controller.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import { Button, Drawer, Form, Input } from '@arco-design/web-react';
import { Button, Drawer } from '@arco-design/web-react';
import React, { useState } from 'react';
import { useResourcePropertiesMeta } from '../../model/resource/meta';
import { useResourceName } from '../../router/hooks';

const FormItem = Form.Item;
import { WebFastifyForm } from '../form';
import _noop from 'lodash/noop';
import { useAsyncRequest } from '../../model/utils';
import { addResource } from '../../model/resource/edit';

export const TushanTableController: React.FC = React.memo(() => {
const resourceName = useResourceName();
const { data: resourceMeta } = useResourcePropertiesMeta(resourceName);

const [addDrawerVisible, setAddDrawerVisible] = useState(false);
const [values, setValues] = useState({});

const [{ loading }, handleAddResource] = useAsyncRequest(async () => {
await addResource(resourceName, values);
setAddDrawerVisible(false);
});

return (
<div className="text-right py-2">
Expand All @@ -24,15 +31,21 @@ export const TushanTableController: React.FC = React.memo(() => {
visible={addDrawerVisible}
closable={true}
maskClosable={false}
okButtonProps={{ loading }}
onOk={handleAddResource}
onCancel={() => setAddDrawerVisible(false)}
>
<Form layout="vertical">
{resourceMeta.map((meta) => (
<FormItem key={meta.name} label={meta.name}>
<Input placeholder={meta.name} />
</FormItem>
))}
</Form>
<WebFastifyForm
layout="vertical"
fields={resourceMeta.map((meta) => ({
type: meta.viewType,
name: meta.name,
label: meta.name,
}))}
extraProps={{ hiddenSubmit: true }}
onChange={setValues}
onSubmit={_noop}
/>
</Drawer>
</div>
);
Expand Down
13 changes: 13 additions & 0 deletions src/client/src/model/resource/edit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { request } from '../utils';

/**
* 新增/编辑 记录
*/
export async function addResource(
resourceName: string,
resourceData: Record<string, any>
): Promise<void> {
await request.put(`/resource/${resourceName}/add`, {
...resourceData,
});
}
7 changes: 5 additions & 2 deletions src/client/src/model/resource/meta.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useRequest } from 'ahooks';
import {
ResourcePropertyMetaType,
ResourcePropertyMetaViewType,
} from '../../../../shared/types';
import { request } from '../utils';

type ResourcePropertyMetaType = 'string' | 'number';

interface ResourceMeta {
resourceName: string;
}
Expand All @@ -12,6 +14,7 @@ interface ResourcePropertyMeta {
isPrimary: boolean;
name: string;
type: ResourcePropertyMetaType;
viewType: ResourcePropertyMetaViewType;
}

/**
Expand Down
24 changes: 24 additions & 0 deletions src/client/src/model/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
import axios from 'axios';
import { Message } from '@arco-design/web-react';
import { useRequest } from 'ahooks';

export const request = axios.create({
baseURL: '/admin',
});

/**
* 发送修改请求
*/
export function useAsyncRequest<T>(fn: () => Promise<T>) {
const { data, error, loading, runAsync } = useRequest(
async () => {
try {
await fn();
Message.success('操作成功');
} catch (err) {
console.error(err);
Message.error('操作失败');
}
},
{
manual: true,
}
);

return [{ data, error, loading }, runAsync] as const;
}
5 changes: 4 additions & 1 deletion src/server/orm.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'reflect-metadata';
import type { ColumnType } from 'typeorm';
import type { ResourcePropertyMetaType } from '../shared/types';

export {
DataSource,
Expand All @@ -12,7 +13,9 @@ export {
/**
* 解析类型成字段
*/
export function parseColumnType(columnType: ColumnType): unknown {
export function parseColumnType(
columnType: ColumnType
): ResourcePropertyMetaType {
if (columnType === Number) {
return 'number';
}
Expand Down
35 changes: 23 additions & 12 deletions src/server/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import type { Tushan } from '../Tushan';
import Router from '@koa/router';
import bodyParser from 'koa-bodyparser';
import { parseColumnType } from './orm';

import { getDefaultViewType } from '../shared/viewType';
import fs from 'fs';
import path from 'path';
import _ from 'lodash';

interface BuildRouterOptions {
/**
Expand Down Expand Up @@ -84,25 +85,35 @@ export async function buildRouter(options: BuildRouterOptions) {
});

// 新增
router.post(`/resource/${resourceName}/add`, (ctx) => {
router.put(`/resource/${resourceName}/add`, (ctx) => {
const body = ctx.request.body;

const entity = tushan.datasource.manager.create(metadata.target, {
...body,
});
const primaryPropertyName = metadata.columns
.filter((col) => col.isPrimary)
.map((col) => col.propertyName);

const entity = tushan.datasource.manager.create(
metadata.target,
_.omit(body, [...primaryPropertyName])
);

return tushan.datasource.manager.save(entity);
});

// 列元信息
router.get(`/meta/${resourceName}/properties`, (ctx) => {
return metadata.columns.map((col) => ({
name: col.propertyName,
default: col.default,
type: parseColumnType(col.type),
isPrimary: col.isPrimary || col.isObjectId,
isNullable: col.isNullable,
}));
return metadata.columns.map((col) => {
const type = parseColumnType(col.type);

return {
name: col.propertyName,
default: col.default,
type,
viewType: getDefaultViewType(type),
isPrimary: col.isPrimary || col.isObjectId,
isNullable: col.isNullable,
};
});
});
});

Expand Down
20 changes: 20 additions & 0 deletions src/shared/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* 数据库类型
*
* 用于在数据库中管理
*/
export type ResourcePropertyMetaType = 'string' | 'number' | 'unknown';

/**
* 视图类型
*
* 用于前端展示
*/
export type ResourcePropertyMetaViewType =
| 'text'
| 'textarea'
| 'number'
| 'password'
| 'select'
| 'checkbox'
| 'custom';
22 changes: 22 additions & 0 deletions src/shared/viewType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type {
ResourcePropertyMetaType,
ResourcePropertyMetaViewType,
} from './types';

/**
* 获取默认视图样式
* @param metaType 数据库类型
*/
export function getDefaultViewType(
metaType: ResourcePropertyMetaType
): ResourcePropertyMetaViewType {
if (metaType === 'string') {
return 'text';
}

if (metaType === 'number') {
return 'number';
}

return 'text';
}

0 comments on commit 04e2df8

Please sign in to comment.