新增AreaSelectTree、AreaCascader组件

民族json、行政区划json
master
LiuJiaNan 2025-11-06 14:31:25 +08:00
parent e904b6264d
commit 562e2482f4
18 changed files with 554 additions and 114 deletions

17
components/Cascader/Area/index.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
import type { FC } from "react";
import type { BasicCascaderProps } from "../Basic";
/**
*
*/
export interface AreaCascaderProps extends Omit<BasicCascaderProps, "options"> {
/** 占位符,默认为"属地" */
placeholder?: string;
}
/**
*
*/
declare const AreaCascader: FC<AreaCascaderProps>;
export default AreaCascader;

View File

@ -0,0 +1,27 @@
import Area from "../../../json/area.json";
import BasicCascader from "../Basic";
/**
* 属地级联组件
*/
function AreaCascader(props) {
const {
placeholder = "属地",
...restProps
} = props;
return (
<BasicCascader
data={Area}
placeholder={placeholder}
nameKey="label"
idKey="value"
childrenKey="children"
{...restProps}
/>
);
}
AreaCascader.displayName = "AreaCascader";
export default AreaCascader;

29
components/Cascader/Basic/index.d.ts vendored Normal file
View File

@ -0,0 +1,29 @@
import type { CascaderProps } from "antd/es/cascader";
import type { FC } from "react";
/**
*
*/
export interface BasicCascaderProps extends CascaderProps {
/** 树形数据 label 字段,默认 name */
nameKey?: string;
/** 树形数据 value 字段,默认 id */
idKey?: string;
/** 树形数据 children 字段,默认 childrenList */
childrenKey?: string;
/** 决定 onGetNodePaths 是否包含自身节点,默认 true */
onGetNodePathsIsIncludeOneself?: boolean;
/** 获取父级节点 */
onGetNodePaths?: (nodes: Record<string, any>[]) => void;
/** 占位符 */
placeholder?: string;
/** 控制只能选择到第几级 */
level?: number;
}
/**
* 使使
*/
declare const BasicCascader: FC<BasicCascaderProps>;
export default BasicCascader;

View File

@ -0,0 +1,58 @@
import { Cascader } from "antd";
import { processTreeDataByLevel } from "../../../utils";
/**
* 基础级联组件不建议直接使用此组件二次继承使用
*/
function BasicCascader(props) {
const {
onChange,
onGetNodePaths,
onGetNodePathsIsIncludeOneself = true,
placeholder = "",
data = [],
nameKey = "name",
idKey = "id",
childrenKey = "childrenList",
level,
...restProps
} = props;
// 根据 level 处理树数据
const processedData = level
? processTreeDataByLevel({
data,
level,
childrenKey,
currentLevel: 1,
})
: data;
const getNodePaths = (selectedOptions) => {
let nodePaths = selectedOptions;
if (!onGetNodePathsIsIncludeOneself && selectedOptions) {
nodePaths = selectedOptions.slice(0, -1);
}
return nodePaths;
};
const handleChange = (value, selectedOptions) => {
const parentNodes = getNodePaths(selectedOptions);
onGetNodePaths?.(parentNodes);
onChange?.(value, selectedOptions);
};
return (
<Cascader
options={processedData}
placeholder={`请选择${placeholder}`}
onChange={handleChange}
fieldNames={{ label: nameKey, value: idKey, children: childrenKey }}
{...restProps}
/>
);
}
BasicCascader.displayName = "BasicCascader";
export default BasicCascader;

View File

@ -51,7 +51,7 @@ function Pdf(props) {
)} )}
<div style={{ height: "88vh", overflowY: "auto", padding: "24px", ...style }}> <div style={{ height: "88vh", overflowY: "auto", padding: "24px", ...style }}>
<Document <Document
file={fileUrl + file} file={!file.includes(fileUrl) ? fileUrl + file : file}
onLoadSuccess={onDocumentLoadSuccess} onLoadSuccess={onDocumentLoadSuccess}
onLoadError={onDocumentLoadError} onLoadError={onDocumentLoadError}
> >

View File

