<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import { RDMS_WORKLOG_DIFFICULTY_DICT_CODE } from '@/constants/dict';
import {
  fetchCreateProjectTaskWorklog,
  fetchDeleteProjectTaskWorklog,
  fetchGetProjectTaskWorklogPage,
  fetchUpdateProjectTaskWorklog
} from '@/service/api/project';
import { useAuthStore } from '@/store/modules/auth';
import { useDict } from '@/hooks/business/dict';
import BusinessAttachmentUploader from '@/components/custom/business-attachment-uploader.vue';
import DictTag from '@/components/custom/dict-tag.vue';
import { formatWorklogPeriod, getWorklogGranularityName } from '../shared';
import type { WorklogChangedPayload } from '../shared';
import TaskWorklogFormDialog from './task-worklog-form-dialog.vue';
import IconMdiDeleteOutline from '~icons/mdi/delete-outline';
import IconMdiEyeOutline from '~icons/mdi/eye-outline';
import IconMdiFilterVariant from '~icons/mdi/filter-variant';
import IconMdiPaperclip from '~icons/mdi/paperclip';
import IconMdiPencilOutline from '~icons/mdi/pencil-outline';

defineOptions({ name: 'ProjectExecutionTaskWorklogPanel' });

type WorklogPageResult = {
  error: unknown;
  data?: Api.Project.PageResult<Api.Project.TaskWorklog> | null;
};

type WorklogMutationResult = {
  error: unknown;
};

interface Props {
  projectId: string;
  executionId: string;
  taskId: string;
  taskOwnerId: string | null;
  /** 任务状态码；用于编辑/删除按钮的状态前置（active / completed 才允许，与 §4.8.4 矩阵对齐） */
  taskStatusCode: string;
  /** 当前用户是否被允许填报（owner 或活跃协办人） */
  canSubmit: boolean;
  /** 用于 form-dialog 在 owner 路径下显示默认进度（task.progressRate） */
  taskProgressRate?: number;
  /** 在岗协办人列表（来自 task.assignees）。owner 视角下用于渲染顶部最新填报汇总条 */
  assignees?: Api.Project.TaskAssigneeRef[] | null;
  /** 外部传入的全量记录。提供后 panel 跳过自身分页接口，使用前端假分页；CRUD 后只 emit changed，由父级重拉数据 */
  externalList?: Api.Project.TaskWorklog[] | null;
  /** owner 昵称，用于构造「填报人」筛选下拉项 */
  ownerNickname?: string | null;
  /** 是否展示「填报人」列与列头筛选；只在 owner 视角下展示 */
  showAssigneeColumn?: boolean;
  /** 是否激活；非激活时不主动加载内部数据 */
  active?: boolean;
  /** 自定义分页查询，个人事项等复用方通过它接入自己的接口 */
  fetchWorklogPage?: (params: Api.Project.TaskWorklogSearchParams) => Promise<WorklogPageResult>;
  /** 自定义新增接口 */
  createWorklog?: (data: Api.Project.SaveTaskWorklogParams) => Promise<WorklogMutationResult>;
  /** 自定义编辑接口 */
  updateWorklog?: (payload: {
    worklogId: string;
    data: Api.Project.SaveTaskWorklogParams;
  }) => Promise<WorklogMutationResult>;
  /** 自定义删除接口 */
  deleteWorklog?: (worklogId: string) => Promise<WorklogMutationResult>;
  /** 附件上传目录 */
  attachmentDirectory?: string;
  createSuccessMessage?: string;
  updateSuccessMessage?: string;
  deleteSuccessMessage?: string;
}

interface Emits {
  (e: 'changed', payload: WorklogChangedPayload): void;
}

const props = withDefaults(defineProps<Props>(), {
  taskProgressRate: 0,
  assignees: null,
  externalList: null,
  ownerNickname: null,
  showAssigneeColumn: false,
  active: true,
  fetchWorklogPage: undefined,
  createWorklog: undefined,
  updateWorklog: undefined,
  deleteWorklog: undefined,
  attachmentDirectory: 'task-worklog',
  createSuccessMessage: '填报成功',
  updateSuccessMessage: '填报已更新',
  deleteSuccessMessage: '工时已删除'
});
const emit = defineEmits<Emits>();

