关于vue2 antd 碰到的问题总结下

1.关于vue2 antd 视图更新问题

1.一种强制更新 

Vue2是通过用Object…defineProperty来设置数据的getter和setter实现对数据和以及视图改变的监听的。对于数组和对象这种引用类型来说,getter和setter无法检测到它们内部的变化。用这种

 this.$set(this.form, "fileUrl", urlArr.join(","));

2.如果碰到

a-form :form="form"

 form: this.$form.createForm(this),

    <a-form :form="form" @submit="handleSubmit">
        <a-form-item
          :labelCol="labelCol"
          :wrapperCol="wrapperCol"
          label="上级仓库"
          hasFeedback
        >
          <a-tree-select
            :treeData="dataSource"
            placeholder="请选择"
            :replaceFields="{
              title: 'name',
              key: 'id',
              value: 'id',
              children: 'children',
            }"
            v-decorator="['parentId', { initialValue: formData.parentId }]"
          />
        </a-form-item>
        <a-form-item
          :labelCol="labelCol"
          :wrapperCol="wrapperCol"
          label="仓库名称"
          hasFeedback
        >
          <a-input
            placeholder="仓库名称"
            v-decorator="[
              'name',
              {
                initialValue: formData.name,
                rules: validatorRules.inputIf.rules,
              },
            ]"
          />
        </a-form-item>
        <a-form-item
          :labelCol="labelCol"
          :wrapperCol="wrapperCol"
          label="所属机构"
          required
        >
          <vorganTree
            v-decorator="[
              'orgId',
              {
                initialValue: formData.orgId,
                rules: validatorRules.inputIf.rules,
              },
            ]"
          ></vorganTree>
        </a-form-item>
        <a-form-item
          :labelCol="labelCol"
          :wrapperCol="wrapperCol2"
          label="位置地点"
        >
          <div class="disflex">
            <a-input
              v-decorator="[
                'address',
                {
                  initialValue: formData.address,
                  rules: validatorRules.inputIf.rules,
                },
              ]"
            />
            <a-icon type="environment" @click="mapShow(true)" class="mapico" />
            <a-button type="link" @click="mapShow(true)">选择地点</a-button>
          </div>
        </a-form-item>
      </a-form>

a-form :form="form"

 form: this.$form.createForm(this),

那么使用

this.form.setFieldsValue({ address: val.address })来更新表单的值,以触发视图的更新。

清空的话

this.form.resetFields();

3.通常双向绑定如果不行试试前两种。

2.关于封装好了表格 使用

1.导入

import STable from "@/components/table/";

index.js

