🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@complex-suite/data

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@complex-suite/data

a complex data

Source
npmnpm
Version
5.0.13
Version published
Weekly downloads
686
-2.28%
Maintainers
1
Weekly downloads
 
Created
Source

@complex-suite/data 快速使用

@complex-suite/data 是 complex-suite 的核心数据层。它不负责渲染 UI,而是负责描述业务页面的数据结构、搜索条件、字典字段、分页、选择、编辑、详情、异步加载和业务操作。

在当前 monorepo 中,它位于依赖链中间:utils → plugin → data → component → component-antd。实际业务页面通常通过 data 创建无头数据模型,再交给 component-antdComplexQuickListComplexQuickCascade 等组件渲染。

安装

pnpm add @complex-suite/data

架构概览

packages/data/
├── index.ts                  # 包入口,按 7 组导出
├── dataConfig.ts             # 全局配置(颜色/empty Symbol/工具函数)
├── src/
│   ├── data/                 # 数据类继承链
│   │   ├── Data.ts           # 基类:_id/_buffer/_syncData 钩子
│   │   ├── SimpleData.ts     # $extra 额外数据
│   │   ├── DefaultData.ts    # $prop/$life 生命周期/Storage
│   │   ├── BaseData.ts       # $status/$promise/$depend/$module/active/loadData
│   │   └── ComplexData.ts    # 业务回调(buildData/changeData/...)+ 模块代理方法
│   ├── core/                 # 业务数据类
│   │   ├── ComplexList.ts    # 列表页主模型
│   │   ├── ComplexInfo.ts    # 详情页模型
│   │   ├── SelectData.ts      # 选择器数据模型
│   │   └── TrackData.ts      # 轨迹回放模型(独立模块)
│   ├── module/               # 可复用功能模块
│   │   ├── ModuleData.ts     # 模块容器
│   │   ├── DictionaryData.ts # 字典模块(必填)
│   │   ├── SearchData.ts     # 检索模块
│   │   ├── PaginationData.ts# 分页模块
│   │   ├── ChoiceData.ts     # 多选模块
│   │   ├── SortData.ts       # 排序模块
│   │   ├── UpdateData.ts     # 定时刷新模块
│   │   ├── StatusData.ts     # 状态机模块
│   │   ├── DependData.ts     # 依赖加载模块
│   │   ├── PromiseData.ts    # Promise 缓存模块
│   │   └── ResetData.ts      # reset/destroy 基类
│   ├── lib/                  # 值对象与工具类
│   │   ├── DictionaryValue.ts# 字典项容器
│   │   ├── ArrayValue.ts     # 可观测数组
│   │   ├── SelectValue.ts     # 选择器数据源
│   │   ├── CascaderValue.ts  # 级联选择器
│   │   ├── FormValue.ts       # 表单校验桥接
│   │   ├── StorageValue.ts   # 持久化缓存
│   │   ├── ForceValue.ts      # 强制加载配置
│   │   ├── InterfaceValue.ts  # 多场景接口值
│   │   ├── AttrsValue.ts      # 属性合并
│   │   ├── TipValue.ts        # 提示文本
│   │   ├── FileValue.ts       # 文件数据
│   │   ├── GridParse.ts       # 栅格解析
│   │   └── LayoutParse.ts     # 布局解析
│   ├── dictionary/           # 字典项实现(24 个)
│   │   ├── DefaultMod.ts     # 字典项基类
│   │   ├── DefaultList.ts, DefaultInfo.ts, DefaultEdit.ts
│   │   ├── InputEdit.ts, TextAreaEdit.ts, InputNumberEdit.ts
│   │   ├── SelectEdit.ts, DefaultSelectEdit.ts, SwitchEdit.ts
│   │   ├── DateEdit.ts, DateRangeEdit.ts, SimpleDateEdit.ts
│   │   ├── FileEdit.ts, ButtonEdit.ts, ButtonGroupEdit.ts
│   │   ├── ContentEdit.ts, CustomEdit.ts, CustomLoadEdit.ts
│   │   ├── FormEdit.ts, ListEdit.ts
│   │   ├── DefaultSimpleEdit.ts, DefaultLoadEdit.ts
│   │   └── ObserveList.ts
│   ├── locale/               # 国际化(zh/en)
│   └── types/                # 类型定义
└── README.md