const authStore = useAuthStore();
const currentUserId = computed(() => authStore.userInfo.userId || '');

const isOwner = computed(() => Boolean(props.taskOwnerId && props.taskOwnerId === currentUserId.value));

const PAGE_SIZE = 10;
// 表头 ~40px + 7 行 × ~50px（含 ElTag/icon 按钮）= 约 390px；超出 7 行走表格内部滚动
const TABLE_HEIGHT = 390;
const pageNo = ref(1);
const internalTotal = ref(0);
const internalList = ref<Api.Project.TaskWorklog[]>([]);
const loading = ref(false);

const usingExternal = computed(() => Array.isArray(props.externalList));

const userFilter = ref<string[]>([]);
const userFilterPopoverVisible = ref(false);
const pendingUserFilter = ref<string[]>([]);

// 完成难度筛选（单选，对齐后端 eqIfPresent）。'' = 未筛选
const difficultyFilter = ref<string>('');
const difficultyFilterPopoverVisible = ref(false);
const pendingDifficultyFilter = ref<string>('');

const { enabledDictData: difficultyDictItems } = useDict(RDMS_WORKLOG_DIFFICULTY_DICT_CODE);

function handleDifficultyFilterConfirm() {
  difficultyFilter.value = pendingDifficultyFilter.value;
  difficultyFilterPopoverVisible.value = false;
}

function handleDifficultyFilterReset() {
  pendingDifficultyFilter.value = '';
}

watch(difficultyFilterPopoverVisible, value => {
  if (value) {
    pendingDifficultyFilter.value = difficultyFilter.value;
  }
});

interface UserFilterRichOption {
  value: string;
  name: string;
  isOwner: boolean;
  hoursText: string;
  progressText: string;
  /** true 表示没有任何 worklog；UI 上隐藏工时/进度，只显示"未填报"灰字 */
  empty: boolean;
}

// 每个 userId 在 externalList 中"最近一条" worklog 的 progressRate
// externalList 已由后端按 end_date desc, id desc 排序，第一条即为最近
const latestProgressByUser = computed(() => {
  const map = new Map<string, number>();
  for (const item of props.externalList ?? []) {
    if (!map.has(item.userId)) {
      map.set(item.userId, item.progressRate);
    }
  }
  return map;
});

// 每个 userId 的累计工时（durationHours 之和）
const totalHoursByUser = computed(() => {
  const map = new Map<string, number>();
  for (const item of props.externalList ?? []) {
    map.set(item.userId, (map.get(item.userId) ?? 0) + (item.durationHours ?? 0));
  }
  return map;
});

const userFilterRichOptions = computed<UserFilterRichOption[]>(() => {
  const options: UserFilterRichOption[] = [];

  if (props.taskOwnerId) {
    // 责任人的"进度"= 任务整体进度（因为责任人填报本就会回写任务进度）
    // 工时仍取该用户实际累计 worklog 时长
    options.push({
      value: props.taskOwnerId,
      name: props.ownerNickname?.trim() || props.taskOwnerId,
      isOwner: true,
      hoursText: formatHours(totalHoursByUser.value.get(props.taskOwnerId) ?? 0),
      progressText: formatProgress(props.taskProgressRate),
      empty: false
    });
  }

  for (const assignee of props.assignees ?? []) {
    // 防止 owner 同时也是 assignee 时重复
    if (assignee.userId !== props.taskOwnerId) {
      const latest = latestProgressByUser.value.get(assignee.userId);
      const hours = totalHoursByUser.value.get(assignee.userId) ?? 0;
      const empty = latest === undefined;
      options.push({
        value: assignee.userId,
        name: assignee.nickname?.trim() || assignee.userId,
        isOwner: false,
        hoursText: empty ? '' : formatHours(hours),
        progressText: empty ? '未填报' : formatProgress(latest!),
        empty
      });
    }
  }

  return options;
});

