AvueAvue
首页
  • 开发指南
  • Skill开发
  • 在线测试工具
  • Form组件
  • Crud组件
  • Default组件
  • Data组件
  • Component组件
产品
工作台
授权
联系
2.x文档
个人支付接口
首页
  • 开发指南
  • Skill开发
  • 在线测试工具
  • Form组件
  • Crud组件
  • Default组件
  • Data组件
  • Component组件
产品
工作台
授权
联系
2.x文档
个人支付接口
  • CRUD API
  • Object对象用法
  • 表格虚拟化
  • 分页
  • 搜索
  • 表头配置
  • 表格行配置项
  • 表格列配置项
  • 数据字典
  • 操作栏配置
  • 增删改查方法
  • 按钮文案和图标
  • 按钮自定义
  • 弹窗表单配置
  • 深层结构数据
  • 卡片模式
  • 统计合计
  • 导入导出
  • 表格树
  • 父子表
  • 行编辑
  • 权限控制
  • 动态行列合并
  • 空状态
  • 等待加载
  • 拖拽排序
  • 其它类型
  • 表格高级用法
  • 大表哥(宇宙最强表格)
  • CRUD模块封装
  • CRUD极简增删改查封装

数据字典

字典把数据中的值转换为可读标签,并为新增、编辑中的选择器提供选项。先确认字段和值的类型,再选择 dicData 或 dicUrl。

请求配置

网络字典需要在安装 Avue 时传入项目的 Axios 实例。本页请求本站固定的 JSON 文件,不依赖外部业务接口,也不会修改全局 Axios。

import axios from 'axios';
app.use(Avue, { axios });

更多配置参考 Form 组件数据字典。

本地字典与网络字典

效果预览可直接操作下方示例

dicData 直接传入数组;dicUrl 从接口加载数组;返回字段不是 label / value 时,通过 props 映射。点击「切换首行状态」,查看保存的数字值和表格标签同步变化。

正在加载示例…
<template>
  <div class="dic-example">
    <el-button @click="toggleStatus">切换首行状态</el-button>
    <avue-crud :data="data" :option="option" @dic-error="handleError" />
    <p class="dic-result" aria-live="polite">
      首行原始值:status = {{ data[0].status }}(数字),province = {{ data[0].province }}(字符串)
    </p>
    <el-alert v-if="error" :title="error" type="error" :closable="false" />
  </div>
</template>

<script setup>
import { ref } from 'vue';

const error = ref('');
const data = ref([
  { id: 1, name: '张三', status: 0, province: '110000' },
  { id: 2, name: '李四', status: 1, province: '130000' }
]);
const option = ref({
  rowKey: 'id',
  border: true,
  addBtn: false,
  menu: false,
  refreshBtn: false,
  columnBtn: false,
  column: [
    { label: '姓名', prop: 'name' },
    {
      label: '本地状态字典',
      prop: 'status',
      type: 'select',
      dicData: [
        { label: '待确认', value: 0 },
        { label: '已确认', value: 1 }
      ]
    },
    {
      label: '网络省份字典',
      prop: 'province',
      type: 'select',
      props: { label: 'name', value: 'code' },
      dicUrl: '/examples/crud-dic/provinces.json'
    }
  ]
});

function toggleStatus() {
  data.value[0].status = data.value[0].status === 0 ? 1 : 0;
}
function handleError() {
  error.value = '省份字典加载失败,请刷新页面后重试。';
}
</script>

<style scoped>
.dic-example > .el-button { margin-bottom: 16px; }
.dic-result {
  margin: 16px 0 0;
  padding: 12px 16px;
  border-radius: 8px;
  background: var(--el-fill-color-light);
  line-height: 1.7;
  overflow-wrap: anywhere;
}
</style>

示例的 status 和字典中的 value 都使用数字,省份和字典中的 code 都使用字符串。若表格只显示原始值,先检查字段映射和两侧类型是否一致;不要把合法的数字 0 当作空值。

按当前行加载字典

3.9.5+

普通字典列的 dicUrl、dicQuery、dicHeaders 包含模板变量时,会按当前行解析参数并保存各行的字典。适合租户、部门等上下文不同,但字段编码相同的表格。

效果预览可直接操作下方示例

