<template>
  <el-dialog :visible.sync="visibleProxy" :show-close="false" :close-on-click-modal="true" :close-on-press-escape="true"
    custom-class="member-dialog" append-to-body>
    <div class="member-dialog-inner">
      <!-- 左侧边栏 -->
      <div class="sidebar">
        <!-- 会员身份区 -->
        <div class="sidebar-identity">
          <div class="member-avatar"><span>{{ initials }}</span></div>
          <div class="member-name">{{ displayName }}</div>
          <div class="member-sub-info">
            <span v-if="member.sjh" class="member-phone"><i class="el-icon-phone"></i>{{ member.sjh }}</span>
            <span v-if="member.dah" class="member-dah">档案号：{{ member.dah }}</span>
          </div>
          <span v-if="consumeLevelText" :class="['level-tag', consumeLevelClass]">{{ consumeLevelText }}</span>
          <div class="member-type-tags" v-if="memberTypeList.length">
            <span v-for="t in memberTypeList" :key="t.type" :class="['type-tag', 'type-tag--' + t.type]">{{ t.label
            }}会员</span>
          </div>
          <div class="member-meta">
            <span v-if="member.xb">{{ member.xb }}</span>
            <span v-if="member.gsmdName || member.storeName">{{ member.gsmdName || member.storeName }}</span>
          </div>
          <div class="member-visit-row">
            <el-tooltip v-if="member.lastVisitTime || member.lastVisit"
              :content="member.lastVisitTime || member.lastVisit" placement="right" effect="dark">
              <span class="member-visit"><i class="el-icon-time"></i>最后到店：{{ relativeTime(member.lastVisitTime ||
                member.lastVisit) }}</span>
            </el-tooltip>
            <span v-else class="member-visit"><i class="el-icon-time"></i>最后到店：—</span>
            <span class="member-sleep" v-if="member.sleepDays > 0"><i class="el-icon-warning"></i>沉睡 {{ member.sleepDays
            }} 天</span>
          </div>
          <div v-if="Array.isArray(member.tags) && member.tags.length" class="tag-row">
            <span v-for="tag in member.tags" :key="tag" class="member-tag">{{ tag }}</span>
          </div>
        </div>

        <!-- 消费统计 -->
        <div class="sidebar-section">
          <div class="sidebar-section-title"><i class="el-icon-wallet"></i>消费统计</div>
          <div class="sidebar-row">
            <span class="sidebar-label">耗卡总金额</span>
            <span class="sidebar-value sidebar-value--amount">¥{{ formatMoney(member.totalConsumeAmount) }}</span>
          </div>
          <div class="sidebar-row">
            <span class="sidebar-label">开卡总金额</span>
            <span class="sidebar-value sidebar-value--amount">¥{{ formatMoney(member.totalBillingAmount) }}</span>
          </div>
          <div class="sidebar-row sidebar-row--highlight">
            <span class="sidebar-label">剩余权益</span>
            <span class="sidebar-value sidebar-value--gradient">¥{{ formatMoney(member.remainingRightsAmount) }}</span>
          </div>
        </div>

        <!-- 基本信息 -->
        <div class="sidebar-section">
          <div class="sidebar-section-title"><i class="el-icon-user"></i>基本信息</div>
          <div class="sidebar-row">
            <span class="sidebar-label"><i class="el-icon-date"></i>生日</span>
            <span class="sidebar-value">{{ formattedBirthday }}</span>
          </div>
          <div class="sidebar-row">
            <span class="sidebar-label">注册时间</span>
            <span class="sidebar-value">{{ member.zcsj || '—' }}</span>
          </div>
          <div class="sidebar-row">
            <span class="sidebar-label">首次到店</span>
            <span class="sidebar-value">{{ member.firstVisitTime || '—' }}</span>
          </div>
          <div class="sidebar-row">
            <span class="sidebar-label">进店渠道</span>
            <span class="sidebar-value">{{ member.jdqd || '—' }}</span>
          </div>
          <div class="sidebar-row">
            <span class="sidebar-label">推荐人</span>
            <span class="sidebar-value">{{ member.tjrName || '—' }}</span>
          </div>
          <div class="sidebar-row">
            <span class="sidebar-label">健康师</span>
            <span class="sidebar-value">{{ member.mainHealthUserName || '—' }}</span>
          </div>
          <div class="sidebar-row">
            <span class="sidebar-label">负责顾问</span>
            <span class="sidebar-value">{{ member.subHealthUserName || '—' }}</span>
          </div>
          <div class="sidebar-row">
            <span class="sidebar-label">拓客人员</span>
            <span class="sidebar-value">{{ member.expandUserName || '—' }}</span>
          </div>
          <div class="sidebar-row">
            <span class="sidebar-label">联系地址</span>
            <span class="sidebar-value">{{ member.lxdz || member.address || '—' }}</span>
          </div>
          <div class="sidebar-row sidebar-row--remark">
            <span class="sidebar-label">备注</span>
            <span class="sidebar-value">{{ member.bz || member.remark || '—' }}</span>
          </div>
        </div>
      </div>

      <!-- 右侧内容区 -->
      <div class="main-content">
        <!-- Tab区 + 搜索 -->
        <div class="content-header">
          <div class="records-tab-list">
            <div class="records-tab-indicator" :style="recordsTabIndicatorStyle" />
            <button v-for="tab in recordTabs" :key="tab.key" class="records-tab"
              :class="{ 'records-tab--active': recordsTab === tab.key }" @click="recordsTab = tab.key">
              <span class="records-tab-label">{{ tab.label }}</span>
            </button>
          </div>
          <div class="records-tabs-search">
            <el-input v-model="currentSearch" size="mini" clearable :placeholder="currentSearchPlaceholder"
              class="records-search">
              <i slot="prefix" class="el-icon-search"></i>
            </el-input>
          </div>
        </div>

        <!-- 表格区 -->
        <div class="content-body">
          <!-- 权益明细 -->
          <div v-if="recordsTab === 'rights'" class="records-panel">
            <div class="records-table-wrap">
              <el-table :data="filteredRemainingItems" size="mini" class="rights-table" empty-text="暂无权益">
                <el-table-column prop="ItemName" label="项目名称" min-width="110" align="center" />
                <el-table-column prop="ItemPrice" label="单价" width="80" align="center">
                  <template slot-scope="scope"><span class="amount-text">¥{{ formatMoney(scope.row.ItemPrice)
                  }}</span></template>
                </el-table-column>
                <el-table-column prop="SourceType" label="来源" width="65" align="center" />
                <el-table-column prop="TotalPurchased" label="总购买" width="65" align="center" />
                <el-table-column prop="ConsumedCount" label="已消费" width="65" align="center" />
                <el-table-column prop="RefundedCount" label="已退款" width="65" align="center" />
                <el-table-column prop="DeductCount" label="已扣除" width="65" align="center" />
                <el-table-column prop="RemainingCount" label="剩余" width="65" align="center">
                  <template slot-scope="scope">
                    <span class="num-remaining">{{ scope.row.RemainingCount ?? scope.row.remainingCount ?? 0 }}</span>
                  </template>
                </el-table-column>
                <el-table-column label="剩余价值" width="90" align="center">
                  <template slot-scope="scope">
                    <span class="num-total">¥{{ formatMoney(remainingItemTotal(scope.row)) }}</span>
                  </template>
                </el-table-column>
              </el-table>
            </div>
            <div class="records-pagination">
              <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="rightsTotalCount"
                :page-size.sync="pageSize" :current-page.sync="rightsPage" :page-sizes="[10, 20, 50, 100]"
                @size-change="initData" @current-change="initData" />
            </div>
          </div>

          <!-- 预约记录 -->
          <div v-else-if="recordsTab === 'booking'" class="records-panel">
            <div class="records-table-wrap">
              <el-table :data="filteredBookingRecords" size="mini" class="record-table" empty-text="暂无预约记录">
                <el-table-column prop="AppointmentDate" label="预约时间" width="140" align="center" />
                <el-table-column prop="StoreName" label="门店" width="80" align="center" />
                <el-table-column prop="InviterName" label="沟通人" width="75" align="center" />
                <el-table-column prop="HealthCoachName" label="预约健康师" width="85" align="center" />
                <el-table-column prop="ExperienceItem" label="体验项目" min-width="100" align="center"
                  show-overflow-tooltip />
                <el-table-column prop="Status" label="状态" width="80" align="center">
                  <template slot-scope="scope">
                    <span :class="['status-capsule', statusClass(scope.row.Status)]">{{ scope.row.Status }}</span>
                  </template>
                </el-table-column>
                <el-table-column prop="NoDealRemark" label="未成交说明" min-width="100" align="center"
                  show-overflow-tooltip />
              </el-table>
            </div>
            <div class="records-pagination">
              <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="bookingTotalCount"
                :page-size.sync="pageSize" :current-page.sync="bookingPage" :page-sizes="[10, 20, 50, 100]"
                @size-change="initData" @current-change="initData" />
            </div>
          </div>

          <!-- 开单记录 -->
          <div v-else-if="recordsTab === 'billing'" class="records-panel">
            <div class="records-table-wrap">
              <el-table :data="filteredBillingRecords" size="mini" class="record-table" empty-text="暂无开单记录">
                <el-table-column prop="BillingDate" label="开单日期" width="140" align="center" />
                <el-table-column prop="StoreName" label="门店" width="80" align="center" />
                <el-table-column prop="CreatorName" label="开单人员" width="75" align="center" />
                <el-table-column prop="HealthCoachNames" label="健康师" width="85" align="center" show-overflow-tooltip />
                <el-table-column prop="TechTeacherNames" label="科技老师" width="85" align="center" show-overflow-tooltip />
                <el-table-column prop="Items" label="开单品项" min-width="140" align="center" show-overflow-tooltip />
                <el-table-column label="实付金额" width="85" align="center">
                  <template slot-scope="scope"><span class="amount-text">¥{{ formatMoney(scope.row.Amount)
                  }}</span></template>
                </el-table-column>
                <el-table-column label="欠款金额" width="85" align="center">
                  <template slot-scope="scope"><span class="amount-text">¥{{ formatMoney(scope.row.DebtAmount)
                  }}</span></template>
                </el-table-column>
                <el-table-column prop="ActivityName" label="活动名称" width="85" align="center" show-overflow-tooltip />
              </el-table>
            </div>
            <div class="records-pagination">
              <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="billingTotalCount"
                :page-size.sync="pageSize" :current-page.sync="billingPage" :page-sizes="[10, 20, 50, 100]"
                @size-change="initData" @current-change="initData" />
            </div>
          </div>

          <!-- 消耗记录 -->
          <div v-else-if="recordsTab === 'consume'" class="records-panel">
            <div class="records-table-wrap">
              <el-table :data="filteredConsumeRecords" size="mini" class="record-table" empty-text="暂无消耗记录">
                <el-table-column prop="ConsumeDate" label="消耗日期" width="140" align="center" />
                <el-table-column prop="StoreName" label="门店" width="100" align="center" />
                <el-table-column prop="OperatorName" label="操作人员" width="75" align="center" />
                <el-table-column prop="HealthCoachNames" label="健康师" width="85" align="center" show-overflow-tooltip />
                <el-table-column prop="TechTeacherNames" label="科技老师" width="85" align="center" show-overflow-tooltip />
                <el-table-column prop="Items" label="消耗品项" min-width="140" align="center" show-overflow-tooltip />
                <el-table-column label="消耗金额" width="100" align="center">
                  <template slot-scope="scope"><span class="amount-text">¥{{ formatMoney(scope.row.Amount)
                  }}</span></template>
                </el-table-column>
                <el-table-column label="手工费" width="100" align="center">
                  <template slot-scope="scope"><span class="amount-text">¥{{ formatMoney(scope.row.LaborCost)
                  }}</span></template>
                </el-table-column>
              </el-table>
            </div>
            <div class="records-pagination">
              <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="consumeTotalCount"
                :page-size.sync="pageSize" :current-page.sync="consumePage" :page-sizes="[10, 20, 50, 100]"
                @size-change="initData" @current-change="initData" />
            </div>
          </div>

          <!-- 服务日志 -->
          <div v-else-if="recordsTab === 'serviceLog'" class="records-panel">
            <div class="records-table-wrap">
              <el-table :data="filteredServiceLogRecords" size="mini" class="record-table" empty-text="暂无服务日志">
                <el-table-column prop="CreateTime" label="记录时间" width="140" align="center" />
                <el-table-column prop="CreatorName" label="添加人" width="75" align="center" />
                <el-table-column prop="Remark" label="备注" min-width="200" align="center" show-overflow-tooltip />
                <el-table-column prop="KjbRemark" label="科技部备注" min-width="100" align="center" show-overflow-tooltip />
              </el-table>
            </div>
            <div class="records-pagination">
              <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="serviceLogTotalCount"
                :page-size.sync="pageSize" :current-page.sync="serviceLogPage" :page-sizes="[10, 20, 50, 100]"
                @size-change="initData" @current-change="initData" />
            </div>
          </div>

          <!-- 旧日志 -->
          <div v-else-if="recordsTab === 'oldLog'" class="records-panel">
            <div class="records-table-wrap">
              <el-table :data="filteredOldLogRecords" size="mini" class="record-table" empty-text="暂无旧日志">
                <el-table-column prop="CreateTime" label="记录时间" width="140" align="center" />
                <el-table-column prop="OrderNo" label="开单号" width="130" align="center" />
                <el-table-column prop="MemberName" label="会员名称" width="85" align="center" />
                <el-table-column prop="Remarks" label="备注" min-width="200" align="center" show-overflow-tooltip />
              </el-table>
            </div>
            <div class="records-pagination">
              <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="oldLogTotalCount"
                :page-size.sync="pageSize" :current-page.sync="oldLogPage" :page-sizes="[10, 20, 50, 100]"
                @size-change="initData" @current-change="initData" />
            </div>
          </div>

          <!-- 退卡列表 -->
          <div v-else-if="recordsTab === 'refund'" class="records-panel">
            <div class="records-table-wrap">
              <el-table :data="filteredRefundRecords" size="mini" class="record-table" empty-text="暂无退卡记录">
                <el-table-column prop="RefundDate" label="退卡日期" width="140" align="center" />
                <el-table-column prop="StoreName" label="门店" width="100" align="center" />
                <el-table-column label="退卡金额" width="100" align="center">
                  <template slot-scope="scope"><span class="amount-text">¥{{ formatMoney(scope.row.RefundAmount)
                  }}</span></template>
                </el-table-column>
                <el-table-column label="实际退款" width="100" align="center">
                  <template slot-scope="scope"><span class="amount-text">¥{{ formatMoney(scope.row.ActualRefundAmount)
                  }}</span></template>
                </el-table-column>
                <el-table-column prop="RefundReason" label="退卡原因" min-width="120" align="center"
                  show-overflow-tooltip />
              </el-table>
            </div>
            <div class="records-pagination">
              <el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="refundTotalCount"
                :page-size.sync="pageSize" :current-page.sync="refundPage" :page-sizes="[10, 20, 50, 100]"
                @size-change="initData" @current-change="initData" />
            </div>
          </div>
        </div>

        <!-- 底部按钮 -->
        <div class="content-footer">
          <span class="records-op-btn records-op-btn--ghost records-op-btn--invite" @click="emitAction('invite')"><i
              class="el-icon-phone-outline"></i>添加沟通记录</span>
          <span class="records-op-btn records-op-btn--ghost records-op-btn--booking" @click="emitAction('booking')"><i
              class="el-icon-date"></i>去预约</span>
          <span class="records-op-btn records-op-btn--ghost records-op-btn--billing" @click="emitAction('billing')"><i
              class="el-icon-document"></i>去开单</span>
          <span class="records-op-btn records-op-btn--ghost records-op-btn--consume" @click="emitAction('consume')"><i
              class="el-icon-s-claim"></i>去耗卡</span>
          <span class="records-op-btn records-op-btn--ghost records-op-btn--refund" @click="emitAction('refund')"><i
              class="el-icon-refresh-left"></i>去退卡</span>
          <span class="records-op-btn records-op-btn--ghost records-op-btn--close" @click="close"><i
              class="el-icon-close"></i>关闭</span>
        </div>
      </div>
    </div>
  </el-dialog>
