<template>
  <div class="plan-board-page">
    <!-- 顶部工具栏 -->
    <div class="board-toolbar">
      <n-space :size="8" align="center">
        <n-button type="primary" size="small" @click="handleAdd">
          <template #icon><n-icon><AddOutline /></n-icon></template>
          新增工序
        </n-button>
        <n-button size="small" type="success" ghost disabled title="待后端接口支持">
          <template #icon><n-icon><CheckmarkCircleOutline /></n-icon></template>
          齐套自动下达
        </n-button>
        <n-button size="small" type="error" ghost disabled title="待后端接口支持">批量删除</n-button>
        <n-button size="small" type="primary" ghost disabled title="待后端接口支持">批量下达</n-button>
        <n-button size="small" quaternary disabled title="待后端接口支持">合并为组工单</n-button>
        <n-dropdown :options="batchOptions" trigger="click" @select="onBatchSelect">
          <n-button size="small" quaternary>
            批量操作
            <n-icon style="margin-left: 4px"><ChevronDownOutline /></n-icon>
          </n-button>
        </n-dropdown>
      </n-space>
      <n-space :size="8" align="center">
        <n-button size="small" quaternary @click="importModalVisible = true">
          <template #icon><n-icon><CloudUploadOutline /></n-icon></template>
          导入
        </n-button>
        <n-button size="small" quaternary @click="handleExport">
          <template #icon><n-icon><DownloadOutline /></n-icon></template>
          导出
        </n-button>
        <n-button size="small" quaternary @click="loadData">
          <template #icon><n-icon><RefreshOutline /></n-icon></template>
          同步
        </n-button>
      </n-space>
    </div>

    <!-- 筛选 -->
    <div class="board-filter">
      <n-form inline :model="searchForm" label-placement="left" size="small">
        <n-form-item label="工序名称">
          <n-input v-model:value="searchForm.name" placeholder="工序名称" clearable style="width: 140px" />
        </n-form-item>
        <n-form-item label="工序编码">
          <n-input v-model:value="searchForm.code" placeholder="工序编码" clearable style="width: 140px" />
        </n-form-item>
        <n-form-item>
          <n-space>
            <n-button type="primary" size="small" @click="handleSearch">
              <template #icon><n-icon><SearchOutline /></n-icon></template>
              搜索
            </n-button>
            <n-button size="small" @click="handleReset">重置</n-button>
          </n-space>
        </n-form-item>
      </n-form>
    </div>

    <div class="board-table-wrap">
      <!-- 表头 -->
      <div class="board-table-head">
        <div class="col-check" />
        <div class="col-product">产品 / 工单编号</div>
        <div class="col-qty">数量</div>
        <div class="col-mode">模式</div>
        <div class="col-kit">齐套率</div>
        <div class="col-flow">工序</div>
        <div class="col-plan">计划开始 / 结束</div>
        <div class="col-life">生命周期</div>
        <div class="col-actions">操作</div>
      </div>

      <!-- 列表 -->
      <n-spin :show="loading">
      <div v-if="!tableData.length && !loading" class="board-empty">
        <n-empty description="暂无工序计划数据" />
      </div>

      <div v-for="order in tableData" :key="orderRowKey(order)" class="order-block">
        <div class="order-row" :class="{ expanded: isExpanded(order) }">
          <div class="col-check">
            <n-checkbox
              :checked="selectedOrderIds.includes(orderRowKey(order))"
              @update:checked="(v: boolean) => toggleSelect(orderRowKey(order), v)"
            />
          </div>
          <div class="col-product">
            <div class="product-name">{{ order.materialName || '-' }}</div>
            <div class="product-code">
              <span>{{ formatWorkOrderCodes(order) }}</span>
              <n-tag v-if="isOverdue(order)" size="tiny" type="error" :bordered="false">逾期</n-tag>
              <n-tag v-if="hasOutsource(order)" size="tiny" type="warning" :bordered="false">委外</n-tag>
            </div>
          </div>
          <div class="col-qty">{{ order.quantity ?? '-' }}</div>
          <div class="col-mode">
            <n-tag v-if="order.routeCode" size="tiny" :bordered="false">工艺型</n-tag>
            <n-tag v-if="order.workshopName" size="tiny" type="info" :bordered="false">{{ order.workshopName }}</n-tag>
          </div>
          <div class="col-kit">-</div>
          <div class="col-flow" :class="{ 'flow-expanded': isExpanded(order) }">
            <ProcessFlowStepper
              :list="order.processList"
              clickable
              @click="toggleExpand(order)"
            />
          </div>
          <div class="col-plan">
            <div>{{ formatShortTime(order.beginTime) }}</div>
            <div class="sub-text">{{ formatShortTime(order.endTime) }}</div>
          </div>
          <div class="col-life">
            <div class="life-cell">
              <n-icon :color="lifeIcon(order).color" size="18">
                <component :is="lifeIcon(order).icon" />
              </n-icon>
              <span>{{ lifeLabel(order) }}</span>
            </div>
          </div>
          <div class="col-actions">
            <n-button text type="primary" size="tiny" @click="openDetail(order)">详情</n-button>
            <n-button text type="info" size="tiny" @click="openPlmModel(order)">模型</n-button>
            <!-- 订单级编辑：打开工序顺序重排弹窗（不进单工序编辑） -->
            <n-button
              text
              type="primary"
              size="tiny"
              :disabled="!hasPermission('biz:orderProcessPlan:edit')"
              @click="openReorder(order)"
            >编辑</n-button>
            <n-dropdown :options="moreOptions" trigger="click" @select="(k) => onMoreSelect(k, order)">
              <n-button text size="tiny">更多</n-button>
            </n-dropdown>
          </div>
        </div>

        <div v-if="isExpanded(order)" class="order-expand">
          <div v-if="!(order.processList?.length)" class="expand-empty">暂无工序明细</div>
          <div v-else class="card-flow-scroll">
            <ProcessCard
              v-for="(proc, idx) in sortedProcessList(order.processList)"
              :key="proc.planId ?? idx"
              :process="proc"
              :material-code="order.materialCode"
              :order-code="order.orderCode"
              :order-begin-time="order.beginTime"
              :order-end-time="order.endTime"
              :workshop-name="order.workshopName"
              :is-last="idx === (order.processList?.length ?? 0) - 1"
              :can-edit="hasPermission('biz:orderItem:edit')"
              :can-assign="hasPermission('biz:orderItem:assign')"
              :can-outsource="hasPermission('biz:orderProcessPlan:add')"
              @edit="(p) => handleEdit(p, order)"
              @assign="(p) => disphand(p, order)"
              @outsource="(p) => openOutsource(order, p)"
              @view-model="(p) => openPlmModel(order, p)"
              @submit-detail = "(p) => openDetailModel(order,p)"
            />
          </div>
        </div>
      </div>
      </n-spin>
    </div>

    <!--模型抽屉 -->
    <PlmModelDrawer ref="plmModelDrawerRef" />

    <div class="board-pagination">
      <n-pagination
        v-model:page="pagination.page"
        v-model:page-size="pagination.pageSize"
        :item-count="pagination.itemCount"
        :page-sizes="[10, 20, 50, 100]"
        show-size-picker
        show-quick-jumper
        @update:page="handlePageChange"
        @update:page-size="handlePageSizeChange"
      >
        <template #prefix>共 {{ pagination.itemCount }} 条</template>
      </n-pagination>
    </div>

    <!-- 详情弹窗 -->
    <n-modal v-model:show="detailVisible" preset="card" title="工序计划详情" style="width: 900px">
      <n-spin :show="detailLoading">
        <template v-if="detailData">
          <n-descriptions :column="3" bordered size="small" label-placement="left">
            <n-descriptions-item label="生产令号">{{ detailData.mainCode || '-' }}</n-descriptions-item>
            <n-descriptions-item label="工单号">{{ formatWorkOrderCodes(detailData) }}</n-descriptions-item>
            <n-descriptions-item label="物料">{{ detailData.materialName || '-' }}</n-descriptions-item>
            <n-descriptions-item label="数量">{{ detailData.quantity ?? '-' }}</n-descriptions-item>
            <n-descriptions-item label="工艺路线">{{ detailData.routeCode || '-' }}</n-descriptions-item>
            <n-descriptions-item label="车间">{{ detailData.workshopName || '-' }}</n-descriptions-item>
            <n-descriptions-item label="计划开工">{{ detailData.beginTime || '-' }}</n-descriptions-item>
            <n-descriptions-item label="计划完工">{{ detailData.endTime || '-' }}</n-descriptions-item>
            <n-descriptions-item label="订单状态">{{ lifeLabel(detailData) }}</n-descriptions-item>
          </n-descriptions>
          <div class="detail-cards">
            <ProcessCard
              v-for="(proc, idx) in (detailData.processList)"
              :key="proc.planId ?? idx"
              :process="proc"
              :material-code="detailData.materialCode"
              :order-code="detailData.orderCode"
              :order-begin-time="detailData.beginTime"
              :order-end-time="detailData.endTime"
              :workshop-name="detailData.workshopName"
              :is-last="idx === (detailData.processList?.length ?? 0) - 1"
              :can-edit="hasPermission('biz:orderItem:edit')"
              :can-assign="hasPermission('biz:orderItem:assign')"
              :can-outsource="hasPermission('biz:orderProcessPlan:add')"
              :can-submitDetail="hasPermission('biz:submitLog:detail')"
              @edit="(p) => handleEdit(p, detailData!)"
              @assign="(p) => disphand(p, detailData!)"
              @outsource="(p) => openOutsource(detailData!, p)"
              @view-model="(p) => openPlmModel(detailData!, p)"
            />
          </div>
        </template>
      </n-spin>
    </n-modal>

    <!-- 订单级工序顺序重排：拖拽 / 上移下移，只提交 planId 顺序 -->
    <n-modal
      v-model:show="reorderVisible"
      preset="card"
      title="调整工序顺序"
      style="width: 640px"
      :mask-closable="false"
      @after-leave="resetReorder"
    >
      <n-spin :show="reorderLoading">
        <n-alert type="info" style="margin-bottom: 12px">
          拖拽行或使用上移/下移调整顺序；保存后按 10、20、30… 重写工序号。存在派工工单或已有转出数量的工序不可调整。
        </n-alert>
        <div v-if="reorderOrderMeta" class="reorder-meta">
          <span>令号：{{ reorderOrderMeta.mainCode || '-' }}</span>
          <span>物料：{{ reorderOrderMeta.materialName || '-' }}</span>
          <span>数量：{{ reorderOrderMeta.quantity ?? '-' }}</span>
        </div>
        <div v-if="!reorderList.length && !reorderLoading" class="reorder-empty">暂无工序可调整</div>
        <VueDraggable
          v-else
          v-model="reorderList"
          :animation="150"
          handle=".reorder-drag-handle"
          class="reorder-list"
        >
          <div
            v-for="(proc, idx) in reorderList"
            :key="proc.planId ?? idx"
            class="reorder-item"
          >
            <n-icon class="reorder-drag-handle" size="18" :depth="3">
              <MenuOutline />
            </n-icon>
            <span class="reorder-index">{{ idx + 1 }}</span>
            <div class="reorder-body">
              <div class="reorder-title">
                <em v-if="proc.operNumber != null">{{ proc.operNumber }}</em>
                {{ proc.processName || '-' }}
              </div>
              <div class="reorder-sub">
                {{ proc.processCode || '-' }} · {{ proc.workOrderCode || '-' }}
              </div>
            </div>
            <n-space :size="4">
              <n-button
                size="tiny"
                quaternary
                :disabled="idx === 0"
                @click="moveReorderItem(idx, -1)"
              >上移</n-button>
              <n-button
                size="tiny"
                quaternary
                :disabled="idx === reorderList.length - 1"
                @click="moveReorderItem(idx, 1)"
              >下移</n-button>
            </n-space>
          </div>
        </VueDraggable>
      </n-spin>
      <template #footer>
        <n-space justify="end">
          <n-button @click="reorderVisible = false">取消</n-button>
          <n-button
            type="primary"
            :loading="reorderSubmitLoading"
            :disabled="!reorderList.length"
            @click="submitReorder"
          >保存顺序</n-button>
        </n-space>
      </template>
    </n-modal>

    <!-- 新增/编辑（单工序字段；顺序请用上方重排弹窗） -->
    <n-modal v-model:show="modalVisible" preset="card" :title="modalTitle" style="width: 800px">
      <n-form ref="formRef" :model="formData" :rules="formRules" label-placement="left" label-width="120px">
        <n-grid :cols="2">
          <n-gi>
            <n-form-item label="工序名称" path="name">
              <n-input v-model:value="formData.name" placeholder="请输入工序名称" />
            </n-form-item>
          </n-gi>
          <n-gi>
            <n-form-item label="工序编码" path="code">
              <n-input v-model:value="formData.code" placeholder="请输入工序编码" />
            </n-form-item>
          </n-gi>
          <n-gi>
            <!-- 顺序请走订单行「编辑」重排，避免单条改 sort 撞号断链 -->
            <n-form-item label="工序顺序" path="sort">
              <n-input v-model:value="formData.sort" placeholder="请通过订单编辑调整顺序" disabled />
            </n-form-item>
          </n-gi>
          <n-gi>
            <n-form-item label="生产订单id" path="orderItemId">
              <n-input v-model:value="formData.orderItemId" placeholder="请输入生产订单id" />
            </n-form-item>
          </n-gi>
          <n-gi>
            <n-form-item label="生产开始时间" path="beginTime">
              <n-date-picker v-model:value="formData.beginTime" type="datetime" clearable style="width: 100%" />
            </n-form-item>
          </n-gi>
          <n-gi>
            <n-form-item label="生产结束时间" path="endTime">
              <n-date-picker v-model:value="formData.endTime" type="datetime" clearable style="width: 100%" />
            </n-form-item>
          </n-gi>
          <n-gi>
            <n-form-item label="生产总数" path="quantity">
              <n-input v-model:value="formData.quantity" placeholder="请输入生产总数" />
            </n-form-item>
          </n-gi>
          <n-gi>
            <n-form-item label="转入数量" path="transferNum">
              <n-input v-model:value="formData.transferNum" placeholder="请输入转入数量" />
            </n-form-item>
          </n-gi>
        </n-grid>
      </n-form>
      <template #footer>
        <n-space justify="end">
          <n-button @click="modalVisible = false">取消</n-button>
          <n-button type="primary" @click="handleSubmit">确定</n-button>
        </n-space>
      </template>
    </n-modal>

    <!-- 工序工单拆单（整单：全部工序一起按数量拆） -->
    <SplitProcessDialog
      v-model:show="splitVisible"
      :plan-id="splitPlanId"
      @success="onSplitSuccess"
    />

    <!-- 派工 -->
    <n-modal v-model:show="dispatchmodal" title="工序派工" preset="card" style="width: 800px" :mask-closable="false">
      <n-divider />
      <n-card>
        <n-grid :cols="2">
          <n-gi>
            <span class="pgClass">当前工序：</span>
            <span>{{dispatchform.name}}</span>
          </n-gi>
           <n-gi>
            <span class="pgClass">计划数量：</span>
            <span>{{dispatchform.quantity}}</span>
          </n-gi>
        </n-grid>
        <n-grid :cols="2">
          <n-gi>
            <span class="pgClass">已完成：</span>
            <span>{{dispatchform.completedQty ?? 0}}</span>
          </n-gi>
          <n-gi>
            <span class="pgClass">本次待派：</span>
            <span style="color: #2080f0; font-weight: 600">{{dispatchform.remainQty}}</span>
          </n-gi>
        </n-grid>
        <n-grid :cols="2">
          <n-gi>
            <span class="pgClass">开始时间：</span>
            <span>{{dispatchform.beginTime}}</span>
          </n-gi>
         <n-gi>
            <span class="pgClass">结束时间：</span>
            <span>{{dispatchform.endTime}}</span>
          </n-gi>
        </n-grid>
      </n-card>
      <n-form ref="dispatchformRef" :model="dispatchform"
       label-placement="left" 
       :rules="dispatchrules"
       style="margin-top: 10px;"
       label-width="80">
        <n-grid :cols="2">
          <n-gi :span="24">
            <Pgitem
              v-for="(n, i) in dispatchform.list"
              :key="i"
              :obj="n"
              :index="i"
              :section-id="dispatchform.sectionId"
              :workshop-id="dispatchform.workshopId"
              listname="list"
              @addhand="addpgnum"
              @delehand="deletenum(i)"
            />
          </n-gi>
        </n-grid>
      </n-form>
      <template #footer>
        <n-space justify="end">
          <n-button size="small" @click="dispatchmodal = false">取消</n-button>
          <n-button size="small" type="primary" :loading="dispatchLoading" @click="dispatchSubmit">确定</n-button>
        </n-space>
      </template>
    </n-modal>

    <!-- 工序委外 -->
    <n-modal
      v-model:show="outsourceModalVisible"
      preset="card"
      :title="outsourceStep === 1 ? '创建工序委外 - 选择工序' : '创建工序委外 - 填写信息'"
      style="width: 720px"
      :mask-closable="false"
      @after-leave="resetOutsourceForm"
    >
      <n-spin :show="outsourceOptionsLoading">
        <template v-if="outsourceStep === 1 && outsourceOptions">
          <n-descriptions :column="2" bordered size="small" label-placement="left" style="margin-bottom: 16px">
            <n-descriptions-item label="生产令号">{{ outsourceOptions.mainCode || '-' }}</n-descriptions-item>
            <n-descriptions-item label="订单编码">{{ outsourceOptions.orderCode || '-' }}</n-descriptions-item>
            <n-descriptions-item label="物料编码">{{ outsourceOptions.materialCode || '-' }}</n-descriptions-item>
            <n-descriptions-item label="物料名称">{{ outsourceOptions.materialName || '-' }}</n-descriptions-item>
            <n-descriptions-item label="生产数量">{{ outsourceOptions.quantity ?? '-' }}</n-descriptions-item>
          </n-descriptions>
          <n-radio-group v-model:value="outsourceSelectedPlanId" style="width: 100%">
            <n-space vertical :size="8" style="width: 100%">
              <div
                v-for="proc in outsourceOptions.processList"
                :key="proc.planId"
                class="outsource-process-item"
                :class="{ active: outsourceSelectedPlanId === proc.planId }"
                @click="outsourceSelectedPlanId = proc.planId!"
              >
                <n-radio :value="proc.planId" />
                <div class="outsource-process-body">
                  <div class="outsource-process-title">
                    <span>{{ proc.processName || '-' }}</span>
                    <n-tag v-if="proc.current" size="tiny" type="info" :bordered="false">当前</n-tag>
                    <n-tag v-if="proc.outsource === 1" size="tiny" type="warning" :bordered="false">已委外</n-tag>
                  </div>
                  <div class="outsource-process-meta">
                    <span>工单号：{{ proc.workOrderCode || '-' }}</span>
                    <span>工序号：{{ proc.operNumber ?? '-' }}</span>
                    <span>数量：{{ proc.quantity ?? '-' }}</span>
                  </div>
                </div>
              </div>
            </n-space>
          </n-radio-group>
        </template>

        <template v-else-if="outsourceStep === 2">
          <n-card size="small" style="margin-bottom: 16px">
            <n-grid :cols="2" :x-gap="12">
              <n-gi>
                <span class="pgClass">委外工序：</span>
                <span>{{ selectedOutsourceProcess?.processName || '-' }}</span>
              </n-gi>
              <n-gi>
                <span class="pgClass">工单号：</span>
                <span>{{ selectedOutsourceProcess?.workOrderCode || '-' }}</span>
              </n-gi>
              <n-gi>
                <span class="pgClass">物料：</span>
                <span>{{ outsourceOptions?.materialName || '-' }}</span>
              </n-gi>
              <n-gi>
                <span class="pgClass">工序数量：</span>
                <span>{{ selectedOutsourceProcess?.quantity ?? '-' }}</span>
              </n-gi>
            </n-grid>
          </n-card>
          <n-form
            ref="outsourceFormRef"
            :model="outsourceForm"
            :rules="outsourceRules"
            label-placement="left"
            label-width="110"
          >
            <n-form-item label="供应商" path="supplierName">
              <n-input v-model:value="outsourceForm.supplierName" placeholder="请输入供应商名称" />
            </n-form-item>
            <n-form-item label="委外数量" path="quantity">
              <n-input-number
                v-model:value="outsourceForm.quantity"
                :min="1"
                :max="selectedOutsourceProcess?.quantity ?? undefined"
                :precision="0"
                placeholder="请输入委外数量"
                style="width: 100%"
              />
            </n-form-item>
            <n-form-item label="单价" path="unitPrice">
              <n-input-number
                v-model:value="outsourceForm.unitPrice"
                :min="0"
                :precision="2"
                placeholder="请输入单价（选填）"
                style="width: 100%"
              />
            </n-form-item>
            <n-form-item label="计划开始时间" path="planStartTime">
              <n-date-picker
                v-model:value="outsourceForm.planStartTime"
                type="datetime"
                clearable
                style="width: 100%"
              />
            </n-form-item>
            <n-form-item label="计划结束时间" path="planEndTime">
              <n-date-picker
                v-model:value="outsourceForm.planEndTime"
                type="datetime"
                clearable
                style="width: 100%"
              />
            </n-form-item>
            <n-form-item label="备注" path="remark">
              <n-input
                v-model:value="outsourceForm.remark"
                type="textarea"
                placeholder="请输入备注（选填）"
                :autosize="{ minRows: 2, maxRows: 4 }"
              />
            </n-form-item>
          </n-form>
        </template>
      </n-spin>
      <template #footer>
        <n-space justify="end">
          <n-button @click="outsourceModalVisible = false">取消</n-button>
          <n-button v-if="outsourceStep === 2" @click="outsourceStep = 1">上一步</n-button>
          <n-button
            v-if="outsourceStep === 1"
            type="primary"
            :disabled="!outsourceSelectedPlanId"
            @click="goOutsourceStep2"
          >下一步</n-button>
          <n-button
            v-else
            type="primary"
            :loading="outsourceSubmitLoading"
            @click="submitOutsource"
          >确认创建</n-button>
        </n-space>
      </template>
    </n-modal>

    <!-- 导入 -->
    <n-modal v-model:show="importModalVisible" preset="card" title="导入工序计划" style="width: 500px">
      <n-space vertical>
        <n-alert type="info">
          <template #header>导入说明</template>
          请先下载模板，按格式填写后上传 .xlsx / .xls 文件。
        </n-alert>
        <n-button type="primary" @click="handleDownloadTemplate">
          <template #icon><n-icon><DownloadOutline /></n-icon></template>
          下载模板
        </n-button>
        <n-upload :max="1" accept=".xlsx,.xls" :custom-request="handleImportUpload">
          <n-upload-dragger>
            <n-text>点击或拖拽文件到此处上传</n-text>
          </n-upload-dragger>
        </n-upload>
      </n-space>
    </n-modal>


    <!-- 汇报详情弹窗 -->
    <n-modal v-model:show="submitLogModalVisible" preset="card" title="工序汇报详情" style="width: 2000px">
      <ReportDetailPage
        :planId="processId"
      />
      <template #footer>
        <n-space justify="end">
          <n-button size="small" @click="submitLogModalVisible = false">取消</n-button>
        </n-space>
      </template>
    </n-modal>


    <n-modal v-model:show="submitModalVisible" preset="card" title="工单汇报详情" style="width: 2000px">
      <OrderReportDetailPage
        :orderItemId="orderItemId"
      />
      <template #footer>
        <n-space justify="end">
          <n-button size="small" @click="submitLogModalVisible = false">取消</n-button>
        </n-space>
      </template>
    </n-modal>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted, h, computed, type Component } from 'vue'
import {
  NButton, NSpace, NIcon, NTag, NSpin, NModal, NForm, NFormItem, NGrid, NGi,
  NInput, NInputNumber, NDatePicker, NCheckbox, NEmpty, NPagination, NDropdown, NDescriptions,
  NDescriptionsItem, NAlert, NUpload, NText, NCard, NRadioGroup, NRadio, NDivider, useMessage, useDialog,
  type UploadCustomRequestOptions, type FormRules,
} from 'naive-ui'
import {
  AddOutline, SearchOutline, RefreshOutline, CloudUploadOutline,
  DownloadOutline, ChevronDownOutline, CheckmarkCircleOutline, CheckmarkCircle,
  EllipseOutline, TimeOutline, PrintOutline, PeopleOutline,
  GitBranchOutline, CloseCircleOutline, LockClosedOutline, TrashOutline, EyeSharp,
  MenuOutline,
} from '@vicons/ionicons5'
import { VueDraggable } from 'vue-draggable-plus'
import {
  orderProcessPlanApi,
  toOrderProcessPlanPayload,
  processItemToEntity,
  ORDER_STATUS_MAP,
  type OrderProcessPlanVO,
  type ProcessPlanItemVO,
  type OutsourcingOptions,
  type OutsourcingProcessOption,
} from '@/api/orderProcessPlan'
import { useUserStore } from '@/stores/user'
import ProcessFlowStepper from './components/ProcessFlowStepper.vue'
import ProcessCard from './components/ProcessCard.vue'
import SplitProcessDialog from './components/SplitProcessDialog.vue'
import PlmModelDrawer from '@/components/PlmModelDrawer.vue'
import type { PlmModelOpenContext } from '@/api/plmModel'
import Pgitem from './pgitem.vue'
import ReportDetailPage from "@/views/biz/orderProcessPlan/components/ReportDetail.vue";
import OrderReportDetailPage from "@/views/biz/orderProcessPlan/components/OrderReportDetail.vue";


