li.shaoyi 2 yıl önce
ebeveyn
işleme
5cd91be915

+ 2 - 1
android/fxgl.txt

@@ -31,4 +31,5 @@ App Name: 铁合金掌上行演示版
 
 多元演示
 cn.muchinfo.demo_v1.0.0.apk
-http://103.40.249.126:18280/cfg?key=mtp_20
+http://103.40.249.126:18280/cfg?key=mtp_20
+210000006/Aa123456

BIN
public/favicon.ico


+ 6 - 4
src/packages/mobile/assets/themes/global/global.less

@@ -139,12 +139,14 @@
             }
 
             &__price {
+                color: #f2270c;
+
                 .unit {
-                    &::before {
-                        content: '¥';
-                    }
+                    font-size: .24rem;
+                }
 
-                    color: red;
+                .integer {
+                    font-size: .3rem;
                 }
             }
         }

+ 8 - 3
src/packages/mobile/components/base/banner/index.vue

@@ -1,10 +1,9 @@
 <template>
     <div class="app-banner" :style="`min-height: ${swipeHeight};`">
         <Swipe :autoplay="5000" indicator-color="white" lazy-render>
-            <SwipeItem v-for="(src, index) in dataList" :key="index" @click="$emit('click')"
-                :style="`height: ${swipeHeight};`">
+            <SwipeItem v-for="(src, index) in dataList" :key="index" :style="`height: ${swipeHeight};`">
                 <slot :src="src">
-                    <img :src="getFileUrl(src)" />
+                    <img :src="getFileUrl(src)" @click="onClick(index)" />
                 </slot>
             </SwipeItem>
         </Swipe>
@@ -28,12 +27,18 @@ const props = defineProps({
     }
 })
 
+const emit = defineEmits(['click'])
+
 const swipeHeight = computed(() => {
     if (typeof props.height === 'number') {
         return props.height + 'px'
     }
     return props.height
 })
+
+const onClick = (index: number) => {
+    emit('click', index)
+}
 </script>
 
 <style lang="less">

+ 1 - 0
src/packages/mobile/components/modules/quote/index.less

@@ -0,0 +1 @@
+.app-quote {}

+ 84 - 0
src/packages/mobile/components/modules/quote/index.vue

@@ -0,0 +1,84 @@
+<template>
+    <div class="app-quote">
+        <div class="app-quote__price" v-if="quote">
+            <div class="wrap-left">
+                <div class="price">
+                    <span :class="quote.lastColor">{{ handleNumberValue(quote.last) }}</span>
+                    <span :class="quote.lastColor">{{ handleNumberValue(quote.rise.toFixed(quote.decimalplace)) }}</span>
+                    <span :class="quote.lastColor">{{ parsePercent(quote.change) }}</span>
+                </div>
+                <div class="time">
+                    <span>{{ formatDate(quote.lasttime, 'MM-DD HH:mm:ss') }}</span>
+                </div>
+            </div>
+            <div class="wrap-right">
+                <slot></slot>
+            </div>
+        </div>
+        <div class="app-quote__info" v-if="quote">
+            <ul>
+                <li>
+                    <span>卖价</span>
+                    <span :class="quote.askColor">{{ quote.ask }}</span>
+                </li>
+                <li>
+                    <span>开盘</span>
+                    <span>{{ quote.opened }}</span>
+                </li>
+                <li>
+                    <span>买价</span>
+                    <span :class="quote.bidColor">{{ quote.bid }}</span>
+                </li>
+                <li>
+                    <span>均价</span>
+                    <span>{{ quote.averageprice }}</span>
+                </li>
+                <li>
+                    <span>昨结</span>
+                    <span>{{ quote.presettle }}</span>
+                </li>
+                <li>
+                    <span>最高</span>
+                    <span :class="quote.highestColor">{{ quote.highest }}</span>
+                </li>
+                <li>
+                    <span>结算</span>
+                    <span>{{ quote.settle }}</span>
+                </li>
+                <li>
+                    <span>昨收</span>
+                    <span>{{ quote.preclose }}</span>
+                </li>
+                <li>
+                    <span>最低</span>
+                    <span :class="quote.lowestColor">{{ quote.lowest }}</span>
+                </li>
+            </ul>
+        </div>
+    </div>
+</template>
+
+<script lang="ts" setup>
+import { onMounted, onUnmounted } from 'vue'
+import { parsePercent, handleNumberValue, formatDate } from '@/filters'
+import { useFuturesStore } from '@/stores'
+import quoteSocket from '@/services/websocket/quote'
+
+const props = defineProps({
+    goodscode: {
+        type: String,
+        required: true
+    }
+})
+
+const futuresStore = useFuturesStore()
+const quote = futuresStore.getQuoteInfo(props.goodscode)
+const subscribe = quoteSocket.addSubscribe([props.goodscode])
+
+onMounted(() => subscribe.start())
+onUnmounted(() => subscribe.stop())
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 17 - 11
src/packages/mobile/views/home/main/Index.vue

