<template>
  <PageContainer title="项目管理">
    <QueryToolbar>
      <el-form :inline="true" @submit.prevent class="project-page-toolbar">
        <el-form-item>
          <el-input v-model="queryName" placeholder="搜索项目名称" clearable class="w-input-md" />
        </el-form-item>
        <!-- <el-form-item>
          <el-checkbox v-model="includeDeleted">包含已删除</el-checkbox>
        </el-form-item> -->
        <el-form-item>
          <el-button v-if="canCreate" type="primary" @click="openCreateDrawer">新建项目</el-button>
          <el-button @click="load">刷新</el-button>
        </el-form-item>
      </el-form>
    </QueryToolbar>

    <el-table
      :data="filteredRows"
      row-key="id"
      lazy
      :load="loadSubProjects"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      class="mt-md project-page-table"
      empty-text="暂无数据"
    >
      <el-table-column prop="name" label="项目名称"  width="230"/>
      <!-- <el-table-column prop="subProjectCount" label="子项目数量"  /> -->
      <el-table-column prop="enterpriseName" label="合作企业"  />
      <!-- <el-table-column label="删除标记" >
        <template #default="{ row }">
          <el-tag v-if="row.deleted" type="danger" size="small">已删除</el-tag>
          <span v-else>-</span>
        </template>
      </el-table-column> -->
      <el-table-column prop="budgetCent" label="预算（元）"  :formatter="budgetFormatter" />
      <el-table-column label="费用合计（元）"  :formatter="projectFeeTotalFormatter" />
      <el-table-column prop="budgetExecutionRatio" label="预算执行率"  :formatter="executionRatioFormatter" />
      <el-table-column prop="meetingTotal" label="会议总期数" width="100"/>
      <el-table-column label="项目周期" width="200">
        <template #default="{ row }">{{ row.startDate || "-" }} ~ {{ row.endDate || "-" }}</template>
      </el-table-column>

      <el-table-column prop="status" label="状态" :formatter="statusFormatter" width="100"/>
      <el-table-column label="操作" width="400">
        <template #default="{ row }">
          <el-button v-if="canCreate" size="small" type="primary" @click="openCreateDrawer(row)">添加子项目</el-button>
          <el-button size="small" @click="openDetailDrawer(row)">详情</el-button>
          <el-button v-if="canCreate" size="small" type="primary" @click="openEditDrawer(row)">编辑</el-button>
          <el-button v-if="canCreateMeeting" size="small" type="primary" @click="handleCreateMeeting(row)">新建会议</el-button>
          <el-button v-if="canFreeze && row.status !== 'FROZEN' && row.status !== 'ARCHIVED'" size="small" type="warning" @click="handleFreeze(row.id)">冻结</el-button>
          <el-button v-if="canUnfreeze && row.status === 'FROZEN'" size="small" type="success" @click="handleUnfreeze(row.id)">解冻</el-button>
          <el-button v-if="canArchive && (row.status === 'COMPLETED' || row.status === 'FROZEN')" size="small" type="info" @click="handleArchive(row.id)">归档</el-button>
          <el-button v-if="canBindUser" size="small" @click="openBindingDialog(row.id)">绑定人员</el-button>
        </template>
      </el-table-column>
    </el-table>

    <ProjectEditDrawer
      v-model="projectDrawerVisible"
      :mode="projectDrawerMode"
      :source-row="projectDrawerSourceRow"
      :edit-id="projectDrawerEditId"
      @saved="load"
    />

    <el-drawer v-model="detailVisible" title="项目详情" size="65%">
      <el-descriptions :column="2" border v-if="currentProject">
        <el-descriptions-item label="项目名称">{{ currentProject.name || "-" }}</el-descriptions-item>
        <el-descriptions-item label="子项目数量">{{ currentProject.subProjectCount || 0 }}</el-descriptions-item>
        <el-descriptions-item label="上级项目ID">{{ currentProject.parentProjectId || "-" }}</el-descriptions-item>
        <el-descriptions-item label="主办单位">{{ currentProject.hostEnterpriseName || "-" }}</el-descriptions-item>
        <el-descriptions-item label="主办单位负责人">{{ currentProject.hostOwnerUsers || "-" }}</el-descriptions-item>
        <el-descriptions-item label="主办单位项目执行人">{{ currentProject.hostExecutorUsers || "-" }}</el-descriptions-item>
        <el-descriptions-item label="合作企业负责人">{{ currentProject.partnerOwnerUsers || "-" }}</el-descriptions-item>
        <el-descriptions-item label="合作企业项目执行人">{{ currentProject.partnerExecutorUsers || "-" }}</el-descriptions-item>
        <el-descriptions-item label="项目周期">{{ currentProject.startDate || "-" }} ~ {{ currentProject.endDate || "-" }}</el-descriptions-item>
        <el-descriptions-item label="项目预算(元)">{{ toYuan(currentProject.budgetCent) }}</el-descriptions-item>
        <el-descriptions-item label="管理费(元)">{{ toYuan(currentProjectFee.managementFeeCent) }}</el-descriptions-item>
        <el-descriptions-item label="税费(元)">{{ toYuan(currentProjectFee.taxFeeCent) }}</el-descriptions-item>
        <el-descriptions-item label="到款金额(元)">{{ toYuan(currentProjectFee.paidAmountCent) }}</el-descriptions-item>
        <el-descriptions-item label="自定义费用(元)">{{ customFeeText }}</el-descriptions-item>
        <el-descriptions-item label="会议总期数">{{ currentProject.meetingTotal || 0 }}</el-descriptions-item>
        <el-descriptions-item label="完成期数">{{ currentProject.meetingCompletedCount || 0 }}</el-descriptions-item>
        <el-descriptions-item label="项目状态">{{ toZhStatus(currentProject.status) }}</el-descriptions-item>

        <el-descriptions-item label="预算执行率">{{ formatExecutionRatio(currentProject.budgetExecutionRatio) }}</el-descriptions-item>
      </el-descriptions>
      <el-divider v-if="canKeyChangeLogRead">关键变更日志</el-divider>
      <el-table v-if="canKeyChangeLogRead" :data="keyChangeLogs" style="width: 100%">
        <el-table-column prop="fieldName" label="字段" width="180" />
        <el-table-column prop="changeType" label="动作" width="160" :formatter="statusFormatter" />
        <el-table-column prop="beforeValue" label="变更前" />
        <el-table-column prop="afterValue" label="变更后" />
        <el-table-column prop="changeReason" label="变更原因" width="150" />
        <el-table-column prop="operatorUserName" label="操作人" width="140" />
        <el-table-column prop="handoverAt" label="交接时间" width="180" />
        <el-table-column prop="createdAt" label="记录时间" width="180" />
      </el-table>
    </el-drawer>

    <el-dialog v-model="bindingVisible" title="绑定项目人员" :width="DIALOG_WIDTH.lg">
      <el-form label-position="left" :label-width="LABEL_WIDTH.lg">
        <el-form-item v-if="!isProjectExecutorRole" label="项目负责人">
          <div class="binding-select-field">
            <div v-if="ownerReadonlyBoundUsers.length" class="binding-readonly-block">
              <div class="binding-readonly-title">他人绑定，不可修改</div>
              <div class="binding-readonly-tags">
                <el-tag v-for="item in ownerReadonlyBoundUsers" :key="item.userId" type="info" effect="plain">
                  {{ formatBindingUserLabel(item) }}
                </el-tag>
              </div>
            </div>
            <el-select v-model="ownerEditableUserIds" multiple filterable clearable class="w-full">
              <el-option v-for="item in visibleOwnerCandidates" :key="item.userId" :label="`${item.userName}(${item.phone})`" :value="item.userId" />
            </el-select>
          </div>
        </el-form-item>
        <el-form-item v-if="!isProjectExecutorRole" label="项目执行人">
          <div class="binding-select-field">
            <div v-if="executorReadonlyBoundUsers.length" class="binding-readonly-block">
              <div class="binding-readonly-title">他人绑定，不可修改</div>
              <div class="binding-readonly-tags">
                <el-tag v-for="item in executorReadonlyBoundUsers" :key="item.userId" type="info" effect="plain">
                  {{ formatBindingUserLabel(item) }}
                </el-tag>
              </div>
            </div>
            <el-select v-model="executorEditableUserIds" multiple filterable clearable class="w-full">
              <el-option v-for="item in visibleExecutorCandidates" :key="item.userId" :label="`${item.userName}(${item.phone})`" :value="item.userId" />
            </el-select>
          </div>
        </el-form-item>
        <el-form-item v-if="canBindExecutorUser || isProjectExecutorRole" label="执行人(EXECUTOR)">
          <div class="binding-select-field">
            <div v-if="legacyExecutorReadonlyBoundUsers.length" class="binding-readonly-block">
              <div class="binding-readonly-title">他人绑定，不可修改</div>
              <div class="binding-readonly-tags">
                <el-tag v-for="item in legacyExecutorReadonlyBoundUsers" :key="item.userId" type="info" effect="plain">
                  {{ formatBindingUserLabel(item) }}
                </el-tag>
              </div>
            </div>
            <el-select v-model="legacyExecutorEditableUserIds" multiple filterable clearable class="w-full">
              <el-option v-for="item in visibleLegacyExecutorCandidates" :key="item.userId" :label="`${item.userName}(${item.phone})`" :value="item.userId" />
            </el-select>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="bindingVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSaveBindings">保存</el-button>
      </template>
    </el-dialog>
  </PageContainer>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import PageContainer from "../../components/PageContainer.vue";