@ -16,7 +16,7 @@ export interface Params {
/** /**
* *
*/ */
export interface DepartmentSelectProps extends Omit<BasicSelectProps, "data"> { export interface PersonnelSelectProps extends Omit<BasicSelectProps, "data"> {
/** 请求参数 */ /** 请求参数 */
params?: Params; params?: Params;
/** 占位符,默认"人员" */ /** 占位符,默认"人员" */
@ -30,8 +30,8 @@ export interface DepartmentSelectProps extends Omit<BasicSelectProps, "data"> {
} }
/** /**
* *
*/ */
declare const DepartmentSelect: FC<DepartmentSelectProps>; declare const PersonnelSelect: FC<PersonnelSelectProps>;
export default DepartmentSelect; export default PersonnelSelect;

View File

@ -3,7 +3,7 @@ import { useEffect, useState } from "react";
import BasicSelect from "../../Basic"; import BasicSelect from "../../Basic";
/** /**
* 基础下拉组件港务局版本 * 人员下拉组件港务局版本
*/ */
function PersonnelSelect(props) { function PersonnelSelect(props) {
const { const {

17
components/SelectTree/Area/index.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
import type { FC } from "react";
import type { BasicSelectTreeProps } from "../Basic";
/**
*
*/
export interface AreaSelectTreeProps extends Omit<BasicSelectTreeProps, "treeData"> {
/** 占位符,默认"属地" */
placeholder?: string;
}
/**
*
*/
declare const AreaSelectTree: FC<AreaSelectTreeProps>;
export default AreaSelectTree;

View File

@ -0,0 +1,27 @@
import Area from "../../../json/area.json";
import BasicSelectTree from "../Basic";
/**
* 属地下拉树组件
*/
function AreaSelectTree(props) {
const {
placeholder = "属地",
...restProps
} = props;
return (
<BasicSelectTree
treeData={Area}
placeholder={placeholder}
nameKey="label"
idKey="value"
childrenKey="children"
{...restProps}
/>
);
}
AreaSelectTree.displayName = "AreaSelectTree";
export default AreaSelectTree;

View File

@ -17,6 +17,8 @@ export interface BasicSelectTreeProps extends TreeSelectProps {
onGetNodePaths?: (nodes: Record<string, any>[]) => void; onGetNodePaths?: (nodes: Record<string, any>[]) => void;
/** 占位符 */ /** 占位符 */
placeholder?: string; placeholder?: string;
/** 控制只能选择到第几级 */
level?: number;
} }
/** /**

View File

@ -1,6 +1,9 @@
import { TreeSelect } from "antd"; import { TreeSelect } from "antd";
import { getTreeNodePaths } from "../../../utils"; import { getTreeNodePaths, processTreeDataByLevel } from "../../../utils";
/**
* 基础下拉树组件不建议直接使用此组件二次继承使用
*/
function BasicSelectTree(props) { function BasicSelectTree(props) {
const { const {
onSelect, onSelect,
@ -11,9 +14,20 @@ function BasicSelectTree(props) {
nameKey = "name", nameKey = "name",
idKey = "id", idKey = "id",
childrenKey = "childrenList", childrenKey = "childrenList",
level,
...restProps ...restProps
} = props; } = props;
// 根据 level 处理树数据
const processedTreeData = level
? processTreeDataByLevel({
data: treeData,
level,
childrenKey,
currentLevel: 1,
})
: treeData;
const handleSelect = (value, node, extra) => { const handleSelect = (value, node, extra) => {
if (value.length > 0) { if (value.length > 0) {
const parentNodes = getTreeNodePaths({ const parentNodes = getTreeNodePaths({
@ -21,7 +35,7 @@ function BasicSelectTree(props) {
targetId: value, targetId: value,
idKey, idKey,
childrenKey, childrenKey,
isIncludeOneself: onGetNodePathsIsIncludeOneself isIncludeOneself: onGetNodePathsIsIncludeOneself,
}); });
onGetNodePaths?.(parentNodes); onGetNodePaths?.(parentNodes);
} }
@ -38,7 +52,7 @@ function BasicSelectTree(props) {
placeholder={`请选择${placeholder}`} placeholder={`请选择${placeholder}`}
onSelect={handleSelect} onSelect={handleSelect}
allowClear allowClear
treeData={treeData} treeData={processedTreeData}
fieldNames={{ label: nameKey, value: idKey, children: childrenKey }} fieldNames={{ label: nameKey, value: idKey, children: childrenKey }}
{...restProps} {...restProps}
/> />

View File

@ -1,6 +1,6 @@
import type { FC } from "react"; import type { FC } from "react";
import type { Params } from "../../../LeftTree/Department/Gwj";
import type { BasicSelectTreeProps } from "../../Basic"; import type { BasicSelectTreeProps } from "../../Basic";
import { Params } from "../../../LeftTree/Department/Gwj";
/** /**
* *
@ -8,7 +8,7 @@ import { Params } from "../../../LeftTree/Department/Gwj";
export interface DepartmentSelectTreeProps extends Omit<BasicSelectTreeProps, "treeData"> { export interface DepartmentSelectTreeProps extends Omit<BasicSelectTreeProps, "treeData"> {
/** 请求参数 */ /** 请求参数 */
params?: Params; params?: Params;
/** 占位符,默认"部门 */ /** 占位符,默认"部门" */
placeholder?: string; placeholder?: string;
/** 是否需要企业id默认 false */ /** 是否需要企业id默认 false */
isNeedCorpInfoId?: boolean; isNeedCorpInfoId?: boolean;
@ -17,7 +17,7 @@ export interface DepartmentSelectTreeProps extends Omit<BasicSelectTreeProps, "t
} }
/** /**
* *
*/ */
declare const DepartmentSelectTree: FC<DepartmentSelectTreeProps>; declare const DepartmentSelectTree: FC<DepartmentSelectTreeProps>;

View File

@ -1,9 +1,9 @@
import { request } from "@cqsjjb/jjb-common-lib/http"; import { request } from "@cqsjjb/jjb-common-lib/http";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import BasicLeftTree from "../../Basic"; import BasicSelectTree from "../../Basic";
/** /**
* 基础下拉树组件港务局版本 * 部门下拉树组件港务局版本
*/ */
function DepartmentSelectTree(props) { function DepartmentSelectTree(props) {
const { const {
@ -34,7 +34,7 @@ function DepartmentSelectTree(props) {
}, [JSON.stringify(params), isNeedCorpInfoId, isNeedParentId]); }, [JSON.stringify(params), isNeedCorpInfoId, isNeedParentId]);
return ( return (
<BasicLeftTree treeData={treeData} placeholder={placeholder} {...restProps} /> <BasicSelectTree treeData={treeData} placeholder={placeholder} {...restProps} />
); );
} }

1
json/area.json Normal file

File diff suppressed because one or more lines are too long

218
json/nation.json Normal file
View File

@ -0,0 +1,218 @@
[
{
"name": "汉族",
"bianma": "hanzu"
},
{
"name": "满族",
"bianma": "manzu"
},
{
"name": "藏族",
"bianma": "zangzu"
},
{
"name": "蒙古族",
"bianma": "mengguzu"
},
{
"name": "回族",
"bianma": "huizu"
},
{
"name": "维吾尔族",
"bianma": "weiwu'erzu"
},
{
"name": "壮族",
"bianma": "zhuangzu"
},
{
"name": "苗族",
"bianma": "miaozu"
},
{
"name": "彝族",
"bianma": "yizu"
},
{
"name": "布依族",
"bianma": "buyizuu"
},
{
"name": "侗族",
"bianma": "dongzu"
},
{
"name": "瑶族",
"bianma": "yaozu"
},
{
"name": "白族",
"bianma": "baizu"
},
{
"name": "哈尼族",
"bianma": "hanizu"
},
{
"name": "哈萨克族",
"bianma": "hasakezu"
},
{
"name": "黎族",
"bianma": "lizu"
},
{
"name": "傣族",
"bianma": "daizu"
},
{
"name": "畲族",
"bianma": "shezu"
},
{
"name": "傈僳族",
"bianma": "lisuzu"
},
{
"name": "仡佬族",
"bianma": "gelaozu"
},
{
"name": "东乡族",
"bianma": "dongxiangzu"
},
{
"name": "高山族",
"bianma": "gaoshanzu"
},
{
"name": "拉祜族",
"bianma": "lahuzu"
},
{
"name": "水族",
"bianma": "shuizu"
},
{
"name": "佤族",
"bianma": "wazu"
},
{
"name": "纳西族",
"bianma": "naxizu"
},
{
"name": "羌族",
"bianma": "qiangzu"
},
{
"name": "土族",
"bianma": "tuzu"
},
{
"name": "仫佬族",
"bianma": "mulaozu"
},
{
"name": "锡伯族",
"bianma": "xibozu"
},
{
"name": "柯尔克孜族",
"bianma": "keerkezizu"
},
{
"name": "达斡尔族",
"bianma": "dawuerzu"
},
{
"name": "景颇族",
"bianma": "jingpozu"
},
{
"name": "毛南族",
"bianma": "maonanzu"
},
{
"name": "撒拉族",
"bianma": "salaizu"
},
{
"name": "布朗族",
"bianma": "bulangzu"
},
{
"name": "塔吉克族",
"bianma": "tajikezu"
},
{
"name": "阿昌族",
"bianma": "achangzu"
},
{
"name": "普米族",
"bianma": "pumizu"
},
{
"name": "鄂温克族",
"bianma": "ewenkezu"
},
{
"name": "怒族",
"bianma": "nuzu"
},
{
"name": "京族",
"bianma": "jingzu"
},
{
"name": "基诺族",
"bianma": "jinuozu"
},
{
"name": "德昂族",
"bianma": "deangzu"
},
{
"name": "保安族",
"bianma": "baoanzu"
},
{
"name": "俄罗斯族",
"bianma": "eluosizu"
},
{
"name": "裕固族",
"bianma": "yuguzu"
},
{
"name": "乌孜别克族",
"bianma": "wuzibiekezu"
},
{
"name": "门巴族",
"bianma": "menbazu"
},
{
"name": "鄂伦春族",
"bianma": "elunchunzu"
},
{
"name": "独龙族",
"bianma": "dulongzu"
},
{
"name": "塔塔尔族",
"bianma": "tataerzu"
},
{
"name": "赫哲族",
"bianma": "hezhezu"
},
{
"name": "珞巴族",
"bianma": "luobazu"
}
]

View File

@ -10,6 +10,7 @@
"components", "components",
"enum", "enum",
"hooks", "hooks",
"json",
"regular", "regular",
"utils", "utils",
"README.md" "README.md"

193
utils/index.d.ts vendored
View File

@ -49,96 +49,6 @@ type FileSuffix
| "tar" | "tar"
| string; // 允许其他可能的类型 | string; // 允许其他可能的类型
// 为 findCharIndex 函数定义接口类型
interface FindCharIndexOptions {
/** 查找的字符串 */
str: string;
/** 查找的字符 */
char: string;
/** 第几次出现 */
num: number;
}
// 为 paging 函数定义接口类型
interface PagingOptions {
/** 分页的数组 */
list: any[];
/** 当前页 */
currentPage: number | string;
/** 每页条数 */
pageSize: number | string;
}
// 为 addingPrefixToFile 函数定义接口类型
interface AddingPrefixToFileOptions {
/** 附件路径字段名 */
pathKey?: string;
/** 附件名称字段名 */
nameKey?: string;
/** 附件id字段名 */
idKey?: string;
}
// 为 getLabelName 函数定义接口类型
interface GetLabelNameOptions {
/** 状态 */
status: number | string;
/** 翻译的数组 */
list: any[];
/** id字段名 */
idKey?: string;
/** name字段名 */
nameKey?: string;
}
// 为 getSelectAppointItemList 函数定义接口类型
interface GetSelectAppointItemListOptions {
/** 获取的数组 */
list: any[];
/** 获取的值 */
value: any[];
/** 获取的id字段名 */
idKey?: string;
}
// 为 listTransTree 函数定义接口类型
interface ListTransTreeOptions {
/** 需要转换的json */
json: any[];
/** id字段 */
idKey: string;
/** 父级id字段 */
parentIdKey: string;
/** 子级字段 */
childrenKey: string;
}
// 为 isEmptyToWhether 函数定义接口类型
interface IsEmptyToWhetherOptions {
/** 真值时显示的文本 */
yesText?: string;
/** 假值时显示的文本 */
noText?: string;
/** 判断为真的值 */
yesValue?: string | number;
}
// 为 getTreeNodePaths 函数定义接口类型
interface GetTreeNodePathsOptions {
/** 树形数据 */
data: any[];
/** 目标节点ID */
targetId: string | number;
/** id字段名 */
idKey: string;
/** 子节点字段名 */
childrenKey: string;
/** 路径数组 */
path?: any[];
/** 是否包含自身 */
isIncludeOneself?: boolean;
}
/** /**
* *
*/ */
@ -190,7 +100,14 @@ export function arrayObjectDeduplication<T>(arr: T[], key: string): T[];
/** /**
* *
*/ */
export function findCharIndex(options: FindCharIndexOptions): number; export function findCharIndex(options: {
/** 查找的字符串 */
str: string;
/** 查找的字符 */
char: string;
/** 第几次出现 */
num: number;
}): number;
/** /**
* *
@ -215,7 +132,14 @@ export function getUrlParam(key: string): string;
/** /**
* *
*/ */
export function paging<T>(options: PagingOptions): T[]; export function paging<T>(options: {
/** 分页的数组 */
list: any[];
/** 当前页 */
currentPage: number | string;
/** 每页条数 */
pageSize: number | string;
}): T[];
/** /**
* *
@ -242,13 +166,29 @@ export function secondConversion(second: string | number): string;
*/ */
export function addingPrefixToFile<T extends Record<string, any>>( export function addingPrefixToFile<T extends Record<string, any>>(
list: T[], list: T[],
options?: AddingPrefixToFileOptions, options?: {
/** 附件路径字段名 */
pathKey?: string;
/** 附件名称字段名 */
nameKey?: string;
/** 附件id字段名 */
idKey?: string;
},
): (T & { url: string; name: string; id: any })[]; ): (T & { url: string; name: string; id: any })[];
/** /**
* *
*/ */
export function getLabelName<T>(options: GetLabelNameOptions): string | undefined; export function getLabelName<T>(options: {
/** 状态 */
status: number | string;
/** 翻译的数组 */
list: any[];
/** id字段名 */
idKey?: string;
/** name字段名 */
nameKey?: string;
}): string | undefined;
/** /**
* *
@ -263,19 +203,42 @@ export function idCardGetDateAndGender(idCard: string): { sex: "1" | "0"; date:
/** /**
* select * select
*/ */
export function getSelectAppointItemList<T>(options: GetSelectAppointItemListOptions): T[]; export function getSelectAppointItemList<T>(options: {
/** 获取的数组 */
list: any[];
/** 获取的值 */
value: any[];
/** 获取的id字段名 */
idKey?: string;
}): T[];
/** /**
* json * json
*/ */
export function listTransTree<T>(options: ListTransTreeOptions): T[]; export function listTransTree<T>(options: {
/** 需要转换的json */
json: any[];
/** id字段 */
idKey: string;
/** 父级id字段 */
parentIdKey: string;
/** 子级字段 */
childrenKey: string;
}): T[];
/** /**
* "是"/"否" * "是"/"否"
*/ */
export function isEmptyToWhether( export function isEmptyToWhether(
value: any, value: any,
options?: IsEmptyToWhetherOptions, options?: {
/** 真值时显示的文本 */
yesText?: string;
/** 假值时显示的文本 */
noText?: string;
/** 判断为真的值 */
yesValue?: string | number;
},
): string; ): string;
/** /**
@ -302,5 +265,39 @@ export function getFileUrl(): string;
* *
*/ */
export function getTreeNodePaths<T extends Record<string, any> = Record<string, any>>( export function getTreeNodePaths<T extends Record<string, any> = Record<string, any>>(
options: GetTreeNodePathsOptions, options: {
/** 树形数据 */
data: any[];
/** 目标节点ID */
targetId: string | number;
/** id字段名 */
idKey: string;
/** 子节点字段名 */
childrenKey: string;
/** 路径数组 */
path?: any[];
/** 是否包含自身 */
isIncludeOneself?: boolean;
},
): T[] | null; ): T[] | null;
/**
* level isLeaf
*/
export function processTreeDataByLevel(
options: {
/** 树形数据 */
data: any[];
/** 层级限制 */
level?: number;
/** 子节点字段名 */
childrenKey: string;
/** 当前层级 */
currentLevel?: number;
},
): {
/** 是否为叶子节点 */
isLeaf: boolean;
/** 子节点 */
[key: string]: any;
}[];

View File

@ -430,6 +430,38 @@ export function getTreeNodePaths(options) {
return null; return null;
} }
/**
* 根据 level 属性处理树数据添加 isLeaf 属性控制节点是否可展开
*/
export const processTreeDataByLevel = (options) => {
const { data, level, childrenKey, currentLevel = 1 } = options;
return data.map((item) => {
const processedItem = { ...item };
// 如果指定了 level 且当前层级达到指定层级,则标记为叶子节点
if (level && currentLevel >= level) {
processedItem.isLeaf = true;
// 移除子节点
delete processedItem[childrenKey];
}
else if (item[childrenKey] && item[childrenKey].length > 0) {
// 未达到指定层级,继续处理子节点
processedItem[childrenKey] = processTreeDataByLevel({
data: item[childrenKey],
currentLevel: currentLevel + 1,
level,
childrenKey,
});
}
else {
// 没有子节点,标记为叶子节点
processedItem.isLeaf = true;
}
return processedItem;
});
};
/** /**
* 获取文件url * 获取文件url
*/ */