li.shaoyi 3 tahun lalu
induk
melakukan
0f993f601c

+ 2 - 2
public/config/appconfig.json

@@ -1,5 +1,5 @@
 {
-  "version": "1.0.2",
-  "versionCode": "100002",
+  "version": "1.0.3",
+  "versionCode": "100003",
   "apiUrl": "http://218.17.158.45:16021/cfg?key=test_thj"
 }

+ 68 - 0
public/proto/thj.proto

@@ -469,4 +469,72 @@ message t2bBankDepositRsp {
 		optional string CenterErrMsg = 11; // 中心返回结果说明
 		optional string CerterCheckDate = 12; // 中心对账日期
 		optional string NetAddr = 13; // 网络地址(当这里有网址时,应自动跳转网页)
+}
+
+// 铁合金现货预售摘牌接口请求
+message SpotPresaleDestingOrderReq {
+	optional MessageHead Header = 1;
+		optional uint32 UserID = 2; // 用户ID,必填
+		optional uint64 AccountID = 3; // 资金账号,必填
+		optional uint64 PresaleApplyID = 4; // 预售申请ID,必填
+		optional uint64 Qty = 5; // 预售数量,必填
+		optional uint64 DepositID = 6; // 定金方式,THJ_PresaleApplyDeposit表ID,必填
+		optional uint32 THJDeliveryMode = 7; // 交割方式,必填1:平台仓储2:自提
+		optional string ContactName = 8; // 联系人姓名,THJDeliveryMode=2,3时必填
+		optional string ContactInfo = 9; // 联系方式,THJDeliveryMode=2,3时必填
+		optional string DesAddress = 10; // 目的地地址,THJDeliveryMode=3时必填
+		optional string ReceiptInfo = 11; // 发票信息,THJDeliveryMode=2,3时必填
+		optional uint32 ClientType = 12; // 终端类型
+		optional string ClientSerialNo = 13; // 客户端流水号
+}
+
+// 铁合金现货预售摘牌接口应答
+message SpotPresaleDestingOrderRsp {
+	optional MessageHead Header = 1; // 消息头
+	optional int32 RetCode = 2; // 返回码
+	optional string RetDesc = 3; // 描述信息
+		optional uint64 PresaleApplyID = 4; // 预售申请ID
+		optional uint64 WRTradeDetailID = 5; // 成交单ID
+		optional string ClientSerialNo = 6; // 客户端流水号
+}
+
+// 铁合金现货预售交收确认接口请求
+message SpotPresaleDeliveryConfirmReq {
+	optional MessageHead Header = 1;
+		optional uint32 UserID = 2; // 用户ID,必填
+		optional uint64 WRTradeDetailID = 3; // 采购成交单ID,必填
+		optional string Remark = 4; // 备注
+		optional uint32 ClientType = 5; // 终端类型
+		optional string ClientSerialNo = 6; // 客户端流水号
+}
+
+// 铁合金现货预售交收确认接口应答
+message SpotPresaleDeliveryConfirmRsp {
+	optional MessageHead Header = 1; // 消息头
+	optional int32 RetCode = 2; // 返回码
+	optional string RetDesc = 3; // 描述信息
+		optional uint32 UserID = 4; // 用户ID,必填
+		optional uint64 WRTradeDetailID = 5; // 采购成交单ID
+		optional string ClientSerialNo = 6; // 客户端流水号
+}
+
+// 铁合金现货预售违约确认接口请求
+message SpotPresaleBreachOfContractConfirmReq {
+	optional MessageHead Header = 1;
+		optional uint64 WRTradeDetailID = 2; // 采购成交单ID,必填
+		optional double BuyAmount = 3; // 买方应退费用,必填
+		optional double ExchangeAmount = 4; // 平台应收,必填
+		optional string HandleRemark = 5; // 处理备注
+		optional uint32 ClientType = 6; // 终端类型
+		optional string ClientSerialNo = 7; // 客户端流水号
+}
+
+// 铁合金现货预售违约确认接口应答
+message SpotPresaleBreachOfContractConfirmRsp {
+	optional MessageHead Header = 1; // 消息头
+	optional int32 RetCode = 2; // 返回码
+	optional string RetDesc = 3; // 描述信息
+		optional uint32 UserID = 4; // 用户ID,必填
+		optional uint64 WRTradeDetailID = 5; // 采购成交单ID
+		optional string ClientSerialNo = 6; // 客户端流水号
 }

