No.4 组件 & Props

本文深入探讨了React中组件的概念,包括如何使用函数和类定义组件,组件的渲染过程,以及如何通过Props传递数据。同时,文章强调了组件的可复用性和组合能力,展示了如何通过分解组件来提高代码的可维护性和复用性。

组件 & Props

组件可以将UI切分成一些独立的、可复用的部件,这样你就只需专注于构建每一个单独的部件。

组件从概念上看就像是函数,它可以接收任意的输入值(称之为“props”),并返回一个需要在页面上展示的React元素。

 

函数定义/类定义组件

定义一个组件最简单的方式是使用JavaScript函数:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

该函数是一个有效的React组件,它接收一个单一的“props”对象并返回了一个React元素。我们之所以称这种类型的组件为函数定义组件,是因为从字面上来看,它就是一个JavaScript函数。

你也可以使用 ES6 class 来定义一个组件:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

上面两个组件在React中是相同的。

我们将在之后讨论类的一些额外特性。在那之前,我们都将使用较为简洁的函数定义组件。

 

组件渲染

在前面,我们遇到的React元素都只是DOM标签:

const element = <div />;

然而,React元素也可以是用户自定义的组件:

const element = <Welcome name="Sara" />;

当React遇到的元素是用户自定义的组件,它会将JSX属性作为单个对象传递给该组件,这个对象称之为“props”。

例如,这段代码会在页面上渲染出”Hello,Sara”:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

在 CodePen 上试试。

我们来回顾一下在这个例子中发生了什么:

  1. 我们对<Welcome name="Sara" />元素调用了ReactDOM.render()方法。
  2. React将{name: 'Sara'}作为props传入并调用Welcome组件。
  3. Welcome组件将<h1>Hello, Sara</h1>元素作为结果返回。
  4. React DOM将DOM更新为<h1>Hello, Sara</h1>

警告:

组件名称必须以大写字母开头。

例如,<div /> 表示一个DOM标签,但 <Welcome /> 表示一个组件,并且在使用该组件时你必须定义或引入它。

组合组件

组件可以在它的输出中引用其它组件,这就可以让我们用同一组件来抽象出任意层次的细节。在React应用中,按钮、表单、对话框、整个屏幕的内容等,这些通常都被表示为组件。

例如,我们可以创建一个App组件,用来多次渲染Welcome组件:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function App() {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
class App extends React.Component {
  render(){
      return (
      <div>
        <Welcome name="Sara" />
        <Welcome name="Cahal" />
        <Welcome name="Edite" />
      </div>
  );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

在 CodePen 上试试。

通常,一个新的React应用程序的顶部是一个App组件。但是,如果要将React集成到现有应用程序中,则可以从下而上使用像Button这样的小组件作为开始,并逐渐运用到视图层的顶部。

警告:

组件的返回值只能有一个根元素。这也是我们要用一个<div>来包裹所有<Welcome />元素的原因。

提取组件

你可以将组件切分为更小的组件,这没什么好担心的。

例如,来看看这个Comment组件:

function formatDate(date) {
  return date.toLocaleDateString();
}

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
             src={props.author.avatarUrl}
             alt={props.author.name} />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

const comment = {
  date: new Date(),
  text: 'I hope you enjoy learning React!',
  author: {
    name: 'Hello Kitty',
    avatarUrl: 'http://placekitten.com/g/64/64'
  }
};
ReactDOM.render(
  <Comment
    date={comment.date}
    text={comment.text}
    author={comment.author} />,
  document.getElementById('root')
);

在 CodePen 上试试。

这个组件接收author(对象)、text(字符串)、以及date(Date对象)作为props,用来描述一个社交媒体网站上的评论。

这个组件由于嵌套,变得难以被修改,可复用的部分也难以被复用。所以让我们从这个组件中提取出一些小组件。

首先,我们来提取Avatar组件:



function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}

Avatar作为Comment的内部组件,不需要知道是否被渲染。因此我们将author改为一个更通用的名字user

我们建议从组件自身的角度来命名props,而不是根据使用组件的上下文命名。

现在我们可以对Comment组件做一些小小的调整:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <Avatar user={props.author} />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

接下来,我们要提取一个UserInfo组件,用来渲染Avatar旁边的用户名:

function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  );
}

这可以让我们进一步简化Comment组件:

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

至此:完整提取后的代码

function formatDate(date) {
  return date.toLocaleDateString();
}

function Avatar(props) {
  return (
    <img className="Avatar"
         src={props.user.avatarUrl}
         alt={props.user.name} />
  );
}

function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  );
}

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

const comment = {
  date: new Date(),
  text: 'I hope you enjoy learning React!',
  author: {
    name: 'Hello Kitty',
    avatarUrl: 'http://placekitten.com/g/64/64'
  }
};
ReactDOM.render(
  <Comment
    date={comment.date}
    text={comment.text}
    author={comment.author} />,
  document.getElementById('root')
);

在 CodePen 上试试。

提取组件一开始看起来像是一项单调乏味的工作,但是在大型应用中,构建可复用的组件完全是值得的。当你的UI中有一部分重复使用了好几次(比如,ButtonPanelAvatar),或者其自身就足够复杂(比如,AppFeedStoryComment),类似这些都是抽象成一个可复用组件的绝佳选择,这也是一个比较好的做法。

Props的只读性

无论是使用函数或是类来声明一个组件,它决不能修改它自己的props。来看这个sum函数:

function sum(a, b) {
  return a + b;
}

类似于上面的这种函数称为“纯函数”,它没有改变它自己的输入值,当传入的值相同时,总是会返回相同的结果。

与之相对的是非纯函数,它会改变它自身的输入值:

function withdraw(account, amount) {
  account.total -= amount;
}

React是非常灵活的,但它也有一个严格的规则:

所有的React组件必须像纯函数那样使用它们的props。

当然,应用的界面是随时间动态变化的,之后介绍一种称为“state”的新概念,State可以在不违反上述规则的情况下,根据用户操作、网络响应、或者其他状态变化,使组件动态的响应并改变组件的输出。

&lt;template&gt; &lt;section&gt; &lt;a-form :form=&quot;formState&quot; @submit.prevent=&quot;onSubmit&quot; ref=&quot;formRef&quot;&gt; &lt;a-row :gutter=&quot;5&quot;&gt; &lt;a-col :span=&quot;3&quot;&gt; &lt;a-form-item label=&quot;基地&quot; :label-col=&quot;{ span: 7 }&quot; :wrapper-col=&quot;{ span: 12 }&quot; :rules=&quot;[{ required: true, message: &#39;请选择基地&#39; }]&quot;&gt; &lt;c-build-case-select v-model:value=&quot;formState.orgNo&quot; :fieldNames=&quot;{ value: &#39;orgNo&#39;, optionLabelProp: &#39;name&#39; }&quot; /&gt; &lt;/a-form-item&gt; &lt;/a-col&gt; &lt;a-col :span=&quot;3&quot;&gt; &lt;a-form-item label=&quot;项目&quot; :label-col=&quot;{ span: 7 }&quot; :wrapper-col=&quot;{ span: 12 }&quot; :rules=&quot;[{ required: true, message: &#39;请选择项目&#39; }]&quot;&gt; &lt;c-project-select v-model:value=&quot;formState.projectNo&quot; style=&quot;width: 160px&quot;/&gt; &lt;/a-form-item&gt; &lt;/a-col&gt; &lt;a-col :span=&quot;5&quot;&gt; &lt;a-form-item label=&quot;需求日期&quot; :label-col=&quot;{ span: 7 }&quot; :wrapper-col=&quot;{ span: 12 }&quot; :rules=&quot;[{ required: true, message: &#39;请选择需求日期&#39; }]&quot;&gt; &lt;a-date-picker v-model:value=&quot;formState.needDate&quot; format=&quot;YYYY-MM-DD&quot;/&gt; &lt;/a-form-item&gt; &lt;/a-col&gt; &lt;a-col :span=&quot;3&quot;&gt; &lt;a-form-item&gt; &lt;a-button @click=&quot;search&quot; type=&quot;primary&quot; :icon=&quot;h(BarChartOutlined)&quot;&gt;齐套分析&lt;/a-button&gt; &lt;/a-form-item&gt; &lt;/a-col&gt; &lt;/a-row&gt; &lt;a-row&gt; &lt;a-col :span=&quot;3&quot;&gt; &lt;a-form-item label=&quot;托盘号&quot; :label-col=&quot;{ span: 7 }&quot; :wrapper-col=&quot;{ span: 12 }&quot;&gt; &lt;a-input v-model:value=&quot;searchHoldNo&quot;/&gt; &lt;/a-form-item&gt; &lt;/a-col&gt; &lt;a-col :span=&quot;5&quot;&gt; &lt;a-form-item&gt; &lt;a-radio-group v-model:value=&quot;searchState&quot;&gt; &lt;a-radio :value=&quot;1&quot;&gt;全部&lt;/a-radio&gt; &lt;a-radio :value=&quot;2&quot;&gt; 可做大于 &lt;a-input v-model:value=&quot;filterNum&quot; type=&quot;number&quot; style=&quot;width: 60px&quot;/&gt; % &lt;/a-radio&gt; &lt;a-radio :value=&quot;3&quot;&gt;管线齐套&lt;/a-radio&gt; &lt;/a-radio-group&gt; &lt;/a-form-item&gt; &lt;/a-col&gt; &lt;a-col :span=&quot;7&quot;&gt; &lt;a-form-item&gt; &lt;a-button @click=&quot;searchFilter&quot; type=&quot;primary&quot; :icon=&quot;h(FilterOutlined)&quot; style=&quot;margin-right: 10px&quot;&gt;过滤&lt;/a-button&gt; &lt;a-button @click=&quot;exportData&quot; type=&quot;primary&quot; :icon=&quot;h(DownloadOutlined)&quot; style=&quot;background-color: #faad14; border-color: #faad14; color: #fff;&quot;&gt;导出&lt;/a-button&gt; &lt;/a-form-item&gt; &lt;/a-col&gt; &lt;/a-row&gt; &lt;/a-form&gt; &lt;c-table filled :data-source=&quot;dataList&quot; :columns=&quot;tableState.columns&quot; :pagination=&quot;false&quot; :sortConfig=&quot;{ showIcon: false }&quot; :row-selection=&quot;rowSelection&quot; ref=&quot;tableRef&quot; &gt; &lt;/c-table&gt; &lt;/section&gt; &lt;/template&gt; &lt;script setup&gt; import {ref, reactive, computed, h} from &#39;vue&#39; import dayjs from &#39;dayjs&#39; import * as server from &quot;@/packages/piping/api/cppf&quot; import XLSX from &#39;xlsx&#39; import {DownloadOutlined, FilterOutlined, BarChartOutlined} from &quot;@ant-design/icons-vue&quot;; const formState = reactive({ orgNo: &#39;&#39;, projectNo: &#39;&#39;, needDate: null }) const formRef = ref() const searchHoldNo = ref(&#39;&#39;) const searchState = ref(1) const filterNum = ref(0) const loading = ref(false) const dataList = ref([]) const dataListOld = ref([ { index: 1, projectNo: &#39;PROJ001&#39;, orgNo: &#39;ORG001&#39;, holdNo: &#39;HOLD001&#39;, preOrgName: &#39;预制地1&#39;, holdSn: &#39;SN001&#39;, needDate: &#39;2023-10-01&#39;, totalNum: 10, totalUnfinishedNum: 5, pipeCanBeMade: &#39;100%&#39;, sequenceTotalCanNum: 3, sequencePipeCanBeMade: &#39;100%&#39;, pipelineList: [ { index: 1, projectNo: &#39;PROJ001&#39;, orgNo: &#39;ORG001&#39;, holdNo: &#39;HOLD001&#39;, preOrgName: &#39;预制地1&#39;, holdSn: &#39;SN001&#39;, needDate: &#39;2023-10-01&#39;, totalNum: 10, totalUnfinishedNum: 5, pipeCanBeMade: &#39;100%&#39;, sequenceTotalCanNum: 3, sequencePipeCanBeMade: &#39;100%&#39; }, { index: 2, projectNo: &#39;PROJ002&#39;, orgNo: &#39;ORG002&#39;, holdNo: &#39;HOLD002&#39;, preOrgName: &#39;预制地2&#39;, holdSn: &#39;SN002&#39;, needDate: &#39;2023-10-02&#39;, totalNum: 8, totalUnfinishedNum: 4, pipeCanBeMade: &#39;75%&#39;, sequenceTotalCanNum: 2, sequencePipeCanBeMade: &#39;75%&#39; } ] }, { index: 2, projectNo: &#39;PROJ002&#39;, orgNo: &#39;ORG002&#39;, holdNo: &#39;HOLD002&#39;, preOrgName: &#39;预制地2&#39;, holdSn: &#39;SN002&#39;, needDate: &#39;2023-10-02&#39;, totalNum: 8, totalUnfinishedNum: 4, pipeCanBeMade: &#39;75%&#39;, sequenceTotalCanNum: 2, sequencePipeCanBeMade: &#39;75%&#39;, pipelineList: [ { index: 1, projectNo: &#39;PROJ001&#39;, orgNo: &#39;ORG001&#39;, holdNo: &#39;HOLD001&#39;, preOrgName: &#39;预制地1&#39;, holdSn: &#39;SN001&#39;, needDate: &#39;2023-10-01&#39;, totalNum: 10, totalUnfinishedNum: 5, pipeCanBeMade: &#39;100%&#39;, sequenceTotalCanNum: 3, sequencePipeCanBeMade: &#39;100%&#39; }, { index: 2, projectNo: &#39;PROJ002&#39;, orgNo: &#39;ORG002&#39;, holdNo: &#39;HOLD002&#39;, preOrgName: &#39;预制地2&#39;, holdSn: &#39;SN002&#39;, needDate: &#39;2023-10-02&#39;, totalNum: 8, totalUnfinishedNum: 4, pipeCanBeMade: &#39;75%&#39;, sequenceTotalCanNum: 2, sequencePipeCanBeMade: &#39;75%&#39; } ] } ] ]) const tableState = reactive({ columns: [ { title: &#39;序号&#39;, dataIndex: &#39;index&#39;, align: &#39;center&#39;, width: 50, }, { title: &quot;项目&quot;, dataIndex: &quot;projectNo&quot;, width: 80, type: &quot;project&quot;, options: { options: [], fieldNames: {label: &quot;projId&quot;, value: &quot;projId&quot;} }, }, { title: &quot;基地&quot;, dataIndex: &quot;orgNo&quot;, width: 100, type: &#39;buildCase&#39; }, { title: &#39;托盘号&#39;, dataIndex: &#39;holdNo&#39;, }, { title: &#39;预制地&#39;, dataIndex: &#39;preOrgName&#39;, width: 160, }, { title: &#39;需求顺序&#39;, dataIndex: &#39;holdSn&#39;, width: 90 }, { title: &#39;需求日期&#39;, dataIndex: &#39;needDate&#39;, type: &#39;date&#39;, width: 110}, { title: &#39;总管数&#39;, dataIndex: &#39;totalNum&#39;, width: 80 }, { title: &#39;未排产管数&#39;, dataIndex: &#39;totalUnfinishedNum&#39;, align: &#39;center&#39;, width: 100 }, { title: &#39;顺序完全占用&#39;, align: &#39;center&#39;, children: [ {title: &#39;整体齐套率&#39;, dataIndex: &#39;pipeCanBeMade&#39;, width: 100}, {title: &#39;可做管数&#39;, dataIndex: &#39;sequenceTotalCanNum&#39;, width: 100}, {title: &#39;齐套率&#39;, dataIndex: &#39;sequencePipeCanBeMade&#39;, width: 80}, ], }, ], selectedRowKeys: [], selectedRows: [], }) const rowSelection = computed(() =&gt; { return { selectedRowKeys: tableState.selectedRowKeys, onChange: (selectedRowKeys, selectedRows) =&gt; { tableState.selectedRowKeys = selectedRowKeys tableState.selectedRows = selectedRows } } }) const onSubmit = () =&gt; { formRef.value .validate().then(() =&gt; { }) } const search = () =&gt; { const values = { orgNo: formState.orgNo, projectNo: formState.projectNo, needDate: formState.needDate ? dayjs(formState.needDate).format(&#39;YYYY-MM-DD&#39;) : &#39;&#39; } loading.value = true server.projectHoldPipeline(values).then(res =&gt; { if (res.data) { dataList.value = res.data dataListOld.value = [...res.data] dataListOld.value.forEach(item =&gt; { item.pipelinelListOld = item.pipelinelList }) } loading.value = false }) } const searchFilter = () =&gt; { let holdNo = searchHoldNo.value let state = searchState.value let oldList = dataListOld.value let list = [...oldList] if (holdNo) { list = list.filter(item =&gt; item.holdNo.includes(holdNo)) } if (state === 2) { list = list.filter(item =&gt; { item.pipelinelList = item.pipelinelList.filter(p =&gt; { const rate = parseInt(p.sequencePipeCanBeMade.replace(&#39;%&#39;, &#39;&#39;)) return rate &gt; filterNum.value }) return item.pipelinelList.length &gt; 0 }) } else if (state === 3) { list = list.filter(item =&gt; { if (item.sequencePipeCanBeMade.includes(&#39;100&#39;)) return true item.pipelinelList = item.pipelinelList.filter(p =&gt; p.canDoAll) return item.pipelinelList.length &gt; 0 }) } dataList.value = list } const exportData = () =&gt; { const ws = XLSX.utils.aoa_to_sheet([[&#39;数据&#39;]]) const wb = XLSX.utils.book_new() XLSX.utils.book_append_sheet(wb, ws, &#39;Sheet1&#39;) XLSX.writeFile(wb, &#39;管线齐套排产导出.xlsx&#39;) } const detail = (record, type) =&gt; { // 排产详情逻辑 } &lt;/script&gt; 点击c-table里面的每一行时,展开所属的数据:pipelineList(是一个数据)和主列表的字段一样 c-table代码:&lt;template&gt; &lt;div class=&quot;c-table-wrap&quot;&gt; &lt;c-toolbar :toolbar=&quot;toolbar&quot; @toolbar-button-click=&quot;onToolbarClick&quot;&gt;&lt;/c-toolbar&gt; &lt;c-table-main v-bind=&quot;$attrs&quot; :customType=&quot;customType&quot; ref=&quot;tableRef&quot; @change=&quot;onTableChange&quot;&gt; &lt;!-- 通过便利实现插槽透传 --&gt; &lt;template v-for=&quot;(item, key, slotIndex) in $slots&quot; :key=&quot;slotIndex&quot; v-slot:[key]=&quot;{ record, index, column }&quot; &gt; &lt;slot :name=&quot;key&quot; v-bind=&quot;{ key: key, index: index, record: record, column: column }&quot; :onEdit=&quot;() =&gt; onEdit(column, record)&quot; &gt;&lt;/slot&gt; &lt;/template&gt; &lt;/c-table-main&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; import { defineComponent, provide, ref, h } from &#39;vue&#39; import CTableMain from &#39;./CTableMain.vue&#39; import CToolbar from &#39;./CToolbar.vue&#39; import { useProjectDropList } from &#39;@packages/hooks/useProjectDropList&#39; import { useCompanyDropList } from &#39;@packages/hooks/useCompanyDropList&#39; import { useCooperantDropList } from &#39;@packages/hooks/useCooperantDropList&#39; import { useBuildCaseDropList } from &#39;@packages/hooks/useBuildCaseDropList&#39; import { useOrganizationDropList } from &#39;@packages/hooks/useOrganizationDropList&#39; import { useMajorDropList } from &#39;@packages/hooks/useMajorDropList&#39; import { useTechMajorDropList } from &#39;@packages/hooks/useTechMajorDropList&#39; import CEmployeeDescription from &#39;@packages/components/CEmployeeDescription/CEmployeeDescription.vue&#39; import CUserInput from &#39;@packages/components/CUserInput/CUserInput.vue&#39; import CProjectSelect from &#39;@packages/components/CProjectSelect/CProjectSelect.vue&#39; import CCompanySelect from &#39;@packages/components/CCompanySelect/CCompanySelect.vue&#39; import CCooperantSelect from &#39;@packages/components/CCooperantSelect/CCooperantSelect.vue&#39; import CBuildCaseSelect from &#39;@packages/components/CBuildCaseSelect/CBuildCaseSelect.vue&#39; import COrganizationSelect from &#39;@packages/components/COrganizationSelect/COrganizationSelect.vue&#39; import CMajorSelect from &#39;@packages/components/CMajorSelect/CMajorSelect.vue&#39; import CTechMajorSelect from &#39;@packages/components/CTechMajorSelect/CTechMajorSelect.vue&#39; class ProjectCellRender { constructor(column) { this.column = column this.projects = [] this.ajaxReq = undefined } async getProjects(column, _this) { if (_this.projects.length &gt; 0) { return _this.projects } const props = column.options || {} const { getProjectList } = useProjectDropList() this.ajaxReq = this.ajaxReq || getProjectList(props.parameter) const response = await this.ajaxReq _this.projects = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : `${item.projId}`, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.projNo } ) return _this.projects } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const projects = await _this.getProjects(column, _this) const item = projects.find((x) =&gt; x.value == text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CProjectSelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, allowCustom: false, fieldNames: fieldNames, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (projectValue, projectOrigin) =&gt; { restOptions?.onChange?.(projectOrigin, record) record[column.dataIndex] = projectValue record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true // 配置 // column.customCell = (recordCell, rowIndex, columnCell) =&gt; { // if (recordCell.id === record.id) { // return { // style: { // &#39;background-color&#39;: &#39;rgb(255,150,150)&#39; // } // } // } // } } }) } } class EmployeeCellRender { constructor(column) { this.column = column } displayRender({ text, record }, column) { let displayValue let displayLabel if (Object.prototype.toString.call(text) === &#39;[object Object]&#39;) { displayValue = text.code displayLabel = text.name } else { const displayProperty = column.options &amp;&amp; column.options.fieldNames displayValue = (displayProperty &amp;&amp; record[displayProperty.value]) || &#39;&#39; displayLabel = displayProperty &amp;&amp; record[displayProperty.label] } return h( CEmployeeDescription, { rowKey: displayValue || text, rowName: displayLabel }, { default: () =&gt; h(&#39;span&#39;, displayLabel ? `${displayLabel} (${displayValue})` : text) } ) } editorRender({ text, record }, column, data, _this) { const { fieldNames, ...restOptions } = column.options || {} let userValue // eslint-disable-next-line no-unused-vars if (Object.prototype.toString.call(text) === &#39;[object Object]&#39;) { userValue = { label: text.name || text.label, value: text.code || text.value } } else { userValue = record[column.dataIndex] || { label: record[fieldNames.label], value: record[fieldNames.value] } } return h(CUserInput, { value: userValue, size: &#39;small&#39;, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (user) =&gt; { restOptions?.onChange?.(user, record) //修改当前行的组装数据及原数据 record[column.dataIndex] = user //displayRender 使用下面值 record[fieldNames.label] = user.label record[fieldNames.value] = user.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class UsersCellRender { constructor(column) { this.column = column } displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { return text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames = {}, ...restOptions } = column.options || {} //源数据,后端接口返回的多个用户字段 const { dataIndex, label, value } = fieldNames const userValues = record[dataIndex]?.map((user) =&gt; ({ label: user[label], value: user[value] })) || [] return h(CUserInput, { value: userValues, size: &#39;small&#39;, mode: &#39;multiple&#39;, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (users) =&gt; { restOptions?.onChange?.(users, record) //修改当前行的组装数据及原数据 record[column.dataIndex] = users record[dataIndex] = users.map((user) =&gt; ({ [label]: user.label, [value]: user.value })) record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class CompanyCellRender { constructor(column) { this.column = column this.companys = [] this.ajaxReq = undefined } async getCompanys(column, _this) { if (_this.companys.length &gt; 0) { return _this.companys } const props = column.options || {} const { getCompanyList } = useCompanyDropList() this.ajaxReq = this.ajaxReq || getCompanyList(props.parameter) const response = await this.ajaxReq _this.companys = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : `${item.name}`, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.code } ) return _this.companys } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const companys = await _this.getCompanys(column, _this) const item = companys.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CCompanySelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (project) =&gt; { restOptions?.onChange?.(project, record) record[column.dataIndex] = project.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class CooperantCellRender { constructor(column) { this.column = column this.cooperants = [] this.ajaxReq = undefined } async getCooperants(column, _this) { if (_this.cooperants.length &gt; 0) { return _this.cooperants } const props = column.options || {} const { getCooperantList } = useCooperantDropList() this.ajaxReq = this.ajaxReq || getCooperantList(props.parameter) const response = await this.ajaxReq _this.cooperants = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : `${item.shortName}`, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.no } ) return _this.cooperants } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const cooperants = await _this.getCooperants(column, _this) const item = cooperants.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CCooperantSelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (project) =&gt; { restOptions?.onChange?.(project, record) record[column.dataIndex] = project.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class BuildCaseCellRender { constructor(column) { this.column = column this.buildCases = [] this.ajaxReq = undefined } async getBuildCases(column, _this) { if (_this.buildCases.length &gt; 0) { return _this.buildCases } const props = column.options || {} const { getBuildCaseList } = useBuildCaseDropList() this.ajaxReq = this.ajaxReq || getBuildCaseList(props.parameter) const response = await this.ajaxReq _this.buildCases = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : item.name, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.orgNo } ) return _this.buildCases } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const buildCases = await _this.getBuildCases(column, _this) const item = buildCases.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CBuildCaseSelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, allowCustom: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (buildCase) =&gt; { restOptions?.onChange?.(buildCase, record) record[column.dataIndex] = buildCase.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class MajorCellRender { constructor(column) { this.column = column this.majors = [] this.ajaxReq = undefined } async getMajors(column, _this) { if (_this.majors.length &gt; 0) { return _this.majors } const props = column.options || {} const { getMajorList } = useMajorDropList() this.ajaxReq = this.ajaxReq || getMajorList(props.parameter) const response = await this.ajaxReq _this.majors = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : item.name, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.id } ) return _this.majors } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const majors = await _this.getMajors(column, _this) const item = majors.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CMajorSelect, { value: text, size: &#39;small&#39;, allowClear: true, allowCustom: false, showSearch: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (major) =&gt; { restOptions?.onChange?.(major, record) record[column.dataIndex] = major.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class TechMajorCellRender { constructor(column) { this.column = column this.techMajors = [] this.ajaxReq = undefined } async getTechMajors(column, _this) { if (_this.techMajors.length &gt; 0) { return _this.techMajors } const props = column.options || {} const { getTechMajorList } = useTechMajorDropList() this.ajaxReq = this.ajaxReq || getTechMajorList(props.parameter) const response = await this.ajaxReq _this.techMajors = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : item.name, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.id } ) return _this.techMajors } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const techMajors = await _this.getTechMajors(column, _this) const item = techMajors.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CTechMajorSelect, { value: text, size: &#39;small&#39;, allowClear: true, allowCustom: false, showSearch: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (techMajor) =&gt; { restOptions?.onChange?.(techMajor, record) record[column.dataIndex] = techMajor.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class OrganizationCellRender { constructor(column) { this.column = column this.organizations = [] this.ajaxReq = undefined } async getOrganizations(column, _this) { if (_this.organizations.length &gt; 0) { return _this.organizations } const props = column.options || {} const { getOrganizationList } = useOrganizationDropList() this.ajaxReq = this.ajaxReq || getOrganizationList(props.parameter) const response = await this.ajaxReq _this.organizations = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : item.name, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.id } ) return _this.organizations } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const organizations = await _this.getOrganizations(column, _this) const item = organizations.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(COrganizationSelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, fieldNames: fieldNames, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (orgValue, orgOrigin) =&gt; { restOptions?.onChange?.(orgOrigin, record) record[column.dataIndex] = orgValue record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } export default defineComponent({ name: &#39;CTable&#39;, components: { CTableMain, CToolbar }, props: { toolbar: { type: [Object, Boolean], default: () =&gt; ({ buttons: [] }) } }, emits: [&#39;toolbar-button-click&#39;, &#39;change&#39;], setup(props, { attrs, emit }) { provide(&#39;__crud_columns&#39;, attrs.columns) const tableRef = ref(null) const customType = { project: ProjectCellRender, employeeDescription: EmployeeCellRender, user: EmployeeCellRender, users: UsersCellRender, company: CompanyCellRender, cooperant: CooperantCellRender, buildCase: BuildCaseCellRender, organization: OrganizationCellRender, major: MajorCellRender, techMajor: TechMajorCellRender } const onToolbarClick = (value) =&gt; { //默认处理save delete事件 tableRef.value.commitProxy(value.code) emit(&#39;toolbar-button-click&#39;, value) } const onTableChange = (...arg) =&gt; { emit(&#39;change&#39;, ...arg) } //监听插槽的变化,记录修改项 const onEdit = (column, record) =&gt; { column.isEdit = true record.isEdit = true } return { tableRef, customType, onEdit, onTableChange, getTable: () =&gt; tableRef.value, onToolbarClick } } }) &lt;/script&gt;
最新发布
10-10
&lt;c-search-panel :columns=&ldquo;tableState.columns.concat(extraColumns)&rdquo; @search=&ldquo;onSearch&rdquo; &gt; &lt;c-table :columns=&ldquo;tableState.columns&rdquo; :toolbar=&ldquo;tableState.toolbar&rdquo; :sortConfig=&ldquo;{ showIcon: false }&rdquo; :proxy-config=&ldquo;tableState.proxyConfig&rdquo; @toolbar-button-click=&ldquo;onToolbarClick&rdquo; :pagination=&ldquo;tableState.pagination&rdquo; :row-selection=&ldquo;rowSelection&rdquo; ref=&ldquo;tableRef&rdquo; &gt; &lt;template #action=&ldquo;{ record }&rdquo;&gt; &lt;a-button type=&ldquo;link&rdquo; @click=&ldquo;editWorkSpace(record)&rdquo; v-resource=&ldquo;[{ url: &lsquo;/service-piping/cp/production/lineWorkSpace&rsquo;, method: &lsquo;POST&rsquo; }]&rdquo; &gt; 分配工位 &lt;a-button type=&ldquo;link&rdquo; @click=&ldquo;setAssyGroupRule(record)&rdquo; v-resource=&ldquo;[{ url: &lsquo;/service-piping/cp/production/updateAssyGroupRule&rsquo;, method: &lsquo;POST&rsquo; }]&rdquo; &gt; 设置组立规则 &lt;a-button type=&ldquo;primary&rdquo; style=&ldquo;margin-right: 10px&rdquo; @click=&ldquo;addWorkSpace&rdquo; :icon=&ldquo;h(PlusOutlined)&rdquo; v-resource=&ldquo;[{ url: &lsquo;/service-piping/cp/production/lineWorkSpace&rsquo;, method: &lsquo;POST&rsquo; }]&rdquo; &gt;新增 &lt;a-button type=&ldquo;primary&rdquo; style=&ldquo;margin-right: 10px&rdquo; @click=&ldquo;saveWorkSpace&rdquo; :icon=&ldquo;h(SaveOutlined)&rdquo; v-resource=&ldquo;[{ url: &lsquo;/service-piping/cp/production/lineWorkSpace&rsquo;, method: &lsquo;POST&rsquo; }]&rdquo; &gt;保存 &lt;a-button type=&ldquo;primary&rdquo; danger @click=&ldquo;deleteWorkSpace&rdquo; :icon=&ldquo;h(DeleteOutlined)&rdquo; v-resource=&ldquo;[ { url: &lsquo;/service-piping/cp/production/lineWorkSpace/delete&rsquo;, method: &lsquo;POST&rsquo; } ]&rdquo; &gt;删除 &lt;template #workSpaceText=&ldquo;{ record }&rdquo;&gt; {{ record.workSpaceNo }} &lt;template #workSpace=&ldquo;{ record }&rdquo;&gt; &lt;a-select showSearch allow-clear v-model:value=&ldquo;record.workSpaceNo&rdquo; @change=&ldquo;changeWorkSpace($event, record)&rdquo;&gt; {{ item.workSpaceNo }} &lt;c-modal :title=&ldquo;&lsquo;设置组立拆分规则&rsquo;&rdquo; v-model:open=&ldquo;assyGroupRuleVisible&rdquo; destroyOnClose @ok=&ldquo;handleAssyGroupRuleOk&rdquo; @cancel=&ldquo;handleAssyGroupRuleCancel&rdquo; width=&ldquo;40%&rdquo; &gt; import * as server from &ldquo;@/packages/piping/api/basic/index&rdquo; import {computed, createVNode, h, reactive, ref} from &ldquo;vue&rdquo; import {message, Modal} from &ldquo;ant-design-vue&rdquo; import {DeleteOutlined, ExclamationCircleOutlined, PlusOutlined, SaveOutlined} from &ldquo;@ant-design/icons-vue&rdquo;; const tableState = reactive({ toolbar: { buttons: [ { code: &ldquo;insertInline&rdquo;, status: &lsquo;primary&rsquo;, icon: &lsquo;PlusOutlined&rsquo;, name: &ldquo;新增&rdquo; }, { code: &ldquo;saveData&rdquo;, status: &lsquo;primary&rsquo;, icon: &lsquo;SaveOutlined&rsquo;, name: &ldquo;保存&rdquo; }, { code: &ldquo;switchStatus&rdquo;, name: &ldquo;启用/禁用&rdquo; } ], showFilter: false }, selectedRowKeys: [], selectedRows: [], pagination: {pageSize: 20}, proxyConfig: { autoLoad: false, ajax: { query: async (pagination) =&gt; { const response = await server.productionLinePage({&hellip;pagination, &hellip;conditionData.value}) response.data.content.forEach((record) =&gt; { if (record.matDefinition) { record.matDefinitionText = record.matDefinition record.matDefinition = record.matDefinition.split(&ldquo;,&rdquo;) } }) return response } } }, columns: [ { title: &ldquo;产线名称&rdquo;, dataIndex: &ldquo;productionLineName&rdquo;, width: 80, condition: true, editable: true, rules: [{required: true, message: &ldquo;必填项!&rdquo;}] }, { title: &ldquo;基地&rdquo;, dataIndex: &ldquo;orgNo&rdquo;, condition: true, editable: true, rules: [{required: true, message: &ldquo;必填项!&rdquo;}], width: 80, type: &ldquo;buildCase&rdquo;, }, { title: &ldquo;材质&rdquo;, dataIndex: &ldquo;matDefinition&rdquo;, type: &ldquo;select&rdquo;, editable: true, width: 70, formatter: ({row}) =&gt; row.matDefinitionText, options: { mode: &ldquo;multiple&rdquo;, options: [], fieldNames: {label: &ldquo;matDefinitionCn&rdquo;, value: &ldquo;matDefinitionCn&rdquo;}, ajax: server.matDefinitionDropList().then((res) =&gt; { return res; }), }, rules: [{required: true, message: &ldquo;必填项!&rdquo;}] }, { title: &ldquo;最大管径&rdquo;, dataIndex: &ldquo;maxPipeDia&rdquo;, width: 80, condition: true, editable: true, rules: [{required: true, message: &ldquo;必填项!&rdquo;}] }, { title: &ldquo;最小管径&rdquo;, dataIndex: &ldquo;minPipeDia&rdquo;, width: 80, condition: true, editable: true, rules: [{required: true, message: &ldquo;必填项!&rdquo;}] }, { title: &ldquo;最大长度&rdquo;, dataIndex: &ldquo;maxLength&rdquo;, width: 80, condition: true, editable: true, rules: [{required: true, message: &ldquo;必填项!&rdquo;}] }, { title: &ldquo;最小长度&rdquo;, dataIndex: &ldquo;minLength&rdquo;, width: 80, condition: true, editable: true, rules: [{required: true, message: &ldquo;必填项!&rdquo;}] }, { dataIndex: &ldquo;status&rdquo;, title: &ldquo;启用&rdquo;, type: &ldquo;select&rdquo;, editable: true, width: 50, decorator: {initialValue: &ldquo;Y&rdquo;}, options: { options: [ {value: &ldquo;Y&rdquo;, label: &ldquo;Y&rdquo;}, {value: &ldquo;N&rdquo;, label: &ldquo;N&rdquo;} ] }, rules: [{required: true, message: &ldquo;必填项!&rdquo;}] }, { title: &ldquo;产能&rdquo;, children: [ { title: &ldquo;下料&rdquo;, dataIndex: &ldquo;layingOffCapacity&rdquo;, width: 50 }, { title: &ldquo;一次组对产能&rdquo;, dataIndex: &ldquo;primaryPairCapacity&rdquo;, width: 60 }, { title: &ldquo;一次焊接产能&rdquo;, dataIndex: &ldquo;primaryWeldCapacity&rdquo;, align: &ldquo;center&rdquo;, width: 60 }, { title: &ldquo;成品组对产能&rdquo;, dataIndex: &ldquo;finishedPairCapacity&rdquo;, align: &ldquo;center&rdquo;, width: 60 }, { title: &ldquo;成品焊接产能&rdquo;, dataIndex: &ldquo;finishedWeldCapacity&rdquo;, align: &ldquo;center&rdquo;, width: 60 } ] }, { title: &ldquo;操作&rdquo;, key: &ldquo;action&rdquo;, scopedSlots: {customRender: &ldquo;action&rdquo;}, width: 120, fixed: &ldquo;right&rdquo;, formInvisible: true } ] }) const extraColumns = ref([ { title: &ldquo;材质&rdquo;, dataIndex: &ldquo;matDefinition&rdquo;, width: 80, condition: true } ]) const tableRef = ref(null) const ctable = computed(() =&gt; tableRef.value?.getTable()) const conditionData = ref() const productionLineId = ref(null) const workSpaceModalVisible = ref(false) const workSpaceData = ref([]) const workSpaceTableRef = ref(null) const cWorkSpaceTable = computed(() =&gt; workSpaceTableRef.value?.getTable()) const workSpaceList = ref([]) const workSpaceState = reactive({ selectedRowKeys: [], selectedRows: [], columns: [ { title: &ldquo;工位号&rdquo;, dataIndex: &ldquo;workSpaceNo&rdquo;, type: &ldquo;select&rdquo;, width: 70, condition: true, editable: true, rules: [{required: true, message: &ldquo;请选择工位&rdquo;}], scopedSlots: { customEditorRender: &ldquo;workSpace&rdquo;, customRender: &ldquo;workSpaceText&rdquo; } }, { title: &ldquo;工位类型&rdquo;, dataIndex: &ldquo;workSpaceType&rdquo;, width: 70 }, { title: &ldquo;产能&rdquo;, dataIndex: &ldquo;capacity&rdquo;, width: 60, }, { dataIndex: &ldquo;status&rdquo;, title: &ldquo;有效&rdquo;, type: &ldquo;select&rdquo;, width: 50, options: { options: [ {value: &ldquo;Y&rdquo;, label: &ldquo;Y&rdquo;}, {value: &ldquo;N&rdquo;, label: &ldquo;N&rdquo;} ] } } ] }) const formState = ref({ assyGroupRule: &ldquo;&rdquo;, }) const formRef = ref() const assyGroupRuleVisible = ref(false) const id = ref(null) //搜索 const onSearch = (values) =&gt; { conditionData.value = values ctable.value.commitProxy(&ldquo;query&rdquo;, values) } //表头按钮操作 const onToolbarClick = (target) =&gt; { switch (target.code) { case &ldquo;insertInline&rdquo;: insertInline() break case &ldquo;saveData&rdquo;: saveData() break case &ldquo;switchStatus&rdquo;: switchStatus() break default: break } } const insertInline = () =&gt; { ctable.value.insert({status: &ldquo;Y&rdquo;}) } const rowSelection = computed(() =&gt; { return { selectedRowKeys: tableState.selectedRowKeys, onChange: (selectedRowKeys, selectedRows) =&gt; { tableState.selectedRowKeys = selectedRowKeys tableState.selectedRows = selectedRows } } }) const workSpaceRowSelection = computed(() =&gt; { return { selectedRowKeys: workSpaceState.selectedRowKeys, onChange: (selectedRowKeys, selectedRows) =&gt; { workSpaceState.selectedRowKeys = selectedRowKeys workSpaceState.selectedRows = selectedRows } } }) const saveData = () =&gt; { const updateRecords = ctable.value.getUpdateRecords() if (!updateRecords || updateRecords.length == 0) return updateRecords.forEach((record) =&gt; { const matDefinition = record.matDefinition if (Array.isArray(matDefinition)) { const newMaterial = matDefinition.join(&ldquo;,&rdquo;) record.matDefinition = newMaterial } }) ctable.value.validateEditFields().then(() =&gt; { server.productionLineSave(updateRecords).then(() =&gt; { message.success(&ldquo;保存成功&rdquo;) ctable.value.commitProxy(&ldquo;query&rdquo;) }) }) } const switchStatus = () =&gt; { if (tableState.selectedRowKeys.length == 0) { message.error(&ldquo;请选择至少一条数据&rdquo;) return } let selectedRows = tableState.selectedRows.map((item) =&gt; { return { &hellip;item, status: item.status == &ldquo;Y&rdquo; ? &ldquo;N&rdquo; : &ldquo;Y&rdquo;, matDefinition: item.matDefinition.join(&ldquo;,&rdquo;) } }) server .productionLineSave(selectedRows) .then(() =&gt; { message.success(&ldquo;状态切换成功&rdquo;) tableState.selectedRowKeys = [] ctable.value.commitProxy(&ldquo;query&rdquo;) }) .catch(() =&gt; { message.error(&ldquo;状态切换失败&rdquo;) }) } const editWorkSpace = (record) =&gt; { workSpaceData.value = [] productionLineId.value = record.id server.getWorkSpaceList({orgNo: record.orgNo}).then((res) =&gt; { workSpaceList.value = res.data }) workSpaceState.selectedRowKeys = [] getWorkSpace(productionLineId.value) } const setAssyGroupRule = (record) =&gt; { id.value = record.id formState.value.assyGroupRule = record.assyGroupRule assyGroupRuleVisible.value = true } const getWorkSpace = (productionLineId) =&gt; { server.getProductionLineWorkSpaceList({productionLineId}).then((response) =&gt; { workSpaceData.value = response.data workSpaceModalVisible.value = true }) } const changeWorkSpace = (workSpaceNo, currentRow) =&gt; { const selectedWorkSpace = workSpaceList.value.find(item =&gt; item.workSpaceNo === workSpaceNo); currentRow.workSpaceType = selectedWorkSpace.workSpaceType currentRow.capacity = selectedWorkSpace.capacity currentRow.status = selectedWorkSpace.status } const addWorkSpace = () =&gt; { cWorkSpaceTable.value.insert({}) } const saveWorkSpace = () =&gt; { const allRecords = cWorkSpaceTable.value.getUpdateRecords() debugger if (!allRecords || allRecords.length == 0) return allRecords.forEach((record) =&gt; { record.productionLineId = productionLineId.value }) cWorkSpaceTable.value.validateEditFields().then(() =&gt; { server.productionLineWorkSpaceSave(allRecords).then(() =&gt; { message.success(&ldquo;保存成功&rdquo;) workSpaceModalVisible.value = false }) }) } const deleteWorkSpace = () =&gt; { if (workSpaceState.selectedRowKeys.length == 0) { message.error(&ldquo;请选择至少一条数据&rdquo;) return } Modal.confirm({ title: &ldquo;请确认是否要进行删除?&rdquo;, icon: createVNode(ExclamationCircleOutlined), content: &ldquo;该操作一旦执行无法撤回&rdquo;, okText: &ldquo;确认&rdquo;, okType: &ldquo;danger&rdquo;, cancelText: &ldquo;取消&rdquo;, onOk() { let selectedRows = workSpaceState.selectedRows.map((item) =&gt; { return { &hellip;item, productionLineId: productionLineId.value } }) server.productionLineWorkSpaceDelete(selectedRows).then(() =&gt; { message.success(&ldquo;删除成功&rdquo;) getWorkSpace(productionLineId.value) }) }, onCancel() { console.log(&ldquo;Cancel&rdquo;) } }) } const handleAssyGroupRuleOk = () =&gt; { formRef.value .validate().then(() =&gt; { assyGroupRuleVisible.value = false server.productionLineAssyGroupRule({ &hellip;formState.value, id: id.value }).then(() =&gt; { message.success(&ldquo;保存成功&rdquo;) ctable.value.commitProxy(&ldquo;query&rdquo;) assyGroupRuleVisible.value = false }) }) } const handleAssyGroupRuleCancel = () =&gt; { assyGroupRuleVisible.value = false ctable.value.commitProxy(&ldquo;query&rdquo;) } cWorkSpaceTable.value.getUpdateRecords()新增的时候能获取到但是编辑的时后,获取不到编辑的行 c-table代码:&lt;template&gt; &lt;div class=&quot;c-table-wrap&quot;&gt; &lt;c-toolbar :toolbar=&quot;toolbar&quot; @toolbar-button-click=&quot;onToolbarClick&quot;&gt;&lt;/c-toolbar&gt; &lt;c-table-main v-bind=&quot;$attrs&quot; :customType=&quot;customType&quot; ref=&quot;tableRef&quot; @change=&quot;onTableChange&quot;&gt; &lt;!-- 通过便利实现插槽透传 --&gt; &lt;template v-for=&quot;(item, key, slotIndex) in $slots&quot; :key=&quot;slotIndex&quot; v-slot:[key]=&quot;{ record, index, column }&quot; &gt; &lt;slot :name=&quot;key&quot; v-bind=&quot;{ key: key, index: index, record: record, column: column }&quot; :onEdit=&quot;() =&gt; onEdit(column, record)&quot; &gt;&lt;/slot&gt; &lt;/template&gt; &lt;/c-table-main&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; import { defineComponent, provide, ref, h } from &#39;vue&#39; import CTableMain from &#39;./CTableMain.vue&#39; import CToolbar from &#39;./CToolbar.vue&#39; import { useProjectDropList } from &#39;@packages/hooks/useProjectDropList&#39; import { useCompanyDropList } from &#39;@packages/hooks/useCompanyDropList&#39; import { useCooperantDropList } from &#39;@packages/hooks/useCooperantDropList&#39; import { useBuildCaseDropList } from &#39;@packages/hooks/useBuildCaseDropList&#39; import { useOrganizationDropList } from &#39;@packages/hooks/useOrganizationDropList&#39; import { useMajorDropList } from &#39;@packages/hooks/useMajorDropList&#39; import { useTechMajorDropList } from &#39;@packages/hooks/useTechMajorDropList&#39; import CEmployeeDescription from &#39;@packages/components/CEmployeeDescription/CEmployeeDescription.vue&#39; import CUserInput from &#39;@packages/components/CUserInput/CUserInput.vue&#39; import CProjectSelect from &#39;@packages/components/CProjectSelect/CProjectSelect.vue&#39; import CCompanySelect from &#39;@packages/components/CCompanySelect/CCompanySelect.vue&#39; import CCooperantSelect from &#39;@packages/components/CCooperantSelect/CCooperantSelect.vue&#39; import CBuildCaseSelect from &#39;@packages/components/CBuildCaseSelect/CBuildCaseSelect.vue&#39; import COrganizationSelect from &#39;@packages/components/COrganizationSelect/COrganizationSelect.vue&#39; import CMajorSelect from &#39;@packages/components/CMajorSelect/CMajorSelect.vue&#39; import CTechMajorSelect from &#39;@packages/components/CTechMajorSelect/CTechMajorSelect.vue&#39; class ProjectCellRender { constructor(column) { this.column = column this.projects = [] this.ajaxReq = undefined } async getProjects(column, _this) { if (_this.projects.length &gt; 0) { return _this.projects } const props = column.options || {} const { getProjectList } = useProjectDropList() this.ajaxReq = this.ajaxReq || getProjectList(props.parameter) const response = await this.ajaxReq _this.projects = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : `${item.projId}`, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.projNo } ) return _this.projects } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const projects = await _this.getProjects(column, _this) const item = projects.find((x) =&gt; x.value == text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CProjectSelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, allowCustom: false, fieldNames: fieldNames, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (projectValue, projectOrigin) =&gt; { restOptions?.onChange?.(projectOrigin, record) record[column.dataIndex] = projectValue record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true // 配置 // column.customCell = (recordCell, rowIndex, columnCell) =&gt; { // if (recordCell.id === record.id) { // return { // style: { // &#39;background-color&#39;: &#39;rgb(255,150,150)&#39; // } // } // } // } } }) } } class EmployeeCellRender { constructor(column) { this.column = column } displayRender({ text, record }, column) { let displayValue let displayLabel if (Object.prototype.toString.call(text) === &#39;[object Object]&#39;) { displayValue = text.code displayLabel = text.name } else { const displayProperty = column.options &amp;&amp; column.options.fieldNames displayValue = (displayProperty &amp;&amp; record[displayProperty.value]) || &#39;&#39; displayLabel = displayProperty &amp;&amp; record[displayProperty.label] } return h( CEmployeeDescription, { rowKey: displayValue || text, rowName: displayLabel }, { default: () =&gt; h(&#39;span&#39;, displayLabel ? `${displayLabel} (${displayValue})` : text) } ) } editorRender({ text, record }, column, data, _this) { const { fieldNames, ...restOptions } = column.options || {} let userValue // eslint-disable-next-line no-unused-vars if (Object.prototype.toString.call(text) === &#39;[object Object]&#39;) { userValue = { label: text.name || text.label, value: text.code || text.value } } else { userValue = record[column.dataIndex] || { label: record[fieldNames.label], value: record[fieldNames.value] } } return h(CUserInput, { value: userValue, size: &#39;small&#39;, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (user) =&gt; { restOptions?.onChange?.(user, record) //修改当前行的组装数据及原数据 record[column.dataIndex] = user //displayRender 使用下面值 record[fieldNames.label] = user.label record[fieldNames.value] = user.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class UsersCellRender { constructor(column) { this.column = column } displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { return text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames = {}, ...restOptions } = column.options || {} //源数据,后端接口返回的多个用户字段 const { dataIndex, label, value } = fieldNames const userValues = record[dataIndex]?.map((user) =&gt; ({ label: user[label], value: user[value] })) || [] return h(CUserInput, { value: userValues, size: &#39;small&#39;, mode: &#39;multiple&#39;, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (users) =&gt; { restOptions?.onChange?.(users, record) //修改当前行的组装数据及原数据 record[column.dataIndex] = users record[dataIndex] = users.map((user) =&gt; ({ [label]: user.label, [value]: user.value })) record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class CompanyCellRender { constructor(column) { this.column = column this.companys = [] this.ajaxReq = undefined } async getCompanys(column, _this) { if (_this.companys.length &gt; 0) { return _this.companys } const props = column.options || {} const { getCompanyList } = useCompanyDropList() this.ajaxReq = this.ajaxReq || getCompanyList(props.parameter) const response = await this.ajaxReq _this.companys = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : `${item.name}`, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.code } ) return _this.companys } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const companys = await _this.getCompanys(column, _this) const item = companys.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CCompanySelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (project) =&gt; { restOptions?.onChange?.(project, record) record[column.dataIndex] = project.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class CooperantCellRender { constructor(column) { this.column = column this.cooperants = [] this.ajaxReq = undefined } async getCooperants(column, _this) { if (_this.cooperants.length &gt; 0) { return _this.cooperants } const props = column.options || {} const { getCooperantList } = useCooperantDropList() this.ajaxReq = this.ajaxReq || getCooperantList(props.parameter) const response = await this.ajaxReq _this.cooperants = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : `${item.shortName}`, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.no } ) return _this.cooperants } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const cooperants = await _this.getCooperants(column, _this) const item = cooperants.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CCooperantSelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (project) =&gt; { restOptions?.onChange?.(project, record) record[column.dataIndex] = project.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class BuildCaseCellRender { constructor(column) { this.column = column this.buildCases = [] this.ajaxReq = undefined } async getBuildCases(column, _this) { if (_this.buildCases.length &gt; 0) { return _this.buildCases } const props = column.options || {} const { getBuildCaseList } = useBuildCaseDropList() this.ajaxReq = this.ajaxReq || getBuildCaseList(props.parameter) const response = await this.ajaxReq _this.buildCases = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : item.name, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.orgNo } ) return _this.buildCases } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const buildCases = await _this.getBuildCases(column, _this) const item = buildCases.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CBuildCaseSelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, allowCustom: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (buildCase) =&gt; { restOptions?.onChange?.(buildCase, record) record[column.dataIndex] = buildCase.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class MajorCellRender { constructor(column) { this.column = column this.majors = [] this.ajaxReq = undefined } async getMajors(column, _this) { if (_this.majors.length &gt; 0) { return _this.majors } const props = column.options || {} const { getMajorList } = useMajorDropList() this.ajaxReq = this.ajaxReq || getMajorList(props.parameter) const response = await this.ajaxReq _this.majors = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : item.name, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.id } ) return _this.majors } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const majors = await _this.getMajors(column, _this) const item = majors.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CMajorSelect, { value: text, size: &#39;small&#39;, allowClear: true, allowCustom: false, showSearch: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (major) =&gt; { restOptions?.onChange?.(major, record) record[column.dataIndex] = major.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class TechMajorCellRender { constructor(column) { this.column = column this.techMajors = [] this.ajaxReq = undefined } async getTechMajors(column, _this) { if (_this.techMajors.length &gt; 0) { return _this.techMajors } const props = column.options || {} const { getTechMajorList } = useTechMajorDropList() this.ajaxReq = this.ajaxReq || getTechMajorList(props.parameter) const response = await this.ajaxReq _this.techMajors = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : item.name, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.id } ) return _this.techMajors } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const techMajors = await _this.getTechMajors(column, _this) const item = techMajors.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(CTechMajorSelect, { value: text, size: &#39;small&#39;, allowClear: true, allowCustom: false, showSearch: false, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (techMajor) =&gt; { restOptions?.onChange?.(techMajor, record) record[column.dataIndex] = techMajor.value record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } class OrganizationCellRender { constructor(column) { this.column = column this.organizations = [] this.ajaxReq = undefined } async getOrganizations(column, _this) { if (_this.organizations.length &gt; 0) { return _this.organizations } const props = column.options || {} const { getOrganizationList } = useOrganizationDropList() this.ajaxReq = this.ajaxReq || getOrganizationList(props.parameter) const response = await this.ajaxReq _this.organizations = response.map((item) =&gt; props.fieldNames &amp;&amp; props.fieldNames instanceof Function ? props.fieldNames(item) : { label: props?.fieldNames?.label ? item[props.fieldNames.label] : item.name, value: props?.fieldNames?.value ? item[props.fieldNames.value] : item.id } ) return _this.organizations } async displayRender(args, column, data, _this) { const { text } = args if (column.formatter &amp;&amp; column.formatter instanceof Function) { return column.formatter({ ...args, cellValue: args.text, row: args.record }) } else { const organizations = await _this.getOrganizations(column, _this) const item = organizations.find((x) =&gt; x.value === text) return item ? item.label : text } } editorRender({ text, record }, column, data, _this) { // eslint-disable-next-line no-unused-vars const { fieldNames, ...restOptions } = column.options || {} return h(COrganizationSelect, { value: text, size: &#39;small&#39;, allowClear: true, showSearch: false, fieldNames: fieldNames, customStyle: column.customStyle || { width: &#39;100px&#39; }, filterOption: (input, option) =&gt; { return ( option &amp;&amp; option.label &amp;&amp; option.label.toLowerCase().indexOf(input.toLowerCase()) &gt;= 0 ) }, ...restOptions, onChange: (orgValue, orgOrigin) =&gt; { restOptions?.onChange?.(orgOrigin, record) record[column.dataIndex] = orgValue record[&#39;isEdit&#39;] = true column[&#39;isEdit&#39;] = true } }) } } export default defineComponent({ name: &#39;CTable&#39;, components: { CTableMain, CToolbar }, props: { toolbar: { type: [Object, Boolean], default: () =&gt; ({ buttons: [] }) } }, emits: [&#39;toolbar-button-click&#39;, &#39;change&#39;], setup(props, { attrs, emit }) { provide(&#39;__crud_columns&#39;, attrs.columns) const tableRef = ref(null) const customType = { project: ProjectCellRender, employeeDescription: EmployeeCellRender, user: EmployeeCellRender, users: UsersCellRender, company: CompanyCellRender, cooperant: CooperantCellRender, buildCase: BuildCaseCellRender, organization: OrganizationCellRender, major: MajorCellRender, techMajor: TechMajorCellRender } const onToolbarClick = (value) =&gt; { //默认处理save delete事件 tableRef.value.commitProxy(value.code) emit(&#39;toolbar-button-click&#39;, value) } const onTableChange = (...arg) =&gt; { emit(&#39;change&#39;, ...arg) } //监听插槽的变化,记录修改项 const onEdit = (column, record) =&gt; { column.isEdit = true record.isEdit = true } return { tableRef, customType, onEdit, onTableChange, getTable: () =&gt; tableRef.value, onToolbarClick } } }) &lt;/script&gt;
09-12
&lt;!-- * @功能描述 客户端绑定密钥列表 --&gt; &lt;script setup&gt; import { Message } from &#39;@plmcsdk/common-ui&#39;; import { ref, getCurrentInstance, watch, computed } from &#39;vue&#39;; import { useI18n } from &#39;vue-i18n&#39;; import { useRoute } from &#39;vue-router&#39;; import AddKeyDialog from &#39;./AddKeyDialog.vue&#39;; import CommonTable from &#39;@/components/common-table/CommonTable.vue&#39;; import UEButton from &#39;@/components/user-experience-components/UEButton.vue&#39;; import { useHsmTypeList, signSchemaList } from &#39;@/constants&#39;; import useProcessStore from &#39;@/store/modules/process&#39;; import { reConfirm } from &#39;@/utils&#39;; const { hsmTypeList } = useHsmTypeList(); const route = useRoute(); const props = defineProps({ tableList: Array, isEdit: Boolean, isShowGroup: Boolean, // 展示群组 }); const { t } = useI18n(); const columnList = computed(() =&gt; { const initColumns = [ { label: t(&#39;process.type&#39;), key: &#39;type&#39;, prop: &#39;type&#39;, width: 200, check: true, contentSlotName: &#39;typeSlot&#39;, hidden: !(isChangeFlow.value || props.isShowGroup), }, { label: t(&#39;bgManagement.bgName&#39;), key: &#39;bgName&#39;, prop: &#39;bgName&#39;, check: true, }, { label: t(&#39;buManagement.buName&#39;), key: &#39;buName&#39;, prop: &#39;buName&#39;, check: true, }, { label: t(&#39;common.signStandard&#39;), key: &#39;signType&#39;, prop: &#39;signType&#39;, check: true, contentSlotName: &#39;signTypeSlot&#39;, }, { label: t(&#39;common.signatureKey&#39;), key: &#39;certAlias&#39;, prop: &#39;certAlias&#39;, check: true, }, { label: t(&#39;process.keyUsage&#39;), key: &#39;keyUsage&#39;, prop: &#39;keyUsage&#39;, check: true, }, { label: t(&#39;common.keyExpDate&#39;), key: &#39;expDate&#39;, prop: &#39;expDate&#39;, check: true, }, { label: t(&#39;common.encryptorType&#39;), key: &#39;hsmType&#39;, prop: &#39;hsmType&#39;, check: true, contentSlotName: &#39;hsmTypeSlot&#39;, }, { key: &#39;operation&#39;, prop: &#39;operation&#39;, width: &#39;80&#39;, label: t(&#39;common.opt&#39;), contentSlotName: &#39;operationContentSlot&#39;, check: true, hidden: !(props.isEdit &amp;&amp; (isChangeFlow.value || props.isShowGroup)), // 更新编辑或者注册构建编辑时 }, ]; if (props.isShowGroup) { // 在签名密钥后面增加群组展示 const index = initColumns.findIndex(item =&gt; item.prop === &#39;certAlias&#39;); initColumns.splice(index + 1, 0, { label: t(&#39;process.cloudGroup&#39;), key: &#39;groupName&#39;, prop: &#39;groupName&#39;, contentSlotName: &#39;groupName&#39;, check: true, }); } return initColumns; }); const baseConfig = computed(() =&gt; { return { showPage: false, showSeq: true, showSelection: props.isEdit, }; }); const isChangeFlow = computed(() =&gt; { return route.fullPath.includes(&#39;clientChange&#39;); }); const data = ref([]); const showDialog = ref(false); const { proxy } = getCurrentInstance(); // bu下拉选项 const buList = ref([]); const selectData = ref([]); const refTable = ref(null); const fillTable = val =&gt; { data.value = [...val]; }; watch( () =&gt; props.tableList, val =&gt; { fillTable(val); }, { immediate: true, deep: true, } ); function validator() { return data.value.length; } // 将基础信息传递过来的产品线进行记录 const curProductLine = computed(() =&gt; { return useProcessStore().productLineCode; }); // 添加 function handleAdd() { if (!curProductLine.value) { Message.error(t(&#39;process.notSelectProductLineMsg&#39;)); return; } showDialog.value = true; } // 删除 function handleDelete() { reConfirm({ content: t(&#39;process.deleteKeyTip&#39;) }).then(() =&gt; { const list = [...data.value]; if (isChangeFlow.value || props.isShowGroup) { const selAddList = selectData.value.filter(item =&gt; item.isDeleted === &#39;2&#39;); const selOldList = selectData.value.filter(item =&gt; item.isDeleted !== &#39;2&#39;); const list2 = list.map(item =&gt; { const sel = selOldList.find( selData =&gt; item.buId === selData.buId &amp;&amp; item.certAlias === selData.certAlias &amp;&amp; item.bgName === selData.bgName &amp;&amp; item.groupId === selData.groupId &amp;&amp; selData.isDeleted === &#39;0&#39; ); if (sel) { return { ...item, isDeleted: &#39;1&#39;, }; } else { return item; } }); data.value = list2.filter(item =&gt; { return !selAddList.some( selData =&gt; item.buId === selData.buId &amp;&amp; item.certAlias === selData.certAlias &amp;&amp; item.bgName === selData.bgName &amp;&amp; item.groupId === selData.groupId ); }); } else { data.value = list.filter(item =&gt; { return !selectData.value.some(selData =&gt; item.buId === selData.buId &amp;&amp; item.certAlias === selData.certAlias &amp;&amp; item.bgName === selData.bgName); }); } refTable.value.elTableRef.$el.clearSelection(); proxy.$bus.$emit(&#39;applyCertList&#39;, data.value); }); } /** * 更新表格数据 * @param key 添加的密钥信息 */ const updateList = key =&gt; { const updateData = itemKey =&gt; { if (isChangeFlow.value || props.isShowGroup) { data.value.push({ ...itemKey, isDeleted: &#39;2&#39; }); proxy.$bus.$emit(&#39;applyCertList&#39;, data.value); } else { data.value.push(key); } }; // groupId修改为多选,需要将多选构建为多条数据 const copyKey = { ...key }; if (key?.groupName?.length) { key.groupName.forEach(item =&gt; { copyKey.groupId = item.id; copyKey.groupName = item.name; updateData(copyKey); }); } else { updateData(key); } refTable.value.elTableRef.$el.clearSelection(); }; const handleTableSelect = val =&gt; { selectData.value = val; }; const cellClassName = ({ row, column }) =&gt; { if (row.isDeleted === &#39;1&#39; &amp;&amp; column.property !== &#39;operation&#39;) { return &#39;client-change-del-cell&#39;; } if (row.isDeleted === &#39;2&#39;) { return &#39;client-change-add-cell&#39;; } return &#39;&#39;; }; const rollback = row =&gt; { row.isDeleted = &#39;0&#39;; }; defineExpose({ validator, data, }); &lt;/script&gt; &lt;template&gt; &lt;div&gt; &lt;ElCollapse model-value=&quot;applicationInstructions&quot; class=&quot;over-hide p-0-20 bt-line&quot;&gt; &lt;ElCollapseItem :title=&quot;$t(&#39;process.clientKeyTableTitle&#39;)&quot; name=&quot;applicationInstructions&quot;&gt; &lt;div v-if=&quot;isEdit&quot; class=&quot;button-group mb-12&quot;&gt; &lt;UEButton type=&quot;primary&quot; @click=&quot;handleAdd&quot;&gt;{{ $t(&#39;common.add&#39;) }}&lt;/UEButton&gt; &lt;ElTooltip :content=&quot;selectData.length === 0 ? $t(&#39;common.selectDataTip&#39;) : &#39;&#39;&quot; placement=&quot;top&quot;&gt; &lt;UEButton :disabled=&quot;selectData.length === 0&quot; @click=&quot;handleDelete&quot;&gt;{{ $t(&#39;common.del&#39;) }}&lt;/UEButton&gt; &lt;/ElTooltip&gt; &lt;/div&gt; &lt;div style=&quot;height: 200px; margin-bottom: var(--ue-element-spacing)&quot;&gt; &lt;CommonTable ref=&quot;refTable&quot; :height=&quot;&#39;100%&#39;&quot; :cell-class-name=&quot;cellClassName&quot; :base-config=&quot;baseConfig&quot; :data=&quot;data&quot; :column-list=&quot;columnList&quot; no-scroll-x @select=&quot;handleTableSelect&quot; &gt; &lt;template #groupName=&quot;scope&quot;&gt; &lt;span&gt;{{ `${scope.row.groupName} | ${scope.row.groupId}` }}&lt;/span&gt; &lt;/template&gt; &lt;template #typeSlot=&quot;scope&quot;&gt; &lt;span v-if=&quot;scope.row.isDeleted === &#39;0&#39;&quot;&gt;{{ $t(&#39;common.alreadyHave&#39;) }}&lt;/span&gt; &lt;span v-if=&quot;scope.row.isDeleted === &#39;1&#39;&quot;&gt;{{ $t(&#39;common.removed&#39;) }}&lt;/span&gt; &lt;span v-if=&quot;scope.row.isDeleted === &#39;2&#39;&quot;&gt;{{ $t(&#39;common.newAdd&#39;) }}&lt;/span&gt; &lt;/template&gt; &lt;template #signTypeSlot=&quot;scope&quot;&gt; &lt;span&gt;{{ signSchemaList.find(item =&gt; item.value === scope.row.signType)?.name }}&lt;/span&gt; &lt;/template&gt; &lt;template #hsmTypeSlot=&quot;scope&quot;&gt; &lt;span&gt;{{ hsmTypeList.find(item =&gt; item.value === scope.row.hsmType)?.name }}&lt;/span&gt; &lt;/template&gt; &lt;template #operationContentSlot=&quot;scope&quot;&gt; &lt;i v-if=&quot;scope.row.isDeleted === &#39;1&#39;&quot; :title=&quot;$t(&#39;process.undoDelete&#39;)&quot; class=&quot;ipd-font-icon icon-revoke&quot; @click=&quot;rollback(scope.row)&quot;&gt;&lt;/i&gt; &lt;/template&gt; &lt;/CommonTable&gt; &lt;/div&gt; &lt;!-- 添加密钥弹窗 --&gt; &lt;AddKeyDialog v-if=&quot;showDialog&quot; v-model=&quot;showDialog&quot; :product-line-code=&quot;curProductLine&quot; :key-list=&quot;data&quot; :is-show-group=&quot;isShowGroup&quot; @update-key-list=&quot;updateList&quot; /&gt; &lt;/ElCollapseItem&gt; &lt;/ElCollapse&gt; &lt;/div&gt; &lt;/template&gt; &lt;style lang=&quot;less&quot; scoped&gt; .ipd-font-icon { color: var(--ue-main-primary-color); } &lt;/style&gt; 这是BindKey组件的内容,结合这个组件分析刚才的问题,并且分析出appCertList对象的属性有哪些
09-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值