</template>

<script>
export default {
  name: 'MemberProfileDialog',
  props: {
    visible: { type: Boolean, default: false },
    member: { type: Object, default: () => ({}) }
  },
  data() {
    return {
      recordsTab: 'rights',
      searchRights: '',
      searchBilling: '',
      searchConsume: '',
      searchInvite: '',
      searchBooking: '',
      searchRefund: '',
      searchServiceLog: '',
      searchOldLog: '',
      pageSize: 5,
      rightsPage: 1,
      billingPage: 1,
      consumePage: 1,
      invitePage: 1,
      bookingPage: 1,
      refundPage: 1,
      serviceLogPage: 1,
      oldLogPage: 1
    }
  },
  computed: {
    visibleProxy: {
      get() { return this.visible },
      set(val) { this.$emit('update:visible', val) }
    },
    displayName() {
      return this.member.khmc || this.member.name || '会员'
    },
    initials() {
      const n = this.displayName
      return n ? n[0] : '会'
    },
    consumeLevelText() {
      const level = this.member.consumeLevel
      const map = { 0: 'D', 1: 'C', 2: 'B', 3: 'A', 4: 'A+', 5: 'A++' }
      return map[level] !== undefined ? map[level] : (this.member.consumeLevelName || '')
    },
    consumeLevelClass() {
      const level = this.member.consumeLevel
      const map = { 0: 'level--d', 1: 'level--c', 2: 'level--b', 3: 'level--a', 4: 'level--aplus', 5: 'level--aplusplus' }
      return map[level] || 'level--default'
    },
    remainingItems() {
      const list = this.member.RemainingItems || this.member.remainingItems || []
      return Array.isArray(list) ? list : []
    },
    remainingRightsTotal() {
      const list = this.remainingItems
      return list.reduce((sum, row) => sum + (Number(row.RemainingCount ?? row.remainingCount ?? 0) * Number(row.ItemPrice ?? row.itemPrice ?? 0)), 0)
    },
    memberTypeSummary() {
      const t = []
      if (this.member.isBeautyMember === 1) t.push('生美')
      if (this.member.isMedicalMember === 1) t.push('医美')
      if (this.member.isTechMember === 1) t.push('科技')
      if (this.member.isEducationMember === 1) t.push('教育')
      return t.length ? t.join(' / ') : '—'
    },
    formattedBirthday() {
      const m = this.member
      const yang = m.yanglsr || ''
      const yin = m.yinlsr || ''
      if (yang && yin) return `${yang}(${yin})`
      if (yang) return yang
      if (yin) return yin
      return '—'
    },
    memberTypeList() {
      const list = []
      if (this.member.isBeautyMember === 1) list.push({ type: 'beauty', label: '生美' })
      if (this.member.isMedicalMember === 1) list.push({ type: 'medical', label: '医美' })
      if (this.member.isTechMember === 1) list.push({ type: 'tech', label: '科美' })
      return list
    },
    filteredRightsAll() {
      const kw = (this.searchRights || '').trim()
      const list = this.remainingItems
      if (!kw) return list
      return list.filter(row => {
        const name = String(row.ItemName || row.itemName || '')
        return name.includes(kw)
      })
    },
    rightsTotalCount() {
      return this.filteredRightsAll.length
    },
    filteredRemainingItems() {
      const list = this.filteredRightsAll
      const size = this.pageSize
      const maxPage = Math.max(1, Math.ceil((list.length || 1) / size))
      const page = Math.min(this.rightsPage || 1, maxPage)
      const start = (page - 1) * size
      return list.slice(start, start + size)
    },
    billingRecords() {
      const list = this.member.billingRecords || this.member.BillingRecords || []
      return Array.isArray(list) ? list : []
    },
    filteredBillingAll() {
      const kw = (this.searchBilling || '').trim()
      const list = this.billingRecords
      if (!kw) return list
      return list.filter(row => {
        const items = String(row.Items || '')
        const creator = String(row.CreatorName || '')
        return items.includes(kw) || creator.includes(kw)
      })
    },
    billingTotalCount() {
      return this.filteredBillingAll.length
    },
    filteredBillingRecords() {
      const list = this.filteredBillingAll
      const size = this.pageSize
      const maxPage = Math.max(1, Math.ceil((list.length || 1) / size))
      const page = Math.min(this.billingPage || 1, maxPage)
      const start = (page - 1) * size
      return list.slice(start, start + size)
    },
    consumeRecords() {
      const list = this.member.consumeRecords || this.member.ConsumeRecords || []
      return Array.isArray(list) ? list : []
    },
    filteredConsumeAll() {
      const kw = (this.searchConsume || '').trim()
      const list = this.consumeRecords
      if (!kw) return list
      return list.filter(row => {
        const items = String(row.Items || '')
        const operator = String(row.OperatorName || '')
        return items.includes(kw) || operator.includes(kw)
      })
    },
    consumeTotalCount() {
      return this.filteredConsumeAll.length
    },
    filteredConsumeRecords() {
      const list = this.filteredConsumeAll
      const size = this.pageSize
      const maxPage = Math.max(1, Math.ceil((list.length || 1) / size))
      const page = Math.min(this.consumePage || 1, maxPage)
      const start = (page - 1) * size
      return list.slice(start, start + size)
    },
    inviteRecords() {
      const list = this.member.inviteRecords || this.member.InviteRecords || []
      return Array.isArray(list) ? list : []
    },
    filteredInviteAll() {
      const kw = (this.searchInvite || '').trim()
      const list = this.inviteRecords
      if (!kw) return list
      return list.filter(row => {
        const record = String(row.ContactRecord || '')
        const inviter = String(row.InviterName || '')
        return record.includes(kw) || inviter.includes(kw)
      })
    },
    inviteTotalCount() {
      return this.filteredInviteAll.length
    },
    filteredInviteRecords() {
      const list = this.filteredInviteAll
      const size = this.pageSize
      const maxPage = Math.max(1, Math.ceil((list.length || 1) / size))
      const page = Math.min(this.invitePage || 1, maxPage)
      const start = (page - 1) * size
      return list.slice(start, start + size)
    },
    bookingRecords() {
      const list = this.member.bookingRecords || this.member.BookingRecords || []
      return Array.isArray(list) ? list : []
    },
    filteredBookingAll() {
      const kw = (this.searchBooking || '').trim()
      const list = this.bookingRecords
      if (!kw) return list
      return list.filter(row => {
        const item = String(row.ExperienceItem || '')
        const coach = String(row.HealthCoachName || '')
        return item.includes(kw) || coach.includes(kw)
      })
    },
    bookingTotalCount() {
      return this.filteredBookingAll.length
    },
    filteredBookingRecords() {
      const list = this.filteredBookingAll
      const size = this.pageSize
      const maxPage = Math.max(1, Math.ceil((list.length || 1) / size))
      const page = Math.min(this.bookingPage || 1, maxPage)
      const start = (page - 1) * size
      return list.slice(start, start + size)
    },
    refundRecords() {
      const list = this.member.refundRecords || this.member.RefundRecords || []
      return Array.isArray(list) ? list : []
    },
    filteredRefundAll() {
      const kw = (this.searchRefund || '').trim()
      const list = this.refundRecords
      if (!kw) return list
      return list.filter(row => {
        const reason = String(row.RefundReason || '')
        return reason.includes(kw)
      })
    },
    refundTotalCount() {
      return this.filteredRefundAll.length
    },
    filteredRefundRecords() {
      const list = this.filteredRefundAll
      const size = this.pageSize
      const maxPage = Math.max(1, Math.ceil((list.length || 1) / size))
      const page = Math.min(this.refundPage || 1, maxPage)
      const start = (page - 1) * size
      return list.slice(start, start + size)
    },
    serviceLogRecords() {
      const list = this.member.serviceLogRecords || []
      return Array.isArray(list) ? list : []
    },
    filteredServiceLogAll() {
      const kw = (this.searchServiceLog || '').trim()
      const list = this.serviceLogRecords
      if (!kw) return list
      return list.filter(row => {
        const remark = String(row.Remark || '')
        const creator = String(row.CreatorName || '')
        return remark.includes(kw) || creator.includes(kw)
      })
    },
    serviceLogTotalCount() { return this.filteredServiceLogAll.length },
    filteredServiceLogRecords() {
      const list = this.filteredServiceLogAll
      const size = this.pageSize
      const maxPage = Math.max(1, Math.ceil((list.length || 1) / size))
      const page = Math.min(this.serviceLogPage || 1, maxPage)
      const start = (page - 1) * size
      return list.slice(start, start + size)
    },
    oldLogRecords() {
      const list = this.member.oldLogRecords || []
      return Array.isArray(list) ? list : []
    },
    filteredOldLogAll() {
      const kw = (this.searchOldLog || '').trim()
      const list = this.oldLogRecords
      if (!kw) return list
      return list.filter(row => {
        const no = String(row.OrderNo || '')
        const remarks = String(row.Remarks || '')
        return no.includes(kw) || remarks.includes(kw)
      })
    },
    oldLogTotalCount() { return this.filteredOldLogAll.length },
    filteredOldLogRecords() {
      const list = this.filteredOldLogAll
      const size = this.pageSize
      const maxPage = Math.max(1, Math.ceil((list.length || 1) / size))
      const page = Math.min(this.oldLogPage || 1, maxPage)
      const start = (page - 1) * size
      return list.slice(start, start + size)
    },
    recordTabs() {
      return [
        { key: 'rights', label: '权益明细' },
        { key: 'invite', label: '联系记录' },
        { key: 'booking', label: '预约记录' },
        { key: 'billing', label: '开单记录' },
        { key: 'consume', label: '消耗记录' },
        { key: 'serviceLog', label: '服务日志' },
        { key: 'oldLog', label: '旧日志' },
        { key: 'refund', label: '退卡列表' }
      ]
    },
    currentSearch: {
      get() {
        switch (this.recordsTab) {
          case 'invite': return this.searchInvite
          case 'booking': return this.searchBooking
          case 'billing': return this.searchBilling
          case 'consume': return this.searchConsume
          case 'refund': return this.searchRefund
          case 'rights': return this.searchRights
          case 'serviceLog': return this.searchServiceLog
          case 'oldLog': return this.searchOldLog
          default: return ''
        }
      },
      set(val) {
        switch (this.recordsTab) {
          case 'invite': this.searchInvite = val; break
          case 'booking': this.searchBooking = val; break
          case 'billing': this.searchBilling = val; break
          case 'consume': this.searchConsume = val; break
          case 'refund': this.searchRefund = val; break
          case 'rights': this.searchRights = val; break
          case 'serviceLog': this.searchServiceLog = val; break
          case 'oldLog': this.searchOldLog = val; break
        }
      }
    },
    currentSearchPlaceholder() {
      switch (this.recordsTab) {
        case 'invite': return '按联系记录/跟进人搜索'
        case 'booking': return '按体验项目/健康师搜索'
        case 'billing': return '按品项/开单人员搜索'
        case 'consume': return '按品项/操作人员搜索'
        case 'refund': return '按退卡原因搜索'
        case 'rights': return '按项目名称搜索'
        case 'serviceLog': return '按备注/添加人搜索'
        case 'oldLog': return '按开单号/备注搜索'
        default: return '输入关键字搜索'
      }
    },
    recordsTabIndicatorStyle() {
      const tabs = this.recordTabs
      const count = tabs.length || 1
      const index = Math.max(0, tabs.findIndex(t => t.key === this.recordsTab))
      const width = 100 / count
      return {
        width: `${width}%`,
        transform: `translateX(${index * 100}%)`
      }
    }
  },
  methods: {
    initData() {
      // 分页切换时由 .sync 自动更新 pageSize/current-page，computed 会自动重算，无需额外逻辑
    },
    formatMoney(val) {
      if (val == null || val === '') return '0.00'
      const n = Number(val)
      if (isNaN(n)) return '0.00'
      return n.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',')
    },
    remainingItemTotal(row) {
      const c = Number(row.RemainingCount ?? row.remainingCount ?? 0)
      const p = Number(row.ItemPrice ?? row.itemPrice ?? 0)
      return c * p
    },
    emitAction(type) {
      this.$emit('action', { type, member: this.member })
    },
    close() {
      this.visibleProxy = false
    },
    relativeTime(dateStr) {
      if (!dateStr) return '—'
      const date = new Date(dateStr)
      if (isNaN(date.getTime())) return dateStr
      const now = new Date()
      const diff = now - date
      const days = Math.floor(diff / (1000 * 60 * 60 * 24))
      if (days < 0) return dateStr
      if (days === 0) return '今天'
      if (days === 1) return '昨天'
      if (days < 7) return `${days}天前`
      if (days < 30) return `${Math.floor(days / 7)}周前`
      if (days < 365) return `${Math.floor(days / 30)}个月前`
      return `${Math.floor(days / 365)}年前`
    },
    statusClass(status) {
      if (!status) return 'status--default'
      const greenList = ['已到店', '已完成', '已签到', '已服务']
      const orangeList = ['待跟进', '待确认', '待服务', '进行中']
      const redList = ['已取消', '已退卡', '已退款', '已过期']
      const blueList = ['已预约', '待到店', '处理中', '已确认']
      if (greenList.includes(status)) return 'status--green'
      if (orangeList.includes(status)) return 'status--orange'
      if (redList.includes(status)) return 'status--red'
      if (blueList.includes(status)) return 'status--blue'
      return 'status--default'
    }
  }
}
</script>