+ 57 - 0
src/business/goods/index.ts

@@ -0,0 +1,57 @@
+import { shallowRef } from 'vue'
+import { useDataTable } from '@/hooks/datatable'
+import { queryTHJWrstandard, queryTHJWrstandardDetail } from '@/services/api/goods'
+
+// 采购列表
+export function useWrstandardList() {
+    const { dataList, total, pageIndex, pageSize, pageCount } = useDataTable<Model.THJWrstandardRsp>()
+    const loading = shallowRef(false)
+
+    const getWrstandardList = () => {
+        loading.value = true
+        return queryTHJWrstandard({
+            data: {
+                page: pageIndex.value,
+                pagesize: pageSize.value,
+            },
+            success: (res) => {
+                total.value = res.total
+                dataList.value = res.data
+            },
+            complete: () => {
+                loading.value = false
+            }
+        })
+    }
+
+    return {
+        loading,
+        dataList,
+        total,
+        pageIndex,
+        pageSize,
+        pageCount,
+        getWrstandardList,
+    }
+}
+
+// 采购详细
+export function useWrstandardDetails(wrstandardid: number) {
+    const details = shallowRef<Model.THJWrstandardDetailRsp>()
+
+    const getWrstandardDetails = () => {
+        return queryTHJWrstandardDetail({
+            data: {
+                wrstandardid,
+            },
+            success: (res) => {
+                console.log(res)
+            }
+        })
+    }
+
+    return {
+        details,
+        getWrstandardDetails,
+    }
+}

+ 36 - 0
src/business/trade/index.ts

@@ -0,0 +1,36 @@
+import { reactive, shallowRef } from 'vue'
+import { v4 } from 'uuid'
+import { ClientType } from '@/constants/client'
+import { useLoginStore } from '@/stores'
+import { spotPresaleDestingOrder } from '@/services/api/trade'
+
+// 采购摘牌
+export function usePurchaseOrderDesting() {
+    const { getUserId, getFirstAccountId } = useLoginStore()
+    const loading = shallowRef(false)
+
+    const formData = reactive<Partial<Proto.SpotPresaleDestingOrderReq>>({
+        UserID: getUserId(), // 用户ID,必填
+        AccountID: getFirstAccountId(), // 资金账号,必填
+        ClientType: ClientType.Web // 终端类型
+    })
+
+    const formSubmit = () => {
+        loading.value = true
+        return spotPresaleDestingOrder({
+            data: {
+                ...formData,
+                ClientSerialNo: v4() // 客户端流水号
+            },
+            complete: () => {
+                loading.value = false
+            }
+        })
+    }
+
+    return {
+        loading,
+        formData,
+        formSubmit,
+    }
+}

+ 28 - 0
src/constants/client.ts

@@ -0,0 +1,28 @@
+import { useEnumStore } from '@/stores'
+
+const { getEnumTypeList } = useEnumStore()
+
+/**
+ * 客户端类型
+ */
+export enum ClientType {
+    None = 0,  // 保留为未填终端类型
+    PCManager = 1,  // PC管理端
+    PCTrade = 2,  // PC交易端
+    Android = 3,  // 手机客户端_安卓
+    Web = 4,  // 网页客户端
+    Wechat = 5,  // 微信客户端
+    IOS = 6,  // 手机客户端_苹果
+    AccountOnline = 7,  // 网上开户客户端
+    Invalid = 8,  // 无效终端编号
+    Quote = 9,  // 报价终端
+    TradeInterface = 10 // 交易接口
+}
+
+/**
+ * 获取客户端类型列表
+ * @returns 
+ */
+export function getClientTypeList() {
+    return getEnumTypeList('clientType')
+}

+ 7 - 0
src/constants/funcode.ts

@@ -43,4 +43,11 @@ export enum FunCode {
     QuoteSubscribeRsp = 0x21, // 实时行情订阅响应
     QueryQuoteReq = 0x22, // 盘面查询请求
     QueryQuoteRsp = 0x23, // 盘面查询应答
+
+    SpotPresaleDestingOrderReq = 1441849, // 铁合金现货预售摘牌接口请求
+    SpotPresaleDestingOrderRsp = 1441850, // 铁合金现货预售摘牌接口应答
+    SpotPresaleDeliveryConfirmReq = 1441861, // 铁合金现货预售交收确认接口请求
+    SpotPresaleDeliveryConfirmRsp = 1441862, // 铁合金现货预售交收确认接口应答
+    SpotPresaleBreachOfContractConfirmReq = 1441857, // 铁合金现货预售违约确认接口请求
+    SpotPresaleBreachOfContractConfirmRsp = 1441858, // 铁合金现货预售违约确认接口应答
 }