function handleUserFilterConfirm() {
  userFilter.value = [...pendingUserFilter.value];
  userFilterPopoverVisible.value = false;
}

function handleUserFilterReset() {
  pendingUserFilter.value = [];
}

// popover 打开瞬间从 userFilter 初始化 pending；让 ElPopover 自己控开关，
// 避免 reference 上挂自定义 click handler 与 trigger="click" 互相 toggle 导致一开就关
watch(userFilterPopoverVisible, value => {
  if (value) {
    pendingUserFilter.value = [...userFilter.value];
  }
});

const filteredExternalList = computed<Api.Project.TaskWorklog[]>(() => {
  let result = props.externalList ?? [];
  if (props.showAssigneeColumn && userFilter.value.length > 0) {
    result = result.filter(item => userFilter.value.includes(item.userId));
  }
  if (difficultyFilter.value) {
    result = result.filter(item => item.difficulty === difficultyFilter.value);
  }
  return result;
});

const total = computed(() => (usingExternal.value ? filteredExternalList.value.length : internalTotal.value));

const list = computed<Api.Project.TaskWorklog[]>(() => {
  if (!usingExternal.value) {
    return internalList.value;
  }
  const start = (pageNo.value - 1) * PAGE_SIZE;
  return filteredExternalList.value.slice(start, start + PAGE_SIZE);
});

const formVisible = ref(false);
const formMode = ref<'create' | 'edit' | 'view'>('create');
const editingWorklog = ref<Api.Project.TaskWorklog | null>(null);
const submitting = ref(false);
const worklogFormDialogRef = ref<InstanceType<typeof TaskWorklogFormDialog> | null>(null);

function getRowIndex(index: number) {
  return (pageNo.value - 1) * PAGE_SIZE + index + 1;
}

const canCreate = computed(() => Boolean(props.canSubmit && props.taskId));

// 编辑 / 删除自己工时按矩阵 §4.8.4：仅本人 + 任务在 active / completed
// completed 态进入 worklog 编辑弹层时，进度字段会自动只读，避免触发任务进度回写
const isWorklogMutableStatus = computed(
  () => props.taskStatusCode === 'active' || props.taskStatusCode === 'completed'
);
const showDeleteAction = computed(() => props.taskStatusCode !== 'completed');

function canEditRow(row: Api.Project.TaskWorklog) {
  return Boolean(isWorklogMutableStatus.value && currentUserId.value && row.userId === currentUserId.value);
}

function canDeleteRow(row: Api.Project.TaskWorklog) {
  return Boolean(props.taskStatusCode === 'active' && currentUserId.value && row.userId === currentUserId.value);
}

function formatHours(hours: number | null | undefined) {
  if (typeof hours !== 'number' || !Number.isFinite(hours)) {
    return '0h';
  }
  return `${hours.toFixed(1)}h`;
}

function formatProgress(value: number | null | undefined) {
  if (typeof value !== 'number' || !Number.isFinite(value)) {
    return '0%';
  }
  // 保留至多 2 位小数，去掉尾部 0：35 → "35%"，35.5 → "35.5%"，35.75 → "35.75%"
  const clamped = Math.min(100, Math.max(0, value));
  const rounded = Math.round(clamped * 100) / 100;
  return `${rounded}%`;
}

async function loadList() {
  // 父级提供了全量数据：跳过自身请求
  if (usingExternal.value) {
    return;
  }

  if (!props.active) {
    return;
  }

  if (!props.projectId || !props.executionId || !props.taskId) {
    if (!props.fetchWorklogPage) {
      internalList.value = [];
      internalTotal.value = 0;
      return;
    }
  }

  if (!props.taskId) {
    internalList.value = [];
    internalTotal.value = 0;
    return;
  }

  loading.value = true;

  const params: Api.Project.TaskWorklogSearchParams = {
    pageNo: pageNo.value,
    pageSize: PAGE_SIZE
  };
  // owner 看全部；协作人/旁观者：协作人按身份过滤；旁观者沿用旧逻辑（不传 userId）
  if (!isOwner.value && props.canSubmit && currentUserId.value) {
    params.userId = currentUserId.value;
  }
  // 难度筛选：未选时不传参（避免 eqIfPresent 把空字符串当筛选条件漏掉全部）
  if (difficultyFilter.value) {
    params.difficulty = difficultyFilter.value;
  }

  const { error, data } = props.fetchWorklogPage
    ? await props.fetchWorklogPage(params)
    : await fetchGetProjectTaskWorklogPage(props.projectId, props.executionId, props.taskId, params);

  loading.value = false;

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

  internalList.value = data.list;
  internalTotal.value = data.total;
}

function handlePageChange(page: number) {
  pageNo.value = page;
  // 外部数据模式下，list 是 computed 切片，pageNo 改变会自动反映；无需触发请求
  if (!usingExternal.value) {
    loadList();
  }
}

function handleCreate() {
  formMode.value = 'create';
  editingWorklog.value = null;
  formVisible.value = true;
}

function handleEdit(row: Api.Project.TaskWorklog) {
  formMode.value = 'edit';
  editingWorklog.value = row;
  formVisible.value = true;
}

function handleView(row: Api.Project.TaskWorklog) {
  formMode.value = 'view';
  editingWorklog.value = row;
  formVisible.value = true;
}

async function handleSubmit(payload: Api.Project.SaveTaskWorklogParams) {
  submitting.value = true;
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    let result: any;

    if (formMode.value === 'create') {
      if (props.createWorklog) {
        result = await props.createWorklog(payload);
      } else {
        result = await fetchCreateProjectTaskWorklog(props.projectId, props.executionId, props.taskId, payload);
      }
    } else {
      const updatePayload = {
        worklogId: editingWorklog.value!.id,
        data: payload
      };

      if (props.updateWorklog) {
        result = await props.updateWorklog(updatePayload);
      } else {
        result = await fetchUpdateProjectTaskWorklog(props.projectId, props.executionId, props.taskId, updatePayload);
      }
    }

    if (result.error) {
      return;
    }

    window.$message?.success(formMode.value === 'create' ? props.createSuccessMessage : props.updateSuccessMessage);
    // 业务保存成功才 commit：删除用户在弹层里标记删除的附件
    await worklogFormDialogRef.value?.commit();
    formVisible.value = false;

    // 外部数据模式：父级监听 changed 后重拉，自身不再触发请求
    if (!usingExternal.value) {
      await loadList();
    }

    emit('changed', {
      mode: formMode.value === 'create' ? 'create' : 'edit',
      taskId: props.taskId,
      progressRate: payload.progressRate
    });
  } finally {
    submitting.value = false;
  }
}

async function handleDelete(row: Api.Project.TaskWorklog) {
  const { error } = props.deleteWorklog
    ? await props.deleteWorklog(row.id)
    : await fetchDeleteProjectTaskWorklog(props.projectId, props.executionId, props.taskId, row.id);
  if (error) {
    return;
  }

  window.$message?.success(props.deleteSuccessMessage);
  if (!usingExternal.value) {
    // 删完最后一页若空了，回退一页（仅 server-side 路径手动处理；外部模式下由 watch(total) 兜底）
    if (list.value.length === 1 && pageNo.value > 1) {
      pageNo.value -= 1;
    }
    await loadList();
  }
  emit('changed', {
    mode: 'delete',
    taskId: props.taskId
  });
}

// 外部模式下数据缩短后把 pageNo 夹回合法范围
watch(total, value => {
  if (!usingExternal.value) return;
  const maxPage = Math.max(1, Math.ceil(value / PAGE_SIZE));
  if (pageNo.value > maxPage) {
    pageNo.value = maxPage;
  }
});

watch(userFilter, () => {
  pageNo.value = 1;
});

watch(difficultyFilter, () => {
  pageNo.value = 1;
  if (!usingExternal.value) {
    loadList();
  }
});

watch(
  () => [props.active, props.taskId] as const,
  ([active]) => {
    pageNo.value = 1;
    userFilter.value = [];
    userFilterPopoverVisible.value = false;
    difficultyFilter.value = '';
    difficultyFilterPopoverVisible.value = false;
    if (active) {
      loadList();
    }
  },
  { immediate: true }
);
</script>

