@cfmm/umi-plugins-ui-v2 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1093,8 +1093,9 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
1093
1093
  [rowKey]: editRow?.[rowKey],
1094
1094
  });
1095
1095
  if (success) {
1096
- actionRef.current?.reload();
1097
1096
  setEditRow(null);
1097
+ actionRef.current?.reload();
1098
+ updateFormRef.current?.resetFields();
1098
1099
  }
1099
1100
  return success;
1100
1101
  })}
@@ -1134,6 +1135,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
1134
1135
  actionRef.current?.reload();
1135
1136
  setEditRow(null);
1136
1137
  setUpdateModalOpen(false);
1138
+ updateFormRef.current?.resetFields();
1137
1139
  }
1138
1140
  return success;
1139
1141
  })}
@@ -1,6 +1,3 @@
1
- // @ts-nocheck
2
- // This file is generated by Umi automatically
3
- // DO NOT CHANGE IT MANUALLY!
4
1
  import { Empty, Select, Spin } from 'antd';
5
2
  import React, {
6
3
  ForwardedRef,
@@ -19,6 +16,18 @@ import { MySelectProps } from '../types';
19
16
 
20
17
  const { Option } = Select;
21
18
 
19
+ /** 无对象、无键,或每个键的值均为 undefined / null / 空串(含纯空白)时视为“无搜索条件” */
20
+ function isSearchObjectAllEmpty(obj?: { [key: string]: string | undefined }): boolean {
21
+ if (!obj) return true;
22
+ const keys = Object.keys(obj);
23
+ if (keys.length === 0) return true;
24
+ return keys.every((key) => {
25
+ const v = obj[key];
26
+ if (v === undefined || v === null) return true;
27
+ return String(v).trim() === '';
28
+ });
29
+ }
30
+
22
31
  const MySelect = <T,>(props: MySelectProps<T>, ref: ForwardedRef<any>) => {
23
32
  const {
24
33
  readonly,
@@ -105,7 +114,7 @@ const MySelect = <T,>(props: MySelectProps<T>, ref: ForwardedRef<any>) => {
105
114
  setListData([]);
106
115
  let params = showSearch ? { ...searchValue, ...otherSearchValue } : otherSearchValue;
107
116
  // 如果显示全部,则不分页
108
- params = showAllList ? params : { pageIndex: 1, pageSize: 20, ...params };
117
+ params = showAllList ? params : { pageIndex: 1, pageSize, ...params };
109
118
  const response = await request(params);
110
119
  if (response.rows && response.rows.length > 0) {
111
120
  // 如果有搜索值,则不添加回显值
@@ -124,7 +133,7 @@ const MySelect = <T,>(props: MySelectProps<T>, ref: ForwardedRef<any>) => {
124
133
  };
125
134
 
126
135
  useEffect(() => {
127
- if (Array.isArray(localListData) && !showSearch) {
136
+ if (Array.isArray(localListData) && isSearchObjectAllEmpty(searchValue)) {
128
137
  setListData(localListData);
129
138
  return;
130
139
  }
@@ -19,7 +19,7 @@ export async function queryAllPermissions() {
19
19
  }
20
20
 
21
21
  const checkStatus = (status: string): boolean => {
22
- return status.toUpperCase() === 'Y';
22
+ return status === '1' || status === 'Y';
23
23
  }
24
24
 
25
25
  /**
@@ -15,96 +15,80 @@ export const useRouteAuth = (currentUser?: CurrentUser) => {
15
15
  const params = useParams();
16
16
  const { pathname } = useLocation();
17
17
 
18
- // 缓存有效菜单列表
19
- const validMenus = useMemo(() => {
20
- return currentUser?.menus?.filter((item: any) => item.status === 'Y') || [];
21
- }, [currentUser?.menus]);
22
-
23
- // 缓存当前路由路径(去除参数)
18
+ // 当前路由路径(去除动态参数片段)
24
19
  const currentRoutePath = useMemo(() => {
25
20
  if (!pathname) return '';
21
+ const normalized = pathname.endsWith('/') ? pathname.slice(0, -1) : pathname;
26
22
 
27
- // 去除路径末尾的斜杠
28
- const handlePathname = pathname.endsWith('/') ? pathname.slice(0, -1) : pathname;
23
+ // 过滤掉通配符 '*':React Router v6 的 catch-all 路由会把剩余路径存入 params['*'],
24
+ // 它不对应独立的 URL 段,计入 paramCount 会导致错误切割(如 /aaa '')
25
+ const segmentParamCount = Object.keys(params || {}).filter((k) => k !== '*').length;
26
+ if (segmentParamCount === 0) return normalized;
29
27
 
30
- const paramCount = Object.keys(params || {}).length;
31
- const splitPath = handlePathname.split('/');
32
-
33
- return splitPath.slice(0, splitPath.length - paramCount).join('/');
28
+ const parts = normalized.split('/');
29
+ const sliceEnd = parts.length - segmentParamCount;
30
+ // 安全兜底:切割结果不能比根路径更短
31
+ return sliceEnd > 0 ? parts.slice(0, sliceEnd).join('/') : normalized;
34
32
  }, [pathname, params]);
35
33
 
36
- // 检查当前路由是否存在于路由配置中
34
+ /**
35
+ * 后端按权限下发菜单,返回的即为当前用户有权访问的全部菜单(item.status === '1' || item.status === 'Y')。
36
+ * 无需再区分「存在性」与「权限」两份列表。
37
+ */
38
+ const validMenus = useMemo(
39
+ () => currentUser?.menus?.filter((item: any) => item.status === '1' || item.status === 'Y') ?? [],
40
+ [currentUser?.menus],
41
+ );
42
+
43
+ /**
44
+ * 路由是否在当前用户的菜单中存在。
45
+ * 后端已按权限过滤,此处同时表达「存在」与「有权访问」两层含义。
46
+ */
37
47
  const routeExists = useMemo(() => {
38
- // 没有路由,返回 true,不显示404,因为会重定向到首页
39
- if (!currentRoutePath) return true;
40
-
41
- // 白名单路由始终存在
42
- if (whiteListRoutes.includes(currentRoutePath)) {
43
- return true;
44
- }
45
-
46
- return currentUser?.menus?.some((menu) => menu.path === currentRoutePath);
47
- }, [currentRoutePath]);
48
-
49
- // 检查当前路由是否有权限
50
- const hasCurrentRouteAuth = useMemo(() => {
51
- // 如果路由不存在,返回 true,让它走到404处理
52
- if (!routeExists) {
53
- return true;
54
- }
55
-
56
- // 如果没有有效菜单或路径为空,返回 true跳转到无任何权限页面
57
- if (!validMenus.length || !currentRoutePath) {
58
- return true;
59
- }
60
-
61
- // 白名单路由,无需权限检查
62
- if (whiteListRoutes.includes(currentRoutePath)) {
63
- return true;
64
- }
65
-
66
- // 检查用户是否有当前路由权限
48
+ if (!currentRoutePath || whiteListRoutes.includes(currentRoutePath)) return true;
67
49
  return validMenus.some((menu) => menu.path === currentRoutePath);
68
- }, [validMenus, currentRoutePath, routeExists]);
69
-
70
- // 检查用户状态,返回应该重定向的页面
50
+ }, [currentRoutePath, validMenus]);
51
+
52
+ /**
53
+ * 与 routeExists 保持一致:路由存在即有权限。
54
+ * 保留此字段供 getChildren 等调用方兼容,不单独计算。
55
+ */
56
+ const hasCurrentRouteAuth = routeExists;
57
+
58
+ /**
59
+ * 检查用户状态,返回应重定向的错误页路径;null 表示状态正常无需重定向。
60
+ *
61
+ * 优先级:
62
+ * 401(未登录)> 400(已禁用)> 404(路由不在菜单中)> 401(无系统权限码)
63
+ *
64
+ * 后端已按权限下发菜单,路由不在菜单中即无权限,统一用 404 表达,无需单独的 403。
65
+ */
71
66
  const getUserStatusRedirect = useMemo<UserStatusRedirect | null>(() => {
72
- // 优先检查路由是否存在,如果不存在则返回404
73
- if (!routeExists) {
74
- return '/404';
75
- }
76
-
77
- // 系统没有用户 -> 401
78
- if (!currentUser || Object.keys(currentUser).length === 0) {
79
- return '/401';
80
- }
67
+ // 1. 用户未登录(无 userId)→ 401
68
+ if (!currentUser?.userId) return '/401';
69
+
70
+ // 2. 用户账号被禁用 → 400
71
+ if (currentUser.status?.toUpperCase() === 'N') return '/400';
81
72
 
82
- // 用户被禁用 -> 400
83
- if (currentUser.status?.toUpperCase() === 'N') {
84
- return '/400';
85
- }
73
+ // 3. 路由不在用户菜单中(后端未下发 = 无权限)→ 404
74
+ // 后端已按权限过滤,不存在即无权访问,无需额外判 403
75
+ if (!routeExists) return '/404';
86
76
 
87
- // 用户没有任何权限 -> 401
88
- if (!currentUser.permissions || currentUser.permissions.length === 0) {
89
- return '/401';
90
- }
91
-
92
- // 没有当前页面权限 -> 403
93
- if (!hasCurrentRouteAuth) {
94
- return '/403';
95
- }
77
+ // 4. 用户无任何系统权限码 401
78
+ if (!currentUser.permissions?.length) return '/401';
96
79
 
97
- return null; // 用户状态正常
98
- }, [currentUser, validMenus, hasCurrentRouteAuth, routeExists]);
80
+ return null;
81
+ }, [currentUser, routeExists]);
99
82
 
100
- // 重定向到403页面
83
+ /** 导航到指定异常页(避免重复跳转到当前所在页) */
101
84
  const redirectToPage = useMemoizedFn((path: UserStatusRedirect) => {
102
- if (currentRoutePath !== `/${path}`) {
103
- history.push(`/${path}`);
85
+ // path 已含前缀 '/'(如 '/403'),直接 push,避免产生 '//403'
86
+ if (currentRoutePath !== path) {
87
+ history.push(path);
104
88
  }
105
89
  });
106
90
 
107
- // 检查特定路径权限
91
+ /** 检查指定路径是否在当前用户有效权限内 */
108
92
  const checkPathAuth = useMemoizedFn((path: string) => {
109
93
  return validMenus.some((menu: any) => menu.path === path);
110
94
  });
@@ -8,7 +8,7 @@ var _default = exports.default = {
8
8
  "cfmmUI.common.userDisable.title": "User Disable",
9
9
  "cfmmUI.common.userDisable.Message": "User Has Been Disabled, Please Contact Your Administrator",
10
10
  "cfmmUI.common.userNoPermission.title": "User No Permission",
11
- "cfmmUI.common.userNoPermission.Message": "User Has No Permission, Please Contact Your Administrator",
11
+ "cfmmUI.common.userNoPermission.Message": "User Has No Any Permission, Please Contact Your Administrator",
12
12
  "cfmmUI.common.UserNoPagePermission.title": "User Has No Page Permission",
13
13
  "cfmmUI.common.UserNoPagePermission.Message": "User Has No Page Permission, Please Click The Left Menu To Switch Other Pages, Still To Contact Your Administrator",
14
14
  "cfmmUI.common.useOtherUserLogin.title": "Use Other User Login"
@@ -8,7 +8,7 @@ var _default = exports.default = {
8
8
  "cfmmUI.common.userDisable.title": "用户禁用",
9
9
  "cfmmUI.common.userDisable.Message": "用户已被禁用,请与管理员联系",
10
10
  "cfmmUI.common.userNoPermission.title": "用户无权限",
11
- "cfmmUI.common.userNoPermission.Message": "用户无任务权限,请与管理员联系",
11
+ "cfmmUI.common.userNoPermission.Message": "用户无任何权限,请与管理员联系",
12
12
  "cfmmUI.common.UserNoPagePermission.title": "用户无该页面权限",
13
13
  "cfmmUI.common.UserNoPagePermission.Message": "用户无该页面权限,请点击左侧菜单切换其他页面,仍要访问与管理员联系",
14
14
  "cfmmUI.common.useOtherUserLogin.title": "使用其他用户登陆"
@@ -1093,8 +1093,9 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
1093
1093
  [rowKey]: editRow?.[rowKey],
1094
1094
  });
1095
1095
  if (success) {
1096
- actionRef.current?.reload();
1097
1096
  setEditRow(null);
1097
+ actionRef.current?.reload();
1098
+ updateFormRef.current?.resetFields();
1098
1099
  }
1099
1100
  return success;
1100
1101
  })}
@@ -1134,6 +1135,7 @@ function CrudTable<T extends Record<string, any>, U = {}, C = {}>(
1134
1135
  actionRef.current?.reload();
1135
1136
  setEditRow(null);
1136
1137
  setUpdateModalOpen(false);
1138
+ updateFormRef.current?.resetFields();
1137
1139
  }
1138
1140
  return success;
1139
1141
  })}