核心概念

  • ComplexList:列表页主数据模型,维护 $list、加载状态、搜索、分页、选择、字典和增删改查方法。
  • ComplexInfo:详情页数据模型,维护 $info,常用于详情弹窗或详情页。
  • module.dictionary:字段字典,统一描述表格列、详情字段、编辑表单、创建表单和搜索字段。
  • module.search:搜索区配置,包含搜索字段和顶部菜单按钮。
  • module.pagination:分页模块,提供 getPage()getPageSize()setPageCount() 等能力。
  • SelectValue / SelectEdit:选择器数据源与选择器字典项,支持静态选项和远程加载。
  • ButtonEdit:按钮字典项,常用于搜索区菜单、自定义操作和上传入口。

数据类继承链

Data (utils._Data)
  └─ SimpleData          # $extra
      └─ DefaultData     # $prop / $life / $storage
          └─ BaseData    # $status / $promise / $depend / $module / loadData
              └─ ComplexData  # 业务回调(getData/buildData/...)+ 模块代理方法
                  ├─ ComplexList  # $list
                  └─ ComplexInfo  # $info

每一层只关心自己的关注点,子类通过 _triggerCreateLife('ClassName', false/true, initOption) 触发对应的 beforeCreate/created 生命周期。

模块系统

ComplexList 通过 module 挂载功能模块,每个模块独立管理一类能力:

模块作用必填
dictionaryDictionaryData字段字典管理
searchSearchData检索表单与菜单-
paginationPaginationData分页参数与总数-
choiceChoiceData多选状态-
sortSortData排序参数-
updateUpdateData定时刷新-
dependDependData依赖加载-
statusStatusData状态机内置
promisePromiseDataPromise 缓存内置

模块通过 installData / uninstallData 安装卸载,触发 _install / _uninstall 钩子。模块间通过 ModuleData.getData(modName) 互相查询。

生命周期

ComplexList 内置 Life 系统,常用生命周期:

名称触发时机
beforeCreate / created实例构造前后
beforeLoadloadData 开始
loaded加载成功
loadFail加载失败
beforeReload / reloaded / reloadFailreloadData 各阶段
beforeSearchsetSearch 校验前
searched / searchFail检索成功/失败
beforeUpdate / updated / updateFail更新数据各阶段
beforeReset / resetedreset 前后
beforeDestroy / destroyeddestroy 前后
dataChange业务方法成功后(buildData/changeData/deleteData/...)
parentChange$setParent

监听方式:

listData.onLife('loaded', {
  id: 'myHandler',
  handler: (lifeValue, res) => {
    console.log('加载完成', res)
  }
})
listData.offLife('loaded', 'myHandler')

onLoaded(handler)loaded 的快捷监听,若当前已加载完成会立即触发。

基础列表用法

下面示例提炼自真实业务页面 src/pages/index/views/list/base/index.vue,展示标准模式:页面创建 ComplexList,配置搜索、字典、分页和业务接口,然后传给 ComplexQuickList 渲染。

<template>
  <div class="local-page">
    <ComplexQuickList
      :list-data="mainData"
      :components="['spin', 'search', 'table', 'edit', 'info']"
      :simple-table="false"
      :components-props="componentsProps"
      @search="onSearch"
      @table="onTable"
    />
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { ButtonEdit, ComplexList, SelectEdit, SelectValue, type fileDataType } from '@complex-suite/data'
import { ComplexQuickList, icon, type componentsProps, type tablePayload } from '@complex-suite/component-antd'
import listApi from '@/api/listApi'