<style lang="scss" scoped>
/* ========== Dialog 外壳 ========== */
::v-deep .el-dialog {
  width: 92vw;
  max-width: 1500px;
  height: 94vh;
  margin-top: 3vh !important;
  border-radius: 20px;
  padding: 0;
  background: radial-gradient(circle at top left, rgba(255, 255, 255, 0.96) 0, rgba(248, 250, 252, 0.98) 38%, rgba(241, 245, 249, 0.98) 100%);
  box-shadow: 0 24px 48px rgba(15, 23, 42, 0.2), 0 0 0 0.5px rgba(148, 163, 184, 0.35);
  border: 1px solid rgba(226, 232, 240, 0.9);
  backdrop-filter: blur(26px);
  -webkit-backdrop-filter: blur(26px);
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
}

::v-deep .el-dialog__header {
  display: none;
}

::v-deep .el-dialog__body {
  padding: 0;
  flex: 1;
  overflow: hidden;
}

/* ========== 主容器：左右分栏 ========== */
.member-dialog-inner {
  display: flex;
  flex-direction: row;
  height: 100%;
  box-sizing: border-box;
}

/* ========== 左侧边栏 ========== */
.sidebar {
  width: 320px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  background: rgba(248, 250, 252, 0.98);
  border-right: 1px solid rgba(226, 232, 240, 0.6);
  border-radius: 0 0 0 20px;
  overflow-y: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;

  &::-webkit-scrollbar {
    display: none;
  }
}