@@ -1,6 +1,3 @@
1
- // @ts-nocheck
2
- // This file is generated by Umi automatically
3
- // DO NOT CHANGE IT MANUALLY!
4
1
  import { Empty, Select, Spin } from 'antd';
5
2
  import React, {
6
3
  ForwardedRef,
@@ -19,6 +16,18 @@ import { MySelectProps } from '../types';
19
16
 
20
17
  const { Option } = Select;
21
18
 
19
+ /** 无对象、无键,或每个键的值均为 undefined / null / 空串(含纯空白)时视为“无搜索条件” */
20
+ function isSearchObjectAllEmpty(obj?: { [key: string]: string | undefined }): boolean {
21
+ if (!obj) return true;
22
+ const keys = Object.keys(obj);
23
+ if (keys.length === 0) return true;
24
+ return keys.every((key) => {
25
+ const v = obj[key];
26
+ if (v === undefined || v === null) return true;
27
+ return String(v).trim() === '';
28
+ });
29
+ }
30
+
22
31
  const MySelect = <T,>(props: MySelectProps<T>, ref: ForwardedRef<any>) => {
23
32
  const {
24
33
  readonly,
@@ -105,7 +114,7 @@ const MySelect = <T,>(props: MySelectProps<T>, ref: ForwardedRef<any>) => {
105
114
  setListData([]);
106
115
  let params = showSearch ? { ...searchValue, ...otherSearchValue } : otherSearchValue;
107
116
  // 如果显示全部,则不分页
108
- params = showAllList ? params : { pageIndex: 1, pageSize: 20, ...params };
117
+ params = showAllList ? params : { pageIndex: 1, pageSize, ...params };
109
118
  const response = await request(params);
110
119
  if (response.rows && response.rows.length > 0) {
111
120
  // 如果有搜索值,则不添加回显值
@@ -124,7 +133,7 @@ const MySelect = <T,>(props: MySelectProps<T>, ref: ForwardedRef<any>) => {
124
133
  };
125
134
 
126
135
  useEffect(() => {
127
- if (Array.isArray(localListData) && !showSearch) {
136
+ if (Array.isArray(localListData) && isSearchObjectAllEmpty(searchValue)) {
128
137
  setListData(localListData);
129
138
  return;
130
139
  }
@@ -19,7 +19,7 @@ export async function queryAllPermissions() {
19
19
  }
20
20
 
21
21
  const checkStatus = (status: string): boolean => {
22
- return status.toUpperCase() === 'Y';
22
+ return status === '1' || status === 'Y';
23
23
  }
24
24
 
25
25
  /**
@@ -15,96 +15,80 @@ export const useRouteAuth = (currentUser?: CurrentUser) => {
15
15
  const params = useParams();
16
16
  const { pathname } = useLocation();
17
17
 
18
- // 缓存有效菜单列表
19
- const validMenus = useMemo(() => {
20
- return currentUser?.menus?.filter((item: any) => item.status === 'Y') || [];
21
- }, [currentUser?.menus]);
22
-
23
- // 缓存当前路由路径(去除参数)
18
+ // 当前路由路径(去除动态参数片段)
24
19
  const currentRoutePath = useMemo(() => {
25
20
  if (!pathname) return '';
21
+ const normalized = pathname.endsWith('/') ? pathname.slice(0, -1) : pathname;
26
22
 
27
- // 去除路径末尾的斜杠
28
- const handlePathname = pathname.endsWith('/') ? pathname.slice(0, -1) : pathname;
23
+ // 过滤掉通配符 '*':React Router v6 的 catch-all 路由会把剩余路径存入 params['*'],
24
+ // 它不对应独立的 URL 段,计入 paramCount 会导致错误切割(如 /aaa '')
25
+ const segmentParamCount = Object.keys(params || {}).filter((k) => k !== '*').length;
26
+ if (segmentParamCount === 0) return normalized;
29
27
 
30
- const paramCount = Object.keys(params || {}).length;
31
- const splitPath = handlePathname.split('/');
32
-
33
- return splitPath.slice(0, splitPath.length - paramCount).join('/');
28
+ const parts = normalized.split('/');
29
+ const sliceEnd = parts.length - segmentParamCount;
30
+ // 安全兜底:切割结果不能比根路径更短
31
+ return sliceEnd > 0 ? parts.slice(0, sliceEnd).join('/') : normalized;
34
32
  }, [pathname, params]);
35
33
 
36
- // 检查当前路由是否存在于路由配置中
34
+ /**
35
+ * 后端按权限下发菜单,返回的即为当前用户有权访问的全部菜单(item.status === '1' || item.status === 'Y')。
36
+ * 无需再区分「存在性」与「权限」两份列表。
37
+ */
38
+ const validMenus = useMemo(
39
+ () => currentUser?.menus?.filter((item: any) => item.status === '1' || item.status === 'Y') ?? [],
40
+ [currentUser?.menus],
41
+ );
42
+
43
+ /**
44
+ * 路由是否在当前用户的菜单中存在。
45
+ * 后端已按权限过滤,此处同时表达「存在」与「有权访问」两层含义。
46
+ */
37
47
  const routeExists = useMemo(() => {
38
- // 没有路由,返回 true,不显示404,因为会重定向到首页
39
- if (!currentRoutePath) return true;
40
-
41
- // 白名单路由始终存在
42
- if (whiteListRoutes.includes(currentRoutePath)) {
43
- return true;
44
- }
45
-
46
- return currentUser?.menus?.some((menu) => menu.path === currentRoutePath);
47
- }, [currentRoutePath]);
48
-
49
- // 检查当前路由是否有权限
50
- const hasCurrentRouteAuth = useMemo(() => {
51
- // 如果路由不存在,返回 true,让它走到404处理
52
- if (!routeExists) {
53
- return true;
54
- }
55
-
56
- // 如果没有有效菜单或路径为空,返回 true跳转到无任何权限页面
57
- if (!validMenus.length || !currentRoutePath) {
58
- return true;
59
- }
60
-
61
- // 白名单路由,无需权限检查
62
- if (whiteListRoutes.includes(currentRoutePath)) {
63
- return true;
64
- }
65
-
66
- // 检查用户是否有当前路由权限
48
+ if (!currentRoutePath || whiteListRoutes.includes(currentRoutePath)) return true;
67
49
  return validMenus.some((menu) => menu.path === currentRoutePath);
68
- }, [validMenus, currentRoutePath, routeExists]);
69
-
70
- // 检查用户状态,返回应该重定向的页面
50
+ }, [currentRoutePath, validMenus]);
51
+
52
+ /**
53
+ * 与 routeExists 保持一致:路由存在即有权限。
54
+ * 保留此字段供 getChildren 等调用方兼容,不单独计算。
55
+ */
56
+ const hasCurrentRouteAuth = routeExists;
57
+
58
+ /**
59
+ * 检查用户状态,返回应重定向的错误页路径;null 表示状态正常无需重定向。
60
+ *
61
+ * 优先级:
62
+ * 401(未登录)> 400(已禁用)> 404(路由不在菜单中)> 401(无系统权限码)
63
+ *
64
+ * 后端已按权限下发菜单,路由不在菜单中即无权限,统一用 404 表达,无需单独的 403。
65
+ */
71
66
  const getUserStatusRedirect = useMemo<UserStatusRedirect | null>(() => {
72
- // 优先检查路由是否存在,如果不存在则返回404
73
- if (!routeExists) {
74
- return '/404';
75
- }
76
-
77
- // 系统没有用户 -> 401
78
- if (!currentUser || Object.keys(currentUser).length === 0) {
79
- return '/401';
80
- }
67
+ // 1. 用户未登录(无 userId)→ 401
68
+ if (!currentUser?.userId) return '/401';
69
+
70
+ // 2. 用户账号被禁用 → 400
71
+ if (currentUser.status?.toUpperCase() === 'N') return '/400';
81
72
 
82
- // 用户被禁用 -> 400
83
- if (currentUser.status?.toUpperCase() === 'N') {
84
- return '/400';
85
- }
73
+ // 3. 路由不在用户菜单中(后端未下发 = 无权限)→ 404
74
+ // 后端已按权限过滤,不存在即无权访问,无需额外判 403
75
+ if (!routeExists) return '/404';
86
76
 
87
- // 用户没有任何权限 -> 401
88
- if (!currentUser.permissions || currentUser.permissions.length === 0) {
89
- return '/401';
90
- }
91
-
92
- // 没有当前页面权限 -> 403
93
- if (!hasCurrentRouteAuth) {
94
- return '/403';
95
- }
77
+ // 4. 用户无任何系统权限码 401
78
+ if (!currentUser.permissions?.length) return '/401';
96
79
 
97
- return null; // 用户状态正常
98
- }, [currentUser, validMenus, hasCurrentRouteAuth, routeExists]);
80
+ return null;
81
+ }, [currentUser, routeExists]);
99
82
 
100
- // 重定向到403页面
83
+ /** 导航到指定异常页(避免重复跳转到当前所在页) */
101
84
  const redirectToPage = useMemoizedFn((path: UserStatusRedirect) => {
102
- if (currentRoutePath !== `/${path}`) {
103
- history.push(`/${path}`);
85
+ // path 已含前缀 '/'(如 '/403'),直接 push,避免产生 '//403'
86
+ if (currentRoutePath !== path) {
87
+ history.push(path);
104
88
  }
105
89
  });
106
90
 
107
- // 检查特定路径权限
91
+ /** 检查指定路径是否在当前用户有效权限内 */
108
92
  const checkPathAuth = useMemoizedFn((path: string) => {
109
93
  return validMenus.some((menu: any) => menu.path === path);
110
94
  });
@@ -2,7 +2,7 @@ export default {
2
2
  "cfmmUI.common.userDisable.title": "User Disable",
3
3
  "cfmmUI.common.userDisable.Message": "User Has Been Disabled, Please Contact Your Administrator",
4
4
  "cfmmUI.common.userNoPermission.title": "User No Permission",
5
- "cfmmUI.common.userNoPermission.Message": "User Has No Permission, Please Contact Your Administrator",
5
+ "cfmmUI.common.userNoPermission.Message": "User Has No Any Permission, Please Contact Your Administrator",
6
6
  "cfmmUI.common.UserNoPagePermission.title": "User Has No Page Permission",
7
7
  "cfmmUI.common.UserNoPagePermission.Message": "User Has No Page Permission, Please Click The Left Menu To Switch Other Pages, Still To Contact Your Administrator",
8
8
  "cfmmUI.common.useOtherUserLogin.title": "Use Other User Login"
@@ -2,7 +2,7 @@ export default {
2
2
  "cfmmUI.common.userDisable.title": "用户禁用",
3
3
  "cfmmUI.common.userDisable.Message": "用户已被禁用,请与管理员联系",
4
4
  "cfmmUI.common.userNoPermission.title": "用户无权限",
5
- "cfmmUI.common.userNoPermission.Message": "用户无任务权限,请与管理员联系",
5
+ "cfmmUI.common.userNoPermission.Message": "用户无任何权限,请与管理员联系",
6
6
  "cfmmUI.common.UserNoPagePermission.title": "用户无该页面权限",
7
7
  "cfmmUI.common.UserNoPagePermission.Message": "用户无该页面权限,请点击左侧菜单切换其他页面,仍要访问与管理员联系",
8
8
  "cfmmUI.common.useOtherUserLogin.title": "使用其他用户登陆"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cfmm/umi-plugins-ui-v2",
3
3
  "author": "ysj <411367308@qq.com>",
4
- "version": "0.0.20",
4
+ "version": "0.0.22",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/cjs/index.d.ts",
7
7
  "publishConfig": {