两行的状态都为 0,但所属租户不同,因此显示不同标签。先切换首行状态,再切换首行租户,观察表格和下方的解析记录。dicUrl 选择本站 JSON 文件,dicQuery 传入当前字段值。

正在加载示例…
<template>
  <div class="row-dic-example">
    <div class="row-dic-actions">
      <el-button @click="toggleStatus">切换首行状态</el-button>
      <el-button @click="toggleTenant">切换首行租户</el-button>
      <el-button @click="reset">恢复示例</el-button>
    </div>
    <avue-crud :data="data" :option="option" @dic-error="handleError" />
    <el-alert v-if="error" :title="error" type="error" :closable="false" />
    <div class="row-dic-result" aria-live="polite">
      <strong>当前保存的数据</strong>
      <pre>{{ dataText }}</pre>
      <strong>最近完成的字典解析</strong>
      <p v-if="!records.length">正在加载本地演示字典…</p>
      <ul v-else>
        <li v-for="record in records" :key="record.id">{{ record.text }}</li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import { computed, onBeforeUnmount, ref } from 'vue';

const initialRows = () => [
  { id: 101, name: '北区订单', tenantId: 'north', status: 0 },
  { id: 102, name: '南区订单', tenantId: 'south', status: 0 }
];
const data = ref(initialRows());
const records = ref([]);
const error = ref('');
let recordId = 0;
let active = true;
onBeforeUnmount(() => { active = false; });

const dataText = computed(() => JSON.stringify(
  data.value.map(({ id, tenantId, status }) => ({ id, tenantId, status })),
  null, 2
));
const option = ref({
  rowKey: 'id',
  border: true,
  addBtn: false,
  menu: false,
  refreshBtn: false,
  columnBtn: false,
  column: [
    { label: '记录', prop: 'name', minWidth: 120 },
    { label: '租户编码', prop: 'tenantId', width: 110 },
    {
      label: '当前行的状态字典',
      prop: 'status',
      type: 'select',
      minWidth: 160,
      // 具名模板取当前行 tenantId,key 取当前列 status。
      dicUrl: '/examples/crud-dic/statuses/{{tenantId}}.json',
      dicQuery: { value: '{{key}}', tenant: '{{tenantId}}' },
      dicFormatter(response, row) {
        if (active) {
          error.value = '';
          records.value = [
            {
              id: ++recordId,
              text: '行 ' + row.id + ':tenant = ' + row.tenantId +
                ',value = ' + row.status + ',返回 ' + response.length + ' 个选项'
            },
            ...records.value
          ].slice(0, 4);
        }
        return response;
      }
    }
  ]
});

function toggleStatus() {
  data.value[0].status = data.value[0].status === 0 ? 1 : 0;
}
function toggleTenant() {
  data.value[0].tenantId = data.value[0].tenantId === 'north' ? 'south' : 'north';
}
function reset() {
  error.value = '';
  records.value = [];
  data.value = initialRows();
}
function handleError() {
  error.value = '演示字典加载失败,请点击「恢复示例」重试。';
}
</script>

<style scoped>
.row-dic-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.row-dic-actions .el-button { margin-left: 0; }
.row-dic-result {
  margin-top: 16px;
  padding: 16px;
  border: 1px solid var(--el-border-color-lighter);
  border-radius: 8px;
  background: var(--el-fill-color-light);
  line-height: 1.7;
  overflow-wrap: anywhere;
}
.row-dic-result pre { margin: 8px 0 16px; white-space: pre-wrap; font-size: 13px; }
.row-dic-result ul { margin: 8px 0 0; padding-left: 20px; }
</style>

模板变量从哪里取值

使用场景{{key}} 的来源示例
普通逐行字典列当前行的当前字段,即 row[column.prop]status 列中为 row.status
通过 cascader 关联的子字段上级字段的值城市字典中为 row.province
remote: true 的远程搜索当前输入的搜索词输入「张」时搜索「张」
普通逐行字典中的 {{字段名}}当前行的对应字段{{tenantId}} 取 row.tenantId

dicQuery 和 dicHeaders 的模板值使用完整占位符,例如 { tenant: '{{tenantId}}' }。GET 请求使用查询参数,其他请求方法使用请求体;dicUrl 可以把占位符放在路径中。

