zouyu
2026-04-20 e19cd654c14f000d7f77b2d23e016429678b1e58
用户管理表格支持拖拽排序
已修改3个文件
156 ■■■■ 文件已修改
src/api/system/user.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/performance/competency/index.vue 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/index.vue 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/user.js
@@ -216,7 +216,7 @@
// 更新用户排序
export function updateUserSort(data) {
  return request({
    url: "/system/user/updateUserSort",
    url: "/system/newUser/updateUserSort",
    method: "post",
    data:data
  });
src/views/performance/competency/index.vue
@@ -46,6 +46,7 @@
      </el-form-item>
    </el-form>
    <el-table
      ref="competencyTable"
      v-if="refreshTable"
      v-loading="loading"
      :data="recordList"
@@ -127,12 +128,12 @@
      levelDictList:[],
      tableHeight:0,
      downloadLoading:false,
      postList:[]
      postList:[],
      layoutTimer: null
    };
  },
  created() {
    this.getLevelDict()
    this.getTableHeader();
    this.getList();
    this.getPostList()
    this.$nextTick(()=>{
@@ -141,11 +142,29 @@
  },
  mounted() {
    window.addEventListener("resize", this.getTableHeight);
    this.scheduleTableLayout()
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.getTableHeight);
    if (this.layoutTimer) {
      clearTimeout(this.layoutTimer)
      this.layoutTimer = null
    }
  },
  methods: {
    scheduleTableLayout() {
      if (this.layoutTimer) {
        clearTimeout(this.layoutTimer)
      }
      this.layoutTimer = setTimeout(() => {
        this.$nextTick(() => {
          const table = this.$refs.competencyTable
          if (table && typeof table.doLayout === 'function') {
            table.doLayout()
          }
        })
      }, 0)
    },
    getPostList(){
      optionSelect().then(res=>{
        if(res.code===200){
@@ -171,6 +190,7 @@
      const innerHeight = window.innerHeight;
      const otherHeight = 50+46+40+51;
      this.tableHeight = innerHeight - otherHeight;
      this.scheduleTableLayout()
    },
    changeSkillLevel(row, itemId){
      const configObj = {...row[itemId]}
@@ -196,20 +216,25 @@
    getTableHeader() {
      listConfig({ isEnable: true }).then((response) => {
        this.tableHeaderList = this.handleTree(response.data, "id");
        this.scheduleTableLayout()
      });
    },
    /** 查询列表 */
    getList() {
      this.loading = true
      this.getTableHeader();
      getPageList(this.queryParams).then(res=>{
        if(res.code===200){
          this.recordList = res.data
      Promise.all([
        listConfig({ isEnable: true }),
        getPageList(this.queryParams)
      ]).then(([headerRes, listRes]) => {
        this.tableHeaderList = this.handleTree(headerRes.data, "id");
        if(listRes.code===200){
          this.recordList = listRes.data
        }
      }).catch(error=>{
        console.log(error)
      }).finally(() => {
          this.loading = false;
          this.scheduleTableLayout()
        });
    },
    /** 搜索按钮操作 */
src/views/system/user/index.vue
@@ -47,7 +47,7 @@
            </div>
          </div>
          <el-col>
            <el-table row-id="userId" ref="dragTable" v-loading="loading" :data="userList" :header-cell-style="{ background: '#f8f8f9', color: '#515a6e' }" border>
            <el-table ref="dragTable" v-loading="loading" row-key="userId" :data="userList" :header-cell-style="{ background: '#f8f8f9', color: '#515a6e' }" border>
              <el-table-column label="序号" align="center" type="index" />
              <el-table-column label="姓名" align="center" key="nickName" prop="nickName" :show-overflow-tooltip="true" />
              <el-table-column label="账号" align="center" key="userName" prop="userName" :show-overflow-tooltip="true" />
@@ -471,6 +471,7 @@
        nickName: '',
      },
      sortTable: null,
      sortSaving: false,
    };
  },
  watch: {
@@ -486,61 +487,102 @@
      this.initPassword = response.msg;
    });
  },
  mounted(){
    // 挂载后初始化拖拽
    this.initDrag()
  beforeDestroy() {
    this.destroyDrag()
  },
  methods: {
    //表格行拖拽排序
    // 表格行拖拽排序
    destroyDrag() {
      if (this.sortTable) {
        this.sortTable.destroy()
        this.sortTable = null
      }
    },
    syncDragDisabledState() {
      if (this.sortTable) {
        this.sortTable.option('disabled', this.loading || this.sortSaving)
      }
    },
    initDrag() {
      this.destroyDrag()
      if (!this.$refs.dragTable || !this.userList || this.userList.length === 0) {
        return
      }
      // 获取 el-table 的 tbody 元素(拖拽的目标容器)
      const tbody = this.$refs.dragTable.$el.querySelector(
        '.el-table__body-wrapper tbody'
      )
      if (!tbody) {
        return
      }
      // 初始化 Sortable
      this.sortable = Sortable.create(tbody, {
      this.sortTable = Sortable.create(tbody, {
        animation: 150, // 拖拽动画过渡时长
        ghostClass: 'sortable-ghost', // 拖拽占位符样式
        chosenClass: 'sortable-chosen', // 选中行样式
        dragClass: 'sortable-drag', // 拖拽元素样式
        disabled: this.loading || this.sortSaving,
        // 拖拽结束触发(核心逻辑)
        onEnd: ({ oldIndex, newIndex }) => {
          // oldIndex:原索引,newIndex:新索引
          const defNum = (this.queryParams.pageNum-1)*this.queryParams.pageSize
          // const row = this.userList[oldIndex]
          // let sort = newIndex+defNum;//排序下标
          const row = this.userList.splice(oldIndex, 1)[0]
          this.userList.splice(newIndex, 0, row)
          const data = this.userList.map(item=>{return {userId:item.userId,userName:item.userName}})
          console.log(data)
          console.log(this.userList)
          // 调用接口更新排序
          // let data = {
          //   userId:row.userId,
          //   sort: sort
          // }
          // updateUserSort(data).then(res=>{
          //   if(res.code===200){
          //     this.$message.success("更新成功")
          //     this.$nextTick(()=>{
          //       this.getList()
          //     })
          //   }
          // })
        onEnd: async({ oldIndex, newIndex }) => {
          if (
            this.loading ||
            this.sortSaving ||
            oldIndex === newIndex ||
            oldIndex === undefined ||
            newIndex === undefined
          ) {
            return
          }
        },
          const previousList = [...this.userList]
          const row = this.userList.splice(oldIndex, 1)[0]
          if (!row) {
            this.userList = previousList
            return
          }
          this.userList.splice(newIndex, 0, row)
          const pageOffset =
            (this.queryParams.pageNum - 1) * this.queryParams.pageSize
          const data = this.userList.map((item, index) => ({
            id: item.userId,
            sort: pageOffset + index + 1
          }))
          this.sortSaving = true
          this.syncDragDisabledState()
          try {
            await updateUserSort(data)
            this.$message.success('更新排序成功')
          } catch (error) {
            this.userList = previousList
            this.$message.error('更新排序失败')
          } finally {
            this.sortSaving = false
            this.$nextTick(() => {
              this.syncDragDisabledState()
            })
          }
        }
      })
    },
    /** 查询用户列表 */
    getList() {
      this.loading = true;
      this.loading = true
      this.syncDragDisabledState()
      listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
        this.userList = response.rows;
        this.total = response.total;
        this.loading = false;
      }
      );
        this.userList = response.rows
        this.total = response.total
        this.loading = false
        this.$nextTick(() => {
          this.initDrag()
        })
      }).catch(() => {
        this.loading = false
        this.destroyDrag()
      })
    },
    // 打开添加架构弹框
    addSchema() {
@@ -958,6 +1000,9 @@
</script>
<style scoped lang="scss">
:deep(.el-table__body-wrapper tbody tr) {
  cursor: move;
}
:deep(.sortable-ghost) {
  opacity: 0.8;
  background: #f0f9eb;