<script setup lang="tsx">
import { computed, markRaw, onMounted, reactive, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import type { TableInstance } from 'element-plus';
import { ElButton, ElTag, ElTooltip } from 'element-plus';
import dayjs from 'dayjs';
import {
  RDMS_REQ_CAN_DELETE_STATUS_DICT_CODE,
  RDMS_REQ_CATEGORY_DICT_CODE,
  RDMS_REQ_PRIORITY_DICT_CODE,
  RDMS_REQ_SOURCE_TYPE_DICT_CODE
} from '@/constants/dict';
import {
  fetchChangeRequirementStatus,
  fetchDeleteRequirement,
  fetchGetProductMembers,
  fetchGetProjectListByProductId,
  fetchGetRequirementAllowedTransitions,
  fetchGetRequirementStatusDict,
  fetchGetRequirementTerminalStatusDict,
  fetchGetRequirementTree,
  fetchHasDispatchedProjectRequirement
} from '@/service/api';
import { useAuth } from '@/hooks/business/auth';
import { useDict } from '@/hooks/business/dict';
import DictTag from '@/components/custom/dict-tag.vue';
import DictText from '@/components/custom/dict-text.vue';
import { useCurrentProduct } from '../shared/use-current-product';
import {
  ACTION_ICON_MAP,
  ACTION_TYPE_MAP,
  type RequirementStatusActionCode,
  getRequirementActionDisplayName,
  getRequirementStatusTagType,
  isRequirementActionNeedProject,
  isRequirementActionNeedReviewChoice,
  isRequirementActionTerminal
} from './shared/requirement-master-data';
import RequirementModuleTree from './modules/requirement-module-tree.vue';
import RequirementSearch from './modules/requirement-search.vue';
import RequirementCreateDialog from './modules/requirement-create-dialog.vue';
import RequirementDetailDialog from './modules/requirement-detail-dialog.vue';
import RequirementSplitDialog from './modules/requirement-split-dialog.vue';
import RequirementActionDialog from './modules/requirement-action-dialog.vue';
import IconMdiSync from '~icons/mdi/sync';

defineOptions({ name: 'ProductRequirement' });

const router = useRouter();
const { currentObjectId } = useCurrentProduct();
const { hasObjectAuth } = useAuth();

const statusOptions = ref<Array<{ label: string; value: string }>>([]);
const terminalStatusOptions = ref<string[]>([]);
const projectOptions = ref<Api.Project.Project[]>([]);

const projectNameMap = computed(() => {
  return new Map(projectOptions.value.map(item => [item.id, item.projectName]));
});

const { hasValue: canDeleteStatusHasValue } = useDict(RDMS_REQ_CAN_DELETE_STATUS_DICT_CODE);

async function loadStatusOptions() {
  const { error, data } = await fetchGetRequirementStatusDict();

  if (error || !data) {
    statusOptions.value = [];
    return;
  }

  statusOptions.value = data.map(item => ({
    label: item.statusName,
    value: item.statusCode
  }));
}

async function loadTerminalStatusOptions() {
  const { error, data } = await fetchGetRequirementTerminalStatusDict();

  if (error || !data) {
    terminalStatusOptions.value = [];
    return;
  }

  terminalStatusOptions.value = data.map(item => item.statusCode);
}

async function loadProjectOptions() {
  if (!currentObjectId.value) {
    projectOptions.value = [];
    return;
  }

  const { error, data } = await fetchGetProjectListByProductId(currentObjectId.value);

  if (error || !data) {
    projectOptions.value = [];
    return;
  }

  projectOptions.value = data;
}

function getStatusLabel(statusCode: string) {
  const item = statusOptions.value.find(opt => opt.value === statusCode);
  return item ? item.label : statusCode;
}

const priorityTagTypeMap: Record<number, UI.ThemeColor> = {
  0: 'info',
  1: 'primary',
  2: 'warning',
  3: 'danger'
};
const hasDispatchedMap = ref<Record<string, boolean>>({});

function formatDateTime(value?: string | null) {
  if (!value) {
    return '--';
  }

  return dayjs(value).format('YYYY-MM-DD HH:mm:ss');
}

function isTerminalStatus(statusCode: string) {
  return terminalStatusOptions.value.includes(statusCode);
}

function canSplitRequirement(row: Api.Product.Requirement) {
  if (row.implementProjectId) {
    return false;
  }
  const hasDispatched = hasDispatchedMap.value[row.id];
  if (hasDispatched) {
    return false;
  }
  return row.statusCode === 'pending_dispatch' || row.statusCode === 'implementing';
}

function canDeleteRequirement(row: Api.Product.Requirement) {
  const isStatusAllowed = canDeleteStatusHasValue(row.statusCode);
  const hasNoChildren = !row.children || row.children.length === 0;
  return isStatusAllowed && hasNoChildren;
}

const selectedModuleId = ref<string | undefined>('');
const memberOptions = ref<Api.Product.ProductMember[]>([]);
const requirementTableRef = ref<TableInstance>();
const loading = ref(false);
const treeData = ref<Api.Product.Requirement[]>([]);
const pagination = reactive({
  pageNo: 1,
  pageSize: 10,
  total: 0
});

const allowedTransitionsMap = ref<Map<string, Api.Product.RequirementLifecycleAction[]>>(new Map());

const searchParams = reactive({
  title: undefined as string | undefined,
  category: undefined as string | undefined,
  priority: undefined as Api.Product.RequirementPriority | undefined,
  statusCode: undefined as Api.Product.RequirementStatusCode | undefined,
  currentHandlerUserId: undefined as string | undefined,
  sourceType: undefined as Api.Product.RequirementSourceType | undefined
});

const createVisible = ref(false);
const detailVisible = ref(false);
const detailMode = ref<'view' | 'edit'>('view');
const selectedRequirement = ref<Api.Product.Requirement | null>(null);
const splitVisible = ref(false);
const splitParentRequirement = ref<Api.Product.Requirement | null>(null);

const actionVisible = ref(false);
const actionRequirement = ref<Api.Product.Requirement | null>(null);
const currentAction = ref<Api.Product.RequirementLifecycleAction | null>(null);

interface MemberUserOption {
  id: string;
  nickname: string;
  roleName: string;
}

const memberUserOptions = computed<MemberUserOption[]>(() => {
  return memberOptions.value
    .filter(m => m.status === 0)
    .map(m => ({
      id: m.userId,
      nickname: m.userNickname,
      roleName: m.roleName
    }));
});

const memberLabelMap = computed(() => {
  return new Map(memberUserOptions.value.map(item => [String(item.id), item.nickname]));
});

function getMemberLabel(userId?: string | null) {
  if (!userId) {
    return '--';
  }

  return memberLabelMap.value.get(String(userId)) || String(userId);
}

function getPriorityTagType(priority?: number | null): UI.ThemeColor {
  if (priority === null || priority === undefined) {
    return 'info';
  }

  return priorityTagTypeMap[priority] || 'info';
}

function flattenTree(nodes: Api.Product.Requirement[]): Api.Product.Requirement[] {
  const result: Api.Product.Requirement[] = [];
  for (const node of nodes) {
    result.push(node);
    if (node.children?.length) {
      result.push(...flattenTree(node.children));
    }
  }
  return result;
}

function collectAllRequirementIds(nodes: Api.Product.Requirement[]): string[] {
  const ids: string[] = [];
  for (const node of nodes) {
    ids.push(node.id);
    if (node.children?.length) {
      ids.push(...collectAllRequirementIds(node.children));
    }
  }
  return ids;
}

function collectRequirementIdsForActions(nodes: Api.Product.Requirement[]): string[] {
  const ids: string[] = [];
  for (const node of nodes) {
    const isTerminal = isTerminalStatus(node.statusCode);
    const hasDispatched = Boolean(node.implementProjectId);
    if (!isTerminal && !hasDispatched) {
      ids.push(node.id);
    }
    if (node.children?.length) {
      ids.push(...collectRequirementIdsForActions(node.children));
    }
  }
  return ids;
}

function collectRequirementIdsForSplitCheck(nodes: Api.Product.Requirement[]): string[] {
  const ids: string[] = [];
  for (const node of nodes) {
    if (!node.implementProjectId) {
      ids.push(node.id);
    }
    if (node.children?.length) {
      ids.push(...collectRequirementIdsForSplitCheck(node.children));
    }
  }
  return ids;
}

async function loadAllowedTransitionsForAll() {
  if (!currentObjectId.value) {
    allowedTransitionsMap.value = new Map();
    return;
  }

  const idsToQuery = collectRequirementIdsForActions(treeData.value);
  const newMap = new Map<string, Api.Product.RequirementLifecycleAction[]>();

  if (idsToQuery.length === 0) {
    allowedTransitionsMap.value = newMap;
    return;
  }

  const results = await Promise.all(
    idsToQuery.map(async id => {
      const { error, data } = await fetchGetRequirementAllowedTransitions(id, currentObjectId.value!);
      return { id, actions: error ? [] : data || [] };
    })
  );

  for (const { id, actions } of results) {
    newMap.set(id, actions);
  }

  allowedTransitionsMap.value = newMap;
}

async function loadHasDispatchedForAll() {
  if (!currentObjectId.value) {
    hasDispatchedMap.value = {};
    return;
  }

  const idsToQuery = collectRequirementIdsForSplitCheck(treeData.value);
  const newMap: Record<string, boolean> = {};

  if (idsToQuery.length === 0) {
    hasDispatchedMap.value = newMap;
    return;
  }

  await Promise.all(
    idsToQuery.map(async id => {
      const { data } = await fetchHasDispatchedProjectRequirement(id, currentObjectId.value!);
      newMap[id] = Boolean(data);
    })
  );

  hasDispatchedMap.value = newMap;
}

function getRowActions(row: Api.Product.Requirement): Api.Product.RequirementLifecycleAction[] {
  return allowedTransitionsMap.value.get(row.id) || [];
}

const columns = computed(() => [
  {
    type: 'index',
    label: '序号',
    width: 64,
    align: 'center',
    index: (index: number): number => {
      const flatList = flattenTree(treeData.value);
      const row = flatList[index];
      if (!row || row.parentId !== '0') {
        return 0;
      }
      const parentIndex = treeData.value.findIndex(item => item.id === row.id);
      return parentIndex >= 0 ? (pagination.pageNo - 1) * pagination.pageSize + parentIndex + 1 : 0;
    }
  },
  {
    prop: 'title',
    label: '需求名称',
    minWidth: 200,
    formatter: (row: Api.Product.Requirement) => {
      const className = 'requirement-title';

      return (
        <ElButton link type="primary" class={className} onClick={() => openView(row)}>
          {row.title}
        </ElButton>
      );
    }
  },
  {
    prop: 'priority',
    label: '优先级',
    width: 75,
    align: 'center',
    formatter: (row: Api.Product.Requirement) => (
      <DictTag dictCode={RDMS_REQ_PRIORITY_DICT_CODE} value={row.priority} type={getPriorityTagType(row.priority)} />
    )
  },
  {
    prop: 'statusCode',
    label: '状态',
    width: 100,
    align: 'center',
    formatter: (row: Api.Product.Requirement) => (
      <ElTag type={getRequirementStatusTagType(row.statusCode)}>{getStatusLabel(row.statusCode)}</ElTag>
    )
  },
  {
    prop: 'workHours',
    label: '所需工时',
    width: 75,
    align: 'center',
    formatter: (row: Api.Product.Requirement) => (row.workHours !== null ? `${row.workHours}h` : '--')
  },
  {
    prop: 'category',
    label: '需求类型',
    minWidth: 100,
    formatter: (row: Api.Product.Requirement) => row.category
  },
  {
    prop: 'sourceType',
    label: '需求来源',
    minWidth: 100,
    align: 'center',
    formatter: (row: Api.Product.Requirement) => (
      <DictText dictCode={RDMS_REQ_SOURCE_TYPE_DICT_CODE} value={row.sourceType} />
    )
  },
  // {
  //   prop: 'description',
  //   label: '内容',
  //   minWidth: 200,
  //   showOverflowTooltip: true,
  //   formatter: (row: Api.Product.Requirement) => {
  //     return row.description?.replace(/<[^>]+>/g, '').trim() || '--';
  //   }
  // },
  {
    prop: 'proposerNickname',
    label: '提出人',
    minWidth: 70,
    formatter: (row: Api.Product.Requirement) => row.proposerNickname || '--'
  },
  {
    prop: 'currentHandlerUserId',
    label: '负责人',
    minWidth: 70,
    formatter: (row: Api.Product.Requirement) => getMemberLabel(row.currentHandlerUserId)
  },
  {
    prop: 'sourceBizId',
    label: '来源业务编号',
    minWidth: 140,
    formatter: (row: Api.Product.Requirement) => {
      if (!row.sourceBizId || row.sourceType === 'manual') {
        return '--';
      }

      return (
        <ElButton link type="primary" class="requirement-source-link">
          {row.sourceBizId}
        </ElButton>
      );
    }
  },
  {
    prop: 'implementProjectId',
    label: '实现项目',
    minWidth: 140,
    formatter: (row: Api.Product.Requirement) => {
      if (!row.implementProjectId) return '--';
      const projectName = projectNameMap.value.get(row.implementProjectId) || row.implementProjectName || '--';
      return (
        <ElButton link type="primary" class="implement-project-link" onClick={() => handleImplementProjectClick(row)}>
          {projectName}
        </ElButton>
      );
    }
  },
  {
    prop: 'createTime',
    label: '创建时间',
    minWidth: 180,
    formatter: (row: Api.Product.Requirement) => formatDateTime(row.createTime)
  },
  {
    prop: 'operate',
    label: '操作',
    width: 200,
    align: 'center',
    fixed: 'right',
    formatter: (row: Api.Product.Requirement) => {
      const actions: {
        key: string;
        label: string;
        icon: object;
        type: 'primary' | 'success' | 'danger';
        disabled?: boolean;
        onClick: () => void;
      }[] = [];

      if (canSplitRequirement(row) && hasObjectAuth('project:product:split')) {
        actions.push({
          key: 'split',
          label: '拆分',
          icon: ACTION_ICON_MAP.split,
          type: ACTION_TYPE_MAP.split,
          onClick: () => openSplit(row)
        });
      }

      if (
        hasObjectAuth('project:product:update') &&
        !isTerminalStatus(row.statusCode) &&
        row.statusCode !== 'accepted' &&
        !row.implementProjectId
      ) {
        actions.push({
          key: 'edit',
          label: '编辑',
          icon: ACTION_ICON_MAP.edit,
          type: ACTION_TYPE_MAP.edit,
          onClick: () => openEdit(row)
        });
      }

      const lifecycleActions = getRowActions(row);
      const hasStatusAuth = hasObjectAuth('project:product:status');

      if (hasStatusAuth) {
        const nonTerminalActions: Api.Product.RequirementLifecycleAction[] = [];
        const terminalActions: Api.Product.RequirementLifecycleAction[] = [];

        for (const action of lifecycleActions) {
          const code = action.actionCode as RequirementStatusActionCode;
          if (isRequirementActionTerminal(code)) {
            terminalActions.push(action);
          } else {
            nonTerminalActions.push(action);
          }
        }

        for (const action of [...nonTerminalActions, ...terminalActions]) {
          actions.push({
            key: `action-${action.actionCode}`,
            label: getRequirementActionDisplayName(action),
            icon: ACTION_ICON_MAP[action.actionCode] ?? markRaw(IconMdiSync),
            type: ACTION_TYPE_MAP[action.actionCode] ?? 'primary',
            onClick: () => handleActionClick(row, action)
          });
        }
      }

      if (canDeleteRequirement(row) && hasObjectAuth('project:product:delete')) {
        actions.push({
          key: 'delete',
          label: '删除',
          icon: ACTION_ICON_MAP.delete,
          type: ACTION_TYPE_MAP.delete,
          onClick: () => handleDelete(row)
        });
      }

      return (
        <div class="requirement-action-cell" onClick={event => event.stopPropagation()}>
          {actions.map(action => {
            const IconComponent = action.icon as any;
            return (
              <ElTooltip key={action.key} content={action.label} placement="top">
                <ElButton
                  link
                  size="small"
                  class="requirement-action-icon-btn"
                  type={action.type}
                  onClick={() => action.onClick()}
                >
                  <IconComponent class="text-18px" />
                </ElButton>
              </ElTooltip>
            );
          })}
        </div>
      );
    }
  }
]);

const columnChecks = ref<UI.TableColumnCheck[]>([]);

watch(
  () => columns.value,
  cols => {
    const existingMap = new Map(columnChecks.value.map(c => [c.prop, c.checked]));
    columnChecks.value = cols
      .filter(col => col.prop && col.prop !== 'operate')
      .map(col => ({
        prop: String(col.prop),
        label: String(col.label || ''),
        checked: existingMap.has(String(col.prop)) ? existingMap.get(String(col.prop))! : true,
        visible: true
      }));
  },
  { immediate: true }
);

const visibleColumns = computed(() => {
  if (columnChecks.value.length === 0) return columns.value;
  const visibleSet = new Set(columnChecks.value.filter(c => c.checked).map(c => c.prop));
  return columns.value.filter(col => {
    const prop = String(col.prop || '');
    if (!prop) return true;
    if (prop === 'operate') return true;
    return visibleSet.has(prop);
  });
});

async function loadMembers() {
  if (!currentObjectId.value) {
    memberOptions.value = [];
    return;
  }

  const { error, data: members } = await fetchGetProductMembers(currentObjectId.value);

  if (error || !members) {
    memberOptions.value = [];
    return;
  }

  memberOptions.value = members;
}

async function loadTreeData() {
  if (!currentObjectId.value) {
    treeData.value = [];
    pagination.total = 0;
    return;
  }

  const { error, data } = await fetchGetRequirementTree({
    productId: currentObjectId.value,
    moduleId: selectedModuleId.value,
    pageNo: pagination.pageNo,
    pageSize: pagination.pageSize,
    title: searchParams.title,
    category: searchParams.category,
    priority: searchParams.priority,
    statusCode: searchParams.statusCode,
    currentHandlerUserId: searchParams.currentHandlerUserId,
    sourceType: searchParams.sourceType
  });

  if (error || !data) {
    treeData.value = [];
    pagination.total = 0;
    return;
  }

  treeData.value = data.list;
  pagination.total = data.total;
}

async function reloadTable() {
  loading.value = true;
  try {
    await loadTreeData();
    await loadAllowedTransitionsForAll();
    await loadHasDispatchedForAll();
  } finally {
    loading.value = false;
  }
}

function handleModuleSelect(moduleId: string | undefined) {
  selectedModuleId.value = moduleId;
  pagination.pageNo = 1;
  reloadTable();
}

function handleSearch() {
  pagination.pageNo = 1;
  reloadTable();
}

function handleResetSearch() {
  searchParams.title = undefined;
  searchParams.category = undefined;
  searchParams.priority = undefined;
  searchParams.statusCode = undefined;
  searchParams.currentHandlerUserId = undefined;
  searchParams.sourceType = undefined;
  pagination.pageNo = 1;
  reloadTable();
}

function handlePageChange(page: number) {
  pagination.pageNo = page;
  reloadTable();
}

function handleSizeChange(size: number) {
  pagination.pageNo = 1;
  pagination.pageSize = size;
  reloadTable();
}

function openCreate() {
  selectedRequirement.value = null;
  createVisible.value = true;
}

function openView(row: Api.Product.Requirement) {
  selectedRequirement.value = row;
  detailMode.value = 'view';
  detailVisible.value = true;
}

function openEdit(row: Api.Product.Requirement) {
  selectedRequirement.value = row;
  detailMode.value = 'edit';
  detailVisible.value = true;
}

function openSplit(row: Api.Product.Requirement) {
  splitParentRequirement.value = row;
  splitVisible.value = true;
}

async function handleImplementProjectClick(row: Api.Product.Requirement) {
  if (!row.implementProjectId) return;

  router.push({
    path: '/project/project/requirement',
    query: {
      objectId: row.implementProjectId
    }
  });
}

function handleActionClick(row: Api.Product.Requirement, action: Api.Product.RequirementLifecycleAction) {
  const actionCode = action.actionCode as RequirementStatusActionCode;

  if (
    !isRequirementActionNeedReviewChoice(actionCode) &&
    !isRequirementActionNeedProject(actionCode) &&
    !isRequirementActionTerminal(actionCode)
  ) {
    handleDirectAction(row, action);
    return;
  }

  actionRequirement.value = row;
  currentAction.value = action;
  actionVisible.value = true;
}

async function handleDirectAction(row: Api.Product.Requirement, action: Api.Product.RequirementLifecycleAction) {
  if (!currentObjectId.value) return;

  try {
    await window.$messageBox?.confirm(`确定要执行"${action.actionName}"操作吗？`, '确认操作', {
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      type: 'info'
    });
  } catch {
    return;
  }

  const { error } = await fetchChangeRequirementStatus({
    id: row.id,
    productId: currentObjectId.value,
    actionCode: action.actionCode
  });

  if (error) {
    return;
  }

  window.$message?.success(`${action.actionName}成功`);
  await reloadTable();
}

async function handleActionSubmitted(payload: { actionCode: string; reason?: string; implementProjectId?: string }) {
  if (!currentObjectId.value || !actionRequirement.value) return;

  const { error } = await fetchChangeRequirementStatus({
    id: actionRequirement.value.id,
    productId: currentObjectId.value,
    actionCode: payload.actionCode,
    reason: payload.reason,
    implementProjectId: payload.implementProjectId
  });

  if (error) {
    return;
  }

  window.$message?.success('操作成功');
  actionVisible.value = false;
  await reloadTable();
}

async function handleDelete(row: Api.Product.Requirement) {
  if (!currentObjectId.value) return;

  try {
    await window.$messageBox?.confirm('确定要删除该需求吗？删除后不可恢复。', '删除确认', {
      confirmButtonText: '确认删除',
      cancelButtonText: '取消',
      type: 'warning'
    });
  } catch {
    return;
  }

  const { error } = await fetchDeleteRequirement({
    id: row.id,
    productId: currentObjectId.value
  });

  if (error) {
    return;
  }

  window.$message?.success('需求删除成功');
  await reloadTable();
}

async function handleCreateSubmitted() {
  createVisible.value = false;
  await reloadTable();
}

async function handleDetailSubmitted() {
  detailVisible.value = false;
  await reloadTable();
}

async function handleSplitSubmitted() {
  splitVisible.value = false;
  await reloadTable();
}

watch(
  () => currentObjectId.value,
  async id => {
    if (id) {
      await Promise.all([loadMembers(), loadTreeData(), loadProjectOptions()]);
      await loadAllowedTransitionsForAll();
      await loadHasDispatchedForAll();
    } else {
      memberOptions.value = [];
      treeData.value = [];
      projectOptions.value = [];
      allowedTransitionsMap.value = new Map();
    }
  },
  { immediate: true }
);

onMounted(async () => {
  await Promise.all([loadStatusOptions(), loadTerminalStatusOptions()]);
});
</script>

<template>
  <div
    class="min-h-560px gap-16px overflow-hidden xl:grid xl:grid-cols-[280px_minmax(0,1fr)] lt-xl:flex lt-xl:flex-col lt-xl:overflow-auto"
  >
    <div class="flex-col-stretch gap-16px xl:min-h-0">
      <RequirementModuleTree :requirement-tree="treeData" @select="handleModuleSelect" @refresh="reloadTable" />
    </div>

    <div class="flex-col-stretch gap-16px xl:min-h-0">
      <RequirementSearch
        v-model:model="searchParams"
        :member-options="memberUserOptions"
        :category-dict-code="RDMS_REQ_CATEGORY_DICT_CODE"
        :priority-dict-code="RDMS_REQ_PRIORITY_DICT_CODE"
        @reset="handleResetSearch"
        @search="handleSearch"
      />

      <ElCard class="card-wrapper xl:flex-1-hidden" body-class="requirement-table-card-body">
        <template #header>
          <div class="flex items-center justify-between gap-12px">
            <div class="flex flex-wrap items-center gap-8px">
              <p>需求列表</p>
              <ElTag effect="plain">{{ pagination.total }} 条</ElTag>
            </div>
            <TableHeaderOperation v-model:columns="columnChecks" :loading="loading" @refresh="reloadTable">
              <template #default>
                <ElButton
                  v-auth="{ code: 'project:product:create', source: 'object' }"
                  plain
                  type="primary"
                  @click="openCreate"
                >
                  <template #icon>
                    <icon-ic-round-plus class="text-icon" />
                  </template>
                  新增
                </ElButton>
              </template>
            </TableHeaderOperation>
          </div>
        </template>

        <div class="flex-1">
          <ElTable
            ref="requirementTableRef"
            v-loading="loading"
            border
            lazy
            row-key="id"
            :indent="32"
            height="100%"
            :data="treeData"
            :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
          >
            <ElTableColumn v-for="col in visibleColumns" :key="String(col.prop || 'index')" v-bind="col" />

            <template #empty>
              <ElEmpty description="当前模块下暂无需求" />
            </template>
          </ElTable>
        </div>

        <div class="mt-16px flex justify-end">
          <ElPagination
            v-model:current-page="pagination.pageNo"
            v-model:page-size="pagination.pageSize"
            :total="pagination.total"
            :page-sizes="[10, 15, 20, 25, 30]"
            layout="total, sizes, prev, pager, next, jumper"
            @current-change="handlePageChange"
            @size-change="handleSizeChange"
          />
        </div>
      </ElCard>
    </div>

    <RequirementCreateDialog
      v-model:visible="createVisible"
      :product-id="currentObjectId || ''"
      :default-module-id="selectedModuleId"
      :member-options="memberOptions"
      :category-dict-code="RDMS_REQ_CATEGORY_DICT_CODE"
      :priority-dict-code="RDMS_REQ_PRIORITY_DICT_CODE"
      @submitted="handleCreateSubmitted"
    />

    <RequirementDetailDialog
      v-model:visible="detailVisible"
      :mode="detailMode"
      :requirement="selectedRequirement"
      :product-id="currentObjectId || ''"
      :member-options="memberOptions"
      :category-dict-code="RDMS_REQ_CATEGORY_DICT_CODE"
      :priority-dict-code="RDMS_REQ_PRIORITY_DICT_CODE"
      @submitted="handleDetailSubmitted"
    />

    <RequirementSplitDialog
      v-model:visible="splitVisible"
      :parent-requirement="splitParentRequirement"
      :product-id="currentObjectId || ''"
      :member-options="memberOptions"
      :category-dict-code="RDMS_REQ_CATEGORY_DICT_CODE"
      :priority-dict-code="RDMS_REQ_PRIORITY_DICT_CODE"
      @submitted="handleSplitSubmitted"
    />

    <RequirementActionDialog
      v-model:visible="actionVisible"
      :action="currentAction"
      :requirement-title="actionRequirement?.title || ''"
      :project-options="projectOptions"
      @submitted="handleActionSubmitted"
    />
  </div>
</template>

<style lang="scss" scoped>
:deep(.requirement-table-card-body) {
  height: calc(100% - 56px);
  display: flex;
  flex-direction: column;
}

:deep(.requirement-title) {
  padding: 0;
  font-weight: 500;
}

:deep(.requirement-title--terminal) {
  padding: 0;
  text-decoration: line-through;
  opacity: 0.6;
}

:deep(.requirement-source-link) {
  padding: 0;
}

:deep(.implement-project-link) {
  padding: 0;
  font-weight: 500;
}

:deep(.el-table__row[class*='el-table__row--level-']:not(.el-table__row--level-0) td:first-child .cell) {
  color: transparent;
}

:deep(.requirement-action-cell) {
  display: inline-flex;
  align-items: center;
  gap: 1px;
}

:deep(.requirement-action-icon-btn) {
  padding: 1px;
  height: auto;
  min-width: auto;
}

:deep(.requirement-action-icon-btn:hover) {
  background-color: var(--el-fill-color-light);
}
</style>
