li.shaoyi 2 meses atrás
pai
commit
1457435962
44 arquivos alterados com 1668 adições e 457 exclusões
  1. 3 0
      src/constants/funcode.ts
  2. 10 38
      src/packages/digital/assets/themes/default/default.less
  3. 102 1
      src/packages/digital/assets/themes/global/global.less
  4. 5 0
      src/packages/digital/components/iconbar/index.less
  5. 47 0
      src/packages/digital/components/iconbar/index.vue
  6. 52 2
      src/packages/digital/router/index.ts
  7. 0 25
      src/packages/digital/views/contract/components/account/index.less
  8. 33 13
      src/packages/digital/views/contract/components/account/index.vue
  9. 38 40
      src/packages/digital/views/contract/components/order/index.vue
  10. 55 57
      src/packages/digital/views/contract/components/position/index.vue
  11. 8 0
      src/packages/digital/views/contract/components/statement/index.vue
  12. 70 0
      src/packages/digital/views/contract/components/trade/index.vue
  13. 81 0
      src/packages/digital/views/contract/detail/index.vue
  14. 1 8
      src/packages/digital/views/contract/goods/detail/index.less
  15. 40 29
      src/packages/digital/views/contract/goods/detail/index.vue
  16. 2 2
      src/packages/digital/views/home/index.vue
  17. 0 176
      src/packages/digital/views/mine/index.vue
  18. 49 0
      src/packages/digital/views/setting/index.vue
  19. 1 1
      src/packages/digital/views/spot/components/account/index.less
  20. 65 0
      src/packages/digital/views/spot/components/account/index.vue
  21. 38 0
      src/packages/digital/views/spot/components/order/cancel/index.vue
  22. 93 0
      src/packages/digital/views/spot/components/order/index.vue
  23. 8 0
      src/packages/digital/views/spot/components/statement/index.vue
  24. 61 0
      src/packages/digital/views/spot/components/trade/index.vue
  25. 83 0
      src/packages/digital/views/spot/detail/index.vue
  26. 20 0
      src/packages/digital/views/spot/goods/chart/index.vue
  27. 2 0
      src/packages/digital/views/spot/goods/detail/index.less
  28. 113 0
      src/packages/digital/views/spot/goods/detail/index.vue
  29. 59 0
      src/packages/digital/views/spot/goods/list/index.less
  30. 97 0
      src/packages/digital/views/spot/goods/list/index.vue
  31. 6 0
      src/packages/digital/views/user/login/index.less
  32. 53 0
      src/packages/digital/views/wallet/components/contract/index.vue
  33. 53 0
      src/packages/digital/views/wallet/components/record/index.vue
  34. 37 0
      src/packages/digital/views/wallet/components/spot/index.less
  35. 48 0
      src/packages/digital/views/wallet/components/spot/index.vue
  36. 11 0
      src/packages/digital/views/wallet/deposit/index.vue
  37. 33 49
      src/packages/digital/views/wallet/index.vue
  38. 20 14
      src/packages/digital/views/wallet/transfer/index.vue
  39. 11 0
      src/packages/digital/views/wallet/withdraw/index.vue
  40. 17 0
      src/packages/mobile/components/base/datepicker/index.less
  41. 63 0
      src/packages/mobile/components/base/datepicker/index.vue
  42. 2 2
      src/packages/mobile/views/bank/sign/components/edit/Index.vue
  43. 14 0
      src/services/api/trade/index.ts
  44. 64 0
      src/types/proto/digital.d.ts

+ 3 - 0
src/constants/funcode.ts

@@ -162,4 +162,7 @@ export enum FunCode {
 
     DigitalAccountTransferApplyReq = 3014657, // 数字账户转入转出申请请求
     DigitalAccountTransferApplyRsp = 3014657, // 数字账户转入转出申请应答
+
+    DigitalOrderReq = 196771, // 数字交易委托请求
+    DigitalOrderRsp = 196772, // 数字交易委托应答
 } 

+ 10 - 38
src/packages/digital/assets/themes/default/default.less

@@ -11,8 +11,8 @@
     --font-x-small: 10px;
 
     /* 颜色规范 */
-    --color-default: #384048;
-    --color-primary: #409EFF;
+    --color-default: #fff;
+    --color-primary: #e55b24;
     --color-secondary: #04c786;
     --color-info: #999;
     --color-border: #eee;
@@ -34,47 +34,19 @@
     --content-inset: 12px;
 
     /* Vant-Button */
-    --van-button-border-width: 0;
-    --van-button-primary-background: #1e78b9;
-    --van-button-danger-background: #d82d42;
+    --van-button-default-background: #37393e;
+    --van-button-default-border-color: var(--van-button-default-background);
+    --van-button-primary-color: #000;
+    --van-button-primary-background: #fff;
 
     /* Vant-Checkbox */
     --van-checkbox-checked-icon-color: #DD364A !important;
 
     /* Vant-Tabs */
-    --van-tabs-bottom-bar-color: #DD364A;
-
-    --van-dialog-confirm-button-text-color: #DD364A;
-}
-
-.app-tabs {
-    .tabs {
-        flex-wrap: wrap;
-
-        &-item {
-            display: flex;
-            justify-content: center;
-            align-items: center;
-            color: #626675;
-            cursor: pointer;
-            border-radius: 2px;
-            background-color: #f0f0f1;
-            padding: 4px 8px;
-
-            &:not(:first-child) {
-                margin-left: 5px;
-            }
-
-            &.is-active {
-                color: #222;
-                font-weight: bold;
-            }
-        }
-    }
+    --van-tabs-bottom-bar-color: var(--color-primary);
 }
 
-.van-cell {
-    &.nowrap &__title {
-        flex: none;
-    }
+.van-dialog {
+    --van-dialog-confirm-button-text-color: var(--color-primary);
+    --van-button-default-background: #1c1c1e;
 }

+ 102 - 1
src/packages/digital/assets/themes/global/global.less

@@ -4,6 +4,107 @@
     }
 
     &-block {
-        //padding: 20px;
+        &--inset {
+            padding: var(--van-padding-md);
+        }
+    }
+
+    &-block+&-block {
+        padding-top: 0;
+    }
+}
+
+.g-price {
+    &-normal {
+        color: #fff;
+    }
+
+    &-up {
+        color: var(--color-up);
+    }
+
+    &-down {
+        color: var(--color-down);
+    }
+}
+
+.g-form {
+    &__container {
+        display: flex;
+        flex-direction: column;
+        gap: 12px;
+
+        .van-field {
+            &__right-icon {
+                align-self: normal;
+            }
+
+            .van-stepper {
+                display: flex;
+                align-items: center;
+                width: 100%;
+
+                &__input {
+                    flex: 1;
+                }
+            }
+        }
+    }
+}
+
+.g-list-table {
+    width: 100%;
+}
+
+.g-detail-table {
+    table {
+        width: 100%;
+        border-bottom: 1px solid #171f2d;
+        padding: 10px;
+
+        td,
+        th {
+            line-height: 1.5;
+            text-align: left;
+            padding: 4px;
+
+            &:last-child:not(:first-child) {
+                text-align: right;
+            }
+
+            >span {
+                display: block;
+            }
+        }
+
+        tfoot {
+            td {
+                text-align: right;
+
+                button {
+                    min-width: 60px;
+
+                    &+button {
+                        margin-left: 10px;
+                    }
+                }
+            }
+        }
+
+        .text-small {
+            font-size: 12px;
+            font-weight: normal;
+            color: #666;
+        }
+    }
+
+    &--inset {
+        padding: var(--van-padding-md);
+
+        table {
+            background-color: #1c1c1e;
+            border-bottom-width: 0;
+            border-radius: 8px;
+        }
     }
 }

+ 5 - 0
src/packages/digital/components/iconbar/index.less

@@ -0,0 +1,5 @@
+.app-iconbar {
+    &--inset {
+        padding: var(--van-padding-md);
+    }
+}

+ 47 - 0
src/packages/digital/components/iconbar/index.vue

@@ -0,0 +1,47 @@
+<template>
+    <div :class="className">
+        <Grid :border="false" :column-num="filteredIcons.length" v-if="filteredIcons.length">
+            <template v-for="(item, index) in filteredIcons" :key="index">
+                <GridItem :icon="item.icon" :text="item.text" :to="item.to" />
+            </template>
+        </Grid>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { shallowReactive, PropType, computed } from 'vue'
+import { Grid, GridItem } from 'vant'
+
+const props = defineProps({
+    query: {
+        type: Object
+    },
+    routes: {
+        type: Array as PropType<string[]>,
+        default: () => ([])
+    },
+    inset: {
+        type: Boolean,
+        default: false
+    }
+})
+
+const className = {
+    'app-iconbar': true,
+    'app-iconbar--inset': props.inset
+}
+
+const icons = shallowReactive([
+    { icon: 'pending-payment', text: '充值', to: { name: 'wallet-deposit' } },
+    { icon: 'paid', text: '提现', to: { name: 'wallet-withdraw' } },
+    { icon: 'peer-pay', text: '划转', to: { name: 'wallet-transfer' } },
+    { icon: 'chart-trending-o', text: '交易', to: { name: 'spot-goods-detail' } },
+    { icon: 'setting-o', text: '设置', to: { name: 'setting' } },
+])
+
+const filteredIcons = computed(() => icons.filter((e) => props.routes.includes(e.to.name)))
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 52 - 2
src/packages/digital/router/index.ts