/* -- 身份区 -- */
.sidebar-identity {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 28px 20px 18px;
}

.member-avatar {
  width: 68px;
  height: 68px;
  border-radius: 50%;
  background: linear-gradient(145deg, #6366f1, #a855f7);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 600;
  font-size: 26px;
  flex-shrink: 0;
  box-shadow: 0 6px 16px rgba(99, 102, 241, 0.3), 0 0 0 3px rgba(255, 255, 255, 0.8);
  margin-bottom: 12px;
}

.member-name {
  font-size: 19px;
  font-weight: 600;
  color: #0f172a;
  letter-spacing: 0.3px;
  text-align: center;
  margin-bottom: 8px;
}

.level-tag {
  display: inline-block;
  font-size: 12px;
  padding: 3px 16px;
  border-radius: 999px;
  font-weight: 600;
  margin-bottom: 10px;
}

.level--d {
  background: #e5e7eb;
  color: #6b7280;
}

.level--c {
  background: rgba(59, 130, 246, 0.1);
  color: #2563eb;
  border: 1px solid rgba(59, 130, 246, 0.2);
}

.level--b {
  background: rgba(34, 197, 94, 0.1);
  color: #16a34a;
  border: 1px solid rgba(34, 197, 94, 0.2);
}

.level--a {
  background: rgba(245, 158, 11, 0.1);
  color: #d97706;
  border: 1px solid rgba(245, 158, 11, 0.2);
}

.level--aplus {
  background: linear-gradient(135deg, #f59e0b, #d97706);
  color: #fff;
  box-shadow: 0 2px 6px rgba(245, 158, 11, 0.3);
}

.level--aplusplus {
  background: linear-gradient(135deg, #ef4444, #dc2626);
  color: #fff;
  box-shadow: 0 2px 6px rgba(239, 68, 68, 0.3);
}

.level--default {
  background: linear-gradient(135deg, #f59e0b, #d97706);
  color: #fff;
}

.member-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  color: #64748b;
  flex-wrap: wrap;
  text-align: center;

  span+span::before {
    content: '\00b7';
    margin: 0 5px;
    color: #cbd5e1;
    font-weight: 700;
    font-size: 15px;
  }
}

.member-sub-info {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 14px;
  color: #64748b;
  margin-bottom: 8px;
  flex-wrap: wrap;
}

.member-phone {
  color: #16a34a;
  font-weight: 500;

  i {
    margin-right: 3px;
    font-size: 14px;
  }
}

.member-dah {
  color: #94a3b8;
  font-size: 13px;
}

.member-type-tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 5px;
  margin-bottom: 6px;
}

.type-tag {
  padding: 3px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
}

.type-tag--beauty {
  background: rgba(34, 197, 94, 0.1);
  color: #16a34a;
  border: 1px solid rgba(34, 197, 94, 0.15);
}

.type-tag--medical {
  background: rgba(249, 115, 22, 0.1);
  color: #ea580c;
  border: 1px solid rgba(249, 115, 22, 0.15);
}

.type-tag--tech {
  background: rgba(59, 130, 246, 0.1);
  color: #2563eb;
  border: 1px solid rgba(59, 130, 246, 0.15);
}

.member-visit-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 6px;
  flex-wrap: wrap;
}

.member-visit {
  font-size: 13px;
  color: #94a3b8;
  cursor: default;

  i {
    margin-right: 3px;
    font-size: 13px;
  }
}

.member-sleep {
  font-size: 12px;
  padding: 3px 10px;
  border-radius: 999px;
  background: rgba(249, 115, 22, 0.1);
  color: #ea580c;
  font-weight: 500;

  i {
    margin-right: 2px;
    font-size: 12px;
  }
}

.tag-row {
  margin-top: 10px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 5px;
}

.member-tag {
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  background: rgba(129, 140, 248, 0.1);
  color: #4f46e5;
  border: 1px solid rgba(129, 140, 248, 0.15);
}

/* -- 侧边栏通用 section -- */
.sidebar-section {
  padding: 14px 20px;
  border-top: 1px solid rgba(226, 232, 240, 0.5);
}

.sidebar-section-title {
  font-size: 14px;
  font-weight: 600;
  color: #64748b;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 5px;

  i {
    font-size: 14px;
    color: #6366f1;
  }
}

.sidebar-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 5px 0;
  min-height: 26px;
}

