li.shaoyi 3 سال پیش
والد
کامیت
18b122fb4c
45فایلهای تغییر یافته به همراه1325 افزوده شده و 317 حذف شده
  1. 48 6
      src/business/goods/index.ts
  2. 49 9
      src/business/trade/index.ts
  3. 29 29
      src/components/base/modal/index.less
  4. 1 1
      src/hooks/navigation/index.ts
  5. BIN
      src/packages/mobile/assets/images/level-bg.png
  6. 34 0
      src/packages/mobile/components/base/popup/index.less
  7. 45 0
      src/packages/mobile/components/base/popup/index.vue
  8. 2 2
      src/packages/mobile/components/base/tabbar/index.vue
  9. 15 8
      src/packages/mobile/views/credit/signin/index.vue
  10. 18 8
      src/packages/mobile/views/home/components/main/index.less
  11. 35 21
      src/packages/mobile/views/home/components/main/index.vue
  12. 18 8
      src/packages/mobile/views/home/index.vue
  13. 14 12
      src/packages/mobile/views/mine/generalize/components/promotion/index.vue
  14. 14 13
      src/packages/mobile/views/mine/generalize/components/tradedata/index.vue
  15. 79 42
      src/packages/mobile/views/mine/generalize/index.less
  16. 93 22
      src/packages/mobile/views/mine/generalize/index.vue
  17. 41 41
      src/packages/mobile/views/mine/main/index.less
  18. 5 5
      src/packages/mobile/views/mine/main/index.vue
  19. 1 1
      src/packages/mobile/views/mine/order/detail/transfer/index.vue
  20. 4 3
      src/packages/mobile/views/mine/order/detail/wrorder/index.vue
  21. 1 4
      src/packages/mobile/views/mine/order/detail/wrtrade/index.vue
  22. 1 1
      src/packages/mobile/views/mine/order/list/components/purchasetrade/index.vue
  23. 10 3
      src/packages/mobile/views/mine/wareorder/components/listing/index.vue
  24. 0 2
      src/packages/mobile/views/mine/wareorder/wroutinapplydetail/index.vue
  25. 3 3
      src/packages/mobile/views/product/detail/index.vue
  26. 3 5
      src/packages/mobile/views/purchase/detail/index.vue
  27. 6 6
      src/packages/mobile/views/purchase/list/index.less
  28. 3 3
      src/packages/mobile/views/purchase/list/index.vue
  29. 15 20
      src/packages/mobile/views/rules/ptgz/index.vue
  30. 7 14
      src/packages/mobile/views/rules/yszc/index.vue
  31. 13 0
      src/packages/mobile/views/supply-demand/detail/components/delisting/index.less
  32. 163 0
      src/packages/mobile/views/supply-demand/detail/components/delisting/index.vue
  33. 13 0
      src/packages/mobile/views/supply-demand/detail/components/listing/index.less
  34. 159 0
      src/packages/mobile/views/supply-demand/detail/components/listing/index.vue
  35. 77 0
      src/packages/mobile/views/supply-demand/detail/index.less
  36. 153 2
      src/packages/mobile/views/supply-demand/detail/index.vue
  37. 6 6
      src/packages/mobile/views/supply-demand/list/index.less
  38. 8 8
      src/packages/mobile/views/supply-demand/list/index.vue
  39. 7 0
      src/services/api/common/index.ts
  40. 14 0
      src/services/api/goods/index.ts
  41. 1 1
      src/services/api/trade/index.ts
  42. 15 0
      src/types/model/common.d.ts
  43. 92 0
      src/types/model/goods.d.ts
  44. 2 0
      src/types/model/order.d.ts
  45. 8 8
      src/types/proto/trade.d.ts

+ 48 - 6
src/business/goods/index.ts

@@ -1,7 +1,8 @@
 import { shallowRef, reactive } from 'vue'
 import { useDataTable } from '@/hooks/datatable'
 import { EchartsDataset } from '@/hooks/echarts/line/interface'
-import { queryTHJWrstandard, queryTHJListing, queryWrMarketTradeConfig, queryTHJWrstandardDetail, addUserFavoriteGoods, removeUserFavoriteGoods, queryTHJProduct, queryMarketRun, queryTHJTradeData, querySpotGoodsPrice } from '@/services/api/goods'
+import { BuyOrSell } from '@/constants/order'
+import { queryTHJWrstandard, queryOrderQuote, queryOrderQuoteDetail, queryWrMarketTradeConfig, queryTHJWrstandardDetail, addUserFavoriteGoods, removeUserFavoriteGoods, queryTHJProduct, queryMarketRun, queryTHJTradeData, querySpotGoodsPrice } from '@/services/api/goods'
 import { useLoginStore } from '@/stores'
 
 // 采购列表
@@ -282,16 +283,17 @@ export function useQueryWrMarketTradeConfig() {
 }
 
 // 供求列表