import QueryToolbar from "../../components/QueryToolbar.vue";
import { DIALOG_WIDTH, LABEL_WIDTH } from "../../constants/ui";
import { ElMessage, ElMessageBox } from "element-plus";
import ProjectEditDrawer from "./project-page/ProjectEditDrawer.vue";
import {
  createMeeting,
  fetchMeetings,
  fetchProjectBindingCandidates,
  fetchProjectChildren,
  fetchProjectBindings,
  fetchProjectKeyChangeLogs,
  fetchProjects,
  freezeProject,
  unfreezeProject,
  archiveProject,
  saveProjectBindings,
} from "../../api/modules";
import { PERMS } from "../../constants/permissions";
import { useAuthStore } from "../../stores/auth";
import { toZhStatus } from "../../utils/status";

const rows = ref<any[]>([]);
const queryName = ref("");
const includeDeleted = ref(false);
const projectDrawerVisible = ref(false);
const projectDrawerMode = ref<"create" | "edit">("create");
const projectDrawerSourceRow = ref<any | null>(null);
const projectDrawerEditId = ref<number | null>(null);
const detailVisible = ref(false);
const bindingVisible = ref(false);
const currentProject = ref<any | null>(null);
const keyChangeLogs = ref<any[]>([]);
const ownerCandidates = ref<any[]>([]);
const executorCandidates = ref<any[]>([]);
const legacyExecutorCandidates = ref<any[]>([]);
const ownerBoundUsers = ref<any[]>([]);
const executorBoundUsers = ref<any[]>([]);
const legacyExecutorBoundUsers = ref<any[]>([]);
const ownerUserIds = ref<number[]>([]);
const executorUserIds = ref<number[]>([]);
const legacyExecutorUserIds = ref<number[]>([]);
const currentBindingProjectId = ref<number | null>(null);
const childrenCache = new Map<number, any[]>();
const authStore = useAuthStore();

