zhb il y a 5 mois
Parent
commit
4d6afee813

+ 7 - 5
locale/ar.json

@@ -25,13 +25,14 @@
       "detail": "تفاصيل الطلب",
       "list": "قائمة سجل الطلبات"
     },
-    "confirmOpen": "هل تريد فتح هذا الرابط؟",
-    "open": "فتح",
-    "copyPrompt": "تم نسخ الرابط، يرجى فتحه في المتصفح",
-    "openFailed": "تعذر فتح الرابط""recharge-record": {
+    "recharge-record": {
       "index": "سجل الشحن",
       "list": "قائمة سجل الشحن",
-      "detail": "تفاصيل سجل الشحن"
+      "detail": "تفاصيل سجل الشحن",
+      "confirmOpen": "هل تريد فتح هذا الرابط؟",
+      "open": "فتح",
+      "copyPrompt": "تم نسخ الرابط، يرجى فتحه في المتصفح",
+      "openFailed": "تعذر فتح الرابط"
     },
     "card-transaction-detail": {
       "index": "تفاصيل المعاملة"
@@ -54,6 +55,7 @@
       "improve": "إكمال الملف الشخصي"
     },
     "wallet": {
+      "global-detail": "تفاصيل الطلب",
       "index": "",
       "balance": "سجل رصيد المحفظة",
       "global-list": "سجل التحويل السريع",

+ 1 - 0
locale/cn.json

@@ -60,6 +60,7 @@
       "kyc": "KYC认证"
     },
     "wallet": {
+      "global-detail": "订单详情",
       "index": "",
       "balance": "钱包余额记录",
       "global-list": "速汇记录",

+ 1 - 0
locale/de.json

@@ -55,6 +55,7 @@
       "improve": "Profil vervollständigen"
     },
     "wallet": {
+      "global-detail": "Bestelldetails",
       "index": "",
       "balance": "Wallet-Guthabenverlauf",
       "global-list": "Schnellüberweisungsverlauf",

+ 1 - 0
locale/en.json

@@ -59,6 +59,7 @@
       "improve": "Complete Profile"
     },
     "wallet": {
+      "global-detail": "Order Details",
       "index": "",
       "balance": "Wallet Balance Record",
       "global-list": "Fast Transfer Record",

+ 1 - 0
locale/es.json

@@ -55,6 +55,7 @@
       "improve": "Completar Perfil"
     },
     "wallet": {
+      "global-detail": "Detalles del Pedido",
       "index": "",
       "balance": "Registro de saldo",
       "global-list": "Registro de transferencias",

+ 1 - 0
locale/fa.json

@@ -55,6 +55,7 @@
       "improve": "تکمیل پروفایل"
     },
     "wallet": {
+      "global-detail": "جزئیات سفارش",
       "index": "",
       "balance": "سوابق موجودی",
       "global-list": "سوابق حواله",

+ 1 - 0
locale/id.json

@@ -55,6 +55,7 @@
       "improve": "Lengkapi Profil"
     },
     "wallet": {
+      "global-detail": "Detail Pesanan",
       "index": "",
       "balance": "Riwayat saldo",
       "global-list": "Riwayat transfer",

+ 1 - 0
locale/ko.json

@@ -55,6 +55,7 @@
       "improve": "프로필 완성"
     },
     "wallet": {
+      "global-detail": "주문 세부 정보",
       "index": "",
       "balance": "잔액 기록",
       "global-list": "송금 기록",

+ 1 - 0
locale/ms.json

@@ -55,6 +55,7 @@
       "improve": "Lengkapkan Profil"
     },
     "wallet": {
+      "global-detail": "Butiran Pesanan",
       "index": "",
       "balance": "Rekod baki dompet",
       "global-list": "Rekod pemindahan",

+ 1 - 0
locale/pt.json

@@ -55,6 +55,7 @@
       "improve": "Completar Perfil"
     },
     "wallet": {
+      "global-detail": "Detalhes do Pedido",
       "index": "",
       "balance": "Registros de saldo",
       "global-list": "Registros de remessa",

+ 1 - 0
locale/th.json

@@ -55,6 +55,7 @@
       "improve": "เติมเต็มโปรไฟล์"
     },
     "wallet": {
+      "global-detail": "รายละเอียดคำสั่งซื้อ",
       "index": "",
       "balance": "ประวัติยอดเงิน",
       "global-list": "ประวัติการโอน",

+ 1 - 0
locale/tr.json

@@ -55,6 +55,7 @@
       "improve": "Profili Tamamla"
     },
     "wallet": {
+      "global-detail": "Sipariş Detayları",
       "index": "",
       "balance": "Bakiye kayıtları",
       "global-list": "Havale kayıtları",

+ 1 - 0
locale/vn.json

@@ -55,6 +55,7 @@
       "improve": "Hoàn thiện hồ sơ"
     },
     "wallet": {
+      "global-detail": "Chi tiết đơn hàng",
       "index": "",
       "balance": "Lịch sử số dư",
       "global-list": "Lịch sử chuyển tiền",

+ 1 - 0
locale/zhHant.json

@@ -55,6 +55,7 @@
       "improve": "完善資訊"
     },
     "wallet": {
+      "global-detail": "訂單詳情",
       "index": "",
       "balance": "錢包餘額紀錄",
       "global-list": "速匯紀錄",

+ 7 - 0
pages.json

@@ -122,6 +122,13 @@
 				"navigationStyle": "custom"
 			}
 		},