export default defineComponent({
  name: 'RecordList',
  components: { ComplexQuickList },
  setup() {
    // 1) 静态选项数据源
    const select = new SelectValue({
      list: [
        { value: 0, label: '选项1' },
        { value: 1, label: '选项2' },
        { value: 2, label: '选项3' }
      ]
    })

    // 2) 创建列表数据模型
    const mainData = new ComplexList({
      prop: 'mainData',
      module: {
        // 搜索区
        search: {
          menu: {
            list: [
              'build',                       // 内置:新增按钮
              'delete',                      // 内置:批量删除按钮
              new ButtonEdit({               // 自定义按钮
                prop: 'choice2',
                type: 'button',
                option: {
                  name: () => '已选择2条时可用',
                  disabled(payload: any) {
                    return payload.choice !== 2
                  },
                  click() {
                    return Promise.resolve({})
                  }
                }
              }),
              new ButtonEdit({               // 文件上传按钮
                prop: '$import',
                type: 'button',
                option: {
                  name: () => '导入',
                  icon: () => icon.local('emptyImage', { size: 16 }),
                  upload: () => Promise.resolve({})
                }
              })
            ]
          },
          list: [
            {
              prop: 'input',
              name: '输入框',
              mod: {
                search: {
                  $format: 'edit',
                  type: 'input',
                  collapse: 2,
                  option: { size: 20 }
                }
              }
            },
            {
              prop: 'search',
              name: '检索框',
              mod: {
                search: {
                  $format: 'edit',
                  type: 'select',
                  cascader: undefined,
                  width: 100,
                  reload: true,
                  search: {},
                  // 远程加载选项
                  getData(this: SelectEdit) {
                    return new Promise((resolve) => {
                      this.$select.setList([
                        { value: this.$search?.value, label: this.$search?.value || '' },
                        { value: 1, label: '1' },
                        { value: 2, label: '2' }
                      ])
                      resolve({})
                    })
                  }
                }
              }
            }
          ]
        },
        // 字典:字段定义(同时服务 list/info/edit/build/change)
        dictionary: {
          propData: { id: 'id' },
          list: [
            { prop: 'menu', name: '操作', originFrom: 'local', mod: { list: { width: 140 } } },
            { prop: '$index', name: 'No', originFrom: 'local', mod: { list: { width: 60 } } },
            {
              prop: 'id',
              name: 'ID',
              mod: { list: { width: 80 }, info: {} }
            },
            {
              prop: 'input',
              name: '输入框',
              mod: {
                list: { width: 100 },
                info: {},
                edit: { type: 'input', required: true, option: { size: 20 } },
                build: { $redirect: 'edit' },
                change: { $redirect: 'edit' }
              }
            },
            {
              prop: 'switch',
              name: '开关',
              assign(value) { return value === 1 ? true : false },
              collect(value) { return value ? 1 : 0 },
              mod: {
                list: { width: 70 },
                edit: { type: 'switch', required: true },
                build: { $redirect: 'edit' },
                change: { $redirect: 'edit' }
              }
            },
            {
              prop: 'select',
              name: '选择器',
              showProp: { default: 'value', list: 'label' },
              assign(value) { return select.getItem(value) },
              mod: {
                list: { width: 100 },
                edit: {
                  type: 'select',
                  cascader: undefined,
                  required: true,
                  select: select,
                  pagination: {},
                  getData(this: any) {
                    return new Promise((resolve) => {
                      setTimeout(() => {
                        this.$select.setList(select.getList())
                        this.$pagination.setCount(100)
                        resolve({})
                      }, 200)
                    })
                  }
                },
                build: { $redirect: 'edit' },
                change: { $redirect: 'edit' }
              }
            },
            {
              prop: 'multipleFile',
              name: '多文件',
              assign(value) { return value ? (value as string).split(',') : [] },
              collect(value) { return value ? (value as string[]).join(',') : '' },
              mod: {
                edit: { type: 'file', multiple: true, required: true },
                build: { $redirect: 'edit' },
                change: { $redirect: 'edit' }
              }
            },
            {
              prop: 'timeRange',
              name: '时间范围',
              assign(value) { return (value as string).split(',') },
              collect(value) { return (value as string[]).join(',') },
              mod: {
                list: { width: 300 },
                edit: {
                  type: 'dateRange',
                  required: true,
                  option: {
                    time: {},
                    rangeLimit: { value: 5 * 24 * 60 * 60 },
                    disabledDate: {
                      start: { value: 'today', eq: true },
                      end: { value: 'tomorrow', eq: true }
                    }
                  }
                },
                build: { $redirect: 'edit' },
                change: { $redirect: 'edit' }
              }
            }
          ]
        },
        pagination: true
      },
      // 业务回调:均要求返回 Promise
      getData(this: ComplexList) {
        return new Promise((resolve, reject) => {
          const postData = {
            ...this.getSearch(),
            page: this.getPage(),
            size: this.getPageSize()
          } as any
          listApi.baseList.require(postData).then(res => {
            this.formatList(res.data.data.list, res.data.data.num)
            resolve(res)
          }).catch(reject)
        })
      },
      buildData(this: ComplexList, targetData) {
        return new Promise((resolve, reject) => {
          listApi.baseBuild.require(targetData).then(res => {
            this.reloadData(true)
            resolve(res)
          }).catch(reject)
        })
      },
      changeData(this: ComplexList, targetData, originData) {
        return new Promise((resolve, reject) => {
          targetData.id = originData.id
          listApi.baseChange.require(targetData).then(res => {
            this.reloadData(true)
            resolve(res)
          }).catch(reject)
        })
      },
      deleteData(this: ComplexList, targetData) {
        return new Promise((resolve) => {
          const index = this.$list.indexOf(targetData)
          if (index > -1) {
            this.$list.splice(index, 1)
          }
          resolve({})
        })
      },
      multipleDeleteData(this: ComplexList, choiceList) {
        return new Promise((resolve) => {
          choiceList.forEach(item => {
            const index = this.$list.indexOf(item)
            if (index > -1) {
              this.$list.splice(index, 1)
            }
          })
          resolve({})
        })
      }
    })

    const onSearch = function(_prop: string) {}
    const onTable = function(_prop: string, _payload: tablePayload) {}

    return {
      mainData: mainData,
      onSearch: onSearch,
      onTable: onTable,
      componentsProps: {
        table: {
          menu: {
            menu: [
              { prop: '$change', name: () => '编辑', color: 'link' },
              { prop: '$delete', name: () => '删除', color: 'danger' },
              { prop: '$info', name: () => '详情', color: 'link' }
            ]
          }
        },
        edit: {}
      } as componentsProps
    }
  },
  mounted() {
    this.mainData.loadData(true)
  }
})
</script>