<template>
  <div class="task-worklog-panel">
    <header v-if="canCreate" class="task-worklog-panel__header">
      <ElButton type="primary" :icon="Plus" size="small" @click="handleCreate">工作日志</ElButton>
    </header>

    <ElTable
      v-loading="loading"
      :data="list"
      :height="TABLE_HEIGHT"
      border
      empty-text="暂无工作日志"
      class="task-worklog-panel__table"
    >
      <ElTableColumn type="index" :index="getRowIndex" label="序号" width="60" align="center" fixed="left" />
      <ElTableColumn label="粒度" width="70" align="center">
        <template #default="{ row }">
          <ElTag
            :type="formatWorklogPeriod(row.startDate, row.endDate).granularity === 'week' ? 'warning' : 'info'"
            size="small"
            effect="plain"
          >
            {{ getWorklogGranularityName(formatWorklogPeriod(row.startDate, row.endDate).granularity) }}
          </ElTag>
        </template>
      </ElTableColumn>
      <ElTableColumn label="日期" width="180" align="center">
        <template #default="{ row }">
          <ElTooltip
            v-if="formatWorklogPeriod(row.startDate, row.endDate).tooltip"
            :content="formatWorklogPeriod(row.startDate, row.endDate).tooltip ?? ''"
            placement="top"
          >
            <span>{{ formatWorklogPeriod(row.startDate, row.endDate).display }}</span>
          </ElTooltip>
          <span v-else>{{ formatWorklogPeriod(row.startDate, row.endDate).display }}</span>
        </template>
      </ElTableColumn>
      <ElTableColumn label="时长" width="100" align="center">
        <template #default="{ row }">
          <span class="task-worklog-panel__duration">{{ formatHours(row.durationHours) }}</span>
        </template>
      </ElTableColumn>
      <ElTableColumn label="进度" width="100" align="center">
        <template #default="{ row }">
          <span class="task-worklog-panel__progress">{{ formatProgress(row.progressRate) }}</span>
        </template>
      </ElTableColumn>
      <ElTableColumn v-if="showAssigneeColumn" label="填报人" width="120" align="center">
        <template #header>
          <div class="task-worklog-panel__user-header">
            <span>填报人</span>
            <ElPopover
              v-model:visible="userFilterPopoverVisible"
              trigger="click"
              placement="bottom"
              :width="260"
              popper-class="task-worklog-panel__user-filter-popper"
            >
              <template #reference>
                <span
                  class="task-worklog-panel__user-filter-trigger"
                  :class="{ 'is-active': userFilter.length > 0 }"
                  @click.stop
                >
                  <IconMdiFilterVariant />
                </span>
              </template>
              <div class="task-worklog-panel__user-filter">
                <ElCheckboxGroup v-model="pendingUserFilter" class="task-worklog-panel__user-filter-list">
                  <label
                    v-for="option in userFilterRichOptions"
                    :key="option.value"
                    class="task-worklog-panel__user-filter-row"
                  >
                    <ElCheckbox :value="option.value">
                      <span class="task-worklog-panel__user-filter-name-cell">
                        <span
                          class="task-worklog-panel__user-filter-name"
                          :class="{ 'is-owner': option.isOwner }"
                          :title="option.name"
                        >
                          {{ option.name }}
                        </span>
                        <ElTag
                          v-if="option.isOwner"
                          type="warning"
                          size="small"
                          effect="plain"
                          class="task-worklog-panel__user-filter-owner-tag"
                        >
                          责任人
                        </ElTag>
                      </span>
                    </ElCheckbox>
                    <span class="task-worklog-panel__user-filter-meta">
                      <template v-if="!option.empty">
                        <span class="task-worklog-panel__user-filter-hours">{{ option.hoursText }}</span>
                        <span class="task-worklog-panel__user-filter-meta-sep">·</span>
                        <span class="task-worklog-panel__user-filter-progress">{{ option.progressText }}</span>
                      </template>
                      <span v-else class="task-worklog-panel__user-filter-progress is-empty">
                        {{ option.progressText }}
                      </span>
                    </span>
                  </label>
                </ElCheckboxGroup>
                <div class="task-worklog-panel__user-filter-footer">
                  <ElButton size="small" link @click="handleUserFilterReset">重置</ElButton>
                  <ElButton size="small" type="primary" @click="handleUserFilterConfirm">确定</ElButton>
                </div>
              </div>
            </ElPopover>
          </div>
        </template>
        <template #default="{ row }">
          <span :title="row.userNickname || row.userId">{{ row.userNickname || row.userId }}</span>
        </template>
      </ElTableColumn>
      <ElTableColumn label="工作内容" min-width="280">
        <template #default="{ row }">
          <ElPopover
            v-if="row.workContent || (row.attachments && row.attachments.length)"
            trigger="hover"
            placement="top"
            :width="360"
            :show-after="200"
            popper-class="task-worklog-panel__content-popover"
          >
            <template #reference>
              <span class="task-worklog-panel__content-cell">
                {{ row.workContent || '附件 ' + (row.attachments?.length ?? 0) + ' 个' }}
              </span>
            </template>
            <div class="task-worklog-panel__content-card">
              <div class="task-worklog-panel__content-card-header">
                <span>{{ formatWorklogPeriod(row.startDate, row.endDate).display }}</span>
                <span class="task-worklog-panel__content-card-meta">
                  {{ formatHours(row.durationHours) }} · {{ formatProgress(row.progressRate) }}
                </span>
              </div>
              <div v-if="row.workContent" class="task-worklog-panel__content-card-body">
                {{ row.workContent }}
              </div>
              <div class="task-worklog-panel__content-card-attachments">
                <div class="task-worklog-panel__content-card-section-title">
                  <ElIcon><IconMdiPaperclip /></ElIcon>
                  <span v-if="row.attachments && row.attachments.length">附件（{{ row.attachments.length }}）</span>
                  <span v-else class="task-worklog-panel__content-card-attachment-empty">无附件</span>
                </div>
                <div
                  v-if="row.attachments && row.attachments.length"
                  class="task-worklog-panel__content-card-attachments-scroll"
                >
                  <BusinessAttachmentUploader :model-value="row.attachments" disabled flat />
                </div>
              </div>
            </div>
          </ElPopover>
          <span v-else class="task-worklog-panel__content-cell-empty">--</span>
        </template>
      </ElTableColumn>
      <ElTableColumn label="难度" width="110" align="center">
        <template #header>
          <div class="task-worklog-panel__user-header">
            <span>难度</span>
            <ElPopover
              v-model:visible="difficultyFilterPopoverVisible"
              trigger="click"
              placement="bottom"
              :width="180"
              popper-class="task-worklog-panel__user-filter-popper"
            >
              <template #reference>
                <span
                  class="task-worklog-panel__user-filter-trigger"
                  :class="{ 'is-active': !!difficultyFilter }"
                  @click.stop
                >
                  <IconMdiFilterVariant />
                </span>
              </template>
              <div class="task-worklog-panel__user-filter">
                <ElRadioGroup v-model="pendingDifficultyFilter" class="task-worklog-panel__difficulty-filter-list">
                  <ElRadio
                    v-for="option in difficultyDictItems"
                    :key="option.value"
                    :value="option.value"
                    class="task-worklog-panel__difficulty-filter-row"
                  >
                    <span class="task-worklog-panel__difficulty-filter-item">
                      <span
                        v-if="option.colorType"
                        class="task-worklog-panel__difficulty-filter-dot"
                        :style="{ background: option.colorType }"
                      />
                      <span class="task-worklog-panel__difficulty-filter-label">{{ option.label }}</span>
                      <span v-if="option.remark" class="task-worklog-panel__difficulty-filter-remark">
                        {{ option.remark }}
                      </span>
                    </span>
                  </ElRadio>
                </ElRadioGroup>
                <div class="task-worklog-panel__user-filter-footer">
                  <ElButton size="small" link @click="handleDifficultyFilterReset">重置</ElButton>
                  <ElButton size="small" type="primary" @click="handleDifficultyFilterConfirm">确定</ElButton>
                </div>
              </div>
            </ElPopover>
          </div>
        </template>
        <template #default="{ row }">
          <DictTag :dict-code="RDMS_WORKLOG_DIFFICULTY_DICT_CODE" :value="row.difficulty" size="small" effect="light" />
        </template>
      </ElTableColumn>
      <ElTableColumn label="操作" width="120" align="center" fixed="right">
        <template #default="{ row }">
          <div class="task-worklog-panel__actions" @click.stop>
            <ElTooltip content="查看">
              <ElButton link type="primary" class="task-worklog-panel__action-btn" @click="handleView(row)">
                <IconMdiEyeOutline class="text-15px" />
              </ElButton>
            </ElTooltip>
            <ElTooltip :content="canEditRow(row) ? '编辑' : '仅可编辑本人填报'">
              <span class="inline-flex">
                <ElButton
                  link
                  type="primary"
                  class="task-worklog-panel__action-btn"
                  :disabled="!canEditRow(row)"
                  @click="handleEdit(row)"
                >
                  <IconMdiPencilOutline class="text-15px" />
                </ElButton>
              </span>
            </ElTooltip>
            <template v-if="showDeleteAction">
              <ElPopconfirm
                v-if="canDeleteRow(row)"
                title="确认删除该条工时记录？"
                confirm-button-text="删除"
                cancel-button-text="取消"
                confirm-button-type="danger"
                @confirm="handleDelete(row)"
              >
                <template #reference>
                  <span class="inline-flex">
                    <ElTooltip content="删除">
                      <ElButton link type="danger" class="task-worklog-panel__action-btn">
                        <IconMdiDeleteOutline class="text-15px" />
                      </ElButton>
                    </ElTooltip>
                  </span>
                </template>
              </ElPopconfirm>
              <ElTooltip v-else content="仅可删除本人填报">
                <span class="inline-flex">
                  <ElButton link type="danger" class="task-worklog-panel__action-btn" disabled>
                    <IconMdiDeleteOutline class="text-15px" />
                  </ElButton>
                </span>
              </ElTooltip>
            </template>
          </div>
        </template>
      </ElTableColumn>
    </ElTable>

    <div class="task-worklog-panel__pagination">
      <ElPagination
        v-if="total > 0"
        size="small"
        background
        layout="total, prev, pager, next"
        :current-page="pageNo"
        :page-size="PAGE_SIZE"
        :total="total"
        @current-change="handlePageChange"
      />
    </div>

    <TaskWorklogFormDialog
      ref="worklogFormDialogRef"
      v-model:visible="formVisible"
      :mode="formMode"
      :row-data="editingWorklog"
      :project-id="projectId"
      :execution-id="executionId"
      :task-id="taskId"
      :task-owner-id="taskOwnerId"
      :task-status-code="taskStatusCode"
      :default-owner-progress-rate="taskProgressRate"
      :attachment-directory="props.attachmentDirectory"
      :confirm-loading="submitting"
      @submit="handleSubmit"
    />
  </div>