+		{
+			"path": "pages/wallet/global-detail",
+			"style": {
+				"navigationBarTitleText": "",
+				"navigationStyle": "custom"
+			}
+		},
 		{
 			"path": "pages/wallet/balance",
 			"style": {

+ 12 - 29
pages/wallet/components/GlobalList.vue

@@ -13,7 +13,7 @@
 
                         <view class="record-info">
                             <view class="info-header">
-                                <text class="record-type">{{ t('global.title1')}}</text>
+                                <text class="record-type">{{ t('global.title1') }}</text>
                                 <view :class="['status-badge', getStatusBadgeClass(record.status)]">
                                     <cwg-icon class="icons" :name="getStatusIcon(record.status)" :size="12"
                                         :color="getStatusColor(record.status)" />
@@ -22,8 +22,10 @@
                                     </text>
                                 </view>
                             </view>
-                            <text class="record-detail" v-if="record.deductionAccountType == 1">{{ record.cardNumber || '--' }}</text>
-                            <text class="record-detail" v-if="record.deductionAccountType == 2">{{ t('global.GlobalOrder.bagBal') }}</text>
+                            <text class="record-detail" v-if="record.deductionAccountType == 1">{{ record.cardNumber ||
+                                '--' }}</text>
+                            <text class="record-detail" v-if="record.deductionAccountType == 2">{{
+                                t('global.GlobalOrder.bagBal') }}</text>
                         </view>
                     </view>
 
@@ -59,6 +61,8 @@ import dayjs from 'dayjs';
 import { useI18n } from 'vue-i18n';
 import { showToast } from '@/utils/toast';
 import { ucardApi, TransactionInfo } from '@/api/ucard';
+import useRouter from "@/hooks/useRouter";
+const router = useRouter();
 import { transactionStatusMap, WITHDRAW_TYPE_MAP } from '@/utils/dataMap';
 import useCardStore from '@/stores/use-card-store';
 
@@ -250,32 +254,11 @@ const fetchRecords = async (isLoadMore = false) => {
 };
 
 const goToDeductionDetail = (record: RecordItem) => {
-    const amount = Number(record.amount || 0);
-    const fee = Number(record.fee || 0);
-    const normalizedStatus = normalizeStatus(record.status);
-
-    const detailPayload = {
-        category: 'deduction' as const,
-        type: getDeductionTypeText(record.type || record.typeStr),
-        amount,
-        fee,
-        actualAmount: amount - fee,
-        currency: record.currency || 'USD',
-        orderStatus: normalizedStatus,
-        statusMessage: getStatusText(record.status),
-        createTime: formatDateTime(record.transactionTime),
-        completeTime: '',
-        merchant: '',
-        bankCard: '',
-        bankCard: record.cardNumber,
-        remark: record.remark || record.reason || '',
-        approvalSteps: [] as any[]
-    };
-
-
-    cardStore.saveOrderDetail(detailPayload);
-    uni.navigateTo({
-        url: '/pages/recharge-record/detail'
+    console.log(record, 1212);
+
+    router.replace({
+        path: '/pages/wallet/global-detail',
+        query: { id: record.id }
     });
 };
 

+ 805 - 0
pages/wallet/global-detail.vue

@@ -0,0 +1,805 @@
+<template>
+  <cwg-page-wrapper>
+    <view class="order-detail-page">
+
+      <!-- Content -->
+      <view class="content">
+        <!-- Status Card -->
+        <!-- <view class="status-card">
+          <view class="status-icon-wrapper">
+            <view :class="['status-icon', `status-icon-${orderDetail.orderStatus}`]">
+              <uni-icons :type="getOrderStatusIcon(orderDetail.orderStatus)" size="40"
+                :color="getOrderStatusColor(orderDetail.orderStatus)" />
+            </view>
+          </view>
+          <text class="status-title">{{ getOrderStatusText(orderDetail.orderStatus) }}</text>
+          <text class="status-subtitle">{{ orderDetail.statusMessage }}</text>
+        </view> -->
+        <!-- Amount Info -->
+        <view class="section-card">
+          <view class="section-header">
+            <uni-icons type="wallet" size="18" color="#2563eb" />
+            <text class="section-title">{{ t('card.Form.f37') }}</text>
+          </view>
+
+          <view class="info-list">
+            <view class="info-row" v-for="(item, index) in list.common" :key="index">
+              <text class="info-label">{{ item.name }}</text>
+              <text class="info-value">{{ item.value }}</text>
+            </view>
+            <view class="info-row">
+              <text class="info-label">{{ t('card.Form.f37') }}</text>
+              <text class="info-value amount-highlight">
+                {{ detailData.deductionAmount || '0' }}
+                <text class="info-valuecurrency">USD</text>
+              </text>
+            </view>
+
+            <view class="info-row">
+              <text class="info-label">{{ t('card.Form.f30') }}</text>
+              <text class="info-value">
+                {{ detailData.deductionFee || '0' }}
+                <text class="currency">USD</text>
+              </text>
+            </view>
+
+            <!-- <view class="divider"></view>
+
+            <view class="info-row">
+              <text class="info-label total-label">{{ t('card.Form.f55') }}</text>
+              <text class="info-value total-value">
+                {{ detailData.actualAmount.toFixed(2) }} <text class="currency">{{ orderDetail.currency || 'USD'
+                  }}</text>
+              </text>
+            </view> -->
+          </view>
+        </view>
+
+        <!-- Order Info -->
+        <view class="section-card">
+          <view class="section-header">
+            <uni-icons type="list" size="18" color="#2563eb" />
+            <text class="section-title">{{ getGroupTitle('sender') }}</text>
+          </view>
+
+          <view class="info-list">
+            <!-- <view class="info-row" v-if="orderDetail.orderNo">
+              <text class="info-label">{{ t('card.Form.f35') }}</text>
+              <view class="info-value-wrapper">
+                <text class="info-value">{{ orderDetail.orderNo }}</text>
+                <cwg-icon name="copy" :size="14" color="#9ca3af" @click.stop="copyOrderNo" />
+              </view>
+            </view> -->
+
+            <view class="info-row" v-for="(item, index) in list.sender" :key="index">
+              <text class="info-label">{{ item.name }}</text>
+              <text class="info-value">{{ item.value }}</text>
+            </view>
+          </view>
+        </view>
+        <view class="section-card">
+          <view class="section-header">
+            <uni-icons type="list" size="18" color="#2563eb" />
+            <text class="section-title">{{ getGroupTitle('receiver') }}</text>
+          </view>
+
+          <view class="info-list">
+            <!-- <view class="info-row" v-if="orderDetail.orderNo">
+              <text class="info-label">{{ t('card.Form.f35') }}</text>
+              <view class="info-value-wrapper">
+                <text class="info-value">{{ orderDetail.orderNo }}</text>
+                <cwg-icon name="copy" :size="14" color="#9ca3af" @click.stop="copyOrderNo" />
+              </view>
+            </view> -->
+
+            <view class="info-row" v-for="(item, index) in list.receiver" :key="index">
+              <text class="info-label">{{ item.name }}</text>
+              <text class="info-value">{{ item.value }}</text>
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+  </cwg-page-wrapper>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, nextTick, computed } from 'vue'
+import { onLoad, onUnload } from '@dcloudio/uni-app';
+import { useI18n } from 'vue-i18n';
+import useCardStore from '@/stores/use-card-store';
+import { ucardApi } from "@/api/ucard";
+
+type OrderStatus = 'success' | 'processing' | 'failed' | 'cancelled';
+type ApprovalStatus = 'completed' | 'current' | 'pending';
+
+interface ApprovalStep {
+  title: string;
+  status: ApprovalStatus;
+  operator?: string;
+  time?: string;
+  remark?: string;
+}
+
+interface OrderDetail {
+  category?: 'recharge' | 'transaction' | 'deduction';
+  orderNo: string;
+  type: string;
+  amount: number;
+  fee: number;
+  actualAmount: number;
+  currency?: string;
+  orderStatus: OrderStatus;
+  statusMessage: string;
+  createTime: string;
+  completeTime?: string;
+  merchant?: string;
+  bankCard?: string;
+  remark?: string;
+  approvalSteps: ApprovalStep[];
+}
+
+// 订单详情数据(默认占位,进入页面后会用缓存覆盖)
+const orderDetail = reactive<OrderDetail>({});
+
+const { t } = useI18n();
+const cardStore = useCardStore();
+
+const getGroupTitle = (type) => {
+  const map = {
+    common: "global.GlobalOrder.common",
+    receiver: "global.GlobalOrder.receiver",
+    sender: "global.GlobalOrder.sender",
+    other: "global.GlobalOrder.other",
+    submitRfi: "global.GlobalOrder.submitRfi",
+  };
+  return t(map[type] || type);
+}
+
+// 获取订单状态图标
+const getOrderStatusIcon = (status: OrderStatus): string => {
+  switch (status) {
+    case 'success':
+      return 'checkmarkempty';
+    case 'processing':
+      return 'loop';
+    case 'failed':
+      return 'closeempty';
+    case 'cancelled':
+      return 'closeempty';
+    default:
+      return 'info';
+  }
+};
+
+// 获取订单状态颜色
+const getOrderStatusColor = (status: OrderStatus): string => {
+  switch (status) {
+    case 'success':
+      return '#22c55e';
+    case 'processing':
+      return '#eab308';
+    case 'failed':
+      return '#ef4444';
+    case 'cancelled':
+      return '#9ca3af';
+    default:
+      return '#9ca3af';
+  }
+};
+
+// 获取订单状态文本
+const getOrderStatusText = (status: OrderStatus): string => {
+  switch (status) {
+    case 'success':
+      return t('card.Status.t1'); // 成功
+    case 'processing':
+      return t('card.Status.t3'); // 处理中
+    case 'failed':
+      return t('card.Status.t2'); // 失败
+    case 'cancelled':
+      return t('card.Status.t5'); // 待处理 / 已取消,复用状态文案
+    default:
+      return t('card.Status.t5');
+  }
+};
+// 复制订单号
+const copyOrderNo = () => {
+  uni.setClipboardData({
+    data: orderDetail.orderNo,
+    success: () => {
+      uni.showToast({
+        title: '订单号已复制',
+        icon: 'success'
+      });
+    }
+  });
+};
+
+// 取消订单
+const cancelOrder = () => {
+  uni.showModal({
+    title: '确认取消',
+    content: '确定要取消此订单吗?',
+    success: (res) => {
+      if (res.confirm) {
+        uni.showToast({
+          title: '订单已取消',
+          icon: 'success'
+        });
+      }
+    }
+  });
+};
+
+// 申诉订单
+const appealOrder = () => {
+  uni.showToast({
+    title: '提交申诉',
+    icon: 'none'
+  });
+};
+
+
+
+const isView = ref(false)
+
+const detailData = ref<any>({})
+const list = ref<Record<string, any[]>>({})
+
+const complianceItems = ref<any[]>([])
+const globalForm = reactive<Record<string, any>>({})
+
+const complianceStatus = ref(false)
+
+// 外部参数
+const type = ref<'1' | '2'>('1')
+async function getOrderDetail(id: string | number) {
+  try {
+    isView.value = false
+
+    const res = await ucardApi.globalOrdersDetail({ id })
+
+    if (res.code !== 200) {
+      // ElMessage.error(res.msg)
+      return
+    }
+
+    detailData.value = res.data
+    console.log(21312312, detailData.value, [...detailData.value.fieldDtos]);
+
+
+    /** 1️⃣ 处理 fieldDtos */
+    /** 1️⃣ 处理 fieldDtos */
+    /** 1️⃣ 处理 fieldDtos */
+    let a = []
+    let listData = [...detailData.value.fieldDtos]
+      .sort((a, b) => a.sorting - b.sorting)
+    listData.map((item) => {
+      const key = Object.keys(detailData.value).find(
+        (k) => k.toLowerCase() === item.fieldName.toLowerCase()
+      )
+
+      // const { t } = useI18n()
+      let name = item.fieldName // 默认使用字段名
+
+      try {
+        // 检查国际化键是否存在
+        const i18nKey = `global.fieldName.${item.fieldName}.fieldTitle`
+        name = t(i18nKey)
+        // 如果国际化返回的值和键相同,说明未找到翻译,使用默认值
+        if (name === i18nKey) {
+          name = item.fieldName
+        }
+      } catch (error) {
+        console.error('国际化处理错误:', error)
+        name = item.fieldName
+      }
+
+      let value = key ? detailData.value[key] : item.fixedValue
+
+      // 特殊处理 select 类型字段
+      if (
+        item.fieldType === 'select' &&
+        key &&
+        !['transferType', 'payoutMethod'].includes(key)
+      ) {
+        value = detailData.value[key + 'Value'] || value
+      }
+      // 确定字段类型,提供默认值
+      let type = item.fieldUserType || 'other'
+      let b = {
+        name,
+        value,
+        type,
+        fieldName: item.fieldName,
+        fieldType: item.fieldType,
+        options: item.options || null
+      }
+      if (item.fieldName === 'transferAmount') b.value = value + ' ' + detailData.value.payoutCurrency
+      a.push(b)
+      return {
+        name,
+        value,
+        type,
+        fieldName: item.fieldName,
+        fieldType: item.fieldType,
+        options: item.options || null
+      }
+    })
+    /** 2️⃣ 分组 */
+    const groups: Record<string, any[]> = {}
+
+    a.forEach((field) => {
+
+      let type = field.type || field.fieldUserType || 'other'
+      // if (type === 'common') type = 'sender'
+      if (!groups[type]) groups[type] = []
+      groups[type].push(field)
+    })
+
+    list.value = groups
+    console.log(list.value, 22222);
+
+
+    /** 3️⃣ nextTick 后处理合规字段 */
+    await nextTick()
+
+    let items: any[] = []
+
+    if (detailData.value?.dataDtos) {
+      items = detailData.value.dataDtos.map((item) => {
+        item.fieldName = `${item.customerType}_${item.fieldName}`
+
+        if (item.status !== 'pending_check') {
+          globalForm[item.fieldName] =
+            item.fieldType === 'file'
+              ? item.rfiValueUrl
+              : item.rfiValue
+
+          return {
+            ...item,
+            disabled: true
+          }
+        }
+
+        return { ...item }
+      })
+    }
+
+    complianceItems.value = items
+
+    /** 4️⃣ 合规状态 */
+    let status = false
+
+    if (type.value === '1') {
+      status =
+        detailData.value?.complianceStatus !== 'pending_check' &&
+        detailData.value?.complianceStatus !== null
+    }
+
+    if (type.value === '2') {
+      status = true
+    }
+
+    complianceStatus.value = status
+    isView.value = true
+  } catch (error: any) {
+    console.log(error, 12121);
+
+    // ElMessage.error(error?.message || 'System Error')
+  } finally {
+  }
+}
+
+
+// 页面加载时,从 store 中读取订单详情
+onLoad((e) => {
+  console.log(e, 2313);
+
+  getOrderDetail(e.id);
+
+});
+
+// 离开页面时清空订单详情
+onUnload(() => {
+  // cardStore.clearOrderDetail();
+});
+</script>
+
+<style scoped lang="scss">
+@import "@/uni.scss";
+
+.page-wrapper {
+  padding: 0;
+}
+
+.order-detail-page {
+  background-color: #f9fafb;
+  padding-bottom: px2rpx(80);
+}
+
+/* Header */
+.header {
+  background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
+  padding: px2rpx(12) px2rpx(16);
+  padding-top: calc(px2rpx(12) + env(safe-area-inset-top));
+}
+
+.header-nav {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.back-btn {
+  width: px2rpx(40);
+  height: px2rpx(40);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.header-title {
+  color: #ffffff;
+  font-size: px2rpx(18);
+}
+
+.header-action {
+  width: px2rpx(40);
+}
+
+/* Content */
+.content {
+  padding: px2rpx(16);
+}
+
+/* Status Card */
+.status-card {
+  background-color: #ffffff;
+  border-radius: px2rpx(16);
+  padding: px2rpx(32) px2rpx(24);
+  margin-bottom: px2rpx(16);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.status-icon-wrapper {
+  margin-bottom: px2rpx(16);
+}
+
+.status-icon {
+  width: px2rpx(80);
+  height: px2rpx(80);
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.status-icon-success {
+  background-color: #f0fdf4;
+}
+
+.status-icon-processing {
+  background-color: #fefce8;
+}
+
+.status-icon-failed {
+  background-color: #fef2f2;
+}
+
+.status-icon-cancelled {
+  background-color: #f9fafb;
+}
+
+.status-title {
+  font-size: px2rpx(22);
+  color: #111827;
+  margin-bottom: px2rpx(8);
+}
+
+.status-subtitle {
+  font-size: px2rpx(14);
+  color: #6b7280;
+  text-align: center;
+}
+
+/* Section Card */
+.section-card {
+  background-color: #ffffff;
+  border-radius: px2rpx(12);
+  padding: px2rpx(16);
+  margin-bottom: px2rpx(16);
+}
+
+.section-header {
+  display: flex;
+  align-items: center;
+  gap: px2rpx(8);
+  margin-bottom: px2rpx(16);
+}
+
+.section-title {
+  font-size: px2rpx(16);
+  color: #111827;
+}
+
+/* Approval Timeline */
+.approval-timeline {
+  display: flex;
+  flex-direction: column;
+}
+
+.timeline-item {
+  display: flex;
+  gap: px2rpx(12);
+}
+
+.timeline-left {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  flex-shrink: 0;
+}
+
+.timeline-dot {
+  width: px2rpx(24);
+  height: px2rpx(24);
+  border-radius: 50%;
+  background-color: #f3f4f6;
+  border: 2px solid #e5e7eb;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+}
+
+.timeline-dot-active {
+  background-color: #22c55e;
+  border-color: #22c55e;
+}
+
+.timeline-dot-current {
+  background-color: #eab308;
+  border-color: #eab308;
+  animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+
+  0%,
+  100% {
+    opacity: 1;
+  }
+
+  50% {
+    opacity: 0.7;
+  }
+}
+
+.timeline-line {
+  width: px2rpx(2);
+  flex: 1;
+  background-color: #e5e7eb;
+  margin: px2rpx(4) 0;
+}
+
+.timeline-right {
+  flex: 1;
+  padding-bottom: px2rpx(24);
+}
+
+.timeline-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: px2rpx(6);
+}
+
+.timeline-title {
+  font-size: px2rpx(15);
+  color: #111827;
+}
+
+.timeline-status {
+  display: flex;
+  align-items: center;
+  gap: px2rpx(4);
+  padding: px2rpx(2) px2rpx(8);
+  border-radius: px2rpx(12);
+}
+
+.timeline-status.completed {
+  background-color: #f0fdf4;
+}
+
+.timeline-status.current {
+  background-color: #fefce8;
+}
+
+.timeline-status.pending {
+  background-color: #f9fafb;
+}
+
+.timeline-status-text {
+  font-size: px2rpx(12);
+}
+
+.timeline-status.completed .timeline-status-text {
+  color: #22c55e;
+}
+
+.timeline-status.current .timeline-status-text {
+  color: #eab308;
+}
+
+.timeline-status.pending .timeline-status-text {
+  color: #9ca3af;
+}
+
+.timeline-operator {
+  font-size: px2rpx(13);
+  color: #6b7280;
+  display: block;
+  margin-bottom: px2rpx(4);
+}
+
+.timeline-time {
+  font-size: px2rpx(12);
+  color: #9ca3af;
+  display: block;
+  margin-bottom: px2rpx(4);
+}
+
+.timeline-remark {
+  font-size: px2rpx(13);
+  color: #6b7280;
+  display: block;
+  margin-top: px2rpx(6);
+  padding: px2rpx(8);
+  background-color: #f9fafb;
+  border-radius: px2rpx(6);
+}
+
+/* Info List */
+.info-list {
+  display: flex;
+  flex-direction: column;
+  gap: px2rpx(12);
+}
+
+.info-row {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: px2rpx(12);
+  padding: px2rpx(4) 0;
+}
+
+.info-row.vertical {
+  flex-direction: column;
+  align-items: flex-start;
+}
+
+.info-label {
+  font-size: px2rpx(14);
+  color: #6b7280;
+  flex-shrink: 0;
+}
+
+.info-value {
+  font-size: px2rpx(14);
+  color: #111827;
+  text-align: right;
+  word-break: break-all;
+}
+
+.info-value-wrapper {
+  display: flex;
+  align-items: center;
+  gap: px2rpx(8);
+  flex: 1;
+  justify-content: flex-end;
+}
+
+.amount-highlight {
+  font-size: px2rpx(20);
+  color: #2563eb;
+}
+
+.total-label {
+  font-size: px2rpx(15);
+  color: #111827;
+}
+
+.total-value {
+  font-size: px2rpx(18);
+  color: #ef4444;
+}
+
+.remark-text {
+  text-align: left;
+  color: #6b7280;
+  line-height: 1.6;
+}
+
+.divider {
+  height: px2rpx(1);
+  background-color: #f3f4f6;
+  margin: px2rpx(4) 0;
+}
+
+/* Service Card */
+.service-card {
+  background-color: #ffffff;
+  border-radius: px2rpx(12);
+  padding: px2rpx(16);
+  display: flex;
+  align-items: center;
+  gap: px2rpx(12);
+  margin-bottom: px2rpx(16);
+}
+
+.service-text {
+  flex: 1;
+  font-size: px2rpx(15);
+  color: #111827;
+}
+
+/* Bottom Actions */
+.bottom-actions {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background-color: #ffffff;
+  border-top: 1px solid #e5e7eb;
+  padding: px2rpx(12) px2rpx(16);
+  padding-bottom: calc(px2rpx(12) + env(safe-area-inset-bottom));
+  display: flex;
+  gap: px2rpx(12);
+}
+
+.action-btn {
+  flex: 1;
+  height: px2rpx(44);
+  border-radius: px2rpx(8);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.cancel-btn {
+  background-color: #f3f4f6;
+}
+
+.cancel-btn .btn-text {
+  color: #6b7280;
+}
+
+.appeal-btn {
+  background-color: #2563eb;
+}
+
+.appeal-btn .btn-text {
+  color: #ffffff;
+}
+
+.delete-btn {
+  background-color: #f3f4f6;
+}
+
+.delete-btn .btn-text {
+  color: #ef4444;
+}
+
+.btn-text {
+  font-size: px2rpx(15);
+}
+
+.currency {
+  font-size: px2rpx(12);
+}
+</style>

Fichier diff supprimé car celui-ci est trop grand
+ 22 - 0
static/svg-icons-lib.js


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff