From 03ffdd67fc4c40f3e9443931a0aa55e508182873 Mon Sep 17 00:00:00 2001
From: wupengfei <834520024@qq.com>
Date: 星期三, 06 八月 2025 17:00:06 +0800
Subject: [PATCH] feat: 字典

---
 src/constants/user.ts                                                 |    4 
 src/views/DictionaryManage/DictionaryCategoryManage.vue               |  165 +++++
 src/constants/dic.ts                                                  |   23 
 src/hooks/dic.ts                                                      |  111 +++
 src/views/DictionaryManage/components/AddOrEditDictionaryCategory.vue |   90 ++
 .eslintrc-auto-import.json                                            |    2 
 src/services/api/typings.d.ts                                         |  429 +++++++++++++
 src/views/DictionaryManage/DataDictionary.vue                         |  169 ++---
 src/services/api/dictionary.ts                                        |  118 +++
 src/views/Permission/OperationUserManage.vue                          |  175 +++++
 src/services/api/enterprise.ts                                        |   18 
 types/api.d.ts                                                        |   12 
 /dev/null                                                             |  147 ----
 src/services/api/index.ts                                             |    8 
 src/services/api/role.ts                                              |   45 +
 src/views/Permission/components/SetOperationUserRoleDialog.vue        |   61 +
 src/services/api/userInfo.ts                                          |   66 ++
 src/views/System/ModuleManage.vue                                     |   29 
 auto-imports.d.ts                                                     |    6 
 src/views/DictionaryManage/components/AddOrEditDictionaryDialog.vue   |  142 ++++
 src/constants/apiEnum.ts                                              |   12 
 src/constants/index.ts                                                |    2 
 src/utils/common/common.ts                                            |    9 
 23 files changed, 1,569 insertions(+), 274 deletions(-)

diff --git a/.eslintrc-auto-import.json b/.eslintrc-auto-import.json
index 9e9f385..edae8cc 100644
--- a/.eslintrc-auto-import.json
+++ b/.eslintrc-auto-import.json
@@ -26,6 +26,8 @@
     "EnumRoleWebApiDataPower": true,
     "EnumRoleWebApiDataPowerText": true,
     "EnumRoleWebApiDataPowerTextForFilter": true,
+    "EnumUserInfoStatus": true,
+    "EnumUserInfoStatusText": true,
     "EnumUserType": true,
     "EnumUserTypeText": true,
     "ExtractDefaultPropTypes": true,
diff --git a/auto-imports.d.ts b/auto-imports.d.ts
index 92e91a2..b150c9f 100644
--- a/auto-imports.d.ts
+++ b/auto-imports.d.ts
@@ -32,6 +32,8 @@
   const EnumRoleWebApiDataPower: typeof import('./src/constants/apiEnum')['EnumRoleWebApiDataPower']
   const EnumRoleWebApiDataPowerText: typeof import('./src/constants/apiEnumText')['EnumRoleWebApiDataPowerText']
   const EnumRoleWebApiDataPowerTextForFilter: typeof import('./src/constants/apiEnumText')['EnumRoleWebApiDataPowerTextForFilter']
+  const EnumUserInfoStatus: typeof import('./src/constants/apiEnum')['EnumUserInfoStatus']
+  const EnumUserInfoStatusText: typeof import('./src/constants/user')['EnumUserInfoStatusText']
   const EnumUserType: typeof import('./src/constants/apiEnum')['EnumUserType']
   const EnumUserTypeText: typeof import('./src/constants/apiEnumText')['EnumUserTypeText']
   const EnumWebApiMethod: typeof import('./src/constants/apiEnum')['EnumWebApiMethod']
@@ -163,7 +165,7 @@
   export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
   import('vue')
   // @ts-ignore
-  export type { EnumClientType, EnumMenuType, EnumMenuVisitLevel, EnumPagedListOrder, EnumResourceController, EnumResourceMethod, EnumRoleWebApiDataPower, EnumUserType, EnumClientType, EnumMenuType, EnumMenuVisitLevel, EnumPagedListOrder, EnumResourceController, EnumResourceMethod, EnumRoleWebApiDataPower, EnumUserType } from './src/constants/apiEnum'
+  export type { EnumClientType, EnumMenuType, EnumMenuVisitLevel, EnumPagedListOrder, EnumResourceController, EnumResourceMethod, EnumRoleWebApiDataPower, EnumUserInfoStatus, EnumUserType, EnumClientType, EnumMenuType, EnumMenuVisitLevel, EnumPagedListOrder, EnumResourceController, EnumResourceMethod, EnumRoleWebApiDataPower, EnumUserInfoStatus, EnumUserType } from './src/constants/apiEnum'
   import('./src/constants/apiEnum')
   // @ts-ignore
   export type { FlexWorkerEleSignEnum, FlexTaskWorkerHireEnum, FlexWorkerEleSignEnum, FlexTaskWorkerHireEnum } from './src/constants/cPerson'
@@ -221,6 +223,8 @@
     readonly EnumRoleWebApiDataPower: UnwrapRef<typeof import('./src/constants/apiEnum')['EnumRoleWebApiDataPower']>
     readonly EnumRoleWebApiDataPowerText: UnwrapRef<typeof import('./src/constants/apiEnumText')['EnumRoleWebApiDataPowerText']>
     readonly EnumRoleWebApiDataPowerTextForFilter: UnwrapRef<typeof import('./src/constants/apiEnumText')['EnumRoleWebApiDataPowerTextForFilter']>
+    readonly EnumUserInfoStatus: UnwrapRef<typeof import('./src/constants/apiEnum')['EnumUserInfoStatus']>
+    readonly EnumUserInfoStatusText: UnwrapRef<typeof import('./src/constants/user')['EnumUserInfoStatusText']>
     readonly EnumUserType: UnwrapRef<typeof import('./src/constants/apiEnum')['EnumUserType']>
     readonly EnumUserTypeText: UnwrapRef<typeof import('./src/constants/apiEnumText')['EnumUserTypeText']>
     readonly FastButtonMap: UnwrapRef<typeof import('./src/constants/module')['FastButtonMap']>
diff --git a/src/constants/apiEnum.ts b/src/constants/apiEnum.ts
index 87b2651..8069622 100644
--- a/src/constants/apiEnum.ts
+++ b/src/constants/apiEnum.ts
@@ -53,6 +53,10 @@
   Resource = 3,
   /**鐢ㄦ埛瑙掕壊 */
   Role = 4,
+  /**鐢ㄦ埛淇℃伅 */
+  UserInfo = 5,
+  /**浼佷笟淇℃伅 */
+  Enterprise = 6,
 }
 
 /** 璧勬簮璇锋眰鏂瑰紡 */
@@ -83,6 +87,14 @@
   All = 999,
 }
 