</template>

<style scoped lang="scss">
.task-worklog-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.task-worklog-panel__header {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
}

.task-worklog-panel__duration {
  color: var(--el-color-primary);
  font-weight: 500;
}

.task-worklog-panel__actions {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.task-worklog-panel__actions :deep(.el-button + .el-button) {
  margin-left: 0;
}

:deep(.task-worklog-panel__action-btn) {
  padding: 3px;
  min-width: auto;
  height: auto;
  line-height: 1;
}

.task-worklog-panel__pagination {
  display: flex;
  justify-content: flex-end;
  min-height: 32px;
}

.task-worklog-panel__progress {
  color: var(--el-color-primary);
  font-weight: 500;
}

.task-worklog-panel__content-cell {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.5;
  cursor: default;
}

.task-worklog-panel__content-cell-empty {
  color: var(--el-text-color-placeholder);
}

.task-worklog-panel__content-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 4px 2px;
}

.task-worklog-panel__content-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
  padding-bottom: 8px;
  border-bottom: 1px solid var(--el-border-color-lighter);
}

.task-worklog-panel__content-card-meta {
  color: var(--el-color-primary);
  font-weight: 500;
}

.task-worklog-panel__content-card-body {
  font-size: 13px;
  line-height: 1.65;
  color: var(--el-text-color-primary);
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 220px;
  overflow-y: auto;
}