@@ -61,6 +61,11 @@ const routes: Array<RouteRecordRaw> = [
             },
           },
           {
+            path: 'spot',
+            name: 'home-spot',
+            component: () => import('../views/spot/goods/list/index.vue'),
+          },
+          {
             path: 'contract',
             name: 'home-contract',
             component: () => import('../views/contract/goods/list/index.vue'),
@@ -70,16 +75,41 @@ const routes: Array<RouteRecordRaw> = [
             name: 'home-wallet',
             component: () => import('../views/wallet/index.vue'),
           },
-          ...homeRoutes
         ]
       }
     ],
   },
   {
+    path: '/spot',
+    component: Page,
+    children: [
+      {
+        path: 'detail',
+        name: 'spot-detail',
+        component: () => import('../views/spot/detail/index.vue'),
+      },
+      {
+        path: 'goods/detail',
+        name: 'spot-goods-detail',
+        component: () => import('../views/spot/goods/detail/index.vue'),
+      },
+      {
+        path: 'goods/chart',
+        name: 'spot-goods-chart',
+        component: () => import('../views/spot/goods/chart/index.vue'),
+      },
+    ]
+  },
+  {
     path: '/contract',
     component: Page,
     children: [
       {
+        path: 'detail',
+        name: 'contract-detail',
+        component: () => import('../views/contract/detail/index.vue'),
+      },
+      {
         path: 'goods/detail',
         name: 'contract-goods-detail',
         component: () => import('../views/contract/goods/detail/index.vue'),
@@ -100,6 +130,27 @@ const routes: Array<RouteRecordRaw> = [
         name: 'wallet-transfer',
         component: () => import('../views/wallet/transfer/index.vue'),
       },
+      {
+        path: 'deposit',
+        name: 'wallet-deposit',
+        component: () => import('../views/wallet/deposit/index.vue'),
+      },
+      {
+        path: 'deposit',
+        name: 'wallet-withdraw',
+        component: () => import('../views/wallet/withdraw/index.vue'),
+      },
+    ]
+  },
+  {
+    path: '/setting',
+    component: Page,
+    children: [
+      {
+        path: '',
+        name: 'setting',
+        component: () => import('../views/setting/index.vue'),
+      }
     ]
   },
   {
@@ -357,7 +408,6 @@ const routes: Array<RouteRecordRaw> = [
       },
     ]
   },
