<script setup lang="tsx">
import { computed, markRaw, reactive, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
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
} from '@/constants/dict';
import { getStatusTagType } from '@/constants/status-tag';
import {
  fetchChangeProjectRequirementStatus,
  fetchDeleteProjectRequirement,
  fetchGetProjectMembers,
  fetchGetProjectRequirementAllowedTransitionsBatch,
  fetchGetProjectRequirementStatusDict,
  fetchGetProjectRequirementTree
} from '@/service/api';
import { useAuth } from '@/hooks/business/auth';
import { useDict } from '@/hooks/business/dict';
import DictTag from '@/components/custom/dict-tag.vue';
import { useCurrentProject } from '../../shared/use-current-project';
import {
  ACTION_ICON_MAP,
  DEFAULT_ACTION_ICON,
  getProjectRequirementActionButtonType,
  getProjectRequirementActionDisplayName,
  getProjectRequirementActionIcon,
  isProjectRequirementActionTerminal
} from './shared/requirement-master-data';
import RequirementActionDialog from './modules/requirement-action-dialog.vue';
import RequirementCreateDialog from './modules/requirement-create-dialog.vue';
import RequirementDetailDialog from './modules/requirement-detail-dialog.vue';
import RequirementModuleTree from './modules/requirement-module-tree.vue';
import RequirementSearch from './modules/requirement-search.vue';
import RequirementSplitDialog from './modules/requirement-split-dialog.vue';
import RequirementReviewDialog from './modules/requirement-review-dialog.vue';
import RequirementReviewRecordDialog from './modules/requirement-review-record-dialog.vue';
import IconMdiEyeOutline from '~icons/mdi/eye-outline';
import IconMdiPencilOutline from '~icons/mdi/pencil-outline';

defineOptions({ name: 'ProjectRequirement' });

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

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

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

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

  return dayjs(value).format('YYYY-MM-DD');
}

function createSearchParams(): Api.Project.ProjectRequirementSearchParams {
  return {
    projectId: '',
    pageNo: 1,
    pageSize: 10,
    title: '',
    moduleId: undefined,
    parentId: undefined,
    category: undefined,
    priority: undefined,
    statusCode: undefined,
    currentHandlerUserId: undefined,
    sourceBizCode: undefined
  };
}

const router = useRouter();
const { currentObjectId, currentProject } = useCurrentProject();
const { hasObjectAuth } = useAuth();
const { hasValue: canDeleteStatusHasValue } = useDict(RDMS_REQ_CAN_DELETE_STATUS_DICT_CODE);

const statusDict = ref<Api.Project.ProjectRequirementStatusDict[]>([]);
const memberOptions = ref<Api.Project.ProjectMember[]>([]);
const treeData = ref<Api.Project.ProjectRequirement[]>([]);
const requirementDisplayTotal = ref(0);
const loading = ref(false);
const selectedModuleId = ref<string | undefined>('');
const searchParams = reactive(createSearchParams());
const pagination = reactive({
  pageNo: 1,
  pageSize: 10,
  total: 0
});

const createVisible = ref(false);
const detailVisible = ref(false);
const detailMode = ref<'view' | 'edit'>('view');
const selectedRequirement = ref<Api.Project.ProjectRequirement | null>(null);
const splitVisible = ref(false);
const splitParentRequirement = ref<Api.Project.ProjectRequirement | null>(null);
const actionVisible = ref(false);
const actionRequirement = ref<Api.Project.ProjectRequirement | null>(null);
const currentAction = ref<Api.Project.ProjectRequirementLifecycleAction | null>(null);
const allowedTransitionsMap = ref<Map<string, Api.Project.ProjectRequirementLifecycleAction[]>>(new Map());
const columnChecks = ref<UI.TableColumnCheck[]>([]);
const reviewVisible = ref(false);
const reviewRequirement = ref<Api.Project.ProjectRequirement | null>(null);
const reviewRecordVisible = ref(false);
const reviewRecordRequirement = ref<Api.Project.ProjectRequirement | null>(null);

const statusOptions = computed(() => {
  return statusDict.value.map(item => ({
    label: item.statusName,
    value: item.statusCode
  }));
});

const statusMetaMap = computed(() => {
  return new Map(statusDict.value.map(item => [item.statusCode, item]));
});

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

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

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

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

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

function isTerminalStatus(statusCode: string) {
  return Boolean(statusMetaMap.value.get(statusCode)?.terminalFlag);
}