const message = useMessage()
const dialog = useDialog()
const userStore = useUserStore()
const hasPermission = (p: string) => userStore.hasPermission(p)

const searchForm = reactive({
  name: '',
  code: '',
})

const tableData = ref<OrderProcessPlanVO[]>([])
const expandedIds = ref<Set<string>>(new Set())
const selectedOrderIds = ref<string[]>([])
const loading = ref(false)
const pagination = reactive({ page: 1, pageSize: 10, itemCount: 0 })

const detailVisible = ref(false)
const detailLoading = ref(false)
const detailData = ref<OrderProcessPlanVO | null>(null)

/** 工序工单拆单 */
const splitVisible = ref(false)
const splitPlanId = ref<number | null>(null)

/** 订单级工序重排弹窗状态 */
const reorderVisible = ref(false)
const reorderLoading = ref(false)
const reorderSubmitLoading = ref(false)
const reorderOrderItemId = ref<number | null>(null)
const reorderOrderMeta = ref<OrderProcessPlanVO | null>(null)
/** 弹窗内可拖拽的工序列表（按当前展示顺序） */
const reorderList = ref<ProcessPlanItemVO[]>([])

const modalVisible = ref(false)
const modalTitle = ref('')
const formRef = ref()
const defaultFormData = {
  name: '', code: '', sort: '', orderItemId: '',
  beginTime: null as number | null, endTime: null as number | null,
  quantity: '', transferNum: '', transferOutNum: '',
  procurement: '', outsource: '', qualityInspection: '', storageEntry: '',
}
const formData = reactive<any>({ ...defaultFormData })
const formRules = {}