-  ...pageRoutes
 ]
 
 const router = animateRouter.create({

+ 0 - 25
src/packages/digital/views/contract/components/account/index.less

@@ -1,25 +0,0 @@
-.contract-account {
-    .account-table {
-        width: 100%;
-        border-bottom: 1px solid #171f2d;
-        padding: 10px;
-
-        td {
-            line-height: 1.5;
-            padding: 8px;
-
-            &:last-child {
-                text-align: right;
-            }
-
-            span {
-                display: block;
-            }
-
-            .text-small {
-                font-size: 12px;
-                color: #666;
-            }
-        }
-    }
-}

+ 33 - 13
src/packages/digital/views/contract/components/account/index.vue

@@ -1,15 +1,14 @@
 <template>
-    <div class="contract-account">
-        <table class="account-table" cellspacing="0" cellpadding="0">
-            <tbody>
+    <div class="g-detail-table">
+        <table cellspacing="0" cellpadding="0">
+            <thead>
                 <tr>
-                    <td colspan="2">
+                    <th colspan="3">
                         <span>资金({{ currentAccount.accountid }})</span>
-                    </td>
-                    <td>
-                        <Icon name="arrow" />
-                    </td>
+                    </th>
                 </tr>
+            </thead>
+            <tbody>
                 <tr>
                     <td colspan="2">
                         <span class="text-small">账户权益(USDT)</span>
@@ -35,19 +34,40 @@
                     </td>
                 </tr>
             </tbody>
+            <tfoot>
+                <tr>
+                    <td colspan="3">
+                        <Button size="small" @click="navigateTo('wallet-transfer')">划转</Button>
+                    </td>
+                </tr>
+            </tfoot>
         </table>
     </div>
 </template>
 
 <script lang="ts" setup>
-import { Icon } from 'vant'
+import { Button } from 'vant'
+import { useNavigation } from '@mobile/router/navigation'
 import { useAccountStore } from '@/stores'
 
+const props = defineProps({
+    accountId: {
+        type: Number,
+        required: true
+    }
+})
+
 const accountStore = useAccountStore()
 const { currentAccount } = accountStore.$toRefs()
 
-</script>
+const { router } = useNavigation()
 
-<style lang="less">
-@import './index.less';
-</style>
+const navigateTo = (name: string) => {
+    router.push({
+        name,
+        query: {
+            id: props.accountId
+        }
+    })
+}
+</script>

+ 38 - 40
src/packages/digital/views/contract/components/order/index.vue

@@ -1,46 +1,44 @@
 <template>
-    <div class="contract-order">
-        <table class="card" cellspacing="0" cellpadding="0" border="1">
+    <div class="g-detail-table">
+        <table cellspacing="0" cellpadding="0" v-for="(item, index) in dataList" :key="index">
             <tbody>
-                <template v-for="(item, index) in dataList" :key="index">
-                    <tr>
-                        <th>
-                            <span>{{ item.goodscode }}/ {{ item.goodsname }}</span>
-                            <time>{{ formatDate(item.ordertime) }}</time>
-                        </th>
-                        <th>
-                            <span>{{ getBuyOrSellName(item.buyorsell) }}</span>
-                        </th>
-                    </tr>
-                    <tr>
-                        <td>
-                            <span>委托单号</span>
-                            <span>{{ item.orderid }}</span>
-                        </td>
-                        <td>
-                            <span>委托状态</span>
-                            <span>{{ getWRTradeOrderStatusName(item.orderstatus) }}</span>
-                        </td>
-                    </tr>
-                    <tr>
-                        <td>
-                            <span>委托价格(USDT)</span>
-                            <span>{{ formatDecimal(item.orderprice, item.decimalplace) }}</span>
-                        </td>
-                        <td>
-                            <span>委托数量({{ item.goodscode }})</span>
-                            <span>{{ item.orderqty }}</span>
-                        </td>
-                    </tr>
-                    <tfoot>
-                        <tr>
-                            <td colspan="2">
-                                <Button type="danger" @click="cancelOrder(item)">撤销</Button>
-                            </td>
-                        </tr>
-                    </tfoot>
-                </template>
+                <tr>
+                    <th>
+                        <span>{{ item.goodscode }}/ {{ item.goodsname }}</span>
+                        <time class="text-small">{{ formatDate(item.ordertime) }}</time>
+                    </th>
+                    <th>
+                        <span>{{ getBuyOrSellName(item.buyorsell) }}</span>
+                    </th>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">委托单号</span>
+                        <span>{{ item.orderid }}</span>
+                    </td>
+                    <td>
+                        <span class="text-small">委托状态</span>
+                        <span>{{ getWRTradeOrderStatusName(item.orderstatus) }}</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">委托价格(USDT)</span>
+                        <span>{{ formatDecimal(item.orderprice, item.decimalplace) }}</span>
+                    </td>
+                    <td>
+                        <span class="text-small">委托数量({{ item.goodscode }})</span>
+                        <span>{{ item.orderqty }}</span>
+                    </td>
+                </tr>
             </tbody>
+            <tfoot>
+                <tr>
+                    <td colspan="2">
+                        <Button size="small" @click="cancelOrder(item)">撤销</Button>
+                    </td>
+                </tr>
+            </tfoot>
         </table>
         <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)"
             @closed="closeComponent" v-if="componentId" />

+ 55 - 57
src/packages/digital/views/contract/components/position/index.vue

@@ -1,67 +1,65 @@
 <!--  合约 - 商品交易 - 持仓单 -->
 <template>
-    <div class="contract-position">
-        <table class="card" cellspacing="0" cellpadding="0" border="1">
+    <div class="g-detail-table">
+        <table cellspacing="0" cellpadding="0" v-for="(item, index) in orderComputedList" :key="index">
             <tbody>
-                <template v-for="(item, index) in orderComputedList" :key="index">
-                    <tr>
-                        <th colspan="2">
-                            <span>{{ item.goodsCode }}/ {{ item.goodsName }}</span>
-                            <time>{{ formatDate(item.tHDetailEx.tradeTime) }}</time>
-                        </th>
-                        <th>
-                            <span :class="!item.buyorsell ? 'g-price-up' : 'g-price-down'">
-                                {{ getBuyOrSellName(item.tHDetailEx.buyOrSell) }}
-                            </span>
-                        </th>
-                    </tr>
-                    <tr>
-                        <td colspan="2">
-                            <span>浮动盈亏( {{ getCurrencyName(item.currencyid) }})</span>
-                            <span :class="item.closeplColor">
-                                {{ formatDecimal(item.tHDetailEx.floatPL, item.decimalPlace) }}
-                            </span>
-                        </td>
-                        <td>
-                            <span>回报率(%)</span>
-                            <span>{{ parsePercent(calReturnRate(item)) }}</span>
-                        </td>
-                    </tr>
-                    <tr>
-                        <td>
-                            <span>持仓量({{ item.goodsCode }})</span>
-                            <span>{{ item.tHDetailEx.holderQty }}</span>
-                        </td>
-                        <td>
-                            <span>保证金( {{ getCurrencyName(item.currencyid) }} )</span>
-                            <span>{{ formatAmount(calUseMargin(item)) }}</span>
-                        </td>
-                        <td>
-                            <span>风险率(%)</span>
-                            <span>{{ parsePercent(calRiskRate(item)) }}</span>
-                        </td>
-                    </tr>
-                    <tr>
-                        <td>
-                            <span>冻结量({{ item.goodsCode }})</span>
-                            <span>{{ item.tHDetailEx.freezeQty }}</span>
-                        </td>
-                        <td>
-                            <span>持仓价格( {{ getCurrencyName(item.currencyid) }})</span>
-                            <span>{{ formatDecimal(item.tHDetailEx.holderPrice, item.decimalPlace) }}</span>
-                        </td>
-                        <td>
-                            <span>持金额( {{ getCurrencyName(item.currencyid) }} )</span>
-                            <span>{{ formatAmount(item.tHDetailEx.holderAmount) }}</span>
-                        </td>
-                    </tr>
-                </template>
+                <tr>
+                    <th colspan="2">
+                        <span>{{ item.goodsCode }}/ {{ item.goodsName }}</span>
+                        <time class="text-small">{{ formatDate(item.tHDetailEx.tradeTime) }}</time>
+                    </th>
+                    <th>
+                        <span :class="!item.buyorsell ? 'g-price-up' : 'g-price-down'">
+                            {{ getBuyOrSellName(item.tHDetailEx.buyOrSell) }}
+                        </span>
+                    </th>
+                </tr>
+                <tr>
+                    <td colspan="2">
+                        <span class="text-small">浮动盈亏( {{ getCurrencyName(item.currencyid) }})</span>
+                        <span :class="item.closeplColor">
+                            {{ formatDecimal(item.tHDetailEx.floatPL, item.decimalPlace) }}
+                        </span>
+                    </td>
+                    <td>
+                        <span class="text-small">回报率(%)</span>
+                        <span>{{ parsePercent(calReturnRate(item)) }}</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">持仓量({{ item.goodsCode }})</span>
+                        <span>{{ item.tHDetailEx.holderQty }}</span>
+                    </td>
+                    <td>
+                        <span class="text-small">保证金( {{ getCurrencyName(item.currencyid) }} )</span>
+                        <span>{{ formatAmount(calUseMargin(item)) }}</span>
+                    </td>
+                    <td>
+                        <span class="text-small">风险率(%)</span>
+                        <span>{{ parsePercent(calRiskRate(item)) }}</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">冻结量({{ item.goodsCode }})</span>
+                        <span>{{ item.tHDetailEx.freezeQty }}</span>
+                    </td>
+                    <td>
+                        <span class="text-small">持仓价格( {{ getCurrencyName(item.currencyid) }})</span>
+                        <span>{{ formatDecimal(item.tHDetailEx.holderPrice, item.decimalPlace) }}</span>
+                    </td>
+                    <td>
+                        <span class="text-small">持金额( {{ getCurrencyName(item.currencyid) }} )</span>
+                        <span>{{ formatAmount(item.tHDetailEx.holderAmount) }}</span>
+                    </td>
+                </tr>
             </tbody>
             <tfoot>
                 <tr>
                     <td colspan="3">
-                        <Button type="danger" @click="closePosition()">平仓</Button>
-                        <Button type="danger" @click="closePositionAtMarket()">市价平仓</Button>
+                        <Button size="small" @click="closePosition()">平仓</Button>
+                        <Button size="small" @click="closePositionAtMarket()">市价平仓</Button>
                     </td>
                 </tr>
             </tfoot>

+ 8 - 0
src/packages/digital/views/contract/components/statement/index.vue

@@ -0,0 +1,8 @@
+<template>
+    <div>
+        流水
+    </div>
+</template>
+
+<script lang="ts" setup>
+</script>

+ 70 - 0
src/packages/digital/views/contract/components/trade/index.vue

@@ -0,0 +1,70 @@
+<template>
+    <div class="g-detail-table">
+        <table cellspacing="0" cellpadding="0">
+            <tbody>
+                <tr>
+                    <td>
+                        <app-select v-model="dateType" :options="options" />
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+        <table cellspacing="0" cellpadding="0">
+            <thead>
+                <tr>
+                    <th>
+                        <span>Gold黄金</span>
+                        <time class="text-small">2025-09-01 11:11:11</time>
+                    </th>
+                    <th>
+                        <span class="g-price-down">多开</span>
+                    </th>
+                </tr>
+            </thead>
+            <tbody>
+                <tr>
+                    <td>
+                        <span class="text-small">成交单号</span>
+                        <span>1001718728455010011</span>
+                    </td>
+                    <td>
+                        <span class="text-small">委托状态</span>
+                        <span>已成交</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">成交价格(USDT)</span>
+                        <span>3,480.88</span>
+                    </td>
+                    <td>
+                        <span class="text-small">手续费(USDT)</span>
+                        <span>100</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">成交数量(Gold)</span>
+                        <span>100</span>
+                    </td>
+                    <td>
+                        <span class="text-small">平仓盈亏(USDT)</span>
+                        <span>374.379644</span>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import AppSelect from '@mobile/components/base/select/index.vue'
+
+const dateType = shallowRef(0)
+
+const options = shallowRef([
+    { label: '当前', value: 0 },
+    { label: '历史', value: 1 }
+])
+</script>

+ 81 - 0
src/packages/digital/views/contract/detail/index.vue

@@ -0,0 +1,81 @@
+<template>
+    <app-view class="contract-detail g-form">
+        <template #header>
+            <app-navbar title="现货明细" />
+        </template>
+        <Grid :border="false" :column-num="2">
+            <GridItem icon="peer-pay" text="划转" :to="{ name: 'wallet-transfer', query: { id: accountId } }" />
+            <GridItem icon="chart-trending-o" text="交易" @click="navigateToContractDetail" />
+        </Grid>
+        <div class="g-detail-table">
+            <table cellspacing="0" cellpadding="0">
+                <tbody>
+                    <tr>
+                        <td colspan="2">
+                            <span class="text-small">账户权益(USDT)</span>
+                            <span>1000.00</span>
+                        </td>
+                        <td>
+                            <span class="text-small">浮动盈亏</span>
+                            <span>+2.87</span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <span class="text-small">可用(USDT)</span>
+                            <span>100</span>
+                        </td>
+                        <td>
+                            <span class="text-small">占用(USDT)</span>
+                            <span>34,808.80</span>
+                        </td>
+                        <td>
+                            <span class="text-small">冻结(USDT)</span>
+                            <span>97.21</span>
+                        </td>
+                    </tr>
+                </tbody>
+            </table>
+        </div>
+        <Tabs v-model:active="tabIndex">
+            <Tab title="委托">
+                <contract-order showDatePicker />
+            </Tab>
+            <Tab title="成交">
+                <contract-trade />
+            </Tab>
+            <Tab title="持仓">
+                <contract-position />
+            </Tab>
+            <Tab title="资金明细">
+                <contract-statement />
+            </Tab>
+        </Tabs>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { Tab, Tabs, Grid, GridItem } from 'vant'
+import { useNavigation } from '@mobile/router/navigation'
+import ContractOrder from '../components/order/index.vue'
+import ContractTrade from '../components/trade/index.vue'
+import ContractPosition from '../components/position/index.vue'
+import ContractStatement from '../components/statement/index.vue'
+
+const { router, getQueryStringToNumber } = useNavigation()
+
+const accountId = getQueryStringToNumber('id')
+const tabIndex = shallowRef(0)
+
+const navigateToContractDetail = () => {
+    const goodsId = accountId
+    // 多个商品弹出列表选择,单个商品直接跳转
+    router.push({
+        name: 'contract-goods-detail',
+        query: {
+            id: goodsId
+        }
+    })
+}
+</script>

+ 1 - 8
src/packages/digital/views/contract/goods/detail/index.less

@@ -1,9 +1,2 @@
-.contract-detail {
-    .card {
-        width: 100%;
-
-        span {
-            display: block;
-        }
-    }
+.contract-goods-detail {
 }

+ 40 - 29
src/packages/digital/views/contract/goods/detail/index.vue

@@ -1,43 +1,50 @@
 <template>
-    <app-view class="contract-detail">
+    <app-view class="contract-goods-detail g-layout g-form">
         <template #header>
-            <app-navbar>
-                <template #left>
-                    <span style="margin-left: 48px;">{{ quote?.goodscode }}</span>
-                </template>
-                <div>
-                    <span>{{ quote?.presettle }}</span>
-                    <span>{{ parsePercent(quote?.change) }}</span>
-                </div>
-                <template #right>
-                    <span @click="routerToChart">图表</span>
+            <app-navbar title="交易">
+                <template #footer>
+                    <Cell>
+                        <template #title>
+                            <b>{{ quote?.goodscode }}</b>
+                        </template>
+                        <template #label>
+                            <span>{{ quote?.presettle }}</span>
+                            <span>{{ parsePercent(quote?.change) }}</span>
+                        </template>
+                        <template #right-icon>
+                            <span @click="routerToChart">图表</span>
+                        </template>
+                    </Cell>
                 </template>
             </app-navbar>
         </template>
-        <Button type="danger">开多</Button>
-        <Button type="primary">开空</Button>
-        <Form ref="formRef">
+        <Row class="g-layout-block g-layout-block--inset" gutter="10">
+            <Col span="12">
+            <Button type="success" size="small" block>开多</Button>
+            </Col>
+            <Col span="12">
+            <Button type="default" size="small" block>开空</Button>
+            </Col>
+        </Row>
+        <Form ref="formRef" class="g-form__container">
             <CellGroup inset>
-                <Field label="限单价">
+                <Field label="限单价" is-link>
                     <template #input>
                         <app-select v-model="formData.PriceMode" :options="options" />
                     </template>
                 </Field>
-                 <Field name="OrderPrice" :rules="formRules.OrderPrice" label="价格">
+                <Field name="OrderPrice" :rules="formRules.OrderPrice" label="价格">
                     <template #input>
-                        <Stepper v-model="formData.OrderPrice" theme="round" min="0.0"
-                            :decimal-length="quote?.decimalplace" :step="quote?.decimalvalue" :auto-fixed="false"
-                            button-size="22" />
+                        <app-stepper v-model="formData.OrderPrice" min="0.0" :decimal-length="quote?.decimalplace"
+                            :step="quote?.decimalvalue" :auto-fixed="false" />
                     </template>
                 </Field>
                 <Field name="OrderQty" :rules="formRules.OrderQty" label="数量">
                     <template #input>
-                        <Stepper v-model="formData.OrderQty" theme="round" min="0.0" button-size="22"
-                            :auto-fixed="false" integer />
+                        <app-stepper v-model="formData.OrderQty" min="0.0" :auto-fixed="false" integer />
                     </template>
                 </Field>
-                <Field label="开仓价值">
-                </Field>
+                <Field label="开仓价值"></Field>
             </CellGroup>
             <CellGroup inset style="margin-top: 20px;">
                 <Cell title="可用余额" value="0" />
@@ -45,7 +52,11 @@
                 <Cell title="预估手续费" value="0" />
             </CellGroup>
         </Form>
-        <Button type="danger" @click="onSubmit">开多</Button>
+        <Row class="g-layout-block g-layout-block--inset">
+            <Col span="24">
+            <Button type="success" block @click="onSubmit">开多</Button>
+            </Col>
+        </Row>
         <Tabs v-model:active="tabIndex">
             <Tab title="持仓">
                 <contract-position v-bind="{ goodsId }" />
@@ -54,7 +65,7 @@
                 <contract-order v-bind="{ goodsId }" />
             </Tab>
             <Tab title="资金">
-                <contract-account />
+                <contract-account v-bind="{ accountId: 0 }" />
             </Tab>
         </Tabs>
     </app-view>
@@ -62,14 +73,14 @@
 
 <script lang="ts" setup>
 import { shallowRef, computed, onMounted } from 'vue'
-import { Form, Button, CellGroup, Field, Cell, Tab, Tabs, FieldRule } from 'vant'
+import { Form, Button, CellGroup, Field, Cell, Tab, Tabs, FieldRule, Col, Row } from 'vant'
 import { EPriceMode, EValidType, EOrderOperateType, EBuildType } from '@/constants/client'
 import { parsePercent } from '@/filters'
 import { useNavigation } from '@mobile/router/navigation'
 import { useFuturesStore } from '@/stores'
 import { fullloading, dialog } from '@/utils/vant'
 import { useOrder } from '@/business/trade'
-import Stepper from '@mobile/components/base/stepper/index.vue'
+import AppStepper from '@mobile/components/base/stepper/index.vue'
 import AppSelect from '@mobile/components/base/select/index.vue'
 import ContractPosition from '../../components/position/index.vue'
 import ContractOrder from '../../components/order/index.vue'
@@ -105,7 +116,7 @@ const routerToChart = () => {
 // 表单验证规则
 const formRules: { [key: string]: FieldRule[] } = {
     OrderPrice: [{
-        message:'请输入价格',
+        message: '请输入价格',
         validator: () => {
             return !!formData.OrderPrice
         }
@@ -156,7 +167,7 @@ const onSubmit = () => {
 }
 
 onMounted(() => {
-    if(quote.value) {
+    if (quote.value) {
         formData.BuyOrSell = BuyOrSell.Buy
         formData.PriceMode = EPriceMode.PRICEMODE_MARKET
     }

+ 2 - 2
src/packages/digital/views/home/index.vue

@@ -8,7 +8,7 @@
         </keep-alive>
       </RouterTransition>
     </router-view>
-    <Tabbar v-model="currentTab" placeholder safe-area-inset-bottom @change="onTabClick">
+    <Tabbar v-model="currentTab" active-color="#ff8400" placeholder safe-area-inset-bottom @change="onTabClick">
       <template v-for="(item, index) in tabbarItems" :key="index">
         <TabbarItem :icon="item.icon">{{ item.label }}</TabbarItem>
       </template>
@@ -47,7 +47,7 @@ const tabbarItems = [
   {
     name: 'home-spot',
     label: '现货',
-    icon: 'cart',
+    icon: 'hot',
   },
   {
     name: 'home-contract',

+ 0 - 176
src/packages/digital/views/mine/index.vue

@@ -1,176 +0,0 @@
-<template>
-    <app-view class="mine">
-        <template #header>
-            <app-navbar :title="$t('mine.title')" :show-back-button="false" @ready="onReady" />
-        </template>
-        <div ref="headerRef" class="mine-header">
-            <div class="mine-header__wrapper">
-                <div class="profile">
-                    <div class="profile-user">
-                        <div class="profile-user__avatar" @click="routerTo('user-avatar')">
-                            <img class="g-image--avatar" :src="userStore.userAvatar" />
-                        </div>
-                        <div class="profile-user__info">
-                            <div class="top">
-                                <span>{{ userStore.customerName }}</span>
-                                <Icon name="checked" color="var(--van-tag-success-color)"
-                                    v-if="authStatus === AuthStatus.Certified" />
-                                <Icon name="warning" color="var(--van-tag-warning-color)" v-else />
-                            </div>
-                            <div class="bottom">{{ loginStore.loginId }}</div>
-                        </div>
-                    </div>
-                    <div class="profile-account">
-                        <div class="profile-account-first">
-                            <span>{{ $t('account.account') }}</span>
-                            <span class="status">{{ $t('mine.normal') }}</span>
-                        </div>
-                        <span>{{ currentAccount.accountid ?? 0 }}</span>
-                    </div>
-                </div>
-                <div class="bank">
-                    <ul>
-                        <li>
-                            <span>{{ $t('mine.balance') }}</span>
-                            <span>{{ currentAccount.currentbalance?.toFixed(2) }}</span>
-                        </li>
-                        <li>
-                            <span>{{ $t('mine.netWorth') }}</span>
-                            <span>{{ currentAccount.hazardValue?.toFixed(2) }}</span>
-                        </li>
-                    </ul>
-                    <ul>
-                        <li>
-                            <span>{{ $t('mine.freezeMargin') }}</span>
-                            <span>{{ currentAccount.freezeMargin?.toFixed(2) }}</span>
-                        </li>
-                        <li>
-                            <span>{{ $t('mine.usedMargin') }}</span>
-                            <span>{{ currentAccount.usedmargin?.toFixed(2) }}</span>
-                        </li>
-                    </ul>
-                    <ul>
-                        <li>
-                            <span>{{ $t('mine.availableFunds') }}</span>
-                            <span>{{ currentAccount.avaiableMoney?.toFixed(2) }}</span>
-                        </li>
-                        <li>
-                            <span>{{ $t('mine.riskRate') }}</span>
-                            <span :class="currentAccount.hazardRatioColor">
-                                {{ parsePercent(currentAccount.hazardRatio) }}
-                            </span>
-                        </li>
-                    </ul>
-                </div>
-                <div class="button">
-                    <Button type="danger" size="small" round @click="doInOutMoney('0')">{{ $t('mine.cashin') }}</Button>
-                    <Button size="small" round @click="doInOutMoney('1')">{{ $t('mine.cashout') }}</Button>
-                </div>
-            </div>
-        </div>
-        <app-block class="mine-iconbar">
-            <ul>
-                <li @click="routerTo('order-position')">
-                    <Iconfont label-direction="bottom" icon="g-icon-position--line">{{ $t('mine.myposition') }}</Iconfont>
-                </li>
-                <li @click="routerTo('order-list')">
-                    <Iconfont label-direction="bottom" icon="g-icon-order--line">{{ $t('mine.myorder') }}</Iconfont>
-                </li>
-                <li @click="routerTo('order-delivery')">
-                    <Iconfont label-direction="bottom" icon="g-icon-delivery--line">{{ $t('mine.delivery') }}</Iconfont>
-                </li>
-                <li @click="routerTo('points-account')">
-                    <Iconfont label-direction="bottom" icon="g-icon-swap--line">积分信息</Iconfont>
-                </li>
-            </ul>
-        </app-block>
-        <app-block class="g-navmenu">
-            <CellGroup>
-                <Cell is-link :to="{ name: 'bank-capital' }">
-                    <template #title>
-                        <Iconfont icon="g-icon-capital">{{ $t('mine.fundsinfo') }}</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'account-authresult' }" v-if="authStatus === AuthStatus.Submitted">
-                    <template #title>
-                        <Iconfont icon="g-icon-certification">实名认证</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'account-certification' }" v-else-if="authStatus !== AuthStatus.Certified">
-                    <template #title>
-                        <Iconfont icon="g-icon-certification">实名认证</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'bank-sign' }" v-if="authStatus === AuthStatus.Certified && canBankSign">
-                    <template #title>
-                        <Iconfont icon="g-icon-sign">签约账户</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'account-protocol' }"
-                    v-if="signRecords.length && userStore.userType != 2 && authStatus === AuthStatus.Certified">
-                    <template #title>
-                        <Iconfont icon="g-icon-order--line">合同签署</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'mine-profile' }">
-                    <template #title>
-                        <Iconfont icon="g-icon-profile">{{ $t('mine.personalinformation') }}</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'rules-zcxy' }">
-                    <template #title>
-                        <Iconfont icon="g-icon-zcxy">{{ $t('rules.zcxy') }}</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'rules-yszc' }">
-                    <template #title>
-                        <Iconfont icon="g-icon-yszc">{{ $t('rules.yszc') }}</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'rules-fwrx' }">
-                    <template #title>
-                        <Iconfont icon="g-icon-fwrx">{{ $t('rules.fwrx') }}</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'mine-setting' }">
-                    <template #title>
-                        <Iconfont icon="g-icon-setting">{{ $t('mine.settings') }}</Iconfont>
-                    </template>
-                </Cell>
-                <Cell is-link :to="{ name: 'rules-gywm' }">
-                    <template #title>
-                        <Iconfont icon="g-icon-gywm">{{ $t('mine.aboutus') }}</Iconfont>
-                    </template>
-                </Cell>
-            </CellGroup>
-        </app-block>
-        <div class="mine-footer">
-            <Button class="button-logout" type="danger" size="small" round @click="userLogout">{{ $t('common.logout') }}</Button>
-        </div>
-    </app-view>
-</template>
-
-<script lang="ts" setup>
-import { Cell, CellGroup, Button, Icon } from 'vant'
-import { parsePercent } from '@/filters'
-import { AuthStatus } from '@/constants/account'
-import Iconfont from '@/components/base/iconfont/index.vue'
-import { useSetup } from '../../../sbyj/views/mine/composables'
-
-const {
-    loginStore,
-    userStore,
-    authStatus,
-    currentAccount,
-    signRecords,
-    canBankSign,
-    userLogout,
-    onReady,
-    routerTo,
-    doInOutMoney
-} = useSetup()
-</script>
-
-<style lang="less">
-@import '@mobile/views/mine/index.less';
-</style>

+ 49 - 0
src/packages/digital/views/setting/index.vue

@@ -0,0 +1,49 @@
+<template>
+    <app-view>
+        <template #header>
+            <app-navbar title="设置" />
+            <CellGroup inset style="margin-top: var(--van-padding-md);">
+                <Cell is-link :to="{ name: 'user-password' }">
+                    <template #title>
+                        <app-iconfont icon="g-icon-password">修改密码</app-iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link :to="{ name: 'user-cancel' }">
+                    <template #title>
+                        <app-iconfont icon="g-icon-cancel">注销服务</app-iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link>
+                    <template #title>
+                        <app-iconfont icon="g-icon-lang">语言设置</app-iconfont>
+                    </template>
+                </Cell>
+                <Cell is-link @click="userLogout">
+                    <template #title>
+                        <app-iconfont icon="g-icon-cancel">退出登录</app-iconfont>
+                    </template>
+                </Cell>
+            </CellGroup>
+        </template>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { Cell, CellGroup } from 'vant'
+import {  dialog } from '@/utils/vant'
+import { useLoginStore  } from '@/stores'
+import eventBus from '@/services/bus'
+import AppIconfont from '@/components/base/iconfont/index.vue'
+
+const loginStore = useLoginStore()
+
+const userLogout = () => {
+    dialog({
+        message: '是否退出当前账号?',
+        showCancelButton: true,
+    }).then(() => {
+        loginStore.clearAutoLoginData()
+        eventBus.$emit('LogoutNotify')
+    })
+}
+</script>

+ 1 - 1
src/packages/digital/views/wallet/index.less → src/packages/digital/views/spot/components/account/index.less

@@ -1,4 +1,4 @@
-.wallet {
+.spot-account {
     .card {
         display: flex;
         justify-content: space-between;

+ 65 - 0
src/packages/digital/views/spot/components/account/index.vue

@@ -0,0 +1,65 @@
+<!-- 现货-账户 -->
+<template>
+    <div class="g-detail-table">
+        <table cellspacing="0" cellpadding="0">
+            <tbody>
+                <tr>
+                    <th>
+                        <span>BTC</span>
+                        <span class="text-small">比特币</span>
+                    </th>
+                    <td>
+                        <span class="text-small">可用(BTC)</span>
+                        <span>1.23455789</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">余额(BTC)</span>
+                        <span>1.23456789</span>
+                    </td>
+
+                    <td>
+                        <span class="text-small">冻结(BTC)</span>
+                        <span>0.00001000</span>
+                    </td>
+                </tr>
+            </tbody>
+            <tfoot>
+                <tr>
+                    <td colspan="2">
+                        <Button size="small" @click="navigateTo('wallet-deposit')">充值</Button>
+                        <Button size="small" @click="navigateTo('wallet-withdraw')">提现</Button>
+                    </td>
+                </tr>
+            </tfoot>
+        </table>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { Button } from 'vant'
+import { useNavigation } from '@mobile/router/navigation'
+
+const props = defineProps({
+    accountId: {
+        type: Number,
+        required: true
+    }
+})
+
+const { router } = useNavigation()
+
+const navigateTo = (name: string) => {
+    router.push({
+        name,
+        query: {
+            id: props.accountId
+        }
+    })
+}
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 38 - 0
src/packages/digital/views/spot/components/order/cancel/index.vue

@@ -0,0 +1,38 @@
+<template>
+    <Dialog v-model:show="showDialog" title="提示" show-cancel-button :before-close="onBeforeClose" @closed="onClosed"
+        message="是否撤销?">
+    </Dialog>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, onMounted } from 'vue'
+import { Dialog } from 'vant'
+
+defineProps({
+    selectedRow: {
+        type: Object,
+        required: true
+    }
+})
+
+const emit = defineEmits(['closed'])
+
+const showDialog = shallowRef(false)
+const refresh = shallowRef(false) // 是否刷新父组件数据
+
+const onBeforeClose = (action: string) => {
+    if (action === 'confirm') {
+        refresh.value = true
+        showDialog.value = false
+    }
+    return true
+}
+
+const onClosed = () => {
+    emit('closed', refresh.value)
+}
+
+onMounted(() => {
+    showDialog.value = true
+})
+</script>

+ 93 - 0
src/packages/digital/views/spot/components/order/index.vue

@@ -0,0 +1,93 @@
+<template>
+    <div class="g-detail-table">
+        <table cellspacing="0" cellpadding="0" v-if="showDatePicker">
+            <tbody>
+                <tr>
+                    <td>
+                        <app-date-picker v-model="date" />
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+        <table cellspacing="0" cellpadding="0">
+            <thead>
+                <tr>
+                    <th>
+                        <span>Gold黄金</span>
+                        <time class="text-small">2025-09-01 11:11:11</time>
+                    </th>
+                    <th>
+                        <span class="g-price-down">买入</span>
+                    </th>
+                </tr>
+            </thead>
+            <tbody>
+                <tr>
+                    <td>
+                        <span class="text-small">委托单号</span>
+                        <span>1001718728455010011</span>
+                    </td>
+                    <td>
+                        <span class="text-small">委托状态</span>
+                        <span>委托成功</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">委托价格(USDT)</span>
+                        <span>3,480.88</span>
+                    </td>
+                    <td>
+                        <span class="text-small">委托数量(Gold)</span>
+                        <span>100</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td colspan="2">
+                        <span class="text-small">委托金额(USDT)</span>
+                        <span>374.379644</span>
+                    </td>
+                </tr>
+            </tbody>
+            <tfoot>
+                <tr>
+                    <td colspan="2">
+                        <Button size="small" @click="cancelOrder()">撤销</Button>
+                    </td>
+                </tr>
+            </tfoot>
+        </table>
+        <component ref="componentRef" v-bind="{ selectedRow }" :is="componentMap.get(componentId)"
+            @closed="closeComponent" v-if="componentId" />
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, defineAsyncComponent } from 'vue'
+import { Button } from 'vant'
+import { useComponent } from '@/hooks/component'
+import AppDatePicker from '@mobile/components/base/datepicker/index.vue'
+
+defineProps({
+    goodsId: Number,
+    showDatePicker: {
+        type: Boolean,
+        default: false
+    }
+})
+
+const componentMap = new Map<string, unknown>([
+    ['Cancel', defineAsyncComponent(() => import('./cancel/index.vue'))], // 撤销
+])
+
+const date = shallowRef('')
+const selectedRow = shallowRef()
+
+const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+
+// 撤销
+const cancelOrder = () => {
+    selectedRow.value = {}
+    openComponent('Cancel')
+}
+</script>

+ 8 - 0
src/packages/digital/views/spot/components/statement/index.vue

@@ -0,0 +1,8 @@
+<template>
+    <div>
+        流水
+    </div>
+</template>
+
+<script lang="ts" setup>
+</script>

+ 61 - 0
src/packages/digital/views/spot/components/trade/index.vue

@@ -0,0 +1,61 @@
+<template>
+    <div class="g-detail-table">
+        <table cellspacing="0" cellpadding="0">
+            <tbody>
+                <tr>
+                    <td>
+                        <app-date-picker v-model="date" />
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+        <table cellspacing="0" cellpadding="0">
+            <thead>
+                <tr>
+                    <th>
+                        <span>Gold黄金</span>
+                        <time class="text-small">2025-09-01 11:11:11</time>
+                    </th>
+                    <th>
+                        <span class="g-price-down">买入</span>
+                    </th>
+                </tr>
+            </thead>
+            <tbody>
+                <tr>
+                    <td>
+                        <span class="text-small">成交单号</span>
+                        <span>1001718728455010011</span>
+                    </td>
+                    <td>
+                        <span class="text-small">手续费(BTC)</span>
+                        <span>10.021332</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">成交价格(USDT)</span>
+                        <span>3,480.88</span>
+                    </td>
+                    <td>
+                        <span class="text-small">成交数量(BTC)</span>
+                        <span>100</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td colspan="2">
+                        <span class="text-small">成交金额(USDT)</span>
+                        <span>374.379644</span>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import AppDatePicker from '@mobile/components/base/datepicker/index.vue'
+
+const date = shallowRef('')
+</script>

+ 83 - 0
src/packages/digital/views/spot/detail/index.vue

@@ -0,0 +1,83 @@
+<template>
+    <app-view class="spot-detail g-form">
+        <template #header>
+            <app-navbar title="现货明细" />
+        </template>
+        <Grid :border="false" :column-num="3">
+            <GridItem icon="pending-payment" text="充值" :to="{ name: 'wallet-deposit', query: { id: accountId } }" />
+            <GridItem icon="paid" text="提现" :to="{ name: 'wallet-withdraw', query: { id: accountId } }" />
+            <GridItem icon="chart-trending-o" text="交易" @click="navigateToSpotDetail" />
+        </Grid>
+        <div class="g-detail-table">
+            <table cellspacing="0" cellpadding="0">
+                <tbody>
+                    <tr>
+                        <td colspan="2">
+                            <span class="text-small">余额(BTC)</span>
+                            <span>1.23456789</span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <span class="text-small">可用(BTC)</span>
+                            <span>1.23455789</span>
+                        </td>
+                        <td>
+                            <span class="text-small">冻结(BTC)</span>
+                            <span>0.00001000</span>
+                        </td>
+                    </tr>
+                </tbody>
+            </table>
+        </div>
+        <Tabs v-model:active="tabIndex">
+            <Tab title="充值">
+                <wallet-record />
+            </Tab>
+            <Tab title="提现">
+                <wallet-record />
+            </Tab>
+            <Tab title="转入">
+                <wallet-record />
+            </Tab>
+            <Tab title="转出">
+                <wallet-record />
+            </Tab>
+            <Tab title="委托">
+                <spot-order showDatePicker />
+            </Tab>
+            <Tab title="成交">
+                <spot-trade />
+            </Tab>
+            <Tab title="资金明细">
+                <spot-statement />
+            </Tab>
+        </Tabs>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import { Tab, Tabs, Grid, GridItem } from 'vant'
+import { useNavigation } from '@mobile/router/navigation'
+import WalletRecord from '../../wallet/components/record/index.vue'
+import SpotOrder from '../components/order/index.vue'
+import SpotTrade from '../components/trade/index.vue'
+import SpotStatement from '../components/statement/index.vue'
+
+const { router, getQueryStringToNumber } = useNavigation()
+
+const accountId = getQueryStringToNumber('id')
+const tabIndex = shallowRef(0)
+
+const navigateToSpotDetail = () => {
+    const goodsId = accountId
+    // 多个商品弹出列表选择,单个商品直接跳转
+    router.push({
+        name: 'spot-goods-detail',
+        query: {
+            id: goodsId
+        }
+    })
+}
+</script>

+ 20 - 0
src/packages/digital/views/spot/goods/chart/index.vue

@@ -0,0 +1,20 @@
+<template>
+    <app-view class="spot-goods-chart g-form">
+        <template #header>
+            <app-navbar :title="quote?.goodscode" />
+        </template>
+        图表
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { computed } from 'vue'
+import { useNavigation } from '@mobile/router/navigation'
+import { useFuturesStore } from '@/stores'
+
+const { getQueryStringToNumber } = useNavigation()
+const goodsid = getQueryStringToNumber('id')
+const futuresStore = useFuturesStore()
+
+const quote = computed(() => futuresStore.getQuoteInfo({ goodsid }))
+</script>

+ 2 - 0
src/packages/digital/views/spot/goods/detail/index.less

@@ -0,0 +1,2 @@
+.sopt-goods-detail {
+}

+ 113 - 0
src/packages/digital/views/spot/goods/detail/index.vue

@@ -0,0 +1,113 @@
+<template>
+    <app-view class="sopt-goods-detail g-layout g-form">
+        <template #header>
+            <app-navbar title="交易">
+                <template #footer>
+                    <Cell>
+                        <template #title>
+                            <b>{{ quote?.goodscode }}</b>
+                        </template>
+                        <template #label>
+                            <span>{{ quote?.presettle }}</span>
+                            <span>{{ parsePercent(quote?.change) }}</span>
+                        </template>
+                        <template #right-icon>
+                            <span @click="navigateToGoodsChart">图表</span>
+                        </template>
+                    </Cell>
+                </template>
+            </app-navbar>
+        </template>
+        <Row class="g-layout-block g-layout-block--inset" gutter="10">
+            <Col span="12">
+            <Button :type="formData.BuyOrSell === BuyOrSell.Buy ? 'success' : 'default'" size="small" block
+                @click="formData.BuyOrSell = BuyOrSell.Buy">买入</Button>
+            </Col>
+            <Col span="12">
+            <Button :type="formData.BuyOrSell === BuyOrSell.Sell ? 'danger' : 'default'" size="small" block
+                @click="formData.BuyOrSell = BuyOrSell.Sell">卖出</Button>
+            </Col>
+        </Row>
+        <Form ref="formRef" class="g-form__container">
+            <CellGroup inset>
+                <Field label="类型" is-link>
+                    <template #input>
+                        <app-select :options="[]" />
+                    </template>
+                </Field>
+                <Field label="价格">
+                    <template #input>
+                        <app-stepper />
+                    </template>
+                </Field>
+                <Field label="数量">
+                    <template #input>
+                        <app-stepper />
+                    </template>
+                </Field>
+                <Cell title="预估支付" value="0" />
+            </CellGroup>
+            <CellGroup inset v-if="formData.BuyOrSell === BuyOrSell.Buy">
+                <Cell title="可用余额" value="0" />
+                <Cell title="可开数量" value="0" />
+                <Cell title="预估手续费" value="0" />
+            </CellGroup>
+            <CellGroup inset v-if="formData.BuyOrSell === BuyOrSell.Sell">
+                <Cell title="可卖数量" value="0" />
+                <Cell title="可获金额" value="0" />
+                <Cell title="预估手续费" value="0" />
+            </CellGroup>
+        </Form>
+        <Row class="g-layout-block g-layout-block--inset">
+            <Col span="24">
+            <Button type="success" block v-if="formData.BuyOrSell === BuyOrSell.Buy">买入</Button>
+            <Button type="danger" block v-if="formData.BuyOrSell === BuyOrSell.Sell">卖出</Button>
+            </Col>
+        </Row>
+        <Tabs v-model:active="tabIndex" sticky>
+            <Tab title="委托">
+                <spot-order v-bind="{ goodsId }" />
+            </Tab>
+            <Tab title="资金">
+                <spot-account v-bind="{ accountId: 0 }" />
+            </Tab>
+        </Tabs>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, reactive, computed } from 'vue'
+import { Form, Button, CellGroup, Field, Cell, Tab, Tabs, Col, Row } from 'vant'
+import { parsePercent } from '@/filters'
+import { BuyOrSell } from '@/constants/order'
+import { useNavigation } from '@mobile/router/navigation'
+import { useFuturesStore } from '@/stores'
+import AppSelect from '@mobile/components/base/select/index.vue'
+import AppStepper from '@mobile/components/base/stepper/index.vue'
+import SpotOrder from '../../components/order/index.vue'
+import SpotAccount from '../../components/account/index.vue'
+
+const { router, getQueryStringToNumber } = useNavigation()
+const goodsId = getQueryStringToNumber('id')
+const futuresStore = useFuturesStore()
+const tabIndex = shallowRef(0)
+
+const quote = computed(() => futuresStore.getQuoteInfo({ goodsid: goodsId }))
+
+const formData = reactive<Partial<Proto.DigitalOrderReq>>({
+    BuyOrSell: BuyOrSell.Buy
+})
+
+const navigateToGoodsChart = () => {
+    router.push({
+        name: 'spot-goods-chart',
+        query: {
+            id: goodsId
+        }
+    })
+}
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 59 - 0
src/packages/digital/views/spot/goods/list/index.less

@@ -0,0 +1,59 @@
+.spot {
+    .table {
+        width: 100%;
+        text-align: right;
+
+        &-row {
+            position: relative;
+
+            &::after {
+                content: '';
+                position: absolute;
+                bottom: 0;
+                right: 0;
+                left: 0;
+                pointer-events: none;
+                border-bottom: 1px solid #292929;
+                transform: scaleY(.5);
+            }
+
+            th,
+            td {
+                &:first-child {
+                    text-align: left;
+                }
+            }
+
+            th {
+                font-size: 12px;
+                font-weight: normal;
+                color: #999;
+            }
+        }
+
+        &-cell {
+            display: flex;
+            flex-direction: column;
+            padding: 10px;
+
+            &--media {
+                flex-direction: row;
+                align-items: center;
+            }
+
+            &__image {
+                margin-right: 10px;
+            }
+
+            &__info {
+                display: flex;
+                flex-direction: column;
+            }
+
+            .text-small {
+                font-size: 12px;
+                color: #999;
+            }
+        }
+    }
+}

+ 97 - 0
src/packages/digital/views/spot/goods/list/index.vue

@@ -0,0 +1,97 @@
+<template>
+    <app-view class="spot">
+        <Search shape="round" placeholder="搜索" />
+        <Tabs v-model:active="currentGroupId">
+            <template v-for="(item, index) in goodsGroups" :key="index">
+                <Tab :title="item.goodsgroupname" :name="item.goodsgroupid">
+                    <table class="table" cellspacing="0" cellpadding="0">
+                        <thead class="table-thead">
+                            <tr class="table-row">
+                                <th>
+                                    <div class="table-cell">代码/名称</div>
+                                </th>
+                                <th>
+                                    <div class="table-cell">最新价格</div>
+                                </th>
+                                <th>
+                                    <div class="table-cell">涨跌</div>
+                                </th>
+                            </tr>
+                        </thead>
+                        <tbody class="table-body">
+                            <template v-for="(item, index) in goodsList" :key="index">
+                                <tr class="table-row" @click="rowClick(item)">
+                                    <td>
+                                        <div class="table-cell table-cell--media">
+                                            <div class="table-cell__image">
+                                                <Image fit="contain" :src="getFirstImage(item.thumurls)" width="28"
+                                                    height="28" round />
+                                            </div>
+                                            <div class="table-cell__info">
+                                                <span>
+                                                    <b>{{ item.goodscode }}</b>
+                                                </span>
+                                                <span class="text-small">
+                                                    {{ item.goodsname }}
+                                                </span>
+                                            </div>
+                                        </div>
+                                    </td>
+                                    <td>
+                                        <div class="table-cell">
+                                            <span :class="item.lastColor">
+                                                {{ handleNumberValue(item.last) }}
+                                            </span>
+                                        </div>
+                                    </td>
+                                    <td>
+                                        <div class="table-cell">
+                                            <span>
+                                                {{ parsePercent(item.change) }}
+                                            </span>
+                                        </div>
+                                    </td>
+                                </tr>
+                            </template>
+                        </tbody>
+                    </table>
+                </Tab>
+            </template>
+        </Tabs>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, onMounted, computed } from 'vue'
+import { Search, Tab, Tabs, Image } from 'vant'
+import { useNavigation } from '@mobile/router/navigation'
+import { parsePercent, handleNumberValue, getFirstImage } from '@/filters'
+import { useFuturesStore, useUserStore } from '@/stores'
+
+const { router } = useNavigation()
+const userStore = useUserStore()
+const futuresStore = useFuturesStore()
+const currentGroupId = shallowRef(0)
+
+const goodsGroups = userStore.userData.goodsgroups.filter((e) => e.marketid === 80201)
+
+const goodsList = computed(() => futuresStore.quotationList.filter((e) => e.goodsgroupid === currentGroupId.value))
+
+const rowClick = (row: Model.GoodsQuote) => {
+    router.push({
+        name: 'spot-goods-detail',
+        query: {
+            id: row.goodsid
+        }
+    })
+}
+
+onMounted(() => {
+    const [firstGroup] = goodsGroups
+    currentGroupId.value = firstGroup ? firstGroup.goodsgroupid : 0
+})
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 6 - 0
src/packages/digital/views/user/login/index.less

@@ -1,10 +1,16 @@
 .login {
+    background: var(--app-bg-color);
+
     &-logo {
         img {
             height: 48px;
         }
     }
 
+    &-form {
+        background-color: #111827;
+    }
+
     .van-field__control {
         background-color: #333 !important;
     }

+ 53 - 0
src/packages/digital/views/wallet/components/contract/index.vue

@@ -0,0 +1,53 @@
+<!-- 合约-账户 -->
+<template>
+    <div class="g-detail-table">
+        <table cellspacing="0" cellpadding="0">
+            <thead>
+                <tr @click="onClick(0)">
+                    <th colspan="2">
+                        <span>资金(250000000011)</span>
+                    </th>
+                    <th>
+                        <Icon name="arrow" />
+                    </th>
+                </tr>
+            </thead>
+            <tbody>
+                <tr>
+                    <td colspan="2">
+                        <span class="text-small">账户权益(USDT)</span>
+                        <span>1000.00</span>
+                    </td>
+                    <td>
+                        <span class="text-small">浮动盈亏</span>
+                        <span>+2.87</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">可用(USDT)</span>
+                        <span>100</span>
+                    </td>
+                    <td>
+                        <span class="text-small">占用(USDT)</span>
+                        <span>34,808.80</span>
+                    </td>
+                    <td>
+                        <span class="text-small">冻结(USDT)</span>
+                        <span>97.21</span>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { Icon } from 'vant'
+
+const emit = defineEmits(['click'])
+
+const onClick = (accountId: number) => {
+    emit('click', accountId)
+}
+</script>

+ 53 - 0
src/packages/digital/views/wallet/components/record/index.vue

@@ -0,0 +1,53 @@
+<!-- 钱包-记录 -->
+<template>
+    <div class="g-detail-table">
+        <table cellspacing="0" cellpadding="0">
+            <tbody>
+                <tr>
+                    <td>
+                        <app-date-picker v-model="date" />
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+        <table cellspacing="0" cellpadding="0">
+            <thead>
+                <tr>
+                    <th colspan="2">
+                        <span>充值(USDT)</span>
+                        <time class="text-small">2025-09-01 11:11:11</time>
+                    </th>
+                </tr>
+            </thead>
+            <tbody>
+                <tr>
+                    <td>
+                        <span class="text-small">申请单号</span>
+                        <span>4031718728455010011</span>
+                    </td>
+                    <td>
+                        <span class="text-small">申请状态</span>
+                        <span>审核通过</span>
+                    </td>
+                </tr>
+                <tr>
+                    <td>
+                        <span class="text-small">申请金额(USDT)</span>
+                        <span>1000.000000</span>
+                    </td>
+                    <td>
+                        <span class="text-small">手续费(USDT)</span>
+                        <span>0.100000</span>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef } from 'vue'
+import AppDatePicker from '@mobile/components/base/datepicker/index.vue'
+
+const date = shallowRef('')
+</script>

+ 37 - 0
src/packages/digital/views/wallet/components/spot/index.less

@@ -0,0 +1,37 @@
+.spot-account {
+    .card {
+        display: flex;
+        justify-content: space-between;
+        border-bottom: 1px solid #171f2d;
+        padding: 10px 20px;
+
+        &-section {
+            display: flex;
+            align-items: center;
+
+            &__info,
+            &__balance {
+                display: flex;
+                flex-direction: column;
+                line-height: 1.5;
+            }
+
+            &__balance {
+                text-align: right;
+            }
+
+            &__image {
+                margin-right: 10px;
+            }
+
+            &__icon {
+                margin-left: 10px;
+            }
+
+            .text-small {
+                font-size: 12px;
+                color: #666;
+            }
+        }
+    }
+}

+ 48 - 0
src/packages/digital/views/wallet/components/spot/index.vue

@@ -0,0 +1,48 @@
+<!-- 现货-账户 -->
+<template>
+    <div class="spot-account">
+        <Search shape="round" placeholder="搜索" />
+        <div class="card" @click="onClick(0)">
+            <div class="card-section">
+                <div class="card-section__image">
+                    <Image fit="contain" src="" width="32" height="32" round />
+                </div>
+                <div class="card-section__info">
+                    <span>
+                        <b>BTC</b>
+                    </span>
+                    <span class="text-small">
+                        比特币
+                    </span>
+                </div>
+            </div>
+            <div class="card-section">
+                <div class="card-section__balance">
+                    <span>
+                        余额(USDT)
+                    </span>
+                    <span class="text-small">
+                        12.65432100
+                    </span>
+                </div>
+                <div class="card-section__icon">
+                    <Icon name="arrow" />
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { Search, Image, Icon } from 'vant'
+
+const emit = defineEmits(['click'])
+
+const onClick = (accountId: number) => {
+    emit('click', accountId)
+}
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 11 - 0
src/packages/digital/views/wallet/deposit/index.vue

@@ -0,0 +1,11 @@
+<!-- 钱包-充值 -->
+<template>
+    <app-view class="wallet-deposit">
+        <template #header>
+            <app-navbar title="充值" />
+        </template>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+</script>

+ 33 - 49
src/packages/digital/views/wallet/index.vue

@@ -1,52 +1,18 @@
 <!-- 钱包 -->
 <template>
-    <app-view class="wallet g-layout">
-        <div class="g-layout-block">
-            <Grid :border="false">
-                <GridItem icon="pending-payment" text="充值" />
-                <GridItem icon="paid" text="提现" />
-                <GridItem icon="peer-pay" text="划转" :to="{ name: 'wallet-transfer' }" />
-                <GridItem icon="setting-o" text="设置" />
-            </Grid>
-        </div>
+    <app-view class="wallet">
+        <Grid :border="false">
+            <GridItem icon="pending-payment" text="充值" :to="{ name: 'wallet-deposit' }" />
+            <GridItem icon="paid" text="提现" :to="{ name: 'wallet-withdraw' }" />
+            <GridItem icon="peer-pay" text="划转" :to="{ name: 'wallet-transfer' }" />
+            <GridItem icon="setting-o" text="设置" :to="{ name: 'setting' }" />
+        </Grid>
         <Tabs v-model:active="currentTabIndex">
             <Tab title="现货">
-                <div class="g-layout-block">
-                    <Search shape="round" placeholder="搜索" />
-                    <div class="card">
-                        <div class="card-section">
-                            <div class="card-section__image">
-                                <Image fit="contain" src="" width="32" height="32" round />
-                            </div>
-                            <div class="card-section__info">
-                                <span>
-                                    <b>BTC</b>
-                                </span>
-                                <span class="text-small">
-                                    比特币
-                                </span>
-                            </div>
-                        </div>
-                        <div class="card-section">
-                            <div class="card-section__balance">
-                                <span>
-                                    余额(USDT)
-                                </span>
-                                <span class="text-small">
-                                    12.65432100
-                                </span>
-                            </div>
-                            <div class="card-section__icon">
-                                <Icon name="arrow" />
-                            </div>
-                        </div>
-                    </div>
-                </div>
+                <spot-account @click="navigateToSpotDetail" />
             </Tab>
             <Tab title="合约">
-                <div class="g-layout-block">
-                    <contract-account />
-                </div>
+                <contract-account @click="navigateToContractDetail" />
             </Tab>
         </Tabs>
     </app-view>
@@ -54,12 +20,30 @@
 
 <script lang="ts" setup>
 import { shallowRef } from 'vue'
-import { Search, Tab, Tabs, Image, Icon, Grid, GridItem } from 'vant'
-import ContractAccount from '../../views/contract/components/account/index.vue'
+import { Tab, Tabs, Grid, GridItem } from 'vant'
+import { useNavigation } from '@mobile/router/navigation'
+import SpotAccount from './components/spot/index.vue'
+import ContractAccount from './components/contract/index.vue'
+
+const { router } = useNavigation()
 
 const currentTabIndex = shallowRef(0)
-</script>
 
-<style lang="less">
-@import './index.less';
-</style>
+const navigateToSpotDetail = (accountId: number) => {
+    router.push({
+        name: 'spot-detail',
+        query: {
+            id: accountId
+        }
+    })
+}
+
+const navigateToContractDetail = (accountId: number) => {
+    router.push({
+        name: 'contract-detail',
+        query: {
+            id: accountId
+        }
+    })
+}
+</script>

+ 20 - 14
src/packages/digital/views/wallet/transfer/index.vue

@@ -1,18 +1,18 @@
 <!-- 钱包-划转 -->
 <template>
-    <app-view class="wallet-transfer g-layout">
+    <app-view class="wallet-transfer g-layout g-form">
         <template #header>
             <app-navbar title="划转" />
         </template>
-        <Form ref="formRef" @submit="onSubmit">
-            <div class="switch-group">
-                <span :class="{ active: formData.DigitalTransferType === 3 }" @click="formData.DigitalTransferType = 3">
-                    从 合约 到 现货
-                </span>
-                <span :class="{ active: formData.DigitalTransferType === 4 }" @click="formData.DigitalTransferType = 4">
-                    从 现货 到 合约
-                </span>
-            </div>
+        <div class="switch-group">
+            <span :class="{ active: formData.DigitalTransferType === 3 }" @click="formData.DigitalTransferType = 3">
+                从 合约 到 现货
+            </span>
+            <span :class="{ active: formData.DigitalTransferType === 4 }" @click="formData.DigitalTransferType = 4">
+                从 现货 到 合约
+            </span>
+        </div>
+        <Form ref="formRef" class="g-form__container" @submit="onSubmit">
             <CellGroup inset>
                 <Field name="CurrencyID" label="币种" :rules="formRules.CurrencyID" is-link>
                     <template #input>
@@ -22,21 +22,27 @@
                 </Field>
                 <Field name="Amount" label="数量" :rules="formRules.Amount">
                     <template #input>
-                        <app-stepper theme="round" v-model="formData.Amount" />
+                        <app-stepper v-model="formData.Amount" />
                     </template>
                 </Field>
                 <Cell title="可用" value="0" />
             </CellGroup>
-            <Button type="danger">取消</Button>
-            <Button type="primary" @click="formRef?.submit">划转</Button>
         </Form>
+        <Row class="g-layout-block g-layout-block--inset" gutter="10">
+            <Col span="12">
+            <Button block>取消</Button>
+            </Col>
+            <Col span="12">
+            <Button type="primary" block @click="formRef?.submit">划转</Button>
+            </Col>
+        </Row>
     </app-view>
 </template>
 
 <script lang="ts" setup>
 import { shallowRef, reactive } from 'vue'
 import { v4 } from 'uuid'
-import { FormInstance, Form, Button, CellGroup, Field, Cell, FieldRule } from 'vant'
+import { FormInstance, Form, Col, Row, Button, CellGroup, Field, Cell, FieldRule } from 'vant'
 import { fullloading } from '@/utils/vant'
 import { getCurrencyList, getDigitalCurrencyList } from '@/constants/order'
 import { DigitalAccountTransferApply } from '@/services/api/bank'

+ 11 - 0
src/packages/digital/views/wallet/withdraw/index.vue

@@ -0,0 +1,11 @@
+<!-- 钱包-提现 -->
+<template>
+    <app-view class="wallet-deposit">
+        <template #header>
+            <app-navbar title="提现" />
+        </template>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+</script>

+ 17 - 0
src/packages/mobile/components/base/datepicker/index.less

@@ -0,0 +1,17 @@
+.app-datepicker {
+    &__placeholder {
+        display: flex;
+        align-items: center;
+        color: #666;
+
+        &::after {
+            content: '';
+            width: 0;
+            height: 0;
+            border-left: 4px solid transparent;
+            border-right: 4px solid transparent;
+            border-top: 5px solid currentColor;
+            margin-left: 5px;
+        }
+    }
+}

+ 63 - 0
src/packages/mobile/components/base/datepicker/index.vue

@@ -0,0 +1,63 @@
+<template>
+    <div class="app-datepicker">
+        <div @click="show = true">
+            <slot>
+                <span class="app-datepicker__placeholder">{{ modelValue || placeholder }}</span>
+            </slot>
+        </div>
+        <Popup v-model:show="show" position="bottom" round>
+            <DatePicker v-model="currentDate" title="选择日期" @cancel="onCancel" @confirm="onConfirm" />
+        </Popup>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { ref, onMounted } from 'vue'
+import { Popup, DatePicker } from 'vant'
+import moment from 'moment'
+
+const props = defineProps({
+    modelValue: {
+        type: String,
+        required: true
+    },
+    // 分隔符
+    separator: {
+        type: String,
+        default: '-'
+    },
+    // 占位符文本
+    placeholder: {
+        type: String,
+        default: '日期选择'
+    }
+})
+
+const emit = defineEmits(['update:modelValue'])
+
+const show = ref(false)
+const currentDate = ref<string[]>([])
+
+const onCancel = () => {
+    show.value = false
+}
+
+const onConfirm = () => {
+    emit('update:modelValue', currentDate.value.join(props.separator))
+    onCancel()
+}
+
+onMounted(() => {
+    if (props.modelValue) {
+        currentDate.value = props.modelValue.split(props.separator)
+    } else {
+        const now = moment()
+        const dateArray = [now.format('YYYY'), now.format('MM'), now.format('DD')]
+        currentDate.value = dateArray
+    }
+})
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 2 - 2
src/packages/mobile/views/bank/sign/components/edit/Index.vue

@@ -284,8 +284,8 @@ const formSubmit = () => {
             dialog(props.isedit ? t('banksign.submitsuccess1') : t('banksign.submitsuccess2')).then(() => {
                 closed(true)
             })
-        }).catch((err) => {
-            hideLoading(err, 'fail')
+        }).catch(() => {
+            hideLoading(t('banksign.tips13'), 'success')
         })
     })
 }

