🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

一個前端工程師的年度作品:從零開發媲美商業級應用的後台管理系統!

@2x封面.png

過去一年,我花了無數個夜晚,在一次次打磨與推翻中,完成了自己最滿意的作品 —— Art Design Pro。

這不是一個普通的後台模板。
它是一場關於「設計美學」與「工程化開發」的融合實驗——
希望讓後台系統不再冰冷枯燥,而是像一件作品:優雅、流暢、有溫度。

為什麼要做這個專案?

在日常開發中,我幾乎體驗過所有主流後台模板。
它們的功能確實完整,但更多時候給人的感覺是——「工具」而非「產品」。

我希望做一個後台系統,
讓人打開的第一眼就覺得舒服,
用起來像是在和它對話。

許多後台系統普遍存在這些問題 👇

視覺疲勞:灰白配色、生硬佈局,難以長時間使用;
體驗割裂:邏輯不統一、入口分散,操作效率低;
重用困難:組件風格不一致,二次開發成本高。

於是我決定從零開始,花一年的時間去打造一個真正屬於自己的系統——
👉 一款「既好看、又好用,還能直接用於商業專案」的後台管理模板。

專案簡介:Art Design Pro

Art Design Pro 是一款基於 Vue 3 + TypeScript + Vite + Element Plus 打造的現代化後台管理系統模板。

它的核心理念是:

讓後台系統兼具設計美學與開發效率。

這個專案有什麼特別的呢?

介面設計:現代化 UI 設計,流暢互動,以用戶體驗與視覺設計為核心
極速上手:簡潔架構 + 完整文檔,後端開發者也能輕鬆使用
豐富組件:內置數據展示、表單等多種高品質組件,滿足不同業務場景的需求
絲滑互動:按鈕點擊、主題切換、頁面過渡、圖表動畫,體驗媲美商業產品
高效開發:內置 useTable、ArtForm 等實用 API,顯著提升開發效率
精簡腳本:內置一鍵清理腳本,可快速清理演示數據,立即得到可開發的基礎專案

技術棧

開發框架:Vue3、TypeScript、Vite、Element-Plus
程式碼規範:Eslint、Prettier、Stylelint、Husky、Lint-staged、cz-git

預覽

主頁儀表盤
主頁儀表盤

電子商務儀表盤
電子商務儀表盤

卡片
卡片

卡片

橫幅
橫幅

圖表
圖表

系統圖標庫
系統圖標庫

富文本編輯器
富文本編輯器

禮花效果
禮花效果

全局搜索
全局搜索

系統設定
系統設定

表格
表格

黑暗模式

黑暗模式

黑暗模式

黑暗模式

黑暗模式
黑暗模式

快速訪問

GitHub: github.com/Daymychen/a…
演示地址: www.artd.pro
官方文檔: www.artd.pro/docs

高效開發

在後台管理系統開發中,表格頁面佔據了 80% 的工作量。每次都要寫分頁、搜尋、刷新、列配置...這些重複的程式碼讓人頭疼。今天分享一套我們團隊正在使用的表格開發方案,讓你的開發效率提升 10 倍!

痛點分析

在開發後台管理系統時,你是否遇到過這些問題:

  • 每個表格頁面都要寫一遍分頁邏輯
  • 搜尋、重置、刷新等功能重複實現
  • 表格列配置、顯示隱藏、拖曳排序需要手動處理
  • 數據請求、loading 狀態、錯誤處理程式碼冗餘
  • 快取策略難以統一管理
  • 行動端適配需要額外處理

如果你的答案是「是」,那這篇文章就是為你準備的。

解決方案概覽

我們的方案包含以下核心部分:

  • useTable - 強大的表格數據管理 Hook
  • ArtTable - 增強的表格組件
  • ArtTableHeader - 表格工具欄組件
  • ArtSearchBar - 智能搜尋欄組件
  • ArtForm - 通用表單組件

一、useTable:表格數據管理的核心

1.1 基礎用法

先看一個最簡單的例子,只需要幾行程式碼就能實現一個完整的表格:

const { 
  data, 
  columns, 
  columnChecks, 
  loading, 
  pagination, 
  refreshData, 
  handleSizeChange, 
  handleCurrentChange 
} = useTable({
  core: {
    apiFn: fetchGetUserList,
    apiParams: {
      current: 1,
      size: 20
    },
    columnsFactory: () => [
      { prop: 'id', label: 'ID' },
      { prop: 'userName', label: '用戶名' },
      { prop: 'userPhone', label: '手機號' }
    ]
  }
})

就這麼簡單!你已經擁有了:

  • ✅ 自動的數據請求
  • ✅ 分頁功能
  • ✅ Loading 狀態
  • ✅ 列配置管理

1.2 核心特性

🚀 智能快取機制

useTable({
  core: {
    /* ... */
  },
  performance: {
    enableCache: true, // 啟用快取
    cacheTime: 5 * 60 * 1000, // 快取 5 分鐘
    debounceTime: 300, // 防抖 300ms
    maxCacheSize: 50 // 最多快取 50 條
  }
})

快取帶來的好處:

  • 相同參數的請求直接從快取讀取,秒開
  • 減少伺服器壓力
  • 提升用戶體驗

🎯 多種刷新策略

不同的業務場景需要不同的刷新策略:

// 新增數據後:回到首頁,清空分頁快取
await refreshCreate()

// 編輯數據後:保持當前頁,只清空當前搜尋快取
await refreshUpdate()

// 刪除數據後:智能處理頁碼,避免空頁面
await refreshRemove()

// 手動刷新:清空所有快取
await refreshData()

// 定時刷新:輕量刷新,保持分頁狀態
await refreshSoft()

這些方法讓你的程式碼更語義化,不用再糾結什麼時候該清快取。

🔄 數據轉換器

有時候介面返回的數據需要處理一下才能用:

useTable({
  core: {
    /* ... */
  },
  transform: {
    dataTransformer: (records) => {
      return records.map((item, index) => ({
        ...item,
        // 替換頭像
        avatar: localAvatars[index % localAvatars.length].avatar,
        // 格式化日期
        createTime: dayjs(item.createTime).format('YYYY-MM-DD')
      }))
    }
  }
})

📊 生命週期鉤子

useTable({
  core: {
    /* ... */
  },
  hooks: {
    onSuccess: (data, response) => {
      console.log('數據加載成功', data)
    },
    onError: (error) => {
      ElMessage.error('加載失敗:' + error.message)
    },
    onCacheHit: (data) => {
      console.log('從快取讀取', data)
    }
  }
})

1.3 搜尋功能

搜尋是表格的核心功能,useTable 提供了完善的搜尋支持:

// 定義搜尋參數
const searchParams = reactive({
  userName: '',
  userPhone: '',
  status: '1'
})

const { getData, resetSearchParams } = useTable({
  core: {
    apiFn: fetchGetUserList,
    apiParams: searchParams
  }
})

// 搜尋
const handleSearch = (params) => {
  Object.assign(searchParams, params)
  getData() // 自動回到首頁
}

// 重置
const handleReset = () => {
  resetSearchParams() // 清空搜尋條件並重新加載
}

二、ArtTable:增強的表格組件

2.1 核心特性

ArtTable 基於 Element Plus 的 ElTable 封裝,完全兼容原有 API,同時提供了更多增強功能:

<ArtTable
  :loading="loading"
  :data="data"
  :columns="columns"
  :pagination="pagination"
  @selection-change="handleSelectionChange"
  @pagination:size-change="handleSizeChange"
  @pagination:current-change="handleCurrentChange"
/>

✨ 自動高度計算

不用再手動計算表格高度了!ArtTable 會自動計算剩餘空間:

<div class="art-full-height">
  <UserSearch />
  <ElCard class="art-table-card">
    <ArtTableHeader />
    <ArtTable /> <!-- 自動佔滿剩餘高度 -->
  </ElCard>
</div>

🎨 列配置靈活

支持多種列類型和自定義渲染:

columnsFactory: () => [
  { type: 'selection' }, // 勾選列
  { type: 'index', width: 60, label: '序號' }, // 序號列
  { type: 'globalIndex' }, // 全球序號(跨頁)
  // 自定義渲染
  {
    prop: 'avatar',
    label: '用戶',
    formatter: (row) => {
      return h('div', { class: 'user-info' }, [
        h(ElImage, { src: row.avatar }),
        h('span', row.userName)
      ])
    }
  },
  // 使用插槽
  {
    prop: 'status',
    label: '狀態',
    useSlot: true // 在模板中使用 #status 插槽
  },
  // 操作列
  {
    prop: 'operation',
    label: '操作',
    fixed: 'right',
    formatter: (row) =>
      h('div', [
        h(ArtButtonTable, {
          type: 'edit',
          onClick: () => handleEdit(row)
        }),
        h(ArtButtonTable, {
          type: 'delete',
          onClick: () => handleDelete(row)
        })
      ])
  }
]

📱 響應式分頁

自動適配行動端、平板、桌面端:

// 行動端:prev, pager, next, sizes, jumper, total
// 平板:prev, pager, next, jumper, total
// 桌面端:total, prev, pager, next, sizes, jumper

三、ArtTableHeader:強大的工具欄

3.1 開箱即用的功能

<ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="refreshData">
  <template #left>
    <ElButton @click="handleAdd">新增用戶</ElButton>
  </template>
</ArtTableHeader>

