zhou zhou
8 小时以前 a49845f424ae5b1e43e391837a55c43ce07ea62d
#前端
13个文件已修改
1560 ■■■■■ 已修改文件
rsf-design/src/api/loc.js 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/api/system-manage.js 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/basic-info/bas-station-area/index.vue 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/basic-info/loc/index.vue 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/basic-info/loc/locPage.helpers.js 225 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/basic-info/loc/locTable.columns.js 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/basic-info/loc/modules/loc-dialog.vue 320 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/system/role/index.vue 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/system/role/modules/role-edit-dialog.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/system/role/modules/role-permission-dialog.vue 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/system/role/modules/role-search.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/system/role/rolePage.helpers.js 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-design/src/views/system/role/roleTable.columns.js 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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) || ''
  }
}
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)
}
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 () => {
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>
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 {
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: '操作',
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 = () => {
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()
  }
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: '正常', 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 = () => {
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) {
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: '正常', 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() {
rsf-design/src/views/system/role/rolePage.helpers.js
@@ -1,3 +1,13 @@
const ROLE_STATUS_META = {
  1: { type: 'success', text: '正常', bool: true },
  0: { type: 'danger', text: '禁用', bool: false }
}
const ROLE_STATUS_OPTIONS = [
  { label: '正常', 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: '正常', 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
  }
}
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)
        })
    }
  ]
}