+/** 鐢ㄦ埛淇℃伅鐘舵�� */
+export enum EnumUserInfoStatus {
+  /**姝e父 */
+  Normal = 10,
+  /**绂佺敤 */
+  Disabled = 100,
+}
+
 /** 鐢ㄦ埛绫诲瀷 */
 export enum EnumUserType {
   /**涓汉 */
diff --git a/src/constants/dic.ts b/src/constants/dic.ts
index 3ad3406..534792d 100644
--- a/src/constants/dic.ts
+++ b/src/constants/dic.ts
@@ -1,23 +1,14 @@
-export enum SearchType {
+export enum CategoryCode {
   /**韬唤 */
-  Identity = 210,
+  Identity = '10',
   /**瀛﹀巻 */
-  Education = 220,
+  Education = '20',
   /**宀椾綅 */
-  Position = 230,
+  Position = '30',
   /**璇佷功绫诲瀷 */
-  CertificateType = 240,
+  CertificateType = '40',
   /**绂忓埄 */
-  Welfare = 250,
+  Welfare = '50',
   /**琛屼笟绫诲瀷 */
-  IndustryCategory = 260,
+  IndustryCategory = '60',
 }
-
-export const SearchTypeText = {
-  [SearchType.Identity]: '韬唤',
-  [SearchType.Education]: '瀛﹀巻',
-  [SearchType.Position]: '宀椾綅',
-  [SearchType.CertificateType]: '璇佷功绫诲瀷',
-  [SearchType.Welfare]: '绂忓埄',
-  [SearchType.IndustryCategory]: '琛屼笟绫诲瀷',
-};
diff --git a/src/constants/index.ts b/src/constants/index.ts
index 1849c34..b179761 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -14,3 +14,5 @@
 export * from './cPerson';
 export * from './apiEnum';
 export * from './apiEnumText';
+export * from './user';
+export * from './dic';
diff --git a/src/constants/user.ts b/src/constants/user.ts
new file mode 100644
index 0000000..588b889
--- /dev/null
+++ b/src/constants/user.ts
@@ -0,0 +1,4 @@
+export const EnumUserInfoStatusText = {
+  [EnumUserInfoStatus.Normal]: '姝e父',
+  [EnumUserInfoStatus.Disabled]: '绂佺敤',
+};
diff --git a/src/hooks/dic.ts b/src/hooks/dic.ts
index 25dd1c8..8935320 100644
--- a/src/hooks/dic.ts
+++ b/src/hooks/dic.ts
@@ -1,8 +1,109 @@
 import { useQuery, useQueryClient } from '@tanstack/vue-query';
-import { SearchType } from '@/constants';
+import * as dictionaryServices from '@/services/api/dictionary';
 
-type UseSearchSettingTypeOptions = {
-  searchType: number;
-  belongType?: number;
-  onSuccess?: (data: any[]) => any;
+export function useGetDictionaryCategorySelect() {
+  const { data: dictionaryCategoryList, refetch } = useQuery({
+    queryKey: ['dictionaryServices/getDictionaryCategorySelect'],
+    queryFn: async () => {
+      let res = await dictionaryServices.getDictionaryCategorySelect({}, { showLoading: false });
+      return res.map((x) => ({
+        ...x,
+        fieldNamesMap: x.data.fieldNames ? JSON.parse(x.data.fieldNames) : {},
+      }));
+    },
+    placeholderData: () =>
+      [] as API.SelectQueryResultOptionGuidGetDictionaryCategorySelectQueryOption[],
+  });
+
+  const queryClient = useQueryClient();
+
+  function ensureQueryData() {
+    return queryClient.ensureQueryData<
+      API.SelectQueryResultOptionGuidGetDictionaryCategorySelectQueryOption[]
+    >({
+      queryKey: ['dictionaryServices/getDictionaryCategorySelect'],
+    });
+  }
+
+  function getDictionaryCategoryById(id: string) {
+    return dictionaryCategoryList.value.find((x) => x.value === id);
+  }
+
+  function getDictionaryCategoryByCode(code: string) {
+    return dictionaryCategoryList.value.find((x) => x.code === code);
+  }
+
+  function getDictionaryCategoryNameByCode(code: string) {
+    return getDictionaryCategoryByCode(code)?.label ?? '';
+  }
+
+  return {
+    dictionaryCategoryList,
+    ensureQueryData,
+    getDictionaryCategoryById,
+    getDictionaryCategoryNameByCode,
+    getDictionaryCategoryByCode,
+  };
+}
+
+type UseDictionaryDataSelectOptions = {
+  categoryId?: MaybeRef<string>;
+  categoryCode?: MaybeRef<string>;
 };
+
+export function useDictionaryDataSelect({
+  categoryId,
+  categoryCode,
+}: UseDictionaryDataSelectOptions) {
+  const { data: dictionaryDataList, refetch } = useQuery({
+    queryKey: ['dictionaryServices/getDictionaryDataSelect'],
+    queryFn: async () => {
+      let res = await dictionaryServices.getDictionaryDataSelect(
+        {
+          categoryId: unref(categoryId),
+          categoryCode: unref(categoryCode),
+        },
+        { showLoading: false }
+      );
+      return res.map((x) => ({
+        ...x,
+        code: x.data?.code ?? '',
+      }));
+    },
+    placeholderData: () =>
+      [] as API.SelectQueryResultOptionGuidGetDictionaryDataSelectQueryResultOption[],
+
+    enabled: !!unref(categoryId) || !!unref(categoryCode),
+  });
+
+  function getDictionaryDataNameById(id: string) {
+    return dictionaryDataList.value?.find((x) => x.value === id)?.label;
+  }
+
+  function getDictionaryDataByCode(code: string) {
+    return dictionaryDataList.value?.find((x) => x.code === code);
+  }
+
+  function getDictionaryDataNameByCode(code: string) {
+    return getDictionaryDataByCode(code)?.label ?? '';
+  }
+
+  const queryClient = useQueryClient();
+
+  function ensureQueryData() {
+    return queryClient.ensureQueryData<
+      API.SelectQueryResultOptionGuidGetDictionaryDataSelectQueryResultOption[]
+    >({
+      queryKey: ['dictionaryServices/getDictionaryDataSelect'],
+    });
+  }
+
+  return {
+    dictionaryDataList,
+    ensureQueryData,
+    refetch,
+    getDictionaryDataNameById,
+    getDictionaryDataNameByCode,
+    getDictionaryDataByCode,
+  };
+}
diff --git a/src/services/api/dictionary.ts b/src/services/api/dictionary.ts
index 961750b..22cee24 100644
--- a/src/services/api/dictionary.ts
+++ b/src/services/api/dictionary.ts
@@ -2,7 +2,60 @@
 // @ts-ignore
 import { request } from '@/utils/request';
 
-/** 鑾峰彇瀛楀吀鏁版嵁鍒嗛〉鍒楄〃 POST /api/main/dictionary/getDictionaryDatas */
+/** 鍒犻櫎鏁版嵁瀛楀吀绫诲埆 DELETE /api/main/dictionary/deleteDictionaryCategory */
+export async function deleteDictionaryCategory(
+  body: API.DeleteDictionaryCategoryCommand,
+  options?: API.RequestConfig
+) {
+  return request<number>('/api/main/dictionary/deleteDictionaryCategory', {
+    method: 'DELETE',
+    headers: {
+      'Content-Type': 'application/json-patch+json',
+    },
+    data: body,
+    ...(options || {}),
+  });
+}
+
+/** 鑾峰彇鏁版嵁瀛楀吀绫诲埆鍒嗛〉鍒楄〃鏁版嵁 POST /api/main/dictionary/getDictionaryCategories */
+export async function getDictionaryCategories(
+  body: API.GetDictionaryCategoriesQuery,
+  options?: API.RequestConfig
+) {
+  return request<API.PagedListQueryResultGetDictionaryCategoriesQueryResultItem>(
+    '/api/main/dictionary/getDictionaryCategories',
+    {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json-patch+json',
+      },
+      data: body,
+      ...(options || {}),
+    }
+  );
+}
+
+/** 鏌ヨ鏁版嵁瀛楀吀绫诲埆閫夋嫨鍣ㄦ暟鎹� GET /api/main/dictionary/getDictionaryCategorySelect */
+export async function getDictionaryCategorySelect(
+  // 鍙犲姞鐢熸垚鐨凱aram绫诲瀷 (闈瀊ody鍙傛暟swagger榛樿娌℃湁鐢熸垚瀵硅薄)
+  params: API.APIgetDictionaryCategorySelectParams,
+  options?: API.RequestConfig
+) {
+  return request<API.SelectQueryResultOptionGuidGetDictionaryCategorySelectQueryOption[]>(
+    '/api/main/dictionary/getDictionaryCategorySelect',
+    {
+      method: 'GET',
+      params: {
+        ...params,
+        request: undefined,
+        ...params['request'],
+      },
+      ...(options || {}),
+    }
+  );
+}
+
+/** 鑾峰彇鏁版嵁瀛楀吀鍒嗛〉鍒楄〃鏁版嵁 POST /api/main/dictionary/getDictionaryDatas */
 export async function getDictionaryDatas(
   body: API.GetDictionaryDatasQuery,
   options?: API.RequestConfig
@@ -19,3 +72,66 @@
     }
   );
 }
+
+/** 鏌ヨ鏁版嵁瀛楀吀閫夋嫨鍣� GET /api/main/dictionary/getDictionaryDataSelect */
+export async function getDictionaryDataSelect(
+  // 鍙犲姞鐢熸垚鐨凱aram绫诲瀷 (闈瀊ody鍙傛暟swagger榛樿娌℃湁鐢熸垚瀵硅薄)
+  params: API.APIgetDictionaryDataSelectParams,
+  options?: API.RequestConfig
+) {
+  return request<API.SelectQueryResultOptionGuidGetDictionaryDataSelectQueryResultOption[]>(
+    '/api/main/dictionary/getDictionaryDataSelect',
+    {
+      method: 'GET',
+      params: {
+        ...params,
+      },
+      ...(options || {}),
+    }
+  );
+}
+
+/** 淇濆瓨鏁版嵁瀛楀吀绫诲埆 POST /api/main/dictionary/saveDictionaryCategory */
+export async function saveDictionaryCategory(
+  body: API.SaveDictionaryCategoryCommand,
+  options?: API.RequestConfig
+) {
+  return request<string>('/api/main/dictionary/saveDictionaryCategory', {
+    method: 'POST',
+    headers: {
+      'Content-Type': 'application/json-patch+json',
+    },
+    data: body,
+    ...(options || {}),
+  });
+}
+
+/** 淇濆瓨鏁版嵁瀛楀吀 POST /api/main/dictionary/saveDictionaryData */
+export async function saveDictionaryData(
+  body: API.SaveDictionaryDataCommand,
+  options?: API.RequestConfig
+) {
+  return request<string>('/api/main/dictionary/saveDictionaryData', {
+    method: 'POST',
+    headers: {
+      'Content-Type': 'application/json-patch+json',
+    },
+    data: body,
+    ...(options || {}),
+  });
+}
+
+/** 璁剧疆鏁版嵁瀛楀吀鏄惁绂佺敤 PUT /api/main/dictionary/setDictionaryDataIsDisabled */
+export async function setDictionaryDataIsDisabled(
+  body: API.SetDictionaryDataIsDisabledCommand,
+  options?: API.RequestConfig
+) {
+  return request<number>('/api/main/dictionary/setDictionaryDataIsDisabled', {
+    method: 'PUT',
+    headers: {
+      'Content-Type': 'application/json-patch+json',
+    },
+    data: body,
+    ...(options || {}),
+  });
+}
diff --git a/src/services/api/enterprise.ts b/src/services/api/enterprise.ts
new file mode 100644
index 0000000..820738d
--- /dev/null
+++ b/src/services/api/enterprise.ts
@@ -0,0 +1,18 @@
+/* eslint-disable */
+// @ts-ignore
+import { request } from '@/utils/request';
+
+/** 鏌ヨ浼佷笟淇℃伅鍒嗛〉鍒楄〃鏁版嵁 POST /api/user/enterprise/getEnterprises */
+export async function getEnterprises(body: API.GetEnterprisesQuery, options?: API.RequestConfig) {
+  return request<API.PagedListQueryResultGetEnterprisesQueryResultItem>(
+    '/api/user/enterprise/getEnterprises',
+    {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json-patch+json',
+      },
+      data: body,
+      ...(options || {}),
+    }
+  );
+}
diff --git a/src/services/api/index.ts b/src/services/api/index.ts
index e96a264..1f801d3 100644
--- a/src/services/api/index.ts
+++ b/src/services/api/index.ts
@@ -2,15 +2,19 @@
 /* eslint-disable */
 // API 鏇存柊鏃堕棿锛�
 // API 鍞竴鏍囪瘑锛�
-import * as dictionary from './dictionary';
 import * as auth from './auth';
 import * as menu from './menu';
+import * as dictionary from './dictionary';
 import * as resource from './resource';
 import * as role from './role';
+import * as userInfo from './userInfo';
+import * as enterprise from './enterprise';
 export default {
-  dictionary,
   auth,
   menu,
+  dictionary,
   resource,
   role,
+  userInfo,
+  enterprise,
 };
diff --git a/src/services/api/role.ts b/src/services/api/role.ts
index 36ede2e..1ed081d 100644
--- a/src/services/api/role.ts
+++ b/src/services/api/role.ts
@@ -41,6 +41,21 @@
   });
 }
 