const canCreate = computed(() => authStore.hasPermission(PERMS.project.create));
const canCreateMeeting = computed(() => authStore.hasPermission(PERMS.meeting.create));
const canFreeze = computed(() => authStore.hasPermission(PERMS.project.freeze));
const canUnfreeze = computed(() => authStore.hasPermission(PERMS.project.unfreeze));
const canArchive = computed(() => authStore.hasPermission(PERMS.project.archive));
const canBindUser = computed(() => authStore.hasPermission(PERMS.project.bindUser));
const canBindExecutorUser = computed(() => authStore.hasPermission(PERMS.project.bindExecutorUser));
const canKeyChangeLogRead = computed(() => authStore.hasPermission(PERMS.project.keyChangeLogRead));
const currentRoles = computed(() => authStore.roles || []);
const currentUserId = computed(() => Number(authStore.userId || 0) || null);
const isProjectExecutorRole = computed(() => currentRoles.value.includes("PROJECT_EXECUTOR"));
const toBindingUserId = (item: any) => Number(item?.userId || 0);
const normalizeBindingUserIds = (ids: unknown[]) =>
  Array.from(new Set((ids || []).map((item) => Number(item || 0)).filter((item) => item > 0)));
const isBindingUserEditableForCurrentUser = (item: any) => {
  if (!isProjectExecutorRole.value) return true;
  if (!currentUserId.value) return false;
  return Number(item?.createdBy || 0) === currentUserId.value;
};
const filterBindingCandidatesForCurrentUser = (candidates: any[]) => {
  return candidates.filter((item: any) => isBindingUserEditableForCurrentUser(item));
};
const filterReadonlyBoundUsersForCurrentUser = (users: any[]) => {
  if (!isProjectExecutorRole.value) return [];
  return users.filter((item: any) => !isBindingUserEditableForCurrentUser(item));
};
const buildEditableBindingUserIdsModel = (allUserIds: { value: number[] }, readonlyBoundUsers: { value: any[] }) =>
  computed<number[]>({
    get: () => {
      const readonlyIds = new Set(readonlyBoundUsers.value.map((item: any) => toBindingUserId(item)));
      return allUserIds.value.filter((item) => !readonlyIds.has(Number(item || 0)));
    },
    set: (value) => {
      allUserIds.value = normalizeBindingUserIds([
        ...readonlyBoundUsers.value.map((item: any) => toBindingUserId(item)),
        ...(value || []),
      ]);
    },
  });