字典字段配置

module.dictionary.list 是列表页的核心协议。一个字段可同时服务多个场景:

{
  prop: 'name',           // 字段标识
  name: '名称',           // 显示名
  originFrom: 'local',   // 数据来源:local / search / data
  showProp: {             // 不同场景下展示的字段
    default: 'value',
    list: 'label'
  },
  assign(value) { ... },  // 接口值进入展示/表单前的转换
  collect(value) { ... }, // 表单值提交前的转换
  dictionary: {           // 嵌套字典(type: 'form'/'list' 时使用)
    list: [...]
  },
  mod: {
    list:   { width: 100 },          // 表格列配置
    info:   {},                      // 详情字段配置
    edit:   { type: 'input', required: true },  // 通用编辑配置
    build:  { $redirect: 'edit' },   // 新增表单:复用 edit
    change: { $redirect: 'edit' },   // 修改表单:复用 edit
    search: { $format: 'edit', type: 'input' }  // 搜索字段
  }
}

编辑类型对照

type字典类适用场景
inputInputEdit文本输入
textAreaTextAreaEdit多行文本
inputNumberInputNumberEdit数字输入
selectSelectEdit / DefaultSelectEdit选择器
switchSwitchEdit开关
dateDateEdit / SimpleDateEdit日期
dateRangeDateRangeEdit日期范围
fileFileEdit文件上传
buttonButtonEdit按钮(搜索区/自定义操作)
formFormEdit内嵌表单
listListEdit内嵌列表
contentContentEdit纯展示
customCustomEdit / CustomLoadEdit自定义渲染

搜索区配置

module.search 分为菜单和搜索字段两部分:

search: {
  menu: {
    list: [
      'build',                        // 内置:新增
      'delete',                       // 内置:批量删除
      new ButtonEdit({ ... })         // 自定义按钮
    ]
  },
  list: [
    {
      prop: 'keyword',
      name: '关键字',
      mod: {
        search: {
          $format: 'edit',
          type: 'input',
          collapse: 2                 // 折叠阈值(字段数 > 2 时折叠)
        }
      }
    }
  ]
}