// 要么是后端数据库中项目需求的某状态的allowEdit字段是true，要么是需求来源是产品需求、且为父需求、状态是implementing
function canEditRequirement(row: Api.Project.ProjectRequirement) {
  return (
    Boolean(statusMetaMap.value.get(row.statusCode)?.allowEdit) ||
    (row.sourceType === 'product_requirement' && row.parentId === '0' && row.statusCode === 'implementing')
  );
}

function isReviewAction(row: Api.Project.ProjectRequirement, action: Api.Project.ProjectRequirementLifecycleAction) {
  return row.statusCode === 'pending_review' && ['pass_review', 'reject_review'].includes(action.actionCode);
}

function isReviewTransitionAction(actionCode: string) {
  return ['pass_review', 'reject_review'].includes(actionCode);
}

function canViewReviewRecord(row: Api.Project.ProjectRequirement) {
  return row.reviewRequired === 1 && !['pending_claim', 'pending_review'].includes(row.statusCode);
}

function canSplitRequirement(row: Api.Project.ProjectRequirement) {
  return ['reviewed', 'implementing'].includes(row.statusCode);
}

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

function flattenTree(nodes: Api.Project.ProjectRequirement[]): Api.Project.ProjectRequirement[] {
  const result: Api.Project.ProjectRequirement[] = [];

  for (const node of nodes) {
    result.push(node);

    if (node.children?.length) {
      result.push(...flattenTree(node.children));
    }
  }

  return result;
}

function countRequirementTreeNodes(nodes: Api.Project.ProjectRequirement[]) {
  return flattenTree(nodes).length;
}

function collectRequirementIdsForActions(nodes: Api.Project.ProjectRequirement[]): string[] {
  const ids: string[] = [];

  for (const node of nodes) {
    if (!isTerminalStatus(node.statusCode)) {
      ids.push(node.id);
    }

    if (node.children?.length) {
      ids.push(...collectRequirementIdsForActions(node.children));
    }
  }

  return ids;
}

function getRowActions(row: Api.Project.ProjectRequirement) {
  return allowedTransitionsMap.value.get(row.id) || [];
}

