<template>
  <div class="app-container goofish-order-layout">
    <div class="goofish-order-main">
    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="96px">
      <el-form-item label="AppKey" prop="appKey">
        <el-input v-model="queryParams.appKey" placeholder="可选" clearable @keyup.enter.native="handleQuery" />
      </el-form-item>
      <el-form-item label="订单号" prop="orderNo">
        <el-input v-model="queryParams.orderNo" placeholder="闲鱼订单号" clearable @keyup.enter.native="handleQuery" />
      </el-form-item>
      <el-form-item label="订单状态" prop="orderStatus">
        <el-select v-model="queryParams.orderStatus" placeholder="全部" clearable style="width: 130px">
          <el-option v-for="o in orderStatusOptions" :key="o.v" :label="o.l" :value="o.v" />
        </el-select>
      </el-form-item>
      <el-form-item label="发货状态" prop="shipStatus">
        <el-select v-model="queryParams.shipStatus" placeholder="全部" clearable style="width: 120px">
          <el-option label="未发货" :value="0" />
          <el-option label="成功" :value="1" />
          <el-option label="失败" :value="2" />
        </el-select>
      </el-form-item>
      <el-form-item label="退款状态" prop="refundStatus">
        <el-select v-model="queryParams.refundStatus" placeholder="全部" clearable filterable style="width: 150px">
          <el-option v-for="o in refundStatusFilterOptions" :key="'rs-' + o.v" :label="o.l" :value="o.v" />
        </el-select>
      </el-form-item>
      <el-form-item label="买家昵称" prop="buyerNick">
        <el-input v-model="queryParams.buyerNick" placeholder="模糊" clearable style="width: 120px" @keyup.enter.native="handleQuery" />
      </el-form-item>
      <el-form-item label="商品标题" prop="goodsTitle">
        <el-input v-model="queryParams.goodsTitle" placeholder="模糊" clearable style="width: 160px" @keyup.enter.native="handleQuery" />
      </el-form-item>
      <el-form-item label="运单号" prop="waybillKeyword">
        <el-input v-model="queryParams.waybillKeyword" placeholder="平台或本地运单模糊" clearable style="width: 150px" @keyup.enter.native="handleQuery" />
      </el-form-item>
      <el-form-item label="内部单备注" prop="jdRemark">
        <el-input v-model="queryParams.jdRemark" placeholder="京东单据 remark 模糊" clearable style="width: 130px" @keyup.enter.native="handleQuery" />
      </el-form-item>
      <el-form-item label="京东三方单号" prop="jdThirdPartyOrderNo">
        <el-input v-model="queryParams.jdThirdPartyOrderNo" placeholder="模糊" clearable style="width: 140px" @keyup.enter.native="handleQuery" />
      </el-form-item>
      <el-form-item label="卖家账号" prop="userName">
        <el-input v-model="queryParams.userName" placeholder="用户名模糊" clearable style="width: 120px" @keyup.enter.native="handleQuery" />
      </el-form-item>
      <el-form-item label="收件手机" prop="receiverMobile">
        <el-input v-model="queryParams.receiverMobile" placeholder="模糊" clearable style="width: 120px" @keyup.enter.native="handleQuery" />
      </el-form-item>
      <el-form-item label="关联京东" prop="jdLinkFilter">
        <el-select v-model="queryParams.jdLinkFilter" placeholder="全部" clearable style="width: 114px">
          <el-option label="已关联" :value="1" />
          <el-option label="未关联" :value="0" />
        </el-select>
      </el-form-item>
      <el-form-item label="平台更新时间">
        <el-date-picker
          v-model="modifyTimeRange"
          type="datetimerange"
          size="small"
          value-format="timestamp"
          range-separator="至"
          start-placeholder="开始"
          end-placeholder="结束"
          style="width: 340px"
          clearable
          @change="onModifyTimeRangeChange"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <el-button
          type="info"
          plain
          icon="el-icon-document"
          size="mini"
          @click="openEventLogTroubleshoot"
          v-hasPermi="['jarvis:erpGoofishOrder:list']"
        >变更日志排查</el-button>
        <el-button
          type="primary"
          plain
          icon="el-icon-download"
          size="mini"
          @click="handlePullAll"
          v-hasPermi="['jarvis:erpGoofishOrder:edit']"
        >增量拉单</el-button>
        <el-button
          type="warning"
          plain
          icon="el-icon-time"
          size="mini"
          @click="handlePullHistoryFull"
          v-hasPermi="['jarvis:erpGoofishOrder:edit']"
        >历史全量拉单</el-button>
      </el-col>
      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
    </el-row>

    <el-table v-loading="loading" :data="list">
      <el-table-column label="订单号" prop="orderNo" min-width="150" show-overflow-tooltip />
      <el-table-column label="商品" min-width="260">
        <template slot-scope="scope">
          <div class="goods-cell">
            <el-image
              v-if="goodsThumb(scope.row)"
              :src="goodsThumb(scope.row)"
              :preview-src-list="[goodsThumb(scope.row)]"
              fit="cover"
              class="goods-thumb"
            >
              <div slot="error" class="goods-thumb-error"><i class="el-icon-picture-outline" /></div>
            </el-image>
            <div v-else class="goods-thumb goods-thumb--empty"><i class="el-icon-goods" /></div>
            <span class="goods-title-txt" :title="displayGoodsTitle(scope.row)">{{ displayGoodsTitle(scope.row) }}</span>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="买家" min-width="120" show-overflow-tooltip>
        <template slot-scope="scope">
          {{ displayBuyerNick(scope.row) }}
        </template>
      </el-table-column>
      <el-table-column label="订单状态" prop="orderStatus" width="118" align="center">
        <template slot-scope="scope">
          <el-tag
            :type="orderStatusTagType(scope.row.orderStatus)"
            :effect="orderStatusTagEffect(scope.row.orderStatus)"
            size="small"
            disable-transitions
          >
            {{ orderStatusLabel(scope.row.orderStatus) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="退款状态" prop="refundStatus" width="128" align="center">
        <template slot-scope="scope">
          <el-tag
            :type="refundStatusTagType(scope.row.refundStatus)"
            size="small"
            disable-transitions
          >
            {{ refundStatusLabel(scope.row.refundStatus) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="实付" prop="payAmount" width="118" align="right">
        <template slot-scope="scope">
          {{ formatPayDisplay(scope.row) }}
        </template>
      </el-table-column>
      <el-table-column label="内部单" prop="jdRemark" width="100" show-overflow-tooltip />

      <el-table-column label="快递" min-width="130" show-overflow-tooltip>
        <template slot-scope="scope">
          <span v-if="displayExpressName(scope.row) !== '—'">
            {{ displayExpressName(scope.row) }}
            <template v-if="scope.row.detailExpressCode || detailDataField(scope.row, 'express_code')">
              ({{ scope.row.detailExpressCode || detailDataField(scope.row, 'express_code') }})
            </template>
          </span>
          <span v-else>—</span>
        </template>
      </el-table-column>
      <el-table-column label="运单号" min-width="188" align="left">
        <template slot-scope="scope">
          <span v-for="w in [waybillDisplay(scope.row)]" :key="'wb-' + scope.row.id" class="waybill-cell">
            <span v-if="w.kind === 'empty'">—</span>
            <span v-else-if="w.kind === 'match'" class="waybill-cell--match" :title="w.text">{{ w.text }}</span>
            <span v-else-if="w.kind === 'single'" class="waybill-cell--single" :title="w.text">
              {{ w.text }}<span v-if="w.source === 'local'" class="waybill-cell--hint">（仅本地）</span>
            </span>
            <div v-else class="waybill-cell--warn">
              <div class="waybill-cell--warn-title"><i class="el-icon-warning-outline" /> 平台与本地不一致</div>
              <div class="waybill-cell--line">平台 {{ w.platform }}</div>
              <div class="waybill-cell--line">本地 {{ w.local }}</div>
            </div>
          </span>
        </template>
      </el-table-column>
      <el-table-column label="收货人/手机" min-width="120" show-overflow-tooltip>
        <template slot-scope="scope">
          {{ displayReceiverName(scope.row) }} {{ displayReceiverMobile(scope.row) }}
        </template>
      </el-table-column>
      <el-table-column label="省/市/区/镇" min-width="140" show-overflow-tooltip>
        <template slot-scope="scope">
          {{ displayRecvSplit(scope.row) }}
        </template>
      </el-table-column>
      <el-table-column label="闲鱼地址" min-width="130" show-overflow-tooltip>
        <template slot-scope="scope">
          {{ displayAddressLine(scope.row) }}
        </template>
      </el-table-column>
      <el-table-column label="京东地址" prop="jdAddress" min-width="140" show-overflow-tooltip />
      <el-table-column label="发货" prop="shipStatus" width="88">
        <template slot-scope="scope">
          {{ shipDisplayLabel(scope.row) }}
        </template>
      </el-table-column>
      <el-table-column label="更新时间" prop="modifyTime" width="158" align="center">
        <template slot-scope="scope">
          {{ formatModifyTime(scope.row.modifyTime) }}
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" width="356" fixed="right">
        <template slot-scope="scope">
          <el-button size="mini" type="text" @click="openJson(scope.row)" v-hasPermi="['jarvis:erpGoofishOrder:query']">详情JSON</el-button>
          <el-button size="mini" type="text" @click="handleRefresh(scope.row)" v-hasPermi="['jarvis:erpGoofishOrder:edit']">刷新详情</el-button>
          <el-button size="mini" type="text" class="goofish-btn-logistics" @click="handleRefreshLogistics(scope.row)" v-hasPermi="['jarvis:erpGoofishOrder:edit']">刷新物流</el-button>
          <el-button size="mini" type="text" @click="handleShipPreview(scope.row)" v-hasPermi="['jarvis:erpGoofishOrder:query']">发货预览</el-button>
          <el-button size="mini" type="text" @click="handleRetryShip(scope.row)" v-hasPermi="['jarvis:erpGoofishOrder:edit']">重试发货</el-button>
        </template>
      </el-table-column>
    </el-table>

    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />

    </div>

    <aside class="goofish-rrs-aside" v-hasPermi="['jarvis:erpGoofishOrder:list']">
      <el-card shadow="hover" class="goofish-rrs-card" v-loading="rrsStatsLoading">
        <div slot="header" class="goofish-rrs-card-hd">
          <span>日日顺物流</span>
        </div>
        <p class="goofish-rrs-desc">已关联京东 · 承运含 rrs 或「日日顺」</p>
        <div class="goofish-rrs-metric">
          <span class="goofish-rrs-label">已出库</span>
          <strong class="goofish-rrs-val goofish-rrs-val--ok">{{ rrsStats.shippedOutboundCount }}</strong>
          <span class="goofish-rrs-hint-row">去重单号 + 无单号已发</span>
        </div>
        <el-divider class="goofish-rrs-divider" />
        <div class="goofish-rrs-metric">
          <span class="goofish-rrs-label">待出库</span>
          <strong class="goofish-rrs-val goofish-rrs-val--warn">{{ rrsStats.pendingOutboundCount }}</strong>
          <span class="goofish-rrs-hint-row">待发货且无运单</span>
        </div>
      </el-card>
    </aside>

    <el-dialog
      title="发货地址比对"
      :visible.sync="shipPreviewDialogVisible"
      width="720px"
      append-to-body
      :close-on-click-modal="false"
      @closed="onShipPreviewDialogClosed"
    >
      <div v-loading="shipPreviewLoading">
        <p v-if="shipPreviewVo.orderNo" class="goofish-rl-order">闲鱼订单号：<code>{{ shipPreviewVo.orderNo }}</code></p>
        <el-alert
          v-if="shipPreviewVo.compareHint"
          :title="shipPreviewVo.compareHint"
          type="info"
          :closable="false"
          show-icon
          style="margin-bottom: 12px;"
        />
        <el-descriptions :column="1" border size="small">
          <el-descriptions-item label="标题 goods.title">{{ shipPreviewVo.goodsTitle || '—' }}</el-descriptions-item>
          <el-descriptions-item label="京东型号">{{ shipPreviewVo.jdModelNumber || '—' }}</el-descriptions-item>
          <el-descriptions-item label="京东整段地址">{{ shipPreviewVo.jdAddressFull || '—' }}</el-descriptions-item>
          <el-descriptions-item label="闲鱼订单收件">{{ shipGoofishRecipientLine }}</el-descriptions-item>
          <el-descriptions-item label="发货提交收件">{{ shipSubmitRecipientLine }}</el-descriptions-item>
        </el-descriptions>
        <el-table :data="shipPreviewCompareRows" size="small" border stripe style="margin-top: 14px;">
          <el-table-column prop="hint" label="" width="156" show-overflow-tooltip />
          <el-table-column prop="addr" label="收件地址文本" min-width="280" show-overflow-tooltip />
          <el-table-column prop="same" label="与发货一致" width="100" align="center">
            <template slot-scope="scope">
              <template v-if="scope.row.same === true"><el-tag type="success" size="mini">一致</el-tag></template>
              <template v-else-if="scope.row.same === false"><el-tag type="danger" size="mini">不一致</el-tag></template>
              <span v-else>—</span>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="shipPreviewDialogVisible = false">关 闭</el-button>
      </div>
    </el-dialog>

    <!-- 刷新物流：结果弹窗（与京东订单页一致，用 append-to-body 避免被表格区裁剪） -->
    <el-dialog
      title="刷新物流结果"
      :visible.sync="refreshLogisticsDialogVisible"
      width="640px"
      append-to-body
      :close-on-click-modal="false"
      @closed="onRefreshLogisticsDialogClosed"
    >
      <div v-loading="refreshLogisticsLoading">
        <p v-if="refreshLogisticsOrderNo" class="goofish-rl-order">闲鱼订单号：<code>{{ refreshLogisticsOrderNo }}</code></p>
        <el-alert
          v-if="refreshLogisticsError"
          :title="refreshLogisticsError"
          type="error"
          :closable="false"
          show-icon
          style="margin-bottom: 12px;"
        />
        <template v-else-if="!refreshLogisticsLoading && refreshLogisticsAfter">
          <el-alert
            :title="refreshLogisticsHasDiff ? '已拉取详情并合并字段，下列有变化' : '已拉取详情，运单/快递等展示字段与刷新前一致'"
            :type="refreshLogisticsHasDiff ? 'success' : 'info'"
            :closable="false"
            style="margin-bottom: 12px;"
          />
          <el-table :data="refreshLogisticsCompareRows" size="small" border stripe>
            <el-table-column prop="label" label="字段" width="120" />
            <el-table-column prop="before" label="刷新前" min-width="160" show-overflow-tooltip />
            <el-table-column prop="after" label="刷新后" min-width="160" show-overflow-tooltip />
          </el-table>
        </template>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="refreshLogisticsDialogVisible = false">关 闭</el-button>
      </div>
    </el-dialog>

    <el-dialog title="订单详情 JSON（含开放平台原始返回）" :visible.sync="jsonOpen" width="900px" append-to-body>
      <el-tabs v-model="jsonTab" @tab-click="onJsonTabClick">
        <el-tab-pane label="摘要" name="sum">
          <el-descriptions :column="1" border size="small">
            <el-descriptions-item label="商品标题 title">
              <div class="sum-goods">
                <el-image
                  v-if="goodsThumb(jsonRow)"
                  :src="goodsThumb(jsonRow)"
                  :preview-src-list="[goodsThumb(jsonRow)]"
                  fit="cover"
                  class="sum-goods-img"
                >
                  <div slot="error" class="goods-thumb-error"><i class="el-icon-picture-outline" /></div>
                </el-image>
                <span>{{ displayGoodsTitle(jsonRow) }}</span>
              </div>
            </el-descriptions-item>
            <el-descriptions-item label="运单号（平台 / 本地）">
              <span v-for="w in [waybillDisplay(jsonRow)]" :key="'jw'">
                <span v-if="w.kind === 'empty'">—</span>
                <span v-else-if="w.kind === 'match'" class="waybill-cell--match">{{ w.text }}</span>
                <span v-else-if="w.kind === 'single'" class="waybill-cell--single">
                  {{ w.text }}<span v-if="w.source === 'local'" class="waybill-cell--hint">（仅本地）</span>
                </span>
                <div v-else class="waybill-cell--warn">
                  <div class="waybill-cell--warn-title"><i class="el-icon-warning-outline" /> 平台与本地不一致</div>
                  <div class="waybill-cell--line">平台 {{ w.platform }}</div>
                  <div class="waybill-cell--line">本地 {{ w.local }}</div>
                </div>
              </span>
            </el-descriptions-item>
            <el-descriptions-item label="快递公司 express_name">{{ displayExpressName(jsonRow) }}</el-descriptions-item>
            <el-descriptions-item label="实付 pay_amount（分→元）">{{ formatPayDisplay(jsonRow) }}</el-descriptions-item>
            <el-descriptions-item label="订单状态 order_status">
              <el-tag
                :type="orderStatusTagType(jsonRow.orderStatus)"
                :effect="orderStatusTagEffect(jsonRow.orderStatus)"
                size="small"
                disable-transitions
              >
                {{ orderStatusLabel(jsonRow.orderStatus) }}
              </el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="退款状态 refund_status">
              <el-tag
                :type="refundStatusTagType(jsonRow.refundStatus)"
                size="small"
                disable-transitions
              >
                {{ refundStatusLabel(jsonRow.refundStatus) }}
              </el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="买家昵称 buyer_nick">{{ displayBuyerNick(jsonRow) }}</el-descriptions-item>
            <el-descriptions-item label="会员名（卖家）">{{ privacyHidden }}</el-descriptions-item>
            <el-descriptions-item label="收货人 receiver_name">{{ displayReceiverName(jsonRow) }}</el-descriptions-item>
            <el-descriptions-item label="手机 receiver_mobile">{{ displayReceiverMobile(jsonRow) || '—' }}</el-descriptions-item>
            <el-descriptions-item label="省/市/区/镇 prov…town">{{ displayRecvSplit(jsonRow) }}</el-descriptions-item>
            <el-descriptions-item label="详细地址 address">{{ displayAddressLine(jsonRow) }}</el-descriptions-item>
            <el-descriptions-item label="闲鱼收件（区划+明细拼接）">{{ displayFullGoofishAddress(jsonRow) }}</el-descriptions-item>
            <el-descriptions-item label="拼接区划 receiver_region">{{ jsonRow.receiverRegion || '—' }}</el-descriptions-item>
            <el-descriptions-item label="京东地址">{{ jsonRow.jdAddress || '-' }}</el-descriptions-item>
          </el-descriptions>
        </el-tab-pane>
        <el-tab-pane label="detail_json" name="detail">
          <pre class="json-pre">{{ pretty(jsonRow.detailJson) }}</pre>
        </el-tab-pane>
        <el-tab-pane label="last_notify_json" name="notify">
          <pre class="json-pre">{{ pretty(jsonRow.lastNotifyJson) }}</pre>
        </el-tab-pane>
        <el-tab-pane label="变更日志" name="events">
          <p class="event-log-hint">含状态/平台物流摘要、<b>JD_LOGISTICS_PUSH</b>（京东物流扫描→Redis/企微→触达闲鱼）、<b>REDIS_WAYBILL</b>、<b>AUTO_SHIP</b> 等。</p>
          <el-table v-loading="eventLogsLoading" :data="eventLogs" size="small" max-height="440" empty-text="暂无记录">
            <el-table-column label="时间" prop="createTime" width="168" />
            <el-table-column label="类型" prop="eventType" width="118" align="center">
              <template slot-scope="scope">
                <el-tag :type="eventLogTagType(scope.row.eventType)" size="mini">{{ scope.row.eventType }}</el-tag>
              </template>
            </el-table-column>
            <el-table-column label="来源" prop="source" width="126" show-overflow-tooltip />
            <el-table-column label="说明" prop="message" min-width="220" show-overflow-tooltip />
          </el-table>
        </el-tab-pane>
      </el-tabs>
      <p v-if="jsonRow.shipError" style="color:#f56c6c">发货错误：{{ jsonRow.shipError }}</p>
    </el-dialog>
  </div>
</template>

<script>
import { listGoofishOrder, listGoofishOrderEventLogs, pullAllGoofishOrders, pullAllGoofishOrdersFull, pullGoofishOrdersFull, refreshGoofishDetail, retryGoofishShip, getGoofishOrder, previewGoofishShip, getGoofishRrsLogisticsStats } from '@/api/jarvis/goofish'
import { parseTime } from '@/utils/ruoyi'

/** 与闲管家开放平台 order_status 一致 */
const GOOFISH_ORDER_STATUS = Object.freeze({
  11: '待付款',
  12: '待发货',
  21: '已发货',
  22: '已完成',
  23: '已退款',
  24: '已关闭'
})
/** 与闲管家开放平台 refund_status 一致 */
const GOOFISH_REFUND_STATUS = Object.freeze({
  0: '未申请退款',
  1: '待商家处理',
  2: '待买家退货',
  3: '待商家收货',
  4: '退款关闭',
  5: '退款成功',
  6: '已拒绝退款',
  8: '待确认退货地址'
})

export default {
  name: 'ErpGoofishOrder',
  data() {
    return {
      loading: false,
      showSearch: true,
      total: 0,
      list: [],
      modifyTimeRange: null,
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        appKey: undefined,
        orderNo: undefined,
        orderStatus: undefined,
        refundStatus: undefined,
        shipStatus: undefined,
        buyerNick: undefined,
        goodsTitle: undefined,
        waybillKeyword: undefined,
        jdRemark: undefined,
        jdThirdPartyOrderNo: undefined,
        userName: undefined,
        receiverMobile: undefined,
        jdLinkFilter: undefined,
        modifyTimeBegin: undefined,
        modifyTimeEnd: undefined
      },
      orderStatusOptions: [
        { v: 11, l: '待付款' },
        { v: 12, l: '待发货' },
        { v: 21, l: '已发货' },
        { v: 22, l: '已完成' },
        { v: 23, l: '已退款' },
        { v: 24, l: '已关闭' }
      ],
      /** 摘要中卖家会员名不展示（买家见 displayBuyerNick） */
      privacyHidden: '—',
      jsonOpen: false,
      jsonTab: 'sum',
      jsonRow: {},
      eventLogs: [],
      eventLogsLoading: false,
      /** 刷新物流结果弹窗 */
      refreshLogisticsDialogVisible: false,
      refreshLogisticsLoading: false,
      refreshLogisticsOrderNo: '',
      refreshLogisticsBefore: null,
      refreshLogisticsAfter: null,
      refreshLogisticsError: '',
      /** 发货预览 */
      shipPreviewDialogVisible: false,
      shipPreviewLoading: false,
      shipPreviewVo: {},
      /** 日日顺 + 关联京东侧边统计（与后端 selectRrsJdLinkedLogisticsStats 口径一致） */
      rrsStatsLoading: false,
      rrsStats: {
        shippedOutboundCount: 0,
        pendingOutboundCount: 0
      }
    }
  },
  computed: {
    /** 退款状态下拉（与开放平台 refund_status 一致） */
    refundStatusFilterOptions() {
      return Object.keys(GOOFISH_REFUND_STATUS).map(k => ({
        v: Number(k),
        l: GOOFISH_REFUND_STATUS[k]
      }))
    },
    refreshLogisticsCompareRows() {
      const b = this.refreshLogisticsBefore
      const a = this.refreshLogisticsAfter
      if (!a && !b) return []
      const cell = (row, key, fmt) => {
        if (fmt) {
          return fmt(row) || '—'
        }
        if (!row || row[key] == null || row[key] === '') return '—'
        return String(row[key])
      }
      const rows = [
        { label: '平台运单', before: cell(b, 'detailWaybillNo'), after: cell(a, 'detailWaybillNo') },
        { label: '快递编码', before: cell(b, 'detailExpressCode'), after: cell(a, 'detailExpressCode') },
        { label: '快递名称', before: cell(b, 'detailExpressName'), after: cell(a, 'detailExpressName') },
        { label: '本地运单', before: cell(b, 'localWaybillNo'), after: cell(a, 'localWaybillNo') },
        { label: '订单状态', before: cell(b, null, r => this.orderStatusLabel(r && r.orderStatus)), after: cell(a, null, r => this.orderStatusLabel(r && r.orderStatus)) },
        { label: '退款状态', before: cell(b, null, r => this.refundStatusLabel(r && r.refundStatus)), after: cell(a, null, r => this.refundStatusLabel(r && r.refundStatus)) },
        { label: '发货展示', before: cell(b, null, r => this.shipDisplayLabel(r)), after: cell(a, null, r => this.shipDisplayLabel(r)) }
      ]
      return rows
    },
    refreshLogisticsHasDiff() {
      return this.refreshLogisticsCompareRows.some(r => r.before !== r.after)
    },
    shipGoofishRecipientLine() {
      const v = this.shipPreviewVo
      if (!v) return '—'
      const n = (v.goofishOrderReceiverName || '').trim()
      const m = (v.goofishOrderReceiverMobile || '').trim()
      const a = (v.goofishOrderFullAddress || '').trim()
      const nm = [n, m].filter(Boolean).join(' ')
      const parts = []
      if (nm) parts.push(nm)
      if (a) parts.push(a)
      return parts.length ? parts.join(' · ') : '—'
    },
    shipSubmitRecipientLine() {
      const v = this.shipPreviewVo
      if (!v) return '—'
      const n = (v.shipReceiverName || '').trim()
      const m = (v.shipReceiverMobile || '').trim()
      const a = (v.shipFullAddress || '').trim()
      const nm = [n, m].filter(Boolean).join(' ')
      const parts = []
      if (nm) parts.push(nm)
      if (a) parts.push(a)
      return parts.length ? parts.join(' · ') : '—'
    },
    shipPreviewCompareRows() {
      const v = this.shipPreviewVo
      if (!v) return []
      const ship = (v.shipFullAddress || '').trim()
      const normalize = s => (s || '').trim().replace(/\s+/g, ' ')
      const normShip = normalize(ship)
      const cmp = text => {
        const nt = normalize(text)
        if (!nt || !normShip) {
          return null
        }
        return nt === normShip
      }
      return [
        { hint: '闲鱼订单收件串', addr: v.goofishOrderFullAddress || '—', same: cmp(v.goofishOrderFullAddress) },
        { hint: '京东整段地址', addr: v.jdAddressFull || '—', same: cmp(v.jdAddressFull) }
      ]
    }
  },
  created() {
    this.getList()
  },
  methods: {
    onRefreshLogisticsDialogClosed() {
      this.refreshLogisticsBefore = null
      this.refreshLogisticsAfter = null
      this.refreshLogisticsError = ''
      this.refreshLogisticsOrderNo = ''
    },
    onShipPreviewDialogClosed() {
      this.shipPreviewVo = {}
    },
    orderStatusLabel(s) {
      if (s == null || s === '') {
        return '—'
      }
      const t = GOOFISH_ORDER_STATUS[s]
      return t != null ? t : `未识别(${s})`
    },
    refundStatusLabel(s) {
      if (s == null || s === '') {
        return '—'
      }
      const t = GOOFISH_REFUND_STATUS[s]
      return t != null ? t : `未识别(${s})`
    },
    /** 退款中/处理中用 warning，成功/关闭用 success/info，拒绝 danger */
    refundStatusTagType(s) {
      if (s == null || s === '') {
        return 'info'
      }
      const m = { 0: 'info', 1: 'warning', 2: 'warning', 3: 'warning', 4: 'info', 5: 'success', 6: 'danger', 8: 'warning' }
      return m[s] !== undefined ? m[s] : 'info'
    },
    /** Element 标签类型（仅 success/info/warning/danger）：与闲管家 order_status 对齐 */
    orderStatusTagType(s) {
      const m = {
        11: 'info',
        12: 'warning',
        21: 'success',
        22: 'success',
        23: 'danger',
        24: 'info'
      }
      if (s == null || s === '') return 'info'
      return m[s] !== undefined ? m[s] : 'info'
    },
    /** 已完成用深色实心，与已发货（浅色 success）区分 */
    orderStatusTagEffect(s) {
      return s === 22 ? 'dark' : 'light'
    },
    /** 开放平台 modify_time：秒级时间戳 → 本地 yyyy-MM-dd HH:mm:ss */
    formatModifyTime(ts) {
      if (ts == null || ts === '') return '-'
      return parseTime(ts) || '-'
    },
    eventLogTagType(t) {
      if (t === 'ORDER_SYNC') return 'info'
      if (t === 'LOGISTICS_SYNC') return 'warning'
      if (t === 'SHIP') return 'warning'
      return ''
    },
    onJsonTabClick(tab) {
      if (tab && tab.name === 'events' && this.jsonRow && this.jsonRow.id) {
        this.loadEventLogs()
      }
    },
    loadEventLogs() {
      if (!this.jsonRow || !this.jsonRow.id) return
      this.eventLogsLoading = true
      listGoofishOrderEventLogs(this.jsonRow.id).then(res => {
        this.eventLogs = Array.isArray(res.data) ? res.data : []
        this.eventLogsLoading = false
      }).catch(() => {
        this.eventLogsLoading = false
      })
    },
    /** 平台侧是否已有发货事实：详情运单号或订单状态已发货/已完成（与 orderStatusOptions 一致） */
    hasPlatformShipped(row) {
      if (!row) return false
      if (this.platformWaybillRaw(row)) return true
      const os = row.orderStatus
      return os === 21 || os === 22
    },
    /**
     * 发货列展示：本系统开放平台发货成功 → 成功；
     * 平台已有物流/已发货但本系统未记成功 → 手动推送（含在闲鱼侧手填物流、或曾自动发货失败后在平台处理等情况）；
     * 其余按 shipStatus。
     */
    shipDisplayLabel(row) {
      if (!row) return '未发'
      if (row.shipStatus === 1) return '成功'
      if (this.hasPlatformShipped(row)) return '手动推送'
      if (row.shipStatus === 2) return '失败'
      return '未发'
    },
    detailDataField(row, key) {
      if (!row || !row.detailJson) return null
      try {
        const root = JSON.parse(row.detailJson)
        const d = root && root.data ? root.data : root
        if (!d || d[key] === undefined || d[key] === null || d[key] === '') return null
        return d[key]
      } catch (e) {
        return null
      }
    },
    /** 订单详情/开放平台 data 根对象（无 detailJson 时 null） */
    detailOrderData(row) {
      if (!row || !row.detailJson) return null
      try {
        const root = JSON.parse(row.detailJson)
        return root && root.data ? root.data : root
      } catch (e) {
        return null
      }
    },
    firstNonEmptyStr(o, keys) {
      if (!o) return null
      for (const k of keys) {
        const v = o[k]
        if (v != null && String(v).trim() !== '') return String(v).trim()
      }
      return null
    },
    displayGoodsTitle(row) {
      if (!row) return '—'
      if (row.goodsTitle) return row.goodsTitle
      const t = this.detailDataField(row, 'goods')
      if (t && t.title) return t.title
      return '—'
    },
    displayBuyerNick(row) {
      if (!row) return '—'
      return row.buyerNick || this.detailDataField(row, 'buyer_nick') || '—'
    },
    /** 收件人：优先订单 detail_json（平台），再退列表/推送落库字段；不用京东侧兜底（京东地址单列展示） */
    displayReceiverName(row) {
      if (!row) return '-'
      const d = this.detailOrderData(row)
      if (d) {
        const n = this.firstNonEmptyStr(d, ['receiver_name', 'ship_name', 'consignee_name', 'contact_name'])
        if (n) return n
        const recv = d.receiver
        if (recv && recv.name != null && String(recv.name).trim() !== '') return String(recv.name).trim()
      }
      if (row.receiverName) return row.receiverName
      return '-'
    },
    displayReceiverMobile(row) {
      if (!row) return ''
      const d = this.detailOrderData(row)
      if (d) {
        const m = this.firstNonEmptyStr(d, ['receiver_mobile', 'ship_mobile', 'receiver_phone', 'contact_mobile'])
        if (m) return m
        const recv = d.receiver
        if (recv) {
          const mm = recv.mobile || recv.phone
          if (mm != null && String(mm).trim() !== '') return String(mm).trim()
        }
      }
      if (row.receiverMobile) return row.receiverMobile
      return ''
    },
    displayRecvSplit(row) {
      if (!row) return '—'
      const p = row.recvProvName || this.detailDataField(row, 'prov_name')
      const c = row.recvCityName || this.detailDataField(row, 'city_name')
      const a = row.recvAreaName || this.detailDataField(row, 'area_name')
      const t = row.recvTownName || this.detailDataField(row, 'town_name')
      const s = [p, c, a, t].filter(x => x != null && String(x).trim() !== '').map(x => String(x).trim()).join(' ')
      return s || '—'
    },
    /** 详细地址：优先平台详情字段，再用列表字段；京东整段地址见「京东地址」列 */
    displayAddressLine(row) {
      if (!row) return '—'
      const d = this.detailOrderData(row)
      if (d) {
        const a = this.firstNonEmptyStr(d, ['receiver_address', 'ship_address', 'detail_address', 'full_address', 'address'])
        if (a) return a
        const recv = d.receiver
        if (recv && recv.address != null && String(recv.address).trim() !== '') return String(recv.address).trim()
      }
      if (row.receiverAddress) return row.receiverAddress
      return '—'
    },
    /** 列表/摘要一行展示：区划列 + 详细地址（与后端 receiverFieldsToShipParts 目视一致） */
    displayFullGoofishAddress(row) {
      if (!row) return '—'
      const rs = this.displayRecvSplit(row)
      const ln = this.displayAddressLine(row)
      const parts = []
      if (rs && rs !== '—') parts.push(rs)
      if (ln && ln !== '—') parts.push(ln)
      return parts.length ? parts.join(' ') : '—'
    },
    normalizeWaybill(v) {
      if (v == null || v === '') return ''
      return String(v).trim()
    },
    /** 开放平台 / 详情中的运单号 */
    platformWaybillRaw(row) {
      if (!row) return ''
      if (row.detailWaybillNo != null && String(row.detailWaybillNo).trim() !== '') {
        return this.normalizeWaybill(row.detailWaybillNo)
      }
      return this.normalizeWaybill(this.detailDataField(row, 'waybill_no'))
    },
    /** 物流扫描写入 Redis 后同步的本地运单 */
    localWaybillRaw(row) {
      if (!row || row.localWaybillNo == null) return ''
      return this.normalizeWaybill(row.localWaybillNo)
    },
    /**
     * 运单展示：双方一致→绿色单行；仅有一边→单行提示；不一致→红色双行
     */
    waybillDisplay(row) {
      const platform = this.platformWaybillRaw(row)
      const local = this.localWaybillRaw(row)
      if (!platform && !local) return { kind: 'empty' }
      if (platform && local) {
        if (platform === local) return { kind: 'match', text: platform }
        return { kind: 'mismatch', platform, local }
      }
      if (platform) return { kind: 'single', text: platform, source: 'platform' }
      return { kind: 'single', text: local, source: 'local' }
    },
    displayExpressName(row) {
      if (!row) return '—'
      const name = row.detailExpressName || this.detailDataField(row, 'express_name')
      if (name) return name
      const code = row.detailExpressCode || this.detailDataField(row, 'express_code')
      return code || '—'
    },
    payAmountFen(row) {
      if (!row) return null
      if (row.payAmount != null && row.payAmount !== '') {
        const n = Number(row.payAmount)
        return Number.isNaN(n) ? null : n
      }
      const v = this.detailDataField(row, 'pay_amount')
      if (v == null || v === '') return null
      const n = Number(v)
      return Number.isNaN(n) ? null : n
    },
    formatPayDisplay(row) {
      const fen = this.payAmountFen(row)
      if (fen == null) return '—'
      return (fen / 100).toFixed(2) + ' 元'
    },
    /** 后端 goodsImageUrl；无则尝试从 detail_json 补一张（旧数据未落库时） */
    goodsThumb(row) {
      if (!row) return ''
      if (row.goodsImageUrl) return row.goodsImageUrl
      const raw = row.detailJson
      if (!raw) return ''
      try {
        const root = JSON.parse(raw)
        const data = root && root.data ? root.data : root
        const g = data && data.goods
        if (!g) return ''
        if (g.images && g.images.length) return g.images[0]
        return g.image || g.pic || g.cover || ''
      } catch (e) {
        return ''
      }
    },
    pretty(s) {
      if (!s) return '-'
      try {
        return JSON.stringify(JSON.parse(s), null, 2)
      } catch (e) {
        return s
      }
    },
    getList() {
      this.loading = true
      listGoofishOrder(this.queryParams).then(res => {
        this.list = res.rows
        this.total = res.total
      }).finally(() => {
        this.loading = false
        this.loadRrsStats()
      })
    },
    loadRrsStats() {
      this.rrsStatsLoading = true
      getGoofishRrsLogisticsStats().then(res => {
        const d = (res && res.data) || {}
        this.rrsStats = {
          shippedOutboundCount: Number(d.shippedOutboundCount) || 0,
          pendingOutboundCount: Number(d.pendingOutboundCount) || 0
        }
      }).catch(() => {
        this.rrsStats = { shippedOutboundCount: 0, pendingOutboundCount: 0 }
      }).finally(() => {
        this.rrsStatsLoading = false
      })
    },
    handleQuery() {
      this.queryParams.pageNum = 1
      this.getList()
    },
    /** 开放平台 modify_time 为秒级；日期控件为毫秒时间戳 */
    onModifyTimeRangeChange(val) {
      if (val && val.length === 2) {
        this.queryParams.modifyTimeBegin = Math.floor(val[0] / 1000)
        this.queryParams.modifyTimeEnd = Math.floor(val[1] / 1000)
      } else {
        this.queryParams.modifyTimeBegin = undefined
        this.queryParams.modifyTimeEnd = undefined
      }
    },
    resetQuery() {
      this.modifyTimeRange = null
      this.queryParams.modifyTimeBegin = undefined
      this.queryParams.modifyTimeEnd = undefined
      this.resetForm('queryForm')
      this.handleQuery()
    },
    handlePullAll() {
      this.$modal.confirm('按配置 pull-lookback-hours 拉取所有启用账号订单（增量），可能较耗时，是否继续？').then(() => {
        return pullAllGoofishOrders()
      }).then(res => {
        const n = (res && res.data && res.data.processedItems) ? res.data.processedItems : 0
        this.$modal.msgSuccess('增量拉单完成，处理项约 ' + n)
        this.getList()
      }).catch(() => {})
    },
    handlePullHistoryFull() {
      this.$prompt('留空 = 所有启用应用；否则只拉此处填写的 AppKey（须已在配置中心启用）', '历史全量拉单', {
        confirmButtonText: '开始',
        cancelButtonText: '取消',
        inputPlaceholder: '可选 AppKey',
        inputValue: this.queryParams.appKey || ''
      }).then(({ value }) => {
        const key = value != null ? String(value).trim() : ''
        const req = key ? pullGoofishOrdersFull(key) : pullAllGoofishOrdersFull()
        return req.then(res => ({ res, key }))
      }).then(({ res, key }) => {
        const n = (res && res.data && res.data.processedItems) ? res.data.processedItems : 0
        const d = res && res.data ? res.data.pullFullHistoryDays : ''
        const c = res && res.data ? res.data.pullTimeChunkSeconds : ''
        this.$modal.msgSuccess(
          (key ? '已按 AppKey 拉取' : '已全部启用账号拉取') + `，处理项约 ${n}（pull-full-history-days=${d}, chunk 秒=${c}）`
        )
        this.getList()
      }).catch(() => {})
    },
    handleRefresh(row) {
      refreshGoofishDetail(row.id).then(() => {
        this.$modal.msgSuccess('已请求刷新详情')
        this.getList()
      }).catch(() => {})
    },
    /** 与「刷新详情」同源：拉闲管家详情并合并运单/快递；弹窗展示刷新前后对比 */
    handleRefreshLogistics(row) {
      if (!row || !row.id) return
      this.refreshLogisticsDialogVisible = true
      this.refreshLogisticsLoading = true
      this.refreshLogisticsError = ''
      this.refreshLogisticsAfter = null
      this.refreshLogisticsOrderNo = row.orderNo || ''
      this.refreshLogisticsBefore = { ...row }
      refreshGoofishDetail(row.id)
        .then(() => getGoofishOrder(row.id))
        .then(res => {
          this.refreshLogisticsAfter = res && res.data ? { ...res.data } : null
          if (!this.refreshLogisticsAfter) {
            this.refreshLogisticsError = '刷新成功但未拿到订单详情，请稍后重试或看列表是否已更新'
          } else {
            this.$modal.msgSuccess('已更新运单与快递信息')
          }
          this.getList()
        })
        .catch(e => {
          const msg = (e && e.response && e.response.data && e.response.data.msg) || (e && e.message) || '请求失败，请检查网络或后台日志'
          this.refreshLogisticsError = String(msg)
        })
        .finally(() => {
          this.refreshLogisticsLoading = false
        })
    },
    handleRetryShip(row) {
      retryGoofishShip(row.id).then(() => {
        this.$modal.msgSuccess('已重试发货流程')
        this.getList()
      })
    },
    /** 后端与自动发货同源：比对闲鱼收件串 vs 开放平台发货参数 */
    handleShipPreview(row) {
      if (!row || !row.id) return
      this.shipPreviewDialogVisible = true
      this.shipPreviewLoading = true
      this.shipPreviewVo = {}
      previewGoofishShip(row.id).then(res => {
        this.shipPreviewVo = res && res.data ? { ...res.data } : {}
      }).catch(() => {
        this.shipPreviewVo = { compareHint: '请求失败，请检查权限或网络', orderNo: row.orderNo }
      }).finally(() => {
        this.shipPreviewLoading = false
      })
    },
    /** 打开「变更日志」排查页：与当前菜单同级路径 erpGoofishEventLog（需在菜单管理配置） */
    openEventLogTroubleshoot() {
      const p = this.$route.path || ''
      const i = p.lastIndexOf('/')
      const prefix = i > 0 ? p.substring(0, i) : p
      const target = prefix + '/erpGoofishEventLog'
      const q = {}
      if (this.queryParams.orderNo) {
        q.orderNo = this.queryParams.orderNo
      }
      this.$tab.openPage('闲鱼订单变更日志', target, q)
    },
    openJson(row) {
      this.jsonRow = { ...row }
      this.jsonTab = 'sum'
      this.eventLogs = []
      this.jsonOpen = true
    }
  }
}
</script>

<style scoped>
.goofish-rl-order {
  margin: 0 0 12px 0;
  font-size: 13px;
  color: #606266;
}
.goofish-rl-order code {
  background: #f4f4f5;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
}
.event-log-hint {
  margin: 0 0 8px 0;
  font-size: 12px;
  color: #909399;
  line-height: 1.5;
}
.json-pre {
  max-height: 480px;
  overflow: auto;
  background: #1e1e1e;
  color: #d4d4d4;
  padding: 12px;
  border-radius: 4px;
  font-size: 12px;
  line-height: 1.4;
}
.mb8 {
  margin-bottom: 8px;
}
.goofish-btn-logistics {
  color: #67c23a;
}
.goofish-btn-logistics:hover {
  color: #85ce61;
}
.goods-cell {
  display: flex;
  align-items: center;
  gap: 10px;
}
.goods-thumb {
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  border-radius: 4px;
  border: 1px solid #ebeef5;
  background: #f5f7fa;
}
.goods-thumb--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #c0c4cc;
  font-size: 20px;
}
.goods-thumb-error {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #c0c4cc;
  font-size: 18px;
}
.goods-title-txt {
  flex: 1;
  min-width: 0;
  line-height: 1.4;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.sum-goods {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.sum-goods-img {
  width: 72px;
  height: 72px;
  flex-shrink: 0;
  border-radius: 4px;
  border: 1px solid #ebeef5;
}
.waybill-cell {
  display: inline-block;
  max-width: 100%;
}
.waybill-cell--match {
  color: #67c23a;
  font-weight: 500;
}
.waybill-cell--single {
  color: #606266;
}
.waybill-cell--hint {
  color: #909399;
  font-size: 12px;
  font-weight: normal;
}
.waybill-cell--warn {
  color: #f56c6c;
  font-size: 12px;
  line-height: 1.45;
}
.waybill-cell--warn-title {
  font-weight: 500;
  margin-bottom: 2px;
}
.waybill-cell--warn-title .el-icon-warning-outline {
  margin-right: 4px;
}
.waybill-cell--line {
  word-break: break-all;
}

/* 左侧列表 + 右侧日日顺物流统计 */
.goofish-order-layout {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  flex-wrap: nowrap;
}
.goofish-order-main {
  flex: 1;
  min-width: 0;
}
.goofish-rrs-aside {
  flex: 0 0 216px;
  position: sticky;
  top: 12px;
  align-self: flex-start;
}
.goofish-rrs-card {
  font-size: 13px;
}
.goofish-rrs-card ::v-deep .el-card__header {
  padding: 12px 14px;
  font-weight: 600;
}
.goofish-rrs-card ::v-deep .el-card__body {
  padding: 12px 14px 16px;
}
.goofish-rrs-desc {
  margin: 0 0 12px;
  color: #909399;
  font-size: 12px;
  line-height: 1.45;
}
.goofish-rrs-metric {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.goofish-rrs-label {
  color: #606266;
  font-size: 13px;
}
.goofish-rrs-val {
  font-size: 26px;
  line-height: 1.15;
}
.goofish-rrs-val--ok {
  color: #67c23a;
}
.goofish-rrs-val--warn {
  color: #e6a23c;
}
.goofish-rrs-hint-row {
  color: #c0c4cc;
  font-size: 12px;
  line-height: 1.35;
}
.goofish-rrs-divider {
  margin: 12px 0;
}
@media (max-width: 1200px) {
  .goofish-order-layout {
    flex-wrap: wrap;
  }
  .goofish-rrs-aside {
    flex: 1 1 100%;
    position: relative;
    top: auto;
    max-width: 360px;
  }
}
</style>
