# ConvertRecordCash

A record detail component that supports both vertical and horizontal layout modes for displaying user's point earning, consumption, and exchange records.

# Usage

# Basic Usage (Vertical Layout)

<template>
  <div>
    <button @click="showDialog = true">Open Record Detail</button>
    
    <PressConvertRecordCash
      :show="showDialog"
      :tab-index="currentTabIndex"
      :tab-list="tabOptions"
      :point-name="pointName"
      :point-amount="userPointAmount"
      :point-num="totalPointNum"
      :expire-time="pointExpireTime"
      :list="recordList"
      :loading="isLoading"
      :finished="isFinished"
      @close="showDialog = false"
      @go-back="showDialog = false"
      @change-tab="handleTabChange"
      @load="handleLoadMore"
      @jump-to-feedback="handleJumpToFeedback"
      @go-jump="handleGoToTask"
      @goto-goods-detail="handleGoodsDetail"
      @record-refresh="handleRecordRefresh"
    >
      <!-- Record Text Slot: Custom record item text display -->
      <template #record-text="{ item, tabIndex, pointName }">
        <template v-if="tabIndex === 1">
          <!-- Earned records: +2 draw times, 9 tokens -->
          <span class="demo-highlight">+{{ item.point }}</span> draw times, <span class="demo-highlight">{{ item.point }}</span> {{ pointName }}
        </template>
        <template v-else-if="tabIndex === 3">
          <!-- Consumed records: display different text based on consumeType -->
          <template v-if="item.consumeType === 'Draw Count'">
            <span class="demo-highlight">-{{ item.point }}</span> draw times
          </template>
          <template v-else>
            <span class="demo-highlight">-{{ item.point }}</span> {{ pointName }}
          </template>
        </template>
      </template>
      
      <!-- Record Tip Slot: Custom statistics text -->
      <template #record-tip>
        <template v-if="currentTabIndex === 1">
          Total earned: <span class="highlight">{{ calculateTotal(recordList) }}</span> draw times, <span class="highlight">{{ calculateTotal(recordList) }}</span> {{ pointName }}
        </template>
        <template v-else-if="currentTabIndex === 3">
          Total consumed: <span class="highlight">{{ calculateConsumeTotal(recordList, 'Draw Count') }}</span> draw times, <span class="highlight">{{ calculateConsumeTotal(recordList, 'Points') }}</span> {{ pointName }}
        </template>
      </template>
    </PressConvertRecordCash>
  </div>
</template>

<script>
import { getMockData } from 'src/packages/press-convert-record-cash/demo-data/index.ts';

export default {
  data() {
    return {
      showDialog: false,
      currentTabIndex: 1,
      ...getMockData(),
    };
  },
  methods: {
    // Calculate total
    calculateTotal(list) {
      if (!list || list.length === 0) return '0';
      return list.reduce((sum, item) => sum + parseInt(item.point || 0, 10), 0);
    },
    // Calculate total by consume type (Draw Count/Points calculated separately)
    calculateConsumeTotal(list, consumeType) {
      if (!list || list.length === 0) return '0';
      const filteredList = list.filter(item => item.consumeType === consumeType);
      return filteredList.reduce((sum, item) => sum + parseInt(item.point || 0, 10), 0);
    },
  },
};
</script>

<style scoped>
.highlight {
  color: #f16253;
}

.demo-highlight {
  color: #ff6b6b;
  font-weight: bold;
}
</style>

# Horizontal Layout (via styleName)

<template>
  <PressConvertRecordCash
    :show="showDialog"
    style-name="tip-hori"
    :tab-index="currentTabIndex"
    :tab-list="tabOptions"
    :point-name="pointName"
    :point-amount="userPointAmount"
    :point-num="totalPointNum"
    :expire-time="pointExpireTime"
    :list="recordList"
    @close="showDialog = false"
  />
</template>

# Empty State

<template>
  <PressConvertRecordCash
    :show="showDialog"
    :tab-index="currentTabIndex"
    :tab-list="tabOptions"
    :point-name="pointName"
    :point-amount="0"
    :point-num="0"
    :list="[]"
    @close="showDialog = false"
  />
</template>

# API

# Props

Property Description Type Default
show Whether to show the component boolean false
z-index Component z-index number 1000
tab-index Current selected tab index number 1
tab-list Tab list data array []
style-name Style class for theme adaptation string ''
money-type Currency type number 0
point-name Point name string ''
point-num Total earned/consumed points string ''
point-amount Current user points string ''
expire-time Point expiration time (ms) number 0
list Record list data array []
loading Whether loading more data boolean false
finished Whether all data loaded boolean false
immediate-check Whether to check immediately boolean false

# Events

Event Description Parameters
close Close component -
go-back Go back -
load Load more data -
change-tab Tab change tabId: number
jump-to-feedback Jump to feedback page -
go-jump Jump to task page -
record-refresh Refresh after expiration -
goto-goods-detail View reward detail item: object

# Slots

Name Description Parameters
expire-time Custom expire time display { pointName: string, expireTime: number, onFinish: function }
record-text Custom record item text display { item: object, tabIndex: number, pointName: string }
record-tip Custom record statistics text -

# Slot Usage

expire-time Slot

Used to customize the display content and format of point expiration time. The component provides a default countdown display.

<template #expire-time="{ pointName, expireTime, onFinish }">
  <div v-if="expireTime > 0">
    {{ pointName }}
    <span class="custom-highlight">
      {{ formatCountdown(expireTime) }}
    </span> will expire
  </div>
</template>