.task-worklog-panel__content-card-attachments {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.task-worklog-panel__content-card-attachments-scroll {
  // 约 3 项高度，再多就内部纵向滚动，避免 popover 被撑高
  max-height: 144px;
  overflow-y: auto;
  padding-right: 4px;
}

.task-worklog-panel__content-card-section-title {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
}

.task-worklog-panel__content-card-attachment-empty {
  color: var(--el-text-color-placeholder);
}

.task-worklog-panel__user-header {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  line-height: 1;
}

.task-worklog-panel__user-filter-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  font-size: 14px;
  color: var(--el-text-color-secondary);
  cursor: pointer;
  border-radius: 3px;
  transition:
    background-color 0.15s ease,
    color 0.15s ease;

  &:hover {
    background-color: var(--el-fill-color-light);
    color: var(--el-text-color-primary);
  }

  &.is-active {
    color: var(--el-color-primary);
  }
}
</style>

<style lang="scss">
// popper 走 teleport 出去，必须用全局样式
.task-worklog-panel__user-filter-popper.el-popover.el-popper {
  padding: 8px 0;
}

.task-worklog-panel__user-filter {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.task-worklog-panel__user-filter-list {
  display: flex;
  flex-direction: column;
  max-height: 280px;
  overflow-y: auto;
  padding: 0 8px;
}

.task-worklog-panel__user-filter-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 4px;
  margin: 0;
  border-radius: 4px;
  cursor: pointer;

  &:hover {
    background-color: var(--el-fill-color-light);
  }

  .el-checkbox {
    flex: 1;
    min-width: 0;
    margin-right: 0;
    height: auto;

    .el-checkbox__label {
      padding-left: 6px;
      min-width: 0;
      flex: 1;
    }
  }
}