一行程式碼,你就擁有了:

  • 🔍 搜尋欄切換
  • 🔄 刷新按鈕(帶加載動畫)
  • 📏 表格尺寸切換(大、中、小)
  • 🖥️ 全螢幕模式
  • 📋 列顯示/隱藏配置
  • 🎨 斑馬紋、邊框、表頭背景切換

3.2 列配置功能

用戶可以:

  • ✅ 勾選顯示/隱藏列
  • ✅ 拖曳調整列順序
  • ✅ 固定列不可拖動

這些配置會自動同步到表格顯示。

3.3 自定義佈局

<ArtTableHeader layout="refresh,size,fullscreen,columns" :show-zebra="false" :show-border="false" />

通過 layout 屬性控制顯示哪些功能按鈕。

四、ArtSearchBar:智能搜尋欄

4.1 配置化搜尋表單

不用再手寫一堆 ElFormItem 了,用配置就能搞定:

<template>
  <ArtSearchBar
    ref="searchBarRef"
    v-model="formData"
    :items="formItems"
    :rules="rules"
    @reset="handleReset"
    @search="handleSearch"
  />
</template>

<script setup lang="ts">
const formData = ref({
  userName: undefined,
  userPhone: undefined,
  status: '1'
})

const formItems = computed(() => [
  {
    label: '用戶名',
    key: 'userName',
    type: 'input',
    placeholder: '請輸入用戶名',
    clearable: true
  },
  {
    label: '手機號',
    key: 'userPhone',
    type: 'input',
    props: { placeholder: '請輸入手機號', maxlength: '11' }
  },
  {
    label: '狀態',
    key: 'status',
    type: 'select',
    props: {
      placeholder: '請選擇狀態',
      options: [
        { label: '在線', value: '1' },
        { label: '離線', value: '2' }
      ]
    }
  },
  {
    label: '性別',
    key: 'userGender',
    type: 'radiogroup',
    props: {
      options: [
        { label: '男', value: '1' },
        { label: '女', value: '2' }
      ]
    }
  }
])

const handleSearch = async () => {
  await searchBarRef.value.validate()
  emit('search', formData.value)
}

const handleReset = () => {
  emit('reset')
}
</script>

4.2 核心特性

🎯 支持多種表單組件

開箱即用的組件類型:

  • input - 輸入框
  • select - 下拉選擇
  • date / datetime / daterange - 日期選擇
  • radiogroup / checkboxgroup - 單選/多選
  • cascader - 级联选择
  • treeselect - 樹選擇
  • 自定義組件 - 支持任意 Vue 組件

📦 自動展開/收起

當搜尋項過多時,自動顯示展開/收起按鈕:

<ArtSearchBar :items="formItems" :show-expand="true" :default-expanded="false" :span="6" />
  • 默認只顯示一行
  • 超出部分自動隱藏
  • 點擊「展開」查看全部搜尋項

🔄 動態選項加載

支持異步加載選項數據:

const statusOptions = ref([])

onMounted(async () => {
  // 模擬介面請求
  statusOptions.value = await fetchStatusOptions()
})

const formItems = computed(() => [
  {
    label: '狀態',
    key: 'status',
    type: 'select',
    props: {
      options: statusOptions.value // 動態選項
    }
  }
])

🎨 響應式佈局

自動適配不同螢幕尺寸:

// 通過 span 控制每行顯示的表單項數量
// span=6: 一行顯示 4 個(24/6=4)
// span=8: 一行顯示 3 個(24/8=3)
// span=12: 一行顯示 2 個(24/12=2)

行動端自動調整為單列佈局。

4.3 表單驗證

支持完整的表單驗證:

const rules = {
  userName: [{ required: true, message: '請輸入用戶名', trigger: 'blur' }],
  userPhone: [
    { required: true, message: '請輸入手機號', trigger: 'blur' },
    { pattern: /^1[3-9]\d{9}$/, message: '手機號格式不正確', trigger: 'blur' }
  ]
}

const handleSearch = async () => {
  // 驗證通過才執行搜尋
  await searchBarRef.value.validate()
  emit('search', formData.value)
}

五、ArtForm:通用表單組件

5.1 配置化表單

ArtForm 和 ArtSearchBar 使用相同的配置方式,但更適合彈窗、詳情頁等場景:

<template>
  <ArtForm
    ref="formRef"
    v-model="formData"
    :items="formItems"
    :rules="formRules"
    :label-width="100"
    :span="12"
    @reset="handleReset"
    @submit="handleSubmit"
  />
</template>

<script setup lang="ts">
const formData = ref({
  userName: '',
  userPhone: '',
  userEmail: '',
  userGender: '1',
  status: true
})