function buildRequirementActions(row: Api.Project.ProjectRequirement) {
  const actions: Array<{
    key: string;
    label: string;
    icon: object;
    type: 'primary' | 'success' | 'danger';
    disabled?: boolean;
    onClick: () => void;
  }> = [];

  const hasUpdateAuth = hasObjectAuth('project:project:requirement:update');
  const hasDeleteAuth = hasObjectAuth('project:project:requirement:delete');
  const hasStatusAuth = hasObjectAuth('project:project:requirement:status');
  const hasSplitAuth = hasObjectAuth('project:project:requirement:split');
  const hasQueryAuth = hasObjectAuth('project:project:requirement:query');
  const hasReviewAuth = hasObjectAuth('project:project:requirement:review');
  const lifecycleActions = getRowActions(row);

  if (hasQueryAuth && canViewReviewRecord(row)) {
    actions.push({
      key: 'reviewRecord',
      label: '查看评审记录',
      icon: markRaw(IconMdiEyeOutline),
      type: 'primary',
      onClick: () => handleViewReviewRecord(row)
    });
  }

  if (hasSplitAuth && canSplitRequirement(row)) {
    actions.push({
      key: 'split',
      label: '拆分',
      icon: getProjectRequirementActionIcon('split'),
      type: getProjectRequirementActionButtonType('split'),
      onClick: () => openSplit(row)
    });
  }

  if (hasUpdateAuth && canEditRequirement(row)) {
    actions.push({
      key: 'edit',
      label: '编辑',
      icon: getProjectRequirementActionIcon('edit'),
      type: getProjectRequirementActionButtonType('edit'),
      onClick: () => openEdit(row)
    });
  }

  if (row.sourceType === 'product_requirement' && row.parentId === '0' && currentProject.value?.productId) {
    actions.push({
      key: 'back',
      label: '回溯',
      icon: ACTION_ICON_MAP.back,
      type: 'primary',
      onClick: () => handleBackToProductRequirement(row)
    });
  }

  if (hasReviewAuth && lifecycleActions.some(action => isReviewAction(row, action))) {
    actions.push({
      key: 'review',
      label: '评审',
      icon: ACTION_ICON_MAP.pass_review,
      type: 'primary',
      onClick: () => openReview(row)
    });
  }

  if (hasStatusAuth) {
    const nonTerminalActions: Api.Project.ProjectRequirementLifecycleAction[] = [];
    const terminalActions: Api.Project.ProjectRequirementLifecycleAction[] = [];

    lifecycleActions
      .filter(action => !isReviewTransitionAction(action.actionCode))
      .forEach(action => {
        if (isProjectRequirementActionTerminal(action.actionCode)) {
          terminalActions.push(action);
        } else {
          nonTerminalActions.push(action);
        }
      });

    [...nonTerminalActions, ...terminalActions].forEach(action => {
      actions.push({
        key: `action-${action.actionCode}`,
        label: getProjectRequirementActionDisplayName(action),
        icon: getProjectRequirementActionIcon(action.actionCode) ?? DEFAULT_ACTION_ICON,
        type: getProjectRequirementActionButtonType(action.actionCode),
        onClick: () => handleActionClick(row, action)
      });
    });
  }

  if (hasDeleteAuth && canDeleteRequirement(row)) {
    actions.push({
      key: 'delete',
      label: '删除',
      icon: getProjectRequirementActionIcon('delete'),
      type: getProjectRequirementActionButtonType('delete'),
      onClick: () => handleDelete(row)
    });
  }

  return actions;
}

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: 220,
    className: 'requirement-title-column',
    formatter: (row: Api.Project.ProjectRequirement) => (
      <ElTooltip content={row.title} placement="top" show-after={300}>
        <span
          class="requirement-title"
          role="button"
          tabindex={0}
          onClick={() => openView(row)}
          onKeydown={event => {
            if (event.key === 'Enter' || event.key === ' ') {
              event.preventDefault();
              openView(row);
            }
          }}
        >
          {row.title}
        </span>
      </ElTooltip>
    )
  },
  {
    prop: 'priority',
    label: '优先级',
    width: 88,
    align: 'center',
    formatter: (row: Api.Project.ProjectRequirement) => (
      <DictTag dictCode={RDMS_REQ_PRIORITY_DICT_CODE} value={row.priority} />
    )
  },
  {
    prop: 'statusCode',
    label: '状态',
    width: 110,
    align: 'center',
    formatter: (row: Api.Project.ProjectRequirement) => (
      <ElTag type={getStatusTagType('projectRequirement', row.statusCode)}>{getStatusLabel(row.statusCode)}</ElTag>
    )
  },
  {
    prop: 'category',
    label: '需求类型',
    minWidth: 120,
    formatter: (row: Api.Project.ProjectRequirement) => row.categoryName || row.category || '--'
  },
  // {
  //   prop: 'sourceType',
  //   label: '需求来源',
  //   minWidth: 110,
  //   align: 'center',
  //   formatter: (row: Api.Project.ProjectRequirement) => (
  //     <DictText dictCode={RDMS_REQ_SOURCE_TYPE_DICT_CODE} value={row.sourceType} />
  //   )
  // },
  {
    prop: 'proposerNickname',
    label: '提出人',
    minWidth: 90,
    formatter: (row: Api.Project.ProjectRequirement) => row.proposerNickname || '--'
  },
  {
    prop: 'currentHandlerUserId',
    label: '负责人',
    minWidth: 90,
    formatter: (row: Api.Project.ProjectRequirement) => getMemberLabel(row.currentHandlerUserId)
  },
  {
    prop: 'sourceBizCode',
    label: '来源业务编号',
    minWidth: 140,
    formatter: (row: Api.Project.ProjectRequirement) => {
      if (!row.sourceBizCode) {
        return '--';
      }

      return row.sourceBizCode;
    }
  },
  {
    prop: 'expectedTime',
    label: '预期完成时间',
    minWidth: 120,
    align: 'center',
    formatter: (row: Api.Project.ProjectRequirement) => formatDate(row.expectedTime)
  },
  {
    prop: 'createTime',
    label: '创建时间',
    minWidth: 180,
    formatter: (row: Api.Project.ProjectRequirement) => formatDateTime(row.createTime)
  },
  {
    prop: 'operate',
    label: '操作',
    width: 200,
    align: 'center',
    fixed: 'right',
    formatter: (row: Api.Project.ProjectRequirement) => {
      const actions = buildRequirementActions(row);

      return (
        <div class="requirement-action-cell" onClick={event => event.stopPropagation()}>
          {actions.length === 0 ? (
            <ElButton link size="small" class="requirement-action-icon-btn" type="primary" disabled>
              <IconMdiPencilOutline class="text-15px" />
            </ElButton>
          ) : (
            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}
                    disabled={action.disabled}
                    onClick={() => action.onClick()}
                  >
                    <IconComponent class="text-15px" />
                  </ElButton>
                </ElTooltip>
              );
            })
          )}
        </div>
      );
    }
  }
]);

