From a49845f424ae5b1e43e391837a55c43ce07ea62d Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期三, 01 四月 2026 15:02:47 +0800
Subject: [PATCH] #前端

---
 rsf-design/src/views/basic-info/loc/modules/loc-dialog.vue          |  320 +++---------
 rsf-design/src/api/system-manage.js                                 |   24 
 rsf-design/src/views/basic-info/loc/locTable.columns.js             |  159 +----
 rsf-design/src/api/loc.js                                           |  122 +---
 rsf-design/src/views/system/role/modules/role-search.vue            |   73 +-
 rsf-design/src/views/system/role/roleTable.columns.js               |   77 +-
 rsf-design/src/views/system/role/rolePage.helpers.js                |   74 +-
 rsf-design/src/views/basic-info/loc/index.vue                       |  213 ++-----
 rsf-design/src/views/system/role/modules/role-permission-dialog.vue |   54 +-
 rsf-design/src/views/basic-info/bas-station-area/index.vue          |  116 ++-
 rsf-design/src/views/system/role/modules/role-edit-dialog.vue       |   68 +-
 rsf-design/src/views/system/role/index.vue                          |   35 
 rsf-design/src/views/basic-info/loc/locPage.helpers.js              |  225 ++------
 13 files changed, 560 insertions(+), 1,000 deletions(-)

diff --git a/rsf-design/src/api/loc.js b/rsf-design/src/api/loc.js
index 4213715..cfa1034 100644
--- a/rsf-design/src/api/loc.js
+++ b/rsf-design/src/api/loc.js
@@ -4,6 +4,10 @@
   return typeof value === 'string' ? value.trim() : value
 }
 
+function hasValue(value) {
+  return value !== '' && value !== null && value !== undefined
+}
+
 function normalizeIds(ids) {
   if (Array.isArray(ids)) {
     return ids
@@ -18,11 +22,23 @@
 }
 
 function normalizeNumber(value, fallback = void 0) {
-  if (value === '' || value === null || value === undefined) {
+  if (!hasValue(value)) {
     return fallback
   }
   const parsed = Number(value)
   return Number.isNaN(parsed) ? fallback : parsed
+}
+
+function toOptionalNumber(value) {
+  return hasValue(value) ? Number(value) : void 0
+}
+
+function toNumberOr(value, fallback) {
+  return hasValue(value) ? Number(value) : fallback
+}
+
+function buildNumberField(key, value) {
+  return hasValue(value) ? { [key]: Number(value) } : {}
 }
 
 function normalizeTypeIds(typeIds = []) {
@@ -66,103 +82,47 @@
 export function buildLocSearchParams(params = {}) {
   const searchParams = {
     condition: normalizeText(params.condition),
-    warehouseId:
-      params.warehouseId !== undefined && params.warehouseId !== null && params.warehouseId !== ''
-        ? Number(params.warehouseId)
-        : void 0,
-    areaId:
-      params.areaId !== undefined && params.areaId !== null && params.areaId !== ''
-        ? Number(params.areaId)
-        : void 0,
+    warehouseId: toOptionalNumber(params.warehouseId),
+    areaId: toOptionalNumber(params.areaId),
     code: normalizeText(params.code),
     useStatus: normalizeText(params.useStatus),
-    row:
-      params.row !== undefined && params.row !== null && params.row !== ''
-        ? Number(params.row)
-        : void 0,
-    col:
-      params.col !== undefined && params.col !== null && params.col !== ''
-        ? Number(params.col)
-        : void 0,
-    lev:
-      params.lev !== undefined && params.lev !== null && params.lev !== ''
-        ? Number(params.lev)
-        : void 0,
-    channel:
-      params.channel !== undefined && params.channel !== null && params.channel !== ''
-        ? Number(params.channel)
-        : void 0,
-    status:
-      params.status !== undefined && params.status !== null && params.status !== ''
-        ? Number(params.status)
-        : void 0,
+    row: toOptionalNumber(params.row),
+    col: toOptionalNumber(params.col),
+    lev: toOptionalNumber(params.lev),
+    channel: toOptionalNumber(params.channel),
+    status: toOptionalNumber(params.status),
     barcode: normalizeText(params.barcode),
     memo: normalizeText(params.memo)
   }
 
-  return Object.fromEntries(
-    Object.entries(searchParams).filter(([, value]) => value !== '' && value !== void 0 && value !== null)
-  )
+  return Object.fromEntries(Object.entries(searchParams).filter(([, value]) => hasValue(value)))
 }
 
 export function buildLocSavePayload(formData = {}) {
   return {
-    ...(formData.id !== undefined && formData.id !== null && formData.id !== ''
-      ? { id: Number(formData.id) }
-      : {}),
-    ...(formData.version !== undefined && formData.version !== null && formData.version !== ''
-      ? { version: Number(formData.version) }
-      : {}),
-    ...(formData.warehouseId !== undefined && formData.warehouseId !== null && formData.warehouseId !== ''
-      ? { warehouseId: Number(formData.warehouseId) }
-      : {}),
-    ...(formData.areaId !== undefined && formData.areaId !== null && formData.areaId !== ''
-      ? { areaId: Number(formData.areaId) }
-      : {}),
+    ...buildNumberField('id', formData.id),
+    ...buildNumberField('version', formData.version),
+    ...buildNumberField('warehouseId', formData.warehouseId),
+    ...buildNumberField('areaId', formData.areaId),
     code: normalizeText(formData.code) || '',
     typeIds: normalizeTypeIds(formData.typeIds),
-    ...(formData.flagLogic !== undefined && formData.flagLogic !== null && formData.flagLogic !== ''
-      ? { flagLogic: Number(formData.flagLogic) }
-      : {}),
+    ...buildNumberField('flagLogic', formData.flagLogic),
     fucAtrrs: normalizeText(formData.fucAtrrs) || '',
     barcode: normalizeText(formData.barcode) || '',
     unit: normalizeText(formData.unit) || '',
-    ...(formData.length !== undefined && formData.length !== null && formData.length !== ''
-      ? { length: Number(formData.length) }
-      : {}),
-    ...(formData.height !== undefined && formData.height !== null && formData.height !== ''
-      ? { height: Number(formData.height) }
-      : {}),
-    ...(formData.width !== undefined && formData.width !== null && formData.width !== ''
-      ? { width: Number(formData.width) }
-      : {}),
-    ...(formData.row !== undefined && formData.row !== null && formData.row !== ''
-      ? { row: Number(formData.row) }
-      : {}),
-    ...(formData.col !== undefined && formData.col !== null && formData.col !== ''
-      ? { col: Number(formData.col) }
-      : {}),
-    ...(formData.lev !== undefined && formData.lev !== null && formData.lev !== ''
-      ? { lev: Number(formData.lev) }
-      : {}),
-    ...(formData.channel !== undefined && formData.channel !== null && formData.channel !== ''
-      ? { channel: Number(formData.channel) }
-      : {}),
-    ...(formData.maxParts !== undefined && formData.maxParts !== null && formData.maxParts !== ''
-      ? { maxParts: Number(formData.maxParts) }
-      : {}),
-    ...(formData.maxPack !== undefined && formData.maxPack !== null && formData.maxPack !== ''
-      ? { maxPack: Number(formData.maxPack) }
-      : {}),
+    ...buildNumberField('length', formData.length),
+    ...buildNumberField('height', formData.height),
+    ...buildNumberField('width', formData.width),
+    ...buildNumberField('row', formData.row),
+    ...buildNumberField('col', formData.col),
+    ...buildNumberField('lev', formData.lev),
+    ...buildNumberField('channel', formData.channel),
+    ...buildNumberField('maxParts', formData.maxParts),
+    ...buildNumberField('maxPack', formData.maxPack),
     useStatus: normalizeText(formData.useStatus) || 'O',
-    ...(formData.flagLabelMange !== undefined && formData.flagLabelMange !== null && formData.flagLabelMange !== ''
-      ? { flagLabelMange: Number(formData.flagLabelMange) }
-      : {}),
+    ...buildNumberField('flagLabelMange', formData.flagLabelMange),
     locAttrs: normalizeText(formData.locAttrs) || '',
-    status:
-      formData.status !== undefined && formData.status !== null && formData.status !== ''
-        ? Number(formData.status)
-        : 1,
+    status: toNumberOr(formData.status, 1),
     memo: normalizeText(formData.memo) || ''
   }
 }
diff --git a/rsf-design/src/api/system-manage.js b/rsf-design/src/api/system-manage.js
index a9b0a8d..407b47c 100644
--- a/rsf-design/src/api/system-manage.js
+++ b/rsf-design/src/api/system-manage.js
@@ -213,7 +213,10 @@
 }
 
 function fetchOperationRecordPage(params = {}) {
-  return request.post({ url: '/operationRecord/page', params: buildOperationRecordPageParams(params) })
+  return request.post({
+    url: '/operationRecord/page',
+    params: buildOperationRecordPageParams(params)
+  })
 }
 
 function fetchConfigPage(params = {}) {
@@ -611,7 +614,9 @@
 }
 
 function fetchGetMenuList(params = {}) {
-  return request.post({ url: '/menu/list', params }).then((menuList) => adaptLegacyMenuTree(buildLegacyMenuTree(menuList)))
+  return request
+    .post({ url: '/menu/list', params })
+    .then((menuList) => adaptLegacyMenuTree(buildLegacyMenuTree(menuList)))
 }
 
 function adaptLegacyMenuTree(menuTree) {
@@ -619,9 +624,7 @@
     return []
   }
 
-  return menuTree
-    .map((node) => adaptLegacyMenuNode(node))
-    .filter(Boolean)
+  return menuTree.map((node) => adaptLegacyMenuNode(node)).filter(Boolean)
 }
 
 function buildLegacyMenuTree(menuList) {
@@ -770,11 +773,12 @@
 }
 
 function buildLegacyMenuPath(node) {
-  const rawPath = typeof node.route === 'string' && node.route.trim()
-    ? node.route
-    : typeof node.path === 'string'
-      ? node.path
-      : ''
+  const rawPath =
+    typeof node.route === 'string' && node.route.trim()
+      ? node.route
+      : typeof node.path === 'string'
+        ? node.path
+        : ''
   return normalizeLegacyPath(rawPath)
 }
 
diff --git a/rsf-design/src/views/basic-info/bas-station-area/index.vue b/rsf-design/src/views/basic-info/bas-station-area/index.vue
index 3160d21..34c283e 100644
--- a/rsf-design/src/views/basic-info/bas-station-area/index.vue
+++ b/rsf-design/src/views/basic-info/bas-station-area/index.vue
@@ -12,7 +12,9 @@
       <ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="refreshData">
         <template #left>
           <ElSpace wrap>
-            <ElButton v-auth="'add'" @click="handleShowDialog('add')" v-ripple>鏂板绔欑偣鍖哄煙</ElButton>
+            <ElButton v-auth="'add'" @click="handleShowDialog('add')" v-ripple
+              >鏂板绔欑偣鍖哄煙</ElButton
+            >
             <ElButton
               v-auth="'delete'"
               type="danger"
@@ -296,9 +298,13 @@
     detailDrawerVisible.value = true
     detailLoading.value = true
     try {
-      const detail = await guardRequestWithMessage(fetchBasStationAreaDetail(row.id), {}, {
-        timeoutMessage: '绔欑偣鍖哄煙璇︽儏鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
-      })
+      const detail = await guardRequestWithMessage(
+        fetchBasStationAreaDetail(row.id),
+        {},
+        {
+          timeoutMessage: '绔欑偣鍖哄煙璇︽儏鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
+        }
+      )
       detailData.value = normalizeBasStationAreaDetailRecord(detail, {
         resolveAreaLabel,
         resolveCrossZoneAreaLabel,
@@ -342,7 +348,9 @@
           timeoutMessage: '绔欑偣鍒悕閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
         }
       )
-      stationOptions.value = resolveBasStationAreaStationOptions(defaultResponseAdapter(response).records)
+      stationOptions.value = resolveBasStationAreaStationOptions(
+        defaultResponseAdapter(response).records
+      )
       stationOptionsLoaded.value = true
     })()
 