.sidebar-row--highlight {
  background: linear-gradient(135deg, rgba(37, 99, 235, 0.04), rgba(124, 58, 237, 0.04));
  border-radius: 6px;
  padding: 4px 8px;
  margin: 1px -8px;
}

.sidebar-row--remark {
  align-items: flex-start;

  .sidebar-value {
    white-space: normal;
    word-break: break-all;
    text-align: right;
    max-width: 160px;
  }
}

.sidebar-label {
  color: #94a3b8;
  font-size: 13px;
  flex-shrink: 0;
  display: flex;
  align-items: center;

  i {
    margin-right: 3px;
    font-size: 13px;
    color: #94a3b8;
  }
}

.sidebar-value {
  color: #1e293b;
  font-size: 14px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 170px;
  text-align: right;
}

.sidebar-value--amount {
  font-size: 15px;
  font-weight: 600;
  color: #0f172a;
}

.sidebar-value--gradient {
  font-size: 16px;
  font-weight: 700;
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

/* ========== 右侧内容区 ========== */
.main-content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: 18px 28px;
}

/* -- 内容头部：Tab + 搜索 -- */
.content-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 14px;
  flex-shrink: 0;
}

.records-tab-list {
  display: inline-flex;
  flex: 1;
  min-width: 0;
  width: 100%;
  max-width: 100%;
  background: rgba(229, 231, 235, 0.7);
  border-radius: 999px;
  padding: 3px;
  position: relative;
  overflow: hidden;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.records-tab {
  border: none;
  outline: none;
  background: transparent;
  padding: 0 10px;
  border-radius: 999px;
  font-size: 14px;
  color: #4b5563;
  cursor: pointer;
  transition: color 0.25s ease;
  flex: 1 1 0;
  text-align: center;
  height: 34px;
  line-height: 34px;
  position: relative;
  z-index: 1;
}

.records-tab--active {
  color: #1d4ed8;
  font-weight: 600;
}

.records-tab-indicator {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.98);
  box-shadow: 0 3px 10px rgba(15, 23, 42, 0.12), 0 0 0 1px rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1);
  z-index: 0;
}