const dispatchmodal = ref(false)
const dispatchLoading = ref(false)
const dispatchformRef = ref()
const dispatchform = reactive<any>({
  id: '', name: '', beginTime: '', endTime: '', quantity: '', sectionId: null as number | null, workshopId: null as number | null,
  list: [{ sectionId:'',deviceId:'', quantity: '', ncId:'' }],
})
const dispatchrules = {}

const importModalVisible = ref(false)
const plmModelDrawerRef = ref<InstanceType<typeof PlmModelDrawer> | null>(null)

const submitModalVisible = ref<Boolean>(false)

const outsourceModalVisible = ref(false)
const outsourceOptionsLoading = ref(false)
const outsourceSubmitLoading = ref(false)
const outsourceStep = ref(1)
const outsourceOptions = ref<OutsourcingOptions | null>(null)
const outsourceSelectedPlanId = ref<number | null>(null)
const outsourceFormRef = ref()
const outsourceForm = reactive({
  supplierName: '',
  quantity: null as number | null,
  unitPrice: null as number | null,
  planStartTime: null as number | null,
  planEndTime: null as number | null,
  remark: '',
})
const outsourceRules: FormRules = {
  supplierName: [{ required: true, message: '请输入供应商', trigger: 'blur' }],
  quantity: [{ required: true, type: 'number', message: '请输入委外数量', trigger: ['blur', 'change'] }],
}