@@ -360,48 +368,66 @@
 
   async function openEditDialog(row) {
     try {
-      const detail = await guardRequestWithMessage(fetchBasStationAreaDetail(row.id), {}, {
-        timeoutMessage: '绔欑偣鍖哄煙璇︽儏鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
-      })
+      const detail = await guardRequestWithMessage(
+        fetchBasStationAreaDetail(row.id),
+        {},
+        {
+          timeoutMessage: '绔欑偣鍖哄煙璇︽儏鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
+        }
+      )
       await handleShowDialog('edit', detail)
     } catch (error) {
       ElMessage.error(error?.message || '鑾峰彇绔欑偣鍖哄煙璇︽儏澶辫触')
     }
   }
 
-  const { columns, columnChecks, data, loading, pagination, getData, replaceSearchParams, resetSearchParams, handleSizeChange, handleCurrentChange, refreshData, refreshCreate, refreshUpdate, refreshRemove } =
-    useTable({
-      core: {
-        apiFn: fetchBasStationAreaPage,
-        apiParams: buildBasStationAreaPageQueryParams(searchForm.value),
-        paginationKey: getBasStationAreaPaginationKey(),
-        columnsFactory: () =>
-          createBasStationAreaTableColumns({
-            handleView: openDetail,
-            handleEdit: hasAuth('update') ? openEditDialog : null,
-            handleDelete: hasAuth('delete') ? (row) => handleDeleteAction?.(row) : null,
-            canEdit: hasAuth('update'),
-            canDelete: hasAuth('delete')
-          })
-      },
-      transform: {
-        dataTransformer: (records) => {
-          if (!Array.isArray(records)) {
-            return []
-          }
-          return records.map((item) =>
-            normalizeBasStationAreaListRow(item, {
-              resolveAreaLabel,
-              resolveCrossZoneAreaLabel,
-              resolveContainerTypeLabel,
-              resolveTypeLabel,
-              resolveStationAliasLabel,
-              resolveUseStatusLabel
-            })
-          )
+  const {
+    columns,
+    columnChecks,
+    data,
+    loading,
+    pagination,
+    getData,
+    replaceSearchParams,
+    resetSearchParams,
+    handleSizeChange,
+    handleCurrentChange,
+    refreshData,
+    refreshCreate,
+    refreshUpdate,
+    refreshRemove
+  } = useTable({
+    core: {
+      apiFn: fetchBasStationAreaPage,
+      apiParams: buildBasStationAreaPageQueryParams(searchForm.value),
+      paginationKey: getBasStationAreaPaginationKey(),
+      columnsFactory: () =>
+        createBasStationAreaTableColumns({
+          handleView: openDetail,
+          handleEdit: hasAuth('update') ? openEditDialog : null,
+          handleDelete: hasAuth('delete') ? (row) => handleDeleteAction?.(row) : null,
+          canEdit: hasAuth('update'),
+          canDelete: hasAuth('delete')
+        })
+    },
+    transform: {
+      dataTransformer: (records) => {
+        if (!Array.isArray(records)) {
+          return []
         }
+        return records.map((item) =>
+          normalizeBasStationAreaListRow(item, {
+            resolveAreaLabel,
+            resolveCrossZoneAreaLabel,
+            resolveContainerTypeLabel,
+            resolveTypeLabel,
+            resolveStationAliasLabel,
+            resolveUseStatusLabel
+          })
+        )
       }
-    })
+    }
+  })
 
   const {
     dialogVisible,
@@ -442,7 +468,9 @@
     const response = await guardRequestWithMessage(fetchWarehouseAreasList(), [], {
       timeoutMessage: '搴撳尯閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
     })
-    const options = resolveBasStationAreaWarehouseAreaOptions(defaultResponseAdapter(response).records)
+    const options = resolveBasStationAreaWarehouseAreaOptions(
+      defaultResponseAdapter(response).records
+    )
     areaOptions.value = options
     crossZoneAreaOptions.value = options
   }
@@ -458,7 +486,9 @@
       { records: [] },
       { timeoutMessage: '瀹瑰櫒绫诲瀷閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟' }
     )
-    containerTypeOptions.value = resolveBasStationAreaContainerTypeOptions(defaultResponseAdapter(response).records)
+    containerTypeOptions.value = resolveBasStationAreaContainerTypeOptions(
+      defaultResponseAdapter(response).records
+    )
   }
 
   async function loadUseStatusOptions() {
@@ -472,7 +502,9 @@
       { records: [] },
       { timeoutMessage: '浣跨敤鐘舵�侀�夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟' }
     )