-export function useListingList() {
-    const { dataList, total, pageIndex, pageSize, pageCount } = useDataTable<Model.THJListingRsp>()
+export function useOrderQuoteList() {
+    const { dataList, total, pageIndex, pageSize, pageCount } = useDataTable<Model.OrderQuoteRsp>()
     const loading = shallowRef(false)
 
-    const getListingList = async () => {
+    const getOrderQuoteList = async () => {
         loading.value = true
-        await queryTHJListing({
+        await queryOrderQuote({
             data: {
                 page: pageIndex.value,
                 pagesize: pageSize.value,
+                wrpricetype: 1,
             },
             success: (res) => {
                 total.value = res.total
@@ -311,6 +313,46 @@ export function useListingList() {
         pageIndex,
         pageSize,
         pageCount,
-        getListingList,
+        getOrderQuoteList,
+    }
+}
+
+// 供求详情
+export function useOrderQuoteDetail(wrfactortypeid?: string) {
+    const { dataList, total, pageIndex, pageSize, pageCount } = useDataTable<Model.OrderQuoteDetailRsp>()
+    const loading = shallowRef(false)
+
+    const getOrderQuoteList = async (buyorsell: BuyOrSell) => {
+        if (wrfactortypeid) {
+            loading.value = true
+            await queryOrderQuoteDetail({
+                data: {
+                    page: pageIndex.value,
+                    pagesize: pageSize.value,
+                    wrpricetype: 1,
+                    haswr: 1,
+                    wrfactortypeid,
+                    buyorsell,
+                },
+                success: (res) => {
+                    total.value = res.total
+                    dataList.value = res.data
+                },
+                complete: () => {
+                    loading.value = false
+                }
+            })
+        }
+        return dataList.value
+    }
+
+    return {
+        loading,
+        dataList,
+        total,
+        pageIndex,
+        pageSize,
+        pageCount,
+        getOrderQuoteList,
     }
 }

+ 49 - 9
src/business/trade/index.ts

@@ -12,10 +12,12 @@ import {
     spotPresaleDeliveryConfirm,
     wrOutApply,
     spotPresaleBreachOfContractApply,
-    hdWROrder
+    hdWROrder,
+    hdWRDealOrder,
 } from '@/services/api/trade'
 import { formatDate } from "@/filters";
 import Long from 'long'
+import { BuyOrSell } from '@/constants/order'
 
 // 采购摘牌
 export function usePurchaseOrderDesting() {
@@ -303,10 +305,9 @@ export function useWrOutInApply(holdlb?: Model.HoldLBRsp) {
 }
 
 // 仓单明细挂牌请求接口
-export function useHdWROrder(holdlb?: Model.HoldLBRsp) {
+export function useHdWROrder() {
     const loading = shallowRef(false)
     const { getUserId, getFirstAccountId, getLoginId } = useLoginStore()
-    const { wrstandardid, subnum, deliverygoodsid, ladingbillid = '0', wrfactortypeid = '0' } = holdlb ?? {}
 
     const formData = reactive<Proto.HdWROrderReq>({
         Header: {
@@ -321,16 +322,11 @@ export function useHdWROrder(holdlb?: Model.HoldLBRsp) {
         AccountID: getFirstAccountId(),
         OperatorID: getLoginId(),
         ClientType: ClientType.Web,
-        BuyOrSell: 1,
+        BuyOrSell: BuyOrSell.Sell,
         WRPriceType: 1,
         MarginFlag: 0,
         TimevalidType: 4,
         HasWr: 1,
-        WRStandardID: wrstandardid,
-        DeliveryGoodsID: deliverygoodsid,
-        LadingBillId: Long.fromString(ladingbillid),
-        WRFactorTypeId: Long.fromString(wrfactortypeid),
-        SubNum: subnum,
         PerformanceTemplateID: -1,
     })
 
@@ -361,4 +357,48 @@ export function useHdWROrder(holdlb?: Model.HoldLBRsp) {
         listingSubmit,
         amount
     }
+}
+
+// 仓单摘牌
+export function useHdWRDealOrder() {
+    const loading = shallowRef(false)
+    const { getUserId, getFirstAccountId, getLoginId } = useLoginStore()
+
+    const formData = reactive<Proto.HdWRDealOrderReq>({
+        UserID: getUserId(), // 用户ID
+        AccountID: getFirstAccountId(), // 资金账号
+        RelatedWRTradeOrderID: Long.fromNumber(0), // 关联委托单号(摘牌委托关联挂牌委托单ID)
+        WRTransferUserID: getUserId(), // 仓单受让用户
+        OrderQty: 0, // 委托数量
+        OrderSrc: OrderSrc.ORDERSRC_CLIENT, // 委托来源
+        ClientSerialNo: '', // 客户端流水号
+        ClientOrderTime: '', // 客户端委托时间
+        ClientType: ClientType.Web, // 终端类型
+        OperatorID: getLoginId(), // 操作员账号ID
+        TradeDate: '', // 交易日
+        HasWr: 1, // 是否有仓单-0:没有仓单1:有仓单
+        IsFinancing: 0, // 是否融资购买(买摘牌时有效)-0:否1:是
+    })
+
+    const formSubmit = () => {
+        const date = new Date().toISOString()
+        loading.value = true
+        return hdWRDealOrder({
+            data: {
+                ...formData,
+                TradeDate: formatDate(date, 'YYYYMMDD'),
+                ClientSerialNo: v4(),
+                ClientOrderTime: formatDate(date),
+            },
+            complete: () => {
+                loading.value = false
+            }
+        })
+    }
+
+    return {
+        loading,
+        formData,
+        formSubmit,
+    }
 }

+ 29 - 29
src/components/base/modal/index.less

@@ -1,18 +1,18 @@
 .app-modal {
-    top   : 0;
-    left  : 0;
-    width : 100%;
+    top: 0;
+    left: 0;
+    width: 100%;
     height: 100%;
 
     &__mask {
-        position             : absolute;
-        top                  : 0;
-        left                 : 0;
-        width                : 100%;
-        height               : 100%;
-        background-color     : rgba(0, 0, 0, .35);
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        background-color: rgba(0, 0, 0, .5);
         //backdrop-filter    : blur(2px);
-        transition-property  : opacity;
+        transition-property: opacity;
 
         &:not(.is-show) {
             opacity: 0;
@@ -20,33 +20,33 @@
     }
 
     &__wrapper {
-        position : relative;
-        z-index  : 1;
-        display  : flex;
+        position: relative;
+        z-index: 1;
+        display: flex;
         flex-wrap: wrap;
-        height   : 100%;
-        overflow : hidden;
+        height: 100%;
+        overflow: hidden;
     }
 
     &__container {
-        max-width : 100vw;
+        max-width: 100vw;
         max-height: 100vh;
     }
 
     /* 全屏 */
     &__wrapper.full {
         justify-content: center;
-        align-items    : center;
+        align-items: center;
     }
 
     &__wrapper.full &__container {
-        width              : 100%;
-        height             : 100%;
-        border-radius      : 0;
+        width: 100%;
+        height: 100%;
+        border-radius: 0;
         transition-property: transform, opacity;
 
         &:not(.is-show) {
-            opacity  : .5;
+            opacity: .5;
             transform: scale(0);
         }
     }
@@ -54,14 +54,14 @@
     /* 居中 */
     &__wrapper.center {
         justify-content: center;
-        align-items    : center;
+        align-items: center;
     }
 
     &__wrapper.center &__container {
         transition-property: transform, opacity;
 
         &:not(.is-show) {
-            opacity  : 0;
+            opacity: 0;
             transform: translate3d(0, -15%, 0);
         }
     }
@@ -69,7 +69,7 @@
     /* 上 */
     &__wrapper.top {
         flex-direction: column;
-        align-items   : center;
+        align-items: center;
     }
 
     &__wrapper.top &__container:not(.is-show) {
@@ -78,9 +78,9 @@
 
     /* 下 */
     &__wrapper.bottom {
-        flex-direction : column;
+        flex-direction: column;
         justify-content: flex-end;
-        align-items    : center;
+        align-items: center;
     }
 
     &__wrapper.bottom &__container:not(.is-show) {
@@ -109,19 +109,19 @@
     /* 右 */
     &__wrapper.right {
         justify-content: flex-end;
-        align-items    : center;
+        align-items: center;
     }
 
     /* 右上 */
     &__wrapper.right-top {
         justify-content: flex-end;
-        align-items    : flex-start;
+        align-items: flex-start;
     }
 
     /* 右下 */
     &__wrapper.right-bottom {
         justify-content: flex-end;
-        align-items    : flex-end;
+        align-items: flex-end;
     }
 
     &__wrapper[class*='right'] &__container:not(.is-show) {

+ 1 - 1
src/hooks/navigation/index.ts

@@ -6,7 +6,7 @@ export function useNavigation() {
     const router = useRouter()
 
     // 缓存全局Url参数
-    const setGlobalUrlParams = (params: unknown) => {
+    const setGlobalUrlParams = <T extends object>(params: T) => {
         sessionStorage.setItem('globalUrlParams', JSON.stringify(params))
     }
 

BIN
src/packages/mobile/assets/images/level-bg.png


+ 34 - 0
src/packages/mobile/components/base/popup/index.less

@@ -0,0 +1,34 @@
+.app-popup {
+    .app-modal__container {
+        border-radius: var(--van-popup-round-border-radius) var(--van-popup-round-border-radius) 0 0;
+        overflow: hidden;
+    }
+
+    &__header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        background-color: #fff;
+        padding: .32rem;
+        padding-bottom: 0;
+
+        .title {
+            font-size: .32rem;
+            font-weight: bold;
+        }
+    }
+
+    &__container {
+        background-color: #fff;
+        padding: .2rem;
+    }
+
+    &__footer {
+        background-color: #fff;
+        padding-top: .48rem;
+
+        &:empty {
+            display: none;
+        }
+    }
+}

+ 45 - 0
src/packages/mobile/components/base/popup/index.vue

@@ -0,0 +1,45 @@
+<template>
+    <app-modal class="app-popup" :show="show" direction="bottom" width="100%" @mask="closed">
+        <app-view class="g-form">
+            <template #header>
+                <slot name="header">
+                    <div class="app-popup__header">
+                        <div class="title">{{ title }}</div>
+                        <Icon name="close" size=".36rem" @click="closed" />
+                    </div>
+                </slot>
+            </template>
+            <div class="app-popup__container">
+                <slot></slot>
+            </div>
+            <template #footer>
+                <div class="g-form__footer app-popup__footer">
+                    <slot name="footer"></slot>
+                </div>
+            </template>
+        </app-view>
+    </app-modal>
+</template>
+
+<script lang="ts" setup>
+import { Icon } from 'vant'
+import AppModal from '@/components/base/modal/index.vue'
+
+defineProps({
+    show: {
+        type: Boolean,
+        default: false
+    },
+    title: String
+})
+
+const emit = defineEmits(['update:show'])
+
+const closed = () => {
+    emit('update:show', false)
+}
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 2 - 2
src/packages/mobile/components/base/tabbar/index.vue

@@ -62,11 +62,11 @@ const onChange = (index: number) => {
   if (selectedIndex.value !== index) {
     selectedIndex.value = index
     emit('update:dataIndex', index)
-    emit('change', index, props.dataList[index])
+    emit('change', props.dataList[index], index)
   }
 }
 
-watch(() => props.dataIndex, (val) => selectedIndex.value = val)
+watch(() => props.dataIndex, (val) => onChange(val))
 </script>
 
 <style lang="less" scoped>

+ 15 - 8
src/packages/mobile/views/credit/signin/index.vue

@@ -44,6 +44,12 @@
                 </dd>
                 <dd class="list-item">
                     <div class="list-item__title">
+                        <app-iconfont class="icon-title" icon="icon-haoyouxiadan">好友下单每次</app-iconfont>
+                        <app-iconfont class="icon-score" icon="icon-jifenyue">+{{ getScoreConfig(4) }}</app-iconfont>
+                    </div>
+                </dd>
+                <dd class="list-item">
+                    <div class="list-item__title">
                         <app-iconfont class="icon-title" icon="icon-yaoqingxinrenzhuce">邀请新人注册</app-iconfont>
                         <app-iconfont class="icon-score" icon="icon-jifenyue">+{{ getScoreConfig(3) }}</app-iconfont>
                     </div>
@@ -53,17 +59,11 @@
                 </dd>
                 <dd class="list-item">
                     <div class="list-item__title">
-                        <app-iconfont class="icon-title" icon="icon-haoyouxiadan">好友下单每次</app-iconfont>
-                        <app-iconfont class="icon-score" icon="icon-jifenyue">+{{ getScoreConfig(4) }}</app-iconfont>
-                    </div>
-                </dd>
-                <dd class="list-item">
-                    <div class="list-item__title">
                         <app-iconfont class="icon-title" icon="icon-caigouxiadan">采购下单每次</app-iconfont>
                         <app-iconfont class="icon-score" icon="icon-jifenyue">+{{ getScoreConfig(5) }}</app-iconfont>
                     </div>
                     <div class="list-item__button">
-                        <Button type="primary" round>去完成</Button>
+                        <Button type="primary" round @click="toPurchase">去完成</Button>
                     </div>
                 </dd>
                 <dd class="list-item">
@@ -92,7 +92,7 @@ import { useNavigation } from '@/hooks/navigation'
 import AppIconfont from '@mobile/components/base/iconfont/index.vue'
 
 const { getUserId } = useLoginStore()
-const { routerTo } = useNavigation()
+const { routerTo, backTo } = useNavigation()
 const headerRef = shallowRef<HTMLDivElement>()
 const userAccount = shallowRef<Partial<Model.UserAccount>>({})
 const scoreConfig = shallowRef<Model.THJScoreConfigRsp[]>([])
@@ -108,6 +108,13 @@ const getScoreConfig = (value: number) => {
     return item?.parma1 ?? 0
 }
 
+// 跳转到采购
+const toPurchase = () => {
+    backTo('Home', {
+        tabName: 'purchase'
+    })
+}
+
 const userSignin = () => {
     fullloading(() => {
         signin({

+ 18 - 8
src/packages/mobile/views/home/components/main/index.less

@@ -103,16 +103,26 @@
         .right {
             flex: 1;
             padding: 0 .24rem;
+            height: 2rem;
 
-            table {
-                width: 100%;
-                font-size: .24rem;
+            .van-swipe {
+                height: 100%;
 
-                tr {
-                    td {
-                        line-height: .4rem;
-                        width: 25%;
-                        text-align: center;
+                &-item {
+                    display: flex;
+                    align-items: center;
+
+                    table {
+                        width: 100%;
+                        font-size: .24rem;
+
+                        tr {
+                            td {
+                                line-height: .4rem;
+                                width: 25%;
+                                text-align: center;
+                            }
+                        }
                     }
                 }
             }

+ 35 - 21
src/packages/mobile/views/home/components/main/index.vue

@@ -5,7 +5,7 @@
     </template>
     <PullRefresh class="home-main__container" v-model="refreshing" @refresh="onRefresh">
       <div class="home-main__banner home-main__banner--header">
-        <Swipe :autoplay="3000" indicator-color="white" lazy-render>
+        <Swipe :autoplay="5000" indicator-color="white" lazy-render>
           <SwipeItem v-for="(item, index) in topBanners" :key="index">
             <img :src="getImageUrl(item.imagepath)" />
           </SwipeItem>
@@ -41,20 +41,24 @@
           <span>{{ formatDate(marketRun.tradedate, "YYYY-MM-DD") }}</span>
         </div>
         <div class="right">
-          <table cellspacing="0" cellpadding="0">
-            <tbody>
-              <tr v-for="(item, index) in dataList" :key="index">
-                <td>{{ item.wrstandardname }}</td>
-                <td>{{ handleNumberValue(item.prespotgoodsprice) }}</td>
-                <td>{{ handleNumberValue(item.todayspotgoodsprice) }}</td>
-                <td>{{ parsePercent(item.chg) }}</td>
-              </tr>
-            </tbody>
-          </table>
+          <Swipe :autoplay="10 * 1000" :show-indicators="false" vertical>
+            <SwipeItem v-for="(items, i) in groupList" :key="i">
+              <table cellspacing="0" cellpadding="0">
+                <tbody>
+                  <tr v-for="(item, n) in items" :key="i + n">
+                    <td>{{ item.wrstandardname }}</td>
+                    <td>{{ handleNumberValue(item.prespotgoodsprice) }}</td>
+                    <td>{{ handleNumberValue(item.todayspotgoodsprice) }}</td>
+                    <td>{{ parsePercent(item.chg) }}</td>
+                  </tr>
+                </tbody>
+              </table>
+            </SwipeItem>
+          </Swipe>
         </div>
       </div>
       <div class="home-main__banner home-main__banner--body">
-        <Swipe :autoplay="3000" indicator-color="white" lazy-render>
+        <Swipe :autoplay="5000" indicator-color="white" lazy-render>
           <SwipeItem v-for="(item, index) in bodyBanners" :key="index">
             <img :src="getImageUrl(item.imagepath)" />
           </SwipeItem>
@@ -76,7 +80,7 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef } from 'vue'
+import { shallowRef, computed } from 'vue'
 import { Cell, CellGroup, Swipe, SwipeItem, PullRefresh } from 'vant'
 import { getImageUrl, formatDate, parsePercent, handleNumberValue } from '@/filters'
 import { useNavigation } from '@/hooks/navigation'
@@ -87,17 +91,33 @@ import { queryMarketRun } from '@/services/api/goods'
 import AppIconfont from '@mobile/components/base/iconfont/index.vue'
 
 const { routerTo } = useNavigation()
+const { dataList, getQuerySpotGoodsPriceLists } = useQuerySpotGoodsPriceLists()
 const refreshing = shallowRef(false) // 是否处于加载中状态
 const topBanners = shallowRef<Model.ImageConfigsRsp[]>([])   // 轮播图列表
 const bodyBanners = shallowRef<Model.ImageConfigsRsp[]>([])  // 轮播图列表
 const newsList = shallowRef<Model.SiteColumnDetailRsp[]>([]) // 资讯列表
 const marketRun = shallowRef<Partial<Model.MarketRunRsp>>({})         // 市场
 
-const { dataList, getQuerySpotGoodsPriceLists } = useQuerySpotGoodsPriceLists()
-getQuerySpotGoodsPriceLists()
+// 合金指数组列表(4条记录为一组)
+const groupList = computed(() => {
+  const result: Model.SpotGoodsPriceRsp[][] = []
+  for (let i = 0; i < dataList.value.length; i += 4) {
+    result.push(dataList.value.slice(i, i + 4))
+  }
+  return result
+})
 
 // 下拉刷新
 const onRefresh = () => {
+  // 合金指数
+  getQuerySpotGoodsPriceLists()
+  // 市场信息
+  queryMarketRun({
+    success: (res) => {
+      marketRun.value = res.data[0]
+    }
+  })
+  // 市场资讯
   querySiteColumnDetail({
     data: {
       page: 1,
@@ -130,12 +150,6 @@ queryImageConfigs({
   }
 })
 
-queryMarketRun({
-  success: (res) => {
-    marketRun.value = res.data[0]
-  }
-})
-
 onRefresh()
 </script>
 

+ 18 - 8
src/packages/mobile/views/home/index.vue

@@ -3,21 +3,22 @@
     <keep-alive>
       <component class="g-flex__body" :is="components[componentId]"></component>
     </keep-alive>
-    <app-tabbar class="home-tabbar" :data-list="tabList" @change="onChange" fixed />
+    <app-tabbar class="home-tabbar" v-model:dataIndex="tabIndex" :data-list="tabList" @change="onChange" fixed />
   </div>
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue'
+import { shallowRef, onActivated } from 'vue'
 import { dialog } from '@/utils/vant'
 import { Tabbar } from '@mobile/components/base/tabbar/interface'
 import { GetAppUpdateInfo } from '@/services/api/common'
+import { useNavigation } from '@/hooks/navigation'
 import plus from '@/utils/h5plus'
 import AppTabbar from '@mobile/components/base/tabbar/index.vue'
 import Home from './components/main/index.vue'
-import Purchase from './components/purchase/index.vue'
-import SupplyDemand from './components/supply-demand/index.vue'
-import Mine from './components/mine/index.vue'
+import Purchase from '@mobile/views/purchase/list/index.vue'
+import SupplyDemand from '@mobile/views/supply-demand/list/index.vue'
+import Mine from '@mobile/views/mine/main/index.vue'
 
 const components = {
   home: Home,
@@ -26,7 +27,9 @@ const components = {
   mine: Mine
 }
 
-const componentId = ref('home')
+const { getGlobalUrlParams } = useNavigation()
+const componentId = shallowRef('home')
+const tabIndex = shallowRef(0)
 
 const tabList: Tabbar[] = [
   {
@@ -55,10 +58,17 @@ const tabList: Tabbar[] = [
   }
 ]
 
-const onChange = (index: number) => {
-  componentId.value = tabList[index].name
+const onChange = (item: Tabbar) => {
+  componentId.value = item.name
 }
 
+onActivated(() => {
+  const { tabName } = getGlobalUrlParams()
+  if (tabName) {
+    tabIndex.value = tabList.findIndex((e) => e.name === tabName)
+  }
+})
+
 // 获取当前应用版本号
 plus.getVersionCode((currentVersionCode) => {
   // 获取应用更新信息

+ 14 - 12
src/packages/mobile/views/mine/generalize/components/promotion/index.vue

@@ -1,8 +1,6 @@
 <template>
-    <app-pull-refresh ref="pullRefreshRef" v-model:error="error" v-model:pageIndex="pageIndex" :page-count="pageCount" @refresh="onRefresh">
-        <DropdownMenu>
-            <DropdownItem v-model="type" :options="options" @change="onChange"></DropdownItem>
-        </DropdownMenu>
+    <app-pull-refresh ref="pullRefreshRef" v-model:error="error" v-model:pageIndex="pageIndex" :page-count="pageCount"
+        @refresh="onRefresh" disabled>
         <app-list :columns="columns" :data-list="dataList" v-if="dataList.length" @click="onClick">
             <!-- 日期 -->
             <template #profitmonth="{ value }">
@@ -14,21 +12,26 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef } from 'vue'
+import { shallowRef, watch } from 'vue'
 import { formatDate } from '@/filters'
 import { useQueryTHJPromotionIncome } from '@/business/order'
 import AppPullRefresh from '@mobile/components/base/pull-refresh/index.vue'
 import AppList from '@mobile/components/base/list/index.vue'
-import { Empty, DropdownItem, DropdownMenu } from 'vant'
+import { Empty } from 'vant'
 import { useNavigation } from '@/hooks/navigation'
 
+const props = defineProps({
+    status: {
+        type: Number,
+        required: true
+    }
+})
+
 const { router } = useNavigation()
 const { pageIndex, pageCount, getTHJPromotionIncome } = useQueryTHJPromotionIncome()
 const dataList = shallowRef<Model.THJPromotionIncomeRsp[]>([])
 const error = shallowRef(false)
 
-const options = [ { text: '全部', value: 0 }, { text: '已支付', value: 1 }, { text: '未支付', value: 2 }]
-const type = shallowRef(0)
 /// 下拉刷新
 const pullRefreshRef = shallowRef()
 
@@ -43,7 +46,7 @@ const onClick = (item: Model.THJPromotionIncomeRsp) => {
 
 const onRefresh = (finish: () => void) => {
     /// 查询数据
-    getTHJPromotionIncome(type.value).then((res) => {
+    getTHJPromotionIncome(props.status).then((res) => {
         if (pageIndex.value === 1) {
             dataList.value = []
         }
@@ -55,10 +58,9 @@ const onRefresh = (finish: () => void) => {
     })
 }
 
-const onChange = () => {
-    /// 查询
+watch(() => props.status, () => {
     pullRefreshRef.value?.refresh()
-}
+})
 </script>
 
 <style lang="less">

+ 14 - 13
src/packages/mobile/views/mine/generalize/components/tradedata/index.vue

@@ -1,9 +1,6 @@
 <template>
     <app-pull-refresh ref="pullRefreshRef" v-model:error="error" v-model:pageIndex="pageIndex" :page-count="pageCount"
-        @refresh="onRefresh">
-        <DropdownMenu>
-            <DropdownItem v-model="type" :options="options" @change="onChange"></DropdownItem>
-        </DropdownMenu>
+        @refresh="onRefresh" disabled>
         <app-list :columns="columns" :data-list="dataList" v-if="dataList.length">
             <!-- 日期 -->
             <template #reckondate="{ value }">
@@ -11,7 +8,7 @@
             </template>
             <!-- 市场 -->
             <template #marketid>
-                {{ type === 0 ? '采购' : '供求' }}
+                {{ marketid === Market.THJ ? '采购' : '供求' }}
             </template>
             <!-- 吨数 -->
             <template #tradeqty="{ row }">
@@ -23,14 +20,21 @@
 </template>
 
 <script lang="ts" setup>
-import { shallowRef } from 'vue'
+import { shallowRef, watch } from 'vue'
 import { formatDate } from '@/filters'
 import { useQueryTHJTradeDataList } from '@/business/goods'
 import { Market } from '@/constants/market'
-import { Empty, DropdownItem, DropdownMenu } from 'vant'
+import { Empty } from 'vant'
 import AppPullRefresh from '@mobile/components/base/pull-refresh/index.vue'
 import AppList from '@mobile/components/base/list/index.vue'
 
+const props = defineProps({
+    marketid: {
+        type: Number,
+        required: true
+    }
+})
+
 const { pageIndex, pageCount, getQueryTHJTradeDataList } = useQueryTHJTradeDataList()
 const dataList = shallowRef<Model.THJTradeDataRsp[]>([])
 const error = shallowRef(false)
@@ -44,14 +48,12 @@ const columns: Model.TableColumn[] = [
     { prop: 'selltradelot', label: '笔数' },
 ]
 
-const options = [{ text: '采购', value: 0 }, { text: '供求', value: 1 }]
-const type = shallowRef(0)
 /// 下拉刷新
 const pullRefreshRef = shallowRef()
 
 const onRefresh = (finish: () => void) => {
     /// 查询数据
-    getQueryTHJTradeDataList(type.value === 0 ? Market.THJ : Market.THJ_Listing).then((res) => {
+    getQueryTHJTradeDataList(props.marketid).then((res) => {
         if (pageIndex.value === 1) {
             dataList.value = []
         }
@@ -63,10 +65,9 @@ const onRefresh = (finish: () => void) => {
     })
 }
 
-const onChange = () => {
-    /// 查询
+watch(() => props.marketid, () => {
     pullRefreshRef.value?.refresh()
-}
+})
 </script>
 
 <style lang="less">

+ 79 - 42
src/packages/mobile/views/mine/generalize/index.less

@@ -1,55 +1,92 @@
 .mine-generalize {
+    background-color: #fff;
 
     &__header {
-        background-color: #fff;
-        margin-bottom   : .2rem;
+        margin-bottom: .2rem;
 
-        .info {
-            text-align : center;
-            padding-top: .48rem;
-
-            h4 {
-                font-size: .32rem;
-                color    : #666;
-            }
+        .rank {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            padding: .32rem 0;
+
+            &-container {
+                width: 7rem;
+                height: 3.56rem;
+                color: #fff;
+                background: url('@mobile/assets/images/level-bg.png') no-repeat;
+                background-size: 100%;
+
+                &__level {
+                    padding: .64rem;
+
+                    h1 {
+                        font-size: .48rem;
+                        font-weight: bold;
+                    }
+
+                    span {
+                        font-size: .24rem;
+                        color: rgba(255, 255, 255, .6);
+                    }
+                }
 
-            span {
-                display  : block;
-                font-size: .6rem;
+                &__next {
+                    padding: 0 1.4rem;
+
+                    .upgrade {
+                        display: flex;
+                        justify-content: flex-end;
+                        align-items: center;
+                        margin-bottom: .2rem;
+
+                        &-left {
+                            font-size: .36rem;
+                            font-weight: bold;
+                            margin-right: 1.2rem;
+                        }
+
+                        &-right {
+                            font-size: .24rem;
+                        }
+                    }
+                }
             }
         }
 
-        .block {
-            display: flex;
-            padding: .48rem .32rem;
+        .info {
+            padding: .48rem 0;
 
-            &-left,
-            &-right {
-                flex      : 1;
+            ul {
+                display: flex;
                 text-align: center;
 
-                h4 {
-                    font-size    : .32rem;
-                    color        : #999;
-                    margin-bottom: .16rem;
-                }
+                li {
+                    flex: 1;
 
-                span {
-                    display    : block;
-                    font-size  : .44rem;
-                    font-weight: bold;
-                }
-            }
+                    &:not(:first-child) {
+                        border-left: 1px solid #ededed;
+                    }
+
+                    h4 {
+                        font-size: .28rem;
+                        color: #999;
+                        margin-bottom: .16rem;
+                    }
 
-            &-left {
-                border-right: 1px solid #d8d8d8;
+                    span {
+                        display: block;
+                        font-size: .36rem;
+                        font-weight: bold;
+                    }
+                }
             }
         }
     }
 
     &__tabs {
-        flex          : 1;
-        display       : flex;
+        flex: 1;
+        display: flex;
         flex-direction: column;
 
         .van-tabs__content {
@@ -62,24 +99,24 @@
     }
 
     &__container {
-        height    : 100%;
+        height: 100%;
         overflow-y: auto;
 
         .list {
-            display    : flex;
+            display: flex;
             align-items: center;
 
             &-row {
-                font-size    : .32rem;
+                font-size: .32rem;
                 border-bottom: 1px solid #eee;
-                padding      : .12rem .32rem;
+                padding: .12rem .32rem;
             }
 
             &-column {
-                flex          : 1;
-                display       : flex;
+                flex: 1;
+                display: flex;
                 flex-direction: column;
-                text-align    : center;
+                text-align: center;
 
                 &:first-child {
                     text-align: left;
@@ -90,7 +127,7 @@
                 }
 
                 span:last-child {
-                    color    : #999;
+                    color: #999;
                     font-size: .24rem;
                 }
             }

+ 93 - 22
src/packages/mobile/views/mine/generalize/index.vue

@@ -1,59 +1,121 @@
 <template>
-    <app-view class="mine-generalize" flex>
+    <app-view class="mine-generalize">
         <template #header>
             <app-navbar title="我的推广" />
         </template>
         <div class="mine-generalize__header">
-            <div class="info">
-                <span>{{ userAccount.refercount }}</span>
-                <h4>推广人数</h4>
-            </div>
-            <div class="block">
-                <div class="block-left">
-                    <h4>当日新增</h4>
-                    <span>{{ userAccount.todayrefercount }}</span>
-                </div>
-                <div class="block-right">
-                    <h4>推广编号</h4>
-                    <span @click="showQRCode = true">{{ userAccount.refernum }}</span>
+            <div class="rank" v-if="userLevelInfo">
+                <div class="rank-container">
+                    <div class="rank-container__level">
+                        <h1>{{ userLevelInfo.levelgroup }}</h1>
+                        <span>{{ userLevelInfo.checkday }}到期</span>
+                    </div>
+                    <div class="rank-container__next">
+                        <div class="upgrade">
+                            <div class="upgrade-left">
+                                <span>{{ userLevelInfo.appup }}</span>
+                            </div>
+                            <div class="upgrade-right">
+                                <span>距</span>
+                                <span>{{ userLevelInfo.nextlevelgroup }}</span>
+                                <span>还需</span>
+                                <span>{{ userLevelInfo.notyet }}</span>
+                            </div>
+                        </div>
+                        <Progress :percentage="userLevelInfo.progress * 100" :show-pivot="false" color="#fff"
+                            track-color="rgba(255,255,255,.35)" />
+                    </div>
                 </div>
             </div>
+            <div class="info">
+                <ul>
+                    <li>
+                        <h4>推广人数</h4>
+                        <span>{{ userAccount.refercount }}</span>
+                    </li>
+                    <li>
+                        <h4>当日新增</h4>
+                        <span>{{ userAccount.todayrefercount }}</span>
+                    </li>
+                    <li>
+                        <h4>推广编号</h4>
+                        <span @click="showQRCode = true">{{ userAccount.refernum }}</span>
+                    </li>
+                </ul>
+            </div>
+            <DropdownMenu>
+                <DropdownItem v-model="selectedMenu" :options="dropdownMenus" @change="onMenuChange" />
+                <DropdownItem v-model="selectedType" :options="dropdownTypes" />
+            </DropdownMenu>
         </div>
-        <Tabs class="mine-generalize__tabs">
-            <Tab title="交易数据">
-                <trade-data></trade-data>
-            </Tab>
-            <Tab title="推广收益">
-                <promotion></promotion>
-            </Tab>
-        </Tabs>
+        <trade-data :marketid="selectedType" v-if="selectedMenu === 0" />
+        <promotion :status="selectedType" v-if="selectedMenu === 1" />
         <app-qrcode v-model:show="showQRCode" :content="qrContent" :file-name="userAccount.refernum" />
     </app-view>
 </template>
 
 <script lang="ts" setup>
 import { shallowRef, computed } from 'vue'
-import { Tab, Tabs } from 'vant'
+import { DropdownItem, DropdownMenu, Progress } from 'vant'
 import { useLoginStore } from '@/stores'
+import { queryUserLevelInfo } from '@/services/api/common'
 import { queryUserAccount } from '@/services/api/account'
 import AppQrcode from '@mobile/components/base/qrcode/index.vue'
 import TradeData from './components/tradedata/index.vue'
 import Promotion from './components/promotion/index.vue'
 import { getServiceUrl } from '@/services/http'
+import { Market } from '@/constants/market'
 
 const { getUserId } = useLoginStore()
 const showQRCode = shallowRef(false)
+const selectedMenu = shallowRef(0)
+const selectedType = shallowRef(Market.THJ)
+const userLevelInfo = shallowRef<Model.UserLevelInfoRsp>()
 
 const userAccount = shallowRef<Partial<Model.UserAccount>>({
     todayrefercount: 0,
     refercount: 0,
 })
 
+const dropdownMenus = [
+    { text: '交易数据', value: 0 },
+    { text: '推广收益', value: 1 }
+]
+
+const dropdownTypes = computed(() => {
+    switch (selectedMenu.value) {
+        case 0: {
+            return [
+                { text: '采购', value: Market.THJ },
+                { text: '转让', value: 64202 },
+                { text: '供求', value: Market.THJ_Listing },
+            ]
+        }
+        case 1: {
+            return [
+                { text: '全部', value: 0 },
+                { text: '已支付', value: 1 },
+                { text: '未支付', value: 2 }
+            ]
+        }
+    }
+    return []
+})
+
 const qrContent = computed(() => {
     const url = getServiceUrl('mobileOpenUrl')
     return url + '/#/?code=' + userAccount.value.refernum
 })
 
+// 切换菜单
+const onMenuChange = () => {
+    if (selectedMenu.value === 0) {
+        selectedType.value = Market.THJ
+    } else {
+        selectedType.value = 0
+    }
+}
+
 queryUserAccount({
     data: {
         userID: getUserId()
@@ -62,6 +124,15 @@ queryUserAccount({
         userAccount.value = res.data
     }
 })
+
+queryUserLevelInfo({
+    data: {
+        userid: getUserId()
+    },
+    success: (res) => {
+        userLevelInfo.value = res.data
+    }
+})
 </script>
 
 <style lang="less">

+ 41 - 41
src/packages/mobile/views/home/components/mine/index.less → src/packages/mobile/views/mine/main/index.less

@@ -1,61 +1,61 @@
-.home-mine {
+.mine {
     @backgroundImage: linear-gradient(#1A84B0, #00587D 3rem, transparent 3rem);
 
     .app-navbar {
         background-image: @backgroundImage;
 
         &__wrapper {
-            color           : #fff;
+            color: #fff;
             background-color: transparent;
         }
     }
 
-    &__header {
-        color           : #000;
+    &-header {
+        color: #000;
         background-color: #fff;
         background-image: @backgroundImage;
-        padding         : 0 .36rem;
-        margin-bottom   : .2rem;
+        padding: 0 .36rem;
+        margin-bottom: .2rem;
 
-        &-wrapper {
-            background-color       : #fff;
-            border-top-left-radius : .2rem;
+        &__wrapper {
+            background-color: #fff;
+            border-top-left-radius: .2rem;
             border-top-right-radius: .2rem;
-            padding                : .24rem;
+            padding: .24rem;
         }
 
         .profile {
             display: flex;
 
             &-user {
-                flex       : 1;
-                display    : flex;
+                flex: 1;
+                display: flex;
                 align-items: center;
 
                 .g-image--avatar {
-                    width        : .8rem;
-                    height       : .8rem;
+                    width: .8rem;
+                    height: .8rem;
                     border-radius: 50%;
-                    font-size    : 0;
-                    margin-right : .16rem;
+                    font-size: 0;
+                    margin-right: .16rem;
                 }
 
                 &__info {
-                    flex          : 1;
-                    display       : flex;
+                    flex: 1;
+                    display: flex;
                     flex-direction: column;
 
                     >span {
                         line-height: .4rem;
-                        font-size  : .3rem;
+                        font-size: .3rem;
                         font-weight: bold;
                     }
                 }
             }
 
             &-account {
-                display        : flex;
-                flex-direction : column;
+                display: flex;
+                flex-direction: column;
                 justify-content: center;
 
                 span {
@@ -63,17 +63,17 @@
 
                     &:first-child {
                         font-size: .24rem;
-                        color    : #46D63C;
+                        color: #46D63C;
 
                         &::before {
-                            content     : '资金账户';
-                            color       : #A1B1C5;
+                            content: '资金账户';
+                            color: #A1B1C5;
                             margin-right: .12rem;
                         }
                     }
 
                     &:last-child {
-                        font-size  : .3rem;
+                        font-size: .3rem;
                         font-weight: bold;
                     }
                 }
@@ -81,12 +81,12 @@
         }
 
         .bank {
-            display        : flex;
+            display: flex;
             justify-content: space-around;
-            padding        : .48rem 0;
+            padding: .48rem 0;
 
             &-item {
-                display       : flex;
+                display: flex;
                 flex-direction: column;
 
                 span {
@@ -94,11 +94,11 @@
 
                     &:first-child {
                         font-size: .24rem;
-                        color    : #A1B1C5;
+                        color: #A1B1C5;
                     }
 
                     &:last-child {
-                        font-size  : .3rem;
+                        font-size: .3rem;
                         font-weight: bold;
                     }
                 }
@@ -110,29 +110,29 @@
         }
 
         .button {
-            display        : flex;
+            display: flex;
             justify-content: space-around;
 
             .van-button {
-                width     : 2.8rem;
+                width: 2.8rem;
                 box-shadow: 0 .06rem .14rem 0 #e0e2e8;
             }
         }
     }
 
-    &__iconbar {
+    &-iconbar {
         background-color: #fff;
-        padding         : .24rem;
-        margin-bottom   : .2rem;
+        padding: .24rem;
+        margin-bottom: .2rem;
 
         ul {
             display: flex;
 
             li {
-                flex          : 1;
-                display       : flex;
+                flex: 1;
+                display: flex;
                 flex-direction: column;
-                align-items   : center;
+                align-items: center;
 
                 .app-iconfont {
                     &__icon {
@@ -140,7 +140,7 @@
                     }
 
                     &__label {
-                        font-size : .24rem;
+                        font-size: .24rem;
                         margin-top: .12rem;
                     }
                 }
@@ -148,11 +148,11 @@
         }
     }
 
-    &__footer {
+    &-footer {
         padding: .2rem 0;
 
         .button-logout {
-            width : 100%;
+            width: 100%;
             border: 0;
         }
     }

+ 5 - 5
src/packages/mobile/views/home/components/mine/index.vue → src/packages/mobile/views/mine/main/index.vue

@@ -1,10 +1,10 @@
 <template>
-  <app-view class="home-mine">
+  <app-view class="mine">
     <template #header>
       <app-navbar title="我的" :show-back-button="false" @ready="onReady" />
     </template>
-    <div ref="headerRef" class="home-mine__header">
-      <div class="home-mine__header-wrapper">
+    <div ref="headerRef" class="mine-header">
+      <div class="mine-header__wrapper">
         <div class="profile">
           <div class="profile-user">
             <div class="profile-user__avatar">
@@ -48,7 +48,7 @@
         </div>
       </div>
     </div>
-    <div class="home-mine__iconbar">
+    <div class="mine-iconbar">
       <ul>
         <li @click="routerTo('mine-generalize')">
           <app-iconfont icon="icon-wodetuiguang" label-direction="bottom">我的推广</app-iconfont>
@@ -106,7 +106,7 @@
         </Cell>
       </CellGroup>
     </div>
-    <div class="home-mine__footer">
+    <div class="mine-footer">
       <Button class="button-logout" @click="userLogout">退出登录</Button>
     </div>
   </app-view>

+ 1 - 1
src/packages/mobile/views/mine/order/detail/transfer/index.vue

@@ -62,7 +62,7 @@ const spotCancelSubmit = () => {
         fullloading((hideLoading) => {
             transferCancelSubmit().then(() => {
                 hideLoading()
-                dialog('转让撤销提交成功,请耐心等待审核。').then(() => {
+                dialog('转让撤销提交成功。').then(() => {
                     router.back()
                 })
             }).catch((err) => {

+ 4 - 3
src/packages/mobile/views/mine/order/detail/wrorder/index.vue

@@ -12,8 +12,8 @@
                 <Cell title="委托价格" :value="detail.fixedprice.toFixed(2)" />
                 <Cell title="挂牌数量" :value="detail.orderqty" />
                 <Cell title="撤销数量" :value="detail.cancelqty" />
-                <Cell title="委托时间" :value="formatDate(detail.ordertime, 'YYYY/MM/DD HH:mm:ss')" />
-                <Cell title="状态" :value="detail.wrtradeorderstatus" />
+                <Cell title="委托时间" :value="formatDate(detail.ordertime)" />
+                <Cell title="状态" :value="getWRTradeOrderStatusName(detail.wrtradeorderstatus)" />
                 <Cell title="委托单号:" :value="detail.wrtradeorderid" />
             </CellGroup>
         </div>
@@ -34,6 +34,7 @@ import { shallowRef } from 'vue'
 import { useNavigation } from '@/hooks/navigation'
 import { fullloading, dialog } from '@/utils/vant'
 import { CellGroup, Cell, Empty, Button, Toast } from 'vant'
+import { getWRTradeOrderStatusName } from '@/constants/order'
 import { formatDate } from "@/filters";
 import { useWrListingCancelOrder } from "@/business/trade"
 
@@ -67,7 +68,7 @@ const spotConfirmSubmit = () => {
             })
         })
     }
-    
+
 }
 
 </script>

+ 1 - 4
src/packages/mobile/views/mine/order/detail/wrtrade/index.vue

@@ -12,7 +12,7 @@
                 <Cell title="成交价格" :value="detail.tradeprice.toFixed(2)" />
                 <Cell title="成交数量" :value="detail.tradeqty" />
                 <Cell title="成交金额" :value="(detail.tradeprice * detail.tradeqty).toFixed(2)" />
-                <Cell title="成交时间" :value="formatDate(detail.tradetime, 'YYYY/MM/DD HH:mm:ss')" />
+                <Cell title="成交时间" :value="formatDate(detail.tradetime)" />
                 <Cell title="对手方" :value="detail.matchusername" />
                 <Cell title="成交单号:" :value="detail.wrtradedetailid" />
             </CellGroup>
@@ -24,7 +24,6 @@
 </template>
 
 <script lang="ts" setup>
-
 import { shallowRef } from 'vue'
 import { useNavigation } from '@/hooks/navigation'
 import { CellGroup, Cell, Empty } from 'vant'
@@ -34,9 +33,7 @@ const { route } = useNavigation()
 const item = route.params.item
 const detail = shallowRef<Model.WrTradeDetailRsp>()
 
-
 if (item) {
     detail.value = JSON.parse(item.toString())
 }
-
 </script>

+ 1 - 1
src/packages/mobile/views/mine/order/list/components/purchasetrade/index.vue

@@ -19,7 +19,7 @@
                     <div class="section-item__content">
                         <table cellspacing="0" cellpadding="0">
                             <tr>
-                                <th>定金</th>
+                                <th>预付款</th>
                                 <td>{{ handleNumberValue(item.payeddeposit) }}</td>
                                 <th>参考价</th>
                                 <td>{{ handleNumberValue(item.tradeprice) }}</td>

+ 10 - 3
src/packages/mobile/views/mine/wareorder/components/listing/index.vue

@@ -18,7 +18,7 @@
                     </Field>
                     <Field label="参考价格">
                         <template #input>
-                            7000元/吨
+                            {{ selectedRow.spotgoodsprice }}
                         </template>
                     </Field>
                     <Field name="Price" label="挂牌价格" v-model="formData.FixedPrice" placeholder="请输入挂牌价格"
@@ -46,8 +46,9 @@
 <script lang="ts" setup>
 import { shallowRef, PropType } from 'vue'
 import { CellGroup, Button, Field, Form, FormInstance, FieldRule, Toast } from 'vant'
-import { useHdWROrder } from "@/business/trade";
+import { useHdWROrder } from "@/business/trade"
 import { fullloading, dialog } from '@/utils/vant'
+import Long from 'long'
 import AppModal from '@/components/base/modal/index.vue'
 
 const props = defineProps({
@@ -60,8 +61,14 @@ const props = defineProps({
 const formRef = shallowRef<FormInstance>()
 const showModal = shallowRef(true)
 const refresh = shallowRef(false) // 是否刷新父组件数据
+const { wrstandardid, subnum, deliverygoodsid, ladingbillid = '0', wrfactortypeid = '0' } = props.selectedRow ?? {}
+const { formData, listingSubmit, amount } = useHdWROrder()
 
-const { formData, listingSubmit, amount } = useHdWROrder(props.selectedRow)
+formData.WRStandardID = wrstandardid
+formData.DeliveryGoodsID = deliverygoodsid
+formData.LadingBillId = Long.fromString(ladingbillid)
+formData.WRFactorTypeId = Long.fromString(wrfactortypeid)
+formData.SubNum = subnum
 
 // 表单验证规则
 const formRules: { [key in keyof Proto.HdWROrderReq]?: FieldRule[] } = {

+ 0 - 2
src/packages/mobile/views/mine/wareorder/wroutinapplydetail/index.vue

@@ -23,7 +23,6 @@
 </template>
 
 <script lang="ts" setup>
-
 import { shallowRef } from 'vue'
 import { useNavigation } from '@/hooks/navigation'
 import { CellGroup, Cell, Empty } from 'vant'
@@ -36,7 +35,6 @@ const detail = shallowRef<Model.WrOutInApplyRsp>()
 if (item) {
     detail.value = JSON.parse(item.toString())
 }
-
 </script>
 
 <style lang="less">

+ 3 - 3
src/packages/mobile/views/product/detail/index.vue

@@ -4,9 +4,9 @@
             <app-navbar title="商品详情" />
         </template>
         <div class="product-details__content">
-            <Swipe class="banner" :autoplay="3000" indicator-color="white" lazy-render>
-                <SwipeItem v-for="(item, index) in topBanners" :key="index">
-                    <img :src="getImageUrl(item)" />
+            <Swipe class="banner" :autoplay="5000" indicator-color="white" lazy-render>
+                <SwipeItem v-for="(url, index) in topBanners" :key="index">
+                    <img :src="url" />
                 </SwipeItem>
             </Swipe>
             <div class="goods">

+ 3 - 5
src/packages/mobile/views/purchase/detail/index.vue

@@ -51,7 +51,7 @@
                 </Field>
                 <Field label="预付款(含定金)" v-if="selectedDate">
                     <template #input>
-                        <span style="color:#999">(≤{{ deposit }}元)</span>
+                        <span style="color:#999">{{ `${deposit}(≤${avaiableMoney.toFixed(2)}元)` }}</span>
                     </template>
                 </Field>
                 <Field label="收货信息" name="addressInfo" :rules="formRules.addressInfo" @click="openComponent('address')"
@@ -76,10 +76,6 @@
             <div class="submitbar">
                 <Button type="primary" @click="formRef?.submit" round block>采购下单</Button>
             </div>
-            <!-- <div class="titlebar" v-if="selectedDate">
-                <span>参考价(元/{{ getGoodsUnitName(goodsinfo.unitid) }})</span>
-                <span>{{ selectedDate.unitprice ?? 0.00 }}</span>
-            </div> -->
             <template v-if="chartData.price.length">
                 <Divider>历史价格走势</Divider>
                 <div class="chart">
@@ -106,6 +102,7 @@ import { getImageUrl, parsePercent } from '@/filters'
 import { getGoodsUnitName } from '@/constants/unit'
 import { useComponent } from '@/hooks/component'
 import { useNavigation } from '@/hooks/navigation'
+import { useAccountStore, } from '@/stores'
 import { useWrstandardDetails } from '@/business/goods'
 import { usePurchaseOrderDesting } from '@/business/trade'
 import AppSelect from '@mobile/components/base/select/index.vue'
@@ -116,6 +113,7 @@ const componentMap = new Map<string, unknown>([
     ['chart', defineAsyncComponent(() => import('@mobile/components/modules/echarts-line/index.vue'))],
 ])
 
+const { avaiableMoney } = useAccountStore()
 const { componentRef, componentId, openComponent, closeComponent } = useComponent()
 const { router, getQueryStringToNumber } = useNavigation()
 

+ 6 - 6
src/packages/mobile/views/home/components/purchase/index.less → src/packages/mobile/views/purchase/list/index.less

@@ -1,4 +1,4 @@
-.home-purchase {
+.purchase {
     &__header {
         .van-search {
             padding-top: 0;
@@ -7,15 +7,15 @@
 
     &__container {
         .van-cell__title {
-            display    : flex;
+            display: flex;
             align-items: center;
 
             img {
-                width        : 1.8rem;
-                height       : 1.8rem;
-                object-fit   : cover;
+                width: 1.8rem;
+                height: 1.8rem;
+                object-fit: cover;
                 border-radius: .16rem;
-                margin-right : .4rem;
+                margin-right: .4rem;
             }
 
             span {

+ 3 - 3
src/packages/mobile/views/home/components/purchase/index.vue → src/packages/mobile/views/purchase/list/index.vue

@@ -1,13 +1,13 @@
 <template>
-  <app-view class="home-purchase">
+  <app-view class="purchase">
     <template #header>
-      <app-navbar class="home-purchase__header" title="采购" :show-back-button="false">
+      <app-navbar class="purchase__header" title="采购" :show-back-button="false">
         <template #footer>
           <Search shape="round" placeholder="商品搜索" />
         </template>
       </app-navbar>
     </template>
-    <app-pull-refresh class="home-purchase__container" v-model:error="error" v-model:pageIndex="pageIndex"
+    <app-pull-refresh class="purchase__container" v-model:error="error" v-model:pageIndex="pageIndex"
       :page-count="pageCount" @refresh="onRefresh">
       <template v-for="(item, index) in dataList" :key="index">
         <Cell @click="$router.push({ name: 'PurchaseDetail', query: { wrstandardid: item.wrstandardid } })">

+ 15 - 20
src/packages/mobile/views/rules/ptgz/index.vue

@@ -3,29 +3,24 @@
         <template #header>
             <app-navbar title="平台规则" />
         </template>
-        <Tabs class="mine-generalize__tabs" v-model:active="active" @click-tab="onClickTab" sticky>
-            <Tab title="平台规则" />
-            <Tab title="买家规则" />
-            <Tab title="卖家规则"/>
-            <Tab title="积分规则"/>
+        <Tabs class="mine-generalize__tabs">
+            <Tab title="平台规则">
+                <app-html url="./html/ptgz.htm" />
+            </Tab>
+            <Tab title="买家规则">
+                <app-html url="./html/mjgz_b.htm" />
+            </Tab>
+            <Tab title="卖家规则">
+                <app-html url="./html/mjgz_s.htm" />
+            </Tab>
+            <Tab title="积分规则">
+                <app-html url="./html/jfgz.htm" />
+            </Tab>
         </Tabs>
-        <app-html v-if="active === 0" url="./html/ptgz.htm" />
-        <app-html v-if="active === 1" url="./html/mjgz_b.htm" />
-        <app-html v-if="active === 2" url="./html/mjgz_s.htm" />
-        <app-html v-if="active === 3" url="./html/jfgz.htm" />
     </app-view>
 </template>
 
 <script lang="ts" setup>
-
-    import { ref } from 'vue'
-    import AppHtml from '@mobile/components/base/html-panel/index.vue'
-    import { Tab, Tabs } from 'vant'
-
-    /// tab激活项
-    const active = ref(0);
-    const onClickTab = (e: any ) => {
-        active.value = e.name
-    };
-
+import { Tab, Tabs } from 'vant'
+import AppHtml from '@mobile/components/base/html-panel/index.vue'
 </script>

+ 7 - 14
src/packages/mobile/views/rules/yszc/index.vue

@@ -3,25 +3,18 @@
         <template #header>
             <app-navbar title="隐私政策" />
         </template>
-        <Tabs class="mine-generalize__tabs" v-model:active="active" @click-tab="onClickTab" sticky>
-            <Tab title="隐私政策" />
-            <Tab title="物流隐私条款" />
+        <Tabs class="mine-generalize__tabs">
+            <Tab title="隐私政策">
+                <app-html url="./html/yszc.htm" />
+            </Tab>
+            <Tab title="物流隐私条款">
+                <app-html url="./html/wlystk.htm" />
+            </Tab>
         </Tabs>
-        <app-html v-if="active === 0" url="./html/yszc.htm" />
-        <app-html v-if="active === 1" url="./html/wlystk.htm" />
     </app-view>
 </template>
 
 <script lang="ts" setup>
-
 import AppHtml from '@mobile/components/base/html-panel/index.vue'
 import { Tab, Tabs } from 'vant'
-import { ref } from 'vue'
-
-/// tab激活项
-const active = ref(0);
-const onClickTab = (e: any ) => {
-    active.value = e.name
-};
-
 </script>

+ 13 - 0
src/packages/mobile/views/supply-demand/detail/components/delisting/index.less

@@ -0,0 +1,13 @@
+.supply-demand-listing {
+    &__form {
+        .van-stepper {
+            display: flex;
+            align-items: center;
+            width: 100%;
+
+            &__input {
+                flex: 1;
+            }
+        }
+    }
+}

+ 163 - 0
src/packages/mobile/views/supply-demand/detail/components/delisting/index.vue

@@ -0,0 +1,163 @@
+<template>
+    <app-popup class="supply-demand-listing" :title="buyorsell === BuyOrSell.Sell ? '卖出' : '买入'"
+        v-model:show="showModal" :refresh="refresh">
+        <Form class="supply-demand-listing__form" ref="formRef" @submit="onSubmit">
+            <Field label="挂牌方">
+                <template #input>
+                    <span>{{ quoteDetail.username }}</span>
+                </template>
+            </Field>
+            <Field label="挂牌价格">
+                <template #input>
+                    <span>{{ quoteDetail.fixedprice }}</span>
+                </template>
+            </Field>
+            <Field label="剩余数量">
+                <template #input>
+                    <span>{{ quoteDetail.orderqty }}</span>
+                </template>
+            </Field>
+            <Field name="WRFactorTypeId" :rules="formRules.WRFactorTypeId" label="现货仓单" is-link
+                v-if="buyorsell === BuyOrSell.Sell">
+                <template #input>
+                    <app-select :options="dataList" :optionProps="{ label: 'wrholdeno', value: 'wrid' }"
+                        @confirm="onConfirm" />
+                </template>
+            </Field>
+            <Field name="OrderQty" :rules="formRules.OrderQty" label="摘牌数量">
+                <template #input>
+                    <Stepper v-model="formData.OrderQty" theme="round" button-size="22" integer />
+                </template>
+            </Field>
+            <Field label="货款金额">
+                <template #input>
+                    <span>{{ amount }}</span>
+                </template>
+            </Field>
+            <Field label="可用资金" v-if="buyorsell === BuyOrSell.Buy">
+                <template #input>
+                    <span>{{ avaiableMoney.toFixed(2) }}</span>
+                </template>
+            </Field>
+        </Form>
+        <template #footer>
+            <Button type="primary" block round @click="formRef?.submit">确定</Button>
+        </template>
+    </app-popup>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType, computed } from 'vue'
+import { Form, Field, Stepper, Button, Toast, FieldRule, FormInstance } from 'vant'
+import { fullloading, dialog } from '@/utils/vant'
+import { useLoginStore, useAccountStore } from '@/stores'
+import { BuyOrSell } from '@/constants/order'
+import { queryHoldLB } from '@/services/api/order'
+import { useHdWRDealOrder } from '@/business/trade'
+import Long from 'long'
+import AppPopup from '@mobile/components/base/popup/index.vue'
+import AppSelect from '@mobile/components/base/select/index.vue'
+
+const props = defineProps({
+    quote: {
+        type: Object as PropType<Model.OrderQuoteRsp>,
+        required: true
+    },
+    quoteDetail: {
+        type: Object as PropType<Model.OrderQuoteDetailRsp>,
+        required: true
+    },
+    buyorsell: {
+        type: Number,
+        required: true
+    }
+})
+
+const { getFirstAccountId } = useLoginStore()
+const { avaiableMoney } = useAccountStore()
+const { formData, formSubmit } = useHdWRDealOrder()
+const formRef = shallowRef<FormInstance>()
+const refresh = shallowRef(false) // 是否刷新父组件数据
+const showModal = shallowRef(true)
+const dataList = shallowRef<Model.HoldLBRsp[]>([]) //现货仓单列表
+const selectedRow = shallowRef<Model.HoldLBRsp>() //选择的仓单
+
+// 货款金额
+const amount = computed(() => {
+    const { OrderQty = 0 } = formData
+    const { fixedprice = 0 } = props.quoteDetail
+    return (OrderQty * fixedprice).toFixed(2)
+})
+
+// 关闭弹窗
+const closed = (isRefresh = false) => {
+    refresh.value = isRefresh
+    showModal.value = false
+}
+
+// 表单验证规则
+const formRules: { [key in keyof Proto.HdWRDealOrderReq]?: FieldRule[] } = {
+    WRFactorTypeId: [{
+        message: '请选择现货仓单',
+        validator: () => {
+            return !!selectedRow.value
+        }
+    }],
+}
+
+// 选择仓单
+const onConfirm = (value: string) => {
+    selectedRow.value = dataList.value.find((e) => e.wrid === value)
+    formRef.value?.validate('WRFactorTypeId')
+    formRef.value?.validate('OrderQty')
+}
+
+// 提交摘牌
+const onSubmit = () => {
+    const { wrfactortypeid = '0' } = props.quote ?? {}
+    const { wrtradeorderid = '0', marketid } = props.quoteDetail ?? {}
+
+    formData.Header = {
+        AccountID: getFirstAccountId(),
+        MarketID: marketid
+    }
+    formData.BuyOrSell = props.buyorsell
+    formData.RelatedWRTradeOrderID = Long.fromString(wrtradeorderid)
+    formData.WRFactorTypeId = Long.fromString(wrfactortypeid)
+
+    if (formData.BuyOrSell === BuyOrSell.Sell) {
+        const { subnum, ladingbillid = '0', wrfactortypeid = '0' } = selectedRow.value ?? {}
+        formData.LadingBillId = Long.fromString(ladingbillid)
+        formData.SubNum = subnum
+        formData.WRFactorTypeId = Long.fromString(wrfactortypeid)
+    }
+
+    fullloading((hideLoading) => {
+        formSubmit().then(() => {
+            hideLoading()
+            dialog('摘牌提交成功。').then(() => closed(true))
+        }).catch((err) => {
+            Toast.fail(err)
+        })
+    })
+}
+
+queryHoldLB({
+    data: {
+        accountid: getFirstAccountId(),
+        wrstandardid: props.quote.wrstandardid
+    },
+    success: (res) => {
+        dataList.value = res.data
+    }
+})
+
+// 暴露组件属性给父组件调用
+defineExpose({
+    closed,
+})
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 13 - 0
src/packages/mobile/views/supply-demand/detail/components/listing/index.less

@@ -0,0 +1,13 @@
+.supply-demand-listing {
+    &__form {
+        .van-stepper {
+            display: flex;
+            align-items: center;
+            width: 100%;
+
+            &__input {
+                flex: 1;
+            }
+        }
+    }
+}

+ 159 - 0
src/packages/mobile/views/supply-demand/detail/components/listing/index.vue

@@ -0,0 +1,159 @@
+<template>
+    <app-popup class="supply-demand-listing" :title="buyorsell === BuyOrSell.Sell ? '我要卖' : '我要买'"
+        v-model:show="showModal">
+        <Form class="supply-demand-listing__form" ref="formRef" @submit="onSubmit">
+            <Field name="FixedPrice" :rules="formRules.FixedPrice" label="价格">
+                <template #input>
+                    <Stepper v-model="formData.FixedPrice" :default-value="quote.spotgoodsprice" theme="round"
+                        button-size="22" />
+                </template>
+            </Field>
+            <Field name="WRFactorTypeId" :rules="formRules.WRFactorTypeId" label="现货仓单" is-link
+                v-if="buyorsell === BuyOrSell.Sell">
+                <template #input>
+                    <app-select :options="dataList" :optionProps="{ label: 'wrholdeno', value: 'wrid' }"
+                        @confirm="onConfirm" />
+                </template>
+            </Field>
+            <Field name="OrderQty" :rules="formRules.OrderQty" label="数量">
+                <template #input>
+                    <Stepper v-model="formData.OrderQty" theme="round" button-size="22" integer />
+                </template>
+            </Field>
+            <Field label="货款金额">
+                <template #input>
+                    <span>{{ amount }}</span>
+                </template>
+            </Field>
+            <Field label="可用资金" v-if="buyorsell === BuyOrSell.Buy">
+                <template #input>
+                    <span>{{ avaiableMoney.toFixed(2) }}</span>
+                </template>
+            </Field>
+        </Form>
+        <template #footer>
+            <Button type="primary" block round @click="formRef?.submit">确定</Button>
+        </template>
+    </app-popup>
+</template>
+
+<script lang="ts" setup>
+import { shallowRef, PropType } from 'vue'
+import { Form, Field, Stepper, Button, Toast, FieldRule, FormInstance } from 'vant'
+import { fullloading, dialog } from '@/utils/vant'
+import { useLoginStore, useAccountStore } from '@/stores'
+import { BuyOrSell } from '@/constants/order'
+import { queryHoldLB } from '@/services/api/order'
+import { useHdWROrder } from '@/business/trade'
+import Long from 'long'
+import AppPopup from '@mobile/components/base/popup/index.vue'
+import AppSelect from '@mobile/components/base/select/index.vue'
+
+const props = defineProps({
+    quote: {
+        type: Object as PropType<Model.OrderQuoteRsp>,
+        required: true
+    },
+    buyorsell: {
+        type: Number,
+        required: true
+    }
+})
+
+const { getFirstAccountId } = useLoginStore()
+const { avaiableMoney } = useAccountStore()
+const { formData, listingSubmit, amount } = useHdWROrder()
+const formRef = shallowRef<FormInstance>()
+const showModal = shallowRef(true)
+const dataList = shallowRef<Model.HoldLBRsp[]>([]) //现货仓单列表
+const selectedRow = shallowRef<Model.HoldLBRsp>() //选择的仓单
+
+// 关闭弹窗
+const closed = () => {
+    showModal.value = false
+}
+
+// 表单验证规则
+const formRules: { [key in keyof Proto.HdWROrderReq]?: FieldRule[] } = {
+    FixedPrice: [{
+        message: '请输入价格',
+        validator: () => {
+            return !!formData.FixedPrice
+        }
+    }],
+    WRFactorTypeId: [{
+        message: '请选择现货仓单',
+        validator: () => {
+            return !!selectedRow.value
+        }
+    }],
+    OrderQty: [{
+        message: '请输入数量',
+        validator: (val) => {
+            if (val) {
+                const { qty = 0, freezerqty = 0 } = selectedRow.value ?? {}
+                const available = qty - freezerqty // 可用数量
+                if (props.buyorsell === BuyOrSell.Buy || val <= available) {
+                    return true
+                }
+                return available ? '数量不能大于 ' + available : '可用数量不足'
+            }
+            return false
+        }
+    }],
+}
+
+// 选择仓单
+const onConfirm = (value: string) => {
+    selectedRow.value = dataList.value.find((e) => e.wrid === value)
+    formRef.value?.validate('WRFactorTypeId')
+    formRef.value?.validate('OrderQty')
+}
+
+// 提交挂牌
+const onSubmit = () => {
+    formData.BuyOrSell = props.buyorsell
+
+    if (formData.BuyOrSell === BuyOrSell.Buy) {
+        const { wrstandardid, deliverygoodsid, wrfactortypeid = '0' } = props.quote ?? {}
+        formData.WRStandardID = wrstandardid
+        formData.DeliveryGoodsID = deliverygoodsid
+        formData.WRFactorTypeId = Long.fromString(wrfactortypeid)
+    } else {
+        const { wrstandardid, subnum, deliverygoodsid, ladingbillid = '0', wrfactortypeid = '0' } = selectedRow.value ?? {}
+        formData.WRStandardID = wrstandardid
+        formData.DeliveryGoodsID = deliverygoodsid
+        formData.LadingBillId = Long.fromString(ladingbillid)
+        formData.WRFactorTypeId = Long.fromString(wrfactortypeid)
+        formData.SubNum = subnum
+    }
+
+    fullloading((hideLoading) => {
+        listingSubmit().then(() => {
+            hideLoading()
+            dialog('挂牌提交成功。').then(() => closed())
+        }).catch((err) => {
+            Toast.fail(err)
+        })
+    })
+}
+
+queryHoldLB({
+    data: {
+        accountid: getFirstAccountId(),
+        wrstandardid: props.quote.wrstandardid
+    },
+    success: (res) => {
+        dataList.value = res.data
+    }
+})
+
+// 暴露组件属性给父组件调用
+defineExpose({
+    closed,
+})
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 77 - 0
src/packages/mobile/views/supply-demand/detail/index.less

@@ -0,0 +1,77 @@
+.supply-demand-details {
+    .g-form__footer {
+        background-color: #fff;
+    }
+
+    &__content {
+        .banner {
+            background-color: #999;
+
+            .van-swipe {
+                min-height: 3rem;
+
+                &-item {
+                    height: 3rem;
+                    font-size: 0;
+
+                    img {
+                        width: 100%;
+                        height: 100%;
+                        object-fit: cover;
+                    }
+                }
+            }
+        }
+
+        .goods {
+            padding: .32rem;
+            background-color: #fff;
+            margin-bottom: .2rem;
+
+            table {
+                width: 100%;
+
+                th {
+                    text-align: left;
+
+                    h1 {
+                        font-size: .36rem;
+                        font-weight: bold;
+                    }
+                }
+
+                td {
+                    padding: .08rem 0;
+
+                    span {
+                        &:first-child {
+                            color: #999;
+                            margin-right: .2rem;
+                        }
+                    }
+                }
+            }
+
+            &-price {
+                text-align: center;
+
+                h2 {
+                    font-size: .48rem;
+                    font-weight: bold;
+                    color: #E84F42;
+                }
+            }
+        }
+
+        .trade {
+            &-section {
+                margin-bottom: .2rem;
+
+                .van-button {
+                    width: 1rem;
+                    border-width: 1px;
+                }
+            }
+        }
+    }
+}

+ 153 - 2
src/packages/mobile/views/supply-demand/detail/index.vue

@@ -1,6 +1,157 @@
 <template>
-    <div></div>
+    <app-view class="supply-demand-details g-form">
+        <template #header>
+            <app-navbar title="供求详情" />
+        </template>
+        <div v-if="quote" class="supply-demand-details__content">
+            <Swipe class="banner" :autoplay="5000" indicator-color="white" lazy-render>
+                <SwipeItem v-for="(url, index) in topBanners" :key="index">
+                    <img :src="url" />
+                </SwipeItem>
+            </Swipe>
+            <div class="goods">
+                <table cellspacing="0" cellpadding="0">
+                    <tr>
+                        <th colspan="3">
+                            <h1>{{ quote.wrstandardname }}</h1>
+                        </th>
+                    </tr>
+                    <tr>
+                        <td>
+                            <span>卖价:</span>
+                            <span>{{ quote.sellprice }}</span>
+                        </td>
+                        <td>
+                            <span>卖量:</span>
+                            <span>{{ quote.sellqty }}</span>
+                        </td>
+                        <td rowspan="3" style="vertical-align:top">
+                            <div class="goods-price">
+                                <h4>参考价(元/{{ quote.enumdicname }})</h4>
+                                <h2>{{ quote.spotgoodsprice }}</h2>
+                            </div>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>
+                            <span>买价:</span>
+                            <span>{{ quote.buyprice }}</span>
+                        </td>
+                        <td>
+                            <span>买量:</span>
+                            <span>{{ quote.buyqty }}</span>
+                        </td>
+                    </tr>
+                    <tr>
+                        <td colspan="2">
+                            <span>仓库:</span>
+                            <span>{{ quote.warehousename }}</span>
+                        </td>
+                    </tr>
+                </table>
+            </div>
+            <div class="trade">
+                <div class="trade-section sell">
+                    <Cell title="卖价" value="更多" />
+                    <app-list :columns="columns" :data-list="sellList">
+                        <template #operate="{ row }">
+                            <Button size="small" round @click="delistingListing(row, BuyOrSell.Buy)">买入</Button>
+                        </template>
+                    </app-list>
+                </div>
+                <div class="trade-section buy">
+                    <Cell title="买价" value="更多" />
+                    <app-list :columns="columns" :data-list="buyList">
+                        <template #operate="{ row }">
+                            <Button size="small" round @click="delistingListing(row, BuyOrSell.Sell)">卖出</Button>
+                        </template>
+                    </app-list>
+                </div>
+            </div>
+            <div class="gallery">
+                <Divider>商品详情</Divider>
+                <template v-for="(url, index) in goodsImages" :key="index">
+                    <img :src="url" alt="" />
+                </template>
+            </div>
+        </div>
+        <Empty v-else />
+        <template #footer>
+            <div class="g-form__footer" v-if="quote">
+                <Button type="warning" block round @click="toggleListing(BuyOrSell.Sell)">我要卖</Button>
+                <Button type="primary" block round @click="toggleListing(BuyOrSell.Buy)">我要买</Button>
+            </div>
+            <component ref="componentRef" :is="componentMap.get(componentId)" v-bind="{ quote, quoteDetail, buyorsell }"
+                @closed="closeComponent" v-if="componentId" />
+        </template>
+    </app-view>
 </template>
 
 <script lang="ts" setup>
-</script>
+import { shallowRef, computed, defineAsyncComponent } from 'vue'
+import { Cell, Swipe, SwipeItem, Empty, Divider, Button } from 'vant'
+import { getImageUrl } from '@/filters'
+import { useComponent } from '@/hooks/component'
+import { useNavigation } from '@/hooks/navigation'
+import { BuyOrSell } from '@/constants/order'
+import { useOrderQuoteDetail } from '@/business/goods'
+import AppList from '@mobile/components/base/list/index.vue'
+
+const componentMap = new Map<string, unknown>([
+    ['listing', defineAsyncComponent(() => import('./components/listing/index.vue'))], // 挂牌
+    ['delisting', defineAsyncComponent(() => import('./components/delisting/index.vue'))], // 摘牌
+])
+
+const { route } = useNavigation()
+const { componentRef, componentId, openComponent, closeComponent } = useComponent()
+const item = route.params.item
+const quote = shallowRef<Model.OrderQuoteRsp>()
+const quoteDetail = shallowRef<Model.OrderQuoteDetailRsp>()
+const buyorsell = shallowRef(BuyOrSell.Buy) // 买卖方向
+
+if (item) {
+    quote.value = JSON.parse(item.toString())
+}
+
+const { dataList: buyList, getOrderQuoteList: getOrderBuyList } = useOrderQuoteDetail(quote.value?.wrfactortypeid)
+const { dataList: sellList, getOrderQuoteList: getOrderSellList } = useOrderQuoteDetail(quote.value?.wrfactortypeid)
+
+const columns: Model.TableColumn[] = [
+    { prop: 'username', label: '挂牌方' },
+    { prop: 'orderqty', label: '数量' },
+    { prop: 'fixedprice', label: '价格' },
+    { prop: 'operate', label: '操作' },
+]
+
+// 商品banner
+const topBanners = computed(() => {
+    const bannerpicurl = quote.value?.bannerpicurl ?? ''
+    return bannerpicurl?.split(',').map((path) => getImageUrl(path))
+})
+
+// 商品图片列表
+const goodsImages = computed(() => {
+    const pictureurls = quote.value?.pictureurls ?? ''
+    return pictureurls.split(',').map((path) => getImageUrl(path))
+})
+
+// 挂牌下单
+const toggleListing = (value: BuyOrSell) => {
+    buyorsell.value = value
+    openComponent('listing')
+}
+
+// 摘牌下单
+const delistingListing = (row: Model.OrderQuoteDetailRsp, value: BuyOrSell) => {
+    buyorsell.value = value
+    quoteDetail.value = row
+    openComponent('delisting')
+}
+
+getOrderBuyList(BuyOrSell.Buy)
+getOrderSellList(BuyOrSell.Sell)
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 6 - 6
src/packages/mobile/views/home/components/supply-demand/index.less → src/packages/mobile/views/supply-demand/list/index.less

@@ -1,4 +1,4 @@
-.home-supply-demand {
+.supply-demand {
     &__header {
         .van-search {
             padding-top: 0;
@@ -7,15 +7,15 @@
 
     &__container {
         .van-cell__title {
-            display    : flex;
+            display: flex;
             align-items: center;
 
             img {
-                width        : 1.8rem;
-                height       : 1.8rem;
-                object-fit   : cover;
+                width: 1.8rem;
+                height: 1.8rem;
+                object-fit: cover;
                 border-radius: .16rem;
-                margin-right : .4rem;
+                margin-right: .4rem;
             }
 
             span {

+ 8 - 8
src/packages/mobile/views/home/components/supply-demand/index.vue → src/packages/mobile/views/supply-demand/list/index.vue

@@ -1,16 +1,16 @@
 <template>
-  <app-view class="home-supply-demand">
+  <app-view class="supply-demand">
     <template #header>
-      <app-navbar class="home-supply-demand__header" title="供求" :show-back-button="false">
+      <app-navbar class="supply-demand__header" title="供求" :show-back-button="false">
         <template #footer>
           <Search shape="round" placeholder="商品搜索" disabled />
         </template>
       </app-navbar>
     </template>
-    <app-pull-refresh class="home-supply-demand__container" v-model:error="error" v-model:pageIndex="pageIndex"
+    <app-pull-refresh class="supply-demand__container" v-model:error="error" v-model:pageIndex="pageIndex"
       :page-count="pageCount" @refresh="onRefresh">
       <template v-for="(item, index) in dataList" :key="index">
-        <Cell @click="$router.push({ name: 'PurchaseDetail', query: { wrstandardid: item.wrstandardid } })">
+        <Cell @click="$router.push({ name: 'SupplyDemandDetail', params: { item: JSON.stringify(item) } })">
           <template #title>
             <img :src="getFirstImage(item.thumurls)" />
             <span>{{ item.wrstandardname }}</span>
@@ -25,11 +25,11 @@
 import { shallowRef } from 'vue'
 import { Cell, Search } from 'vant'
 import { getImageUrl } from '@/filters'
-import { useListingList } from '@/business/goods'
+import { useOrderQuoteList } from '@/business/goods'
 import AppPullRefresh from '@mobile/components/base/pull-refresh/index.vue'
 
-const { pageIndex, pageCount, getListingList } = useListingList()
-const dataList = shallowRef<Model.THJWrstandardRsp[]>([])
+const { pageIndex, pageCount, getOrderQuoteList } = useOrderQuoteList()
+const dataList = shallowRef<Model.OrderQuoteRsp[]>([])
 const error = shallowRef(false)
 
 // 获取商品首图
@@ -39,7 +39,7 @@ const getFirstImage = (url: string) => {
 }
 
 const onRefresh = (finish: () => void) => {
-  getListingList().then((res) => {
+  getOrderQuoteList().then((res) => {
     if (pageIndex.value === 1) {
       dataList.value = []
     }

+ 7 - 0
src/services/api/common/index.ts

@@ -84,4 +84,11 @@ export function signin(params: HttpParams<{ req: { userid: number }, rsp: { sign
  */
 export function queryMyRegisterMoney(params: HttpParams<{ req: Model.MyRegisterMoneyReq, rsp: Model.MyRegisterMoneyRsp[] }>) {
     return httpRequest('/Ferroalloy/QueryMyRegisterMoney', 'get', params);
+}
+
+/**
+ * 查询用户等级信息
+ */
+export function queryUserLevelInfo(params: HttpParams<{ req: Model.UserLevelInfoReq, rsp: Model.UserLevelInfoRsp }>) {
+    return httpRequest('/Ferroalloy/QueryUserLevelInfo', 'get', params);
 }

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

@@ -30,6 +30,20 @@ export function queryTHJListing(params: HttpParams<{ req: Model.THJListingReq, r
 }
 
 /**
+ * 查询大厅行情列表
+ */
+export function queryOrderQuote(params: HttpParams<{ req: Model.OrderQuoteReq, rsp: Model.OrderQuoteRsp[] }>) {
+    return httpRequest('/WrTrade2/QueryOrderQuote', 'get', params);
+}
+
+/**
+ * 查询买卖大厅
+ */
+export function queryOrderQuoteDetail(params: HttpParams<{ req: Model.OrderQuoteDetailReq, rsp: Model.OrderQuoteDetailRsp[] }>) {
+    return httpRequest('/WrTrade2/QueryOrderQuoteDetail', 'get', params);
+}
+
+/**
  * 移除用户商品收藏信息
  */
 export function removeUserFavoriteGoods(params: HttpParams<{ req: Model.UserFavoriteGoodsReq, rsp: Model.UserFavoriteGoodsRsp }>) {

+ 1 - 1
src/services/api/trade/index.ts

@@ -13,7 +13,7 @@ export function spotPresaleDestingOrder(params: TradeParams<Partial<Proto.SpotPr
  * 铁合金现货预售交收确认
  */
 export function spotPresaleDeliveryConfirm(params: TradeParams<Proto.SpotPresaleDeliveryConfirmReq, Proto.SpotPresaleDeliveryConfirmRsp>) {
-    return tradeServerRequest('SpotPresaleDeliveryConfirmReq', 'SpotPresaleDeliveryConfirmRsp', params);
+    return tradeServerRequest('SpotPresaleDeliveryConfirmReq', 'SpotPresaleDeliveryConfirmRsp', params, Market.THJ);
 }
 
 /**

+ 15 - 0
src/types/model/common.d.ts

@@ -144,6 +144,21 @@ declare global {
             amount: number; // 红包
         }
 
+        /** 查询用户等级信息 请求 */
+        interface UserLevelInfoReq {
+            userid: number; // 用户ID
+        }
+
+        /** 查询用户等级信息 响应 */
+        interface UserLevelInfoRsp {
+            appup: number; // 晋升已累计的数量
+            checkday: string; // 最近一次考核日
+            levelgroup: string; // 当前等级
+            nextlevelgroup: string; // 下一等级
+            notyet: number; // 晋升还差多少数量
+            progress: number; // 进度
+        }
+
         /** 文件上传请求 */
         interface uploadFileReq {
             /// 文件信息

+ 92 - 0
src/types/model/goods.d.ts

@@ -385,9 +385,101 @@ declare namespace Model {
 
     /** 查询供求列表 响应 */
     interface THJListingRsp {
+        areauserid: number; // 所属机构
+        bannerpicurl: string; // Banner图(逗号分隔)
+        convertfactor: number; // 标仓系数
+        deliverygoodsid: number; // 现货品种ID
+        isvalid: number; // 是否有效 - 0:无效 1:有效
+        minivalue: number; // 最小变动值
+        minivaluedp: number; // 最小变动值小数位
+        pictureurls: string; // 详情图片(逗号分隔)
+        realminivalue: number; // 实际最小变动值
+        realminivaluedp: number; // 实际最小变动值小数位
+        storagefee: number; // 仓储费(固定: 111)
         thumurls: string; // 缩略图片(1:1)(逗号分隔)
+        unitid: number; // 现货商品单位ID
+        vatrate: number; // 现货增值税率
+        wrsstatus: number; // 状态 - 作废 - 0:未激活 1:正常
         wrstandardcode: string; // 现货商品代码
         wrstandardid: number; // 现货商品ID(自增 SEQ_GOODS 确保不重复)
         wrstandardname: string; // 现货商品名称(模糊查询)
     }
+
+    /** 查询大厅行情列表 请求 */
+    interface OrderQuoteReq {
+        page?: number; // 页码
+        pagesize?: number; // 每页条数
+        marketid?: number; // 仓单贸易市场id
+        wrpricetype: number; // 价格方式 - 1:固定价 2-浮动价
+        haswr?: number; // 0:仓单预售 1:仓单贸易
+        dgitemname?: string; // 商品要素项名称模糊匹配, 逗号隔开, 如 产地1,品牌1,规格12mm
+        warehouseid?: number; // 仓库id(筛选条件)
+        deliverygoodsid?: number; // 品种id
+        wrstandardid?: number; // 品类id
+        brandid?: number; // 品牌id(dgfactoryitemid)
+        yearsid?: number; // 年份id(dgfactoryitemid)
+        wrfactortypeid?: number; // 仓单要素id
+        deliverymonth?: string; // 交收月(yyyy-mm) 仓单预售填写
+    }
+
+    /** 查询大厅行情列表 响应 */
+    interface OrderQuoteRsp {
+        bannerpicurl: string; // Banner图
+        buyprice: number; // 买价
+        buypricemove: number; // 买升贴水(基差)
+        buyqty: number; // 买量
+        deliverygoodscode: string; // 品种代码
+        deliverygoodsid: number; // 品种id
+        deliverygoodsname: string; // 品种名称
+        deliverymonth: string; // 交收月
+        enumdicname: string; // 单位名称
+        goodscode: string; // 商品合约(浮动价列表才有)
+        goodsid: number; // 商品id(浮动价列表才有)
+        minivalue: number; // 现货商品最小变动值
+        pictureurls: string; // 详情图片(逗号分隔)
+        sellprice: number; // 卖价
+        sellpricemove: number; // 卖升贴水(基差)
+        sellqty: number; // 卖量
+        spotgoodsprice: number; // 参考价(THJ)
+        thumurls: string; // 缩略图片(1:1)(逗号分隔)
+        warehousecode: string; // 仓库代码
+        warehouseid: number; // 仓库id
+        warehousename: string; // 仓库名称
+        wrfactortypeid: string; // 仓单要素id
+        wrfactortypename: string; // 仓单要素类型名称(选择项要素的名称合并显示,逗号分隔)
+        wrgoodsname: string; // 商品(商品名称+仓库要素名称 拼接)
+        wrstandardcode: string; // 商品代码
+        wrstandardid: number; // 商品id
+        wrstandardname: string; // 商品名称
+    }
+
+    /** 查询买卖大厅 请求 */
+    interface OrderQuoteDetailReq {
+        page?: number; // 页码
+        pagesize?: number; // 每页条数
+        marketid?: number; // 仓单贸易市场id
+        wrpricetype: number; // 价格方式 - 1:固定价 2-浮动价
+        haswr?: number; // 0:仓单预售 1:仓单贸易
+        wrfactortypeid: string; // 仓单要素id
+        goodsid?: number; // 期货商品id(浮动价方式时填)
+        buyorsell: number; // 买卖方向 0-买 1-卖
+        deliverymonth?: string; // 交收月(yyyy-mm) 查仓单预售的买卖大厅时填写
+    }
+
+    /** 查询买卖大厅 响应 */
+    interface OrderQuoteDetailRsp {
+        buyorsell: number; // 买卖 - 0:买 1:卖
+        delistminqty: number; // 期初均价
+        deliverymonth: string; // 交收月
+        enumdicname: string; // 单位名称
+        fixedprice: number; // 买(卖)价
+        marketid: number; // 市场id
+        minivalue: number; // 现货商品最小变动值
+        orderqty: number; // 买(卖)量(=委托量-成交量)
+        ordertime: string; // 委托时间
+        pricemove: number; // 买(卖)升贴水- 基差
+        userid: number; // 购买方(销售方)用户ID
+        username: string; // 购买方(销售方)
+        wrtradeorderid: string; // 仓单贸易委托单ID(320+Unix秒时间戳(10位)+xxxxxx)
+    }
 }

+ 2 - 0
src/types/model/order.d.ts

@@ -393,6 +393,8 @@ declare namespace Model {
         pledgeqty: number
         /// 数量
         qty: number
+        // 参考价(THJ)
+        spotgoodsprice: number;
         /// 提单子单号
         subnum: number
         /// 缩略图

+ 8 - 8
src/types/proto/trade.d.ts

@@ -256,7 +256,7 @@ declare global {
             Header?: IMessageHead;
             UserID: number; // 用户ID
             AccountID: number; // 资金账号
-            RelatedWRTradeOrderID: number; // 关联委托单号(摘牌委托关联挂牌委托单ID)
+            RelatedWRTradeOrderID: Long; // 关联委托单号(摘牌委托关联挂牌委托单ID)
             WRTransferUserID: number; // 仓单受让用户
             OrderQty: number; // 委托数量
             OrderSrc: number; // 委托来源
@@ -264,16 +264,16 @@ declare global {
             ClientOrderTime: string; // 客户端委托时间
             ClientType: number; // 终端类型
             OperatorID: number; // 操作员账号ID
-            BuyOrSell: number; // 买卖方向
-            ApplyID: number; // 申请ID
-            LadingBillId: number; // 提单id(wrholdlb的LadingBillId字段),卖的时候填写
-            SubNum: number; // 提单子单号(wrholdlb的SubNum字段),卖的时候填写
-            WRFactorTypeId: number; // 仓单要素ID(wrholdlb的WRFactorTypeId字段),卖的时候填写
+            BuyOrSell?: number; // 买卖方向
+            ApplyID?: number; // 申请ID
+            LadingBillId?: Long; // 提单id(wrholdlb的LadingBillId字段),卖的时候填写
+            SubNum?: number; // 提单子单号(wrholdlb的SubNum字段),卖的时候填写
+            WRFactorTypeId?: Long; // 仓单要素ID(wrholdlb的WRFactorTypeId字段),卖的时候填写
             TradeDate: string; // 交易日
-            DeliveryMonth: string; // 交收月
+            DeliveryMonth?: string; // 交收月
             HasWr: number; // 是否有仓单-0:没有仓单1:有仓单
             IsFinancing: number; // 是否融资购买(买摘牌时有效)-0:否1:是
-            ProductDetailID: number; // 金融机构产品组合ID(融资购买时有效)
+            ProductDetailID?: number; // 金融机构产品组合ID(融资购买时有效)
         }
 
         // 持仓单摘牌应答