ComplexQuickList 已内置处理这些菜单:

prop行为
$search调用 listData.setSearch(),更新搜索条件并触发列表加载
$reset调用 listData.resetSearch(),重置搜索条件
$refresh调用 listData.reloadData({ data: true, sync: true })
$build打开新增弹窗
$delete触发批量删除(基于 choice)
$info打开详情弹窗
$export调用 listData.triggerMethod('exportData')
$import / $image文件上传按钮(通过 upload 回调)

ButtonEdit 区分两种语义:

  • click():普通点击回调,返回 Promise
  • upload(file: File):文件上传专用回调,由组件触发文件选择 → 拿到 File → 调用 upload

远程选择器

选择器可以使用静态 SelectValue,也可以在 SelectEdit.getData 中远程加载选项:

{
  prop: 'search',
  name: '检索框',
  mod: {
    search: {
      $format: 'edit',
      type: 'select',
      cascader: undefined,        // 显式声明无级联
      width: 100,
      reload: true,                // 搜索框值变化时重新加载
      search: {                   // SelectValue 配置
        limit: 3,                  // 最多保留 3 个历史选项
        limitContent: '限制3个'
      },
      getData(this: SelectEdit) {
        return new Promise((resolve) => {
          this.$select.setList([
            { value: this.$search?.value, label: this.$search?.value || '' },
            { value: 1, label: '1' },
            { value: 2, label: '2' }
          ])
          resolve({})
        })
      }
    }
  }
}

如果远程接口有分页结果,可在 getData 中同时调用 this.$pagination.setCount(total)

数据加载与提交

ComplexList 的业务方法都要求返回 Promise,这样状态模块才能正确维护 loadoperate 等状态。

getData(this: ComplexList) {
  return new Promise((resolve, reject) => {
    const postData = {
      ...this.getSearch(),       // 搜索条件
      page: this.getPage(),      // 当前页码
      size: this.getPageSize()   // 每页数量
    }
    api.list(postData).then(res => {
      this.formatList(res.list, res.total)  // 写入 $list 和分页总数
      resolve(res)
    }).catch(reject)
  })
}

常用方法:

方法作用
loadData(force?, ...args)加载数据,force 控制是否强制
reloadData(force?, ...args)重新加载,触发 beforeReload/reloaded/reloadFail
formatList(list, total)写入 $list,同步分页总数
getSearch()获取搜索区当前值
getPage() / getPageSize()获取当前分页参数
setPage(page) / setPageSize(size)修改分页参数
triggerMethod(method, args, option)通过状态机触发业务方法
triggerMethodWithOperateAndStatus(method, args, statusOption, operateOption)触发并联动目标 status + operate
setSort(prop, order)设置排序
setChoice(data) / resetChoice()多选操作

force 参数支持多种形式:

listData.loadData(true)                          // 强制重新加载
listData.loadData(false)                         // 仅在未加载或失败时加载
listData.loadData({ data: true, ing: true })     // 强制数据 + 强制进行中
listData.loadData({                              // 完整配置
  data: true,            // 强制数据加载
  ing: true,             // 强制进行中状态
  promise: true,         // 强制触发 promise
  sync: true,            // 等待 promise 完成
  trigger: { from: 'search', action: 'set' },
  module: { pagination: true }   // 同时重置某些模块
})

业务回调

ComplexList 支持在初始化配置中定义业务回调,this 绑定到当前实例:

interface ComplexDataInitOption {
  module: ModuleDataInitOption
  getData?: (this: ComplexList) => Promise<any>
  buildData?: (this: ComplexList, targetData) => Promise<any>
  changeData?: (this: ComplexList, targetData, originData) => Promise<any>
  editData?: (this: ComplexList, targetData, originData) => Promise<any>
  deleteData?: (this: ComplexList, targetData) => Promise<any>
  multipleDeleteData?: (this: ComplexList, choiceList) => Promise<any>
  refreshData?: (this: ComplexList, targetData) => Promise<any>
  updateData?: (this: ComplexList) => Promise<any>
  exportData?: (this: ComplexList) => Promise<any>
  importData?: (this: ComplexList, file: File) => Promise<any>
}

