Skip to content

Commit

Permalink
feat: add genCrudQuerySearch
Browse files Browse the repository at this point in the history
  • Loading branch information
SolidZORO committed May 17, 2020
1 parent 1f47746 commit 9558c72
Show file tree
Hide file tree
Showing 16 changed files with 256 additions and 190 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Category } from '@leaa/common/src/entrys';

@ObjectType()
export class CategoryTreeObject extends Category {
@Field(() => String)
readonly key!: string;
// @Field(() => String)
// readonly key!: string;

@Field(() => String)
readonly value!: string;
Expand All @@ -17,7 +17,7 @@ export class CategoryTreeObject extends Category {
readonly subtitle?: string;

@Field(() => Boolean, { nullable: true })
readonly expanded?: boolean;
readonly expanded?: boolean | 'true' | 'false';

@Field(() => [CategoryTreeObject], { nullable: true })
readonly children?: CategoryTreeObject[];
Expand Down
4 changes: 2 additions & 2 deletions packages/_leaa-common/src/entrys/category.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ export class Category extends Base {
parent?: Category | null;

// Virtual Field (not in DB)
@Field(() => String, { nullable: true })
key?: string | null;
// @Field(() => String, { nullable: true })
// key?: string | null;
}
7 changes: 5 additions & 2 deletions packages/leaa-api/src/interfaces/category.interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { FindOneOptions } from 'typeorm';
import { CategoriesArgs, CategoryArgs } from '@leaa/common/src/dtos/category';
import { CategoryArgs } from '@leaa/common/src/dtos/category';
import { Category } from '@leaa/common/src/entrys';

export type ICategoriesArgs = CategoriesArgs & FindOneOptions<Category>;
// export type ICategoriesQuery = CategoriesArgs & FindOneOptions<Category>;
export type ICategoriesQuery = {
expanded?: boolean;
};
export type ICategoryArgs = CategoryArgs & FindOneOptions<Category>;
15 changes: 11 additions & 4 deletions packages/leaa-api/src/modules/category/category.controller.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { Controller, UseGuards, Get, Req, Query } from '@nestjs/common';
import { Crud, CrudController, ParsedRequest, CrudRequest } from '@nestjsx/crud';
import { Crud, CrudController, CrudRequest } from '@nestjsx/crud';

import { Permissions } from '@leaa/api/src/decorators';
// import { crudConfig } from '@leaa/api/src/configs';
import { CreateCategoryInput, UpdateCategoryInput } from '@leaa/common/src/dtos/category';
import { ICategoriesQuery } from '@leaa/api/src/interfaces';
import { JwtGuard, PermissionsGuard } from '@leaa/api/src/guards';
import { Category } from '@leaa/common/src/entrys';
import { CategoryService } from './category.service';
import { QueryBuilder } from 'typeorm';

@Crud({
model: {
type: Category,
},
params: {
id: {
field: 'id',
type: 'uuid',
primary: true,
},
},
query: {
maxLimit: 1000,
alwaysPaginate: true,
Expand All @@ -37,7 +44,7 @@ export class CategoryController implements CrudController<Category> {

@Get('tree')
// async tree(@ParsedRequest() req: CrudRequest) {
async tree(@Req() req: CrudRequest, @Query() query: any) {
return this.service.tree();
async tree(@Req() req: CrudRequest, @Query() query: ICategoriesQuery) {
return this.service.tree(query);
}
}
16 changes: 7 additions & 9 deletions packages/leaa-api/src/modules/category/category.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';
import { Category } from '@leaa/common/src/entrys';
import { Repository, TreeRepository, getManager } from 'typeorm';
import moment from 'moment';
import { ICategoriesArgs } from '@leaa/api/src/interfaces';
import { ICategoriesQuery } from '@leaa/api/src/interfaces';
import { CategoryTreeObject } from '@leaa/common/src/dtos/category';
import { CrudController, Override, CrudRequest } from '@nestjsx/crud';

Expand All @@ -15,17 +15,15 @@ export class CategoryService extends TypeOrmCrudService<Category> {
super(repo as TreeRepository<Category>);
}

async tree() {
// const manager = getManager();
// const categories = await manager.getTreeRepository(Category).findTrees();
async tree(options?: ICategoriesQuery) {
const categories = await (this.repo as TreeRepository<Category>).findTrees();

return this.categoriesByTrees(categories);
return this.categoriesByTrees(categories, options);
}

rootCategory(children?: any[]) {
return {
key: '0-0-0-root',
// key: '0-0-0-root',
id: '----',
parent_id: null,
slug: '----',
Expand All @@ -40,15 +38,15 @@ export class CategoryService extends TypeOrmCrudService<Category> {
};
}

categoriesByTrees(items: Category[], args?: ICategoriesArgs): CategoryTreeObject[] {
categoriesByTrees(items: Category[], options?: ICategoriesQuery): CategoryTreeObject[] {
const appendInfoToItem = (item: Category): Omit<CategoryTreeObject, 'children'> => ({
...item,
key: `${item.parent_id}-${item.id}-${item.slug}`,
// key: `${item.parent_id}-${item.id}-${item.slug}`,
//
title: `${item.name}`,
subtitle: item.slug,
value: item.id,
expanded: args && args.expanded,
expanded: Boolean([true, 'true'].includes(options?.expanded || '')),
});

const recursiveItems = (categories: Category[]) => {
Expand Down
8 changes: 4 additions & 4 deletions packages/leaa-api/src/modules/category/category.service222.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
CategoryTreeObject,
} from '@leaa/common/src/dtos/category';
import { argsFormat, commonUpdate, commonDelete, isOneField, calcQbPageInfo, errorMsg } from '@leaa/api/src/utils';
import { ICategoriesArgs, ICategoryArgs, IGqlCtx } from '@leaa/api/src/interfaces';
import { ICategoriesQuery, ICategoryArgs, IGqlCtx } from '@leaa/api/src/interfaces';
import { ConfigService } from '@leaa/api/src/modules/config/config.service';
import { categorySeed } from '@leaa/api/src/modules/seed/seed.data';

Expand Down Expand Up @@ -57,7 +57,7 @@ export class CategoryService {
};
}

categoriesByTrees(items: Category[], args?: ICategoriesArgs): CategoryTreeObject[] {
categoriesByTrees(items: Category[], args?: ICategoriesQuery): CategoryTreeObject[] {
const appendInfoToItem = (item: Category): Omit<CategoryTreeObject, 'children'> => ({
...item,
key: `${item.parent_id}-${item.id}-${item.slug}`,
Expand Down Expand Up @@ -86,8 +86,8 @@ export class CategoryService {
return [this.rootCategory(result)];
}

async categories(args: ICategoriesArgs): Promise<CategoriesWithPaginationOrTreeObject | undefined> {
const nextArgs: ICategoriesArgs = argsFormat(args, gqlCtx);
async categories(args: ICategoriesQuery): Promise<CategoriesWithPaginationOrTreeObject | undefined> {
const nextArgs: ICategoriesQuery = argsFormat(args, gqlCtx);

const qb = this.categoryRepository.createQueryBuilder();
qb.select().orderBy(nextArgs.orderBy || 'created_at', nextArgs.orderSort);
Expand Down
20 changes: 9 additions & 11 deletions packages/leaa-dashboard/src/components/FilterIcon/FilterIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ import { DEFAULT_QUERY } from '@leaa/dashboard/src/constants';
import style from './style.module.less';

interface IProps {
query?: ICrudListQueryParams | any;
clearQuery?: string[];
onClose: (clearQuery: any) => void;
crudQuery?: ICrudListQueryParams | any;
clear?: string[];
onClose: (clearCondition: any) => void;
}

export const FilterIcon = (props: IProps) => {
const [showClose, setShowClose] = useState(false);

const onClose = () => {
if (!showClose || !props.clearQuery) return;
if (!showClose || !props.clear) return;

const clearQ = props.clearQuery.reduce((attrs: any, cur: any) => {
const clearQ = props.clear.reduce((attrs: any, cur: any) => {
// eslint-disable-next-line no-param-reassign
attrs[cur] = undefined;

Expand All @@ -31,14 +31,12 @@ export const FilterIcon = (props: IProps) => {
};

useEffect(() => {
if (props.query && props.clearQuery) {
// const ignoreQuery = ['sort'];
// const queryObj = _.pick(_.omit(props.query, ignoreQuery), props.clearQuery);
const queryObj = _.pick(props.query, props.clearQuery);
if (props.crudQuery && props.clear) {
const prevQueryObj = _.pick(props.crudQuery, props.clear);

setShowClose(JSON.stringify(queryObj) !== '{}');
setShowClose(JSON.stringify(prevQueryObj) !== '{}');
}
}, [props.query]);
}, [props.crudQuery]);

return (
<Rcon
Expand Down
22 changes: 10 additions & 12 deletions packages/leaa-dashboard/src/components/SearchInput/SearchInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import _ from 'lodash';
import React, { useState, useCallback, useEffect } from 'react';
import React, { useState, useEffect } from 'react';
import cx from 'classnames';
import { useTranslation } from 'react-i18next';
import { Input } from 'antd';
Expand All @@ -17,18 +16,17 @@ export const SearchInput = (props: IProps) => {
const { t } = useTranslation();
const [text, setText] = useState<string | number | string[] | undefined>(props.value);

const onSearch = useCallback(
_.debounce((str?: string) => {
if (props.onSearch) props.onSearch(str);
}, 300),
[],
);

const onChange = (str?: string) => {
const nextStr = str || undefined;
if (typeof nextStr === 'undefined' && props.onSearch) props.onSearch(nextStr);

setText(nextStr);
onSearch(nextStr);
};

const onSearch = (str?: string) => {
const nextStr = str || undefined;

if (props.onSearch) props.onSearch(nextStr);
};

useEffect(() => {
Expand All @@ -44,9 +42,9 @@ export const SearchInput = (props: IProps) => {
onChange={(e) => onChange(e.currentTarget.value)}
value={text}
addonAfter={
<SearchOutlined className={style['search-input-search-button']} onClick={() => onChange(text as string)} />
<SearchOutlined className={style['search-input-search-button']} onClick={() => onSearch(text as string)} />
}
onPressEnter={() => onChange(text as string)}
onPressEnter={() => onSearch(text as string)}
className={cx(style['search-input-wrapper'], 'search-input-wrapper')}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
import _ from 'lodash';
import cx from 'classnames';
import React, { useState, useEffect } from 'react';
import { TreeSelect } from 'antd';
import { useTranslation } from 'react-i18next';
import { useQuery } from '@apollo/react-hooks';
// import { useQuery } from '@apollo/react-hooks';
import { TreeSelectProps } from 'antd/es/tree-select';

import { GET_CATEGORIES } from '@leaa/dashboard/src/graphqls';
import { CategoriesArgs, CategoriesWithPaginationOrTreeObject } from '@leaa/common/src/dtos/category';

import { ICategoriesQuery } from '@leaa/api/src/interfaces';
import { ajax, errorMsg } from '@leaa/dashboard/src/utils';
import { envConfig } from '@leaa/dashboard/src/configs';
import { IHttpRes, IHttpError } from '@leaa/dashboard/src/interfaces';
import { TreeItem } from 'react-sortable-tree';

import style from './style.module.less';

interface IProps {
value?: string | string[] | null;
initialValues?: string | string[] | null;
className?: string;
onChange?: (value?: string | string[] | null) => void;
// onChange?: (value?: string | string[] | null) => void;
onChange?: (value?: any) => void;
multipleSelect?: boolean;
componentProps?: TreeSelectProps<any>;
parentId?: string;
Expand All @@ -26,26 +34,27 @@ interface IProps {
export const SelectCategoryIdByTree = (props: IProps) => {
const { t } = useTranslation();

// query
const getCategoriesVariables: CategoriesArgs = {
expanded: true,
treeType: true,
parentId: props.parentId,
parentSlug: props.parentSlug,
const [tree, setTree] = useState<TreeItem[]>([]);
const [treeLoading, setTreeLoading] = useState(false);

const fetchList = (params: ICategoriesQuery = { expanded: true }) => {
setTreeLoading(true);

ajax
.get(`${envConfig.API_URL}/categories/tree`, { params })
.then((res: IHttpRes<TreeItem[]>) => {
setTree(res.data?.data);
})
.catch((err: IHttpError) => errorMsg(err.response?.data?.message || err.message))
.finally(() => setTreeLoading(false));
};

const getCategoriesQuery = useQuery<{ categories: CategoriesWithPaginationOrTreeObject }, CategoriesArgs>(
GET_CATEGORIES,
{
variables: getCategoriesVariables,
fetchPolicy: 'network-only',
},
);
useEffect(() => fetchList(), []);

const [value, setValue] = useState<string | string[] | undefined | null>(props.value || props.initialValues);

const onChange = (v?: string | string[] | null) => {
setValue(v);
setValue(v || undefined);

if (props.onChange) props.onChange(v);
};
Expand All @@ -66,24 +75,17 @@ export const SelectCategoryIdByTree = (props: IProps) => {
}
: {};

const onCalcTreeData = () => {
if (getCategoriesQuery.data?.categories?.trees?.length) {
return getCategoriesQuery.data.categories.trees;
}

return [];
};

return (
<div className={cx(style['wrapper'], props.className)}>
<TreeSelect
{...multipleSelectOption}
loading={getCategoriesQuery.loading}
// TIPS: waiting data then select (fix only show number)
value={value || '----'}
loading={treeLoading}
// TIPS: value 即便是有值,也必须等待 tree query 完毕后才现实,不然 select 会被 uuid 撑开
value={!_.isEmpty(tree) ? value : '----'}
treeDefaultExpandAll
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={onCalcTreeData()}
dropdownClassName={style['tree-dropdown']}
dropdownMatchSelectWidth={false}
treeData={tree as any}
placeholder={props.placeholder || t('_lang:category')}
onChange={onChange}
className={style['tree-select-wrapper']}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
width: 100%;
min-width: 150px;
}

.tree-dropdown {
width: 280px;
}
4 changes: 4 additions & 0 deletions packages/leaa-dashboard/src/interfaces/crud.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ import { CreateQueryParams } from '@nestjsx/crud-request';
export interface ICrudListQueryParams extends CreateQueryParams {
q?: string;
s?: string;
categoryId?: string;
banderId?: string;
tagId?: string;
userId?: string;
}

0 comments on commit 9558c72

Please sign in to comment.