const selectedOutsourceProcess = computed<OutsourcingProcessOption | null>(() => {
  if (!outsourceSelectedPlanId.value) return null
  return outsourceOptions.value?.processList?.find(p => p.planId === outsourceSelectedPlanId.value) ?? null
})

function openPlmModel(order: OrderProcessPlanVO, process?: ProcessPlanItemVO) {
  const ctx: PlmModelOpenContext = {
    orderItemId: order.orderItemId,
    materialCode: order.materialCode,
    materialName: order.materialName,
    drawingNo: order.materialCode,
    title: process
      ? `三维模型 · ${process.processName || process.processCode || ''}`
      : `三维模型 · ${order.materialName || order.materialCode || ''}`,
  }
  if (process?.planId) ctx.processPlanId = process.planId
  plmModelDrawerRef.value?.open(ctx)
}

//汇报记录详情
const submitLogModalVisible = ref<Boolean>(false)
const processId = ref<number | null>(null)

//汇报详情
function openDetailModel(order:ProcessPlanItemVO,process?:OrderProcessPlanVO) {
 
  submitLogModalVisible.value = true
  console.log(process.planId)
  processId.value = process.planId

}

const batchOptions = [
  { label: '全部展开', key: 'expandAll' },
  { label: '全部收起', key: 'collapseAll' },
]

function dropdownIcon(icon: Component) {
  return () => h(NIcon, null, { default: () => h(icon) })
}

function dangerDropdownItem(label: string, key: string, icon: Component) {
  return {
    label,
    key,
    icon: () => h(NIcon, { color: '#d03050' }, { default: () => h(icon) }),
    props: { style: { color: '#d03050' } },
  }
}

const moreOptions = [
  {
    type: 'group',
    label: '查看与编辑',
    key: 'group-view-edit',
    children: [
      { label: '打印', key: 'print', icon: dropdownIcon(PrintOutline) },
    ],
  },
  {
    type: 'group',
    label: '派生操作',
    key: 'group-derived',
    children: [
      { label: '创建工序委外', key: 'createOutsource', icon: dropdownIcon(PeopleOutline) },
      { label: '拆分工单', key: 'splitWorkOrder', icon: dropdownIcon(GitBranchOutline) },
      { label: '汇报详情', key: 'reportDetailView', icon: dropdownIcon(EyeSharp) },
    ],
  },
  {
    type: 'group',
    label: '状态控制',
    key: 'group-status',
    children: [
      dangerDropdownItem('撤回', 'withdraw', CloseCircleOutline),
      dangerDropdownItem('冻结工单', 'freeze', LockClosedOutline),
    ],
  },
  {
    type: 'group',
    label: '危险操作',
    key: 'group-danger',
    children: [
      dangerDropdownItem('删除', 'delete', TrashOutline),
    ],
  },
]

/** 列表行主键：按工单号（拆单后同订单多工单分行） */
function orderRowKey(row: OrderProcessPlanVO) {
  if (row.workOrderCode) return row.workOrderCode
  return `oi-${row.orderItemId ?? 'x'}`
}

/** 订单级工单号展示 */
function formatWorkOrderCodes(order?: OrderProcessPlanVO | null) {
  if (order?.workOrderCode) return order.workOrderCode
  const codes = (order?.processList ?? [])
    .map((p) => p.workOrderCode)
    .filter((c): c is string => !!c)
  const unique = [...new Set(codes)]
  return unique.length ? unique.join('、') : '-'
}

function sortedProcessList(list?: ProcessPlanItemVO[]) {
  return [...(list ?? [])].sort((a, b) => {
    const oa = a.operNumber ?? 0
    const ob = b.operNumber ?? 0
    if (oa !== ob) return oa - ob
    return (a.planId ?? 0) - (b.planId ?? 0)
  })
}

function isExpanded(order: OrderProcessPlanVO) {
  return expandedIds.value.has(orderRowKey(order))
}

function toggleExpand(order: OrderProcessPlanVO) {
  const key = orderRowKey(order)
  const next = new Set(expandedIds.value)
  if (next.has(key)) next.delete(key)
  else next.add(key)
  expandedIds.value = next
}

/** 整单拆分入口：有计划数量且未全部完工即可点开 */
function canSplitWorkOrder(order: OrderProcessPlanVO) {
  const qty = order.quantity ?? 0
  if (qty <= 0) return false
  if (order.orderStatus === 2) return false
  return (order.processList?.length ?? 0) > 0
}