import T from "ant-design-vue/es/table/Table";
import get from "lodash.get"
export default {
  data() {
    return {
      needTotalList: [],
      selectedRows: [],
      selectedRowKeys: [],

      localLoading: false,
      localDataSource: [],
      localPagination: Object.assign({}, T.props.pagination)
    };
  },
  props: Object.assign({}, T.props, {
    rowKey: {
      type: [String, Function],
      default: 'id'
    },
    data: {
      type: Function,
      required: true
    },
    pageNum: {
      type: Number,
      default: 1
    },
    pageSize: {
      type: Number,
      default: 10
    },
    showSizeChanger: {
      type: Boolean,
      default: true
    },
    showAlertInfo: {
      type: Boolean,
      default: false
    },
    showPagination: {
      default: 'auto'
    },
    deleteShow: { // 删除键
      type: Boolean,
      default: false
    },
    bordered: {
      type: Boolean,
      default: true
    },
  }),
  watch: {
    'localPagination.current'(val) {
      this.$router.push({
        name: this.$route.name,
        params: Object.assign({}, this.$route.params, {
          current: val
        }),
      });
    },
    pageNum(val) {
      Object.assign(this.localPagination, {
        current: val
      });
    },
    pageSize(val) {
      Object.assign(this.localPagination, {
        pageSize: val
      });
    },
    showSizeChanger(val) {
      Object.assign(this.localPagination, {
        showSizeChanger: val
      });
    }
  },
  zzh() {
    const that = this
    return that;
  },
  created() {
    this.localPagination = ['auto', true].includes(this.showPagination) && Object.assign({}, this.localPagination, {
      current: this.pageNum,
      pageSize: this.pageSize,
      showSizeChanger: this.showSizeChanger
    });
    this.needTotalList = this.initTotalList(this.columns)
    this.loadData();
  },
  methods: {
    loadingShow(value) {
      this.localLoading = value
    },
    refresh() {
      var mm = {
        current: 1,
        total: 0,
        size: this.pageSize,
      }
      this.loadData(mm);
    },
    deleteRefresh() {
      this.loadData()
    },
    loadData(pagination, filters, sorter) {
      this.localLoading = true
      var result = this.data(
        Object.assign({
          current: (pagination && pagination.current) ||
            this.localPagination.current,
          size: (pagination && pagination.pageSize) ||
            this.localPagination.pageSize
        },
          (sorter && sorter.field && {
            sortField: sorter.field
          }) || {},
          (sorter && sorter.order && {
            sortOrder: sorter.order
          }) || {}, {
          ...filters
        }
        )
      );

      if (result instanceof Promise) {
        result.then(r => {
          this.localPagination = Object.assign({}, this.localPagination, {
            current: (pagination && pagination.current) ||
              this.localPagination.current,  // 返回结果中的当前分页数
            total: r.totalCount, // 返回结果中的总记录数
            showSizeChanger: this.showSizeChanger,
            pageSize: (pagination && pagination.pageSize) ||
              this.localPagination.pageSize
          });

          !r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false)
          this.localDataSource = r.data; // 返回结果中的数组数据
          this.localLoading = false
        });
      }
    },
    initTotalList(columns) {
      const totalList = []
      columns && columns instanceof Array && columns.forEach(column => {
        if (column.needTotal) {
          totalList.push({
            ...column,
            total: 0
          })
        }
      })
      return totalList
    },
    updateSelect(selectedRowKeys, selectedRows) {
      this.selectedRowKeys = selectedRowKeys
      this.selectedRows = selectedRows
      let list = this.needTotalList
      this.needTotalList = list.map(item => {
        return {
          ...item,
          total: selectedRows.reduce((sum, val) => {
            let total = sum + get(val, item.dataIndex)
            return isNaN(total) ? 0 : total
          }, 0)
        }
      })
    },
    updateEdit() {
      this.selectedRows = []
    },
    onClearSelected() {
      this.selectedRowKeys = []
      this.selectedRows = []
      this.updateSelect([], [])
      this.$emit('emptyData', { selectedRowKeys: [], selectedRows: [] })
      this.$emit('onSelect', { selectedRowKeys: [], selectedRows: [] })
    },
    onDeleteSelected() {
      this.$emit('DeleteData')
    },
    handleRowClick(record) {
      const selectedRowKeys = [...this.selectedRowKeys];
      const selectedRows = [...this.selectedRows];

      const rowKey = typeof this.rowKey === 'function' ? this.rowKey(record) : record[this.rowKey];

      const rowIndex = selectedRowKeys.indexOf(rowKey);
      if (rowIndex >= 0) {
        selectedRowKeys.splice(rowIndex, 1);
        selectedRows.splice(rowIndex, 1);
      } else {
        selectedRowKeys.push(rowKey);
        selectedRows.push(record);
      }

      this.updateSelect(selectedRowKeys, selectedRows);
      this.$emit('onSelect', { selectedRowKeys, selectedRows });
    },
    renderMsg(h) {
      const _vm = this
      this.that = this
      let d = []

      return d
    },
    renderAlert(h) {
      return h('span', {
        slot: 'message'
      }, this.renderMsg(h))
    },
  },

  render(h) {
    const _vm = this

    let props = {},
      localKeys = Object.keys(this.$data);

    Object.keys(T.props).forEach(k => {
      let localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}`;
      if (localKeys.includes(localKey)) {
        return props[k] = _vm[localKey];
      }
      return props[k] = _vm[k];
    })


    // 显示信息提示
    if (this.showAlertInfo) {

      props.rowSelection = {
        selectedRowKeys: this.selectedRowKeys,
        onChange: (selectedRowKeys, selectedRows) => {
          _vm.updateSelect(selectedRowKeys, selectedRows)
          _vm.$emit('onSelect', { selectedRowKeys: selectedRowKeys, selectedRows: selectedRows })
        }
      };

      props.customRow = (record) => ({
        on: {
          click: () => {
            _vm.handleRowClick(record);
          },
        },
      });

      return h('div', {}, [
        h("a-table", {
          tag: "component",
          attrs: props,
          on: {
            change: _vm.loadData
          },
          scopedSlots: this.$scopedSlots
        }, this.$slots.default)
      ]);

    }

    props.customRow = (record) => ({
      on: {
        click: () => {
          _vm.handleRowClick(record);
        },
      },
    });

    return h("a-table", {
      tag: "component",
      attrs: props,
      on: {
        change: _vm.loadData
      },
      scopedSlots: this.$scopedSlots
    }, this.$slots.default);

  },
};

使用

 <s-table
            ref="tableAssets"
            size="default"
            :rowKey="(record) => record.id"
            :columns="columns1"
            :data="loadDataListAssets"
            :showAlertInfo="true"
            @onSelect="onChangeAssetsList"
          ></s-table>




 loadDataListAssets: (parameter) => {
        return getUserPage(Object.assign(parameter, this.listAssetsParam)).then(
          (res) => {
            var mm = { data: [] };
            mm.size = res.data.size;
            mm.current = res.data.current;
            mm.totalCount = res.data.total;
            mm.totalPage = res.data.pages;
            mm.data = res.data.records;
            return mm;
          }
        );
      },


    onChangeAssetsList(row) {
      console.log(row);
      let self = this;
      self.personList = [];
      let arr = [...new Set([...row.selectedRows])];
      let AssetsListRow = [
        ...new Set([...self.AssetsListRow.concat(arr), ...arr]),
      ];
      self.AssetsListRow = AssetsListRow.filter((item) =>
        row.selectedRowKeys.includes(item.id)
      );
      self.personList = [...new Set([...self.AssetsListRow, ...arr])];
      // self.personList = [...new Set([...self.personList, ...arr])];
      // const strings = self.personList.map((item) => JSON.stringify(item));
      // const removeDupList = Array.from(new Set(strings));
      // const result = removeDupList.map((item) => JSON.parse(item));
      // self.personList = result;
    },

有slot使用

 <s-table ref="tableAssets2" size="default" :columns="columns2" :data="loadDataListAssets2">
              <span slot="action" slot-scope="text, record" class="flx-row-c-c">
                <div>
                  <a @click="handleDel(record)">删除</a>
                </div>
              </span>
</s-table> 
           

3.关于单选封装好的组件使用

    <j-select-supplier
                  v-decorator="['supplierId']"
                  :multiple="false"
                  @accountData="accountData2"
                ></j-select-supplier>



import JSelectSupplier from "@/components/jeecgbiz/JSelectSupplier";



    accountData2(e) {
      if (e.length > 0) {
        this.editform.supplierName = e[0].name;
        this.editform.supplierId = e[0].id;
      } else {
        this.editform.supplierName = "";
        this.editform.supplierId = "";
      }
      console.log(e);
    },
<template>
  <!-- 定义在这里的参数都是不可在外部覆盖的,防止出现问题 -->
  <j-select-biz-component-two
    :value="value"
    :ellipsisLength="25"
    :listUrl="url.list"
    :columns="columns"
    :multiple="false"
    v-on="$listeners"
    v-bind="attrs"
    @commitData="commitData"
  />
</template>

<script>
import JSelectBizComponentTwo from "./JSelectBizComponentTwo";

export default {
  name: "JSelectSupplier",
  components: { JSelectBizComponentTwo },
  props: ["value"],
  data() {
    return {
      url: { list: "/asset/supplierinfo/page" },
      columns: [
        { title: "供应商", align: "center", dataIndex: "name" },
        {
          title: "联系人",
          align: "center",

          dataIndex: "linkman",
        },
        {
          title: "联系电话",
          align: "center",

          dataIndex: "phone",
        },
      ],
      // 定义在这里的参数都是可以在外部传递覆盖的,可以更灵活的定制化使用的组件
      default: {
        name: "供应商",
        width: "80%",
        displayKey: "name",
        returnKeys: ["id", "name"],
        rowKey: "id",
        valueKey: "id",
        queryParamText: "供应商名称", //左侧搜索框名称
        queryParamCode: "name", //左侧搜索框字段名
      },
    };
  },
  computed: {
    attrs() {
      return Object.assign(this.default, this.$attrs);
    },
  },
  methods: {
    // 提交数据
    commitData(e) {
      console.log(e);
      this.$emit("accountData", e);
    },
  },
};
</script>

<style lang="less" scoped></style>

外层也就是index

<template>
  <a-row class="j-select-biz-component-box" type="flex" :gutter="8">
    <a-col class="left" :class="{'full': !buttons}">
      <slot name="left">
        <a-select
          mode="multiple"
          :placeholder="placeholder"
          v-model="selectValue"
          :options="selectOptions"
          allowClear
          :disabled="disabled"
          :open="selectOpen"
          style="width: 100%;"
          @dropdownVisibleChange="handleDropdownVisibleChange"
          @click.native="visible=(buttons?visible:true)"
        />
      </slot>
    </a-col>

    <a-col v-if="buttons" class="right">
      <a-button type="primary" icon="search" :disabled="disabled" @click="visible=true">{{selectButtonText}}</a-button>
    </a-col>

    <j-select-biz-component-modal
      v-model="selectValue"
      :visible.sync="visible"
      v-bind="modalProps"
      :multiple="multiple"
      @options="handleOptions"
      @commitData="commitData"
    />
  </a-row>
</template>

<script>
  import JSelectBizComponentModal from './JSelectBizComponentModal'

  export default {
    name: 'JSelectBizComponent',
    components: { JSelectBizComponentModal },
    props: {
      value: {
        type: String,
        default: ''
      },
      /** 是否返回 id,默认 false,返回 code */
      returnId: {
        type: Boolean,
        default: false
      },
      placeholder: {
        type: String,
        default: '请选择'
      },
      disabled: {
        type: Boolean,
        default: false
      },
      // 是否支持多选,默认 true
      multiple: {
        type: Boolean,
        default: true
      },
      // 是否显示按钮,默认 true
      buttons: {
        type: Boolean,
        default: true
      },
      // 显示的 Key
      displayKey: {
        type: String,
        default: null
      },
      // 返回的 key
      returnKeys: {
        type: Array,
        default: () => ['id', 'id']
      },
      // 选择按钮文字
      selectButtonText: {
        type: String,
        default: '选择'
      },

    },
    data() {
      return {
        selectValue: [],
        selectOptions: [],
        dataSourceMap: {},
        visible: false,
        selectOpen: false,
      }
    },
    computed: {
      valueKey() {
        return this.returnId ? this.returnKeys[0] : this.returnKeys[1]
      },
      modalProps() {
        return Object.assign({
          valueKey: this.valueKey,
          multiple: this.multiple,
          returnKeys: this.returnKeys,
          displayKey: this.displayKey || this.valueKey
        }, this.$attrs)
      },
    },
    watch: {
      value: {
        immediate: true,
        handler(val) {
          console.log('cake撒',val)
          if (val) {
            this.selectValue = val.split(',')
          } else {
            this.selectValue = []
          }
        }
      },
      selectValue: {
        deep: true,
        handler(val) {
          console.log(this.materialUseTime)
          let rows = val.map(key => this.dataSourceMap[key])
          this.$emit('select', rows)
          let data = val.join(',')
          this.$emit('input', data)
          this.$emit('change', data)
        }
      }
    },
    methods: {
      commitData(e) {
        this.$emit('commitData',e)
      },
      handleOptions(options, dataSourceMap) {
        this.selectOptions = options
        this.dataSourceMap = dataSourceMap
      },
      handleDropdownVisibleChange() {
        // 解决antdv自己的bug —— open 设置为 false 了,点击后还是添加了 open 样式,导致点击事件失效
        this.selectOpen = true
        this.$nextTick(() => {
          this.selectOpen = false
        })
      },
    }
  }
</script>

<style lang="less" scoped>
  .j-select-biz-component-box {

    @width: 82px;

    .left {
      width: calc(100% - @width - 8px);
    }

    .right {
      width: @width;
    }

    .full {
      width: 100%;
    }

    /deep/ .ant-select-search__field {
      display: none !important;
    }
  }
</style>

 内层

<template>
  <a-modal
    centered
    :title="name + '选择'"
    :width="width"
    :visible="visible"
    @ok="handleOk"
    @cancel="close"
    cancelText="关闭"
  >
    <a-row :gutter="18">
      <a-col :span="16">
        <!-- 查询区域 -->
        <div class="table-page-search-wrapper">
          <a-form layout="inline">
            <a-row :gutter="24">
              <a-col :span="14">
                <a-form-item :label="queryParamText || name">
                  <a-input
                    v-model="queryParam[queryParamCode || valueKey]"
                    :placeholder="'请输入' + (queryParamText || name)"
                    @pressEnter="searchQuery"
                  />
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <span
                  style="float: left; overflow: hidden"
                  class="table-page-search-submitButtons"
                >
                  <a-button type="primary" @click="searchQuery" icon="search"
                    >查询</a-button
                  >
                  <a-button
                    type="primary"
                    @click="searchReset"
                    icon="reload"
                    style="margin-left: 8px"
                    >重置</a-button
                  >
                </span>
              </a-col>
            </a-row>
          </a-form>
        </div>

        <a-table
          size="small"
          bordered
          :rowKey="rowKey"
          :columns="innerColumns"
          :dataSource="dataSource"
          :pagination="ipagination"
          :loading="loading"
          :scroll="{ y: 240 }"
          :rowSelection="{
            selectedRowKeys,
            onChange: onSelectChange,
            type: multiple ? 'checkbox' : 'radio',
            width: '60px',
          }"
          :customRow="customRowFn"
          @change="handleTableChange"
        >
        </a-table>
      </a-col>
      <a-col :span="8">
        <a-card
          :title="'已选中的' + name"
          :bordered="false"
          :head-style="{ padding: 0 }"
          :body-style="{ padding: 0 }"
        >
          <a-table
            size="small"
            :rowKey="rowKey"
            bordered
            v-bind="selectedTable"
          >
            <span slot="action" slot-scope="text, record, index">
              <a @click="handleDeleteSelected(record, index)">删除</a>
            </span>
          </a-table>
        </a-card>
      </a-col>
    </a-row>
  </a-modal>
</template>

<script>
// import { getAction } from '@/api/manage'
import Ellipsis from "@/components/Ellipsis";
import { JeecgListMixin } from "@/mixins/JeecgListMixin";
import { cloneObject, pushIfNotExist } from "@/utils/util";

export default {
  name: "JSelectBizComponentModal",
  mixins: [JeecgListMixin],
  components: { Ellipsis },
  props: {
    value: {
      type: Array,
      default: () => [],
    },
    visible: {
      type: Boolean,
      default: false,
    },
    valueKey: {
      type: String,
      required: true,
    },
    multiple: {
      type: Boolean,
      default: true,
    },
    width: {
      type: [Number, String],
      default: "80%",
    },

    name: {
      type: String,
      default: "",
    },
    listUrl: {
      type: String,
      required: true,
      default: "",
    },
    // 根据 value 获取显示文本的地址,例如存的是 username,可以通过该地址获取到 realname
    valueUrl: {
      type: String,
      default: "",
    },
    displayKey: {
      type: String,
      default: null,
    },
    columns: {
      type: Array,
      required: true,
      default: () => [],
    },
    // 查询条件Code
    queryParamCode: {
      type: String,
      default: null,
    },
    // 查询条件文字
    queryParamText: {
      type: String,
      default: null,
    },
    rowKey: {
      type: String,
      default: "id",
    },
    // 过长裁剪长度,设置为 -1 代表不裁剪
    ellipsisLength: {
      type: Number,
      default: 12,
    },
  },
  data() {
    return {
      innerValue: [],
      // 已选择列表
      selectedTable: {
        pagination: false,
        scroll: { y: 240 },
        columns: [
          {
            ...this.columns[0],
            width: this.columns[0].widthRight || this.columns[0].width,
          },
          {
            ...this.columns[1],
            width: this.columns[1].widthRight || this.columns[1].width,
          },
          {
            title: "操作",
            dataIndex: "action",
            align: "center",
            width: 60,
            scopedSlots: { customRender: "action" },
          },
        ],
        dataSource: [],
      },
      renderEllipsis: (value) => (
        <ellipsis length={this.ellipsisLength}>{value}</ellipsis>
      ),
      url: { list: this.listUrl },
      /* 分页参数 */
      ipagination: {
        current: 1,
        pageSize: 5,
        pageSizeOptions: ["5", "10", "20", "30"],
        showTotal: (total, range) => {
          return range[0] + "-" + range[1] + " 共" + total + "条";
        },
        showQuickJumper: true,
        showSizeChanger: true,
        total: 0,
      },
      options: [],
      dataSourceMap: {},
    };
  },
  computed: {
    // 表头
    innerColumns() {
      let columns = cloneObject(this.columns);
      columns.forEach((column) => {
        // 给所有的列加上过长裁剪
        if (this.ellipsisLength !== -1) {
          column.customRender = (text) => this.renderEllipsis(text);
        }
      });
      return columns;
    },
  },
  watch: {
    value: {
      deep: true,
      immediate: true,
      handler(val) {
        console.log(val);
        this.innerValue = cloneObject(val);
        this.selectedRowKeys = [];
        this.valueWatchHandler(val);
        this.queryOptionsByValue(val);
      },
    },
    dataSource: {
      deep: true,
      handler(val) {
        // 重置之后key恢复
        this.emitOptions(val);
        this.valueWatchHandler(this.innerValue);
      },
    },
    selectedRowKeys: {
      immediate: true,
      deep: true,
      handler(val) {
        this.selectedTable.dataSource = val.map((key) => {
          for (let data of this.dataSource) {
            if (data[this.rowKey] === key) {
              pushIfNotExist(this.innerValue, data[this.valueKey]);
              return data;
            }
          }
          for (let data of this.selectedTable.dataSource) {
            if (data[this.rowKey] === key) {
              pushIfNotExist(this.innerValue, data[this.valueKey]);
              return data;
            }
          }
          console.warn("未找到选择的行信息,key:" + key);
          return {};
        });
      },
    },
  },

  methods: {
    /** 关闭弹窗 */
    close() {
      this.$emit("update:visible", false);
    },

    valueWatchHandler(val) {
      console.log(val);
      val.forEach((item) => {
        this.dataSource
          .concat(this.selectedTable.dataSource)
          .forEach((data) => {
            if (data[this.valueKey] === item) {
              pushIfNotExist(this.selectedRowKeys, data[this.rowKey]);
            }
          });
      });
    },

    queryOptionsByValue(value) {
      console.log(value);
      if (!value || value.length === 0) {
        return;
      }
      // 判断options是否存在value,如果已存在数据就不再请求后台了
      let notExist = false;
      for (let val of value) {
        let find = false;
        for (let option of this.options) {
          if (val === option.value) {
            find = true;
            break;
          }
        }
        if (!find) {
          notExist = true;
          break;
        }
      }
      if (!notExist) return;
      // listDepartUser( {
      //   // 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询,防止后台进行了模糊匹配,导致查询结果不准确
      //   // [this.valueKey]: value.join(',') + ',',
      //   pageNo: 1,
      //   pageSize: value.length
      // }).then((res) => {
      //   if (res.success) {
      //     let dataSource = res.result
      //     if (!(dataSource instanceof Array)) {
      //       dataSource = res.result.records
      //     }
      //     this.emitOptions(dataSource, (data) => {
      //       pushIfNotExist(this.innerValue, data[this.valueKey])
      //       pushIfNotExist(this.selectedRowKeys, data[this.rowKey])
      //       pushIfNotExist(this.selectedTable.dataSource, data, this.rowKey)
      //     })
      //   }
      // })
    },

    emitOptions(dataSource, callback) {
      dataSource.forEach((data) => {
        let key = data[this.valueKey];
        this.dataSourceMap[key] = data;
        pushIfNotExist(
          this.options,
          { label: data[this.displayKey || this.valueKey], value: key },
          "value"
        );
        typeof callback === "function" ? callback(data) : "";
      });
      this.$emit("options", this.options, this.dataSourceMap);
    },

    /** 完成选择 */
    handleOk() {
      let value = this.selectedTable.dataSource.map(
        (data) => data[this.valueKey]
      );
      this.$emit("input", value);
      this.$emit("commitData", this.selectedTable.dataSource);
      this.close();
    },

    /** 删除已选择的 */
    handleDeleteSelected(record, index) {
      this.selectionRows.splice(
        this.selectedRowKeys.indexOf(record[this.rowKey]),
        1
      );
      this.selectedRowKeys.splice(
        this.selectedRowKeys.indexOf(record[this.rowKey]),
        1
      );
      this.selectedTable.dataSource.splice(index, 1);
      console.log(this.selectedRowKeys, this.selectionRows);
    },

    customRowFn(record) {
      return {
        on: {
          click: () => {
            let key = record[this.rowKey];
            if (!this.multiple) {
              this.selectedRowKeys = [key];
              this.selectedTable.dataSource = [record];
            } else {
              let index = this.selectedRowKeys.indexOf(key);
              if (index === -1) {
                this.selectedRowKeys.push(key);
                this.selectedTable.dataSource.push(record);
              } else {
                this.handleDeleteSelected(record, index);
              }
            }
          },
        },
      };
    },
  },
};
</script>
<style lang="less" scoped>
</style>

JeecgListMixin的方法

/**
 * 新增修改完成调用 modalFormOk方法 编辑弹框组件ref定义为modalForm
 * 高级查询按钮调用 superQuery方法  高级查询组件ref定义为superQueryModal
 * data中url定义 list为查询列表  delete为删除单条记录  deleteBatch为批量删除
 */
import { filterObj } from "@/utils/util";
import { deleteAction, getAction, downFile, getFileAccessHttpUrl } from "@/api/manage";

export const JeecgListMixin = {
  data() {
    return {
      /* 查询条件-请不要在queryParam中声明非字符串值的属性 */
      queryParam: {},
      /* 数据源 */
      dataSource: [],
      /* 分页参数 */
      ipagination: {
        current: 1,
        pageSize: 10,
        pageSizeOptions: ["10", "20", "30"],
        showTotal: (total, range) => {
          return range[0] + "-" + range[1] + " 共" + total + "条";
        },
        showQuickJumper: true,
        showSizeChanger: true,
        total: 0,
      },
      /* 排序参数 */
      isorter: {
        column: "createTime",
        order: "desc",
      },
      /* 筛选参数 */
      filters: {},
      /* table加载状态 */
      loading: false,
      /* table选中keys*/
      selectedRowKeys: [],
      /* table选中records*/
      selectionRows: [],
      /* 查询折叠 */
      toggleSearchStatus: false,
      /* 高级查询条件生效状态 */
      superQueryFlag: false,
      /* 高级查询条件 */
      superQueryParams: "",
      /** 高级查询拼接方式 */
      superQueryMatchType: "and",
    };
  },
  created() {
    if (!this.disableMixinCreated) {
      console.log(" -- mixin created -- ");
      this.loadData();
      //初始化字典配置 在自己页面定义
      this.initDictConfig();
    }
  },
  computed: {},
  methods: {
    loadData(arg) {
      if (!this.url.list) {
        this.$message.error("请设置url.list属性!");
        return;
      }
      //加载数据 若传入参数1则加载第一页的内容
      if (arg === 1) {
        this.ipagination.current = 1;
      }
      var params = this.getQueryParams(); //查询条件
      this.loading = true;
      getAction(this.url.list, params)
        .then((res) => {
          if (res.ok) {
            //update-begin---author:zhangyafei    Date:20201118  for:适配不分页的数据列表------------
            this.dataSource = res.data.records || res.data;
            if (res.data.total) {
              this.ipagination.total = res.data.total;
            } else {
              this.ipagination.total = 0;
            }
            //update-end---author:zhangyafei    Date:20201118  for:适配不分页的数据列表------------
          } else {
            this.$message.warning(res.msg);
          }
        })
        .finally(() => {
          this.loading = false;
        });
    },
    initDictConfig() {
      console.log("--这是一个假的方法!");
    },
    handleSuperQuery(params, matchType) {
      //高级查询方法
      if (!params) {
        this.superQueryParams = "";
        this.superQueryFlag = false;
      } else {
        this.superQueryFlag = true;
        this.superQueryParams = JSON.stringify(params);
        this.superQueryMatchType = matchType;
      }
      this.loadData(1);
    },
    getQueryParams() {
      //获取查询条件
      let sqp = {};
      if (this.superQueryParams) {
        sqp["superQueryParams"] = encodeURI(this.superQueryParams);
        sqp["superQueryMatchType"] = this.superQueryMatchType;
      }
      var param = Object.assign(sqp, this.queryParam, this.isorter, this.filters);
      // param.field = this.getQueryField();
      param.current = this.ipagination.current;
      param.size = this.ipagination.pageSize;
      return filterObj(param);
    },
    getQueryField() {
      //TODO 字段权限控制
      var str = "id,";
      this.columns.forEach(function (value) {
        str += "," + value.dataIndex;
      });
      return str;
    },
    onSelectChange(selectedRowKeys, selectionRows) {
      this.selectedRowKeys = selectedRowKeys;
      this.selectionRows = selectionRows;
      console.log(selectedRowKeys, selectionRows);
    },
    onClearSelected() {
      this.selectedRowKeys = [];
      this.selectionRows = [];
    },
    searchQuery() {
      this.loadData(1);
    },
    superQuery() {
      this.$refs.superQueryModal.show();
    },
    searchReset() {
      this.queryParam = {};
      this.loadData(1);
    },
    batchDel: function () {
      if (!this.url.deleteBatch) {
        this.$message.error("请设置url.deleteBatch属性!");
        return;
      }
      if (this.selectedRowKeys.length <= 0) {
        this.$message.warning("请选择一条记录!");
        return;
      } else {
        var ids = "";
        for (var a = 0; a < this.selectedRowKeys.length; a++) {
          ids += this.selectedRowKeys[a] + ",";
        }
        var that = this;
        this.$confirm({
          title: "确认删除",
          content: "是否删除选中数据?",
          onOk: function () {
            that.loading = true;
            deleteAction(that.url.deleteBatch, { ids: ids })
              .then((res) => {
                if (res.success) {
                  //重新计算分页问题
                  that.reCalculatePage(that.selectedRowKeys.length);
                  that.$message.success(res.message);
                  that.loadData();
                  that.onClearSelected();
                } else {
                  that.$message.warning(res.message);
                }
              })
              .finally(() => {
                that.loading = false;
              });
          },
        });
      }
    },
    handleDelete: function (id) {
      if (!this.url.delete) {
        this.$message.error("请设置url.delete属性!");
        return;
      }
      var that = this;
      deleteAction(`${that.url.delete}/${id}`, { id: id }).then((res) => {
        if (res.ok) {
          //重新计算分页问题
          that.reCalculatePage(1);
          that.$message.success("操作成功");
          that.loadData();
        } else {
          that.$message.warning(res.msg);
        }
      });
    },
    reCalculatePage(count) {
      //总数量-count
      let total = this.ipagination.total - count;
      //获取删除后的分页数
      let currentIndex = Math.ceil(total / this.ipagination.pageSize);
      //删除后的分页数<所在当前页
      if (currentIndex < this.ipagination.current) {
        this.ipagination.current = currentIndex;
      }
      console.log("currentIndex", currentIndex);
    },
    handleEdit: function (record) {
      this.$refs.modalForm.edit(record);
      this.$refs.modalForm.title = "编辑";
      this.$refs.modalForm.disableSubmit = false;
    },
    handleAdd: function () {
      this.$refs.modalForm.add();
      this.$refs.modalForm.title = "新增";
      this.$refs.modalForm.disableSubmit = false;
    },
    handleTableChange(pagination, filters, sorter) {
      //分页、排序、筛选变化时触发
      //TODO 筛选
      console.log(pagination);
      if (Object.keys(sorter).length > 0) {
        // this.isorter.column = sorter.field;
        this.isorter.order = "ascend" == sorter.order ? "asc" : "desc";
      }
      this.ipagination = pagination;
      this.loadData();
    },
    handleToggleSearch() {
      this.toggleSearchStatus = !this.toggleSearchStatus;
    },
    // 给popup查询使用(查询区域不支持回填多个字段,限制只返回一个字段)
    getPopupField(fields) {
      return fields.split(",")[0];
    },
    modalFormOk() {
      // 新增/修改 成功时,重载列表
      this.loadData();
      //清空列表选中
      this.onClearSelected();
    },
    handleDetail: function (record) {
      this.$refs.modalForm.edit(record);
      this.$refs.modalForm.title = "详情";
      this.$refs.modalForm.disableSubmit = true;
    },
    /* 导出 */
    handleExportXls2() {
      let paramsStr = encodeURI(JSON.stringify(this.getQueryParams()));
      let url = `${window._CONFIG["domianURL"]}/${this.url.exportXlsUrl}?paramsStr=${paramsStr}`;
      window.location.href = url;
    },
    handleExportXls(fileName) {
      if (!fileName || typeof fileName != "string") {
        fileName = "导出文件";
      }
      let param = this.getQueryParams();
      if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
        param["selections"] = this.selectedRowKeys.join(",");
      }
      console.log("导出参数", param);
      downFile(this.url.exportXlsUrl, param).then((data) => {
        if (!data) {
          this.$message.warning("文件下载失败");
          return;
        }
        if (typeof window.navigator.msSaveBlob !== "undefined") {
          window.navigator.msSaveBlob(new Blob([data], { type: "application/vnd.ms-excel" }), fileName + ".xls");
        } else {
          console.log(data);
          let url = window.URL.createObjectURL(new Blob([data.data], { type: "application/vnd.ms-excel" }));
          let link = document.createElement("a");
          link.style.display = "none";
          link.href = url;
          link.setAttribute("download", fileName + ".xls");
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link); //下载完成移除元素
          window.URL.revokeObjectURL(url); //释放掉blob对象
        }
      });
    },
    /* 图片预览 */
    getImgView(text) {
      if (text && text.indexOf(",") > 0) {
        text = text.substring(0, text.indexOf(","));
      }
      return getFileAccessHttpUrl(text);
    },
    /* 文件下载 */
    // update--autor:lvdandan-----date:20200630------for:修改下载文件方法名uploadFile改为downloadFile------
    downloadFile(text) {
      if (!text) {
        this.$message.warning("未知的文件");
        return;
      }
      if (text.indexOf(",") > 0) {
        text = text.substring(0, text.indexOf(","));
      }
      let url = getFileAccessHttpUrl(text);
      window.open(url);
    },
  },
};

 

Ellipsis的方法

import Ellipsis from './Ellipsis'

export default Ellipsis

Ellipsis.vue

<script>
  import { cutStrByFullLength, getStrFullLength } from '@/components/_util/StringUtil'

  export default {
    name: 'Ellipsis',
    props: {
      prefixCls: {
        type: String,
        default: 'ant-pro-ellipsis'
      },
      tooltip: {
        type: Boolean,
        default: true,
      },
      length: {
        type: Number,
        default: 25,
      },
      lines: {
        type: Number,
        default: 1
      },
      fullWidthRecognition: {
        type: Boolean,
        default: false
      }
    },
    methods: {},
    render() {
      const { tooltip, length } = this.$props
      let text = ''
      // 处理没有default插槽时的特殊情况
      if (this.$slots.default) {
        text = this.$slots.default.map(vNode => vNode.text).join('')
      }
      // 判断是否显示 tooltip
      if (tooltip && getStrFullLength(text) > length) {
        return (
          <a-tooltip>
            <template slot="title">{text}</template>
            <span>{cutStrByFullLength(text, this.length) + '…'}</span>
          </a-tooltip>
        )
      } else {
        return (<span>{text}</span>)
      }
    }
  }
</script>

4.关于封装好的复选表格

  <j-select-contract
                  :trigger-change="true"
                  v-decorator="['purchaseContractIds']"
                  customReturnField="purchaseContractIds"
                  @accountData="changeContract"
                  :multiple="true"
                  :status="2"
                ></j-select-contract>
import JSelectContract from "@/components/jeecgbiz/JSelectContract";

<template>
  <!-- 定义在这里的参数都是不可在外部覆盖的,防止出现问题 -->
  <j-select-biz-component
    :value="value"
    :ellipsisLength="25"
    :listUrl="url.list"
    :columns="columns"
    :multiple="multiple"
    v-on="$listeners"
    v-bind="attrs"
    @commitData="commitData"
  />
</template>

<script>
import JSelectBizComponent from "./JSelectBizComponent";

export default {
  name: "JSelectContract",
  components: { JSelectBizComponent },
  props: ["value", "multiple"],
  data() {
    return {
      url: { list: "/asset/purchasecontract/page?contractStatus=2&isAllTake=0" },
      columns: [
        { title: "合同单据号", align: "center", width: "25%", widthRight: "70%", dataIndex: "purchaseContractNo" },
        { title: "订购时间", align: "center", width: "25%", dataIndex: "orderDate" },
        { title: "采购员", align: "center", width: "20%", dataIndex: "purchasePersonName" },
        { title: "采购部门", align: "center", width: "20%", dataIndex: "organName" },
      ],
      // 定义在这里的参数都是可以在外部传递覆盖的,可以更灵活的定制化使用的组件
      default: {
        name: "采购合同",
        width: 1200,
        displayKey: "purchaseContractNo",
        returnKeys: ["id", "purchaseContractNo", "organName", "organId"],
        queryParamText: "合同单据号",
        queryParamCode: "purchaseContractNo",
      },
    };
  },
  computed: {
    attrs() {
      return Object.assign(this.default, this.$attrs);
    },
  },
  methods: {
    // 提交数据
    commitData(e) {
      this.$emit("accountData", e);
    },
  },
};
</script>

<style lang="less" scoped></style>

 index外层

<template>
  <a-row class="j-select-biz-component-box" type="flex" :gutter="8">
    <a-col class="left" :class="{'full': !buttons}">
      <slot name="left">
        <a-select
          mode="multiple"
          :placeholder="placeholder"
          v-model="selectValue"
          :options="selectOptions"
          allowClear
          :disabled="disabled"
          :open="selectOpen"
          style="width: 100%;"
          @dropdownVisibleChange="handleDropdownVisibleChange"
          @click.native="visible=(buttons?visible:true)"
        />
      </slot>
    </a-col>

    <a-col v-if="buttons" class="right">
      <a-button type="primary" icon="search" :disabled="disabled" @click="visible=true">{{selectButtonText}}</a-button>
    </a-col>

    <j-select-biz-component-modal
      v-model="selectValue"
      :visible.sync="visible"
      v-bind="modalProps"
      :multiple="multiple"
      @options="handleOptions"
      @commitData="commitData"
    />
  </a-row>
</template>

<script>
  import JSelectBizComponentModal from './JSelectBizComponentModal'

  export default {
    name: 'JSelectBizComponent',
    components: { JSelectBizComponentModal },
    props: {
      value: {
        type: String,
        default: ''
      },
      /** 是否返回 id,默认 false,返回 code */
      returnId: {
        type: Boolean,
        default: false
      },
      placeholder: {
        type: String,
        default: '请选择'
      },
      disabled: {
        type: Boolean,
        default: false
      },
      // 是否支持多选,默认 true
      multiple: {
        type: Boolean,
        default: true
      },
      // 是否显示按钮,默认 true
      buttons: {
        type: Boolean,
        default: true
      },
      // 显示的 Key
      displayKey: {
        type: String,
        default: null
      },
      // 返回的 key
      returnKeys: {
        type: Array,
        default: () => ['id', 'id']
      },
      // 选择按钮文字
      selectButtonText: {
        type: String,
        default: '选择'
      },

    },
    data() {
      return {
        selectValue: [],
        selectOptions: [],
        dataSourceMap: {},
        visible: false,
        selectOpen: false,
      }
    },
    computed: {
      valueKey() {
        return this.returnId ? this.returnKeys[0] : this.returnKeys[1]
      },
      modalProps() {
        return Object.assign({
          valueKey: this.valueKey,
          multiple: this.multiple,
          returnKeys: this.returnKeys,
          displayKey: this.displayKey || this.valueKey
        }, this.$attrs)
      },
    },
    watch: {
      value: {
        immediate: true,
        handler(val) {
          console.log('cake撒',val)
          if (val) {
            this.selectValue = val.split(',')
          } else {
            this.selectValue = []
          }
        }
      },
      selectValue: {
        deep: true,
        handler(val) {
          console.log(this.materialUseTime)
          let rows = val.map(key => this.dataSourceMap[key])
          this.$emit('select', rows)
          let data = val.join(',')
          this.$emit('input', data)
          this.$emit('change', data)
        }
      }
    },
    methods: {
      commitData(e) {
        this.$emit('commitData',e)
      },
      handleOptions(options, dataSourceMap) {
        this.selectOptions = options
        this.dataSourceMap = dataSourceMap
      },
      handleDropdownVisibleChange() {
        // 解决antdv自己的bug —— open 设置为 false 了,点击后还是添加了 open 样式,导致点击事件失效
        this.selectOpen = true
        this.$nextTick(() => {
          this.selectOpen = false
        })
      },
    }
  }
</script>

<style lang="less" scoped>
  .j-select-biz-component-box {

    @width: 82px;

    .left {
      width: calc(100% - @width - 8px);
    }

    .right {
      width: @width;
    }

    .full {
      width: 100%;
    }

    /deep/ .ant-select-search__field {
      display: none !important;
    }
  }
</style>

 内层

<template>
  <a-modal
    centered
    :title="name + '选择'"
    :width="width"
    :visible="visible"
    @ok="handleOk"
    @cancel="close"
    cancelText="关闭"
  >
    <a-row :gutter="18">
      <a-col :span="16">
        <!-- 查询区域 -->
        <div class="table-page-search-wrapper">
          <a-form :labelCol="{ span: 5 }" :wrapperCol="{ span: 18, offset: 1 }">
            <a-row :gutter="24">
              <a-col :span="14">
                <a-form-item :label="queryParamText || name">
                  <a-input
                    v-model="queryParam[queryParamCode || valueKey]"
                    :placeholder="'请输入' + (queryParamText || name)"
                    @pressEnter="searchQuery"
                  />
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <span
                  style="float: left; overflow: hidden"
                  class="table-page-search-submitButtons"
                >
                  <a-button type="primary" @click="searchQuery" icon="search"
                    >查询</a-button
                  >
                  <a-button
                    type="primary"
                    @click="searchReset"
                    icon="reload"
                    style="margin-left: 8px"
                    >重置</a-button
                  >
                </span>
              </a-col>
            </a-row>
          </a-form>
        </div>

        <a-table
          size="small"
          bordered
          :rowKey="rowKey"
          :columns="innerColumns"
          :dataSource="dataSource"
          :pagination="ipagination"
          :loading="loading"
          :scroll="{ y: 240 }"
          :rowSelection="{
            selectedRowKeys,
            onChange: onSelectChange,
            type: multiple ? 'checkbox' : 'radio',
          }"
          :customRow="customRowFn"
          @change="handleTableChange"
        >
        </a-table>
      </a-col>
      <a-col :span="8">
        <a-card
          :title="'已选' + name"
          :bordered="false"
          :head-style="{ padding: 0 }"
          :body-style="{ padding: 0 }"
        >
          <a-table
            size="small"
            :rowKey="rowKey"
            bordered
            v-bind="selectedTable"
          >
            <span slot="action" slot-scope="text, record, index">
              <a @click="handleDeleteSelected(record, index)">删除</a>
            </span>
          </a-table>
        </a-card>
      </a-col>
    </a-row>
  </a-modal>
</template>

<script>
// import { getAction } from '@/api/manage'
import Ellipsis from "@/components/Ellipsis";
import { JeecgListMixin } from "@/mixins/JeecgListMixin";
import { cloneObject, pushIfNotExist } from "@/utils/util";
import { listDepartUser } from "@/api/apis";

export default {
  name: "JSelectBizComponentModal",
  mixins: [JeecgListMixin],
  components: { Ellipsis },
  props: {
    value: {
      type: Array,
      default: () => [],
    },
    visible: {
      type: Boolean,
      default: false,
    },
    valueKey: {
      type: String,
      required: true,
    },
    multiple: {
      type: Boolean,
      default: true,
    },
    width: {
      type: Number,
      default: 900,
    },

    name: {
      type: String,
      default: "",
    },
    listUrl: {
      type: String,
      required: true,
      default: "",
    },
    // 根据 value 获取显示文本的地址,例如存的是 username,可以通过该地址获取到 realname
    valueUrl: {
      type: String,
      default: "",
    },
    displayKey: {
      type: String,
      default: null,
    },
    columns: {
      type: Array,
      required: true,
      default: () => [],
    },
    // 查询条件Code
    queryParamCode: {
      type: String,
      default: null,
    },
    // 查询条件文字
    queryParamText: {
      type: String,
      default: null,
    },
    rowKey: {
      type: String,
      default: "id",
    },
    // 过长裁剪长度,设置为 -1 代表不裁剪
    ellipsisLength: {
      type: Number,
      default: 12,
    },
  },
  data() {
    return {
      innerValue: [],
      // 已选择列表
      selectedTable: {
        pagination: false,
        scroll: { y: 240 },
        columns: [
          {
            ...this.columns[0],
            width: this.columns[0].widthRight || this.columns[0].width,
          },
          {
            title: "操作",
            dataIndex: "action",
            align: "center",
            width: 60,
            scopedSlots: { customRender: "action" },
          },
        ],
        dataSource: [],
      },
      renderEllipsis: (value) => (
        <ellipsis length={this.ellipsisLength}>{value}</ellipsis>
      ),
      url: { list: this.listUrl },
      /* 分页参数 */
      ipagination: {
        current: 1,
        pageSize: 5,
        pageSizeOptions: ["5", "10", "20", "30"],
        showTotal: (total, range) => {
          return range[0] + "-" + range[1] + " 共" + total + "条";
        },
        showQuickJumper: true,
        showSizeChanger: true,
        total: 0,
      },
      options: [],
      dataSourceMap: {},
    };
  },
  computed: {
    // 表头
    innerColumns() {
      let columns = cloneObject(this.columns);
      columns.forEach((column) => {
        // 给所有的列加上过长裁剪
        if (this.ellipsisLength !== -1) {
          column.customRender = (text) => this.renderEllipsis(text);
        }
      });
      return columns;
    },
  },
  watch: {
    value: {
      deep: true,
      immediate: true,
      handler(val) {
        console.log(val);
        this.innerValue = cloneObject(val);
        this.selectedRowKeys = [];
        this.valueWatchHandler(val);
        this.queryOptionsByValue(val);
      },
    },
    dataSource: {
      deep: true,
      handler(val) {
        // 重置之后key恢复
        this.emitOptions(val);
        this.valueWatchHandler(this.innerValue);
      },
    },
    selectedRowKeys: {
      immediate: true,
      deep: true,
      handler(val) {
        this.selectedTable.dataSource = val.map((key) => {
          for (let data of this.dataSource) {
            if (data[this.rowKey] === key) {
              pushIfNotExist(this.innerValue, data[this.valueKey]);
              return data;
            }
          }
          for (let data of this.selectedTable.dataSource) {
            if (data[this.rowKey] === key) {
              pushIfNotExist(this.innerValue, data[this.valueKey]);
              return data;
            }
          }
          console.warn("未找到选择的行信息,key:" + key);
          return {};
        });
      },
    },
  },

  methods: {
    /** 关闭弹窗 */
    close() {
      this.$emit("update:visible", false);
    },

    valueWatchHandler(val) {
      console.log(val);
      val.forEach((item) => {
        this.dataSource
          .concat(this.selectedTable.dataSource)
          .forEach((data) => {
            if (data[this.valueKey] === item) {
              pushIfNotExist(this.selectedRowKeys, data[this.rowKey]);
            }
          });
      });
    },

    queryOptionsByValue(value) {
      console.log(value);
      if (!value || value.length === 0) {
        return;
      }
      // 判断options是否存在value,如果已存在数据就不再请求后台了
      let notExist = false;
      for (let val of value) {
        let find = false;
        for (let option of this.options) {
          if (val === option.value) {
            find = true;
            break;
          }
        }
        if (!find) {
          notExist = true;
          break;
        }
      }
      if (!notExist) return;
      // listDepartUser( {
      //   // 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询,防止后台进行了模糊匹配,导致查询结果不准确
      //   // [this.valueKey]: value.join(',') + ',',
      //   pageNo: 1,
      //   pageSize: value.length
      // }).then((res) => {
      //   if (res.success) {
      //     let dataSource = res.result
      //     if (!(dataSource instanceof Array)) {
      //       dataSource = res.result.records
      //     }
      //     this.emitOptions(dataSource, (data) => {
      //       pushIfNotExist(this.innerValue, data[this.valueKey])
      //       pushIfNotExist(this.selectedRowKeys, data[this.rowKey])
      //       pushIfNotExist(this.selectedTable.dataSource, data, this.rowKey)
      //     })
      //   }
      // })
    },

    emitOptions(dataSource, callback) {
      dataSource.forEach((data) => {
        let key = data[this.valueKey];
        this.dataSourceMap[key] = data;
        pushIfNotExist(
          this.options,
          { label: data[this.displayKey || this.valueKey], value: key },
          "value"
        );
        typeof callback === "function" ? callback(data) : "";
      });
      this.$emit("options", this.options, this.dataSourceMap);
    },

    /** 完成选择 */
    handleOk() {
      let value = this.selectedTable.dataSource.map(
        (data) => data[this.valueKey]
      );
      this.$emit("input", value);
      console.log(this.selectedTable.dataSource);
      this.$emit("commitData", this.selectedTable.dataSource);
      this.close();
    },

    /** 删除已选择的 */
    handleDeleteSelected(record, index) {
      this.selectionRows.splice(
        this.selectedRowKeys.indexOf(record[this.rowKey]),
        1
      );
      this.selectedRowKeys.splice(
        this.selectedRowKeys.indexOf(record[this.rowKey]),
        1
      );
      this.selectedTable.dataSource.splice(index, 1);
      console.log(this.selectedRowKeys, this.selectionRows);
    },

    customRowFn(record) {
      return {
        on: {
          click: () => {
            let key = record[this.rowKey];
            if (!this.multiple) {
              this.selectedRowKeys = [key];
              this.selectedTable.dataSource = [record];
            } else {
              let index = this.selectedRowKeys.indexOf(key);
              if (index === -1) {
                this.selectedRowKeys.push(key);
                this.selectedTable.dataSource.push(record);
              } else {
                this.handleDeleteSelected(record, index);
              }
            }
          },
        },
      };
    },
  },
};
</script>
<style lang="less" scoped>
</style>

这边的方法通单选框是一样的

5.关于没有封装的单选框表格同时要实现点击行增加单选框选中效果

<a-table
            style="width: 100%; margin-top: 50px"
            :rowKey="(record) => record.id"
            :dataSource="tableData"
            :columns="columns"
            :row-selection="{
              type: 'radio',
              onChange: onSelectChange,
              selectedRowKeys: selectedRowKeys,
            }"
            :customRow="customRowFn"
            @change="handleTableChange"
            :pagination="ipagination"
            :loading="tableLoading"
            bordered
          >
          </a-table>
data(){
return{
      tableSelectRow: {},
      selectedRowKeys: [],
   /* 分页参数 */
      ipagination: {
        current: 1,
        pageSize: 10,
        total: 0,
      },
}
}




method:{
//控制单选框
    onSelectChange(val, row) {
      console.log("val", val, "row", row);
      this.tableSelectRow = row[0];
      this.selectedRowKeys = val;
    },
//控制行customRowFn属性
 customRowFn(record) {
      return {
        on: {
          click: () => {
            // console.log("record", record);
            this.tableSelectRow = record;
            this.selectedRowKeys = [record.id];
            // console.log("this.tableSelectRow", this.tableSelectRow);
            // console.log("this.selectedRowKeys", this.selectedRowKeys);
          },
        },
      };
    },
    handleTableChange(pagination) {
      //分页、排序、筛选变化时触发
      this.ipagination = pagination;
      this.getlistassetstandardmodel();
    },
}


  // 资产型号确定
    chosmodelok() {
      console.log(this.assetsData);
      console.log(this.tableSelectRow);
      this.form.setFieldsValue({
        assetName: this.tableSelectRow.standardName,
        categoryId: this.tableSelectRow.categoryId,
        assetModel: this.tableSelectRow.standardModel,
        assetMetering: this.tableSelectRow.standardMetering,
      });
      (this.assetsData.categoryName = this.tableSelectRow.categoryName),
        (this.chosmodel = false);
    },

6.关于没有封装的单选框表格同时要实现点击行增加多选框选中效果

 <a-table
        :columns="columns"
        :data-source="dataSource"
        size="small"
        rowKey="id"
        :loading="loading"
        :pagination="ipagination"
        bordered
        :rowSelection="{
          selectedRowKeys: selectedRowKeys,
          onChange: onChangeTableSelect,
        }"
        :customRow="customRowFn"
        @change="handleTableChange"
      >
   selectedRowKeys: [],
    
   selectionRows: [],
 methods: {
    customRowFn(record) {
      return {
        on: {
          click: () => {
            // console.log("record", record);
            // this.tableSelectRow = record;
            // this.selectedRowKeys = [record.id];
            // console.log("this.tableSelectRow", this.tableSelectRow);
            // console.log("this.selectedRowKeys", this.selectedRowKeys);

            let key = record.id;
            let index = this.selectedRowKeys.indexOf(key);
            // console.log("index", index);
            if (index === -1) {
              this.selectedRowKeys.push(key);
              this.selectionRows.push(record);
            } else {
              this.selectionRows.splice(
                this.selectionRows.indexOf(record.id),
                1
              );
              this.selectedRowKeys.splice(
                this.selectedRowKeys.indexOf(record.id),
                1
              );
            }
            console.log("this.selectionRows", this.selectionRows);
          },
        },
      };
    },

    onChangeTableSelect(selectedRowKeys, selectionRows) {
      this.selectedRowKeys = selectedRowKeys;
      let mRow = JSON.parse(JSON.stringify(this.selectionRows));
      selectionRows.forEach((item) => {
        pushIfNotExist(mRow, item, "id");
      });
      this.selectionRows = this.selectedRowKeys.map((item) => {
        let mObj = {};
        mRow.forEach((items) => {
          if (items.id == item) {
            mObj = items;
          }
        });
        console.log(mObj);
        return mObj;
      });
      console.log(this.selectionRows);
    },
    clickShowModal(rows) {
      let mRows = JSON.parse(JSON.stringify(rows));
      this.onClearSelected();
      this.selectedRowKeys = mRows.map((item) => item.id);
      this.selectionRows = mRows;
      this.visible = true;
      this.loadData(1);
    },
    handleOk() {
      this.visible = false;
      this.$emit(
        "select",
        JSON.parse(JSON.stringify(this.selectedRowKeys)),
        JSON.parse(JSON.stringify(this.selectionRows))
      );
    },
  },
};

 这边表格分页效果是来自JeecgListMixin这个组件或者看5那边有单独写出来分页

/**
 * 新增修改完成调用 modalFormOk方法 编辑弹框组件ref定义为modalForm
 * 高级查询按钮调用 superQuery方法  高级查询组件ref定义为superQueryModal
 * data中url定义 list为查询列表  delete为删除单条记录  deleteBatch为批量删除
 */
import { filterObj } from "@/utils/util";
import { deleteAction, getAction, downFile, getFileAccessHttpUrl } from "@/api/manage";

export const JeecgListMixin = {
  data() {
    return {
      /* 查询条件-请不要在queryParam中声明非字符串值的属性 */
      queryParam: {},
      /* 数据源 */
      dataSource: [],
      /* 分页参数 */
      ipagination: {
        current: 1,
        pageSize: 10,
        pageSizeOptions: ["10", "20", "30"],
        showTotal: (total, range) => {
          return range[0] + "-" + range[1] + " 共" + total + "条";
        },
        showQuickJumper: true,
        showSizeChanger: true,
        total: 0,
      },
      /* 排序参数 */
      isorter: {
        column: "createTime",
        order: "desc",
      },
      /* 筛选参数 */
      filters: {},
      /* table加载状态 */
      loading: false,
      /* table选中keys*/
      selectedRowKeys: [],
      /* table选中records*/
      selectionRows: [],
      /* 查询折叠 */
      toggleSearchStatus: false,
      /* 高级查询条件生效状态 */
      superQueryFlag: false,
      /* 高级查询条件 */
      superQueryParams: "",
      /** 高级查询拼接方式 */
      superQueryMatchType: "and",
    };
  },
  created() {
    if (!this.disableMixinCreated) {
      console.log(" -- mixin created -- ");
      this.loadData();
      //初始化字典配置 在自己页面定义
      this.initDictConfig();
    }
  },
  computed: {},
  methods: {
    loadData(arg) {
      if (!this.url.list) {
        this.$message.error("请设置url.list属性!");
        return;
      }
      //加载数据 若传入参数1则加载第一页的内容
      if (arg === 1) {
        this.ipagination.current = 1;
      }
      var params = this.getQueryParams(); //查询条件
      this.loading = true;
      getAction(this.url.list, params)
        .then((res) => {
          if (res.ok) {
            //update-begin---author:zhangyafei    Date:20201118  for:适配不分页的数据列表------------
            this.dataSource = res.data.records || res.data;
            if (res.data.total) {
              this.ipagination.total = res.data.total;
            } else {
              this.ipagination.total = 0;
            }
            //update-end---author:zhangyafei    Date:20201118  for:适配不分页的数据列表------------
          } else {
            this.$message.warning(res.msg);
          }
        })
        .finally(() => {
          this.loading = false;
        });
    },
    initDictConfig() {
      console.log("--这是一个假的方法!");
    },
    handleSuperQuery(params, matchType) {
      //高级查询方法
      if (!params) {
        this.superQueryParams = "";
        this.superQueryFlag = false;
      } else {
        this.superQueryFlag = true;
        this.superQueryParams = JSON.stringify(params);
        this.superQueryMatchType = matchType;
      }
      this.loadData(1);
    },
    getQueryParams() {
      //获取查询条件
      let sqp = {};
      if (this.superQueryParams) {
        sqp["superQueryParams"] = encodeURI(this.superQueryParams);
        sqp["superQueryMatchType"] = this.superQueryMatchType;
      }
      var param = Object.assign(sqp, this.queryParam, this.isorter, this.filters);
      // param.field = this.getQueryField();
      param.current = this.ipagination.current;
      param.size = this.ipagination.pageSize;
      return filterObj(param);
    },
    getQueryField() {
      //TODO 字段权限控制
      var str = "id,";
      this.columns.forEach(function (value) {
        str += "," + value.dataIndex;
      });
      return str;
    },
    onSelectChange(selectedRowKeys, selectionRows) {
      this.selectedRowKeys = selectedRowKeys;
      this.selectionRows = selectionRows;
      console.log(selectedRowKeys, selectionRows);
    },
    onClearSelected() {
      this.selectedRowKeys = [];
      this.selectionRows = [];
    },
    searchQuery() {
      this.loadData(1);
    },
    superQuery() {
      this.$refs.superQueryModal.show();
    },
    searchReset() {
      this.queryParam = {};
      this.loadData(1);
    },
    batchDel: function () {
      if (!this.url.deleteBatch) {
        this.$message.error("请设置url.deleteBatch属性!");
        return;
      }
      if (this.selectedRowKeys.length <= 0) {
        this.$message.warning("请选择一条记录!");
        return;
      } else {
        var ids = "";
        for (var a = 0; a < this.selectedRowKeys.length; a++) {
          ids += this.selectedRowKeys[a] + ",";
        }
        var that = this;
        this.$confirm({
          title: "确认删除",
          content: "是否删除选中数据?",
          onOk: function () {
            that.loading = true;
            deleteAction(that.url.deleteBatch, { ids: ids })
              .then((res) => {
                if (res.success) {
                  //重新计算分页问题
                  that.reCalculatePage(that.selectedRowKeys.length);
                  that.$message.success(res.message);
                  that.loadData();
                  that.onClearSelected();
                } else {
                  that.$message.warning(res.message);
                }
              })
              .finally(() => {
                that.loading = false;
              });
          },
        });
      }
    },
    handleDelete: function (id) {
      if (!this.url.delete) {
        this.$message.error("请设置url.delete属性!");
        return;
      }
      var that = this;
      deleteAction(`${that.url.delete}/${id}`, { id: id }).then((res) => {
        if (res.ok) {
          //重新计算分页问题
          that.reCalculatePage(1);
          that.$message.success("操作成功");
          that.loadData();
        } else {
          that.$message.warning(res.msg);
        }
      });
    },
    reCalculatePage(count) {
      //总数量-count
      let total = this.ipagination.total - count;
      //获取删除后的分页数
      let currentIndex = Math.ceil(total / this.ipagination.pageSize);
      //删除后的分页数<所在当前页
      if (currentIndex < this.ipagination.current) {
        this.ipagination.current = currentIndex;
      }
      console.log("currentIndex", currentIndex);
    },
    handleEdit: function (record) {
      this.$refs.modalForm.edit(record);
      this.$refs.modalForm.title = "编辑";
      this.$refs.modalForm.disableSubmit = false;
    },
    handleAdd: function () {
      this.$refs.modalForm.add();
      this.$refs.modalForm.title = "新增";
      this.$refs.modalForm.disableSubmit = false;
    },
    handleTableChange(pagination, filters, sorter) {
      //分页、排序、筛选变化时触发
      //TODO 筛选
      console.log(pagination);
      if (Object.keys(sorter).length > 0) {
        // this.isorter.column = sorter.field;
        this.isorter.order = "ascend" == sorter.order ? "asc" : "desc";
      }
      this.ipagination = pagination;
      this.loadData();
    },
    handleToggleSearch() {
      this.toggleSearchStatus = !this.toggleSearchStatus;
    },
    // 给popup查询使用(查询区域不支持回填多个字段,限制只返回一个字段)
    getPopupField(fields) {
      return fields.split(",")[0];
    },
    modalFormOk() {
      // 新增/修改 成功时,重载列表
      this.loadData();
      //清空列表选中
      this.onClearSelected();
    },
    handleDetail: function (record) {
      this.$refs.modalForm.edit(record);
      this.$refs.modalForm.title = "详情";
      this.$refs.modalForm.disableSubmit = true;
    },
    /* 导出 */
    handleExportXls2() {
      let paramsStr = encodeURI(JSON.stringify(this.getQueryParams()));
      let url = `${window._CONFIG["domianURL"]}/${this.url.exportXlsUrl}?paramsStr=${paramsStr}`;
      window.location.href = url;
    },
    handleExportXls(fileName) {
      if (!fileName || typeof fileName != "string") {
        fileName = "导出文件";
      }
      let param = this.getQueryParams();
      if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
        param["selections"] = this.selectedRowKeys.join(",");
      }
      console.log("导出参数", param);
      downFile(this.url.exportXlsUrl, param).then((data) => {
        if (!data) {
          this.$message.warning("文件下载失败");
          return;
        }
        if (typeof window.navigator.msSaveBlob !== "undefined") {
          window.navigator.msSaveBlob(new Blob([data], { type: "application/vnd.ms-excel" }), fileName + ".xls");
        } else {
          console.log(data);
          let url = window.URL.createObjectURL(new Blob([data.data], { type: "application/vnd.ms-excel" }));
          let link = document.createElement("a");
          link.style.display = "none";
          link.href = url;
          link.setAttribute("download", fileName + ".xls");
          document.body.appendChild(link);
          link.click();
          document.body.removeChild(link); //下载完成移除元素
          window.URL.revokeObjectURL(url); //释放掉blob对象
        }
      });
    },
    /* 图片预览 */
    getImgView(text) {
      if (text && text.indexOf(",") > 0) {
        text = text.substring(0, text.indexOf(","));
      }
      return getFileAccessHttpUrl(text);
    },
    /* 文件下载 */
    // update--autor:lvdandan-----date:20200630------for:修改下载文件方法名uploadFile改为downloadFile------
    downloadFile(text) {
      if (!text) {
        this.$message.warning("未知的文件");
        return;
      }
      if (text.indexOf(",") > 0) {
        text = text.substring(0, text.indexOf(","));
      }
      let url = getFileAccessHttpUrl(text);
      window.open(url);
    },
  },
};

7.打印和导出写法

// 打印资产标签列表
const printAssetList = (fileName, params) => downloadFile("/asset/warehousing/printAssetList", fileName, params, "pdf"); // 打印资产标签列表
//导出资产列表
const warehousingExport = (fileName, params) => downloadFile("/asset/assetsinfo/export", fileName, params, "get"); // 导出资产列表
  // 打印资产
    clickAssetsPrint() {
      this.assetsPrintLoading = true;
      var mm = {};
      mm.id = this.selectedRows.map((item) => {
        return item.materialCode;
      });
      printAssetList("资产标签", mm)
        .then((res) => {
          this.assetsPrintLoading = false;
        })
        .catch((err) => {
          this.assetsPrintLoading = false;
        });

      // this.$refs.barCode.transferData(this.selectedRows)
    },
    // 导出资产
    getWarehousingExport() {
      var mm = {};
      mm.id = this.selectedRows.map((item) => {
        return item.materialCode;
      });
      warehousingExport("资产列表", mm).then((res) => {
        // let execlName = "资产文件名称";
        // const buf = Buffer.from(res),
        //   blob = new Blob([buf], { type: "application/vnd.ms-excel" }),
        //   downloadElement = document.createElement('a'),
        //   href = window.URL.createObjectURL(blob); // 创建下载的链接
        // downloadElement.href = href;
        // downloadElement.download = `${execlName}.xls`; // 下载后文件名
        // document.body.appendChild(downloadElement);
        // downloadElement.click(); // 点击下载
        // window.URL.revokeObjectURL(href); // 释放掉blob对象
      });
    },

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/685818.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【问题复盘】第三方接口变慢导致服务崩溃

一、事件经过 -1、一个不在公司的下午&#xff0c;接到客户投诉&#xff0c;说平台不能访问了。 0、介入调查&#xff0c;发现服务器http请求无法访问&#xff0c;https请求却可以正常访问&#xff0c;一时有些无法理解&#xff1b;&#xff08;后来发现&#xff0c;http和htt…

CMMI软件能力成熟度评估标准

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl CMMI概述 CMMI&#xff0c;全称为Capability Maturity Model Integration&#xff0c;即能力成熟度模型集成&#xff0c;是在原有的CMM&#xff08;Capability Maturity Mo…

C语言小例程8/100

题目&#xff1a;输出特殊图案&#xff0c;请在c环境中运行&#xff0c;看一看 程序分析&#xff1a;字符共有256个。不同字符&#xff0c;图形不一样。 #include<stdio.h> int main() {char a176,b219;printf("%c%c%c%c%c\n",b,a,a,a,b);printf("%c%c%c…

【Python报错】已解决ModuleNotFoundError: No module named ‘packaging’

成功解决“ModuleNotFoundError: No module named ‘packaging’”错误的全面指南 在Python编程中&#xff0c;遇到ModuleNotFoundError: No module named packaging这样的错误&#xff0c;通常意味着你的Python环境中缺少名为packaging的模块&#xff0c;或者该模块没有被正确…

达梦 执行查询语句时报[-544]:Out of sort buf space

达梦数据库有时执行SQL中有时报[-544]:Out of sort buf space, try to adjust SORT_BUF_GLOBAL_SIZE, SORT_BUF_SIZE, SORT_BLK_SIZE. 第一反应是这条语句占用排序区太大。但真实原因是前面执行的语句耗光了全局排序区&#xff0c;后面SQL任何小的排序操作都会报这个错误从而执…

『哈哥赠书 - 54期』-『架构思维:从程序员到CTO』

文章目录 ⭐️ 架构思维&#xff1a;从程序员到CTO⭐️ 本书简介⭐️ 作者简介⭐️ 编辑推荐⭐️ 不想成为架构师的程序员不是好CTO 在程序员的职业规划中&#xff0c;成为软件架构师是一个非常有吸引力的选择。但是对于如何才能成为一名架构师&#xff0c;不少同学认为只要代码…

用langchain搭配最新模型ollama打造属于自己的gpt

langchain 前段时间去玩了一下langchain,熟悉了一下大模型的基本概念&#xff0c;使用等。前段时间meta的ollama模型发布了3.0,感觉还是比较强大的&#xff0c;在了解过后&#xff0c;自己去用前后端代码&#xff0c;调用ollama模型搭建了一个本地的gpt应用。 核心逻辑 开始搭…

智谱 GLM4 模型开源,意料之中的尺寸,意料之外的效果

最近智谱开了GLM-4-9B的模型&#xff0c;不是6B&#xff0c;是9B。 一共开源了四个模型&#xff0c;Base版本模型&#xff08;GLM-4-9B&#xff09;、Chat版本模型&#xff08;GLM-4-9B-Chat和GLM-4-9B-Chat-1M&#xff09;和多模态模型&#xff08;GLM-4V-9B-Chat&#xff09…

Vue3的ref创建一个全局变量,非常好用!

1. 前言 Vue3的ref对象我们都知道其用法,通过ref可以创建一个响应式对象使用,同时可以用compute,watch等Vue3的API对其进行操作 不同于Vue2的是,Vue3使用的是组合式API,这也就意味着,我可以在外部单独创建一个ref对象,然后保存,通过导出的方式,给其他的页面使用 理论存在,开始…

SOA的发展历史

1.SOA的发展历程 回顾SOA发展历程&#xff0c;我们把其大致分为了三个阶段&#xff0c;下面将分别介绍每个阶段的重要标准和规范。 1.1.萌芽阶段 这一阶段以XML技术为标志&#xff0c;时间大致从20世纪90年代末到21世纪初。XML系W3C所建&#xff0c;源自流行的标准通用标记语…

course-nlp——8-translation-transformer

本文参考自https://github.com/fastai/course-nlp。 注意力机制和 Transformer Nvidia AI 研究员 Chip Huyen 写了一篇很棒的文章《Top 8 trends from ICLR 2019》&#xff0c;其中的趋势之一是 RNN 正在失去研究人员的青睐。 这是有原因的&#xff0c;RNN 可能很麻烦&#…

网络编程(UPD和TCP)

//发送数据 //UDP协议发送数据 package com.example.mysocketnet.a02UDPdemo;import java.io.IOException; import java.net.*;public class SendMessageDemo {public static void main(String[] args) throws IOException {//发送数据//1.创建DatagramSocket对象(快递公司)//…

MySQL--MHA高可用及读写分离

一、什么是高可用 1.企业级高可用标准&#xff1a;全年无故障时间 全年无故障时间全年故障时间具体时间99.9%0.1%525.6 minkeeplive双主 &#xff08;切换需要人为干预&#xff09;99.99%0.01%52.56 minMHA &#xff08;半自动化&#xff09;99.999%0.001%5.256 minPXC、MGR、…

超详细!新手入门PMP®考试指南,收藏起来备考更高效​!

回复数字“6”&#xff0c;查看PMP考试过关口诀 无论你是刚刚踏入项目管理领域的新手&#xff0c;对于PMP考试充满好奇与期待&#xff1b; 还是已经在职场中摸爬滚打多年&#xff0c;希望通过PMP认证来进一步提升自己的项目管理能力和职业竞争力。 相信这份指南都会为你提供…

超速解读多模态InternVL-Chat1.5 ,如何做到开源SOTA——非官方首发核心技巧版(待修订)

解读InternVL-chat1.5系列 最近并行是事情太杂乱了&#xff0c;静下心来看一看优秀的开源项目,但是AI技术迭代这么快&#xff0c;现在基本是同时看五、六个方向的技术架构和代码&#xff0c;哪个我都不想放&#xff0c;都想知道原理和代码细节&#xff0c;还要自己训练起来&am…

企业自建邮件系统的优势,安全性更高,功能更灵活,维护更便捷

在当今企业信息管理的浪潮中&#xff0c;企业邮件系统显得尤为关键&#xff0c;它不仅加强了内部的沟通效率&#xff0c;还对外展示了企业的专业形象。然而&#xff0c;传统租用企业邮箱服务存在一些不足&#xff0c;如缺乏灵活性、数据管理混乱和难以实现个性化需求&#xff0…

自定义Springboot Starter

创建一个Springboot Starter&#xff0c;借助该Starter我们可以自定义欢迎消息。 本Starter的内容不是重点&#xff0c;重点是创建Starter的流程。 1. 创建Starter工程 1.1 创建Springboot项目 1.2 导入相关依赖&#xff0c;删除spring-boot-maven-plugin <?xml version&…

【Python机器学习】预处理对监督学习的作用

还是用cancer数据集&#xff0c;观察使用MinMaxScaler对学习SVC的作用。 首先&#xff0c;在原始数据上拟合SVC&#xff1a; cancerload_breast_cancer() X_train,X_test,y_train,y_testtrain_test_split(cancer.data,cancer.target,random_state0 ) svmSVC(C100) svm.fit(X_t…

OpenCV的小部件最基本范例

OpenCV也有与PYQT类似的小部件&#xff0c;例如滑块slider。OpenCV可以用与PYQT类似的“信号与槽”方法&#xff0c;也可以在函数中直接查询小部件的值。 import cv2 import numpy as npcv2.namedWindow(Show1) image np.zeros((100, 400, 3), np.uint8) # 创建一个空白内容…

【WP】猿人学_19_乌拉乌拉乌拉

https://match.yuanrenxue.cn/match/19 发包测试 经过发包测试&#xff0c;并没有携带加密参数&#xff0c;但是使用python无法复现&#xff0c;requests&#xff0c;httpx以及异步都不行&#xff0c;网上搜索了一下&#xff0c;这是使用了JA3指纹。可能是我做的时间比较晚&…