.records-tab-label {
  white-space: nowrap;
}

.records-tabs-search {
  flex-shrink: 0;
  margin-left: 12px;
}

.records-search {
  width: 200px;
}

.records-search ::v-deep .el-input__inner {
  border-radius: 999px;
  height: 34px;
  line-height: 34px;
  font-size: 14px;
  border-color: #e2e8f0;
  transition: border-color 0.2s;

  &:focus {
    border-color: #6366f1;
  }
}

.records-search ::v-deep .el-input__prefix {
  display: flex;
  align-items: center;
  height: 100%;
}

/* -- 表格主体区：flex:1 填满 -- */
.content-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.records-panel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.records-table-wrap {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;

  &::-webkit-scrollbar {
    display: none;
  }
}

.record-table,
.rights-table {
  font-size: 14px;
}

::v-deep .el-table {
  &::before {
    display: none;
  }

  th {
    padding: 10px 0;
    font-size: 13px;
    background: #f8fafc;
    color: #64748b;
    font-weight: 500;
    border-bottom: 1px solid #e2e8f0;
  }

  td {
    padding: 9px 0;
    border-bottom: 1px solid #f1f5f9;
  }

  .el-table__row:hover>td {
    background: rgba(99, 102, 241, 0.03);
  }

  &.el-table--border td,
  &.el-table--border th {
    border-right: none;
  }

  &.el-table--border::after {
    display: none;
  }
}