const formatBindingUserLabel = (item: any) => {
  const name = String(item?.userName || "").trim();
  const phone = String(item?.phone || "").trim();
  const userId = toBindingUserId(item);
  if (name && phone) return `${name}(${phone})`;
  if (name) return name;
  if (phone) return phone;
  return userId ? `用户#${userId}` : "-";
};
const visibleOwnerCandidates = computed(() => filterBindingCandidatesForCurrentUser(ownerCandidates.value));
const visibleExecutorCandidates = computed(() => filterBindingCandidatesForCurrentUser(executorCandidates.value));
const visibleLegacyExecutorCandidates = computed(() => filterBindingCandidatesForCurrentUser(legacyExecutorCandidates.value));
const ownerReadonlyBoundUsers = computed(() => filterReadonlyBoundUsersForCurrentUser(ownerBoundUsers.value));
const executorReadonlyBoundUsers = computed(() => filterReadonlyBoundUsersForCurrentUser(executorBoundUsers.value));
const legacyExecutorReadonlyBoundUsers = computed(() => filterReadonlyBoundUsersForCurrentUser(legacyExecutorBoundUsers.value));
const ownerEditableUserIds = buildEditableBindingUserIdsModel(ownerUserIds, ownerReadonlyBoundUsers);
const executorEditableUserIds = buildEditableBindingUserIdsModel(executorUserIds, executorReadonlyBoundUsers);
const legacyExecutorEditableUserIds = buildEditableBindingUserIdsModel(legacyExecutorUserIds, legacyExecutorReadonlyBoundUsers);
const statusFormatter = (_row: any, _column: any, value: unknown) => toZhStatus(value);
const toYuan = (cent: unknown) => Number(((Number(cent) || 0) / 100).toFixed(2));
const formatExecutionRatio = (ratio: unknown) => `${((Number(ratio) || 0) * 100).toFixed(2)}%`;
const budgetFormatter = (_row: any, _column: any, value: unknown) => toYuan(value);
const executionRatioFormatter = (_row: any, _column: any, value: unknown) => formatExecutionRatio(value);
const projectFeeTotalFormatter = (row: any) => {
  const fee = parseProjectFee(row?.projectFeeJson);
  const total = (fee.managementFeeCent || 0)
    + (fee.taxFeeCent || 0)
    + (fee.paidAmountCent || 0)
    + (fee.customFees || []).reduce((acc: number, cur: { amountCent: number }) => acc + (cur.amountCent || 0), 0);
  return toYuan(total);
};
const parseProjectFee = (projectFeeJson: unknown) => {
  const defaults = {
    managementFeeCent: 0,
    taxFeeCent: 0,
    paidAmountCent: 0,
    customFees: [] as Array<{ name: string; amountCent: number; remark?: string }>,
  };
  if (!projectFeeJson) return defaults;
  try {
    const parsed = JSON.parse(String(projectFeeJson));
    return {
      managementFeeCent: Math.max(0, Number(parsed?.managementFeeCent) || 0),
      taxFeeCent: Math.max(0, Number(parsed?.taxFeeCent) || 0),
      paidAmountCent: Math.max(0, Number(parsed?.paidAmountCent) || 0),
      customFees: Array.isArray(parsed?.customFees)
        ? parsed.customFees
            .map((item: any) => ({
              name: String(item?.name || "").trim(),
              amountCent: Math.max(0, Number(item?.amountCent) || 0),
              remark: String(item?.remark || ""),
            }))
            .filter((item: { name: string }) => !!item.name)
        : [],
    };
  } catch (_e) {
    return defaults;
  }
};
const currentProjectFee = computed(() => parseProjectFee(currentProject.value?.projectFeeJson));
const customFeeText = computed(() =>
  currentProjectFee.value.customFees.length
    ? currentProjectFee.value.customFees.map((item: { name: string; amountCent: number }) => `${item.name}:${toYuan(item.amountCent)}元`).join("；")
    : "-",
);
const normalizeProjectRow = (row: any) => ({
  ...row,
  hasChildren: Number(row?.subProjectCount || 0) > 0,
});
const filteredRows = computed(() =>
  rows.value
    .map((row) => normalizeProjectRow(row))
    .filter((r) => !queryName.value || String(r.name || "").includes(queryName.value)),
);

