Forráskód Böngészése

今日工作12.12 接口联调 1,C2C和大宗交易的聊天、购买及出售3个模块整体流程完成,还有一些细节未完善 2,支付宝账户添加 3,设置密码 页面修改 1,C2C,快捷交易,大宗交易 2,重写axios接口文件,调整为将所有数据全部返回。post,get请求方式修改 3,OTC购买和出售逻辑修改 新增页面 1,设置密码 2,输入密码

jhaoG 2 hete
szülő
commit
9db96e9879

BIN
dist.zip


+ 1 - 0
src/api/index.js

@@ -1,6 +1,7 @@
 import request from "@/utils/request";
 
 // 登录接口
+// data表示body params表示拼接在路由后面
 export function login(data) {
   return request({
     url: "/custom/login/",

+ 2 - 1
src/api/otc.js

@@ -1,4 +1,5 @@
 import request from "@/utils/request";
+import axiosRequest from "@/utils/axiosRequest";
 
 // 挂单列表
 export function GetOTCPendingOrder(params) {
@@ -28,7 +29,7 @@ export function GetPayList(id) {
 
 // 获取OTC下单
 export function BuyCoin(data) {
-  return request({
+  return axiosRequest({
     url: `/otc/otc_order/buy_coin/`,
     method: "post",
     data,

+ 9 - 0
src/api/user.js

@@ -7,3 +7,12 @@ export function getInviteInfo() {
     method: "get",
   });
 }
+
+// 设置密码
+export function setPassword(data) {
+  return request({
+    url: "/custom/custom/set_password/",
+    method: "post",
+    data,
+  });
+}

+ 1 - 0
src/router/index.js

@@ -71,6 +71,7 @@ import OptionTrading from "@/views/bitcoin/lever/OptionTrading.vue";
 import AddressAuth from "@/views/user/AddressAuth.vue";
 import RelativeAuth from "@/views/user/RelativeAuth.vue";
 import LanguageSwitch from "@/views/user/LanguageSwitch.vue"; //语言国际化
+import InputPassword from "@/views/user/InputPassword.vue";
 
 const routes = [
   {

+ 40 - 0
src/utils/axiosRequest.js

@@ -0,0 +1,40 @@
+import axios from "axios";
+import { showToast, showFailToast } from "vant";
+import "vant/es/toast/style";
+
+const service = axios.create({
+  baseURL: process.env.VUE_APP_BASE_API || "/api",
+  timeout: 10000,
+  headers: {
+    "Content-Type": "application/json;charset=utf-8",
+  },
+});
+
+service.interceptors.request.use(
+  (config) => {
+    const token = localStorage.getItem("token");
+    if (token) {
+      config.headers["Authorization"] = "JWT " + token;
+    }
+    return config;
+  },
+  (error) => {
+    console.log(error);
+    return Promise.reject(error);
+  }
+);
+
+service.interceptors.response.use((response) => {
+  const res = response.data;
+  // else if (res.msg == "please set your password") {
+  //   showFailToast("您还没有设置密码,请设置密码");
+  // }
+  if (res.code === 401) {
+    localStorage.removeItem("token");
+    location.reload();
+  } else {
+    return res;
+  }
+});
+
+export default service;

+ 2 - 2
src/utils/request.js

@@ -43,11 +43,11 @@ service.interceptors.response.use(
     if (res.code !== "00000") {
       // 特殊处理:比如 401 表示 Token 过期,需要跳回登录页
       if (res.code === 401) {
-        //以此处逻辑为准:清除本地数据,强制刷新或跳转
         localStorage.removeItem("token");
         location.reload();
+      } else if (res.msg == "please set your password") {
+        showFailToast("您还没有设置密码,请设置密码");
       }
-
       // return Promise.reject(new Error(res.msg || "Error"));
     } else {
       // 成功,直接把数据剥离出来

+ 37 - 16
src/views/asset/dialog/C2CBuy.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="sell-and-buy">
-    <div class="apply-mask" @click="emits('sellAndBuyClose')"></div>
+    <div class="apply-mask" @click="emits('BuyClose')"></div>
     <div class="apply-content">
       <div class="slide-line"></div>
       <div class="apply-text pf600 fs18 fc121212">购买</div>
@@ -57,22 +57,27 @@
       </div>
       <div class="sure-btn pf600 fs14 fcFFFFFF" @click="sureBuy">确定购买</div>
     </div>
+    <InputPassword
+      v-show="inputPasswordFlag"
+      @inputPasswordClose="inputPasswordClose"></InputPassword>
   </div>
 </template>
 <script setup>
-  import { useRoute, useRouter } from "vue-router";
-  import { GetPayList, BuyCoin } from "@/api/otc";
+  import { useRouter } from "vue-router";
+  import { BuyCoin } from "@/api/otc";
   import { watch, ref } from "vue";
+  import { showToast, showFailToast } from "vant";
+  import InputPassword from "@/views/user/InputPassword.vue";
 
   const router = useRouter();
   const props = defineProps(["otcId", "chatId", "orderId"]);
-  const emits = defineEmits(["sellAndBuyClose"]);
+  const emits = defineEmits(["BuyClose"]);
 
   const payList = ref({});
   const otcId = ref();
   const chatId = ref();
   const orderId = ref();
-  const buyCount = ref(0);
+  const buyCount = ref();
 
   watch(
     () => props.otcId,
@@ -97,20 +102,36 @@
     }
   );
 
-  const sureBuy = async () => {
-    const params = {
-      pid: orderId.value,
-      count: buyCount.value,
-    };
-    const data = await BuyCoin(params);
-    if (data == "success") {
-      router.push({
-        name: "OTCCustomService",
-        params: { chatId: chatId.value, otcId: otcId.value },
-      });
+  const inputPasswordFlag = ref(false);
+  const inputPasswordClose = async (password) => {
+    inputPasswordFlag.value = false;
+
+    if (buyCount.value > 0) {
+      const params = {
+        pid: orderId.value,
+        count: buyCount.value,
+        password: password,
+      };
+      const data = await BuyCoin(params);
+      if (data.msg == "please set your password") {
+        showFailToast("请前往个人中心设置您的密码");
+      } else if (data.msg == "password error") {
+        showFailToast("支付密码错误");
+      } else if (data.data == "success") {
+        router.push({
+          name: "OTCCustomService",
+          params: { chatId: chatId.value, otcId: otcId.value },
+        });
+      }
+    } else {
+      showFailToast("请输入您要卖出的数量");
     }
   };
 
+  const sureBuy = async () => {
+    inputPasswordFlag.value = true;
+  };
+
   const goAddBankAccount = () => {
     router.push("/addBankAccount");
   };

+ 55 - 9
src/views/asset/dialog/C2CSell.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="sell-and-buy">
-    <div class="apply-mask" @click="emits('sellAndBuyClose')"></div>
+    <div class="apply-mask" @click="emits('sellClose')"></div>
     <div class="apply-content">
       <div class="slide-line"></div>
       <div class="apply-text pf600 fs18 fc121212">出售</div>
@@ -34,7 +34,8 @@
         <input
           type="text"
           class="input pf400 fs14 fc333333"
-          placeholder="请输入卖出数量" />
+          placeholder="请输入卖出数量"
+          v-model="buyCount" />
         <div class="all pf400 fs14 fc333333">USDT <span class="fcDF384C">全部</span></div>
       </div>
       <div class="use-number pf400 fs12 fc333333">可卖&nbsp; 215.0508 USDT</div>
@@ -47,28 +48,73 @@
       </div>
       <div class="account pf500 fs14 fc999999">
         <div>收款账号</div>
-        <div class="account-right fcDF384C" @click="goAddBankAccount">
+        <div class="account-right fcDF384C">
           请选择
           <img src="@/assets/icon/asset/right-arrow-black.svg" alt="" />
         </div>
       </div>
-      <div class="sure-btn pf600 fs14 fcFFFFFF" @click="goAddzfbAccount">确定出售</div>
+      <div class="sure-btn pf600 fs14 fcFFFFFF" @click="sureSell">确定出售</div>
     </div>
+    <InputPassword
+      v-show="inputPasswordFlag"
+      @inputPasswordClose="inputPasswordClose"></InputPassword>
   </div>
 </template>
 <script setup>
   import { useRoute, useRouter } from "vue-router";
+  import { watch, ref } from "vue";
+  import { BuyCoin } from "@/api/otc";
+  import { showToast, showFailToast } from "vant";
+  import InputPassword from "@/views/user/InputPassword.vue";
 
   const router = useRouter();
 
-  const emits = defineEmits(["sellAndBuyClose"]);
+  const props = defineProps(["otcId", "orderId"]);
+  const emits = defineEmits(["sellClose"]);
 
-  const goAddzfbAccount = () => {
-    router.push("/addzfbAccount");
+  const otcId = ref();
+  const orderId = ref();
+  const buyCount = ref();
+
+  watch(
+    () => props.otcId,
+    async (newVal, oldVal) => {
+      otcId.value = newVal;
+      console.log(otcId.value);
+    }
+  );
+
+  watch(
+    () => props.orderId,
+    async (newVal, oldVal) => {
+      orderId.value = newVal;
+    }
+  );
+
+  const inputPasswordFlag = ref(false);
+  const inputPasswordClose = async (password) => {
+    if (buyCount.value > 0) {
+      const params = {
+        pid: orderId.value,
+        count: buyCount.value,
+        password: password,
+      };
+      const data = await BuyCoin(params);
+      if (data.msg == "password error") {
+        showFailToast("支付密码错误");
+      } else if (data.msg == "please set your password") {
+        showFailToast("请前往个人中心设置您的密码");
+      } else if (data.data == "success") {
+        showToast("出售成功");
+        emits("sellClose");
+      }
+    } else {
+      showFailToast("请输入您要卖出的数量");
+    }
   };
 
-  const goAddBankAccount = () => {
-    router.push("/addBankAccount");
+  const sureSell = async () => {
+    inputPasswordFlag.value = true;
   };
 </script>
 <style lang="less" scoped>

+ 2 - 2
src/views/asset/dialog/NotPaymentWay.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="payment-way">
-    <div class="apply-mask" @click="emits('notPaymentWayClose')"></div>
+    <div class="apply-mask" @click="emits('paymentWayClose')"></div>
     <div class="apply-content">
       <div class="slide-line"></div>
       <img src="@/assets/icon/asset/not-payment-way.svg" alt="" />
@@ -10,7 +10,7 @@
   </div>
 </template>
 <script setup>
-  const emits = defineEmits(["notPaymentWayClose"]);
+  const emits = defineEmits(["paymentWayClose"]);
 </script>
 <style lang="less" scoped>
   .payment-way {

+ 16 - 2
src/views/asset/dialog/PaymentWay.vue

@@ -5,9 +5,16 @@
       <div class="slide-line"></div>
       <div class="apply-text pf600 fs18 fc121212">支付方式</div>
       <div class="payment-main">
-        <div class="payment-item" v-for="(item, index) in paymentWayData" :key="index">
+        <div
+          class="payment-item"
+          v-for="(item, index) in paymentWayData"
+          :key="index"
+          @click="paymentChoiceData(index)">
           <div class="pf500 fs16 fc121212">{{ item }}</div>
-          <img src="@/assets/icon/asset/ic_check_blue.svg" alt="" />
+          <img
+            src="@/assets/icon/asset/ic_check_blue.svg"
+            alt=""
+            v-if="paymentChoice == index" />
         </div>
       </div>
       <div class="sure-btn pf600 fs14 fcFFFFFF">确认</div>
@@ -16,9 +23,16 @@
   </div>
 </template>
 <script setup>
+  import { ref } from "vue";
+
   const emits = defineEmits(["paymentWayClose"]);
 
+  const paymentChoice = ref(0);
   const paymentWayData = ["全部", "支付宝", "银行卡"];
+
+  const paymentChoiceData = (index) => {
+    paymentChoice.value = index;
+  };
 </script>
 <style lang="less" scoped>
   .payment-way {

+ 1 - 1
src/views/asset/otc/message/CustomerService.vue

@@ -145,7 +145,7 @@
    ========================================================== */
   const initWebSocket = () => {
     const token = localStorage.getItem("token");
-    ws = new WebSocket(`ws://63.141.230.43:57676/ws/custom_chat/?token=${token}`);
+    ws = new WebSocket(`wss://test2.66linknow.com/ws/custom_chat/?token=${token}`);
 
     ws.onopen = () => {
       console.log("WebSocket 已连接");

+ 12 - 5
src/views/asset/otc/message/Index.vue

@@ -15,7 +15,8 @@
     <div
       class="merchant-service margin-top17"
       v-for="(item, index) in OTCChatData"
-      :key="index">
+      :key="index"
+      @click="chatMessage(item.id, item.otc)">
       <div class="service-left">
         <img src="@/assets/img/asset/Avatar.svg" class="platform-head" alt="" />
         <div class="left-info">
@@ -29,18 +30,24 @@
 </template>
 <script setup>
   import HeaderNav from "../../../index/components/HeaderNav.vue";
-  import { GetOTCChat, GetOTCChatDetails } from "@/api/otc";
+  import { GetOTCChat } from "@/api/otc";
   import { ref, onMounted } from "vue";
+  import { useRouter } from "vue-router";
+
+  const router = useRouter();
 
   const OTCChatData = ref();
 
   const getOTCChatData = async () => {
     const data = await GetOTCChat();
     OTCChatData.value = data.list;
-    console.log(OTCChatData.value);
+  };
 
-    const data1 = await GetOTCChatDetails(OTCChatData.value[0].otc);
-    console.log(2, data1);
+  const chatMessage = (id, otc) => {
+    router.push({
+      name: "OTCCustomService",
+      params: { chatId: id, otcId: otc },
+    });
   };
 
   onMounted(async () => {

+ 1 - 0
src/views/asset/otc/transaction/AddBankAccount.vue

@@ -56,6 +56,7 @@
 
   const submit = async () => {
     const params = {
+      type: 1,
       name: name.value,
       phone: phone.value,
       open_bank: bankOfDeposit.value,

+ 42 - 4
src/views/asset/otc/transaction/AddzfbAccount.vue

@@ -4,25 +4,41 @@
     <div class="account-item">
       <div class="item-title pf500 fs14 fc333333">姓名</div>
       <div class="left-input">
-        <input type="text" class="input pf400 fs14 fc333333" placeholder="请输入" />
+        <input
+          type="text"
+          class="input pf400 fs14 fc333333"
+          placeholder="请输入"
+          v-model="name" />
       </div>
     </div>
     <div class="account-item">
       <div class="item-title pf500 fs14 fc333333">手机号</div>
       <div class="left-input">
-        <input type="text" class="input pf400 fs14 fc333333" placeholder="请输入" />
+        <input
+          type="text"
+          class="input pf400 fs14 fc333333"
+          placeholder="请输入"
+          v-model="phone" />
       </div>
     </div>
     <div class="account-item">
       <div class="item-title pf500 fs14 fc333333">身份证号</div>
       <div class="left-input">
-        <input type="text" class="input pf400 fs14 fc333333" placeholder="请输入" />
+        <input
+          type="text"
+          class="input pf400 fs14 fc333333"
+          placeholder="请输入"
+          v-model="bankOfDeposit" />
       </div>
     </div>
     <div class="account-item">
       <div class="item-title pf500 fs14 fc333333">支付宝账号</div>
       <div class="left-input">
-        <input type="text" class="input pf400 fs14 fc333333" placeholder="请输入" />
+        <input
+          type="text"
+          class="input pf400 fs14 fc333333"
+          placeholder="请输入"
+          v-model="bankNumber" />
       </div>
     </div>
     <div class="submit pf600 fs14 fcFFFFFF" @click="submit">提交</div>
@@ -30,6 +46,28 @@
 </template>
 <script setup>
   import HeaderNav from "../../../index/components/HeaderNav.vue";
+  import { AddBankManager } from "@/api/otc";
+  import { ref } from "vue";
+
+  const name = ref();
+  const phone = ref();
+  const bankOfDeposit = ref();
+  const bankNumber = ref();
+
+  const submit = async () => {
+    const params = {
+      type: 2,
+      name: name.value,
+      phone: phone.value,
+      open_bank: bankOfDeposit.value,
+      card_number: bankNumber.value,
+    };
+    const data = await AddBankManager(params);
+    if (data) {
+      // 差一个跳转到购买的页面
+      console.log(data);
+    }
+  };
 </script>
 <style lang="less" scoped>
   .add-zfb-account {

+ 254 - 21
src/views/asset/otc/transaction/Bulk.vue

@@ -1,9 +1,19 @@
 <template>
-  <!-- <img src="@/assets/icon/asset/dazong-sell-banner.svg" class="c2c" alt="" /> -->
+  <!-- <img src="@/assets/icon/asset/c2c.svg" class="c2c" alt="" /> -->
   <div class="buy-sell">
     <div class="buy-left">
-      <div class="buy-btn pf500 fs14 fcFFFFFF">购买</div>
-      <div class="sell-btn pf500 fs14 fc999999">出售</div>
+      <div
+        class="buy-btn pf500 fs14 fc999999"
+        :class="buySellFlag == 1 ? 'buy-green' : ''"
+        @click="buySellData(1)">
+        购买
+      </div>
+      <div
+        class="sell-btn pf500 fs14 fc999999"
+        :class="buySellFlag == 2 ? 'buy-red' : ''"
+        @click="buySellData(2)">
+        出售
+      </div>
     </div>
     <div class="buy-right">
       <div class="text pf400 fs14 fc333333">CNY</div>
@@ -17,67 +27,266 @@
         <div class="text pf400 fs14 fc333333">BTC</div>
         <img src="@/assets/icon/asset/bottom-arrow-black.svg" class="bottom-arrow" />
       </div>
-      <div class="left-money">
+      <div class="left-money" @click="amountFlag = true">
         <div class="text pf400 fs14 fc333333">金额</div>
         <img src="@/assets/icon/asset/bottom-arrow-black.svg" class="bottom-arrow" />
       </div>
-      <div class="left-pay-way">
+      <div class="left-pay-way" @click="paymentWayFlag = true">
         <div class="text pf400 fs14 fc333333">支付方式</div>
         <img src="@/assets/icon/asset/bottom-arrow-black.svg" class="bottom-arrow" />
       </div>
     </div>
-    <div class="filter-right">
+    <div class="filter-right" @click="filterFlag = true">
       <img src="@/assets/icon/asset/filter.svg" alt="" />
     </div>
   </div>
   <div class="goods-area">
-    <div class="goods-item" v-for="(item, index) in 2" :key="index">
+    <div class="goods-item" v-for="(item, index) in OTCPendingOrderData" :key="index">
       <div class="item-merchant">
-        <div class="merchant-left">
+        <div class="merchant-left" @click="goMerchantDetails">
           <img src="@/assets/img/index/user/default-head.png" alt="" />
-          <div class="left-name pf500 fs14 fc2C3131">商家昵称</div>
-          <div class="vip-flag pf500 fs10 fcDF384C">V2</div>
+          <div class="left-name pf500 fs14 fc2C3131">{{ item.otc_name }}</div>
+          <div class="vip-flag pf500 fs10 fcDF384C">{{ item.otc_level }}</div>
         </div>
         <div class="merchant-right pf400 fs10 fc999999">
-          入驻时间: 2025-11-07 12:25:10
+          入驻时间: {{ item.otc_create_time }}
         </div>
       </div>
       <div class="item-chengjiao-number pf400 fs10 fc999999">
-        成交量 12550 · 98.95% 成交率
+        成交量 {{ item.order_info.total }} · {{ item.order_info.rate }} 成交率
       </div>
       <div class="item-price">
         <div class="price-area">
           <div class="text pf400 fs10 fc999999">单价</div>
           <div class="price-number pf400 fs10 fc999999">
-            <span class="pf500 fs16 fc333333">6.58</span>
+            <span class="pf500 fs16 fc333333">{{ Number(item.price).toFixed(2) }}</span>
             /USDT
           </div>
           <div class="number pf400 fs10 fc999999">
-            数量 <span class="pf400 fs12 fc666666">1000.05 USDT</span>
+            数量
+            <span class="pf400 fs12 fc666666"
+              >{{ Number(item.left_count).toFixed(2) }} USDT</span
+            >
           </div>
           <div class="number pf400 fs10 fc999999">
-            限额 <span class="pf400 fs12 fc666666">20000 - 1000.05 CNY</span>
+            限额
+            <span class="pf400 fs12 fc666666">
+              {{ Number(item.min_limit).toFixed(2) }} -
+              {{ Number(item.max_limit).toFixed(2) }} CNY</span
+            >
           </div>
         </div>
         <div class="price-func">
           <div class="func-time pf400 fs10 fc999999">
-            <img src="@/assets/icon/asset/clock-gray.svg" alt="" />0m 45s
+            <img src="@/assets/icon/asset/clock-gray.svg" alt="" />
+            {{ item.order_info.avg_time }}
           </div>
           <div class="func-pay-way pf400 fs10 fc999999">
             <div class="color"></div>
-            银行卡
+            <!-- 1.银行卡 2.支付宝 3.微信 -->
+            <div v-if="item.status == 1">银行卡</div>
+            <div v-if="item.status == 2">支付宝</div>
+            <div v-if="item.status == 3">微信</div>
           </div>
           <div class="func-main">
-            <div class="func-chat pf500 fs12 fcDF384C">聊天</div>
-            <div class="func-buy pf500 fs12 fcFFFFFF">验证购买</div>
+            <div class="func-chat pf500 fs12 fcDF384C" @click="getChatIdData(item.otc)">
+              聊天
+            </div>
+            <div
+              class="func-buy pf500 fs12 fcFFFFFF"
+              @click="OTCBuy(item.id, item.otc)"
+              v-if="buySellFlag == 1">
+              购买
+            </div>
+            <div
+              class="func-sell pf500 fs12 fcFFFFFF"
+              @click="OTCSell(item)"
+              v-if="buySellFlag == 2">
+              出售
+            </div>
           </div>
         </div>
       </div>
     </div>
+    <PaymentWay v-show="paymentWayFlag" @paymentWayClose="paymentWayClose"></PaymentWay>
+    <Amount v-show="amountFlag" @amountClose="amountClose"></Amount>
+    <Filter v-show="filterFlag" @filterClose="filterClose"></Filter>
+    <!-- 购买弹窗 -->
+    <C2CBuy
+      v-show="BuyFlag"
+      :otcId="otcId"
+      :chatId="chatId"
+      :orderId="orderId"
+      @BuyClose="BuyClose"></C2CBuy>
+    <!-- 出售弹窗 -->
+    <C2CSell
+      v-show="sellFlag"
+      :otcId="otcId"
+      :orderId="orderId"
+      @sellClose="sellClose"></C2CSell>
+    <!-- 暂无收款方式,还没点击的地方 -->
+    <NotPaymentWay
+      v-show="notPaymnetWayFlag"
+      @notPaymentWayClose="notPaymentWayClose"></NotPaymentWay>
+    <!-- 添加收款方式,还没点击的地方 -->
+    <PaymentAccount
+      v-show="paymentAccountFlag"
+      @paymentAccountClose="paymentAccountClose"></PaymentAccount>
+    <!-- 取消订单,还没点击的地方 -->
+    <CancelOrder
+      v-show="cancelOrderFlag"
+      @cancelOrderClose="cancelOrderClose"></CancelOrder>
+    <!-- 是否完成付款,还没点击的地方 -->
+    <CompletePayment
+      v-show="completePaymentFlag"
+      @completePaymentClose="completePaymentClose"></CompletePayment>
   </div>
 </template>
-<script setup></script>
+<script setup>
+  import { ref, onMounted } from "vue";
+  import { useRoute, useRouter } from "vue-router";
+  import { GetOTCPendingOrder, GetChatId } from "@/api/otc";
+  import PaymentWay from "../../dialog/PaymentWay.vue";
+  import Amount from "../../dialog/Amount.vue";
+  import Filter from "../../dialog/Filter.vue";
+  import C2CSell from "../../dialog/C2CSell.vue";
+  import C2CBuy from "../../dialog/C2CBuy.vue";
+  import NotPaymentWay from "../../dialog/NotPaymentWay.vue";
+  import PaymentAccount from "../../dialog/PaymentAccount.vue";
+  import CancelOrder from "../../dialog/CancelOrder.vue";
+  import CompletePayment from "../../dialog/CompletePayment.vue";
+
+  const router = useRouter();
+
+  const otcId = ref();
+  const chatId = ref();
+  const orderId = ref();
+  const buySellFlag = ref(1);
+  const orderData = ref({
+    // 1购买 2出售
+    order_type: "1",
+  });
+
+  const buySellData = (flag) => {
+    buySellFlag.value = flag;
+    orderData.value.order_type = flag;
+    GetOTCPendingOrderData();
+  };
+
+  // item.id 6, item.otc 1
+  const OTCBuy = async (id, otc) => {
+    otcId.value = otc;
+    orderId.value = id;
+
+    const params = {
+      otc_id: otc,
+    };
+    const data = await GetChatId(params);
+    if (data) {
+      chatId.value = data;
+      BuyFlag.value = true;
+    }
+  };
+
+  const OTCSell = (item) => {
+    otcId.value = item.otc;
+    orderId.value = item.id;
+    console.log(3, orderId.value);
+    sellFlag.value = true;
+    // console.log(1, item);
+  };
+
+  const getChatIdData = async (otc) => {
+    const params = {
+      otc_id: otc,
+    };
+    const data = await GetChatId(params);
+    if (data) {
+      chatId.value = data;
+
+      router.push({
+        name: "OTCCustomService",
+        params: { chatId: chatId.value, otcId: otc },
+      });
+    }
+  };
+
+  const goMerchantDetails = () => {
+    router.push("/OTCMerchantDetails");
+  };
+
+  const OTCPendingOrderData = ref();
+  const GetOTCPendingOrderData = async () => {
+    OTCPendingOrderData.value = [];
+    const params = {
+      // 1购买,2出售
+      order_type: orderData.value.order_type,
+      // 1,普通交易,2快捷交易,3.大宗交易
+      trans_type: "3",
+      coin_type: "",
+      price: "",
+      count: "",
+      min_limit: "",
+      min_amount: "",
+      pay_type: "",
+      left_count: "",
+    };
+    const data = await GetOTCPendingOrder(params);
+    if (data) {
+      OTCPendingOrderData.value = data.list;
+    }
+  };
+
+  onMounted(() => {
+    GetOTCPendingOrderData();
+  });
+
+  const completePaymentFlag = ref(false);
+  const completePaymentClose = () => {
+    completePaymentFlag.value = false;
+  };
+
+  const cancelOrderFlag = ref(false);
+  const cancelOrderClose = () => {
+    cancelOrderFlag.value = false;
+  };
+
+  const paymentAccountFlag = ref(false);
+  const paymentAccountClose = () => {
+    paymentAccountFlag.value = false;
+  };
+
+  const notPaymnetWayFlag = ref(false);
+  const notPaymentWayClose = () => {
+    notPaymnetWayFlag.value = false;
+  };
+
+  const BuyFlag = ref(false);
+  const BuyClose = () => {
+    BuyFlag.value = false;
+  };
+
+  const sellFlag = ref(false);
+  const sellClose = () => {
+    sellFlag.value = false;
+  };
+
+  const filterFlag = ref(false);
+  const filterClose = () => {
+    filterFlag.value = false;
+  };
+
+  const amountFlag = ref(false);
+  const amountClose = () => {
+    amountFlag.value = false;
+  };
+
+  const paymentWayFlag = ref(false);
+  const paymentWayClose = () => {
+    paymentWayFlag.value = false;
+  };
+</script>
 <style lang="less" scoped>
   .c2c {
     margin-top: 13px;
@@ -99,13 +308,25 @@
       justify-content: flex-start;
       height: 100%;
 
+      .buy-green {
+        background: #45b26b !important;
+        color: #ffffff;
+        transition: all ease 0.3s;
+      }
+
+      .buy-red {
+        background: #df384c !important;
+        color: #ffffff;
+        transition: all ease 0.3s;
+      }
+
       .buy-btn {
         width: 85px;
         height: 35px;
         line-height: 35px;
         text-align: center;
         border-radius: 6px;
-        background: #45b26b;
+        background: #f5f5f5;
       }
 
       .sell-btn {
@@ -224,6 +445,8 @@
   }
 
   .goods-area {
+    margin-top: 10px;
+    margin-bottom: 30px;
     width: 345px;
 
     .goods-item {
@@ -360,6 +583,16 @@
               border-radius: 5px;
               background: #45b26b;
             }
+
+            .func-sell {
+              margin-left: 8px;
+              width: 58px;
+              height: 24px;
+              line-height: 24px;
+              text-align: center;
+              border-radius: 5px;
+              background: #df384c;
+            }
           }
         }
       }

+ 86 - 17
src/views/asset/otc/transaction/C2C.vue

@@ -2,8 +2,18 @@
   <!-- <img src="@/assets/icon/asset/c2c.svg" class="c2c" alt="" /> -->
   <div class="buy-sell">
     <div class="buy-left">
-      <div class="buy-btn pf500 fs14 fcFFFFFF">购买</div>
-      <div class="sell-btn pf500 fs14 fc999999">出售</div>
+      <div
+        class="buy-btn pf500 fs14 fc999999"
+        :class="buySellFlag == 1 ? 'buy-green' : ''"
+        @click="buySellData(1)">
+        购买
+      </div>
+      <div
+        class="sell-btn pf500 fs14 fc999999"
+        :class="buySellFlag == 2 ? 'buy-red' : ''"
+        @click="buySellData(2)">
+        出售
+      </div>
     </div>
     <div class="buy-right">
       <div class="text pf400 fs14 fc333333">CNY</div>
@@ -80,14 +90,21 @@
             <div v-if="item.status == 3">微信</div>
           </div>
           <div class="func-main">
-            <div
-              class="func-chat pf500 fs12 fcDF384C"
-              @click="getChatIdData(item.id, item.otc)">
+            <div class="func-chat pf500 fs12 fcDF384C" @click="getChatIdData(item.otc)">
               聊天
             </div>
-            <div class="func-buy pf500 fs12 fcFFFFFF" @click="OTCBuy(item.id, item.otc)">
+            <div
+              class="func-buy pf500 fs12 fcFFFFFF"
+              @click="OTCBuy(item.id, item.otc)"
+              v-if="buySellFlag == 1">
               购买
             </div>
+            <div
+              class="func-sell pf500 fs12 fcFFFFFF"
+              @click="OTCSell(item)"
+              v-if="buySellFlag == 2">
+              出售
+            </div>
           </div>
         </div>
       </div>
@@ -95,12 +112,19 @@
     <PaymentWay v-show="paymentWayFlag" @paymentWayClose="paymentWayClose"></PaymentWay>
     <Amount v-show="amountFlag" @amountClose="amountClose"></Amount>
     <Filter v-show="filterFlag" @filterClose="filterClose"></Filter>
+    <!-- 购买弹窗 -->
     <C2CBuy
-      v-show="sellAndBuyFlag"
+      v-show="BuyFlag"
       :otcId="otcId"
       :chatId="chatId"
       :orderId="orderId"
-      @sellAndBuyClose="sellAndBuyClose"></C2CBuy>
+      @BuyClose="BuyClose"></C2CBuy>
+    <!-- 出售弹窗 -->
+    <C2CSell
+      v-show="sellFlag"
+      :otcId="otcId"
+      :orderId="orderId"
+      @sellClose="sellClose"></C2CSell>
     <!-- 暂无收款方式,还没点击的地方 -->
     <NotPaymentWay
       v-show="notPaymnetWayFlag"
@@ -123,7 +147,7 @@
   import { ref, onMounted } from "vue";
   import { useRoute, useRouter } from "vue-router";
   import { GetOTCPendingOrder, GetChatId } from "@/api/otc";
-  import PaymentWay from "../../dialog/NotPaymentWay.vue";
+  import PaymentWay from "../../dialog/PaymentWay.vue";
   import Amount from "../../dialog/Amount.vue";
   import Filter from "../../dialog/Filter.vue";
   import C2CSell from "../../dialog/C2CSell.vue";
@@ -138,6 +162,17 @@
   const otcId = ref();
   const chatId = ref();
   const orderId = ref();
+  const buySellFlag = ref(1);
+  const orderData = ref({
+    // 1购买 2出售
+    order_type: "1",
+  });
+
+  const buySellData = (flag) => {
+    buySellFlag.value = flag;
+    orderData.value.order_type = flag;
+    GetOTCPendingOrderData();
+  };
 
   // item.id 6, item.otc 1
   const OTCBuy = async (id, otc) => {
@@ -150,13 +185,18 @@
     const data = await GetChatId(params);
     if (data) {
       chatId.value = data;
-      sellAndBuyFlag.value = true;
+      BuyFlag.value = true;
     }
   };
 
-  const getChatIdData = async (id, otc) => {
-    otcId.value = id;
+  const OTCSell = (item) => {
+    otcId.value = item.otc;
+    orderId.value = item.id;
+    sellFlag.value = true;
+    // console.log(1, item);
+  };
 
+  const getChatIdData = async (otc) => {
     const params = {
       otc_id: otc,
     };
@@ -177,8 +217,10 @@
 
   const OTCPendingOrderData = ref();
   const GetOTCPendingOrderData = async () => {
+    OTCPendingOrderData.value = [];
     const params = {
-      order_type: "1",
+      order_type: orderData.value.order_type,
+      // 1,普通交易,2快捷交易,3.大宗交易
       trans_type: "1",
       coin_type: "",
       price: "",
@@ -218,9 +260,14 @@
     notPaymnetWayFlag.value = false;
   };
 
-  const sellAndBuyFlag = ref(false);
-  const sellAndBuyClose = () => {
-    sellAndBuyFlag.value = false;
+  const BuyFlag = ref(false);
+  const BuyClose = () => {
+    BuyFlag.value = false;
+  };
+
+  const sellFlag = ref(false);
+  const sellClose = () => {
+    sellFlag.value = false;
   };
 
   const filterFlag = ref(false);
@@ -259,13 +306,25 @@
       justify-content: flex-start;
       height: 100%;
 
+      .buy-green {
+        background: #45b26b !important;
+        color: #ffffff;
+        transition: all ease 0.3s;
+      }
+
+      .buy-red {
+        background: #df384c !important;
+        color: #ffffff;
+        transition: all ease 0.3s;
+      }
+
       .buy-btn {
         width: 85px;
         height: 35px;
         line-height: 35px;
         text-align: center;
         border-radius: 6px;
-        background: #45b26b;
+        background: #f5f5f5;
       }
 
       .sell-btn {
@@ -522,6 +581,16 @@
               border-radius: 5px;
               background: #45b26b;
             }
+
+            .func-sell {
+              margin-left: 8px;
+              width: 58px;
+              height: 24px;
+              line-height: 24px;
+              text-align: center;
+              border-radius: 5px;
+              background: #df384c;
+            }
           }
         }
       }

+ 30 - 4
src/views/asset/otc/transaction/Fast.vue

@@ -1,7 +1,17 @@
 <template>
   <div class="buy-left">
-    <div class="buy-btn pf500 fs14 fcFFFFFF">购买</div>
-    <div class="sell-btn pf500 fs14 fc999999">出售</div>
+    <div
+      class="buy-btn pf500 fs14 fc999999"
+      :class="buySellFlag == 0 ? 'buy-green' : ''"
+      @click="buySellFlag = 0">
+      购买
+    </div>
+    <div
+      class="sell-btn pf500 fs14 fc999999"
+      :class="buySellFlag == 1 ? 'buy-red' : ''"
+      @click="buySellFlag = 1">
+      出售
+    </div>
   </div>
   <div class="user-staking margin-top43">
     <div class="user-staking-title pf500 fs14 fc2C3131">我要支付</div>
@@ -35,7 +45,11 @@
   </div>
   <div class="buy-sell-btn pf600 fs14 fcFFFFFF">购买</div>
 </template>
-<script setup></script>
+<script setup>
+  import { ref, onMounted } from "vue";
+
+  const buySellFlag = ref(0);
+</script>
 <style lang="less" scoped>
   .buy-left {
     display: flex;
@@ -45,13 +59,25 @@
     width: 345px;
     height: 35px;
 
+    .buy-green {
+      background: #45b26b !important;
+      color: #ffffff;
+      transition: all ease 0.3s;
+    }
+
+    .buy-red {
+      background: #df384c !important;
+      color: #ffffff;
+      transition: all ease 0.3s;
+    }
+
     .buy-btn {
       width: 85px;
       height: 35px;
       line-height: 35px;
       text-align: center;
       border-radius: 6px;
-      background: #45b26b;
+      background: #f5f5f5;
     }
 
     .sell-btn {

+ 8 - 1
src/views/index/user/SafetySet.vue

@@ -62,7 +62,7 @@
         <div class="key-use pf500 fs12 fc999999">36*****90@qq.com</div>
       </div>
     </div>
-    <div class="pay-password">
+    <div class="pay-password" @click="goSetPassword">
       <div class="pf500 fs14 fc333333">支付密码</div>
       <div class="password-right pf500 fs14 fc999999">
         设置
@@ -94,9 +94,16 @@
 <script setup>
   import Switch from "../../../components/ui/Switch.vue";
   import { ref } from "vue";
+  import { useRouter } from "vue-router";
+
+  const router = useRouter();
 
   const hiddenAddress = ref(true);
   const keepLogin = ref(false);
+
+  const goSetPassword = () => {
+    router.push("/set-password");
+  };
 </script>
 <style lang="less" scoped>
   .safety-set {

+ 122 - 0
src/views/user/InputPassword.vue

@@ -0,0 +1,122 @@
+<template>
+  <div class="cancel-order">
+    <div class="apply-mask" @click="emits('inputPasswordClose')"></div>
+    <div class="apply-content">
+      <div class="slide-line"></div>
+      <div class="order-title pf600 fs18 fc333333">支付密码</div>
+      <div class="password-inputs" style="display: flex; gap: 12px; margin: 30px 0 0 0">
+        <input
+          v-for="(digit, idx) in 6"
+          :key="idx"
+          ref="inputs"
+          type="password"
+          maxlength="1"
+          inputmode="numeric"
+          pattern="[0-9]*"
+          class="pw-input"
+          v-model="password[idx]"
+          @input="onInput(idx, $event)"
+          @keydown.backspace="onBackspace(idx, $event)"
+          style="
+            width: 40px;
+            height: 40px;
+            text-align: center;
+            font-size: 24px;
+            border: 1px solid #ccc;
+            border-radius: 8px;
+          " />
+      </div>
+      <div class="sure-btn pf600 fs14 fcFFFFFF" @click="payment">支付</div>
+    </div>
+  </div>
+</template>
+<script setup>
+  const emits = defineEmits(["inputPasswordClose"]);
+
+  import { ref, nextTick } from "vue";
+
+  const password = ref(Array(6).fill(""));
+  const inputs = ref([]);
+
+  function onInput(idx, e) {
+    const val = e.target.value.replace(/\D/g, "").slice(0, 1);
+    password.value[idx] = val;
+    if (val && idx < 5) {
+      nextTick(() => {
+        inputs.value[idx + 1]?.focus();
+      });
+    }
+  }
+
+  function onBackspace(idx, e) {
+    if (!password.value[idx] && idx > 0) {
+      nextTick(() => {
+        inputs.value[idx - 1]?.focus();
+      });
+    }
+  }
+
+  const payment = () => {
+    const passwordStr = password.value.join("");
+    emits("inputPasswordClose", passwordStr);
+  };
+</script>
+<style lang="less" scoped>
+  .cancel-order {
+    position: fixed;
+    left: 0;
+    top: 0;
+    z-index: 1000;
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-end;
+    width: 100%;
+    min-height: 100vh;
+
+    .apply-mask {
+      position: fixed;
+      left: 0;
+      top: 0;
+      z-index: -1;
+      width: 100%;
+      min-height: 100vh;
+      background: rgba(0, 0, 0, 0.5);
+    }
+
+    .apply-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: flex-start;
+      align-items: center;
+      width: 375px;
+      height: 237px;
+      background: #ffffff;
+      border-radius: 24px 24px 0px 0px;
+
+      .slide-line {
+        margin-top: 12px;
+        width: 32px;
+        height: 4px;
+        border-radius: 2px;
+        opacity: 0.4;
+        background: rgba(0, 0, 0, 0.5);
+      }
+
+      .order-title {
+        margin-top: 20px;
+        height: 24px;
+        line-height: 24px;
+      }
+
+      .sure-btn {
+        margin-top: 30px;
+        width: 311px;
+        height: 40px;
+        line-height: 40px;
+        text-align: center;
+        border-radius: 100px;
+        background: #df384c;
+      }
+    }
+  }
+</style>

+ 136 - 112
src/views/user/SetPassword.vue

@@ -3,14 +3,19 @@
     <!-- 导航栏 -->
     <div class="nav-bar">
       <div class="nav-left" @click="$router.back()">
-        <svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M15 18L9 12L15 6" stroke="#333" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
+        <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
+          <path
+            d="M15 18L9 12L15 6"
+            stroke="#333"
+            stroke-width="2"
+            stroke-linecap="round"
+            stroke-linejoin="round" />
+        </svg>
       </div>
-      <div class="nav-title" >设置密码</div>
+      <div class="nav-title">设置密码</div>
       <div class="nav-right"></div>
     </div>
-
     <div class="content">
-
       <!-- 表单区域 -->
       <div class="form-group">
         <label class="form-label">填写支付密码</label>
@@ -20,11 +25,9 @@
             v-model="password"
             placeholder="请输入"
             class="custom-input"
-            maxlength="6"
-          />
+            maxlength="6" />
         </div>
       </div>
-
       <div class="form-group">
         <label class="form-label">请确认支付密码</label>
         <!-- 这里的 class 用于演示截图中的选中状态效果,实际使用中浏览器自带 focus 样式 -->
@@ -34,131 +37,152 @@
             v-model="confirmPassword"
             placeholder="请输入"
             class="custom-input"
-            maxlength="6"
-          />
+            maxlength="6" />
         </div>
       </div>
-
       <!-- 提交按钮 -->
       <div class="footer-action">
         <button class="submit-btn" @click="handleSubmit">提交</button>
       </div>
-
     </div>
   </div>
 </template>
-
 <script setup>
-import { ref } from 'vue';
-import { useRouter } from 'vue-router';
-// 引入 Vant Toast (如果你的项目有安装 Vant,没有则用 alert)
-// import { showToast } from 'vant';
-
-const router = useRouter();
+  import { ref } from "vue";
+  import { useRouter } from "vue-router";
+  import { showToast } from "vant";
+  import { setPassword } from "@/api/user";
+
+  const router = useRouter();
+
+  const password = ref("");
+  const confirmPassword = ref("");
+
+  const handleSubmit = async () => {
+    if (!password.value || !confirmPassword.value) {
+      showToast("请输入密码");
+      return;
+    }
+    if (!/^\d+$/.test(password.value) || !/^\d+$/.test(confirmPassword.value)) {
+      showToast("密码只能为数字");
+      return;
+    }
+    if (password.value !== confirmPassword.value) {
+      showToast("两次输入的密码不一致");
+      return;
+    }
+    if (password.value.length !== 6) {
+      showToast("密码长度必须为6位");
+      return;
+    }
+
+    const params = {
+      password: password.value,
+    };
+    const data = await setPassword(params);
+    if (data.code == "00000") {
+      showToast("密码设置成功");
+      router.back();
+    }
+  };
+</script>
 
-const password = ref('');
-const confirmPassword = ref('');
+<style scoped>
+  .page-container {
+    min-height: 100vh;
+    background-color: #fff;
+    display: flex;
+    flex-direction: column;
+  }
 
-const handleSubmit = () => {
-  if (!password.value || !confirmPassword.value) {
-    alert('请输入密码');
-    return;
+  /* 导航栏 */
+  .nav-bar {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: 44px;
+    padding: 0 16px;
+    background: #fff;
+    position: sticky;
+    top: 0;
+    z-index: 10;
   }
-  if (password.value !== confirmPassword.value) {
-    alert('两次输入的密码不一致');
-    return;
+  .nav-title {
+    font-size: 18px;
+    font-weight: 600;
+    color: #333;
   }
-  if (password.value.length < 6) {
-    alert('密码长度不能少于6位');
-    return;
+  .nav-left,
+  .nav-right {
+    width: 40px;
+    display: flex;
+    align-items: center;
   }
 
-  // 提交逻辑...
-  console.log('提交密码:', password.value);
-  alert('设置成功');
-  router.back();
-};
-</script>
-
-<style scoped>
-.page-container {
-  min-height: 100vh;
-  background-color: #fff;
-  display: flex; flex-direction: column;
-}
-
-/* 导航栏 */
-.nav-bar {
-  display: flex; justify-content: space-between; align-items: center;
-  height: 44px; padding: 0 16px; background: #fff;
-  position: sticky; top: 0; z-index: 10;
-}
-.nav-title { font-size: 18px; font-weight: 600; color: #333; }
-.nav-left, .nav-right { width: 40px; display: flex; align-items: center; }
-
-/* 内容区 */
-.content {
-  padding: 20px;
-  flex: 1;
-  display: flex; flex-direction: column;
-}
+  /* 内容区 */
+  .content {
+    padding: 20px;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+  }
 
-.form-group {
-  margin-bottom: 24px;
-}
+  .form-group {
+    margin-bottom: 24px;
+  }
 
-.form-label {
-  display: block;
-  font-size: 16px;
-  color: #333;
-  font-weight: 500;
-  margin-bottom: 12px;
-}
+  .form-label {
+    display: block;
+    font-size: 16px;
+    color: #333;
+    font-weight: 500;
+    margin-bottom: 12px;
+  }
 
-/* 输入框样式 */
-.custom-input {
-  width: 100%;
-  height: 50px;
-  background: #F7F8FA; /* 截图中的浅灰背景 */
-  border: 1px solid transparent; /* 默认无边框 */
-  border-radius: 8px;
-  padding: 0 16px;
-  font-size: 16px;
-  color: #333;
-  box-sizing: border-box;
-  outline: none; /* 去掉浏览器默认的黑框 */
-  transition: all 0.2s;
-}
+  /* 输入框样式 */
+  .custom-input {
+    width: 100%;
+    height: 50px;
+    background: #f7f8fa; /* 截图中的浅灰背景 */
+    border: 1px solid transparent; /* 默认无边框 */
+    border-radius: 8px;
+    padding: 0 16px;
+    font-size: 16px;
+    color: #333;
+    box-sizing: border-box;
+    outline: none; /* 去掉浏览器默认的黑框 */
+    transition: all 0.2s;
+  }
 
-/* 占位符颜色 */
-.custom-input::placeholder {
-  color: #C2C4CC;
-}
+  /* 占位符颜色 */
+  .custom-input::placeholder {
+    color: #c2c4cc;
+  }
 
-/* 核心细节:输入框聚焦时变蓝 */
-.custom-input:focus {
-  border-color: #2B6BFF; /* 截图中的亮蓝色边框 */
-  background: #fff;      /* 聚焦时背景可能变白,视设计而定,这里保留灰底或变白均可 */
-}
+  /* 核心细节:输入框聚焦时变蓝 */
+  .custom-input:focus {
+    border-color: #2b6bff; /* 截图中的亮蓝色边框 */
+    background: #fff; /* 聚焦时背景可能变白,视设计而定,这里保留灰底或变白均可 */
+  }
 
-/* 底部按钮区域 */
-.footer-action {
-  margin-top: auto; /* 把按钮推到最底部 */
-  padding-bottom: 30px;
-}
+  /* 底部按钮区域 */
+  .footer-action {
+    margin-top: auto; /* 把按钮推到最底部 */
+    padding-bottom: 30px;
+  }
 
-.submit-btn {
-  width: 100%;
-  height: 48px;
-  background: #E02F44; /* 截图中的红色 */
-  color: #fff;
-  border: none;
-  border-radius: 24px;
-  font-size: 16px;
-  font-weight: 600;
-  cursor: pointer;
-}
-.submit-btn:active {
-  opacity: 0.9;
-}
-</style>
+  .submit-btn {
+    width: 100%;
+    height: 48px;
+    background: #e02f44; /* 截图中的红色 */
+    color: #fff;
+    border: none;
+    border-radius: 24px;
+    font-size: 16px;
+    font-weight: 600;
+    cursor: pointer;
+  }
+  .submit-btn:active {
+    opacity: 0.9;
+  }
+</style>