.task-worklog-panel__user-filter-name-cell {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  max-width: 100%;
}

.task-worklog-panel__user-filter-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  color: var(--el-text-color-primary);

  &.is-owner {
    font-weight: 700;
  }
}

.task-worklog-panel__user-filter-owner-tag {
  flex: 0 0 auto;
}

.task-worklog-panel__user-filter-meta {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  flex: 0 0 auto;
  font-size: 12px;
  color: var(--el-text-color-secondary);
  font-variant-numeric: tabular-nums;
}

.task-worklog-panel__user-filter-hours {
  color: var(--el-color-primary);
  font-weight: 500;
}

.task-worklog-panel__user-filter-meta-sep {
  color: var(--el-text-color-placeholder);
}

.task-worklog-panel__user-filter-progress {
  color: var(--el-text-color-secondary);

  &.is-empty {
    color: var(--el-text-color-placeholder);
  }
}

.task-worklog-panel__user-filter-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 6px 8px 0;
  border-top: 1px solid var(--el-border-color-lighter);
  margin-top: 4px;
}

.task-worklog-panel__difficulty-filter-list {
  display: flex;
  flex-direction: column;
  padding: 0 12px;
}

.task-worklog-panel__difficulty-filter-row.el-radio {
  height: auto;
  margin: 0;
  padding: 4px 0;
}

.task-worklog-panel__difficulty-filter-row .el-radio__label {
  padding-left: 6px;
  flex: 1;
  min-width: 0;
}

.task-worklog-panel__difficulty-filter-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: 100%;
}

.task-worklog-panel__difficulty-filter-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
  flex: 0 0 auto;
}

.task-worklog-panel__difficulty-filter-label {
  color: var(--el-text-color-primary);
}

.task-worklog-panel__difficulty-filter-remark {
  margin-left: auto;
  color: var(--el-text-color-secondary);
  font-size: 12px;
}
</style>