const parseDateOnly = (value: unknown) => {
  const dateText = String(value || "").trim();
  if (!dateText) return null;
  const parsed = new Date(`${dateText}T00:00:00`);
  return Number.isNaN(parsed.getTime()) ? null : parsed;
};

const formatDateOnly = (value: Date) => {
  const y = value.getFullYear();
  const m = String(value.getMonth() + 1).padStart(2, "0");
  const d = String(value.getDate()).padStart(2, "0");
  return `${y}-${m}-${d}`;
};

const load = async () => {
  const resp = await fetchProjects({ parentOnly: true });
  rows.value = resp?.data?.list || [];
  childrenCache.clear();
};

const loadSubProjects = async (row: any, _treeNode: unknown, resolve: (data: any[]) => void) => {
  const projectId = Number(row?.id || 0);
  if (!projectId) {
    resolve([]);
    return;
  }
  if (childrenCache.has(projectId)) {
    resolve(childrenCache.get(projectId) || []);
    return;
  }
  const resp = await fetchProjectChildren(projectId);
  const children = (resp?.data || []).map((item: any) => normalizeProjectRow(item));
  childrenCache.set(projectId, children);
  resolve(children);
};

const openCreateDrawer = (parentRow?: any) => {
  projectDrawerMode.value = "create";
  projectDrawerSourceRow.value = parentRow || null;
  projectDrawerEditId.value = null;
  projectDrawerVisible.value = true;
};

const openEditDrawer = (row: any) => {
  projectDrawerMode.value = "edit";
  projectDrawerSourceRow.value = row || null;
  projectDrawerEditId.value = Number(row?.id || 0) || null;
  projectDrawerVisible.value = true;
};

const openDetailDrawer = async (row: any) => {
  currentProject.value = row;
  detailVisible.value = true;
  if (!canKeyChangeLogRead.value) {
    keyChangeLogs.value = [];
    return;
  }
  const resp = await fetchProjectKeyChangeLogs(row.id);
  keyChangeLogs.value = resp?.data || [];
};

const handleCreateMeeting = async (row: any) => {
  const meetingTotal = Math.floor(Number(row?.meetingTotal) || 0);
  if (meetingTotal <= 0) {
    ElMessage.warning("请先设置项目会议期数后再新建会议");
    return;
  }
  const projectStart = parseDateOnly(row?.startDate);
  const projectEnd = parseDateOnly(row?.endDate);
  if (!projectStart || !projectEnd || projectStart.getTime() > projectEnd.getTime()) {
    ElMessage.warning("请先完善项目周期后再新建会议");
    return;
  }

  const meetingResp = await fetchMeetings({ projectId: row.id });
  const existingMeetingCount = (meetingResp?.data?.list || []).length;
  if (existingMeetingCount >= meetingTotal) {
    ElMessage.warning(`该项目会议已达到总期数(${meetingTotal}期)，无法继续新建`);
    return;
  }

  const fee = parseProjectFee(row?.projectFeeJson);
  const customFeeCent = (fee.customFees || []).reduce((acc: number, cur: { amountCent: number }) => acc + (Number(cur?.amountCent) || 0), 0);
  const distributableBudgetCent = (Number(row?.budgetCent) || 0) - (Number(fee.managementFeeCent) || 0) - (Number(fee.taxFeeCent) || 0) - customFeeCent;
  const defaultMeetingBudgetCent = Math.floor(distributableBudgetCent / meetingTotal);
  if (defaultMeetingBudgetCent <= 0) {
    ElMessage.warning("项目可分配会议预算不足，请先检查项目预算或费用设置");
    return;
  }

  const now = new Date();
  const meetingDate = now >= projectStart && now <= projectEnd ? now : projectStart;
  const meetingDateText = formatDateOnly(meetingDate);
  const currentPeriod = existingMeetingCount + 1;
  await createMeeting({
    projectId: row.id,
    topic: `${row.name || "会议"}-第${currentPeriod}期`,
    budgetCent: defaultMeetingBudgetCent,
    laborRatio: Number(row?.laborFeeRatio) || 0,
    meetingCategory: "学术会",
    meetingForm: "线下",
    location: "线下",
    startTime: `${meetingDateText} 09:00:00`,
    endTime: `${meetingDateText} 18:00:00`,
  });
  ElMessage.success("会议创建成功");
};