+ 14 - 0
src/services/api/trade/index.ts

@@ -428,4 +428,18 @@ export function goodsInventoryApply(config: RequestConfig<Partial<Proto.GoodsInv
         requestCode: 'GoodsInventoryApplyReq',
         responseCode: 'GoodsInventoryApplyRsp',
     })
+}
+
+/**
+ * 数字交易委托请求
+ */
+export function digitalOrder(config: RequestConfig<Partial<Proto.DigitalOrderReq>>) {
+    return http.mqRequest<Proto.DigitalOrderRsp>({
+        data: {
+            ClientSerialNo: v4(),
+            ...config.data
+        },
+        requestCode: 'DigitalOrderReq',
+        responseCode: 'DigitalOrderRsp',
+    })
 }

+ 64 - 0
src/types/proto/digital.d.ts

@@ -0,0 +1,64 @@
+import { IMessageHead } from './proto'
+
+declare global {
+    namespace Proto {
+        /** 数字交易委托请求 */
+        interface DigitalOrderReq {
+            Header?: IMessageHead;
+            ClientSerialNo: string; // 客户端流水号
+            ClientOrderTime: string; // 客户端委托时间
+            ClientType: number; // 终端类型
+            LoginID: number; // 登陆账号
+            BaseAccountID: number; // 基础货币账号
+            GoodsID: number; // 商品ID
+            MarketID: number; // 市场ID
+            ValidType: number; // 校验类型
+            OperateType: number; // 操作类型:
+            OrderSrc: number; // 单据来源
+            OperatorID: number; // 操作员账号ID
+            OrderPrice: number; // 委托价格
+            MarketMaxSub: number; // 市价允许最大偏差(做市)
+            OrderQty: number; // 委托数量
+            BuyOrSell: number; // 买卖方向
+            BuildType: number; // 下单类型
+            CurtQuotePrice: number; // 保留,计算冻结金额使用
+            SpPrice: number; // 止盈价格
+            SlPrice: number; // 止损价格
+            PriceMode: number; // 取价方式
+            TimevalidType: number; // 时间有效类型
+            TriggerType: number; // 预埋单触发类型
+            TriggerPrice: number; // 预埋单触发价格
+            ListingSelectType: number; // 挂牌点选类型
+            DelistingType: number; // 摘牌类型
+            RelatedID: number; // 关联单号
+            OptionType: number; // 期权类型(1:认购(看涨)2:认沽(看跌))
+            Premium: number; // 权利金
+            TriggerOperator: number; // 触发条件(1:大于等于2:小于等于)
+            ServiceTime: string; // 服务端时间
+            CouponTypeID: number; // 优惠券类型ID(买方)
+            UsedQty: number; // 使用数量
+            ValidTime: string; // 指定有效日期
+            ReceiveInfoID: number; // 收货地址ID
+            OrderFlag: number; // 委托标识-1:按量
+            OrderAmount: number; // 委托金额OrderFlag=2必填
+            IsAutoAddDeposit: number; // 是否允许自动补定金
+            IsAutoRefundDeposit: number; // 是否允许自动退定金
+            AddrInfo: string; // 地址信息
+            TPFlag: number; // 止盈标识:0-未设置1-设置
+            TPRatio: number; // 止盈比例
+            SLFlag: number; // 止损标识:0-未设置1-设置
+            SLRatio: number; // 止损比例
+            QuoteAccountID: number; // 计价数字账户
+            OrderMode: number; // 委托方式-1:按数量
+        }
+
+        /** 数字交易委托应答 */
+        interface DigitalOrderRsp {
+            Header: IMessageHead;
+            RetCode: number; // 返回码
+            RetDesc: string; // 描述信息
+            OrderID: number; // 一级生成的订单号
+            OrderTime: string; // 接收委托交易的时间
+        }
+    }
+}