<template>
  <div class="app-container">
    <el-row>
      <el-col :span="16">
        <el-form :model="queryParams" ref="queryRef" :inline="true" label-width="68px">
          <el-form-item label="任务名称">
            <el-input v-model="queryParams.jobName" style="width: 150px" placeholder="请输入任务名称"/>
          </el-form-item>
          <el-form-item label="任务状态">
            <el-select v-model="queryParams.jobStatus" class="noBorSel" placeholder="请选择任务状态"
                       style="width: 120px;">
              <el-option label="启用" :value="0"/>
              <el-option label="禁用" :value="1"/>
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="getTable">查询</el-button>
          </el-form-item>
        </el-form>
      </el-col>
      <el-col :span="8" style="display: flex;justify-content: right;">
        <el-button plain type="primary" @click="showAdd" style="margin-left:auto;" :icon="Plus">新增
        </el-button>
        <el-button type="danger" @click="delAll" plain style="margin-left:1%;" :icon="Delete">删除
        </el-button>
      </el-col>
    </el-row>
    <el-table
        :data="tableData"
        :cell-style="{ paddingTop:'3px',paddingBottom:'3px' }"
        :header-cell-style="{height: heightAll*0.01+'px',}"
        @selection-change="handleSelectionChange"
        :row-style="{ fontSize: '16px',textAlign:'center'}"
        border
        :height="tableheight">
      <el-table-column type="selection" width="55"/>
      <el-table-column type="index" label="序号" width="80"></el-table-column>
      <el-table-column prop="jobName" label="任务名称" width="160" v-if="showTablepane.rw">
        <template #default="scope">
          <el-button type="primary" @click="showDe(scope.row)" text style="margin-left: 1%;">
            {{ scope.row.jobName }}
          </el-button>
        </template>
      </el-table-column>
      <el-table-column prop="groupName" label="组名称" width="160" v-if="showTablepane.zm"/>
      <el-table-column prop="executorInfo" label="执行器名称" width="160" v-if="showTablepane.zx"/>
      <el-table-column prop="ownerName" label="负责人" width="160" v-if="showTablepane.fz"/>
      <el-table-column prop="nextTriggerAt" label="触发时间" width="180" v-if="showTablepane.cf">
      </el-table-column>
      <el-table-column prop="jobStatus" label="状态" width="170" v-if="showTablepane.zt">
        <template #default="scope">
          <el-switch @change="changejobStatus(scope.row)" v-model="scope.row.jobStatus"/>
        </template>
      </el-table-column>
      <el-table-column prop="taskType" label="任务类型" width="170" v-if="showTablepane.rwl">
        <template #default="scope">
          <el-tag v-if="scope.row.taskType==1" type="success">集群</el-tag>
          <el-tag v-if="scope.row.taskType==2" type="info">广播</el-tag>
          <el-tag v-if="scope.row.taskType==3" type="warning">Sharding</el-tag>
          <el-tag v-if="scope.row.taskType==4" type="danger">Map</el-tag>
          <el-tag v-if="scope.row.taskType==5">MapReduce</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="triggerType" label="触发类型" width="170" v-if="showTablepane.cfl">
        <template #default="scope">
          <el-tag v-if="scope.row.triggerType==2">固定时间</el-tag>
          <el-tag v-if="scope.row.triggerType==3">CRON 表达式</el-tag>
          <el-tag v-if="scope.row.triggerType==99">工作流</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="retryInterval" label="间隔时长" width="170" v-if="showTablepane.jg"/>
      <el-table-column prop="blockStrategy" label="阻塞策略" width="170" v-if="showTablepane.zs">
        <template #default="scope">
          <el-tag v-if="scope.row.blockStrategy==1">丢弃</el-tag>
          <el-tag v-if="scope.row.blockStrategy==2">覆盖</el-tag>
          <el-tag v-if="scope.row.blockStrategy==3">并行</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="executorTimeout" label="超时时间(秒)" width="170" v-if="showTablepane.cs"/>
      <el-table-column prop="updateDt" label="更新时间" width="170" v-if="showTablepane.gx"/>
      <el-table-column prop="address" label="操作" width="222" fixed="right">
        <template #default="scope">
          <div style="display: flex;justify-content: space-between;width: 100%;">
            <el-button type="primary" @click="showEdit(scope.row)" text style="margin-left: 1%;">编辑
            </el-button>
            <el-button @click="snaliTrigger(scope.row)" type="primary" text style="margin-left: 1%;">
              执行
            </el-button>
            <el-button @click="delRow(scope.row)" type="danger" text style="margin-left: 1%;">删除
            </el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>
  </div>

  <el-dialog :title="title" @close="clearForm" v-model="dialogVisible" title="" width="60%" destroy-on-close>
    <el-form style="margin-top: 0;width: 98%;" :model="formJi" label-position="right" ref="formRefJi"
             label-width="120px" :rules="rulesJi">
      <el-row :gutter="24">
        <el-col :span="8">
          <el-form-item label="任务名称:" prop="jobName" style="">
            <div style="display: flex;width: 100%;justify-content: space-between;">
              <el-input v-model="formJi.jobName" style="width: 100%;"/>
            </div>
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="负责人:" prop="" style="">
            <div style="display: flex;width: 100%;justify-content: space-between;">
              <el-input v-model="formJi.ownerName" style="width: 100%;"/>
            </div>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="48">
        <el-col :span="15">
          <!-- <el-form-item label="标签:" prop="" style="">
               <div
                  v-if="parTag.length==0"
                  @click='addTag'
                  style="
                  cursor: pointer;
                  display: flex;
                  justify-content: center;
                  align-items: center;
                  width: 200px;
                  height: 30px;
                  border: 0.5px dashed #c8c9cc;
                  border-radius: 8px;
                  position: relative;
                  "
              >
              +  &nbsp;添加
              </div>
              <div v-if="parTag.length!=0" v-for="(item,index) in parTag">
                  <div style="display: flex;align-items: center;margin-top: 3%;" :class="{ 'no-margin-top': index === 0 }">
                      <el-input  v-model="item.key" style="width: 50%;" resize="none" placeholder="key"/>
                      <div style="margin-left: 1%;">:</div>
                      <el-input  v-model="item.value" style="width: 50%;margin-left: 1%;" resize="none" placeholder="value"/>
                      <el-icon @click="delTag(index)" style="margin-left: 3%;color: red;cursor: pointer;"><Minus /></el-icon>
                      <el-icon @click="addTag" style="margin-left: 3%;color: #337ecc;cursor: pointer;"><Plus /></el-icon>
                  </div>
              </div>
          </el-form-item> -->
        </el-col>
      </el-row>
      <el-row :gutter="48">
        <el-col :span="8">
          <el-form-item label="状态:" prop="jobStatus">
            <el-radio-group :disabled="!isAddTa" v-model="formJi.jobStatus" class="custom-radio-group"
                            style="width: 100%;margin-top: -1%;">
              <el-radio :label="1">启用</el-radio>
              <el-radio :label="0">禁用</el-radio>
            </el-radio-group>
          </el-form-item>
        </el-col>

      </el-row>
      <el-row :gutter="48">
        <el-col :span="8">
          <el-form-item label="任务类型:" prop="taskType">
            <el-select
                v-model="formJi.taskType"
                class="noBorSel"
                placeholder=""
                style="width: 100%;margin-left: 0;"
            >
              <el-option
                  v-for="item in optionsTaskType"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
              />
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
      <div style="margin-top: 0;">
        <el-form-item label="任务配置:">
          <args-str v-model="formJi.argsStr"></args-str>
        </el-form-item>
        <el-row :gutter="48">
          <el-col :span="8">
            <el-form-item label="路由策略:" prop="routeKey">
              <el-select
                  v-model="formJi.routeKey"
                  class="noBorSel"
                  placeholder=""
                  style="width: 100%;margin-left: 0;"
              >
                <el-option label="Hash" :value="1"/>
                <el-option label="随机" :value="2"/>
                <el-option label="LRU" :value="3"/>
                <el-option label="轮询" :value="4"/>
                <el-option label="匹配第一个" :value="5"/>
                <el-option label="匹配最后一个" :value="6"/>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="阻塞策略:" prop="blockStrategy">
              <el-select
                  v-model="formJi.blockStrategy"
                  class="noBorSel"
                  placeholder=""
                  style="width: 100%;margin-left: 0;"
              >
                <el-option label="丢弃" :value="1"/>
                <el-option label="覆盖" :value="2"/>
                <el-option label="并行" :value="3"/>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="48">
          <el-col :span="8">
            <el-form-item label="触发类型:" prop="triggerType">
              <el-select
                  v-model="formJi.triggerType"
                  class="noBorSel"
                  placeholder=""
                  style="width: 100%;margin-left: 0;"
              >
                <el-option label="固定时间" :value="2"/>
                <el-option label="CRON 表达式" :value="3"/>
                <el-option label="工作流" :value="99"/>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="间隔时长:" prop="triggerInterval">
              <el-input v-model="formJi.triggerInterval" placeholder="请选择调度周期">
                <template #append>
                  <el-button type="primary" @click="handleShowCron" style="background-color: #2666fb; color: #fff">
                    配置
                    <i class="el-icon-time el-icon--right"></i>
                  </el-button>
                </template>
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="48">
          <el-col :span="8">
            <el-form-item label="超时时间(秒):" prop="executorTimeout">
              <el-input-number
                  v-model="formJi.executorTimeout"
                  style="width: 100%;"
                  class="mx-4"
                  :min="1"
                  :max="10"
                  controls-position="right"
              />
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="最大重试次数:" prop="maxRetryTimes">
              <el-input-number
                  v-model="formJi.maxRetryTimes"
                  style="width: 100%;"
                  class="mx-4"
                  :min="1"
                  :max="10"
                  controls-position="right"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="48">
          <el-col :span="8">
            <el-form-item label="重试间隔:" prop="retryInterval">
              <el-input-number
                  v-model="formJi.retryInterval"
                  style="width: 100%;"
                  class="mx-4"
                  :min="1"
                  :max="10"
                  controls-position="right"
              />
            </el-form-item>
          </el-col>
        </el-row>
        <el-form-item label="描述:">
          <el-input v-model="formJi.description" style="width: 75%;" placeholder="" type="textarea" :row="2"
                    resize="none"/>
        </el-form-item>
      </div>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button v-if="isAddTa" type="primary" @click="addTa">
          提交
        </el-button>
        <el-button v-if="!isAddTa" type="primary" @click="saveEditTa">
          提交
        </el-button>
      </span>
    </template>
  </el-dialog>
  <el-dialog @close="clearFromTree" v-model="dialogVisibleTree" title="" width="55%" destroy-on-close>
    <el-descriptions
        class="margin-top"
        :title="titleDe"
        style="padding-top: 2%;"
        :column="3"
        :size="size"
        border
    >
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            任务名称
          </div>
        </template>
        {{ formJi.jobName }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            组名称
          </div>
        </template>
        {{ formJi.groupName }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            负责人
          </div>
        </template>
        {{ formJi.ownerName }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            状态
          </div>
        </template>
        <el-tag>{{ formJi.jobStatus }}</el-tag>
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            任务类型
          </div>
        </template>
        {{ formJi.taskType }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            执行器名称
          </div>
        </template>
        {{ formJi.executorInfo }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            方法参数
          </div>
        </template>
        {{ formJi.argsStr }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            路由策略
          </div>
        </template>
        {{ formJi.routeKey }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            阻塞策略
          </div>
        </template>
        {{ formJi.blockStrategy }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            触发类型
          </div>
        </template>
        {{ formJi.triggerType }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            间隔时长
          </div>
        </template>
        {{ formJi.triggerInterval }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            超时时间(秒)
          </div>
        </template>
        {{ formJi.executorTimeout }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            最大重试次数
          </div>
        </template>
        {{ formJi.maxRetryTimes }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            重试间隔
          </div>
        </template>
        {{ formJi.retryInterval }}
      </el-descriptions-item>
      <el-descriptions-item>
        <template #label>
          <div class="cell-item">
            描述:
          </div>
        </template>
        {{ formJi.description }}
      </el-descriptions-item>
    </el-descriptions>
    <template #footer>
      <span class="dialog-footer">
        <el-button type="primary" @click="dialogVisibleTree = false">确定</el-button>
      </span>
    </template>
  </el-dialog>
  <el-dialog title="Cron表达式生成器" v-model="openCron" class="dialog" append-to-body destroy-on-close>
    <crontab ref="crontabRef" @hide="openCron = false" @fill="crontabFill" :expression="expression"></crontab>
  </el-dialog>
</template>
<script setup>
import {Delete, Plus} from '@element-plus/icons-vue'
import {onMounted, reactive, ref} from 'vue'
import {addSnail, delSnamil, snailDe, snailEdit, snailList, snailSta, snailTri} from "@/api/service/timing";
import ArgsStr from "@/views/dpp/task/integratioTask/argsStr.vue";
import Crontab from "@/components/Crontab/index.vue";
import {copyObj} from "codemirror/src/util/misc.js";

const queryParams = ref({
  jobName: '',
  jobStatus: null,
})
const {proxy} = getCurrentInstance();
const title = ref([])
const total = ref(1)
const tableData = ref([])
const tableheight = window.innerHeight * 0.8
const heightAll = window.innerHeight
const dialogVisible = ref(false)
const dialogVisibleTree = ref(false)
const isAddTa = ref(false)
const titleDe = ref('')
const optionsTaskType = ref([
  {
    label: '集群',
    value: 1
  },
  {
    label: '广播',
    value: 2
  },
  {
    label: 'Sharding',
    value: 3
  },
  {
    label: 'Map',
    value: 4
  },
  {
    label: 'MapReduce',
    value: 5
  },
])
const showTablepane = ref({
  rw: true,
  zm: true,
  zx: true,
  fz: true,
  bq: true,
  cf: true,
  zt: true,
  rwl: true,
  cfl: true,
  jg: true,
  zs: true,
  cs: true,
  gx: true,
})
const formJi = ref({
  jobName: '',
  groupName: '',
  jobStatus: '',
  taskType: '',
  executorInfo: '',
  executorInfoTy: '',
  type: '',
  mdContact: '',
  mdUnit: '',
  devUnit: '',
  devContact: '',
  deployDir: '',
  deployIp: '',
  deployPort: '',
  mirrorImageUrl: '',
  mdRunCmd: '',
  envOs: '',
  envDisk: '',
  envGpuMem: '11',
  evnArmX86: '',
  envCpuNum: '',
  envGpuType: '',
  envGpuNum: '2',
  envMem: '',
  mdInNote: '',
  mdOutNote: '',
  triggerInterval: ''
});
const selectedRows = ref([])
const rulesJi = reactive({
  jobName: [{required: true, message: '必填', trigger: 'blur'}],
  groupName: [{required: true, message: '必填', trigger: 'blur'}],
  taskType: [{required: true, message: '必填', trigger: 'blur'}],
  jobStatus: [{required: true, message: '必填', trigger: 'blur'}],
  executorInfo: [{required: true, message: '必填', trigger: 'blur'}],
  routeKey: [{required: true, message: '可选', trigger: 'blur'}],
  blockStrategy: [{required: true, message: '必填', trigger: 'blur'}],
  triggerInterval: [{required: true, message: '必填', trigger: 'blur'}],
  executorTimeout: [{required: true, message: '必填', trigger: 'blur'}],
  maxRetryTimes: [{required: true, message: '必填', trigger: 'blur'}],
  retryInterval: [{required: true, message: '必填', trigger: 'blur'}],
  triggerType: [{required: true, message: '必填', trigger: 'blur'}],
});
const formRefJi = ref();
const formTree = ref({
  itemName: '',
  catePid: '',
  itemNo: '',
  itemNotes: ''
});
let openCron = ref(false);
const expression = ref("");
const handleSelectionChange = (selection) => {
  selectedRows.value = selection;
};

function snaliTrigger(row) {
  var par = {
    jobId: row.id,
    taskType: row.taskType
  }
  snailTri(par).then(res => {
    if (res.code === 200) {
      proxy.$modal.msgSuccess(res.msg);
    }
  })
}

function showCode() {
  Object.keys(rulesJi).forEach(key => {
    delete rulesJi[key];
  });
  if (formJi.value.executorInfoTy === '自定义执行器') {
    Object.assign(rulesJi, {
      jobName: [{required: true, message: '必填', trigger: 'blur'}],
      groupName: [{required: true, message: '必填', trigger: 'blur'}],
      taskType: [{required: true, message: '必填', trigger: 'blur'}],
      jobStatus: [{required: true, message: '必填', trigger: 'blur'}],
      executorInfo: [{required: true, message: '必填', trigger: 'blur'}],
      routeKey: [{required: true, message: '可选', trigger: 'blur'}],
      blockStrategy: [{required: true, message: '必填', trigger: 'blur'}],
      triggerInterval: [{required: true, message: '必填', trigger: 'blur'}],
      executorTimeout: [{required: true, message: '必填', trigger: 'blur'}],
      maxRetryTimes: [{required: true, message: '必填', trigger: 'blur'}],
      retryInterval: [{required: true, message: '必填', trigger: 'blur'}],
      triggerType: [{required: true, message: '必填', trigger: 'blur'}],
    });
  }
  if (formJi.value.executorInfoTy === '内置执行器') {
    Object.assign(rulesJi, {
      jobName: [{required: true, message: '必填', trigger: 'blur'}],
      groupName: [{required: true, message: '必填', trigger: 'blur'}],
      taskType: [{required: true, message: '必填', trigger: 'blur'}],
      jobStatus: [{required: true, message: '必填', trigger: 'blur'}],
      executorInfo: [{required: true, message: '必填', trigger: 'blur'}],
      routeKey: [{required: true, message: '可选', trigger: 'blur'}],
      blockStrategy: [{required: true, message: '必填', trigger: 'blur'}],
      triggerInterval: [{required: true, message: '必填', trigger: 'blur'}],
      executorTimeout: [{required: true, message: '必填', trigger: 'blur'}],
      maxRetryTimes: [{required: true, message: '必填', trigger: 'blur'}],
      retryInterval: [{required: true, message: '必填', trigger: 'blur'}],
      triggerType: [{required: true, message: '必填', trigger: 'blur'}],
    });
  }
}

function delAll() {
  var parDel = ''
  selectedRows.value.forEach(item => {
    parDel = parDel + item.id + ','
  })
  parDel = parDel.slice(0, -1)
  proxy.$modal.confirm('是否确认删除？').then(function () {
    var par = {
      jobIds: parDel
    }
    return delSnamil(par);
  }).then(() => {
    getTable();
    proxy.$modal.msgSuccess("删除成功");
  }).catch(() => {
  });
}

function showDe(row) {
  dialogVisibleTree.value = true
  var par = {
    jobId: row.id
  }
  snailDe(par).then(res => {
    formJi.value = res.data
    if (formJi.value.jobStatus === 0) {
      formJi.value.jobStatus = '启用'
    }
    if (formJi.value.jobStatus === 1) {
      formJi.value.jobStatus = '关闭'
    }
  })
}

async function changejobStatus(row) {
  var par = {
    jobId: row.id,
    status: row.jobStatus === true ? 1 : 0
  }
  await snailSta(par).then(res => {
    formJi.value = res
    if (res.code === 200) {
      proxy.$modal.msgSuccess("修改成功");
    }
  })

}

function clearForm() {
  formJi.value = {}
}

function formatTimestamp(ms) {
  const date = new Date(ms);
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0'); // 补零
  const day = String(date.getDate()).padStart(2, '0'); // 补零
  return `${year}年${month}月${day}日`;
}

function getTable() {
  queryParams.value.executorInfo = 'cleanDataJob'
  snailList(queryParams.value).then(res => {
    tableData.value = res.rows
    tableData.value.forEach(item => {
      if (item.jobStatus === 0) {
        item.jobStatus = false
      }
      if (item.jobStatus === 1) {
        item.jobStatus = true
      }
      item.nextTriggerAt = formatTimestamp(item.nextTriggerAt)
    })
    total.value = res.total
  })
}

function showAdd() {
  isAddTa.value = true
  title.value = '新增'
  dialogVisible.value = true
  formJi.value = {
    taskType: 1,
    jobStatus: 1,
    routeKey: 4,
    blockStrategy: 1,
    triggerType: 3,
    executorTimeout: 60,
    maxRetryTimes: 3,
    retryInterval: 1,
  }
}

function showEdit(row) {
  isAddTa.value = false
  title.value = '编辑'
  dialogVisible.value = true
  var par = {
    jobId: row.id
  }
  snailDe(par).then(res => {
    formJi.value = res.data
  })
}

function clearFromTree() {
  formTree.value = {
    itemName: '',
    catePid: '',
    itemNo: '',
    itemNotes: ''
  }
}

function addTa() {
  formRefJi.value.validate(async (valid) => {
    if (valid) {
      formJi.value.executorInfo = 'cleanDataJob'
      formJi.value.argsStrMap = JSON.parse(formJi.value.argsStr)
      await addSnail(formJi.value).then(res => {
        if (res.code === 200) {
          proxy.$modal.msgSuccess("新增成功");
          getTable()
          dialogVisible.value = false
        }
      })
    }
  });
}

function saveEditTa() {
  formJi.value.executorInfo = 'cleanDataJob'
  formJi.value.argsStrMap = JSON.parse(formJi.value.argsStr)
  snailEdit(formJi.value).then(res => {
    if (res.code === 200) {
      proxy.$modal.msgSuccess("修改成功");
      dialogVisible.value = false
      getTable()
    }
  })
}

function delRow(row) {
  proxy.$modal.confirm('是否确认删除？').then(function () {
    var par = {
      jobIds: row.id
    }
    return delSnamil(par);
  }).then(() => {
    getTable();
    proxy.$modal.msgSuccess("删除成功");
  }).catch(() => {
  });
}

/** 调度周期按钮操作 */
function handleShowCron() {
  expression.value = formJi.value.triggerInterval;
  openCron.value = true;
}

/** 确定后回传值 */
function crontabFill(value) {
  formJi.value.triggerInterval = value;
}


onMounted(() => {
  getTable()
})
</script>
<style scoped>
.no-margin-top {
  margin-top: 0 !important;
}

.drag-handle {
  cursor: move;
}

.ghost {
  opacity: 0.5;
  background: #c8ebfb;
}

/* 防止文字选中 */
:deep(.el-table__row) {
  user-select: none;
  -webkit-user-select: none;
}
</style>
<style scoped lang="scss">


.el-table .el-table__row td {
  height: 60px !important; /* 行高 */
}

.custom-tree-node {
  display: flex; /* 启用 Flex 布局 */
  align-items: center; /* 垂直居中 */
  gap: 8px; /* 图标与文字间距 */
}

.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
</style>