const handleFreeze = async (id: number) => {
  const reason = await ElMessageBox.prompt("请输入冻结原因", "冻结项目", { confirmButtonText: "确定", cancelButtonText: "取消" }).catch(() => null);
  if (!reason) return;
  await freezeProject(id, reason.value);
  ElMessage.success("项目已冻结");
  await load();
};

const handleUnfreeze = async (id: number) => {
  const reason = await ElMessageBox.prompt("请输入解冻原因", "解冻项目", { confirmButtonText: "确定", cancelButtonText: "取消" }).catch(() => null);
  if (!reason) return;
  await unfreezeProject(id, { reason: reason.value });
  ElMessage.success("项目已解冻");
  await load();
};

const handleArchive = async (id: number) => {
  await ElMessageBox.confirm("归档后项目将不可编辑，确认归档？", "归档项目", { type: "warning" }).catch(() => null);
  try {
    await archiveProject(id);
    ElMessage.success("项目已归档");
    await load();
  } catch (_e) {
    // 用户取消或接口异常
  }
};

const ensureBindingCandidates = async () => {
  if (ownerCandidates.value.length > 0 || executorCandidates.value.length > 0 || legacyExecutorCandidates.value.length > 0) return;
  const resp = await fetchProjectBindingCandidates();
  ownerCandidates.value = resp?.data?.ownerUsers || [];
  executorCandidates.value = resp?.data?.executorUsers || [];
  legacyExecutorCandidates.value = resp?.data?.legacyExecutorUsers || [];
};

const openBindingDialog = async (projectId: number) => {
  await ensureBindingCandidates();
  const resp = await fetchProjectBindings(projectId);
  ownerBoundUsers.value = resp?.data?.ownerUsers || [];
  executorBoundUsers.value = resp?.data?.executorUsers || [];
  legacyExecutorBoundUsers.value = resp?.data?.legacyExecutorUsers || [];
  ownerUserIds.value = ownerBoundUsers.value.map((item: any) => item.userId);
  executorUserIds.value = executorBoundUsers.value.map((item: any) => item.userId);
  legacyExecutorUserIds.value = legacyExecutorBoundUsers.value.map((item: any) => item.userId);
  currentBindingProjectId.value = projectId;
  bindingVisible.value = true;
};

const handleSaveBindings = async () => {
  if (!currentBindingProjectId.value) return;
  await saveProjectBindings(currentBindingProjectId.value, {
    ownerUserIds: ownerUserIds.value,
    executorUserIds: executorUserIds.value,
    legacyExecutorUserIds: (canBindExecutorUser.value || isProjectExecutorRole.value) ? legacyExecutorUserIds.value : [],
  });
  ElMessage.success("绑定保存成功");
  bindingVisible.value = false;
};

onMounted(async () => {
  await load();
});
</script>

<style scoped>
/* :deep(.project-page-toolbar .el-form-item:nth-child(2)) {
  display: none;
} */

.binding-select-field {
  width: 100%;
}

.binding-readonly-block {
  margin-bottom: 8px;
}

.binding-readonly-title {
  margin-bottom: 6px;
  color: var(--el-text-color-secondary);
  font-size: 12px;
}

.binding-readonly-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
</style>