.records-pagination {
  margin-top: 8px;
  text-align: right;
  flex-shrink: 0;
}

/* ========== 状态胶囊 ========== */
.status-capsule {
  display: inline-block;
  padding: 3px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.6;
}

.status--green {
  background: rgba(34, 197, 94, 0.1);
  color: #16a34a;
}

.status--orange {
  background: rgba(249, 115, 22, 0.1);
  color: #ea580c;
}

.status--red {
  background: rgba(239, 68, 68, 0.1);
  color: #dc2626;
}

.status--blue {
  background: rgba(59, 130, 246, 0.1);
  color: #2563eb;
}

.status--default {
  background: rgba(148, 163, 184, 0.1);
  color: #64748b;
}

.amount-text {
  font-weight: 600;
  color: #2563eb;
}

.num-remaining {
  font-weight: 600;
  color: #2563eb;
}

.num-total {
  font-weight: 600;
  color: #7c3aed;
}

/* -- 底部操作按钮 -- */
.content-footer {
  display: flex;
  justify-content: flex-start;
  gap: 10px;
  padding-top: 8px;
  flex-shrink: 0;
  border-top: 1px solid rgba(226, 232, 240, 0.5);
}

.records-op-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 84px;
  height: 32px;
  padding: 0 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: color 0.2s ease, box-shadow 0.2s ease, transform 0.12s ease;

  i {
    font-size: 13px;
  }
}