回调内可直接访问 this.$listthis.reloadData()this.getSearch() 等。buildData/changeData/deleteData 等修改类方法成功后会自动触发 dataChange 生命周期。

表格菜单

业务页面通常通过 componentsProps.table.menu.menu 配置表格行操作:

componentsProps: {
  table: {
    menu: {
      menu: [
        { prop: '$change', name: () => '编辑', color: 'link' },
        { prop: '$delete', name: () => '删除', color: 'danger' },
        { prop: '$info', name: () => '详情', color: 'link' }
      ]
    }
  }
}

ComplexQuickList 默认行为:

prop行为
$change打开编辑弹窗,使用当前行作为原始数据
$delete确认后调用 listData.triggerMethod('deleteData', [targetData])
$info打开详情弹窗

字段转换:assign 与 collect

接口值与表单值往往存在差异,字典字段提供了两个转换点:

{
  prop: 'switch',
  // 接口值(number)→ 展示/表单值(boolean)
  assign(value) {
    return value === 1 ? true : false
  },
  // 表单值(boolean)→ 提交值(number)
  collect(value) {
    return value ? 1 : 0
  }
}
  • assign:在 getData 成功后、数据进入 $list/$info/表单前调用
  • collect:在 buildData/changeData 提交前调用

对于多文件等场景,可结合 isFile 判断:

{
  prop: 'multipleFile',
  assign(value) { return value ? (value as string).split(',') : [] },
  collect(value) {
    return (value as any[])
      .map(item => isFile(item) ? item.name : item)
      .join(',')
  }
}

嵌套字典(FormEdit / ListEdit)

字段可嵌套完整字典,用于复杂场景(如内嵌表单/列表):

{
  prop: 'form',
  name: '内嵌表单',
  assign(value) { return value || { name: 'a', date: '2019-05-18' } },
  collect(value) { return value },
  dictionary: {
    list: [
      {
        prop: 'name',
        name: '名称',
        mod: {
          list: { width: 120 },
          info: { $redirect: 'edit' },
          edit: { type: 'input', required: true },
          build: { $redirect: 'edit' },
          change: { $redirect: 'edit' }
        }
      }
    ]
  },
  mod: {
    list: { width: 300 },
    info: { $redirect: 'edit' },
    edit: {
      grid: {                          // 栅格布局自定义
        line: 1,
        custom(data, position, _gridParse) {
          if (position === 'label') return { span: 0 }
          if (position === 'content') return { span: 24 }
          return data
        }
      },
      type: 'form',
      required: true,
      option: {}
    },
    build: { $redirect: 'edit' },
    change: { $redirect: 'edit' }
  }
}

级联列表

级联列表通常使用 ComplexQuickCascade。主列表通过表格菜单暴露 $sublist,点击后打开子列表弹窗,并由子列表自己的 ComplexList 加载数据。

推荐模式:

// 父列表
const parentData = new ComplexList({
  prop: 'parentData',
  module: {
    dictionary: { list: [...] },
    pagination: true
  },
  getData(this: ComplexList) {
    return new Promise((resolve, reject) => {
      listApi.parentList.require({
        ...this.getSearch(),
        page: this.getPage(),
        size: this.getPageSize()
      }).then(res => {
        this.formatList(res.data.data.list, res.data.data.num)
        resolve(res)
      }).catch(reject)
    })
  }
})

// 子列表
const childData = new ComplexList({
  prop: 'childData',
  module: {
    dictionary: { list: [...] },
    pagination: true
  },
  getData(this: ComplexList) {
    const parentId = this.getExtra('parentId')
    return new Promise((resolve, reject) => {
      listApi.childList.require({
        parentId,
        page: this.getPage(),
        size: this.getPageSize()
      }).then(res => {
        this.formatList(res.data.data.list, res.data.data.num)
        resolve(res)
      }).catch(reject)
    })
  }
})

// 触发子列表加载
const showSubList = function(targetData: any) {
  childData.setExtra('parentId', targetData.id)
  childData.reloadData(true)
}

$extra 是不参与字典/搜索/分页的额外数据容器,通过 setExtra / getExtra / clearExtra 操作。