watch(
  () => columns.value,
  value => {
    const existingMap = new Map(columnChecks.value.map(item => [item.prop, item.checked]));

    columnChecks.value = value
      .filter(column => column.prop && column.prop !== 'operate')
      .map(column => ({
        prop: String(column.prop),
        label: String(column.label || ''),
        checked: existingMap.has(String(column.prop)) ? existingMap.get(String(column.prop))! : true,
        visible: true
      }));
  },
  { immediate: true }
);

const visibleColumns = computed(() => {
  if (!columnChecks.value.length) {
    return columns.value;
  }

  const visibleSet = new Set(columnChecks.value.filter(item => item.checked).map(item => item.prop));

  return columns.value.filter(column => {
    const prop = String(column.prop || '');

    if (!prop || prop === 'operate') {
      return true;
    }

    return visibleSet.has(prop);
  });
});

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

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

  statusDict.value = data;
}

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

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

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

  memberOptions.value = data;
}

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

  const { error, data } = await fetchGetProjectRequirementTree({
    projectId: currentObjectId.value,
    moduleId: selectedModuleId.value,
    pageNo: pagination.pageNo,
    pageSize: pagination.pageSize,
    title: searchParams.title?.trim() || undefined,
    category: searchParams.category,
    priority: searchParams.priority,
    statusCode: searchParams.statusCode,
    currentHandlerUserId: searchParams.currentHandlerUserId,
    sourceBizCode: searchParams.sourceBizCode?.trim() || undefined
  });

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

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

async function loadRequirementDisplayTotal() {
  if (!currentObjectId.value) {
    requirementDisplayTotal.value = 0;
    return;
  }

  const baseParams = {
    projectId: currentObjectId.value,
    pageNo: 1
  };
  const rootTotalResult = await fetchGetProjectRequirementTree({
    ...baseParams,
    pageSize: 1
  });

  if (rootTotalResult.error || !rootTotalResult.data) {
    requirementDisplayTotal.value = pagination.total;
    return;
  }

  const rootTotal = rootTotalResult.data.total;

  if (rootTotal <= 0) {
    requirementDisplayTotal.value = 0;
    return;
  }

  const allTreeResult = await fetchGetProjectRequirementTree({
    ...baseParams,
    pageSize: rootTotal
  });

  if (allTreeResult.error || !allTreeResult.data) {
    requirementDisplayTotal.value = rootTotal;
    return;
  }

  requirementDisplayTotal.value = countRequirementTreeNodes(allTreeResult.data.list);
}

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

  const idsToQuery = collectRequirementIdsForActions(treeData.value);
  const nextMap = new Map<string, Api.Project.ProjectRequirementLifecycleAction[]>();

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

  const { error, data } = await fetchGetProjectRequirementAllowedTransitionsBatch({
    projectId: currentObjectId.value,
    requirementIds: idsToQuery
  });

  if (error || !data) {
    allowedTransitionsMap.value = nextMap;
    return;
  }

  data.forEach(item => {
    nextMap.set(item.requirementId, item.transitions || []);
  });

  allowedTransitionsMap.value = nextMap;
}

async function reloadTable() {
  loading.value = true;

  try {
    await loadTreeData();
    await loadAllowedTransitionsForAll();
  } finally {
    loading.value = false;
  }
}

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

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

function handleResetSearch() {
  Object.assign(searchParams, createSearchParams(), {
    projectId: currentObjectId.value || '',
    pageSize: pagination.pageSize
  });
  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.Project.ProjectRequirement) {
  selectedRequirement.value = row;
  detailMode.value = 'view';
  detailVisible.value = true;
}

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

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

function openReview(row: Api.Project.ProjectRequirement) {
  reviewRequirement.value = row;
  reviewVisible.value = true;
}

function handleViewReviewRecord(row: Api.Project.ProjectRequirement) {
  if (!canViewReviewRecord(row)) {
    return;
  }

  reviewRecordRequirement.value = row;
  reviewRecordVisible.value = true;
}

async function handleBackToProductRequirement(row: Api.Project.ProjectRequirement) {
  const productId = currentProject.value?.productId;
  if (!productId || row.sourceType !== 'product_requirement') return;

  await router.replace({
    path: '/product/requirement',
    query: {
      objectId: productId
    }
  });
}