.records-op-btn--ghost {
  background: rgba(239, 246, 255, 0.9);
  color: #2563eb;
  border: 1px solid rgba(37, 99, 235, 0.18);
}

.records-op-btn:hover {
  transform: translateY(-0.5px);
  box-shadow: 0 4px 10px rgba(15, 23, 42, 0.12);
}

.records-op-btn--ghost:hover {
  color: #ffffff;
}

.records-op-btn::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-size: 200% 100%;
  background-position: 0% 0;
  opacity: 0.9;
  transform: translateX(-100%);
  transition: transform 0.25s ease;
  z-index: -1;
}

.records-op-btn:hover::before {
  transform: translateX(0);
}

.records-op-btn--invite::before {
  background-image: linear-gradient(135deg, #0ea5e9, #22c55e);
}

.records-op-btn--booking::before {
  background-image: linear-gradient(135deg, #f97316, #facc15);
}

.records-op-btn--billing::before {
  background-image: linear-gradient(135deg, #3b82f6, #2563eb);
}

.records-op-btn--consume::before {
  background-image: linear-gradient(135deg, #22c55e, #16a34a);
}

.records-op-btn--refund::before {
  background-image: linear-gradient(135deg, #f97316, #ef4444);
}

.records-op-btn--close {
  margin-left: auto;

  &::before {
    background-image: linear-gradient(135deg, #94a3b8, #64748b);
  }
}
</style>