function openSplitFromOrder(order: OrderProcessPlanVO) {
  if (!hasPermission('biz:orderProcessPlan:edit')) {
    message.warning('无拆单权限')
    return
  }
  const list = sortedProcessList(order.processList)
  const seed = list.find((p) => p.planId != null)
  if (!seed?.planId) {
    message.warning('当前工单暂无工序，无法拆单')
    return
  }
  if (!canSplitWorkOrder(order)) {
    message.warning('该工单不可拆（无数量或已完工）')
    return
  }
  splitPlanId.value = seed.planId
  splitVisible.value = true
}

function onSplitSuccess() {
  loadData()
  if (detailVisible.value && detailData.value?.orderItemId) {
    openDetail(detailData.value)
  }
}

function toggleSelect(id: string, checked: boolean) {
  if (checked) selectedOrderIds.value = [...selectedOrderIds.value, id]
  else selectedOrderIds.value = selectedOrderIds.value.filter(v => v !== id)
}

function formatShortTime(val?: string | null) {
  if (!val) return '-'
  return val.length > 16 ? val.slice(0, 16) : val
}

function isOverdue(order: OrderProcessPlanVO) {
  if (order.orderStatus === 2 || !order.endTime) return false
  return new Date(order.endTime.replace(' ', 'T')).getTime() < Date.now()
}

function hasOutsource(order: OrderProcessPlanVO) {
  return order.processList?.some(p => p.outsource === 1)
}

function lifeLabel(order: OrderProcessPlanVO) {
  const s = order.orderStatus
  if (s == null) return '-'
  return ORDER_STATUS_MAP[s]?.label ?? String(s)
}

function lifeIcon(order: OrderProcessPlanVO) {
  const s = order.orderStatus
  if (s === 2) return { icon: CheckmarkCircle, color: '#18a058' }
  if (s === 1) return { icon: TimeOutline, color: '#2080f0' }
  return { icon: EllipseOutline, color: '#8c8c8c' }
}

async function loadData() {
  loading.value = true
  try {
    const res = await orderProcessPlanApi.page({
      page: pagination.page,
      pageSize: pagination.pageSize,
      name: searchForm.name || undefined,
      code: searchForm.code || undefined,
    })
    tableData.value = res.list ?? []
    pagination.itemCount = res.total
  } finally {
    loading.value = false
  }
}

function handleSearch() {
  pagination.page = 1
  loadData()
}

function handleReset() {
  searchForm.name = ''
  searchForm.code = ''
  handleSearch()
}

function handlePageChange(page: number) {
  pagination.page = page
  loadData()
}

function handlePageSizeChange(pageSize: number) {
  pagination.pageSize = pageSize
  pagination.page = 1
  loadData()
}

function onBatchSelect(key: string) {
  if (key === 'expandAll') {
    expandedIds.value = new Set(tableData.value.map(o => orderRowKey(o)))
  } else if (key === 'collapseAll') {
    expandedIds.value = new Set()
  }
}

function onMoreSelect(key: string, order: OrderProcessPlanVO) {
  if (key === 'createOutsource') {
    openOutsource(order)
    return
  }
  if (key === 'reportDetailView') {
    openReportDetail(order)
    return;
  }
  if (key === 'splitWorkOrder') {
    openSplitFromOrder(order)
    return
  }

  const labels: Record<string, string> = {
    print: '打印',
    withdraw: '撤回',
    freeze: '冻结工单',
    delete: '删除',
  }
  if (labels[key]) message.info(`${labels[key]}功能待后端接口支持`)
}

function resolveDefaultPlanId(order: OrderProcessPlanVO, process?: ProcessPlanItemVO) {
  if (process?.planId) return process.planId
  const list = sortedProcessList(order.processList)
  if (!list.length) return null
  const current = list.find(p => p.operNumber === order.currentOperNumber)
  return current?.planId ?? list[0].planId ?? null
}

function resetOutsourceForm() {
  outsourceStep.value = 1
  outsourceOptions.value = null
  outsourceSelectedPlanId.value = null
  outsourceForm.supplierName = ''
  outsourceForm.quantity = null
  outsourceForm.unitPrice = null
  outsourceForm.planStartTime = null
  outsourceForm.planEndTime = null
  outsourceForm.remark = ''
  outsourceFormRef.value?.restoreValidation()
}

function fillOutsourceFormFromProcess(proc?: OutsourcingProcessOption | null) {
  if (!proc) return
  outsourceForm.quantity = proc.quantity ?? null
  outsourceForm.planStartTime = parseDateTime(proc.planStartTime)
  outsourceForm.planEndTime = parseDateTime(proc.planFinishTime)
}

async function openOutsource(order: OrderProcessPlanVO, process?: ProcessPlanItemVO) {
  const planId = resolveDefaultPlanId(order, process)
  if (!planId) {
    message.warning('当前订单暂无可委外工序')
    return
  }
  resetOutsourceForm()
  outsourceModalVisible.value = true
  outsourceOptionsLoading.value = true
  try {
    const options = await orderProcessPlanApi.getOutsourcingOptions(planId)
    outsourceOptions.value = options
    const preferredId = process?.planId ?? options.currentProcessPlanId ?? options.processList?.[0]?.planId ?? null
    outsourceSelectedPlanId.value = preferredId
    if (process?.planId) {
      outsourceStep.value = 2
      fillOutsourceFormFromProcess(selectedOutsourceProcess.value)
    }
  } catch {
    outsourceModalVisible.value = false
  } finally {
    outsourceOptionsLoading.value = false
  }
}

function goOutsourceStep2() {
  if (!outsourceSelectedPlanId.value) {
    message.warning('请选择委外工序')
    return
  }
  fillOutsourceFormFromProcess(selectedOutsourceProcess.value)
  outsourceStep.value = 2
}

function formatSubmitDateTime(ts: number | null) {
  if (!ts) return undefined
  return new Date(ts).toISOString().slice(0, 19).replace('T', ' ')
}

async function submitOutsource() {
  await outsourceFormRef.value?.validate()
  if (!outsourceSelectedPlanId.value) {
    message.warning('请选择委外工序')
    return
  }
  const maxQty = selectedOutsourceProcess.value?.quantity
  if (maxQty != null && (outsourceForm.quantity ?? 0) > maxQty) {
    message.error(`委外数量不能大于工序数量 ${maxQty}`)
    return
  }
  if (outsourceForm.planStartTime && outsourceForm.planEndTime
    && outsourceForm.planEndTime < outsourceForm.planStartTime) {
    message.error('计划结束时间不能早于计划开始时间')
    return
  }
  outsourceSubmitLoading.value = true
  try {
    await orderProcessPlanApi.createOutsourcing({
      processPlanId: outsourceSelectedPlanId.value,
      supplierName: outsourceForm.supplierName.trim(),
      quantity: outsourceForm.quantity!,
      unitPrice: outsourceForm.unitPrice ?? undefined,
      planStartTime: formatSubmitDateTime(outsourceForm.planStartTime),
      planEndTime: formatSubmitDateTime(outsourceForm.planEndTime),
      remark: outsourceForm.remark || undefined,
    })
    message.success('委外单创建成功')
    outsourceModalVisible.value = false
    loadData()
  } finally {
    outsourceSubmitLoading.value = false
  }
}