function handleActionClick(row: Api.Project.ProjectRequirement, action: Api.Project.ProjectRequirementLifecycleAction) {
  if (!action.needReason) {
    handleDirectAction(row, action);
    return;
  }

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

async function handleDirectAction(
  row: Api.Project.ProjectRequirement,
  action: Api.Project.ProjectRequirementLifecycleAction
) {
  if (!currentObjectId.value) {
    return;
  }

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

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

  if (error) {
    return;
  }

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

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

  const { error } = await fetchChangeProjectRequirementStatus({
    id: actionRequirement.value.id,
    projectId: currentObjectId.value,
    actionCode: payload.actionCode,
    reason: payload.reason
  });

  if (error) {
    return;
  }

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

async function handleDelete(row: Api.Project.ProjectRequirement) {
  if (!currentObjectId.value) {
    return;
  }

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

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

  if (error) {
    return;
  }

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

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

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

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

async function handleReviewSubmitted() {
  reviewVisible.value = false;
  await reloadTable();
}

watch(
  () => currentObjectId.value,
  async id => {
    Object.assign(searchParams, createSearchParams(), {
      projectId: id || '',
      pageSize: pagination.pageSize
    });
    selectedModuleId.value = '';
    pagination.pageNo = 1;

    if (!id) {
      memberOptions.value = [];
      treeData.value = [];
      allowedTransitionsMap.value = new Map();
      pagination.total = 0;
      requirementDisplayTotal.value = 0;
      return;
    }

    treeData.value = [];
    allowedTransitionsMap.value = new Map();
    pagination.total = 0;
    await Promise.all([loadMembers(), loadRequirementDisplayTotal()]);
  },
  { immediate: true }
);

Promise.all([loadStatusOptions()]);
</script>

<template>
  <div v-if="currentObjectId" class="project-requirement-page">
    <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"
        :status-options="statusOptions"
        @reset="handleResetSearch"
        @search="handleSearch"
      />

      <ElCard class="card-wrapper xl:flex-1-hidden" body-class="requirement-table-card-body">
        <template #header>
          <div class="project-requirement-card-header">
            <div class="min-w-0 flex-1">
              <div class="flex flex-wrap items-center gap-8px">
                <p class="truncate text-16px font-600">项目需求列表</p>
                <ElTag effect="plain">{{ requirementDisplayTotal }}</ElTag>
              </div>
            </div>
            <TableHeaderOperation v-model:columns="columnChecks" :loading="loading" @refresh="reloadTable">
              <template #default>
                <ElButton
                  v-auth="{ code: 'project:project:requirement: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
            v-loading="loading"
            border
            lazy
            row-key="id"
            :indent="32"
            height="100%"
            :data="treeData"
            :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
          >
            <ElTableColumn v-for="column in visibleColumns" :key="String(column.prop || 'index')" v-bind="column" />

            <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"
      :project-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"
      :project-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"
      :project-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 || ''"
      @submitted="handleActionSubmitted"
    />

    <RequirementReviewDialog
      v-model:visible="reviewVisible"
      :project-id="currentObjectId || ''"
      :requirement="reviewRequirement"
      :member-options="memberOptions"
      @submitted="handleReviewSubmitted"
    />

    <RequirementReviewRecordDialog
      v-model:visible="reviewRecordVisible"
      :project-id="currentObjectId || ''"
      :requirement="reviewRecordRequirement"
      :member-options="memberOptions"
    />
  </div>

  <ElEmpty v-else description="未获取到当前项目上下文，请返回项目列表重新选择项目" />
</template>

<style lang="scss" scoped>
.project-requirement-page {
  display: grid;
  min-height: 560px;
  gap: 16px;
  overflow: hidden;
  grid-template-columns: 280px minmax(0, 1fr);
}

.project-requirement-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

:deep(.requirement-title) {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
  padding: 0;
  font-weight: 500;
  color: var(--el-color-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 1.5;
  vertical-align: middle;
  cursor: pointer;
}

:deep(.requirement-title-column .cell) {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  min-width: 0;
}

:deep(.requirement-title:hover) {
  text-decoration: underline;
}

:deep(.requirement-table-card-body) {
  height: calc(100% - 56px);
  display: flex;
  flex-direction: column;
}

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

:deep(.requirement-action-cell .el-button + .el-button) {
  margin-left: 0;
}

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

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

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

@media (width <= 1280px) {
  .project-requirement-page {
    display: flex;
    flex-direction: column;
    overflow: auto;
  }

  .project-requirement-card-header {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>