-    useStatusOptions.value = resolveBasStationAreaUseStatusOptions(defaultResponseAdapter(response).records)
+    useStatusOptions.value = resolveBasStationAreaUseStatusOptions(
+      defaultResponseAdapter(response).records
+    )
   }
 
   onMounted(async () => {
diff --git a/rsf-design/src/views/basic-info/loc/index.vue b/rsf-design/src/views/basic-info/loc/index.vue
index c4287c6..8e69d59 100644
--- a/rsf-design/src/views/basic-info/loc/index.vue
+++ b/rsf-design/src/views/basic-info/loc/index.vue
@@ -103,6 +103,7 @@
     buildLocSavePayload,
     buildLocSearchParams,
     createLocSearchState,
+    filterLocAreaOptionsByWarehouse,
     getLocPaginationKey,
     getLocStatusOptions,
     getLocUseStatusOptions,
@@ -130,141 +131,74 @@
 
   const reportTitle = LOC_REPORT_TITLE
   const reportQueryParams = computed(() => buildLocSearchParams(searchForm.value))
+  const filteredSearchAreaOptions = computed(() =>
+    filterLocAreaOptionsByWarehouse(areaOptions.value, searchForm.value.warehouseId)
+  )
 
-  const searchItems = computed(() => [
-    {
-      label: '鍏抽敭瀛�',
-      key: 'condition',
+  function createInputSearchItem(label, key, placeholder) {
+    return {
+      label,
+      key,
       type: 'input',
       props: {
         clearable: true,
-        placeholder: '璇疯緭鍏ュ簱浣嶅彿/瀹瑰櫒缂栫爜/澶囨敞'
-      }
-    },
-    {
-      label: '浠撳簱',
-      key: 'warehouseId',
-      type: 'select',
-      props: {
-        clearable: true,
-        filterable: true,
-        options: warehouseOptions.value
-      }
-    },
-    {
-      label: '搴撳尯',
-      key: 'areaId',
-      type: 'select',
-      props: {
-        clearable: true,
-        filterable: true,
-        options: areaOptions.value.filter((item) => {
-          if (!searchForm.value.warehouseId) {
-            return true
-          }
-          if (item?.warehouseId === undefined || item?.warehouseId === null) {
-            return true
-          }
-          return Number(item.warehouseId) === Number(searchForm.value.warehouseId)
-        })
-      }
-    },
-    {
-      label: '搴撲綅鍙�',
-      key: 'code',
-      type: 'input',
-      props: {
-        clearable: true,
-        placeholder: '璇疯緭鍏ュ簱浣嶅彿'
-      }
-    },
-    {
-      label: '浣跨敤鐘舵��',
-      key: 'useStatus',
-      type: 'select',
-      props: {
-        clearable: true,
-        filterable: true,
-        options: getLocUseStatusOptions()
-      }
-    },
-    {
-      label: '鎺�',
-      key: 'row',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ユ帓'
-      }
-    },
-    {
-      label: '鍒�',
-      key: 'col',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ュ垪'
-      }
-    },
-    {
-      label: '灞�',
-      key: 'lev',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ュ眰'
-      }
-    },
-    {
-      label: '宸烽亾',
-      key: 'channel',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ュ贩閬�'
-      }
-    },
-    {
-      label: '鐘舵��',
-      key: 'status',
-      type: 'select',
-      props: {
-        clearable: true,
-        options: getLocStatusOptions()
-      }
-    },
-    {
-      label: '瀹瑰櫒缂栫爜',
-      key: 'barcode',
-      type: 'input',
-      props: {
-        clearable: true,
-        placeholder: '璇疯緭鍏ュ鍣ㄧ紪鐮�'
-      }
-    },
-    {
-      label: '澶囨敞',
-      key: 'memo',
-      type: 'input',
-      props: {
-        clearable: true,
-        placeholder: '璇疯緭鍏ュ娉�'
+        placeholder
       }
     }
+  }
+
+  function createNumberSearchItem(label, key, placeholder) {
+    return {
+      label,
+      key,
+      type: 'number',
+      props: {
+        min: 0,
+        controlsPosition: 'right',
+        placeholder
+      }
+    }
+  }
+
+  function createSelectSearchItem(label, key, options, extraProps = {}) {
+    return {
+      label,
+      key,
+      type: 'select',
+      props: {
+        clearable: true,
+        ...extraProps,
+        options
+      }
+    }
+  }
+
+  const searchItems = computed(() => [
+    createInputSearchItem('鍏抽敭瀛�', 'condition', '璇疯緭鍏ュ簱浣嶅彿/瀹瑰櫒缂栫爜/澶囨敞'),
+    createSelectSearchItem('浠撳簱', 'warehouseId', warehouseOptions.value, { filterable: true }),
+    createSelectSearchItem('搴撳尯', 'areaId', filteredSearchAreaOptions.value, { filterable: true }),
+    createInputSearchItem('搴撲綅鍙�', 'code', '璇疯緭鍏ュ簱浣嶅彿'),
+    createSelectSearchItem('浣跨敤鐘舵��', 'useStatus', getLocUseStatusOptions(), { filterable: true }),
+    createNumberSearchItem('鎺�', 'row', '璇疯緭鍏ユ帓'),
+    createNumberSearchItem('鍒�', 'col', '璇疯緭鍏ュ垪'),
+    createNumberSearchItem('灞�', 'lev', '璇疯緭鍏ュ眰'),
+    createNumberSearchItem('宸烽亾', 'channel', '璇疯緭鍏ュ贩閬�'),
+    createSelectSearchItem('鐘舵��', 'status', getLocStatusOptions()),
+    createInputSearchItem('瀹瑰櫒缂栫爜', 'barcode', '璇疯緭鍏ュ鍣ㄧ紪鐮�'),
+    createInputSearchItem('澶囨敞', 'memo', '璇疯緭鍏ュ娉�')
   ])
+
+  async function fetchLocDetailById(id) {
+    return guardRequestWithMessage(fetchGetLocDetail(id), {}, {
+      timeoutMessage: '搴撲綅璇︽儏鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
+    })
+  }
 
   async function openDetail(row) {
     detailDrawerVisible.value = true
     detailLoading.value = true
     try {
-      const detail = await guardRequestWithMessage(fetchGetLocDetail(row.id), {}, {
-        timeoutMessage: '搴撲綅璇︽儏鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
-      })
-      detailData.value = normalizeLocListRow(detail)
+      detailData.value = normalizeLocListRow(await fetchLocDetailById(row.id))
     } catch (error) {
       detailDrawerVisible.value = false
       detailData.value = {}
@@ -276,10 +210,7 @@
 
   async function openEditDialog(row) {
     try {
-      const detail = await guardRequestWithMessage(fetchGetLocDetail(row.id), {}, {
-        timeoutMessage: '搴撲綅璇︽儏鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
-      })
-      showDialog('edit', detail)
+      showDialog('edit', await fetchLocDetailById(row.id))
     } catch (error) {
       ElMessage.error(error?.message || '鑾峰彇搴撲綅璇︽儏澶辫触')
     }
@@ -400,25 +331,9 @@
     })
   )
 
-  async function loadWarehouseOptions() {
-    const response = await guardRequestWithMessage(fetchWarehouseList(), [], {
-      timeoutMessage: '浠撳簱閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
-    })
-    warehouseOptions.value = resolveLocWarehouseOptions(defaultResponseAdapter(response).records)
-  }
-
-  async function loadAreaOptions() {
-    const response = await guardRequestWithMessage(fetchWarehouseAreasList(), [], {
-      timeoutMessage: '搴撳尯閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
-    })
-    areaOptions.value = resolveLocAreaOptions(defaultResponseAdapter(response).records)
-  }
-
-  async function loadLocTypeOptions() {
-    const response = await guardRequestWithMessage(fetchLocTypeList(), [], {
-      timeoutMessage: '搴撲綅绫诲瀷閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'
-    })
-    locTypeOptions.value = resolveLocTypeOptions(defaultResponseAdapter(response).records)
+  async function loadOptions(requestFn, resolver, targetRef, timeoutMessage) {
+    const response = await guardRequestWithMessage(requestFn(), [], { timeoutMessage })
+    targetRef.value = resolver(defaultResponseAdapter(response).records)
   }
 
   function handleSearch(params) {
@@ -432,6 +347,10 @@
   }
 
   onMounted(async () => {
-    await Promise.all([loadWarehouseOptions(), loadAreaOptions(), loadLocTypeOptions()])
+    await Promise.all([
+      loadOptions(fetchWarehouseList, resolveLocWarehouseOptions, warehouseOptions, '浠撳簱閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'),
+      loadOptions(fetchWarehouseAreasList, resolveLocAreaOptions, areaOptions, '搴撳尯閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟'),
+      loadOptions(fetchLocTypeList, resolveLocTypeOptions, locTypeOptions, '搴撲綅绫诲瀷閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟')
+    ])
   })
 </script>
diff --git a/rsf-design/src/views/basic-info/loc/locPage.helpers.js b/rsf-design/src/views/basic-info/loc/locPage.helpers.js
index 333ddf8..c85fc74 100644
--- a/rsf-design/src/views/basic-info/loc/locPage.helpers.js
+++ b/rsf-design/src/views/basic-info/loc/locPage.helpers.js
@@ -12,6 +12,12 @@
   F: { text: '鍦ㄥ簱', type: 'primary' }
 }
 
+const LOC_ID_FIELDS = ['id', 'version', 'warehouseId', 'areaId']
+const LOC_SIZE_FIELDS = ['length', 'height', 'width']
+const LOC_POSITION_FIELDS = ['row', 'col', 'lev', 'channel']
+const LOC_CAPACITY_FIELDS = ['maxParts', 'maxPack']
+const LOC_OPTIONAL_NUMBER_FIELDS = [...LOC_ID_FIELDS, ...LOC_SIZE_FIELDS, ...LOC_POSITION_FIELDS, ...LOC_CAPACITY_FIELDS]
+
 export const LOC_REPORT_TITLE = '搴撲綅鎶ヨ〃'
 export const LOC_REPORT_STYLE = {
   titleAlign: 'center',
@@ -25,12 +31,32 @@
   return String(value ?? '').trim()
 }
 
+function hasValue(value) {
+  return value !== '' && value !== null && value !== undefined
+}
+
 function normalizeNumber(value, fallback = void 0) {
-  if (value === '' || value === null || value === undefined) {
+  if (!hasValue(value)) {
     return fallback
   }
   const parsed = Number(value)
   return Number.isNaN(parsed) ? fallback : parsed
+}
+
+function toOptionalNumber(value) {
+  return hasValue(value) ? Number(value) : void 0
+}
+
+function toNumberOr(value, fallback) {
+  return hasValue(value) ? Number(value) : fallback
+}
+
+function buildNumberField(key, value) {
+  return hasValue(value) ? { [key]: Number(value) } : {}
+}
+
+function buildOptionalNumberFields(source = {}, fields = []) {
+  return Object.fromEntries(fields.map((field) => [field, toOptionalNumber(source[field])]).filter(([, value]) => hasValue(value)))
 }
 
 function normalizeFlagText(value) {
@@ -45,19 +71,27 @@
 
 function normalizeTypeIds(typeIds = []) {
   if (Array.isArray(typeIds)) {
-    return typeIds
-      .map((item) => normalizeNumber(item, void 0))
-      .filter((item) => item !== void 0 && item !== null)
+    return typeIds.map((item) => normalizeNumber(item, void 0)).filter(hasValue)
   }
 
   if (typeof typeIds === 'string' && typeIds.trim()) {
-    return typeIds
-      .split(',')
-      .map((item) => normalizeNumber(item, void 0))
-      .filter((item) => item !== void 0 && item !== null)
+    return typeIds.split(',').map((item) => normalizeNumber(item, void 0)).filter(hasValue)
   }
 
   return []
+}
+
+export function filterLocAreaOptionsByWarehouse(options = [], warehouseId) {
+  if (!warehouseId) {
+    return options
+  }
+
+  return options.filter((item) => {
+    if (!hasValue(item?.warehouseId)) {
+      return true
+    }
+    return Number(item.warehouseId) === Number(warehouseId)
+  })
 }
 
 export function createLocSearchState() {
@@ -158,43 +192,20 @@
 export function buildLocSearchParams(params = {}) {
   const searchParams = {
     condition: normalizeText(params.condition),
-    warehouseId:
-      params.warehouseId !== undefined && params.warehouseId !== null && params.warehouseId !== ''
-        ? Number(params.warehouseId)
-        : void 0,
-    areaId:
-      params.areaId !== undefined && params.areaId !== null && params.areaId !== ''
-        ? Number(params.areaId)
-        : void 0,
+    warehouseId: toOptionalNumber(params.warehouseId),
+    areaId: toOptionalNumber(params.areaId),
     code: normalizeText(params.code),
     useStatus: normalizeText(params.useStatus),
-    row:
-      params.row !== undefined && params.row !== null && params.row !== ''
-        ? Number(params.row)
-        : void 0,
-    col:
-      params.col !== undefined && params.col !== null && params.col !== ''
-        ? Number(params.col)
-        : void 0,
-    lev:
-      params.lev !== undefined && params.lev !== null && params.lev !== ''
-        ? Number(params.lev)
-        : void 0,
-    channel:
-      params.channel !== undefined && params.channel !== null && params.channel !== ''
-        ? Number(params.channel)
-        : void 0,
-    status:
-      params.status !== undefined && params.status !== null && params.status !== ''
-        ? Number(params.status)
-        : void 0,
+    row: toOptionalNumber(params.row),
+    col: toOptionalNumber(params.col),
+    lev: toOptionalNumber(params.lev),
+    channel: toOptionalNumber(params.channel),
+    status: toOptionalNumber(params.status),
     barcode: normalizeText(params.barcode),
     memo: normalizeText(params.memo)
   }
 
-  return Object.fromEntries(
-    Object.entries(searchParams).filter(([, value]) => value !== '' && value !== void 0 && value !== null)
-  )
+  return Object.fromEntries(Object.entries(searchParams).filter(([, value]) => hasValue(value)))
 }
 
 export function buildLocPageQueryParams(params = {}) {
@@ -207,62 +218,18 @@
 
 export function buildLocSavePayload(formData = {}) {
   return {
-    ...(formData.id !== undefined && formData.id !== null && formData.id !== ''
-      ? { id: Number(formData.id) }
-      : {}),
-    ...(formData.version !== undefined && formData.version !== null && formData.version !== ''
-      ? { version: Number(formData.version) }
-      : {}),
-    ...(formData.warehouseId !== undefined && formData.warehouseId !== null && formData.warehouseId !== ''
-      ? { warehouseId: Number(formData.warehouseId) }
-      : {}),
-    ...(formData.areaId !== undefined && formData.areaId !== null && formData.areaId !== ''
-      ? { areaId: Number(formData.areaId) }
-      : {}),
+    ...buildOptionalNumberFields(formData, LOC_ID_FIELDS),
     code: normalizeText(formData.code) || '',
     typeIds: normalizeTypeIds(formData.typeIds),
-    ...(formData.flagLogic !== undefined && formData.flagLogic !== null && formData.flagLogic !== ''
-      ? { flagLogic: Number(formData.flagLogic) }
-      : {}),
+    ...buildNumberField('flagLogic', formData.flagLogic),
     fucAtrrs: normalizeText(formData.fucAtrrs) || '',
     barcode: normalizeText(formData.barcode) || '',
     unit: normalizeText(formData.unit) || '',
-    ...(formData.length !== undefined && formData.length !== null && formData.length !== ''
-      ? { length: Number(formData.length) }
-      : {}),
-    ...(formData.height !== undefined && formData.height !== null && formData.height !== ''
-      ? { height: Number(formData.height) }
-      : {}),
-    ...(formData.width !== undefined && formData.width !== null && formData.width !== ''
-      ? { width: Number(formData.width) }
-      : {}),
-    ...(formData.row !== undefined && formData.row !== null && formData.row !== ''
-      ? { row: Number(formData.row) }
-      : {}),
-    ...(formData.col !== undefined && formData.col !== null && formData.col !== ''
-      ? { col: Number(formData.col) }
-      : {}),
-    ...(formData.lev !== undefined && formData.lev !== null && formData.lev !== ''
-      ? { lev: Number(formData.lev) }
-      : {}),
-    ...(formData.channel !== undefined && formData.channel !== null && formData.channel !== ''
-      ? { channel: Number(formData.channel) }
-      : {}),
-    ...(formData.maxParts !== undefined && formData.maxParts !== null && formData.maxParts !== ''
-      ? { maxParts: Number(formData.maxParts) }
-      : {}),
-    ...(formData.maxPack !== undefined && formData.maxPack !== null && formData.maxPack !== ''
-      ? { maxPack: Number(formData.maxPack) }
-      : {}),
+    ...buildOptionalNumberFields(formData, [...LOC_SIZE_FIELDS, ...LOC_POSITION_FIELDS, ...LOC_CAPACITY_FIELDS]),
     useStatus: normalizeText(formData.useStatus) || 'O',
-    ...(formData.flagLabelMange !== undefined && formData.flagLabelMange !== null && formData.flagLabelMange !== ''
-      ? { flagLabelMange: Number(formData.flagLabelMange) }
-      : {}),
+    ...buildNumberField('flagLabelMange', formData.flagLabelMange),
     locAttrs: normalizeText(formData.locAttrs) || '',
-    status:
-      formData.status !== undefined && formData.status !== null && formData.status !== ''
-        ? Number(formData.status)
-        : 1,
+    status: toNumberOr(formData.status, 1),
     memo: normalizeText(formData.memo) || ''
   }
 }
@@ -270,70 +237,17 @@
 export function buildLocDialogModel(record = {}) {
   return {
     ...createLocFormState(),
-    ...(record.id !== undefined && record.id !== null && record.id !== '' ? { id: Number(record.id) } : {}),
-    ...(record.version !== undefined && record.version !== null && record.version !== ''
-      ? { version: Number(record.version) }
-      : {}),
-    warehouseId:
-      record.warehouseId !== undefined && record.warehouseId !== null && record.warehouseId !== ''
-        ? Number(record.warehouseId)
-        : void 0,
-    areaId:
-      record.areaId !== undefined && record.areaId !== null && record.areaId !== ''
-        ? Number(record.areaId)
-        : void 0,
+    ...buildOptionalNumberFields(record, LOC_OPTIONAL_NUMBER_FIELDS),
     code: normalizeText(record.code || ''),
     typeIds: normalizeTypeIds(record.typeIds ?? record.type ?? ''),
-    flagLogic:
-      record.flagLogic !== undefined && record.flagLogic !== null && record.flagLogic !== ''
-        ? Number(record.flagLogic)
-        : 0,
+    flagLogic: toNumberOr(record.flagLogic, 0),
     fucAtrrs: normalizeText(record.fucAtrrs || ''),
     barcode: normalizeText(record.barcode || ''),
     unit: normalizeText(record.unit || ''),
-    length:
-      record.length !== undefined && record.length !== null && record.length !== ''
-        ? Number(record.length)
-        : void 0,
-    height:
-      record.height !== undefined && record.height !== null && record.height !== ''
-        ? Number(record.height)
-        : void 0,
-    width:
-      record.width !== undefined && record.width !== null && record.width !== ''
-        ? Number(record.width)
-        : void 0,
-    row:
-      record.row !== undefined && record.row !== null && record.row !== ''
-        ? Number(record.row)
-        : void 0,
-    col:
-      record.col !== undefined && record.col !== null && record.col !== ''
-        ? Number(record.col)
-        : void 0,
-    lev:
-      record.lev !== undefined && record.lev !== null && record.lev !== ''
-        ? Number(record.lev)
-        : void 0,
-    channel:
-      record.channel !== undefined && record.channel !== null && record.channel !== ''
-        ? Number(record.channel)
-        : void 0,
-    maxParts:
-      record.maxParts !== undefined && record.maxParts !== null && record.maxParts !== ''
-        ? Number(record.maxParts)
-        : void 0,
-    maxPack:
-      record.maxPack !== undefined && record.maxPack !== null && record.maxPack !== ''
-        ? Number(record.maxPack)
-        : void 0,
     useStatus: normalizeText(record.useStatus || 'O') || 'O',
-    flagLabelMange:
-      record.flagLabelMange !== undefined && record.flagLabelMange !== null && record.flagLabelMange !== ''
-        ? Number(record.flagLabelMange)
-        : 0,
+    flagLabelMange: toNumberOr(record.flagLabelMange, 0),
     locAttrs: normalizeText(record.locAttrs || ''),
-    status: record.status !== undefined && record.status !== null ? Number(record.status) : 1,
+    status: toNumberOr(record.status, 1),
     memo: normalizeText(record.memo || '')
   }
 }
@@ -344,6 +258,7 @@
   const typeIds = normalizeTypeIds(record.typeIds ?? record.type ?? '')
   return {
     ...record,
+    ...buildOptionalNumberFields(record, [...LOC_SIZE_FIELDS, ...LOC_POSITION_FIELDS, ...LOC_CAPACITY_FIELDS]),
     warehouseName: normalizeText(record.warehouseId$ || record.warehouseName || ''),
     areaName: normalizeText(record.areaId$ || record.areaName || ''),
     typeIds,
@@ -361,15 +276,6 @@
     statusText: statusMeta.text,
     statusType: statusMeta.type,
     statusBool: record.statusBool !== void 0 ? Boolean(record.statusBool) : statusMeta.bool,
-    row: record.row !== undefined && record.row !== null ? Number(record.row) : void 0,
-    col: record.col !== undefined && record.col !== null ? Number(record.col) : void 0,
-    lev: record.lev !== undefined && record.lev !== null ? Number(record.lev) : void 0,
-    channel: record.channel !== undefined && record.channel !== null ? Number(record.channel) : void 0,
-    length: record.length !== undefined && record.length !== null ? Number(record.length) : void 0,
-    height: record.height !== undefined && record.height !== null ? Number(record.height) : void 0,
-    width: record.width !== undefined && record.width !== null ? Number(record.width) : void 0,
-    maxParts: record.maxParts !== undefined && record.maxParts !== null ? Number(record.maxParts) : void 0,
-    maxPack: record.maxPack !== undefined && record.maxPack !== null ? Number(record.maxPack) : void 0,
     createByText: normalizeText(record.createBy$ || record.createByText || ''),
     createTimeText: normalizeText(record.createTime$ || record.createTime || ''),
     updateByText: normalizeText(record.updateBy$ || record.updateByText || ''),
@@ -417,7 +323,7 @@
         return null
       }
       const value = item.id ?? item.value
-      if (value === void 0 || value === null || value === '') {
+      if (!hasValue(value)) {
         return null
       }
       return {
@@ -439,16 +345,13 @@
         return null
       }
       const value = item.id ?? item.value
-      if (value === void 0 || value === null || value === '') {
+      if (!hasValue(value)) {
         return null
       }
       return {
         value: Number(value),
         label: normalizeText(item.name || item.code || `搴撳尯 ${value}`),
-        warehouseId:
-          item.warehouseId !== undefined && item.warehouseId !== null && item.warehouseId !== ''
-            ? Number(item.warehouseId)
-            : void 0
+        warehouseId: toOptionalNumber(item.warehouseId)
       }
     })
     .filter(Boolean)
@@ -465,7 +368,7 @@
         return null
       }
       const value = item.id ?? item.value
-      if (value === void 0 || value === null || value === '') {
+      if (!hasValue(value)) {
         return null
       }
       return {
diff --git a/rsf-design/src/views/basic-info/loc/locTable.columns.js b/rsf-design/src/views/basic-info/loc/locTable.columns.js
index aff5d2f..2ea0bcb 100644
--- a/rsf-design/src/views/basic-info/loc/locTable.columns.js
+++ b/rsf-design/src/views/basic-info/loc/locTable.columns.js
@@ -3,6 +3,39 @@
 import ArtButtonMore from '@/components/core/forms/art-button-more/index.vue'
 import { getLocStatusMeta, getLocUseStatusMeta } from './locPage.helpers'
 
+function createTextColumn(prop, label, minWidth, formatter) {
+  return {
+    prop,
+    label,
+    minWidth,
+    showOverflowTooltip: true,
+    formatter: formatter || ((row) => row[prop] || '--')
+  }
+}
+
+function createNumberColumn(prop, label, width) {
+  return {
+    prop,
+    label,
+    width,
+    align: 'center',
+    formatter: (row) => row[prop] ?? '--'
+  }
+}
+
+function createTagColumn(prop, label, width, resolveMeta) {
+  return {
+    prop,
+    label,
+    width,
+    align: 'center',
+    formatter: (row) => {
+      const statusMeta = resolveMeta(row)
+      return h(ElTag, { type: statusMeta.type, effect: 'light' }, () => statusMeta.text)
+    }
+  }
+}
+
 export function createLocTableColumns({
   handleView,
   handleEdit,
@@ -23,117 +56,21 @@
   return [
     { type: 'selection', width: 48, align: 'center' },
     { type: 'globalIndex', label: '搴忓彿', width: 72, align: 'center' },
-    {
-      prop: 'code',
-      label: '搴撲綅鍙�',
-      minWidth: 160,
-      showOverflowTooltip: true,
-      formatter: (row) => row.code || '--'
-    },
-    {
-      prop: 'warehouseName',
-      label: '浠撳簱',
-      minWidth: 150,
-      showOverflowTooltip: true,
-      formatter: (row) => row.warehouseName || row.warehouseId$ || '--'
-    },
-    {
-      prop: 'areaName',
-      label: '搴撳尯',
-      minWidth: 150,
-      showOverflowTooltip: true,
-      formatter: (row) => row.areaName || row.areaId$ || '--'
-    },
-    {
-      prop: 'typeIdsText',
-      label: '搴撲綅绫诲瀷',
-      minWidth: 180,
-      showOverflowTooltip: true,
-      formatter: (row) => row.typeIdsText || '--'
-    },
-    {
-      prop: 'row',
-      label: '鎺�',
-      width: 80,
-      align: 'center',
-      formatter: (row) => row.row ?? '--'
-    },
-    {
-      prop: 'col',
-      label: '鍒�',
-      width: 80,
-      align: 'center',
-      formatter: (row) => row.col ?? '--'
-    },
-    {
-      prop: 'lev',
-      label: '灞�',
-      width: 80,
-      align: 'center',
-      formatter: (row) => row.lev ?? '--'
-    },
-    {
-      prop: 'channel',
-      label: '宸烽亾',
-      width: 90,
-      align: 'center',
-      formatter: (row) => row.channel ?? '--'
-    },
-    {
-      prop: 'useStatus',
-      label: '浣跨敤鐘舵��',
-      width: 110,
-      align: 'center',
-      formatter: (row) => {
-        const statusMeta = getLocUseStatusMeta(row.useStatus)
-        return h(ElTag, { type: statusMeta.type, effect: 'light' }, () => statusMeta.text)
-      }
-    },
-    {
-      prop: 'flagLogicText',
-      label: '铏氭嫙搴撲綅',
-      width: 110,
-      align: 'center',
-      formatter: (row) => row.flagLogicText || '--'
-    },
-    {
-      prop: 'flagLabelMangeText',
-      label: '鏍囩绠$悊',
-      width: 110,
-      align: 'center',
-      formatter: (row) => row.flagLabelMangeText || '--'
-    },
-    {
-      prop: 'barcode',
-      label: '瀹瑰櫒缂栫爜',
-      minWidth: 150,
-      showOverflowTooltip: true,
-      formatter: (row) => row.barcode || '--'
-    },
-    {
-      prop: 'status',
-      label: '鐘舵��',
-      width: 100,
-      align: 'center',
-      formatter: (row) => {
-        const statusMeta = getLocStatusMeta(row.statusBool ?? row.status)
-        return h(ElTag, { type: statusMeta.type, effect: 'light' }, () => statusMeta.text)
-      }
-    },
-    {
-      prop: 'updateTimeText',
-      label: '鏇存柊鏃堕棿',
-      minWidth: 170,
-      showOverflowTooltip: true,
-      formatter: (row) => row.updateTimeText || row.updateTime$ || '--'
-    },
-    {
-      prop: 'memo',
-      label: '澶囨敞',
-      minWidth: 180,
-      showOverflowTooltip: true,
-      formatter: (row) => row.memo || '--'
-    },
+    createTextColumn('code', '搴撲綅鍙�', 160),
+    createTextColumn('warehouseName', '浠撳簱', 150, (row) => row.warehouseName || row.warehouseId$ || '--'),
+    createTextColumn('areaName', '搴撳尯', 150, (row) => row.areaName || row.areaId$ || '--'),
+    createTextColumn('typeIdsText', '搴撲綅绫诲瀷', 180),
+    createNumberColumn('row', '鎺�', 80),
+    createNumberColumn('col', '鍒�', 80),
+    createNumberColumn('lev', '灞�', 80),
+    createNumberColumn('channel', '宸烽亾', 90),
+    createTagColumn('useStatus', '浣跨敤鐘舵��', 110, (row) => getLocUseStatusMeta(row.useStatus)),
+    createTextColumn('flagLogicText', '铏氭嫙搴撲綅', 110),
+    createTextColumn('flagLabelMangeText', '鏍囩绠$悊', 110),
+    createTextColumn('barcode', '瀹瑰櫒缂栫爜', 150),
+    createTagColumn('status', '鐘舵��', 100, (row) => getLocStatusMeta(row.statusBool ?? row.status)),
+    createTextColumn('updateTimeText', '鏇存柊鏃堕棿', 170, (row) => row.updateTimeText || row.updateTime$ || '--'),
+    createTextColumn('memo', '澶囨敞', 180),
     {
       prop: 'operation',
       label: '鎿嶄綔',
diff --git a/rsf-design/src/views/basic-info/loc/modules/loc-dialog.vue b/rsf-design/src/views/basic-info/loc/modules/loc-dialog.vue
index a3a88c2..4765f26 100644
--- a/rsf-design/src/views/basic-info/loc/modules/loc-dialog.vue
+++ b/rsf-design/src/views/basic-info/loc/modules/loc-dialog.vue
@@ -35,6 +35,7 @@
   import {
     buildLocDialogModel,
     createLocFormState,
+    filterLocAreaOptionsByWarehouse,
     getLocBinaryOptions,
     getLocStatusOptions,
     getLocUseStatusOptions
@@ -56,17 +57,53 @@
   const isEdit = computed(() => props.dialogType === 'edit')
   const dialogTitle = computed(() => (isEdit.value ? '缂栬緫搴撲綅' : '鏂板搴撲綅'))
 
-  const filteredAreaOptions = computed(() => {
-    if (!form.warehouseId) {
-      return props.areaOptions
+  const filteredAreaOptions = computed(() =>
+    filterLocAreaOptionsByWarehouse(props.areaOptions || [], form.warehouseId)
+  )
+
+  function createInputFormItem(label, key, placeholder, extraProps = {}, extraConfig = {}) {
+    return {
+      label,
+      key,
+      type: 'input',
+      props: {
+        placeholder,
+        clearable: true,
+        ...extraProps
+      },
+      ...extraConfig
     }
-    return (props.areaOptions || []).filter((item) => {
-      if (item?.warehouseId === undefined || item?.warehouseId === null) {
-        return true
-      }
-      return Number(item.warehouseId) === Number(form.warehouseId)
-    })
-  })
+  }
+
+  function createNumberFormItem(label, key, placeholder, extraProps = {}, extraConfig = {}) {
+    return {
+      label,
+      key,
+      type: 'number',
+      props: {
+        min: 0,
+        controlsPosition: 'right',
+        placeholder,
+        ...extraProps
+      },
+      ...extraConfig
+    }
+  }
+
+  function createSelectFormItem(label, key, placeholder, options, extraProps = {}, extraConfig = {}) {
+    return {
+      label,
+      key,
+      type: 'select',
+      props: {
+        placeholder,
+        clearable: true,
+        options,
+        ...extraProps
+      },
+      ...extraConfig
+    }
+  }
 
   const rules = computed(() => ({
     warehouseId: [{ required: true, message: '璇烽�夋嫨浠撳簱', trigger: 'change' }],
@@ -80,237 +117,38 @@
   }))
 
   const formItems = computed(() => [
-    {
-      label: '浠撳簱',
-      key: 'warehouseId',
-      type: 'select',
-      props: {
-        placeholder: '璇烽�夋嫨浠撳簱',
-        clearable: true,
-        filterable: true,
-        options: props.warehouseOptions
-      }
-    },
-    {
-      label: '搴撳尯',
-      key: 'areaId',
-      type: 'select',
-      props: {
-        placeholder: '璇烽�夋嫨搴撳尯',
-        clearable: true,
-        filterable: true,
-        options: filteredAreaOptions.value
-      }
-    },
-    {
-      label: '搴撲綅鍙�',
-      key: 'code',
-      type: 'input',
-      props: {
-        placeholder: '璇疯緭鍏ュ簱浣嶅彿',
-        clearable: true
-      }
-    },
-    {
-      label: '搴撲綅绫诲瀷',
-      key: 'typeIds',
-      type: 'select',
-      props: {
-        placeholder: '璇烽�夋嫨搴撲綅绫诲瀷',
-        clearable: true,
-        multiple: true,
-        collapseTags: true,
-        filterable: true,
-        options: props.locTypeOptions
-      }
-    },
-    {
-      label: '浣跨敤鐘舵��',
-      key: 'useStatus',
-      type: 'select',
-      props: {
-        placeholder: '璇烽�夋嫨浣跨敤鐘舵��',
-        clearable: true,
-        filterable: true,
-        options: getLocUseStatusOptions()
-      }
-    },
-    {
-      label: '鐘舵��',
-      key: 'status',
-      type: 'select',
-      props: {
-        placeholder: '璇烽�夋嫨鐘舵��',
-        clearable: true,
-        options: getLocStatusOptions()
-      }
-    },
-    {
-      label: '鎺�',
-      key: 'row',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ユ帓'
-      }
-    },
-    {
-      label: '鍒�',
-      key: 'col',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ュ垪'
-      }
-    },
-    {
-      label: '灞�',
-      key: 'lev',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ュ眰'
-      }
-    },
-    {
-      label: '宸烽亾',
-      key: 'channel',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ュ贩閬�'
-      }
-    },
-    {
-      label: '瀹瑰櫒缂栫爜',
-      key: 'barcode',
-      type: 'input',
-      props: {
-        placeholder: '璇疯緭鍏ュ鍣ㄧ紪鐮�',
-        clearable: true
-      }
-    },
-    {
-      label: '瀛樻斁鍗曚綅',
-      key: 'unit',
-      type: 'input',
-      props: {
-        placeholder: '璇疯緭鍏ュ瓨鏀惧崟浣�',
-        clearable: true
-      }
-    },
-    {
-      label: '铏氭嫙搴撲綅',
-      key: 'flagLogic',
-      type: 'select',
-      props: {
-        placeholder: '璇烽�夋嫨铏氭嫙搴撲綅',
-        clearable: true,
-        options: getLocBinaryOptions()
-      }
-    },
-    {
-      label: '鏍囩绠$悊',
-      key: 'flagLabelMange',
-      type: 'select',
-      props: {
-        placeholder: '璇烽�夋嫨鏍囩绠$悊',
-        clearable: true,
-        options: getLocBinaryOptions()
-      }
-    },
-    {
-      label: '闀�',
-      key: 'length',
-      type: 'number',
-      props: {
-        min: 0,
-        step: 0.01,
-        precision: 2,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ラ暱'
-      }
-    },
-    {
-      label: '瀹�',
-      key: 'width',
-      type: 'number',
-      props: {
-        min: 0,
-        step: 0.01,
-        precision: 2,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ュ'
-      }
-    },
-    {
-      label: '楂�',
-      key: 'height',
-      type: 'number',
-      props: {
-        min: 0,
-        step: 0.01,
-        precision: 2,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ラ珮'
-      }
-    },
-    {
-      label: '鏈�澶ч浂浠舵暟',
-      key: 'maxParts',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ユ渶澶ч浂浠舵暟'
-      }
-    },
-    {
-      label: '鏈�澶у寘瑁呮暟',
-      key: 'maxPack',
-      type: 'number',
-      props: {
-        min: 0,
-        controlsPosition: 'right',
-        placeholder: '璇疯緭鍏ユ渶澶у寘瑁呮暟'
-      }
-    },
-    {
-      label: '鍔熻兘灞炴��',
-      key: 'fucAtrrs',
-      type: 'input',
-      span: 24,
-      props: {
-        placeholder: '璇疯緭鍏ュ姛鑳藉睘鎬�',
-        clearable: true
-      }
-    },
-    {
-      label: '灞炴��',
-      key: 'locAttrs',
-      type: 'input',
-      span: 24,
-      props: {
-        placeholder: '璇疯緭鍏ュ睘鎬�',
-        clearable: true
-      }
-    },
-    {
-      label: '澶囨敞',
-      key: 'memo',
-      type: 'input',
-      span: 24,
-      props: {
-        type: 'textarea',
-        rows: 3,
-        placeholder: '璇疯緭鍏ュ娉�',
-        clearable: true
-      }
-    }
+    createSelectFormItem('浠撳簱', 'warehouseId', '璇烽�夋嫨浠撳簱', props.warehouseOptions, { filterable: true }),
+    createSelectFormItem('搴撳尯', 'areaId', '璇烽�夋嫨搴撳尯', filteredAreaOptions.value, { filterable: true }),
+    createInputFormItem('搴撲綅鍙�', 'code', '璇疯緭鍏ュ簱浣嶅彿'),
+    createSelectFormItem('搴撲綅绫诲瀷', 'typeIds', '璇烽�夋嫨搴撲綅绫诲瀷', props.locTypeOptions, {
+      multiple: true,
+      collapseTags: true,
+      filterable: true
+    }),
+    createSelectFormItem('浣跨敤鐘舵��', 'useStatus', '璇烽�夋嫨浣跨敤鐘舵��', getLocUseStatusOptions(), { filterable: true }),
+    createSelectFormItem('鐘舵��', 'status', '璇烽�夋嫨鐘舵��', getLocStatusOptions()),
+    createNumberFormItem('鎺�', 'row', '璇疯緭鍏ユ帓'),
+    createNumberFormItem('鍒�', 'col', '璇疯緭鍏ュ垪'),
+    createNumberFormItem('灞�', 'lev', '璇疯緭鍏ュ眰'),
+    createNumberFormItem('宸烽亾', 'channel', '璇疯緭鍏ュ贩閬�'),
+    createInputFormItem('瀹瑰櫒缂栫爜', 'barcode', '璇疯緭鍏ュ鍣ㄧ紪鐮�'),
+    createInputFormItem('瀛樻斁鍗曚綅', 'unit', '璇疯緭鍏ュ瓨鏀惧崟浣�'),
+    createSelectFormItem('铏氭嫙搴撲綅', 'flagLogic', '璇烽�夋嫨铏氭嫙搴撲綅', getLocBinaryOptions()),
+    createSelectFormItem('鏍囩绠$悊', 'flagLabelMange', '璇烽�夋嫨鏍囩绠$悊', getLocBinaryOptions()),
+    createNumberFormItem('闀�', 'length', '璇疯緭鍏ラ暱', { step: 0.01, precision: 2 }),
+    createNumberFormItem('瀹�', 'width', '璇疯緭鍏ュ', { step: 0.01, precision: 2 }),
+    createNumberFormItem('楂�', 'height', '璇疯緭鍏ラ珮', { step: 0.01, precision: 2 }),
+    createNumberFormItem('鏈�澶ч浂浠舵暟', 'maxParts', '璇疯緭鍏ユ渶澶ч浂浠舵暟'),
+    createNumberFormItem('鏈�澶у寘瑁呮暟', 'maxPack', '璇疯緭鍏ユ渶澶у寘瑁呮暟'),
+    createInputFormItem('鍔熻兘灞炴��', 'fucAtrrs', '璇疯緭鍏ュ姛鑳藉睘鎬�', {}, { span: 24 }),
+    createInputFormItem('灞炴��', 'locAttrs', '璇疯緭鍏ュ睘鎬�', {}, { span: 24 }),
+    createInputFormItem(
+      '澶囨敞',
+      'memo',
+      '璇疯緭鍏ュ娉�',
+      { type: 'textarea', rows: 3 },
+      { span: 24 }
+    )
   ])
 
   const loadFormData = () => {
diff --git a/rsf-design/src/views/system/role/index.vue b/rsf-design/src/views/system/role/index.vue
index 2833f51..c703b2f 100644
--- a/rsf-design/src/views/system/role/index.vue
+++ b/rsf-design/src/views/system/role/index.vue
@@ -118,6 +118,14 @@
   const userStore = useUserStore()
   const reportTitle = ROLE_REPORT_TITLE
   const reportQueryParams = computed(() => buildRoleSearchParams(searchForm.value))
+  const roleActionHandlers = {
+    'scope-menu': (row) => openScopeDialog('menu', row),
+    'scope-pda': (row) => openScopeDialog('pda', row),
+    'scope-matnr': (row) => openScopeDialog('matnr', row),
+    'scope-warehouse': (row) => openScopeDialog('warehouse', row),
+    edit: (row) => showDialog('edit', row),
+    delete: (row) => handleDelete(row)
+  }
 
   function openScopeDialog(scopeType, row) {
     permissionScopeType.value = scopeType
@@ -126,28 +134,7 @@
   }
 
   function handleActionClick(item, row) {
-    switch (item.key) {
-      case 'scope-menu':
-        openScopeDialog('menu', row)
-        break
-      case 'scope-pda':
-        openScopeDialog('pda', row)
-        break
-      case 'scope-matnr':
-        openScopeDialog('matnr', row)
-        break
-      case 'scope-warehouse':
-        openScopeDialog('warehouse', row)
-        break
-      case 'edit':
-        showDialog('edit', row)
-        break
-      case 'delete':
-        handleDelete(row)
-        break
-      default:
-        break
-    }
+    roleActionHandlers[item.key]?.(row)
   }
 
   const {
@@ -262,12 +249,12 @@
     })
   )
 
-  const handleSearch = (params) => {
+  function handleSearch(params) {
     replaceSearchParams(buildRoleSearchParams(params))
     getData()
   }
 
-  const handleReset = () => {
+  function handleReset() {
     Object.assign(searchForm.value, createRoleSearchState())
     resetSearchParams()
   }
diff --git a/rsf-design/src/views/system/role/modules/role-edit-dialog.vue b/rsf-design/src/views/system/role/modules/role-edit-dialog.vue
index 713149b..fbb5d54 100644
--- a/rsf-design/src/views/system/role/modules/role-edit-dialog.vue
+++ b/rsf-design/src/views/system/role/modules/role-edit-dialog.vue
@@ -30,7 +30,7 @@
 
 <script setup>
   import ArtForm from '@/components/core/forms/art-form/index.vue'
-  import { buildRoleDialogModel, createRoleFormState } from '../rolePage.helpers'
+  import { buildRoleDialogModel, createRoleFormState, getRoleStatusOptions } from '../rolePage.helpers'
 
   const props = defineProps({
     visible: { required: false, default: false },
@@ -49,50 +49,40 @@
     name: [{ required: true, message: '璇疯緭鍏ヨ鑹插悕绉�', trigger: 'blur' }]
   }))
 
-  const formItems = computed(() => [
-    {
-      label: '瑙掕壊鍚嶇О',
-      key: 'name',
+  function createInputFormItem(label, key, placeholder, extraProps = {}, extraConfig = {}) {
+    return {
+      label,
+      key,
       type: 'input',
       props: {
-        placeholder: '璇疯緭鍏ヨ鑹插悕绉�',
-        clearable: true
-      }
-    },
-    {
-      label: '瑙掕壊缂栫爜',
-      key: 'code',
-      type: 'input',
-      props: {
-        placeholder: '璇疯緭鍏ヨ鑹茬紪鐮�',
-        clearable: true
-      }
-    },
-    {
-      label: '鐘舵��',
-      key: 'status',
+        placeholder,
+        clearable: true,
+        ...extraProps
+      },
+      ...extraConfig
+    }
+  }
+
+  function createSelectFormItem(label, key, placeholder, options, extraProps = {}, extraConfig = {}) {
+    return {
+      label,
+      key,
       type: 'select',
       props: {
-        placeholder: '璇烽�夋嫨鐘舵��',
+        placeholder,
         clearable: true,
-        options: [
-          { label: '姝e父', value: 1 },
-          { label: '绂佺敤', value: 0 }
-        ]
-      }
-    },
-    {
-      label: '澶囨敞',
-      key: 'memo',
-      type: 'input',
-      span: 24,
-      props: {
-        type: 'textarea',
-        rows: 3,
-        placeholder: '璇疯緭鍏ュ娉�',
-        clearable: true
-      }
+        options,
+        ...extraProps
+      },
+      ...extraConfig
     }
+  }
+
+  const formItems = computed(() => [
+    createInputFormItem('瑙掕壊鍚嶇О', 'name', '璇疯緭鍏ヨ鑹插悕绉�'),
+    createInputFormItem('瑙掕壊缂栫爜', 'code', '璇疯緭鍏ヨ鑹茬紪鐮�'),
+    createSelectFormItem('鐘舵��', 'status', '璇烽�夋嫨鐘舵��', getRoleStatusOptions()),
+    createInputFormItem('澶囨敞', 'memo', '璇疯緭鍏ュ娉�', { type: 'textarea', rows: 3 }, { span: 24 })
   ])
 
   const resetForm = () => {
diff --git a/rsf-design/src/views/system/role/modules/role-permission-dialog.vue b/rsf-design/src/views/system/role/modules/role-permission-dialog.vue
index c7c58ec..ccc6c63 100644
--- a/rsf-design/src/views/system/role/modules/role-permission-dialog.vue
+++ b/rsf-design/src/views/system/role/modules/role-permission-dialog.vue
@@ -96,21 +96,7 @@
     label: 'label',
     children: 'children'
   }
-  const scopeState = reactive(
-    Object.fromEntries(
-      scopeConfigs.map((config) => [
-        config.scopeType,
-        {
-          loading: false,
-          loaded: false,
-          treeData: [],
-          checkedKeys: [],
-          halfCheckedKeys: [],
-          condition: ''
-        }
-      ])
-    )
-  )
+  const scopeState = reactive(Object.fromEntries(scopeConfigs.map((config) => [config.scopeType, createScopeTabState()])))
 
   const visible = computed({
     get: () => props.visible,
@@ -119,18 +105,37 @@
 
   const roleLabel = computed(() => props.roleData?.name || props.roleData?.code || '鏈�夋嫨瑙掕壊')
 
+  function createScopeTabState() {
+    return {
+      loading: false,
+      loaded: false,
+      treeData: [],
+      checkedKeys: [],
+      halfCheckedKeys: [],
+      condition: ''
+    }
+  }
+
+  function resetScopeTabState(state) {
+    Object.assign(state, createScopeTabState())
+  }
+
+  function hasNodeKey(value) {
+    return value !== void 0 && value !== null && value !== ''
+  }
+
   const loadScopeData = async (scopeType, { reloadSelection = true } = {}) => {
     const config = getRoleScopeConfig(scopeType)
     const state = scopeState[scopeType]
     state.loading = true
     try {
-      const requests = [fetchGetRoleScopeTree(config.scopeType, { condition: state.condition || '' })]
-      if (reloadSelection) {
-        requests.unshift(fetchGetRoleScopeList(config.scopeType, props.roleData.id))
-      }
+      const selectionRequest = reloadSelection
+        ? fetchGetRoleScopeList(config.scopeType, props.roleData.id)
+        : Promise.resolve(state.checkedKeys)
+      const treeRequest = fetchGetRoleScopeTree(config.scopeType, { condition: state.condition || '' })
 
       const guardedResult = await guardRequestWithMessage(
-        reloadSelection ? Promise.all(requests) : Promise.resolve([state.checkedKeys, await requests[0]]),
+        Promise.all([selectionRequest, treeRequest]),
         null,
         {
           timeoutMessage: `${config.title}鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟`
@@ -237,12 +242,7 @@
   const handleClosed = () => {
     activeScopeType.value = props.scopeType || 'menu'
     Object.keys(scopeState).forEach((key) => {
-      scopeState[key].loading = false
-      scopeState[key].loaded = false
-      scopeState[key].treeData = []
-      scopeState[key].checkedKeys = []
-      scopeState[key].halfCheckedKeys = []
-      scopeState[key].condition = ''
+      resetScopeTabState(scopeState[key])
     })
   }
 
@@ -250,7 +250,7 @@
     const keys = []
     const traverse = (nodeList) => {
       nodeList.forEach((node) => {
-        if (node.id !== void 0 && node.id !== null && node.id !== '') {
+        if (hasNodeKey(node.id)) {
           keys.push(String(node.id))
         }
         if (node.children?.length) {
diff --git a/rsf-design/src/views/system/role/modules/role-search.vue b/rsf-design/src/views/system/role/modules/role-search.vue
index a8838ab..dd19870 100644
--- a/rsf-design/src/views/system/role/modules/role-search.vue
+++ b/rsf-design/src/views/system/role/modules/role-search.vue
@@ -10,7 +10,7 @@
 </template>
 
 <script setup>
-  import { createRoleSearchState } from '../rolePage.helpers'
+  import { createRoleSearchState, getRoleStatusOptions } from '../rolePage.helpers'
 
   const props = defineProps({
     modelValue: { required: true }
@@ -24,56 +24,37 @@
     set: (val) => emit('update:modelValue', val)
   })
 
-  const formItems = computed(() => [
-    {
-      label: '瑙掕壊鍚嶇О',
-      key: 'name',
+  function createInputSearchItem(label, key, placeholder) {
+    return {
+      label,
+      key,
       type: 'input',
       props: {
-        placeholder: '璇疯緭鍏ヨ鑹插悕绉�',
+        placeholder,
         clearable: true
-      }
-    },
-    {
-      label: '瑙掕壊缂栫爜',
-      key: 'code',
-      type: 'input',
-      props: {
-        placeholder: '璇疯緭鍏ヨ鑹茬紪鐮�',
-        clearable: true
-      }
-    },
-    {
-      label: '澶囨敞',
-      key: 'memo',
-      type: 'input',
-      props: {
-        placeholder: '璇疯緭鍏ュ娉�',
-        clearable: true
-      }
-    },
-    {
-      label: '鍏抽敭瀛�',
-      key: 'condition',
-      type: 'input',
-      props: {
-        placeholder: '杈撳叆鍏抽敭瀛楁悳绱�',
-        clearable: true
-      }
-    },
-    {
-      label: '鐘舵��',
-      key: 'status',
-      type: 'select',
-      props: {
-        placeholder: '璇烽�夋嫨鐘舵��',
-        clearable: true,
-        options: [
-          { label: '姝e父', value: 1 },
-          { label: '绂佺敤', value: 0 }
-        ]
       }
     }
+  }
+
+  function createSelectSearchItem(label, key, placeholder, options) {
+    return {
+      label,
+      key,
+      type: 'select',
+      props: {
+        placeholder,
+        clearable: true,
+        options
+      }
+    }
+  }
+
+  const formItems = computed(() => [
+    createInputSearchItem('瑙掕壊鍚嶇О', 'name', '璇疯緭鍏ヨ鑹插悕绉�'),
+    createInputSearchItem('瑙掕壊缂栫爜', 'code', '璇疯緭鍏ヨ鑹茬紪鐮�'),
+    createInputSearchItem('澶囨敞', 'memo', '璇疯緭鍏ュ娉�'),
+    createInputSearchItem('鍏抽敭瀛�', 'condition', '杈撳叆鍏抽敭瀛楁悳绱�'),
+    createSelectSearchItem('鐘舵��', 'status', '璇烽�夋嫨鐘舵��', getRoleStatusOptions())
   ])
 
   function handleReset() {
diff --git a/rsf-design/src/views/system/role/rolePage.helpers.js b/rsf-design/src/views/system/role/rolePage.helpers.js
index 0b2696f..aa4c451 100644
--- a/rsf-design/src/views/system/role/rolePage.helpers.js
+++ b/rsf-design/src/views/system/role/rolePage.helpers.js
@@ -1,3 +1,13 @@
+const ROLE_STATUS_META = {
+  1: { type: 'success', text: '姝e父', bool: true },
+  0: { type: 'danger', text: '绂佺敤', bool: false }
+}
+
+const ROLE_STATUS_OPTIONS = [
+  { label: '姝e父', value: 1 },
+  { label: '绂佺敤', value: 0 }
+]
+
 export function createRoleSearchState() {
   return {
     name: '',
@@ -6,6 +16,14 @@
     status: void 0,
     condition: ''
   }
+}
+
+function hasValue(value) {
+  return value !== '' && value !== void 0 && value !== null
+}
+
+function normalizeText(value) {
+  return String(value ?? '').trim()
 }
 
 export function createRoleFormState() {
@@ -18,20 +36,20 @@
   }
 }
 
+export function getRoleStatusOptions() {
+  return ROLE_STATUS_OPTIONS.map((option) => ({ ...option }))
+}
+
 export function buildRoleSearchParams(params = {}) {
   const searchParams = {
-    name: params.name,
-    code: params.code,
-    memo: params.memo,
+    name: normalizeText(params.name),
+    code: normalizeText(params.code),
+    memo: normalizeText(params.memo),
     status: params.status,
-    condition: params.condition
+    condition: normalizeText(params.condition)
   }
 
-  return Object.fromEntries(
-    Object.entries(searchParams).filter(
-      ([, value]) => value !== '' && value !== void 0 && value !== null
-    )
-  )
+  return Object.fromEntries(Object.entries(searchParams).filter(([, value]) => hasValue(value)))
 }
 
 export function buildRolePageQueryParams(params = {}) {
@@ -137,22 +155,12 @@
 export function buildRoleDialogModel(record = {}) {
   return {
     ...createRoleFormState(),
-    id: normalizeRoleId(record.id),
-    name: record.name || '',
-    code: record.code || '',
-    memo: record.memo || '',
-    status: record.status !== void 0 && record.status !== null ? record.status : 1
+    ...buildRoleFormData(record)
   }
 }
 
 export function buildRoleSavePayload(form = {}) {
-  return {
-    id: normalizeRoleId(form.id),
-    name: form.name || '',
-    code: form.code || '',
-    memo: form.memo || '',
-    status: form.status !== void 0 && form.status !== null ? form.status : 1
-  }
+  return buildRoleFormData(form)
 }
 
 export function normalizeRoleListRow(record = {}) {
@@ -162,17 +170,17 @@
     statusBool: record.statusBool !== void 0 ? Boolean(record.statusBool) : statusMeta.bool,
     statusText: statusMeta.text,
     statusType: statusMeta.type,
-    createTimeText: record.createTime$ || record.createTime || '',
-    updateTimeText: record.updateTime$ || record.updateTime || ''
+    createTimeText: normalizeText(record.createTime$ || record.createTime),
+    updateTimeText: normalizeText(record.updateTime$ || record.updateTime)
   }
 }
 
 export function getRoleStatusMeta(status) {
-  if (status === true || status === 1) {
-    return { type: 'success', text: '姝e父', bool: true }
+  if (status === true || status === 1 || status === '1') {
+    return ROLE_STATUS_META[1]
   }
-  if (status === false || status === 0) {
-    return { type: 'danger', text: '绂佺敤', bool: false }
+  if (status === false || status === 0 || status === '0') {
+    return ROLE_STATUS_META[0]
   }
   return { type: 'info', text: '鏈煡', bool: false }
 }
@@ -314,7 +322,7 @@
 }
 
 function normalizeRoleId(value) {
-  if (value === '' || value === null || value === void 0) {
+  if (!hasValue(value)) {
     return void 0
   }
   const numeric = Number(value)
@@ -323,3 +331,13 @@
   }
   return numeric
 }
+
+function buildRoleFormData(source = {}) {
+  return {
+    id: normalizeRoleId(source.id),
+    name: normalizeText(source.name),
+    code: normalizeText(source.code),
+    memo: normalizeText(source.memo),
+    status: hasValue(source.status) ? source.status : 1
+  }
+}
diff --git a/rsf-design/src/views/system/role/roleTable.columns.js b/rsf-design/src/views/system/role/roleTable.columns.js
index 8fe8642..d9756f1 100644
--- a/rsf-design/src/views/system/role/roleTable.columns.js
+++ b/rsf-design/src/views/system/role/roleTable.columns.js
@@ -43,50 +43,43 @@
   }
 ]
 
+function createTextColumn(prop, label, minWidth, extra = {}) {
+  return {
+    prop,
+    label,
+    minWidth,
+    showOverflowTooltip: true,
+    ...extra
+  }
+}
+
+function createTagColumn(prop, label, width, resolveMeta) {
+  return {
+    prop,
+    label,
+    width,
+    formatter: (row) => {
+      const statusMeta = resolveMeta(row)
+      return h(ElTag, { type: statusMeta.type, effect: 'light' }, () => statusMeta.text)
+    }
+  }
+}
+
 export function createRoleTableColumns(handleActionClick) {
   return [
     { type: 'selection', width: 52, fixed: 'left' },
-    {
-      prop: 'name',
-      label: '瑙掕壊鍚嶇О',
-      minWidth: 140,
-      showOverflowTooltip: true
-    },
-    {
-      prop: 'code',
-      label: '瑙掕壊缂栫爜',
-      minWidth: 140,
-      showOverflowTooltip: true
-    },
-    {
-      prop: 'memo',
-      label: '澶囨敞',
-      minWidth: 180,
-      showOverflowTooltip: true
-    },
-    {
-      prop: 'status',
-      label: '鐘舵��',
-      width: 120,
-      formatter: (row) => {
-        const statusMeta = getRoleStatusMeta(row.statusBool ?? row.status)
-        return h(ElTag, { type: statusMeta.type, effect: 'light' }, () => statusMeta.text)
-      }
-    },
-    {
-      prop: 'updateTimeText',
-      label: '鏇存柊鏃堕棿',
-      minWidth: 180,
+    createTextColumn('name', '瑙掕壊鍚嶇О', 140),
+    createTextColumn('code', '瑙掕壊缂栫爜', 140),
+    createTextColumn('memo', '澶囨敞', 180),
+    createTagColumn('status', '鐘舵��', 120, (row) => getRoleStatusMeta(row.statusBool ?? row.status)),
+    createTextColumn('updateTimeText', '鏇存柊鏃堕棿', 180, {
       sortable: true,
       formatter: (row) => row.updateTimeText || '-'
-    },
-    {
-      prop: 'createTimeText',
-      label: '鍒涘缓鏃堕棿',
-      minWidth: 180,
+    }),
+    createTextColumn('createTimeText', '鍒涘缓鏃堕棿', 180, {
       sortable: true,
       formatter: (row) => row.createTimeText || '-'
-    },
+    }),
     {
       prop: 'operation',
       label: '鎿嶄綔',
@@ -94,12 +87,10 @@
       align: 'center',
       fixed: 'right',
       formatter: (row) =>
-        h('div', [
-          h(ArtButtonMore, {
-            list: ROLE_MORE_ACTIONS,
-            onClick: (item) => handleActionClick(item, row)
-          })
-        ])
+        h(ArtButtonMore, {
+          list: ROLE_MORE_ACTIONS,
+          onClick: (item) => handleActionClick(item, row)
+        })
     }
   ]
 }

--
Gitblit v1.9.1