+/** 鏌ヨ瑙掕壊鐢ㄦ埛鍒楄〃 GET /api/user/role/getRoleUserInfos */
+export async function getRoleUserInfos(
+  // 鍙犲姞鐢熸垚鐨凱aram绫诲瀷 (闈瀊ody鍙傛暟swagger榛樿娌℃湁鐢熸垚瀵硅薄)
+  params: API.APIgetRoleUserInfosParams,
+  options?: API.RequestConfig
+) {
+  return request<API.GetRoleUserInfosQueryResultItem[]>('/api/user/role/getRoleUserInfos', {
+    method: 'GET',
+    params: {
+      ...params,
+    },
+    ...(options || {}),
+  });
+}
+
 /** 淇濆瓨瑙掕壊 POST /api/user/role/saveRole */
 export async function saveRole(body: API.SaveRoleCommand, options?: API.RequestConfig) {
   return request<string>('/api/user/role/saveRole', {
@@ -52,3 +67,33 @@
     ...(options || {}),
   });
 }
+
+/** 璁剧疆瑙掕壊鏄惁绂佺敤 PUT /api/user/role/setRoleIsDisabled */
+export async function setRoleIsDisabled(
+  body: API.SetRoleIsDisabledCommand,
+  options?: API.RequestConfig
+) {
+  return request<number>('/api/user/role/setRoleIsDisabled', {
+    method: 'PUT',
+    headers: {
+      'Content-Type': 'application/json-patch+json',
+    },
+    data: body,
+    ...(options || {}),
+  });
+}
+
+/** 璁剧疆瑙掕壊鐢ㄦ埛 PUT /api/user/role/setRoleUserInfos */
+export async function setRoleUserInfos(
+  body: API.SetRoleUserInfosCommand,
+  options?: API.RequestConfig
+) {
+  return request<number>('/api/user/role/setRoleUserInfos', {
+    method: 'PUT',
+    headers: {
+      'Content-Type': 'application/json-patch+json',
+    },
+    data: body,
+    ...(options || {}),
+  });
+}
diff --git a/src/services/api/typings.d.ts b/src/services/api/typings.d.ts
index 5773566..960421a 100644
--- a/src/services/api/typings.d.ts
+++ b/src/services/api/typings.d.ts
@@ -13,6 +13,20 @@
     request?: GetCurrentLogierMenusQuery;
   }
 