const formItems = [
  {
    label: '用戶名',
    key: 'userName',
    type: 'input',
    placeholder: '請輸入用戶名'
  },
  {
    label: '手機號',
    key: 'userPhone',
    type: 'input',
    props: { maxlength: 11 }
  },
  {
    label: '郵箱',
    key: 'userEmail',
    type: 'input',
    placeholder: '請輸入郵箱'
  },
  {
    label: '性別',
    key: 'userGender',
    type: 'radiogroup',
    props: {
      options: [
        { label: '男', value: '1' },
        { label: '女', value: '2' }
      ]
    }
  },
  {
    label: '是否啟用',
    key: 'status',
    type: 'switch'
  },
  {
    label: '備註',
    key: 'remark',
    type: 'input',
    span: 24, // 占滿整行
    props: {
      type: 'textarea',
      rows: 4
    }
  }
]

const formRules = {
  userName: [{ required: true, message: '請輸入用戶名', trigger: 'blur' }],
  userEmail: [{ type: 'email', message: '郵箱格式不正確', trigger: 'blur' }]
}

const handleSubmit = async () => {
  await formRef.value.validate()
  // 提交表單
  console.log('表單數據:', formData.value)
}
</script>

5.2 高級特性

🎨 自定義組件渲染

支持使用 h 函數渲染任意組件:

import ArtIconSelector from '@/components/core/base/art-icon-selector/index.vue'

const formItems = [
  {
    label: '圖標選擇',
    key: 'icon',
    type: () =>
      h(ArtIconSelector, {
        iconType: IconTypeEnum.UNICODE,
        width: '100%'
      })
  },
  {
    label: '文件上傳',
    key: 'files',
    type: () =>
      h(
        ElUpload,
        {
          action: '#',
          multiple: true,
          limit: 5,
          onChange: (file, fileList) => {
            formData.value.files = fileList
          }
        },
        {
          default: () => h(ElButton, { type: 'primary' }, () => '點擊上傳')
        }
      )
  }
]

🔌 插槽支持

支持為表單項添加插槽:

<ArtForm v-model="formData" :items="formItems">
  <template #customField>
    <div class="custom-content">
      <!-- 自定義內容 -->
    </div>
  </template>
</ArtForm>

或者在配置中使用插槽:

const formItems = [
  {
    label: '網站',
    key: 'website',
    type: 'input',
    slots: {
      prepend: () => h('span', 'https://'),
      append: () => h('span', '.com')
    }
  }
]

🎯 條件顯示

根據條件動態顯示/隱藏表單項:

const formItems = computed(() => [
  {
    label: '用戶類型',
    key: 'userType',
    type: 'select',
    props: {
      options: [
        { label: '個人', value: 'personal' },
        { label: '企業', value: 'enterprise' }
      ]
    }
  },
  {
    label: '企業名稱',
    key: 'companyName',
    type: 'input',
    // 只有選擇企業類型時才顯示
    hidden: formData.value.userType !== 'enterprise'
  }
])

📏 靈活佈局

通過 span 控制表單項寬度:

const formItems = [
  {
    label: '用戶名',
    key: 'userName',
    type: 'input',
    span: 12 // 占半行
  },
  {
    label: '手機號',
    key: 'userPhone',
    type: 'input',
    span: 12 // 占半行
  },
  {
    label: '地址',
    key: 'address',
    type: 'input',
    span: 24 // 占整行
  }
]

5.3 與 ArtSearchBar 的區別

特性 ArtSearchBar ArtForm
使用場景 表格搜尋 表單提交、彈窗
展開/收起 ✅ 支持 ❌ 不支持
按鈕文案 搜尋/重置 提交/重置
樣式 卡片樣式 無背景
默認佈局 橫向排列 橫向排列

六、完整示例

讓我們看一個完整的用戶管理頁面:

<template>
  <div class="user-page art-full-height">
    <!-- 搜尋欄 -->
    <ArtSearchBar
      v-model="searchForm"
      :items="searchItems"
      @search="handleSearch"
      @reset="resetSearchParams"
    />

    <ElCard class="art-table-card" shadow="never">
      <!-- 工具欄 -->
      <ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="refreshData">
        <template #left>
          <ElButton @click="handleAdd">新增用戶</ElButton>
        </template>
      </ArtTableHeader>

      <!-- 表格 -->
      <ArtTable
        :loading="loading"
        :data="data"
        :columns="columns"
        :pagination="pagination"
        @selection-change="handleSelectionChange"
        @pagination:size-change="handleSizeChange"
        @pagination:current-change="handleCurrentChange"
      />
    </ElCard>

    <!-- 彈窗 -->
    <UserDialog
      v-model:visible="dialogVisible"
      :type="dialogType"
      :user-data="currentUserData"
      @submit="handleDialogSubmit"
    />
  </div>
</template>

<script setup lang="ts">
import { useTable } from '@/composables/useTable'

原文出處:https://juejin.cn/post/7560845871291269159


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝23   💬9   ❤️6
638
🥈
我愛JS
📝4   💬15   ❤️7
281
🥉
御魂
💬1  
3
#4
2
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付