@@ -140,7 +140,9 @@ import { queryNewTitles } from "@/services/api/news";
 import { useFuturesList } from "@/business/market";
 import { queryMarketRun } from "@/services/api/goods";
 import { queryThjSpotQuoteConfig } from "@/services/api/market";
+import { useLoginStore } from '@/stores'
 
+const loginStore = useLoginStore();
 const { router, routerTo, setGlobalUrlParams } = useNavigation();
 const { dataList } = useFuturesList();
 const refreshing = shallowRef(false); // 是否处于加载中状态
@@ -156,17 +158,21 @@ const currentSpotQuote = computed(() => spotQuoteList.value[spotQuoteIndex.value
 
 // 跳转导航页面
 const switchTab = (tabIndex: number) => {
-  setGlobalUrlParams({ tabIndex })
-  switch (tabIndex) {
-    case 1:
-      routerTo('home-presale', true)
-      break
-    case 2:
-      routerTo('home-transfer', true)
-      break
-    case 3:
-      routerTo('home-swap', true)
-      break
+  if (loginStore.token) {
+    setGlobalUrlParams({ tabIndex })
+    switch (tabIndex) {
+      case 1:
+        routerTo('home-presale', true)
+        break
+      case 2:
+        routerTo('home-transfer', true)
+        break
+      case 3:
+        routerTo('home-swap', true)
+        break
+    }
+  } else {
+    routerTo('user-login')
   }
 }
 

+ 34 - 40
src/packages/mobile/views/presale/detail/Index.vue

@@ -4,51 +4,38 @@
             <app-navbar title="商品详情" />
         </template>
         <Banner :data-list="detailBanners" height="4rem" />
-        <div class="g-detail__info">
-            <div class="pricebar">
-                <div class="pricebar-left">
-                    <span class="tag">起拍价</span>
-                    <span class="unit">¥</span>
-                    <span class="price">{{ detail.startprice?.toFixed(2) }}</span>
+        <div class="g-detail__buy">
+            <div class="topic">
+                <div class="topic-left">
+                    <span class="price-text">起拍价</span>
+                    <span class="price-unit">¥</span>
+                    <span class="price-integer">{{ detail.startprice?.toFixed(2) }}</span>
                 </div>
-                <div class="pricebar-right">
-                    <span>总量:{{ detail.presaleqty }}</span>
+                <div class="topic-right">
+                    <span>开始:{{ detail.starttime }}</span>
+                    <span>结束:{{ detail.endtime }}</span>
                 </div>
             </div>
-            <div class="tag">
+            <div class="title">
                 <Tag type="danger" round>大宗竞拍</Tag>
-            </div>
-            <div class="titlebar">
                 <span>{{ detail.sellname }}</span>
-                <span>{{ detail.goodsname }}</span>
+                <span>{{ detail.goodscode }}/{{ detail.goodsname }}</span>
             </div>
-            <div class="timebar">
-
+            <div class="qty">
+                <span>总量:{{ detail.presaleqty }}</span>
+            </div>
+            <div class="info">
+                <ul>
+                    <li>
+                        <span>预售定金</span>
+                        <span>{{ earnest }}</span>
+                    </li>
+                    <li>
+                        <span>转让比例</span>
+                        <span>{{ parsePercent(detail.transferdepositratio) }}</span>
+                    </li>
+                </ul>
             </div>
-        </div>
-        <div class="g-detail__cell">
-            <ul>
-                <li>
-                    <span>预售定金</span>
-                    <span>{{ earnest }}</span>
-                </li>
-                <li>
-                    <span>转让比例</span>
-                    <span>{{ parsePercent(detail.transferdepositratio) }}</span>
-                </li>
-            </ul>
-        </div>
-        <div class="g-detail__cell">
-            <ul>
-                <li>
-                    <span>开始时间</span>
-                    <span>{{ detail.starttime }}</span>
-                </li>
-                <li>
-                    <span>结束时间</span>
-                    <span>{{ detail.endtime }}</span>
-                </li>
-            </ul>
         </div>
         <div class="g-detail__desc">
             <template v-for="(url, index) in detailImages" :key="index">
@@ -57,7 +44,14 @@
         </div>
         <template #footer>
             <div class="g-detail__footer">
-                <Button type="primary" block round @click="openComponent('delisting')">我要出价</Button>
+                <div class="price">
+                    <span class="price-text">起拍价:</span>
+                    <span class="price-unit">¥</span>
+                    <span class="price-integer">{{ detail.startprice?.toFixed(2) }}</span>
+                </div>
+                <div class="submit">
+                    <span class="submit-button danger" @click="openComponent('delisting')">我要出价</span>
+                </div>
             </div>
             <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ detail }" @closed="closeComponent"
                 v-if="componentId" />
@@ -67,7 +61,7 @@
 
 <script lang="ts" setup>
 import { computed, defineAsyncComponent } from 'vue'
-import { Button, Tag } from 'vant'
+import { Tag } from 'vant'
 import { getFileUrl, parsePercent } from '@/filters'
 import { useComponent } from '@/hooks/component'
 import { useNavigation } from '@/hooks/navigation'

+ 1 - 1
src/packages/mobile/views/presale/detail/components/delisting/index.vue

@@ -30,7 +30,7 @@
             </Field>
         </Form>
         <template #footer>
-            <Button type="primary" block round @click="formRef?.submit">确定</Button>
+            <Button type="primary" block round @click="formRef?.submit">提交</Button>
         </template>
     </app-popup>
 </template>

+ 82 - 37
src/packages/mobile/views/presale/detail/index.less

@@ -1,72 +1,69 @@
 .g-detail {
-    &__info {
+    &__buy {
         background-color: #fff;
-        border-bottom-left-radius: .2rem;
-        border-bottom-right-radius: .2rem;
-        padding: .32rem;
 
-        .pricebar {
+        .topic {
             display: flex;
             justify-content: space-between;
             align-items: center;
+            color: #fff;
+            background-image: linear-gradient(to right, #ee0a24, #ff6034);
+            padding: .24rem;
 
             &-left {
-                color: red;
-
-                .tag {
+                .price-text {
                     font-size: .24rem;
                 }
 
-                .price {
+                .price-integer {
                     font-size: .44rem;
                 }
             }
 
             &-right {
+                display: flex;
+                flex-direction: column;
                 font-size: .24rem;
-                color: #999;
             }
         }
 
-        .tag {
-            margin-top: .24rem;
-        }
-
-        .titlebar {
-            font-size: .32rem;
+        .title {
+            font-size: .3rem;
             font-weight: bold;
-            margin-top: .2rem;
+            line-height: .48rem;
+            padding: .24rem;
+            padding-bottom: 0;
 
             span {
                 margin-right: .1rem;
             }
         }
 
-        .timebar {
-            display: flex;
-            justify-content: space-around;
+        .qty {
+            font-size: .24rem;
+            color: #999;
+            padding: .1rem .24rem 0 .24rem;
         }
-    }
 
-    &__cell {
-        background-color: #fff;
-        border-radius: .2rem;
-        margin-top: .24rem;
-        padding: .2rem .32rem;
+        .info {
+            background-color: #fff;
+            padding: .2rem;
 
-        ul {
-            li {
+            ul {
                 display: flex;
-                padding: .12rem;
+                flex-wrap: wrap;
+                font-size: .26rem;
 
-                span {
-                    &:first-child {
-                        width: 1.6rem;
-                        color: #999;
-                    }
+                li {
+                    display: flex;
+                    justify-content: space-between;
+                    width: 50%;
+                    padding: .08rem .24rem;
 
-                    &:last-child {
-                        flex: 1;
+                    span {
+                        &:first-child {
+                            color: #999;
+                        }
                     }
                 }
             }
@@ -78,7 +75,55 @@
     }
 
     &__footer {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        height: .88rem;
         background-color: #fff;
-        padding: .12rem .24rem;
+
+        .price {
+            padding-left: .32rem;
+
+            &-text,
+            &-unit {
+                font-size: .24rem;
+            }
+
+            &-unit {
+                color: #f2270c;
+            }
+
+            &-integer {
+                font-size: .36rem;
+                color: #f2270c;
+            }
+        }
+
+        .submit {
+            align-self: stretch;
+            display: flex;
+            margin-left: auto;
+
+            &-button {
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                height: 100%;
+                min-width: 2rem;
+                font-weight: bold;
+                color: #fff;
+                padding: 0 .48rem;
+
+                &.warning {
+                    background-image: linear-gradient(to right, #ffd01e, #ff8917);
+                    background-color: #ff8a17;
+                }
+
+                &.danger {
+                    background-image: linear-gradient(to right, #ff6034, #ee0a24);
+                    background-color: #ee270a;
+                }
+            }
+        }
     }
 }

+ 21 - 10
src/packages/mobile/views/presale/list/Index.vue

@@ -3,19 +3,19 @@
         <template #header>
             <app-navbar title="预售竞拍" :show-back-button="false" />
         </template>
-        <Banner :data-list="bannerList" />
+        <Banner :data-list="bannerList" @click="onBannerClick" />
         <Waterfall class="g-goods-list" :data-list="startList">
             <template #default="{ item }">
-                <div class="goods"
-                    @click="$router.push({ name: 'presale-detail', params: { item: JSON.stringify(item) } })">
+                <div class="goods" @click="toDetail(item)">
                     <div class="goods-image">
                         <img :src="getFileUrl(item.attachmenturl)" />
                     </div>
                     <div class="goods-info">
                         <div class="goods-info__title">{{ item.goodsname }}</div>
                         <div class="goods-info__price">
-                            <Tag type="danger">起拍价</Tag>
-                            <span class="unit">{{ item.startprice }}</span>
+                            <Tag type="danger" plain>起拍价</Tag>
+                            <span class="unit">¥</span>
+                            <span class="integer">{{ item.startprice }}</span>
                         </div>
                     </div>
                 </div>
@@ -24,16 +24,16 @@
         <Divider>发售历史</Divider>
         <Waterfall class="g-goods-list" :data-list="endList">
             <template #default="{ item }">
-                <div class="goods"
-                    @click="$router.push({ name: 'presale-detail', params: { item: JSON.stringify(item) } })">
+                <div class="goods" @click="toDetail(item)">
                     <div class="goods-image">
                         <img :src="getFileUrl(item.attachmenturl)" />
                     </div>
                     <div class="goods-info">
                         <div class="goods-info__title">{{ item.goodsname }}</div>
                         <div class="goods-info__price">
-                            <Tag type="danger">预售价</Tag>
-                            <span class="unit">{{ item.refprice }}</span>
+                            <Tag type="danger" plain>预售价</Tag>
+                            <span class="unit">¥</span>
+                            <span class="integer">{{ item.refprice }}</span>
                         </div>
                     </div>
                 </div>
@@ -46,14 +46,16 @@
 import { shallowRef } from 'vue'
 import { Tag, Divider } from 'vant'
 import { getFileUrl } from '@/filters'
+import { useNavigation } from '@/hooks/navigation'
 import { useRequest } from '@/hooks/request'
 import { queryPresaleAuctions } from '@/services/api/presale'
 import Banner from '@mobile/components/base/banner/index.vue'
 import Waterfall from '@mobile/components/base/waterfall/index.vue'
 
+const { router } = useNavigation()
 const bannerList = shallowRef<string[]>([])
 
-useRequest(queryPresaleAuctions, {
+const { dataList } = useRequest(queryPresaleAuctions, {
     params: {
         presalemode: 4,
         presalestatus: 1
@@ -76,6 +78,15 @@ const { dataList: endList } = useRequest(queryPresaleAuctions, {
         presalestatus: 3
     },
 })
+
+const onBannerClick = (index: number) => {
+    toDetail(dataList.value[index])
+}
+
+// 打开详情页
+const toDetail = (item: Model.PresaleAuctionsRsp) => {
+    router.push({ name: 'presale-detail', params: { item: JSON.stringify(item) } })
+}
 </script>
 
 <style lang="less">

+ 20 - 12
src/packages/mobile/views/swap/detail/Index.vue

@@ -1,49 +1,55 @@
 <template>
     <app-view>
         <template #header>
-            <app-navbar title="掉期挂牌大厅" >
+            <app-navbar :title="`${item.goodscode}/${item.goodsname}`">
                 <template #right>
                     <div class="button-more" @click="onListing">
                         <span>挂牌</span>
                     </div>
                 </template>
             </app-navbar>
-            <div>
-                <span>{{ item.goodsgroupname }}/{{ item.goodscode }}</span>
-                <span>--</span>
-            </div>
         </template>
+        <Cell :title="`${item.goodscode}/${item.goodsname}`" is-link style="margin-bottom: .2rem;">
+            <template #title v-if="quote">
+                <span :class="quote.lastColor" style="font-size: .32rem;">{{ handleNumberValue(quote.last) }}</span>
+                <span :class="quote.lastColor" style="margin-left: .2rem;">{{
+                    handleNumberValue(quote.rise.toFixed(quote.decimalplace)) }}</span>
+                <span :class="quote.lastColor" style="margin-left: .2rem;">{{ parsePercent(quote.change) }}</span>
+            </template>
+        </Cell>
         <Tabs v-model:active="tabIndex" @click="onTabChange">
             <Tab title="买大厅" />
             <Tab title="卖大厅" />
         </Tabs>
         <app-pull-refresh ref="pullRefreshRef" v-model:loading="loading" v-model:error="error" v-model:pageIndex="pageIndex"
-        :page-count="pageCount" @refresh="onTabChange">
+            :page-count="pageCount" @refresh="onTabChange">
             <div class="trade-section sell" v-if="dataList.length">
                 <app-list :columns="columns" :data-list="dataList">
                     <template #username="{ row }">
-                        <span >{{ row.userid }}/{{ row.username }}</span>
+                        <span>{{ row.userid }}/{{ row.username }}</span>
                     </template>
                     <template #operate="{ row }">
-                        <Button size="small" type="primary" round @click="onDelisting(row)">{{ tabIndex === 0 ? '卖出' : '买入' }}</Button>
+                        <Button size="small" type="primary" round @click="onDelisting(row)">{{ tabIndex === 0 ? '卖出' : '买入'
+                        }}</Button>
                     </template>
                 </app-list>
             </div>
         </app-pull-refresh>
-        <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ selectedRow, tabIndex, item }" @closed="closeComponent"
-            v-if="componentId" />
+        <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ selectedRow, tabIndex, item }"
+            @closed="closeComponent" v-if="componentId" />
     </app-view>
 </template>
 
 <script lang="ts" setup>
 import { shallowRef, defineAsyncComponent } from 'vue'
-import { Tab, Tabs, Button, showToast } from 'vant'
+import { Tab, Tabs, Button, showToast, Cell } from 'vant'
+import { parsePercent, handleNumberValue } from '@/filters'
 import { useRequest } from '@/hooks/request'
 import { useNavigation } from '@/hooks/navigation'
 import { useComponent } from '@/hooks/component'
 import AppList from '@mobile/components/base/list/index.vue'
 import { queryTjmdTradeOrderDetail } from '@/services/api/swap'
-import { useLoginStore } from '@/stores'
+import { useLoginStore, useFuturesStore } from '@/stores'
 import AppPullRefresh from '@mobile/components/base/pull-refresh/index.vue'
 
 const componentMap = new Map<string, unknown>([
@@ -55,11 +61,13 @@ const loginStore = useLoginStore()
 
 const { getParamString } = useNavigation()
 const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+const futuresStore = useFuturesStore()
 const item: Model.QuoteGoodsListRsp = JSON.parse(getParamString('item')?.toString() || '{}')
 const tabIndex = shallowRef(0)
 const selectedRow = shallowRef<Model.TjmdTradeOrderDetailRsp>()
 const error = shallowRef(false)
 const dataList = shallowRef<Model.TjmdTradeOrderDetailRsp[]>([])
+const quote = futuresStore.getQuoteInfo(item.refgoodscode)
 
 const { pageIndex, loading, run, pageCount } = useRequest(queryTjmdTradeOrderDetail, {
     params: {

+ 13 - 5
src/packages/mobile/views/swap/list/Index.vue

@@ -3,10 +3,7 @@
         <template #header>
             <app-navbar title="掉期贸易" :show-back-button="false" />
         </template>
-        <app-list :columns="columns" :data-list="tableList">
-            <template #goodsname="{ row }">
-                <span @click="$router.push({ name: 'swap-detail', params: { item: JSON.stringify(row) } })">{{ row.goodsname }}</span>
-            </template>
+        <app-list :columns="columns" :data-list="tableList" @row-click="rowClick">
             <!-- 当前价 -->
             <template #last="{ row }">
                 <span :class="row.lastColor">{{ row.last }}</span>
@@ -40,11 +37,13 @@ import { computed } from 'vue'
 import { v4 } from 'uuid'
 import { parsePercent, handleNumberValue } from '@/filters'
 import { useRequest } from '@/hooks/request'
+import { useNavigation } from '@/hooks/navigation'
 import { queryQuoteGoodsList } from '@/services/api/swap'
 import { useFuturesStore, useUserStore } from '@/stores'
 import quoteSocket from '@/services/websocket/quote'
 import AppList from '@mobile/components/base/list/index.vue'
 
+const { router } = useNavigation()
 const futuresStore = useFuturesStore()
 const userStore = useUserStore()
 const subscribeId = v4()
@@ -56,7 +55,7 @@ const { dataList } = useRequest(queryQuoteGoodsList, {
     },
     onSuccess: (res) => {
         const goodsCodes = res.data.map((e) => e.refgoodscode)
-        const subscribe = quoteSocket.addSubscribe(goodsCodes,  subscribeId)
+        const subscribe = quoteSocket.addSubscribe(goodsCodes, subscribeId)
         subscribe.start()
     }
 })
@@ -95,4 +94,13 @@ const columns: Model.TableColumn[] = [
     { prop: 'highest', label: '最高' },
     { prop: 'amplitude', label: '振幅' },
 ]
+
+const rowClick = (row: Model.QuoteGoodsListRsp) => {
+    router.push({
+        name: 'swap-detail',
+        params: {
+            item: JSON.stringify(row)
+        }
+    })
+}
 </script>

+ 2 - 3
src/packages/mobile/views/transfer/delisting/Index.vue

@@ -1,14 +1,13 @@
 <template>
     <app-view>
         <template #header>
-            <app-navbar title="转让列表" />
+            <app-navbar :title="detail ? `${detail.goodscode}/${detail.goodsname}` : '转让列表'" />
         </template>
-        <div v-if="detail">{{ detail.goodsname }}</div>
         <app-pull-refresh ref="pullRefreshRef" v-model:loading="loading" v-model:error="error" v-model:pageIndex="pageIndex"
             :page-count="pageCount" @refresh="run">
             <app-list :columns="columns" :data-list="dataList">
                 <template #operate="{ row }">
-                    <Button type="primary" size="small" round @click="delisting(row)">买入</Button>
+                    <Button type="primary" size="small" round @click="delisting(row)" style="width: 1.2rem;">买入</Button>
                 </template>
             </app-list>
         </app-pull-refresh>

+ 27 - 9
src/packages/mobile/views/transfer/delisting/components/delisting/index.vue

@@ -5,7 +5,7 @@
                 <app-navbar title="买入" @back="closed" />
             </template>
             <Form ref="formRef" class="g-form__container" @submit="onSubmit">
-                <CellGroup title="买入信息" inset>
+                <CellGroup inset>
                     <Field label="预售价">
                         <template #input>
                             <span>{{ detail.presaleprice }}</span>
@@ -13,7 +13,7 @@
                     </Field>
                     <Field label="转让定金比例">
                         <template #input>
-                            <span>{{ detail.transferdepositratio }}</span>
+                            <span>{{ parsePercent(detail.transferdepositratio) }}</span>
                         </template>
                     </Field>
                     <Field label="订单量">
@@ -32,6 +32,16 @@
                                 integer />
                         </template>
                     </Field>
+                    <Field label="定金">
+                        <template #input>
+                            <span>{{ deposit }}</span>
+                        </template>
+                    </Field>
+                    <Field label="差价">
+                        <template #input>
+                            <span>{{ spread }}</span>
+                        </template>
+                    </Field>
                 </CellGroup>
             </Form>
             <template #footer>
@@ -44,9 +54,10 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef, PropType } from 'vue'
+import { shallowRef, PropType, computed } from 'vue'
 import { CellGroup, Form, Field, Stepper, Button, FieldRule, FormInstance } from 'vant'
 import { fullloading, dialog } from '@/utils/vant'
+import { parsePercent } from '@/filters'
 import { useOrder } from '@/business/trade'
 import AppModal from '@/components/base/modal/index.vue'
 import { BuyOrSell } from '@/constants/order'
@@ -70,12 +81,6 @@ const showModal = shallowRef(true)
 
 // 表单验证规则
 const formRules: { [key in keyof Proto.OrderReq]?: FieldRule[] } = {
-    OrderPrice: [{
-        message: '请输入价格',
-        validator: () => {
-            return !!formData.OrderPrice
-        }
-    }],
     OrderQty: [{
         message: '请输入数量',
         validator: () => {
@@ -84,6 +89,19 @@ const formRules: { [key in keyof Proto.OrderReq]?: FieldRule[] } = {
     }],
 }
 
+// 定金
+const deposit = computed(() => {
+    const amount = props.detail.presaleprice * props.detail.transferdepositratio
+    return amount.toFixed(2)
+})
+
+// 差价
+const spread = computed(() => {
+    const price = props.selectedRow.orderprice - props.detail.presaleprice
+    const amount = price * (formData.OrderQty ?? 0)
+    return amount.toFixed(2)
+})
+
 // 关闭弹窗
 const closed = (isRefresh = false) => {
     refresh.value = isRefresh

+ 34 - 18
src/packages/mobile/views/transfer/detail/Index.vue

@@ -8,20 +8,29 @@
                 <img :src="url" />
             </SwipeItem>
         </Swipe>
-        <div class="g-detail__info" v-if="detail">
-            <div class="pricebar">
-                <div class="pricebar-left">
-                    <span class="tag">最新价</span>
-                    <span class="unit">¥</span>
-                    <span class="price">{{ getQuotePrice(detail.goodscode) }}</span>
-                </div>
-                <div class="pricebar-right">
-                    <span>订货价:{{ detail.presaleprice.toFixed(2) }}</span>
-                </div>
+        <div class="g-detail__buy" v-if="detail">
+            <div class="title">
+                <span>{{ detail.goodscode }}/{{ detail.goodsname }}</span>
             </div>
-            <div class="titlebar">
-                <span>{{ detail.sellname }}</span>
-                <span>{{ detail.goodsname }}</span>
+            <div class="info">
+                <ul>
+                    <li>
+                        <span>发售方</span>
+                        <span>{{ detail.sellname }}</span>
+                    </li>
+                    <li>
+                        <span>订货价</span>
+                        <span>¥{{ detail.presaleprice.toFixed(2) }}</span>
+                    </li>
+                    <li>
+                        <span>最新价</span>
+                        <span>¥{{ getQuotePrice(detail.goodscode) }}</span>
+                    </li>
+                    <li>
+                        <span>转让比例</span>
+                        <span>{{ parsePercent(detail.transferdepositratio) }}</span>
+                    </li>
+                </ul>
             </div>
         </div>
         <div class="g-detail__desc">
@@ -31,9 +40,16 @@
         </div>
         <template #footer>
             <div class="g-detail__footer">
-                <Button type="warning" block round @click="openComponent('listing')" v-if="dataList.length">转让</Button>
-                <Button type="primary" block round
-                    @click="$router.push({ name: 'transfer-delisting', query: { goodsid } })">买入</Button>
+                <div class="price" v-if="detail">
+                    <span class="price-text">订货价:</span>
+                    <span class="price-unit">¥</span>
+                    <span class="price-integer">{{ detail.presaleprice.toFixed(2) }}</span>
+                </div>
+                <div class="submit">
+                    <span class="submit-button warning" @click="openComponent('listing')" v-if="dataList.length">转让</span>
+                    <span class="submit-button danger"
+                        @click="$router.push({ name: 'transfer-delisting', query: { goodsid } })">买入</span>
+                </div>
             </div>
             <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ selectedRow: dataList[0] }"
                 @closed="closeComponent" v-if="componentId" />
@@ -43,8 +59,8 @@
 
 <script lang="ts" setup>
 import { computed, defineAsyncComponent } from 'vue'
-import { Swipe, SwipeItem, Button } from 'vant'
-import { getFileUrl } from '@/filters'
+import { Swipe, SwipeItem } from 'vant'
+import { getFileUrl, parsePercent } from '@/filters'
 import { useRequest } from '@/hooks/request'
 import { queryPresaleDefault, queryMineTradePositionExs } from '@/services/api/transfer'
 import { useComponent } from '@/hooks/component'

+ 71 - 59
src/packages/mobile/views/transfer/detail/index.less

@@ -15,74 +15,40 @@
         }
     }
 
-    &__info {
+    &__buy {
         background-color: #fff;
-        border-bottom-left-radius: .2rem;
-        border-bottom-right-radius: .2rem;
-        padding: .32rem;
 
-        .pricebar {
-            display: flex;
-            justify-content: space-between;
-            align-items: center;
-
-            &-left {
-                color: red;
-
-                .tag {
-                    font-size: .24rem;
-                }
-
-                .price {
-                    font-size: .44rem;
-                }
-            }
-
-            &-right {
-                font-size: .24rem;
-                color: #999;
-            }
-        }
-
-        .tag {
-            margin-top: .24rem;
-        }
-
-        .titlebar {
-            font-size: .32rem;
+        .title {
+            font-size: .3rem;
             font-weight: bold;
-            margin-top: .2rem;
+            line-height: .48rem;
+            padding: .24rem;
+            padding-bottom: 0;
 
             span {
                 margin-right: .1rem;
             }
         }
 
-        .timebar {
-            display: flex;
-            justify-content: space-around;
-        }
-    }
-
-    &__cell {
-        background-color: #fff;
-        border-radius: .2rem;
-        margin-top: .24rem;
-        padding: .2rem .32rem;
+        .info {
+            background-color: #fff;
+            padding: .2rem;
 
-        ul {
-            li {
+            ul {
                 display: flex;
-                padding: .12rem;
-
-                span {
-                    &:first-child {
-                        width: 1.6rem;
-                        color: #999;
-                    }
-
-                    &:last-child {
-                        flex: 1;
+                flex-wrap: wrap;
+                font-size: .26rem;
+
+                li {
+                    display: flex;
+                    justify-content: space-between;
+                    width: 50%;
+                    padding: .08rem .24rem;
+
+                    span {
+                        &:first-child {
+                            color: #999;
+                        }
                     }
                 }
             }
@@ -95,8 +61,54 @@
 
     &__footer {
         display: flex;
-        gap: .2rem;
+        justify-content: space-between;
+        align-items: center;
+        height: .88rem;
         background-color: #fff;
-        padding: .12rem .24rem;
+
+        .price {
+            padding-left: .32rem;
+
+            &-text,
+            &-unit {
+                font-size: .24rem;
+            }
+
+            &-unit {
+                color: #f2270c;
+            }
+
+            &-integer {
+                font-size: .36rem;
+                color: #f2270c;
+            }
+        }
+
+        .submit {
+            align-self: stretch;
+            display: flex;
+            margin-left: auto;
+
+            &-button {
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                height: 100%;
+                min-width: 2rem;
+                font-weight: bold;
+                color: #fff;
+                padding: 0 .48rem;
+
+                &.warning {
+                    background-image: linear-gradient(to right, #ffd01e, #ff8917);
+                    background-color: #ff8a17;
+                }
+
+                &.danger {
+                    background-image: linear-gradient(to right, #ff6034, #ee0a24);
+                    background-color: #ee270a;
+                }
+            }
+        }
     }
 }

+ 3 - 1
src/packages/mobile/views/transfer/list/Index.vue

@@ -42,7 +42,9 @@ const columns: Model.TableColumn[] = [
 const rowClick = ({ goodsid }: Model.Futures) => {
     router.push({
         name: 'transfer-detail',
-        query: { goodsid }
+        query: {
+            goodsid
+        }
     })
 }
 

+ 3 - 3
src/stores/modules/futures.ts

@@ -138,12 +138,12 @@ export const useFuturesStore = defineStore(() => {
     }
 
     // 通过 goodscode 获取实时行情信息
-    const getQuoteInfo = (goodscode: string) => {
-        return computed(() => quoteList.value.find((e) => e.goodscode.toUpperCase() === goodscode.toUpperCase()))
+    const getQuoteInfo = (goodscode?: string) => {
+        return computed(() => quoteList.value.find((e) => e.goodscode.toUpperCase() === goodscode?.toUpperCase()))
     }
 
     // 通过 goodscode 获取实时行情报价
-    const getQuotePrice = (goodscode: string) => {
+    const getQuotePrice = (goodscode?: string) => {
         return computed(() => {
             const quote = getQuoteInfo(goodscode)
             return quote.value?.last ?? 0