async function openDetail(order: OrderProcessPlanVO) {
  if (!order.orderItemId) return
  detailVisible.value = true
  detailLoading.value = true
  detailData.value = null
  try {
    detailData.value = await orderProcessPlanApi.detail(order.orderItemId, order.workOrderCode)
  } catch {
    detailData.value = order
  } finally {
    detailLoading.value = false
  }
}

/** 打开订单级工序顺序调整（拉详情，按 operNumber 排序后供拖拽） */
async function openReorder(order: OrderProcessPlanVO) {
  if (!order.orderItemId) {
    message.warning('缺少生产订单id')
    return
  }
  reorderVisible.value = true
  reorderLoading.value = true
  reorderOrderItemId.value = order.orderItemId
  reorderOrderMeta.value = order
  reorderList.value = []
  try {
    const detail = await orderProcessPlanApi.detail(order.orderItemId, order.workOrderCode)
    reorderOrderMeta.value = detail
    // 仅当前工单工序，按 operNumber 升序
    reorderList.value = sortedProcessList(detail.processList).map((p) => ({ ...p }))
    if (!reorderList.value.length) {
      message.warning('当前工单暂无工序计划')
    }
  } catch {
    // 详情失败时降级用列表行数据，仍可本地排序后提交
    reorderList.value = sortedProcessList(order.processList).map((p) => ({ ...p }))
  } finally {
    reorderLoading.value = false
  }
}

function resetReorder() {
  reorderOrderItemId.value = null
  reorderOrderMeta.value = null
  reorderList.value = []
  reorderSubmitLoading.value = false
}

/** 上移 / 下移（delta: -1 上移，+1 下移） */
function moveReorderItem(index: number, delta: number) {
  const next = index + delta
  if (next < 0 || next >= reorderList.value.length) return
  const list = [...reorderList.value]
  const [item] = list.splice(index, 1)
  list.splice(next, 0, item)
  reorderList.value = list
}

/** 提交重排：只传 orderItemId + planId 顺序 */
async function submitReorder() {
  if (!reorderOrderItemId.value) {
    message.warning('缺少生产订单id')
    return
  }
  if (!reorderList.value.length) {
    message.warning('暂无工序可保存')
    return
  }
  const missing = reorderList.value.some((p) => p.planId == null)
  if (missing) {
    message.error('存在缺少 planId 的工序，请刷新后重试')
    return
  }
  reorderSubmitLoading.value = true
  try {
    await orderProcessPlanApi.reorder({
      orderItemId: reorderOrderItemId.value,
      items: reorderList.value.map((p) => ({ planId: p.planId! })),
    })
    message.success('工序顺序已更新')
    reorderVisible.value = false
    loadData()
  } finally {
    reorderSubmitLoading.value = false
  }
}

function handleAdd() {
  modalTitle.value = '新增工序计划'
  Object.assign(formData, defaultFormData)
  modalVisible.value = true
}

function parseDateTime(val: string | null | undefined) {
  if (!val) return null
  const ts = new Date(val.replace(' ', 'T')).getTime()
  return Number.isNaN(ts) ? null : ts
}

function handleEdit(process: ProcessPlanItemVO, order?: OrderProcessPlanVO) {
  modalTitle.value = '编辑工序计划'
  const entity = processItemToEntity(process, order?.orderItemId)
  Object.assign(formData, {
    ...defaultFormData,
    ...entity,
    sort: entity.sort != null ? String(entity.sort) : '',
    orderItemId: entity.orderItemId != null ? String(entity.orderItemId) : '',
    quantity: entity.quantity != null ? String(entity.quantity) : '',
    transferNum: entity.transferNum != null ? String(entity.transferNum) : '',
    beginTime: parseDateTime(entity.beginTime),
    endTime: parseDateTime(entity.endTime),
  })
  modalVisible.value = true
}

async function handleSubmit() {
  await formRef.value?.validate()
  const submitData = toOrderProcessPlanPayload({ ...formData })
  if (typeof submitData.beginTime === 'number') {
    submitData.beginTime = new Date(submitData.beginTime).toISOString().slice(0, 19).replace('T', ' ')
  }
  if (typeof submitData.endTime === 'number') {
    submitData.endTime = new Date(submitData.endTime).toISOString().slice(0, 19).replace('T', ' ')
  }
  if (submitData.id) {
    await orderProcessPlanApi.update(submitData)
    message.success('修改成功')
  } else {
    await orderProcessPlanApi.create(submitData)
    message.success('新增成功')
  }
  modalVisible.value = false
  loadData()
}

function disphand(process: ProcessPlanItemVO, order?: OrderProcessPlanVO) {
  const entity = processItemToEntity(process, order?.orderItemId)

  const planQty = Number(entity.quantity) || 0
  const completedQty = Number(process.completedQty) || 0
  const remainQty = Math.max(0, planQty - completedQty)
  dispatchmodal.value = true
  dispatchformRef.value?.restoreValidation()
  dispatchform.id = entity.id
  dispatchform.name = entity.name
  // 工序计划时间优先，没有则用订单头 beginTime/endTime
  dispatchform.beginTime = entity.beginTime || order?.beginTime || ''
  dispatchform.endTime = entity.endTime || order?.endTime || ''
  // quantity 保持工序计划总数，提交时不能改掉计划数量
  dispatchform.quantity = entity.quantity
  dispatchform.completedQty = completedQty
  dispatchform.remainQty = remainQty
  dispatchform.orderItemId = entity.orderItemId
  dispatchform.sort = entity.sort
  dispatchform.sectionId = entity.sectionId ?? process.sectionId ?? null
  dispatchform.workshopId = entity.workshopId ?? process.workshopId ?? order?.workshopId ?? null
  dispatchform.list = [{ sectionId: '', deviceId: '', quantity: remainQty || '',ncId:'' }]
}

function addpgnum() {
  dispatchform.list.push({ sectionId: '', deviceId: '', quantity: '',ncId:'' })
}

function deletenum(index: number) {
  dispatchform.list.splice(index, 1)
}

function dispatchSubmit() {
  let total = 0
  dispatchform.list.forEach((n: any) => {
    total += Number(n.quantity) || 0
  })
  const remainQty = Number(dispatchform.remainQty)
  if (remainQty <= 0) {
    message.warning('当前工序已全部完成，无需再派工')
    return
  }

  dispatchformRef.value?.validate((errors: any) => {
    // Naive UI：有 errors 表示校验失败
    if (errors) return
    if (total !== remainQty) {
      message.error(`派工总数量需等于待派数量 ${remainQty}（计划 ${dispatchform.quantity}，已完成 ${dispatchform.completedQty ?? 0}）`, {
        duration: 4000,
      })
      return
    }

    dispatchLoading.value = true
    // 提交时 quantity 仍传计划总数，避免把工序计划数量改成待派数
    orderProcessPlanApi.assignWork(dispatchform).then(() => {
      message.success('派工成功')
      dispatchmodal.value = false
      loadData()
    }).finally(() => { dispatchLoading.value = false })
  })
}

async function handleExport() {
  const blob = await orderProcessPlanApi.export({
    name: searchForm.name || undefined,
    code: searchForm.code || undefined,
  })
  const url = window.URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = url
  link.download = '工序计划数据.xlsx'
  link.click()
  window.URL.revokeObjectURL(url)
}

async function handleDownloadTemplate() {
  const blob = await orderProcessPlanApi.downloadTemplate()
  const url = window.URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = url
  link.download = '工序计划导入模板.xlsx'
  link.click()
  window.URL.revokeObjectURL(url)
}

async function handleImportUpload({ file }: UploadCustomRequestOptions) {
  if (!file.file) return
  const result = await orderProcessPlanApi.importData(file.file)
  if (result.fail > 0) {
    dialog.warning({
      title: '导入结果',
      content: `成功 ${result.success} 条，失败 ${result.fail} 条`,
      positiveText: '确定',
    })
  } else {
    message.success(`导入成功，共 ${result.success} 条`)
    importModalVisible.value = false
  }
  loadData()
}


const orderItemId = ref<number>(null)

function  openReportDetail(order) {
  submitModalVisible.value = true
  orderItemId.value = order.orderItemId

}

onMounted(loadData)
</script>

<style scoped>
.plan-board-page {
  padding: 0;
  background: #f5f7fa;
  min-height: 100%;
}

.board-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 12px 16px;
  background: #fff;
  border-radius: 8px 8px 0 0;
  border-bottom: 1px solid #eef0f3;
}

.board-filter {
  padding: 12px 16px;
  background: #fff;
  border-bottom: 1px solid #eef0f3;
}

.board-table-wrap {
  overflow-x: auto;
  background: #fff;
}

.board-table-head,
.order-row {
  display: grid;
  /* 勾选 | 产品工单 | 数量 | 模式 | 齐套率 | 工序轴 | 计划时间 | 生命周期 | 操作 */
  grid-template-columns:
    40px
    minmax(220px, 1.6fr)
    64px
    108px
    72px
    minmax(200px, 1.4fr)
    168px
    96px
    140px;
  align-items: center;
  gap: 8px;
  padding: 0 16px;
  min-width: 1280px;
}

.board-table-head {
  height: 40px;
  background: #fafbfc;
  border-bottom: 1px solid #e8eaed;
  font-size: 12px;
  font-weight: 600;
  color: #8c8c8c;
}

.order-block {
  background: #fff;
  border-bottom: 1px solid #eef0f3;
}

.order-row {
  min-height: 64px;
  transition: background 0.15s;
}

.order-row:hover {
  background: #f8faff;
}

.order-row.expanded {
  background: rgba(32, 128, 240, 0.04);
}

.col-check {
  display: flex;
  justify-content: center;
  flex-shrink: 0;
}

.col-product {
  min-width: 0;
}

.col-qty,
.col-kit {
  text-align: center;
  font-size: 13px;
  white-space: nowrap;
}

.product-name {
  font-size: 14px;
  font-weight: 600;
  color: #1a1a1a;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.product-code {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  font-size: 12px;
  color: #8c8c8c;
}

.col-mode {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-start;
}

.col-plan {
  font-size: 13px;
  line-height: 1.4;
  white-space: nowrap;
}

.col-plan .sub-text {
  font-size: 12px;
  color: #8c8c8c;
  margin-top: 2px;
}

.col-life {
  white-space: nowrap;
}

.col-flow {
  min-width: 0;
  overflow: hidden;
}

.col-flow.flow-expanded :deep(.flow-stepper) {
  background: rgba(32, 128, 240, 0.1);
}

.life-cell {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
}

.col-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: nowrap;
  white-space: nowrap;
}

.order-expand {
  padding: 12px 16px 16px 56px;
  background: linear-gradient(180deg, rgba(32, 128, 240, 0.03) 0%, #fff 100%);
  border-top: 1px dashed #e8eaed;
}

.card-flow-scroll,
.detail-cards {
  display: flex;
  align-items: flex-start;
  gap: 0;
  overflow-x: auto;
  padding-bottom: 8px;
}

.detail-cards {
  margin-top: 16px;
  padding-top: 8px;
  border-top: 1px solid #f0f0f0;
}

.expand-empty {
  font-size: 13px;
  color: #8c8c8c;
  padding: 8px 0;
}

.board-empty {
  padding: 48px;
  background: #fff;
}

.board-pagination {
  display: flex;
  justify-content: flex-end;
  padding: 12px 16px;
  background: #fff;
  border-radius: 0 0 8px 8px;
}
.pgClass {
  font-weight: bold;
}

.outsource-process-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 12px;
  border: 1px solid #e8e8e8;
  border-radius: 8px;
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}

.outsource-process-item:hover,
.outsource-process-item.active {
  border-color: #2080f0;
  background: rgba(32, 128, 240, 0.04);
}

.outsource-process-body {
  flex: 1;
  min-width: 0;
}

.outsource-process-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  color: #1a1a1a;
}

.outsource-process-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 6px;
  font-size: 12px;
  color: #8c8c8c;
}

.reorder-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-bottom: 12px;
  font-size: 13px;
  color: #595959;
}

.reorder-empty {
  padding: 24px 0;
  text-align: center;
  color: #8c8c8c;
  font-size: 13px;
}

.reorder-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 420px;
  overflow-y: auto;
}

.reorder-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: #fafbfc;
  border: 1px solid #eef0f3;
  border-radius: 8px;
}

.reorder-drag-handle {
  cursor: grab;
  flex-shrink: 0;
  color: #8c8c8c;
}

.reorder-drag-handle:active {
  cursor: grabbing;
}

.reorder-index {
  width: 22px;
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  color: #2080f0;
  flex-shrink: 0;
}

.reorder-body {
  flex: 1;
  min-width: 0;
}

.reorder-title {
  font-size: 14px;
  font-weight: 600;
  color: #1a1a1a;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.reorder-title em {
  font-style: normal;
  margin-right: 6px;
  color: #2080f0;
}

.reorder-sub {
  margin-top: 2px;
  font-size: 12px;
  color: #8c8c8c;
}
</style>