+ 9 - 0
src/constants/market.ts

@@ -0,0 +1,9 @@
+/**
+ * 交易市场
+ */
+export enum Market {
+    /** 广钻 */
+    GZ = 67201,
+    /** 铁合金 */
+    THJ = 64201,
+}

+ 4 - 1
src/packages/mobile/components/base/pull-refresh/index.less

@@ -1 +1,4 @@
-.app-pull-refresh {}
+.app-pull-refresh {
+    height    : 100%;
+    overflow-y: auto;
+}

+ 33 - 9
src/packages/mobile/components/base/pull-refresh/index.vue

@@ -1,17 +1,23 @@
 <template>
     <PullRefresh class="app-pull-refresh" v-model="refreshing" @refresh="onRefresh">
         <slot name="header"></slot>
-        <List v-model:loading="loading" :finished="finished" :finished-text="finishedText" @load="onLoad">
+        <List v-model:loading="loading" v-model:error="showError" :finished="finished" @load="onLoad">
             <template v-for="(item, index) in dataList" :key="index">
                 <slot :item="item" :index="index"></slot>
             </template>
+            <template #finished>
+                <span>{{ finishedText }}</span>
+            </template>
+            <template #error>
+                <span>{{ errorText }}</span>
+            </template>
         </List>
         <slot name="footer"></slot>
     </PullRefresh>
 </template>
 
 <script lang="ts" setup>