全局配置与国际化

import { dataConfig, dataLocale } from '@complex-suite/data'

// 读取主题色
const primary = dataConfig.style.color.primary  // '#1677ff'

// 国际化
dataLocale.use('en')                              // 切换语言
dataLocale.t('baseData.methodNotExist', { method: 'foo' })  // 翻译

可注入自定义消息:

import { dataLocale, type DataMessages } from '@complex-suite/data'

const customMessages: Partial<DataMessages> = {
  zh: { baseData: { methodNotExist: '方法 {method} 不存在' } }
}
dataLocale.inject(customMessages)

重置与销毁

// 重置(不清除生命周期、storage)
listData.reset()                                  // 全部重置
listData.reset({ status: false, pagination: true })  // 选择性重置

// 销毁(彻底清理)
listData.destroy()                                // 全部销毁
listData.destroy({ life: true, depend: true })    // 同时销毁生命周期和依赖

resetOption 通过 parseResetOption(option, prop) 解析:true / false / undefined / { [prop]: boolean }

TypeScript 泛型

ComplexList 支持泛型约束列表项类型:

interface UserItem { id: number; name: string }
interface UserVO { id: number; name: string; deptName: string }

const listData = new ComplexList<UserItem, UserVO>({
  prop: 'userList',
  module: { dictionary: { list: [] }, pagination: true },
  getData(this: ComplexList<UserItem, UserVO>) {
    return fetch('/api/users').then(r => r.json()).then(res => {
      this.formatList(res.list, res.total)
      return res
    })
  }
})

listData.$list  // 类型为 UserItem[]

ComplexInfo<D> 类似,用于详情页:

const infoData = new ComplexInfo<UserVO>({
  prop: 'userInfo',
  module: { dictionary: { list: [...] } },
  getData(this: ComplexInfo<UserVO>) {
    return fetch(`/api/users/${this.$extra.id}`).then(r => r.json()).then(res => {
      this.formatInfo(res.data)
      return res
    })
  }
})

infoData.$info  // 类型为 Partial<UserVO>

SelectValue 与级联

import { SelectValue, CascaderValue } from '@complex-suite/data'

// 静态选择器
const select = new SelectValue({
  list: [{ value: 1, label: 'A' }, { value: 2, label: 'B' }],
  equal: (a, b) => a.value === b.value,   // 自定义相等判断
  hidden: true                              // 启用隐藏能力
})

// 级联选择器(cascader 指定子字段名)
const cascader = new CascaderValue({
  list: [
    {
      value: 'zhejiang', label: '浙江',
      children: [
        { value: 'hangzhou', label: '杭州' },
        { value: 'ningbo', label: '宁波' }
      ]
    }
  ],
  cascader: 'children'
})

推荐实践

  • 列表页优先用 ComplexList 作为唯一业务状态入口,UI 组件只消费它,不重复维护列表、分页和搜索状态。
  • 字段配置优先集中在 module.dictionary.list,通过 listinfoeditbuildchange 复用同一字段语义。
  • 所有业务回调都返回 Promise,包括 getDatabuildDatachangeDatadeleteData、自定义按钮 click 和上传 upload
  • 接口返回值进入表单前使用 assign,提交前使用 collect,避免在 UI 组件中散落转换逻辑。
  • 新增和修改表单大多可通过 $redirect: 'edit' 复用配置,只在字段行为确实不同的时候单独覆盖。
  • 远程加载选择器时,在 getData 中同步调用 this.$pagination.setCount(total) 让分页模块拿到总数。
  • 使用 onLife / offLife 监听关键生命周期(loadeddataChangebeforeReset),避免在组件内用 setTimeout 等待异步。
  • force 参数优先用对象形式({ data: true, ing: true }),可读性优于布尔简写。
  • 使用 component-antd 时,data 只负责无头数据协议,渲染细节交给 ComplexQuickListTableViewEditAreaInfoArea

依赖

  • @complex-suite/utils:核心工具函数和基类(Life、Watcher、setProp 等)。
  • @complex-suite/plugin:布局和通知系统。

Keywords

complex

FAQs

Package last updated on 06 Jul 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts