npm package: @junhe/common-table
Description: 要确保项目中使用的 Vue2 版本为 2.6.14，步骤如下：
Author: Billy Chen
Latest version: 1.0.27

# 使用前准备

要确保项目中使用的 Vue2 版本为 2.6.14，步骤如下：

* 在 package.json 中：

  * "vue": "^2.6.14" 改为 "vue": "2.6.14",

  * "vue-template-compiler": "^2.6.14" 改为 "vue-template-compiler": "2.6.14"

* 然后删除项目中的 node_modules 和 package-lock.json

* 最后重新安装一下依赖：npm install

# 使用说明书(FlexibleTableIntegration.vue)

## 外部可以调用的方法

refreshTableRows 刷新表格内容数据

resetCurrPageAndRefreshTableRows 重置当前页码到第一页，并刷新表格内容数据

addFormRow 添加一行新的表单行

addNewRows 添加一或多行新的普通数据行

getRowMultiSelection 获取所有被多选列勾选的数据

setRowMultiSelection 设置多选列的选中状态

getRowSingleSelection 获取被单选列选中的数据

setRowSingleSelection 设置单选列的选中状态

## 对外抛出的事件

cell-click 当表格的可点击单元格被点击时

column-button-click 当表格中的图标列的单元格被点击时

cell-corner-tip-click 当表格的单元格右上角的提示性按钮被点击时

row-multi-select 当多选列的选中状态被改变时

text-search 当搜索框有改变并确认时

selection-list-change 当筛选栏的当前筛选器的筛选项被选中或取消时

## Props

| 属性名               | 解释                                                 |
|----------------------|------------------------------------------------------|
| baseURL              | 后端地址(指定本值，主要用于测试用途)                 |
| normalTabs           | 标签列表                                             |
| extraTabs            | 不显示本页内容的标签                                 |
| defaultTabIndex      | 默认显示的标签的序号                                 |
| operationWidth       | 操作按钮列的宽度                                     |
| cardWidth            | 卡片视图下卡片的宽度                                 |
| moduleName           | 模块名称(传给后端)                                   |
| hasDataOverview      | 是否有数据概览                                       |
| hasClassification    | 是否有标签栏                                         |
| defaultFilterIndex   | 默认打开第几个单列条件选择器(从0开始)                |
| hasCheckboxColumn    | 是否有多选列                                         |
| isSelectionReserved  | 换页时，是否保持之前的选择                           |
| hasDataStatistics    | 是否有统计数据                                       |
| hasExportData        | 是否有导出表格数据的功能按钮                         |
| hasOperation         | 是否有操作按钮                                       |
| hasViewSwitcher      | 是否有表格视图和卡片视图的切换功能                   |
| hasSideFilter        | 是否有侧边筛选栏                                     |
| formCellUpdateType   | 表格型单元格的更新类型                               |
| defaultView          | 默认的视图                                           |
| confirmCellSelection | 表格中的下拉框单元格的下拉列表的某一项被选中时的回调 |

## 使用方法示例
```html
<template>
  <div class="test-flexible-table">
    <div class="module-btns">
      <ElButton
        :type="moduleName === '模块1' ? 'primary' : 'default'"
        size="mini"
        @click="onModuleBtnClick(1)"
        >模块1</ElButton
      >
      <ElButton
        :type="moduleName === '模块2' ? 'primary' : 'default'"
        size="mini"
        @click="onModuleBtnClick(2)"
        >模块2</ElButton
      >
    </div>
    <div class="flexible-table-container">
      <FlexibleTableIntegration
        ref="flexibleTableIntegration"
        :baseURL="baseURL"
        :normalTabs="NORMAL_TABS"
        :extraTabs="EXTRA_TABS"
        :defaultTabIndex="DEFAULT_TAB_INDEX"
        :operationWidth="100"
        :cardWidth="300"
        :moduleName="moduleName"
        :hasDataOverview="false"
        :hasClassification="false"
        :defaultFilterIndex="2"
        :hasCheckboxColumn="isMultiSelection"
        :hasRadioColumn="!isMultiSelection"
        :isSelectionReserved="true"
        :hasExportData="true"
        :hasOperation="true"
        :hasViewSwitcher="true"
        :hasSideFilter="true"
        :defaultSideFilterVisible="true"
        :defaultView="'table'"
        :confirmCellSelection="confirmCellSelection"
        @cell-click="onBodyCellClick"
        @cell-corner-tip-click="onBodyCellCornerTipClick"
        @column-button-click="onColumnButtonClick"
        @row-multi-select="onRowMultiSelect"
      >
        <template v-slot:operation="row">
          <OperationButton
            :name="'op1'"
            :title="'操作1'"
            :row="row"
            :hasIcon="true"
            :maxTitleCount="3"
            @btn-click="onOperationBtnClick"
          >
            <!-- <template v-slot:icon>
              <IconFilter :size="12" />
            </template> -->
          </OperationButton>

          <!-- <OperationDropdown>
            <OperationDropdownItem
              :name="'op4'"
              :title="'操作4'"
              :row="row"
              :hasIcon="false"
              @item-click="onOperationBtnClick"
            ></OperationDropdownItem>
            <OperationDropdownItem
              :name="'op5'"
              :title="'操作5'"
              :row="row"
              :hasIcon="true"
              @item-click="onOperationBtnClick"
            >
              <template v-slot:icon>
                <IconFilter :size="12" />
              </template>
            </OperationDropdownItem>
            <OperationDropdownItem
              :name="'op6'"
              :title="'操作6'"
              :row="row"
              :hasIcon="true"
              @item-click="onOperationBtnClick"
            >
              <template v-slot:icon>
                <IconFilter :size="12" />
              </template>
            </OperationDropdownItem>
          </OperationDropdown> -->
        </template>

        <template v-slot:midbar>
          <ElSwitch
            :style="{ width: '132px' }"
            v-model="isMultiSelection"
            active-text="多选"
            inactive-text="单选"
          >
          </ElSwitch>
          <ElButton type="primary" size="small" @click="onGetSelectClick"
            >获取选择</ElButton
          >
          <ElButton type="primary" size="small" @click="onSetSelectClick"
            >尝试选择</ElButton
          >
        </template>
        11
        <template v-slot:card="{ row }">
          <CardTemplate
            class="my-card"
            :height="200"
            :imgSrc="'https://youimg1.c-ctrip.com/target/100r10000000pycel4E0E.jpg'"
          >
            <template v-slot:header>{{ row["type_row_id"] }}</template>
            <template v-slot:details>
              <div class="rows">
                <div class="row">
                  <span>{{ row["type_string2"] }}</span>
                </div>

                <OverflowTooltip :content="row['type_string']">
                  <div class="row">
                    <span>{{ row["type_string"] }}</span>
                  </div>
                </OverflowTooltip>

                <div class="row">
                  <span>{{ row["type_merge_str"] }}</span>
                </div>
              </div>
            </template>
          </CardTemplate>
        </template>

        <template v-slot:button-column-icon="{ iconClass, data }">
          <template v-if="iconClass === 'plus'">
            <IconAdd />
          </template>
          <template v-else-if="iconClass === 'copy'">
            <IconCopy />
          </template>
          <template v-else-if="iconClass === 'edit'">
            <IconEdit />
          </template>
          <template v-else-if="iconClass === 'comment-btn'">
            <IconComment />
          </template>
          <template v-else-if="iconClass === 'receivable-node-btn'">
            <template v-if="Array.isArray(data)">
              <template v-for="(node, index) in data">
                <IconTextCircle
                  :key="index"
                  :text="node['name']"
                  :active="node['active']"
                />
              </template>
            </template>
          </template>
          <template v-else-if="iconClass === 'alert-btn'">
            <IconAlertSign :text="'已有风险'" />
            <!-- <template v-for="(node, index) in data">
              </template> -->
          </template>
          <template v-else></template>
        </template>

        <!-- <template v-slot:cell-bottom="{ row, col }">
          <div
            class="my-progress-bar"
            v-if="col.id === 'type_number' && row['type_row_id']"
          >
            <el-progress
              :text-inside="true"
              :stroke-width="8"
              :percentage="70"
            ></el-progress>
          </div>
        </template> -->

        <!-- <template v-slot:cell-left="{ row, col }">
          <div
            class="my-tip"
            v-if="col.id === 'type_number' && row['type_row_id']"
          ></div>
        </template> -->

        <template v-slot:form-cell="{ row, col }">
          <template v-if="col.id === 'icon_col_1'">
            <div class="my-form-cell">
              <template v-if="typeof row[col.id] === 'string'">
                <div class="my-column-icon" :style="{ cursor: 'pointer' }">
                  <Icon
                    :size="24"
                    :iconBaseUrl="row[col.id]"
                    @click.native="onFormCellBtnEditClick(row, col)"
                  />
                </div>
              </template>
              <template v-else>
                <ElButton
                  type="text"
                  size="mini"
                  @click="onFormCellBtnEditClick(row, col)"
                  >自定义功能</ElButton
                >
              </template>
            </div>
          </template>
        </template>
      </FlexibleTableIntegration>
    </div>

    <ElDialog
      class="my-dial-icon-selection"
      title="提示"
      :visible.sync="isIconDialVisible"
      width="30%"
    >
      <div class="content">
        <div :style="{ marginBottom: '16px' }">在此选择头像</div>
        <div>
          <template v-for="(url, index) in iconUrls">
            <Icon
              class="user-icon"
              :style="{ cursor: 'pointer', marginRight: '16px' }"
              :key="index"
              :iconBaseUrl="url"
              @click.native="onDialIconClick(url)"
            />
          </template>
        </div>
      </div>

      <span slot="footer" class="dialog-footer">
        <el-button @click="isIconDialVisible = false">取 消</el-button>
        <el-button type="primary" @click="isIconDialVisible = false"
          >确 定</el-button
        >
      </span>
    </ElDialog>
  </div>
</template>
<script>
import Vue from "vue";
import {
  Button as ElButton,
  // Progress as ElProgress,
  Dialog as ElDialog,
  Switch as ElSwitch,
} from "element-ui";

import {
  FlexibleTableIntegration,
  CardTemplate,
  OperationButton,
  // OperationDropdown,
  // OperationDropdownItem,
  OverflowTooltip,
  Icon,
  IconAdd,
  IconCopy,
  IconEdit,
  IconComment,
  IconTextCircle,
  IconAlertSign,
  // IconFilter,
  // BaseColumn,
  // Column,
  ButtonColumn,
  // IconColumn,
  // KeyValuePair,
} from "@junhe/common-table";

const NORMAL_TABS = [
  { name: "tab-name-1", label: "标签1" },
  { name: "tab-name-2", label: "标签2" },
  { name: "tab-name-3", label: "标签3" },
];

const EXTRA_TABS = [{ name: "board", label: "看板" }];

const DEFAULT_TAB_INDEX = 0;

export default Vue.extend({
  name: "TestWithFakeData",
  components: {
    ElButton,
    // ElProgress,
    ElDialog,
    ElSwitch,
    IconAdd,
    IconCopy,
    IconEdit,
    IconComment,
    IconTextCircle,
    IconAlertSign,
    // IconFilter,
    FlexibleTableIntegration,
    CardTemplate,
    OperationButton,
    // OperationDropdown,
    // OperationDropdownItem,
    OverflowTooltip,
    Icon,
  },
  data() {
    return {
      moduleName: "模块1",
      NORMAL_TABS,
      EXTRA_TABS,
      DEFAULT_TAB_INDEX,

      baseURL: "http://220.168.85.72:10930",
      // baseURL: "http://localhost:10930",

      isIconDialVisible: false,
      iconUrls: [
        "http://220.168.85.72:3000/avatars/d73d86c441955bd24b89577835608fa3?size=512",
        "http://220.168.85.72:3000/avatars/e47e9a540465ff1cc530b46afa573c6e?size=512",
      ],
      currCellInfo: {
        row: {},
        col: {},
      },

      isMultiSelection: false, // 是显示多选列还是单选列
    };
  },
  computed: {
    iconStyle() {
      const size = 12;
      return { width: `${size}px`, height: `${size}px` };
    },
  },
  methods: {
    onModuleBtnClick(flag) {
      this.moduleName = `模块${flag}`;
    },
    // 表格操作列中的某个按钮被点击
    onOperationBtnClick(row, name) {
      console.log("row, name :>> ", row, name);
    },
    // 当表格的可点击单元格被点击时
    onBodyCellClick(row, col) {
      console.log("row, col :>> ", row, col);
    },
    // 当表格中的图标列的单元格被点击时
    onColumnButtonClick(row, col, insideBtnCol) {
      const refTb = this.$refs["flexibleTableIntegration"];

      if (col instanceof ButtonColumn) {
        // 属于独立按钮列
        switch (col.iconClass) {
          case "comment-btn": {
            // 复制一遍 row，然后添加到表格中
            const newRow = JSON.parse(JSON.stringify(row));
            newRow.id = `id-${Math.random()}`;
            newRow.type_merge_str = `${Math.floor(Math.random() * 1000)}`;
            refTb.addNewRows(row, [newRow]);
            break;
          }
          case "receivable-node-btn": {
            console.log("receivable-node-btn", row);
            break;
          }
          default:
            break;
        }
      } else {
        // 属于内置按钮列
        switch (insideBtnCol.iconClass) {
          case "plus": {
            refTb.addFormRow(row, "new", {
              submissionExceptionClassNames: ["my-dial-icon-selection"],
            });
            break;
          }
          case "copy": {
            refTb.addFormRow(row, "copy", {
              submissionExceptionClassNames: ["my-dial-icon-selection"],
            });
            break;
          }
          default:
            break;
        }
      }
    },
    // 当表格的单元格右上角的提示性按钮被点击时
    onBodyCellCornerTipClick(row, col) {
      console.log("row, col :>> ", row, col);
    },
    // 当多选列的选中状态被改变时
    onRowMultiSelect(selection) {
      console.log("selection :>> ", selection);
    },
    /**
     * 表格中的下拉框单元格 -> 下拉列表的某一项被选中时的回调
     * @param resolve resolve(true) 代表确认选择，resolve(false) 代表取消选择
     */
    confirmCellSelection(row, column, item, resolve) {
      console.log("row, column, item :>> ", row, column, item);
      setTimeout(() => {
        resolve(true);
      }, 1000);
    },
    onGetSelectClick() {
      const refTb = this.$refs["flexibleTableIntegration"];

      let selection;
      if (this.isMultiSelection) {
        selection = refTb.getRowMultiSelection();
      } else {
        selection = refTb.getRowSingleSelection();
      }

      console.log("当前选择的行 :>> ", selection);
    },
    onSetSelectClick() {
      const refTb = this.$refs["flexibleTableIntegration"];

      if (this.isMultiSelection) {
        refTb.setRowMultiSelection(["id-2", "id-3"]);
      } else {
        refTb.setRowSingleSelection("id-2");
      }
    },
    onFormCellBtnEditClick(row, col) {
      console.log("col :>> ", col);
      this.currCellInfo = { row, col };
      this.isIconDialVisible = true;
    },
    onDialIconClick(url) {
      const { row, col } = this.currCellInfo;

      if (row && col) {
        console.log("row, col :>> ", row, col);
        row[col.id] = url;
      }
    },
  },
});
</script>
<style lang="scss" scoped>
.test-flexible-table {
  width: 100%;
  height: 100%;

  $module-btns-height: 32px;

  .module-btns {
    box-sizing: border-box;
    width: 100%;
    height: $module-btns-height;
    border-bottom: 1px solid #eee;
  }

  .flexible-table-container {
    box-sizing: border-box;
    width: 100%;
    height: calc(100% - $module-btns-height);
  }

  .my-progress-bar {
    width: 100%;
  }

  .my-card {
    .rows {
      box-sizing: border-box;
      width: 100%;
      height: 100%;
      padding: 8px 0;

      .row {
        width: 100%;
        height: 28px;
        line-height: 28px;
      }
    }
  }

  .my-form-cell {
    .my-column-icon {
    }
  }

  .my-dial-icon-selection {
  }
}
</style>
```