+  interface APIgetDictionaryCategorySelectParams {
+    /** 鏌ヨ鏁版嵁瀛楀吀绫诲埆閫夋嫨鍣ㄦ暟鎹� */
+    request?: GetDictionaryCategorySelectQuery;
+  }
+
+  interface APIgetDictionaryDataSelectParams {
+    /** 绫诲埆Id锛圛d/缂栧彿浜岄�変竴锛� */
+    categoryId?: string;
+    /** 绫诲埆缂栧彿锛圛d/缂栧彿浜岄�変竴锛� */
+    categoryCode?: string;
+    /** 涓婄骇Id */
+    parentId?: string;
+  }
+
   interface APIgetMenuParams {
     /** Id */
     id?: string;
@@ -46,6 +60,22 @@
   interface APIgetRoleParams {
     /** Id */
     id?: string;
+  }
+
+  interface APIgetRoleUserInfosParams {
+    /** 瑙掕壊Id */
+    roleId?: string;
+  }
+
+  interface APIgetUserInfoRolesParams {
+    /** 鐢ㄦ埛Id */
+    userInfoId?: string;
+    /** 瀹㈡埛绔被鍨� */
+    clientType?: EnumClientType;
+  }
+
+  interface DeleteDictionaryCategoryCommand {
+    ids: string[];
   }
 
   interface DeleteMenuCommand {
@@ -103,6 +133,10 @@
     Resource = 3,
     /**鐢ㄦ埛瑙掕壊 */
     Role = 4,
+    /**鐢ㄦ埛淇℃伅 */
+    UserInfo = 5,
+    /**浼佷笟淇℃伅 */
+    Enterprise = 6,
   }
 
   enum EnumResourceMethod {
@@ -129,6 +163,13 @@
     CurrentEnterprise = 30,
     /**鏌ヨ鎵�鏈� */
     All = 999,
+  }
+
+  enum EnumUserInfoStatus {
+    /**姝e父 */
+    Normal = 10,
+    /**绂佺敤 */
+    Disabled = 100,
   }
 
   enum EnumUserType {
@@ -289,6 +330,100 @@
     timestamp?: number;
   }
 
+  interface FriendlyResultListGetRoleUserInfosQueryResultItem {
+    /** 璺熻釜Id */
+    traceId?: string;
+    /** 鐘舵�佺爜 */
+    code?: number;
+    /** 閿欒鐮� */
+    errorCode?: string;
+    /** 鏁版嵁 */
+    data?: GetRoleUserInfosQueryResultItem[];
+    /** 鎵ц鎴愬姛 */
+    success?: boolean;
+    /** 閿欒淇℃伅 */
+    msg?: any;
+    /** 闄勫姞鏁版嵁 */
+    extras?: any;
+    /** 鏃堕棿鎴� */
+    timestamp?: number;
+  }
+
+  interface FriendlyResultListGetUserInfoRolesQueryResultItem {
+    /** 璺熻釜Id */
+    traceId?: string;
+    /** 鐘舵�佺爜 */
+    code?: number;
+    /** 閿欒鐮� */
+    errorCode?: string;
+    /** 鏁版嵁 */
+    data?: GetUserInfoRolesQueryResultItem[];
+    /** 鎵ц鎴愬姛 */
+    success?: boolean;
+    /** 閿欒淇℃伅 */
+    msg?: any;
+    /** 闄勫姞鏁版嵁 */
+    extras?: any;
+    /** 鏃堕棿鎴� */
+    timestamp?: number;
+  }
+
+  interface FriendlyResultListSelectQueryResultOptionGuidGetDictionaryCategorySelectQueryOption {
+    /** 璺熻釜Id */
+    traceId?: string;
+    /** 鐘舵�佺爜 */
+    code?: number;
+    /** 閿欒鐮� */
+    errorCode?: string;
+    /** 鏁版嵁 */
+    data?: SelectQueryResultOptionGuidGetDictionaryCategorySelectQueryOption[];
+    /** 鎵ц鎴愬姛 */
+    success?: boolean;
+    /** 閿欒淇℃伅 */
+    msg?: any;
+    /** 闄勫姞鏁版嵁 */
+    extras?: any;
+    /** 鏃堕棿鎴� */
+    timestamp?: number;
+  }
+
+  interface FriendlyResultListSelectQueryResultOptionGuidGetDictionaryDataSelectQueryResultOption {
+    /** 璺熻釜Id */
+    traceId?: string;
+    /** 鐘舵�佺爜 */
+    code?: number;
+    /** 閿欒鐮� */
+    errorCode?: string;
+    /** 鏁版嵁 */
+    data?: SelectQueryResultOptionGuidGetDictionaryDataSelectQueryResultOption[];
+    /** 鎵ц鎴愬姛 */
+    success?: boolean;
+    /** 閿欒淇℃伅 */
+    msg?: any;
+    /** 闄勫姞鏁版嵁 */
+    extras?: any;
+    /** 鏃堕棿鎴� */
+    timestamp?: number;
+  }
+
+  interface FriendlyResultPagedListQueryResultGetDictionaryCategoriesQueryResultItem {
+    /** 璺熻釜Id */
+    traceId?: string;
+    /** 鐘舵�佺爜 */
+    code?: number;
+    /** 閿欒鐮� */
+    errorCode?: string;
+    data?: PagedListQueryResultGetDictionaryCategoriesQueryResultItem;
+    /** 鎵ц鎴愬姛 */
+    success?: boolean;
+    /** 閿欒淇℃伅 */
+    msg?: any;
+    /** 闄勫姞鏁版嵁 */
+    extras?: any;
+    /** 鏃堕棿鎴� */
+    timestamp?: number;
+  }
+
   interface FriendlyResultPagedListQueryResultGetDictionaryDatasQueryResultItem {
     /** 璺熻釜Id */
     traceId?: string;
@@ -297,6 +432,42 @@
     /** 閿欒鐮� */
     errorCode?: string;
     data?: PagedListQueryResultGetDictionaryDatasQueryResultItem;
+    /** 鎵ц鎴愬姛 */
+    success?: boolean;
+    /** 閿欒淇℃伅 */
+    msg?: any;
+    /** 闄勫姞鏁版嵁 */
+    extras?: any;
+    /** 鏃堕棿鎴� */
+    timestamp?: number;
+  }
+
+  interface FriendlyResultPagedListQueryResultGetEnterprisesQueryResultItem {
+    /** 璺熻釜Id */
+    traceId?: string;
+    /** 鐘舵�佺爜 */
+    code?: number;
+    /** 閿欒鐮� */
+    errorCode?: string;
+    data?: PagedListQueryResultGetEnterprisesQueryResultItem;
+    /** 鎵ц鎴愬姛 */
+    success?: boolean;
+    /** 閿欒淇℃伅 */
+    msg?: any;
+    /** 闄勫姞鏁版嵁 */
+    extras?: any;
+    /** 鏃堕棿鎴� */
+    timestamp?: number;
+  }
+
+  interface FriendlyResultPagedListQueryResultGetOperationUserInfosQueryResultItem {
+    /** 璺熻釜Id */
+    traceId?: string;
+    /** 鐘舵�佺爜 */
+    code?: number;
+    /** 閿欒鐮� */
+    errorCode?: string;
+    data?: PagedListQueryResultGetOperationUserInfosQueryResultItem;
     /** 鎵ц鎴愬姛 */
     success?: boolean;
     /** 閿欒淇℃伅 */
@@ -355,11 +526,98 @@
 
   type GetCurrentLogierMenusQuery = Record<string, any>;
 
-  interface GetDictionaryDatasQuery {
+  interface GetDictionaryCategoriesQuery {
     pageModel?: PagedListQueryPageModel;
+    /** 鍏抽敭瀛� */
+    keywords?: string;
   }
 
-  type GetDictionaryDatasQueryResultItem = Record<string, any>;
+  interface GetDictionaryCategoriesQueryResultItem {
+    /** Id */
+    id?: string;
+    /** 缂栧彿 */
+    code?: string;
+    /** 鍚嶇О */
+    name?: string;
+    /** 瀛楁鍚嶏紙閫楀彿闅斿紑锛� */
+    fieldNames?: string;
+    /** 鎺掑簭 */
+    sort?: number;
+  }
+
+  type GetDictionaryCategorySelectQuery = Record<string, any>;
+
+  interface GetDictionaryDatasQuery {
+    pageModel?: PagedListQueryPageModel;
+    /** 绫诲埆Id锛圛d/缂栧彿浜岄�変竴锛� */
+    categoryId?: string;
+    /** 绫诲埆缂栧彿锛圛d/缂栧彿浜岄�変竴锛� */
+    categoryCode?: string;
+    /** 鍏抽敭瀛� */
+    keywords?: string;
+  }
+
+  interface GetDictionaryDatasQueryResultItem {
+    /** Id */
+    id?: string;
+    /** 绫诲埆Id */
+    categoryId?: string;
+    /** 绫诲埆缂栧彿 */
+    categoryCode?: string;
+    /** 绫诲埆鍚嶇О */
+    categoryName?: string;
+    category?: GetDictionaryDatasQueryResultItemCategory;
+    /** 涓婄骇Id */
+    parentId?: string;
+    /** 缂栧彿 */
+    code?: string;
+    /** 鏄剧ず鍐呭 */
+    content: string;
+    /** 瀛楁1 */
+    field1?: string;
+    /** 瀛楁2 */
+    field2?: string;
+    /** 瀛楁3 */
+    field3?: string;
+    /** 瀛楁4 */
+    field4?: string;
+    /** 瀛楁5 */
+    field5?: string;
+    /** 鎺掑簭 */
+    sort?: number;
+    /** 鏄惁绂佺敤 */
+    isDisabled?: boolean;
+  }
+
+  interface GetDictionaryDatasQueryResultItemCategory {
+    /** 绫诲埆缂栧彿 */
+    code?: string;
+    /** 鍚嶇О */
+    name?: string;
+  }
+
+  interface GetEnterprisesQuery {
+    pageModel?: PagedListQueryPageModel;
+    /** 鍏抽敭瀛� */
+    keywords?: string;
+    /** 鏄惁宸查厤缃� */
+    isConfigured?: boolean;
+  }
+
+  interface GetEnterprisesQueryResultItem {
+    /** Id */
+    id?: string;
+    /** 浼佷笟鍏ㄧО */
+    enterpriseName?: string;
+    /** 娉曚汉濮撳悕 */
+    legalPerson?: string;
+    /** 缁熶竴绀句細淇$敤浠g爜 */
+    societyCreditCode?: string;
+    /** 鑱旂郴浜� */
+    contacts?: string;
+    /** 鑱旂郴鐢佃瘽 */
+    contactNumber?: string;
+  }
 
   interface GetMenuQueryResult {
     /** Id */
@@ -477,6 +735,37 @@
     remark?: string;
   }
 
+  interface GetOperationUserInfosQuery {
+    pageModel?: PagedListQueryPageModel;
+    /** 鍏抽敭瀛� */
+    keywords?: string;
+  }
+
+  interface GetOperationUserInfosQueryResultItem {
+    /** Id */
+    id?: string;
+    /** 濮撳悕 */
+    name?: string;
+    /** 鐢ㄦ埛鍚� */
+    userName?: string;
+    /** 鎵嬫満鍙� */
+    phoneNumber?: string;
+    /** 澶囨敞 */
+    remark?: string;
+    /** 瑙掕壊 */
+    roles?: GetOperationUserInfosQueryResultItemRole[];
+    status?: EnumUserInfoStatus;
+  }
+
+  interface GetOperationUserInfosQueryResultItemRole {
+    /** 鐢ㄦ埛Id */
+    userInfoId?: string;
+    /** 瑙掕壊Id */
+    id?: string;
+    /** 鍚嶇О */
+    name?: string;
+  }
+
   interface GetResourceFieldsQueryResultItem {
     /** 缂栧彿 */
     code?: string;
@@ -537,6 +826,8 @@
     pageModel?: PagedListQueryPageModel;
     userType?: EnumUserType;
     clientType?: EnumClientType;
+    /** 鍏抽敭瀛� */
+    keywords?: string;
   }
 
   interface GetRolesQueryResultItem {
@@ -551,6 +842,32 @@
     dataPower?: EnumRoleWebApiDataPower;
     /** 澶囨敞 */
     remark?: string;
+    /** 鏄惁绂佺敤 */
+    isDisabled?: boolean;
+    /** 鐢ㄦ埛鏁伴噺 */
+    userCount?: number;
+  }
+
+  interface GetRoleUserInfosQueryResultItem {
+    /** 鐢ㄦ埛Id */
+    id?: string;
+    /** 濮撳悕 */
+    name?: string;
+    /** 鐢ㄦ埛鍚� */
+    userName?: string;
+    /** 鏄惁閫変腑 */
+    isChecked?: boolean;
+  }
+
+  interface GetUserInfoRolesQueryResultItem {
+    /** 瑙掕壊Id */
+    id?: string;
+    /** 鍚嶇О */
+    name?: string;
+    /** 澶囨敞 */
+    remark?: string;
+    /** 鏄惁閫変腑 */
+    isChecked?: boolean;
   }
 
   interface PagedListQueryPageModel {
@@ -568,10 +885,28 @@
     order?: EnumPagedListOrder;
   }
 
+  interface PagedListQueryResultGetDictionaryCategoriesQueryResultItem {
+    pageModel?: PagedListQueryResultPageModel;
+    /** 鏁版嵁 */
+    data?: GetDictionaryCategoriesQueryResultItem[];
+  }
+
   interface PagedListQueryResultGetDictionaryDatasQueryResultItem {
     pageModel?: PagedListQueryResultPageModel;
     /** 鏁版嵁 */
     data?: GetDictionaryDatasQueryResultItem[];
+  }
+
+  interface PagedListQueryResultGetEnterprisesQueryResultItem {
+    pageModel?: PagedListQueryResultPageModel;
+    /** 鏁版嵁 */
+    data?: GetEnterprisesQueryResultItem[];
+  }
+
+  interface PagedListQueryResultGetOperationUserInfosQueryResultItem {
+    pageModel?: PagedListQueryResultPageModel;
+    /** 鏁版嵁 */
+    data?: GetOperationUserInfosQueryResultItem[];
   }
 
   interface PagedListQueryResultGetRolesQueryResultItem {
@@ -607,6 +942,46 @@
     accessToken?: string;
     /** 鍒锋柊浠ょ墝 */
     refreshToken?: string;
+  }
+
+  interface SaveDictionaryCategoryCommand {
+    /** Id */
+    id?: string;
+    /** 缂栧彿 */
+    code: string;
+    /** 鍚嶇О */
+    name: string;
+    /** 瀛楁鍚嶏紙閫楀彿闅斿紑锛� */
+    fieldNames?: string;
+    /** 鎺掑簭 */
+    sort?: number;
+  }
+
+  interface SaveDictionaryDataCommand {
+    /** Id */
+    id?: string;
+    /** 绫诲埆Id */
+    categoryId?: string;
+    /** 涓婄骇Id */
+    parentId?: string;
+    /** 缂栧彿 */
+    code?: string;
+    /** 鏄剧ず鍐呭 */
+    content: string;
+    /** 瀛楁1 */
+    field1?: string;
+    /** 瀛楁2 */
+    field2?: string;
+    /** 瀛楁3 */
+    field3?: string;
+    /** 瀛楁4 */
+    field4?: string;
+    /** 瀛楁5 */
+    field5?: string;
+    /** 鎺掑簭 */
+    sort?: number;
+    /** 鏄惁绂佺敤 */
+    isDisabled?: boolean;
   }
 
   interface SaveMenuButtonCommand {
@@ -750,6 +1125,30 @@
     resources?: GetRoleQueryResultResource[];
   }
 
+  interface SelectQueryResultOptionGuidGetDictionaryCategorySelectQueryOption {
+    /** 鍊� */
+    value?: string;
+    /** 鏍囩 */
+    label?: string;
+    /** 鏁版嵁 */
+    data?: any;
+  }
+
+  interface SelectQueryResultOptionGuidGetDictionaryDataSelectQueryResultOption {
+    /** 鍊� */
+    value?: string;
+    /** 鏍囩 */
+    label?: string;
+    /** 鏁版嵁 */
+    data?: any;
+  }
+
+  interface SetDictionaryDataIsDisabledCommand {
+    ids?: string[];
+    /** 鏄惁宸茬鐢� */
+    isDisabled?: boolean;
+  }
+
   interface SetMenuSwitchCommand {
     /** Id */
     ids?: string[];
@@ -759,4 +1158,30 @@
     /** 鏄惁缂撳瓨锛坣ull鏃朵笉鏇存柊锛� */
     isCache?: boolean;
   }
+
+  interface SetRoleIsDisabledCommand {
+    ids?: string[];
+    /** 鏄惁宸茬鐢� */
+    isDisabled?: boolean;
+  }
+
+  interface SetRoleUserInfosCommand {
+    /** 瑙掕壊Id */
+    roleId?: string;
+    /** 鐢ㄦ埛Id */
+    userInfoIds?: string[];
+  }
+
+  interface SetUserInfoRolesCommand {
+    /** 鐢ㄦ埛Id */
+    userInfoId?: string;
+    /** 瑙掕壊Id */
+    roleIds?: string[];
+  }
+
+  interface SetUserInfoStatusCommand {
+    /** Id */
+    ids?: string[];
+    status?: EnumUserInfoStatus;
+  }
 }
diff --git a/src/services/api/userInfo.ts b/src/services/api/userInfo.ts
new file mode 100644
index 0000000..4367d18
--- /dev/null
+++ b/src/services/api/userInfo.ts
@@ -0,0 +1,66 @@
+/* eslint-disable */
+// @ts-ignore
+import { request } from '@/utils/request';
+
+/** 鏌ヨ杩愯惀绔敤鎴峰垎椤靛垪琛ㄦ暟鎹� POST /api/user/userInfo/getOperationUserInfos */
+export async function getOperationUserInfos(
+  body: API.GetOperationUserInfosQuery,
+  options?: API.RequestConfig
+) {
+  return request<API.PagedListQueryResultGetOperationUserInfosQueryResultItem>(
+    '/api/user/userInfo/getOperationUserInfos',
+    {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json-patch+json',
+      },
+      data: body,
+      ...(options || {}),
+    }
+  );
+}
+
+/** 鏌ヨ鐢ㄦ埛瑙掕壊鍒楄〃 GET /api/user/userInfo/getUserInfoRoles */
+export async function getUserInfoRoles(
+  // 鍙犲姞鐢熸垚鐨凱aram绫诲瀷 (闈瀊ody鍙傛暟swagger榛樿娌℃湁鐢熸垚瀵硅薄)
+  params: API.APIgetUserInfoRolesParams,
+  options?: API.RequestConfig
+) {
+  return request<API.GetUserInfoRolesQueryResultItem[]>('/api/user/userInfo/getUserInfoRoles', {
+    method: 'GET',
+    params: {
+      ...params,
+    },
+    ...(options || {}),
+  });
+}
+
+/** 璁剧疆鐢ㄦ埛淇℃伅瑙掕壊 PUT /api/user/userInfo/setUserInfoRoles */
+export async function setUserInfoRoles(
+  body: API.SetUserInfoRolesCommand,
+  options?: API.RequestConfig
+) {
+  return request<number>('/api/user/userInfo/setUserInfoRoles', {
+    method: 'PUT',
+    headers: {
+      'Content-Type': 'application/json-patch+json',
+    },
+    data: body,
+    ...(options || {}),
+  });
+}
+
+/** 璁剧疆鐢ㄦ埛淇℃伅鐘舵�� PUT /api/user/userInfo/setUserInfoStatus */
+export async function setUserInfoStatus(
+  body: API.SetUserInfoStatusCommand,
+  options?: API.RequestConfig
+) {
+  return request<number>('/api/user/userInfo/setUserInfoStatus', {
+    method: 'PUT',
+    headers: {
+      'Content-Type': 'application/json-patch+json',
+    },
+    data: body,
+    ...(options || {}),
+  });
+}
diff --git a/src/utils/common/common.ts b/src/utils/common/common.ts
index b05dfc3..374c3a8 100644
--- a/src/utils/common/common.ts
+++ b/src/utils/common/common.ts
@@ -106,3 +106,12 @@
 export function filterNumbersFromString(str: string) {
   return str.replace(/\D/g, '');
 }
+
+export function formatRoleName(roleName: string) {
+  let lastUnderscoreIndex = roleName.lastIndexOf('_');
+
+  if (lastUnderscoreIndex !== -1) {
+    roleName = roleName.substring(0, lastUnderscoreIndex);
+  }
+  return roleName;
+}
diff --git a/src/views/DictionaryManage/DataDictionary.vue b/src/views/DictionaryManage/DataDictionary.vue
index 782f4d8..de06a45 100644
--- a/src/views/DictionaryManage/DataDictionary.vue
+++ b/src/views/DictionaryManage/DataDictionary.vue
@@ -5,26 +5,15 @@
         <template #query>
           <QueryFilterItem>
             <FieldSelect
-              v-model="extraParamState.searchType"
+              v-model="extraParamState.categoryId"
               @change="getList()"
-              :value-enum="SearchTypeText"
+              :value-enum="dictionaryCategoryList"
               placeholder="璇烽�夋嫨鎵�灞炵被鍒�"
-            ></FieldSelect>
-          </QueryFilterItem>
-          <QueryFilterItem v-if="extraParamState.searchType === SearchType.Position">
-            <FieldSelect
-              v-model="extraParamState.parentId"
-              @change="getList()"
-              :value-enum="typeList"
-              enum-label-key="name"
-              enum-value-key="id"
-              placeholder="璇烽�夋嫨琛屼笟绫诲瀷"
-              clearable
             ></FieldSelect>
           </QueryFilterItem>
           <QueryFilterItem>
             <SearchInput
-              v-model="extraParamState.name"
+              v-model="extraParamState.keywords"
               style="width: 200px"
               placeholder="璇疯緭鍏ュ悕绉�"
               @on-click-search="getList"
@@ -44,19 +33,22 @@
         </template>
       </ProTableQueryFilterBar>
       <ProTableV2 v-bind="proTableProps" :columns="column" :operationBtns="operationBtns">
-        <template #columns="{ row, column }">
-          <template v-if="column.property === 'status'">
-            <FieldSwitch
-              v-model="row.status"
-              active-text="鏄剧ず"
-              inactive-text="闅愯棌"
-              :before-change="() => setCategoryVis(row)"
-            />
-          </template>
+        <template #isDisabled="{ row }">
+          <FieldSwitch
+            v-model="row.isDisabled"
+            active-text="鍚敤"
+            inactive-text="绂佺敤"
+            :active-value="false"
+            :inactive-value="true"
+            :before-change="() => setCategoryVis(row)"
+          />
+        </template>
+        <template #category="{ row }">
+          {{ row.category?.name }}
         </template>
       </ProTableV2>
     </AppContainer>
-    <AddOrEditSearchSetting v-bind="dialogProps" :typeList="typeList" />
+    <AddOrEditDictionaryDialog v-bind="dialogProps" />
   </LoadingLayout>
 </template>
 
@@ -74,20 +66,13 @@
   UploadUserFile,
   FieldSwitch,
   FieldSelect,
-  FieldRadio,
 } from '@bole-core/components';
-import { useAccess } from '@/hooks';
-import {
-  SearchType,
-  SearchTypeText,
-  // BelongType,
-  // BelongTypeText,
-  BooleanOptions,
-} from '@/constants';
-import { OrderInputType, Message } from '@bole-core/core';
-import AddOrEditSearchSetting from './components/AddOrEditSearchSetting.vue';
-import { convertApi2FormUrl } from '@/utils';
-import { useQueryClient } from '@tanstack/vue-query';
+import { useAccess, useDictionaryDataSelect, useGetDictionaryCategorySelect } from '@/hooks';
+import { Message } from '@bole-core/core';
+import AddOrEditDictionaryDialog from './components/AddOrEditDictionaryDialog.vue';
+import { convertApi2FormUrl, convertApi2FormUrlOnlyOne } from '@/utils';
+import * as dictionaryServices from '@/services/api/dictionary';
+import { CategoryCode } from '@/constants';
 
 defineOptions({
   name: 'DataDictionary',
@@ -101,14 +86,23 @@
   operationBtnMap,
 });
 
+const { dictionaryCategoryList, ensureQueryData, getDictionaryCategoryNameByCode } =
+  useGetDictionaryCategorySelect();
+
+const { getDictionaryDataNameByCode } = useDictionaryDataSelect({
+  categoryCode: CategoryCode.IndustryCategory,
+});
+
 const BaseState = {
   loading: true,
 };
-const queryClient = useQueryClient();
-const typeList = ref([]);
 const state = reactive({ ...BaseState });
 
 onMounted(async () => {
+  const dictionaryCategoryList = await ensureQueryData();
+  if (dictionaryCategoryList.length > 0) {
+    extraParamState.categoryId = dictionaryCategoryList[0].value;
+  }
   await getList();
   state.loading = false;
 });
@@ -122,23 +116,16 @@
 } = useTable(
   async ({ pageIndex, pageSize }, extraParamState) => {
     try {
-      let params: API.GetSearchSettingListInput = {
+      let params: API.GetDictionaryDatasQuery = {
         pageModel: {
           rows: pageSize,
           page: pageIndex,
           orderInput: extraParamState.orderInput,
         },
-        name: extraParamState.name,
-        // belongType: Number(extraParamState.belongType),
-        searchType: Number(extraParamState.searchType),
-        status: extraParamState.status,
+        categoryId: extraParamState.categoryId,
+        keywords: extraParamState.keywords,
       };
-
-      if (extraParamState.searchType === SearchType.Position) {
-        params.isRecommend = extraParamState.isRecommend;
-        params.parentId = extraParamState.parentId;
-      }
-      let res = await searchSettingServices.getSearchSettingList(params, {
+      let res = await dictionaryServices.getDictionaryDatas(params, {
         showLoading: !state.loading,
       });
       return res;
@@ -148,34 +135,38 @@
   },
   {
     defaultExtraParams: {
-      name: '',
-      searchType: SearchType.Identity,
-      orderInput: [{ property: 'sort', order: OrderInputType.Asc }],
-      status: '' as any as boolean,
-      isRecommend: '' as any as boolean,
-      parentId: '',
+      categoryId: '',
+      keywords: '',
+      orderInput: [{ property: 'sort', order: EnumPagedListOrder.Asc }],
     },
-    queryKey: ['searchSettingServices/getSearchSettingList'],
+    queryKey: ['dictionaryServices/getDictionaryDatas'],
     columnsRenderProps: {
-      searchType: { type: 'enum', valueEnum: SearchTypeText },
+      field1: {
+        formatter(row: API.GetDictionaryDatasQueryResultItem) {
+          return row.categoryCode == CategoryCode.Position
+            ? getDictionaryDataNameByCode(row.field1)
+            : '';
+        },
+      },
     },
   }
 );
 
-function openDialog(row?: API.GetSearchSettingList) {
+function openDialog(row?: API.GetDictionaryDatasQueryResultItem) {
   if (row) {
     handleEdit({
       id: row.id,
-      searchType: extraParamState.searchType,
-      name: row.name,
+      categoryId: row.categoryId,
+      code: row.code,
+      content: row.content,
       sort: row.sort,
-      status: row.status,
-      src: row.src?.length ? [convertApi2FormUrl(row.src)] : [],
-      parentId: row.parentId ?? '',
+      isDisabled: row.isDisabled,
+      field1: row.field1,
+      field2: convertApi2FormUrlOnlyOne(row.field2),
     });
   } else {
     handleAdd({
-      searchType: extraParamState.searchType,
+      categoryId: extraParamState.categoryId,
     });
   }
 }
@@ -184,55 +175,47 @@
   onConfirm: handleAddOrEdit,
   defaultFormParams: {
     id: '',
-    searchType: SearchType.Identity,
-    name: '',
+    categoryId: '',
+    code: '',
+    content: '',
     sort: 0,
-    status: true,
-    src: [] as UploadUserFile[],
-    parentId: '',
+    isDisabled: false,
+    field1: '',
+    field2: [] as UploadUserFile[],
   },
 });
 
 async function handleAddOrEdit() {
   try {
-    let params: API.CreateOrEditSearchInput = {
-      searchType: extraParamState.searchType,
-      name: editForm.name,
+    let params: API.SaveDictionaryDataCommand = {
+      categoryId: editForm.categoryId,
+      code: editForm.code,
       sort: editForm.sort,
-      status: editForm.status,
-      src: editForm.src?.[0]?.path ?? '',
-      parentId: editForm.parentId ?? '',
+      content: editForm.content,
+      isDisabled: editForm.isDisabled,
+      field1: editForm.field1,
+      field2: editForm.field2?.[0]?.path ?? '',
     };
     if (editForm.id) {
       params.id = editForm.id;
     }
-    let res = await searchSettingServices.createOrEditSearchSetting(params);
+    let res = await dictionaryServices.saveDictionaryData(params);
     if (res) {
       Message.successMessage('鎿嶄綔鎴愬姛');
       getList(paginationState.pageIndex);
       dialogState.dialogVisible = false;
-      updateCategoryMenu();
     }
   } catch (error) {}
 }
 
-function updateCategoryMenu() {
-  queryClient.invalidateQueries({
-    queryKey: [
-      'searchSettingServices/getTypeSearchSettingList',
-      { searchType: extraParamState.searchType, belongType: null },
-    ],
-  });
-}
-
-async function setCategoryVis(row: API.GetSearchSettingList) {
+async function setCategoryVis(row: API.GetDictionaryDatasQueryResultItem) {
   try {
-    let params: API.EnableSearchSettingInput = {
-      id: row.id,
-      status: !row.status,
+    await Message.tipMessage(`纭瑕�${row.isDisabled ? '鍚敤' : '绂佺敤'}鍚楋紵`);
+    let params: API.SetDictionaryDataIsDisabledCommand = {
+      ids: [row.id],
+      isDisabled: !row.isDisabled,
     };
-    let res = await searchSettingServices.enableSearchSetting(params);
-    updateCategoryMenu();
+    let res = await dictionaryServices.setDictionaryDataIsDisabled(params);
     getList(paginationState.pageIndex);
     return !!res;
   } catch (error) {}
diff --git a/src/views/DictionaryManage/DictionaryCategoryManage.vue b/src/views/DictionaryManage/DictionaryCategoryManage.vue
new file mode 100644
index 0000000..b110d7b
--- /dev/null
+++ b/src/views/DictionaryManage/DictionaryCategoryManage.vue
@@ -0,0 +1,165 @@
+<template>
+  <LoadingLayout :loading="state.loading">
+    <AppContainer>
+      <ProTableQueryFilterBar @on-reset="reset">
+        <template #query>
+          <QueryFilterItem>
+            <SearchInput
+              v-model="extraParamState.keywords"
+              style="width: 200px"
+              placeholder="鍚嶇О/缂栧彿"
+              @on-click-search="getList"
+              @keyup.enter="getList()"
+            >
+            </SearchInput>
+          </QueryFilterItem>
+        </template>
+        <template #btn>
+          <el-button
+            v-if="checkSubModuleItemShow('pageButton', 'addBtn')"
+            @click="openDialog()"
+            icon="Plus"
+            type="primary"
+            >鏂板</el-button
+          >
+        </template>
+      </ProTableQueryFilterBar>
+      <ProTableV2 v-bind="proTableProps" :columns="column" :operationBtns="operationBtns">
+      </ProTableV2>
+    </AppContainer>
+    <AddOrEditDictionaryCategory v-bind="dialogProps" />
+  </LoadingLayout>
+</template>
+
+<script setup lang="ts">
+import {
+  ProTableQueryFilterBar,
+  OperationBtnType,
+  ProTableV2,
+  SearchInput,
+  LoadingLayout,
+  AppContainer,
+  QueryFilterItem,
+  useTable,
+  useFormDialog,
+} from '@bole-core/components';
+import { useAccess } from '@/hooks';
+import { Message } from '@bole-core/core';
+import AddOrEditDictionaryCategory from './components/AddOrEditDictionaryCategory.vue';
+import { useQueryClient } from '@tanstack/vue-query';
+import * as dictionaryServices from '@/services/api/dictionary';
+
+defineOptions({
+  name: 'DictionaryCategoryManage',
+});
+
+const operationBtnMap: Record<string, OperationBtnType> = {
+  editBtn: { emits: { onClick: (role) => openDialog(role) } },
+  delBtn: { emits: { onClick: (role) => handleDel(role) }, props: { type: 'danger' } },
+};
+
+const { checkSubModuleItemShow, column, operationBtns } = useAccess({
+  operationBtnMap,
+});
+
+const BaseState = {
+  loading: true,
+};
+const state = reactive({ ...BaseState });
+
+onMounted(async () => {
+  await getList();
+  state.loading = false;
+});
+
+const {
+  getDataSource: getList,
+  proTableProps,
+  paginationState,
+  extraParamState,
+  reset,
+} = useTable(
+  async ({ pageIndex, pageSize }, extraParamState) => {
+    try {
+      let params: API.GetDictionaryCategoriesQuery = {
+        pageModel: {
+          rows: pageSize,
+          page: pageIndex,
+          orderInput: extraParamState.orderInput,
+        },
+        keywords: extraParamState.keywords,
+      };
+      let res = await dictionaryServices.getDictionaryCategories(params, {
+        showLoading: !state.loading,
+      });
+      return res;
+    } catch (error) {
+      console.log('error: ', error);
+    }
+  },
+  {
+    defaultExtraParams: {
+      keywords: '',
+      orderInput: [{ property: 'sort', order: EnumPagedListOrder.Asc }],
+    },
+    queryKey: ['dictionaryServices/getDictionaryCategories'],
+    columnsRenderProps: {},
+  }
+);
+
+function openDialog(row?: API.GetDictionaryCategoriesQueryResultItem) {
+  if (row) {
+    handleEdit({
+      id: row.id,
+      name: row.name,
+      sort: row.sort,
+      code: row.code,
+      fieldNames: row.fieldNames,
+    });
+  } else {
+    handleAdd();
+  }
+}
+
+const { dialogProps, handleAdd, handleEdit, editForm } = useFormDialog({
+  onConfirm: handleAddOrEdit,
+  defaultFormParams: {
+    id: '',
+    name: '',
+    code: '',
+    fieldNames: '',
+    sort: 0,
+  },
+});
+
+async function handleAddOrEdit() {
+  try {
+    let params: API.SaveDictionaryCategoryCommand = {
+      code: editForm.code,
+      name: editForm.name,
+      sort: editForm.sort,
+      fieldNames: editForm.fieldNames,
+    };
+    if (editForm.id) {
+      params.id = editForm.id;
+    }
+    let res = await dictionaryServices.saveDictionaryCategory(params);
+    if (res) {
+      Message.successMessage('鎿嶄綔鎴愬姛');
+      getList(paginationState.pageIndex);
+    }
+  } catch (error) {}
+}
+
+async function handleDel(row: API.GetDictionaryCategoriesQueryResultItem) {
+  try {
+    await Message.tipMessage('纭瑕佸垹闄よ绫诲埆鍚楋紵');
+    let params: API.DeleteDictionaryCategoryCommand = { ids: [row.id] };
+    let res = await dictionaryServices.deleteDictionaryCategory(params);
+    if (res) {
+      Message.successMessage('鎿嶄綔鎴愬姛');
+      getList(paginationState.pageIndex);
+    }
+  } catch (error) {}
+}
+</script>
diff --git a/src/views/DictionaryManage/components/AddOrEditDictionaryCategory.vue b/src/views/DictionaryManage/components/AddOrEditDictionaryCategory.vue
new file mode 100644
index 0000000..021d6e4
--- /dev/null
+++ b/src/views/DictionaryManage/components/AddOrEditDictionaryCategory.vue
@@ -0,0 +1,90 @@
+<template>
+  <ProDialog
+    :title="`${title}绫诲埆`"
+    v-model="visible"
+    @close="onDialogClose"
+    destroy-on-close
+    draggable
+  >
+    <ProForm :model="form" ref="dialogForm" label-width="90px">
+      <ProFormItemV2 label="鍚嶇О:" prop="name" :check-rules="[{ message: '璇疯緭鍏ュ悕绉�' }]">
+        <ProFormText
+          placeholder="璇疯緭鍏ュ悕绉�"
+          v-model.trim="form.name"
+          :maxlength="15"
+        ></ProFormText>
+      </ProFormItemV2>
+      <ProFormItemV2 label="缂栧彿:" prop="code">
+        <ProFormText placeholder="璇疯緭鍏ョ紪鍙�" v-model.trim="form.code"></ProFormText>
+      </ProFormItemV2>
+      <ProFormItemV2 label="瀛楁鍚�:" prop="fieldNames">
+        <ProFormText placeholder="璇疯緭鍏ョ紪鍙�" v-model.trim="form.fieldNames"></ProFormText>
+      </ProFormItemV2>
+      <ProFormItemV2 label="鎺掑簭:" prop="sort">
+        <ProFormInputNumber
+          v-model="form.sort"
+          :controls="false"
+          :min="0"
+          :max="999999"
+        ></ProFormInputNumber>
+      </ProFormItemV2>
+    </ProForm>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="emit('onCancel')">鍙� 娑�</el-button>
+        <el-button type="primary" @click="handleConfirm">纭� 瀹�</el-button>
+      </span>
+    </template>
+  </ProDialog>
+</template>
+
+<script setup lang="ts">
+import { FormInstance } from 'element-plus';
+import {
+  ProDialog,
+  ProForm,
+  ProFormItemV2,
+  ProFormText,
+  ProFormInputNumber,
+} from '@bole-core/components';
+
+defineOptions({
+  name: 'AddOrEditDictionaryCategory',
+});
+
+type Form = {
+  id?: string;
+  name: string;
+  sort: number;
+  code: string;
+  fieldNames: string;
+};
+
+const form = defineModel<Form>('form');
+const visible = defineModel<boolean>('modelValue');
+
+const title = computed(() => (form.value.id ? '缂栬緫' : '鏂板'));
+
+const emit = defineEmits<{
+  (e: 'onConfirm'): void;
+  (e: 'onCancel'): void;
+}>();
+
+const dialogForm = ref<FormInstance>();
+
+function onDialogClose() {
+  if (!dialogForm.value) return;
+  dialogForm.value.resetFields();
+}
+
+function handleConfirm() {
+  if (!dialogForm.value) return;
+  dialogForm.value.validate((valid) => {
+    if (valid) {
+      emit('onConfirm');
+    } else {
+      return;
+    }
+  });
+}
+</script>
diff --git a/src/views/DictionaryManage/components/AddOrEditDictionaryDialog.vue b/src/views/DictionaryManage/components/AddOrEditDictionaryDialog.vue
new file mode 100644
index 0000000..9784ece
--- /dev/null
+++ b/src/views/DictionaryManage/components/AddOrEditDictionaryDialog.vue
@@ -0,0 +1,142 @@
+<template>
+  <ProDialog
+    :title="`${title}绫诲埆`"
+    v-model="visible"
+    @close="onDialogClose"
+    destroy-on-close
+    draggable
+  >
+    <ProForm :model="form" ref="dialogForm" label-width="90px">
+      <ProFormItemV2
+        label="琛屼笟绫诲瀷:"
+        prop="field1"
+        v-if="category?.data?.code === '30'"
+        :check-rules="[{ message: '璇烽�夋嫨琛屼笟绫诲瀷' }]"
+      >
+        <ProFormSelect
+          v-model="form.field1"
+          :value-enum="dictionaryDataList"
+          enum-value-key="code"
+        />
+      </ProFormItemV2>
+      <ProFormItemV2 label="鍚嶇О:" prop="content" :check-rules="[{ message: '璇疯緭鍏ュ悕绉�' }]">
+        <ProFormText
+          placeholder="璇疯緭鍏ュ悕绉�"
+          v-model.trim="form.content"
+          :maxlength="15"
+        ></ProFormText>
+      </ProFormItemV2>
+      <ProFormItemV2 label="鎺掑簭:" prop="sort">
+        <ProFormInputNumber
+          v-model="form.sort"
+          :controls="false"
+          :min="0"
+          :max="999999"
+        ></ProFormInputNumber>
+      </ProFormItemV2>
+      <ProFormItemV2 label="缂栧彿:" prop="code">
+        <ProFormText v-model.trim="form.code"></ProFormText>
+      </ProFormItemV2>
+      <ProFormItemV2 label="鍥剧墖:" prop="src" v-if="category?.data?.code === '50'">
+        <ProFormImageUpload v-model:file-url="form.field2" :limitFileCount="1"></ProFormImageUpload>
+      </ProFormItemV2>
+      <ProFormItemV2 label="鐘舵��:" prop="status">
+        <ProFormRadio
+          v-model="form.isDisabled"
+          :value-enum="[
+            { label: '鍚敤', value: false },
+            { label: '绂佺敤', value: true },
+          ]"
+        ></ProFormRadio>
+      </ProFormItemV2>
+    </ProForm>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="emit('onCancel')">鍙� 娑�</el-button>
+        <el-button type="primary" @click="handleConfirm">纭� 瀹�</el-button>
+      </span>
+    </template>
+  </ProDialog>
+</template>
+
+<script setup lang="ts">
+import { FormInstance } from 'element-plus';
+import {
+  ProDialog,
+  ProForm,
+  ProFormItemV2,
+  ProFormText,
+  ProFormInputNumber,
+  ProFormSelect,
+  ProFormRadio,
+  UploadUserFile,
+  ProFormImageUpload,
+} from '@bole-core/components';
+import { useDictionaryDataSelect, useGetDictionaryCategorySelect } from '@/hooks';
+import { CategoryCode } from '@/constants';
+
+defineOptions({
+  name: 'AddOrEditDictionaryDialog',
+});
+
+type Form = {
+  id?: string;
+  categoryId: string;
+  content: string;
+  code: string;
+  sort: number;
+  isDisabled: boolean;
+  field1?: string;
+  field2?: UploadUserFile[];
+};
+
+const form = defineModel<Form>('form');
+const visible = defineModel<boolean>('modelValue');
+
+const title = computed(() => (form.value.id ? '缂栬緫' : '鏂板'));
+
+const { getDictionaryCategoryById } = useGetDictionaryCategorySelect();
+
+const { dictionaryDataList, refetch, getDictionaryDataNameById } = useDictionaryDataSelect({
+  categoryCode: computed(() => CategoryCode.IndustryCategory),
+});
+
+const category = computed(() => {
+  return getDictionaryCategoryById(form.value.categoryId);
+});
+
+watch(
+  () => visible.value,
+  (value) => {
+    if (value) {
+      refetch();
+    }
+  },
+  {
+    immediate: true,
+  }
+);
+
+const emit = defineEmits<{
+  (e: 'onConfirm'): void;
+  (e: 'onCancel'): void;
+}>();
+
+const dialogForm = ref<FormInstance>();
+
+function onDialogClose() {
+  if (!dialogForm.value) return;
+  dialogForm.value.resetFields();
+}
+
+function handleConfirm() {
+  if (!dialogForm.value) return;
+  dialogForm.value.validate((valid) => {
+    if (valid) {
+      emit('onConfirm');
+    } else {
+      return;
+    }
+  });
+}
+</script>
diff --git a/src/views/DictionaryManage/components/AddOrEditSearchSetting.vue b/src/views/DictionaryManage/components/AddOrEditSearchSetting.vue
deleted file mode 100644
index 1eab56d..0000000
--- a/src/views/DictionaryManage/components/AddOrEditSearchSetting.vue
+++ /dev/null
@@ -1,147 +0,0 @@
-<template>
-  <ProDialog
-    :title="innerForm.title"
-    v-model="innerVisible"
-    @close="onDialogClose"
-    destroy-on-close
-    draggable
-  >
-    <ProForm :rules="rules" :model="innerForm" ref="dialogForm" label-width="90px">
-      <ProFormItemV2 label="琛屼笟绫诲瀷:" prop="parentId" v-if="showWorkSearchType">
-        <ProFormSelect
-          v-model="innerForm.parentId"
-          :value-enum="typeList"
-          enum-value-key="id"
-          enum-label-key="name"
-        />
-      </ProFormItemV2>
-      <ProFormItemV2 label="鍚嶇О:" prop="name">
-        <ProFormText
-          placeholder="璇疯緭鍏ュ悕绉�"
-          v-model.trim="innerForm.name"
-          :maxlength="15"
-        ></ProFormText>
-      </ProFormItemV2>
-      <ProFormItemV2 label="鎺掑簭:" prop="sort" required>
-        <ProFormInputNumber
-          v-model="innerForm.sort"
-          :controls="false"
-          :min="0"
-          :max="999"
-        ></ProFormInputNumber>
-      </ProFormItemV2>
-      <ProFormItemV2
-        label="绫诲埆鍥炬爣:"
-        prop="src"
-        :check-rules="[{ type: 'upload', required: false }]"
-      >
-        <ProFormImageUpload
-          v-model:file-url="innerForm.src"
-          :limitFileCount="1"
-        ></ProFormImageUpload>
-      </ProFormItemV2>
-      <ProFormItemV2 label="鐘舵��:" prop="status" required>
-        <el-radio-group v-model="innerForm.status">
-          <el-radio-button :value="true">鏄剧ず</el-radio-button>
-          <el-radio-button :value="false">闅愯棌</el-radio-button>
-        </el-radio-group>
-      </ProFormItemV2>
-    </ProForm>
-    <template #footer>
-      <span class="dialog-footer">
-        <el-button @click="emit('onCancel')">鍙� 娑�</el-button>
-        <el-button type="primary" @click="handleConfirm">纭� 瀹�</el-button>
-      </span>
-    </template>
-  </ProDialog>
-</template>
-
-<script setup lang="ts">
-import { FormRules, FormInstance } from 'element-plus';
-import { SearchType } from '@/constants';
-import {
-  ProDialog,
-  ProForm,
-  ProFormItemV2,
-  ProFormRadio,
-  ProFormText,
-  ProFormInputNumber,
-  ProFormImageUpload,
-  UploadUserFile,
-  ProFormSelect,
-} from '@bole-core/components';
-
-defineOptions({
-  name: 'AddOrEditSearchSetting',
-});
-
-type Props = {
-  modelValue: boolean;
-  form?: {
-    title?: string;
-    searchType: number;
-    name: string;
-    sort: number;
-    status: boolean;
-    src: UploadUserFile[];
-    parentId?: string;
-  };
-  typeList: API.GetTypeSearchSettingList[];
-};
-
-const props = withDefaults(defineProps<Props>(), {
-  modelValue: false,
-});
-
-const showWorkSearchType = computed(() => props.form.searchType === SearchType.Position);
-
-const emit = defineEmits<{
-  (e: 'update:modelValue', value: boolean): void;
-  (e: 'update:form', value: Props['form']): void;
-  (e: 'onConfirm'): void;
-  (e: 'onCancel'): void;
-}>();
-
-const dialogForm = ref<FormInstance>();
-
-const innerVisible = computed({
-  get() {
-    return props.modelValue;
-  },
-  set(val) {
-    emit('update:modelValue', val);
-  },
-});
-
-const innerForm = computed({
-  get() {
-    return props.form;
-  },
-  set(val) {
-    emit('update:form', val);
-  },
-});
-
-const rules = reactive<FormRules>({
-  status: [{ required: true, message: '璇烽�夋嫨鐘舵��', trigger: 'change' }],
-  name: [{ required: true, message: '璇疯緭鍏ュ悕绉�', trigger: 'blur' }],
-  sort: [{ required: true, message: '璇疯緭鍏ユ帓搴�', trigger: 'blur' }],
-  parentId: [{ required: true, message: '璇烽�夋嫨鎵�灞炵被鍒�', trigger: 'change' }],
-});
-
-function onDialogClose() {
-  if (!dialogForm.value) return;
-  dialogForm.value.resetFields();
-}
-
-function handleConfirm() {
-  if (!dialogForm.value) return;
-  dialogForm.value.validate((valid) => {
-    if (valid) {
-      emit('onConfirm');
-    } else {
-      return;
-    }
-  });
-}
-</script>
diff --git a/src/views/Permission/OperationUserManage.vue b/src/views/Permission/OperationUserManage.vue
new file mode 100644
index 0000000..a008812
--- /dev/null
+++ b/src/views/Permission/OperationUserManage.vue
@@ -0,0 +1,175 @@
+<template>
+  <LoadingLayout :loading="state.loading">
+    <AppContainer>
+      <ProTableQueryFilterBar @on-reset="reset">
+        <template #query>
+          <QueryFilterItem>
+            <SearchInput
+              v-model="extraParamState.keywords"
+              style="width: 200px"
+              placeholder="瑙掕壊鍚嶇О"
+              @on-click-search="getList"
+              @keyup.enter="getList()"
+            >
+            </SearchInput>
+          </QueryFilterItem>
+        </template>
+      </ProTableQueryFilterBar>
+      <ProTableV2 v-bind="proTableProps" :columns="column" :operationBtns="operationBtns">
+        <template #roles="{ row }">
+          {{ row.roles?.map((x) => formatRoleName(x.name)).join() }}
+        </template>
+        <template #status="{ row }">
+          <FieldSwitch
+            v-model="row.status"
+            active-text="鍚敤"
+            inactive-text="绂佺敤"
+            :active-value="EnumUserInfoStatus.Normal"
+            :inactive-value="EnumUserInfoStatus.Disabled"
+            :before-change="() => setStatus(row)"
+          />
+        </template>
+      </ProTableV2>
+    </AppContainer>
+    <SetOperationUserRoleDialog v-bind="dialogProps" />
+  </LoadingLayout>
+</template>
+
+<script setup lang="ts">
+import {
+  ProTableQueryFilterBar,
+  OperationBtnType,
+  ProTableV2,
+  SearchInput,
+  LoadingLayout,
+  AppContainer,
+  QueryFilterItem,
+  useTable,
+  FieldSwitch,
+  useFormDialog,
+} from '@bole-core/components';
+import { useAccess } from '@/hooks';
+import { formatRoleName } from '@/utils';
+import * as userInfoServices from '@/services/api/userInfo';
+import { Message } from '@bole-core/core';
+import { EnumUserInfoStatus } from '@/constants';
+import SetOperationUserRoleDialog from './components/SetOperationUserRoleDialog.vue';
+
+defineOptions({
+  name: 'OperationUserManage',
+});
+
+const operationBtnMap: Record<string, OperationBtnType> = {
+  setRoleBtn: { emits: { onClick: (role) => openDialog(role) } },
+};
+
+const { checkSubModuleItemShow, column, operationBtns } = useAccess({
+  operationBtnMap,
+});
+
+const BaseState = {
+  loading: true,
+};
+
+const state = reactive({ ...BaseState });
+
+onMounted(async () => {
+  await getList();
+  state.loading = false;
+});
+
+const {
+  getDataSource: getList,
+  proTableProps,
+  paginationState,
+  extraParamState,
+  reset,
+} = useTable(
+  async ({ pageIndex, pageSize }, extraParamState) => {
+    try {
+      let params: API.GetOperationUserInfosQuery = {
+        pageModel: {
+          rows: pageSize,
+          page: pageIndex,
+          orderInput: extraParamState.orderInput,
+        },
+        keywords: extraParamState.keywords,
+      };
+      let res = await userInfoServices.getOperationUserInfos(params, {
+        showLoading: !state.loading,
+      });
+      return res;
+    } catch (error) {}
+  },
+  {
+    defaultExtraParams: {
+      keywords: '',
+      orderInput: [{ property: 'id', order: EnumPagedListOrder.Desc }],
+    },
+    queryKey: ['userInfoServices/getOperationUserInfos'],
+    columnsRenderProps: {},
+  }
+);
+
+async function setStatus(row: API.GetOperationUserInfosQueryResultItem) {
+  try {
+    await Message.tipMessage(
+      `纭瑕�${row.status === EnumUserInfoStatus.Normal ? '绂佺敤' : '鍚敤'}璇ヨ处鍙峰悧锛焋
+    );
+    let params: API.SetUserInfoStatusCommand = {
+      ids: [row.id],
+      status:
+        row.status === EnumUserInfoStatus.Normal
+          ? EnumUserInfoStatus.Disabled
+          : EnumUserInfoStatus.Normal,
+    };
+    let res = await userInfoServices.setUserInfoStatus(params);
+    return !!res;
+  } catch (error) {}
+}
+
+const { dialogProps, handleEdit, editForm } = useFormDialog({
+  onConfirm: setUserInfoRoles,
+  defaultFormParams: {
+    roleIds: [] as string[],
+    userInfoId: '',
+    roles: [] as API.GetOperationUserInfosQueryResultItem[],
+  },
+});
+
+async function openDialog(row?: API.GetOperationUserInfosQueryResultItem) {
+  if (row) {
+    const roles = await getUserInfoRoles(row);
+    handleEdit({
+      userInfoId: row.id,
+      roleIds: row.roles?.map((x) => x.id),
+      roles: roles,
+    });
+  }
+}
+
+async function setUserInfoRoles() {
+  try {
+    let params: API.SetUserInfoRolesCommand = {
+      userInfoId: editForm.userInfoId,
+      roleIds: editForm.roleIds,
+    };
+    let res = await userInfoServices.setUserInfoRoles(params);
+    if (res) {
+      Message.successMessage('鎿嶄綔鎴愬姛');
+      getList(paginationState.pageIndex);
+    }
+  } catch (error) {}
+}
+
+async function getUserInfoRoles(row: API.GetOperationUserInfosQueryResultItem) {
+  try {
+    let params: API.APIgetUserInfoRolesParams = {
+      userInfoId: row.id,
+      // clientType: row.clientType,
+    };
+    let res = await userInfoServices.getUserInfoRoles(params);
+    return res;
+  } catch (error) {}
+}
+</script>
diff --git a/src/views/Permission/components/SetOperationUserRoleDialog.vue b/src/views/Permission/components/SetOperationUserRoleDialog.vue
new file mode 100644
index 0000000..05a104a
--- /dev/null
+++ b/src/views/Permission/components/SetOperationUserRoleDialog.vue
@@ -0,0 +1,61 @@
+<template>
+  <ProDialog title="璁剧疆瑙掕壊" v-model="visible" @close="onDialogClose" destroy-on-close draggable>
+    <ProForm :model="form" ref="dialogForm" label-width="90px">
+      <ProFormItemV2 label="瑙掕壊" prop="roleIds" :check-rules="[{ message: '璇烽�夋嫨瑙掕壊' }]">
+        <ProFormCheckbox
+          v-model="form.roleIds"
+          :value-enum="form.roles"
+          enumLabelKey="name"
+          enum-value-key="id"
+        ></ProFormCheckbox>
+      </ProFormItemV2>
+    </ProForm>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="emit('onCancel')">鍙� 娑�</el-button>
+        <el-button type="primary" @click="handleConfirm">纭� 瀹�</el-button>
+      </span>
+    </template>
+  </ProDialog>
+</template>
+
+<script setup lang="ts">
+import { FormInstance } from 'element-plus';
+import { ProDialog, ProForm, ProFormItemV2, ProFormCheckbox } from '@bole-core/components';
+
+defineOptions({
+  name: 'SetOperationUserRoleDialog',
+});
+
+type Form = {
+  userInfoId: string;
+  roleIds: string[];
+  roles: API.GetOperationUserInfosQueryResultItem[];
+};
+
+const form = defineModel<Form>('form');
+const visible = defineModel({ type: Boolean });
+
+const emit = defineEmits<{
+  (e: 'onConfirm'): void;
+  (e: 'onCancel'): void;
+}>();
+
+const dialogForm = ref<FormInstance>();
+
+function onDialogClose() {
+  if (!dialogForm.value) return;
+  dialogForm.value.resetFields();
+}
+
+function handleConfirm() {
+  if (!dialogForm.value) return;
+  dialogForm.value.validate((valid) => {
+    if (valid) {
+      emit('onConfirm');
+    } else {
+      return;
+    }
+  });
+}
+</script>
diff --git a/src/views/System/ModuleManage.vue b/src/views/System/ModuleManage.vue
index 5a20161..217df8b 100644
--- a/src/views/System/ModuleManage.vue
+++ b/src/views/System/ModuleManage.vue
@@ -556,17 +556,32 @@
     if (drawerState.type === SubModuleType.Column) {
       let columnModuleList = drawerState.tableData; //.filter((d) => d.isEdit);
       if (columnModuleList.length > 0) {
-        const groups = currentDrawerModule.value.groups.map((group) => {
-          if (group.group === state.group) {
-            group.fields = columnModuleList.map((c) => ({
+        let groups = [...currentDrawerModule.value.groups];
+        const isExist = groups.some((g) => g.group === state.group);
+        if (isExist) {
+          groups = groups.map((group) => {
+            if (group.group === state.group) {
+              group.fields = columnModuleList.map((c) => ({
+                code: c.enCode,
+                name: c.name,
+                width: c.width,
+                sort: c.sortCode,
+              }));
+            }
+            return group;
+          });
+        } else {
+          const group: API.GetMenuQueryResultGroup = {
+            group: state.group,
+            fields: columnModuleList.map((c) => ({
               code: c.enCode,
               name: c.name,
               width: c.width,
               sort: c.sortCode,
-            }));
-          }
-          return group;
-        });
+            })),
+          };
+          groups.push(group);
+        }
         let params: API.SaveMenuCommand = {
           ...currentDrawerModule.value,
           groups: groups,
diff --git a/types/api.d.ts b/types/api.d.ts
index 1061075..bfb7903 100644
--- a/types/api.d.ts
+++ b/types/api.d.ts
@@ -14,5 +14,17 @@
     customErrorHandler?: (error: any) => boolean;
   }
 
+  interface SelectQueryResultOptionGuidGetDictionaryCategorySelectQueryOptionMap{
+    field1?:string
+  }
+
+  interface SelectQueryResultOptionGuidGetDictionaryCategorySelectQueryOption{
+    fieldNamesMap?: SelectQueryResultOptionGuidGetDictionaryCategorySelectQueryOptionMap;
+    code?:string
+  }
+
+  interface SelectQueryResultOptionGuidGetDictionaryDataSelectQueryResultOption{
+    code?:string
+  }
 
 }

--
Gitblit v1.9.1