使用边界

  • 逐行字典适用于普通 CRUD 字典列。级联子列、remote: true、lazy: true 和 dicFlag: false 的列仍走各自的加载流程。
  • 模板引用的值为空时,不请求该行字典;数字 0 是有效值。列表数据或模板依赖字段改变后会重新加载,无需手动拼接每行 URL。
  • 每个逐行字典列会针对列表中的各行发起请求。数据量大时,优先分页,或使用通用 dicData,避免不必要的请求。
  • 示例 JSON 是固定演示数据。接入业务时,将路径换成自己的接口,让接口根据参数返回字典;不需要复制解析记录面板。

省、市、区字典联动

效果预览可直接操作下方示例

父字段的 cascader 指向子字段的 prop。城市接口中的 {{key}} 使用省份编码,区县接口中的 {{key}} 使用城市编码。点击「切换首行地区」重新加载级联标签,也可以点击「编辑」逐级选择并保存。

正在加载示例…
<template>
  <div class="cascader-example">
    <el-button :loading="loading" @click="switchRegion">切换首行地区</el-button>
    <avue-crud ref="crud"
               v-model="form"
               :data="data"
               :option="option"
               @row-update="saveRow"
               @dic-error="handleError" />
    <el-alert v-if="error" :title="error" type="error" :closable="false" />
    <p class="cascader-result" aria-live="polite">
      首行编码:省 {{ data[0].province }} → 市 {{ data[0].city }} → 区 {{ data[0].area }}
    </p>
  </div>
</template>

<script setup>
import { nextTick, onMounted, ref } from 'vue';

const crud = ref(null);
const form = ref({});
const loading = ref(false);
const error = ref('');
const data = ref([
  { id: 1, name: '张三', province: '110000', city: '110100', area: '110101' },
  { id: 2, name: '李四', province: '130000', city: '130100', area: '130102' }
]);
const props = { label: 'name', value: 'code' };
const option = ref({
  rowKey: 'id',
  border: true,
  addBtn: false,
  delBtn: false,
  refreshBtn: false,
  columnBtn: false,
  menuWidth: 100,
  column: [
    { label: '姓名', prop: 'name', minWidth: 90 },
    {
      label: '省份',
      prop: 'province',
      type: 'select',
      props,
      cascader: ['city'],
      cascaderIndex: 0,
      dicUrl: '/examples/crud-dic/provinces.json'
    },
    {
      label: '城市',
      prop: 'city',
      type: 'select',
      props,
      cascader: ['area'],
      cascaderIndex: 0,
      // 子字段 key 由上级 province 提供。
      dicUrl: '/examples/crud-dic/cities/{{key}}.json'
    },
    {
      label: '区县',
      prop: 'area',
      type: 'select',
      props,
      // 子字段 key 由上级 city 提供。
      dicUrl: '/examples/crud-dic/areas/{{key}}.json'
    }
  ]
});

async function loadCascader() {
  await nextTick();
  await crud.value?.dicInit('cascader');
}
async function switchRegion() {
  loading.value = true;
  error.value = '';
  const isBeijing = data.value[0].province === '110000';
  Object.assign(data.value[0], isBeijing
    ? { province: '130000', city: '130100', area: '130102' }
    : { province: '110000', city: '110100', area: '110101' });
  try {
    await loadCascader();
  } finally {
    loading.value = false;
  }
}
async function saveRow(row, index, done) {
  data.value.splice(index, 1, { ...row });
  done();
  await loadCascader();
}
function handleError() {
  error.value = '级联字典加载失败,请刷新页面后重试。';
}
onMounted(loadCascader);
</script>

<style scoped>
.cascader-example > .el-button { margin-bottom: 16px; }
.cascader-result {
  margin: 16px 0 0;
  padding: 12px 16px;
  border-radius: 8px;
  background: var(--el-fill-color-light);
  line-height: 1.7;
  overflow-wrap: anywhere;
}
</style>

列表首次赋值、分页取回数据或外部修改级联值后,在 Vue 更新数据后加载用于表格回显的级联字典:

data.value = records;
await nextTick();
await crud.value.dicInit('cascader');

父列配置的是 cascader: ['city'],字段名必须与子列的 prop 一致。城市、区县保存各自的编码。外部代码修改父级时,也应清空子级或同步写入匹配的子级值;本例切换按钮同时写入一组有效的省、市、区编码。

最后更新:
贡献者: smallwei
Prev
表格列配置项
Next
操作栏配置