-import { shallowRef } from 'vue'
+import { shallowRef, computed } from 'vue'
 import { List, PullRefresh } from 'vant'
 
 const props = defineProps({
@@ -27,19 +33,32 @@ const props = defineProps({
         type: Number,
         default: 1,
     },
+    error: {
+        type: Boolean,
+        default: false,
+    },
     finishedText: {
         type: String,
         default: '没有更多了',
+    },
+    errorText: {
+        type: String,
+        default: '请求失败,点击重新加载',
     }
 })
 
-const emit = defineEmits(['update:pageIndex', 'refresh', 'updated'])
+const emit = defineEmits(['update:pageIndex', 'update:error', 'refresh', 'updated'])
 const refreshing = shallowRef(false) // 是否处于下拉加载状态
 const finished = shallowRef(false) // 是否已加载完成所有数据
 const loading = shallowRef(false)
 // eslint-disable-next-line
 const dataList = shallowRef<any[]>([])
 
+const showError = computed({
+    get: () => props.error,
+    set: (val) => emit('update:error', val)
+})
+
 // 上拉加载
 const onLoad = () => {
     let pageIndex = props.pageIndex
@@ -53,12 +72,13 @@ const onLoad = () => {
             dataList.value = []
             refreshing.value = false
         }
-        pageIndex++
-        dataList.value.push(...props.updateList)
+        if (!showError.value) {
+            pageIndex++
+            dataList.value.push(...props.updateList)
+            emit('update:pageIndex', pageIndex)
+            emit('updated', dataList.value)
+        }
         loading.value = false
-
-        emit('update:pageIndex', pageIndex)
-        emit('updated', dataList.value)
     }
 
     if (pageIndex <= props.pageCount) {
@@ -75,4 +95,8 @@ const onRefresh = () => {
     loading.value = true
     onLoad()
 }
-</script>
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 14 - 0
src/packages/mobile/router/index.ts

@@ -116,6 +116,20 @@ const routes: Array<RouteRecordRaw> = [
     ]
   },
   {
+    path: '/goods',
+    component: Page,
+    children: [
+      {
+        path: 'details',
+        name: 'goods-details',
+        component: () => import('../views/goods/details/index.vue'),
+        meta: {
+          ignoreAuth: true,
+        },
+      }
+    ]
+  },
+  {
     path: '/market',
     component: Page,
     children: [

+ 3 - 3
src/packages/mobile/views/bank/statement/index.vue

@@ -5,7 +5,7 @@
             </app-navbar>
         </template>
         <app-pull-refresh class="credit-statement__container" v-model:pageIndex="pageIndex" :page-count="pageCount"
-            :updateList="dataList" @refresh="onRefresh" @updated="onUpdated">
+            :updateList="dataList" @refresh="onRefresh" @updated="onRefreshUpdated">
             <template #header>
                 <ul class="list list-row" v-if="showHeader">
                     <li class="list-column">
@@ -44,10 +44,10 @@ const { dataList, pageIndex, pageCount, getBankStatementList } = useBankStatemen
 const showHeader = shallowRef(false)
 
 const onRefresh = (callback: () => void) => {
-    getBankStatementList().then(() => callback())
+    getBankStatementList().finally(() => callback())
 }
 
-const onUpdated = (data: Model.UserScoreLogRsp[]) => {
+const onRefreshUpdated = (data: Model.UserScoreLogRsp[]) => {
     showHeader.value = data.length > 0
 }
 </script>

+ 3 - 3
src/packages/mobile/views/credit/statement/index.vue

@@ -5,7 +5,7 @@
             </app-navbar>
         </template>
         <app-pull-refresh class="credit-statement__container" v-model:pageIndex="pageIndex" :page-count="pageCount"
-            :updateList="dataList" @refresh="onRefresh" @updated="onUpdated">
+            :updateList="dataList" @refresh="onRefresh" @updated="onRefreshUpdated">
             <template #header>
                 <ul class="list list-row" v-if="showHeader">
                     <li class="list-column">
@@ -44,10 +44,10 @@ const { dataList, pageIndex, pageCount, getCreditStatementList } = useCreditStat
 const showHeader = shallowRef(false)
 
 const onRefresh = (callback: () => void) => {
-    getCreditStatementList().then(() => callback())
+    getCreditStatementList().finally(() => callback())
 }
 
-const onUpdated = (data: Model.UserScoreLogRsp[]) => {
+const onRefreshUpdated = (data: Model.UserScoreLogRsp[]) => {
     showHeader.value = data.length > 0
 }
 </script>

+ 1 - 0
src/packages/mobile/views/goods/details/index.less

@@ -0,0 +1 @@
+.goods-details {}

+ 28 - 0
src/packages/mobile/views/goods/details/index.vue

@@ -0,0 +1,28 @@
+<template>
+    <app-view class="goods-details">
+        <template #header>
+            <app-navbar title="采购详情" />
+        </template>
+    </app-view>
+</template>
+
+<script lang="ts" setup>
+import { useNavigation } from '@/hooks/navigation'
+import { useWrstandardDetails } from '@/business/goods'
+import { usePurchaseOrderDesting } from '@/business/trade'
+
+const props = defineProps({
+    wrstandardid: {
+        type: Number,
+        required: true
+    }
+})
+
+const { details, getWrstandardDetails } = useWrstandardDetails(props.wrstandardid)
+
+getWrstandardDetails()
+</script>
+
+<style lang="less">
+@import './index.less';
+</style>

+ 13 - 10
src/packages/mobile/views/home/components/main/index.vue

@@ -91,7 +91,18 @@ const newsList = shallowRef<Model.SiteColumnDetailRsp[]>([]) // 资讯列表
 
 // 下拉刷新
 const onRefresh = () => {
-  refreshing.value = false
+  querySiteColumnDetail({
+    data: {
+      page: 1,
+      pagesize: 10,
+    },
+    success: (res) => {
+      newsList.value = res.data
+    },
+    complete: () => {
+      refreshing.value = false
+    }
+  })
 }
 
 queryImageConfigs({
@@ -112,15 +123,7 @@ queryImageConfigs({
   }
 })
 
-querySiteColumnDetail({
-  data: {
-    page: 1,
-    pagesize: 10,
-  },
-  success: (res) => {
-    newsList.value = res.data
-  }
-})
+onRefresh()
 </script>
 
 <style lang="less">

+ 22 - 8
src/packages/mobile/views/home/components/purchase/index.vue

@@ -7,21 +7,35 @@
         </template>
       </app-navbar>
     </template>
-    <div class="home-purchase__container">
-      <CellGroup>
-        <Cell v-for="i in 4" :key="i">
+    <app-pull-refresh class="home-purchase__container" v-model:error="error" v-model:pageIndex="pageIndex"
+      :page-count="pageCount" :updateList="dataList" @refresh="onRefresh">
+      <template #default="{ item }">
+        <Cell @click="$router.push({ name: 'goods-details' })">
           <template #title>
-            <img src="http://103.40.249.123:8070/onlineopen/uploadFile/20221020/202210201817131130.jpg" />
-            <span>硅锰合金</span>
+            <img :src="getImageUrl(item.thumurls)" />
+            <span>{{ item.wrstandardname }}</span>
           </template>
         </Cell>
-      </CellGroup>
-    </div>
+      </template>
+    </app-pull-refresh>
   </app-view>
 </template>
 
 <script lang="ts" setup>
-import { Cell, CellGroup, Search } from 'vant'
+import { shallowRef } from 'vue'
+import { Cell, Search } from 'vant'
+import { getImageUrl } from '@/filters'
+import { useWrstandardList } from '@/business/goods'
+import AppPullRefresh from '@mobile/components/base/pull-refresh/index.vue'
+
+const { dataList, pageIndex, pageCount, getWrstandardList } = useWrstandardList()
+const error = shallowRef(false)
+
+const onRefresh = (callback: () => void) => {
+  getWrstandardList().catch(() => {
+    error.value = true
+  }).finally(() => callback())
+}
 </script>
 
 <style lang="less">

+ 1 - 1
src/packages/mobile/views/home/index.vue

@@ -59,7 +59,7 @@ const tabList: Tabbar[] = [
 ]
 
 const onChange = (index: number) => {
-  if ([0, 3].includes(index)) {
+  if (index !== 2) {
     componentId.value = tabList[index].name
   }
 }

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

@@ -6,4 +6,18 @@ import { HttpParams } from '@/services/http/interface'
  */
 export function queryGoodsList(params: HttpParams<{ rsp: Model.GoodsRsp[] }>) {
     return httpRequest('/goods', 'get', params);
+}
+
+/**
+ * 查询采购列表
+ */
+export function queryTHJWrstandard(params: HttpParams<{ req: Model.THJWrstandardReq, rsp: Model.THJWrstandardRsp[] }>) {
+    return httpRequest('/Ferroalloy/QueryTHJWrstandard', 'get', params);
+}
+
+/**
+ * 查询采购详情
+ */
+export function queryTHJWrstandardDetail(params: HttpParams<{ req: Model.THJWrstandardDetailReq, rsp: Model.THJWrstandardDetailRsp[] }>) {
+    return httpRequest('/Ferroalloy/QueryTHJWrstandardDetail', 'get', params);
 }

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

@@ -0,0 +1,23 @@
+import { tradeServerRequest } from '@/services/socket/trade'
+import { TradeParams } from '@/services/socket/trade/interface'
+
+/**
+ * 铁合金现货预售摘牌
+ */
+export function spotPresaleDestingOrder(params: TradeParams<Partial<Proto.SpotPresaleDestingOrderReq>, Proto.SpotPresaleDestingOrderRsp>) {
+    return tradeServerRequest('SpotPresaleDestingOrderReq', 'SpotPresaleDestingOrderRsp', params);
+}
+
+/**
+ * 铁合金现货预售交收确认
+ */
+export function spotPresaleDeliveryConfirm(params: TradeParams<Proto.SpotPresaleDeliveryConfirmReq, Proto.SpotPresaleDeliveryConfirmRsp>) {
+    return tradeServerRequest('SpotPresaleDeliveryConfirmReq', 'SpotPresaleDeliveryConfirmRsp', params);
+}
+
+/**
+ * 铁合金现货预售违约确认
+ */
+export function spotPresaleBreachOfContractConfirm(params: TradeParams<Proto.SpotPresaleBreachOfContractConfirmReq, Proto.SpotPresaleBreachOfContractConfirmRsp>) {
+    return tradeServerRequest('SpotPresaleBreachOfContractConfirmReq', 'SpotPresaleBreachOfContractConfirmRsp', params);
+}

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

@@ -74,4 +74,55 @@ declare namespace Model {
             isvalid: number; // 是否有效 0-无效 1-有效
         }
     }
+
+    /** 查询采购列表 请求 */
+    interface THJWrstandardReq {
+        page?: number; // 页码
+        pagesize?: number; // 每页条数
+        wrstandardname?: string; // 现货商品名称(模糊查询)
+    }
+
+    /** 查询采购列表 响应 */
+    interface THJWrstandardRsp {
+        thumurls: string; // 缩略图片(1:1)(逗号分隔)
+        wrstandardcode: string; // 现货商品代码
+        wrstandardid: number; // 现货商品ID(自增 SEQ_GOODS 确保不重复)
+        wrstandardname: string; // 现货商品名称(模糊查询)
+    }
+
+    /** 查询采购详情 请求 */
+    interface THJWrstandardDetailReq {
+        wrstandardid: number; // 现货商品ID
+    }
+
+    /** 查询采购详情 响应 */
+    interface THJWrstandardDetailRsp {
+        deliveryModes: {
+            enumdicname: string; // 枚举项名称
+            enumitemname: number; // 枚举项值
+        }[];
+        deliveryMonth: {
+            enddate: string; // 预售结束日期(yyyy-mm-dd)
+            endmonth: string; // 预售结束月份(yyyy-mm)
+            orderqty: number; // 委托数量
+            presaleapplyid: number; // 预售申请ID(184+Unix秒时间戳(10位)+xxxxxx)
+            remainqty: number; // 可用数量
+            tradeqty: number; // 成交数量
+        }[];
+        goodsInfo: {
+            pictureurls: string; // 详情图片(逗号分隔)
+            spotgoodsprice: number; // 现货价格
+            wrstandardcode: string; // 现货商品代码
+            wrstandardid: number; // 现货商品ID(自增 SEQ_GOODS 确保不重复)
+            wrstandardname: string; // 现货商品名称
+        }[];
+        presaleApplyDeposits: {
+            depositrate: number; // 定金比例
+            discountamount: number; // 优惠金额(每吨)
+        }[];
+        spotGoodsPriceLogs: {
+            spotgoodsprice: number; // 现货价格
+            tradedate: string; // 交易日(yyyyMMdd)
+        }[];
+    }
 }

+ 73 - 0
src/types/proto/trade.d.ts

@@ -0,0 +1,73 @@
+import { IMessageHead } from '@/services/socket/trade/protobuf/proto'
+
+declare global {
+    namespace Proto {
+        /** 铁合金现货预售摘牌接口请求 */
+        interface SpotPresaleDestingOrderReq {
+            Header?: IMessageHead;
+            UserID: number; // 用户ID,必填
+            AccountID: number; // 资金账号,必填
+            PresaleApplyID: number; // 预售申请ID,必填
+            Qty: number; // 预售数量,必填
+            DepositID: number; // 定金方式,THJ_PresaleApplyDeposit表ID,必填
+            THJDeliveryMode: number; // 交割方式,必填1:平台仓储2:自提
+            ContactName: string; // 联系人姓名,THJDeliveryMode=2,3时必填
+            ContactInfo: string; // 联系方式,THJDeliveryMode=2,3时必填
+            DesAddress: string; // 目的地地址,THJDeliveryMode=3时必填
+            ReceiptInfo: string; // 发票信息,THJDeliveryMode=2,3时必填
+            ClientType: number; // 终端类型
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 铁合金现货预售摘牌接口应答 */
+        interface SpotPresaleDestingOrderRsp {
+            Header?: IMessageHead;
+            RetCode: number; // 返回码
+            RetDesc: string; // 描述信息
+            PresaleApplyID: number; // 预售申请ID
+            WRTradeDetailID: number; // 成交单ID
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 铁合金现货预售交收确认接口请求 */
+        interface SpotPresaleDeliveryConfirmReq {
+            Header?: IMessageHead;
+            UserID: number; // 用户ID,必填
+            WRTradeDetailID: number; // 采购成交单ID,必填
+            Remark: string; // 备注
+            ClientType: number; // 终端类型
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 铁合金现货预售交收确认接口应答 */
+        interface SpotPresaleDeliveryConfirmRsp {
+            Header?: IMessageHead;
+            RetCode: number; // 返回码
+            RetDesc: string; // 描述信息
+            UserID: number; // 用户ID,必填
+            WRTradeDetailID: number; // 采购成交单ID
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 铁合金现货预售违约确认接口请求 */
+        interface SpotPresaleBreachOfContractConfirmReq {
+            Header?: IMessageHead;
+            WRTradeDetailID: number; // 采购成交单ID,必填
+            BuyAmount: number; // 买方应退费用,必填
+            ExchangeAmount: number; // 平台应收,必填
+            HandleRemark: string; // 处理备注
+            ClientType: number; // 终端类型
+            ClientSerialNo: string; // 客户端流水号
+        }
+
+        /** 铁合金现货预售违约确认接口应答 */
+        interface SpotPresaleBreachOfContractConfirmRsp {
+            Header?: IMessageHead;
+            RetCode: number; // 返回码
+            RetDesc: string; // 描述信息
+            UserID: number; // 用户ID,必填
+            WRTradeDetailID: number; // 采购成交单ID
+            ClientSerialNo: string; // 客户端流水号
+        }
+    }
+}