Parameters:

  • pointName: Point name (e.g., "Lucky Coins")
  • expireTime: Expiration timestamp (milliseconds)
  • onFinish: Countdown finish callback function

record-text Slot

Used to customize the text display of record items. Only displayed when item.showViewButton is false or doesn't exist.

<template #record-text="{ item, tabIndex, pointName }">
  <template v-if="tabIndex === 1">
    <!-- Earned records: +2 draw times, 9 tokens -->
    <span class="demo-highlight">+{{ item.point }}</span> draw times, <span class="demo-highlight">{{ item.point }}</span> {{ pointName }}
  </template>
  <template v-else-if="tabIndex === 3">
    <!-- Consumed records: display different text based on consumeType -->
    <template v-if="item.consumeType === 'Draw Count'">
      <span class="demo-highlight">-{{ item.point }}</span> draw times
    </template>
    <template v-else>
      <span class="demo-highlight">-{{ item.point }}</span> {{ pointName }}
    </template>
  </template>
</template>

Parameters:

  • item: Record item data
  • tabIndex: Current tab index (1: Earned, 2: Rewards, 3: Consumed)
  • pointName: Point name (e.g., "Lucky Coins")

record-tip Slot

Used to customize the statistics text at the top of the record list, supporting different content for different tabs.

<template #record-tip>
  <template v-if="currentTabIndex === 1">
    Total earned: <span class="highlight">{{ calculateTotal(list) }}</span> draw times, <span class="highlight">{{ calculateTotal(list) }}</span> {{ pointName }}
  </template>
  <template v-else-if="currentTabIndex === 3">
    Total consumed: <span class="highlight">{{ calculateConsumeTotal(list, 'Draw Count') }}</span> draw times, <span class="highlight">{{ calculateConsumeTotal(list, 'Points') }}</span> {{ pointName }}
  </template>
</template>

Calculation Methods Example:

methods: {
  // Calculate total
  calculateTotal(list) {
    if (!list || list.length === 0) return '0';
    return list.reduce((sum, item) => sum + parseInt(item.point || 0, 10), 0);
  },
  // Calculate total by consume type (Draw Count/Points calculated separately)
  calculateConsumeTotal(list, consumeType) {
    if (!list || list.length === 0) return '0';
    const filteredList = list.filter(item => item.consumeType === consumeType);
    return filteredList.reduce((sum, item) => sum + parseInt(item.point || 0, 10), 0);
  },
}

# Data Structure

# tabList Format

[
  { id: 1, name: 'Earned Records' },
  { id: 2, name: 'Reward Records' },
  { id: 3, name: 'Consumed Records' },
]

# list Format

[
  {
    orderid: 'Order ID',
    desc: 'Record description',
    time: 'Time string',
    opertype: 1, // 1:earned times 2:reward 3:consumed draw times 4:exchange deduction 5:expired
    point: 'Point amount', // Point amount or draw count
    showViewButton: true, // Whether to show "View Reward" button (optional)
    rewardType: 'Draw Reward', // Reward type (optional, for business logic)
    consumeType: 'Draw Count' | 'Points' // Consume type (optional, for consumed records)
  }
]

# Features

# Slot Architecture Design

The component adopts the design philosophy of complete separation of UI and business logic:

  1. expire-time Slot: Fully customizable expiration time display

    • Component provides default countdown display
    • User controls: display conditions, text format, time formatting logic
  2. record-text Slot: Fully customizable record item text display

    • Component only provides container styles
    • User controls: text format for different tabs, highlight styles
    • When item.showViewButton is true, component automatically shows "View Reward" button instead of this Slot
  3. record-tip Slot: Fully customizable statistics text

    • Component only provides container styles
    • User controls: statistics logic for different tabs, text format, highlight styles

Design Advantages:

  • ✅ UI component has single responsibility, only handles styles and structure
  • ✅ Business logic is flexible and controllable, can be customized for different projects
  • ✅ Flexible button display control through showViewButton field

# Other Features

  1. Multi-tab Support: Support earned, reward, and consumed record tabs
  2. Countdown Timer: Display point expiration countdown with custom format
  3. Infinite Scroll: Support loading more data with loading states
  4. Empty State: Automatic empty state display when no data
  5. Responsive Design: Automatic layout switching for different orientations
  6. Statistics Display: Show accumulated totals for different record types

# Style Customization

Component styles are written in SCSS, with all definitions in the css/index.scss file. To customize styles:

  1. Via customClass prop: Pass custom class name to override default styles
  2. Via styleName prop: Pass game theme style class name (e.g., tip-hori for horizontal layout)
  3. Direct modification: Modify style definitions in css/index.scss

# Style Adaptation

The component supports automatic switching between vertical and horizontal layouts through the style-name prop:

// Vertical
styleName: 'tip-pvp tip-vert'

// Horizontal  
styleName: 'tip-pvp tip-hori'

# Notes

  1. Slot Usage: The component adopts Slot architecture design, record-text and record-tip Slots are provided by the user with business logic
  2. View Reward Button: Controlled by the showViewButton field in record data, shows button when true, shows record-text Slot content when false or doesn't exist
  3. Style Class Names: Demo files should use custom style classes (e.g., demo-highlight), not component internal BEM class names
  4. Fixed Positioning: Component uses fixed positioning for full-screen overlay
  5. Horizontal Adaptation: In horizontal mode, return button and wish button are automatically hidden
  6. Countdown Callback: Automatically triggers record-refresh event when countdown expires
  7. Empty State: Empty state automatically shows empty page when no data
  8. Record Types: Different record types are distinguished by opertype field (1:earned times 2:reward 3:consumed draw times 4:exchange deduction 5:expired)