Pārlūkot izejas kodu

:rocket:feat: '持仓历史'

Ritchie 1 gadu atpakaļ
vecāks
revīzija
3e08bf2a55

BIN
src/assets/position/hisBillIcon.png


+ 108 - 111
src/common/style/global.less

@@ -1,277 +1,274 @@
 /*
     margin padding fontSize 通用样式表
-    免去你每次重写样式的烦恼
-    marked by king
 */
 .loop(@counter) when (@counter > 0) {
-    .o-p-@{counter} {
-        padding: (1px * @counter);
-    }
+  .o-p-@{counter} {
+    padding: (1px * @counter);
+  }
 
-    .o-ptb-@{counter} {
-        padding-top: (1px * @counter);
-        padding-bottom: (1px * @counter);
-    }
+  .o-ptb-@{counter} {
+    padding-top: (1px * @counter);
+    padding-bottom: (1px * @counter);
+  }
 
-    .o-plr-@{counter} {
-        padding-right: (1px * @counter);
-        padding-left: (1px * @counter);
-    }
+  .o-plr-@{counter} {
+    padding-right: (1px * @counter);
+    padding-left: (1px * @counter);
+  }
 
-    .o-pt-@{counter} {
-        padding-top: (1px * @counter);
-    }
+  .o-pt-@{counter} {
+    padding-top: (1px * @counter);
+  }
 
-    .o-pr-@{counter} {
-        padding-right: (1px * @counter);
-    }
+  .o-pr-@{counter} {
+    padding-right: (1px * @counter);
+  }
 
-    .o-pb-@{counter} {
-        padding-bottom: (1px * @counter);
-    }
+  .o-pb-@{counter} {
+    padding-bottom: (1px * @counter);
+  }
 
-    .o-pl-@{counter} {
-        padding-left: (1px * @counter);
-    }
+  .o-pl-@{counter} {
+    padding-left: (1px * @counter);
+  }
 
-    .o-m-@{counter} {
-        margin: (1px * @counter);
-    }
+  .o-m-@{counter} {
+    margin: (1px * @counter);
+  }
 
-    .o-mtb-@{counter} {
-        margin-top: (1px * @counter);
-        margin-bottom: (1px * @counter);
-    }
+  .o-mtb-@{counter} {
+    margin-top: (1px * @counter);
+    margin-bottom: (1px * @counter);
+  }
 
-    .o-mlr-@{counter} {
-        margin-right: (1px * @counter);
-        margin-left: (1px * @counter);
-    }
+  .o-mlr-@{counter} {
+    margin-right: (1px * @counter);
+    margin-left: (1px * @counter);
+  }
 
-    .o-mt-@{counter} {
-        margin-top: (1px * @counter);
-    }
+  .o-mt-@{counter} {
+    margin-top: (1px * @counter);
+  }
 
-    .o-mr-@{counter} {
-        margin-right: (1px * @counter);
-    }
+  .o-mr-@{counter} {
+    margin-right: (1px * @counter);
+  }
 
-    .o-mb-@{counter} {
-        margin-bottom: (1px * @counter);
-    }
+  .o-mb-@{counter} {
+    margin-bottom: (1px * @counter);
+  }
 
-    .o-ml-@{counter} {
-        margin-left: (1px * @counter);
-    }
+  .o-ml-@{counter} {
+    margin-left: (1px * @counter);
+  }
 
-    .c-text-@{counter} {
-        font-size: (1px * @counter);
-    }
+  .c-text-@{counter} {
+    font-size: (1px * @counter);
+  }
 
-    .c-radius-@{counter} {
-        border-radius: (1px * @counter);
-    }
+  .c-radius-@{counter} {
+    border-radius: (1px * @counter);
+  }
 
-    .loop((@counter - 1)); // 递归调用自身
+  .loop((@counter - 1)); // 递归调用自身
 }
 
 .loop(200);
 
 /*超过一行显示省略号*/
 .c-text-line1 {
-    overflow: hidden; //超出的文本隐藏
-    text-overflow: ellipsis; //溢出用省略号显示
-    white-space: nowrap; //溢出则不换行
+  overflow: hidden; //超出的文本隐藏
+  text-overflow: ellipsis; //溢出用省略号显示
+  white-space: nowrap; //溢出则不换行
 }
 
 /*全局border*/
 .c-border {
-    border-radius: 2px;
-    border: 1px solid #B9BAD0;
+  border-radius: 2px;
+  border: 1px solid #b9bad0;
 }
 
 /* 隐藏 */
 .hidden {
-    visibility: hidden;
+  visibility: hidden;
 }
 
 .overHid {
-    overflow: hidden;
+  overflow: hidden;
 }
 
 /* 全局宽度 */
 .o-w {
-    width: 100%;
+  width: 100%;
 }
 
 .o-h {
-    height: 100%;
+  height: 100%;
 }
 
 .c-text-c {
-    text-align: center;
+  text-align: center;
 }
 
 .c-text-r {
-    text-align: right;
+  text-align: right;
 }
 
 .c-text-b {
-    font-weight: bold;
+  font-weight: bold;
 }
 
 .c-text-color {
-    color: #404D74;
+  color: #404d74;
 }
 
 .c-color {
-    color: #8787A6;
+  color: #8787a6;
 }
 
 .c-text-w5 {
-    font-weight: 500;
+  font-weight: 500;
 }
 
 .c-text-w6 {
-    font-weight: 600;
+  font-weight: 600;
 }
 
 /* 盒模型转换 */
 .l-bs {
-    box-sizing: border-box;
+  box-sizing: border-box;
 }
 .l-in {
-	display: inline-block;
+  display: inline-block;
 }
 /* 全局阴影 */
 .l-boxShadow {
-    box-shadow: 0px 0px 12rpx rgba(0, 0, 0, 0.16);
+  box-shadow: 0px 0px 12rpx rgba(0, 0, 0, 0.16);
 }
 
 /* 自定义全局flex */
 .l-flex-center {
-    display: flex;
-    justify-content: center;
-    align-items: center;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 }
 
 .l-flex-RC {
-    display: flex;
-    align-items: center;
+  display: flex;
+  align-items: center;
 }
 
 .l-flex-between {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
 }
 
 .l-f {
-    display: flex;
+  display: flex;
 }
 
 .l-flex-d {
-    flex-direction: column;
+  flex-direction: column;
 }
 
 .l-flex-w {
-    flex-wrap: wrap;
+  flex-wrap: wrap;
 }
 
 .l-flex-j-c {
-    justify-content: center;
+  justify-content: center;
 }
 
 .l-flex-j-b {
-    justify-content: space-between;
+  justify-content: space-between;
 }
 
 .l-flex-j-a {
-    justify-content: space-around;
+  justify-content: space-around;
 }
 
 .l-flex-j-e {
-    justify-content: flex-end;
+  justify-content: flex-end;
 }
 
 .l-flex-j-s {
-    justify-content: flex-start;
+  justify-content: flex-start;
 }
 
 .l-flex-c {
-    align-items: center;
+  align-items: center;
 }
 
 .l-flex-e {
-    align-items: flex-end;
+  align-items: flex-end;
 }
 
 /* 定位相关 */
 .l-re {
-    position: relative;
+  position: relative;
 }
 
 .l-ab {
-    position: absolute;
+  position: absolute;
 }
 
 .l-fixed {
-    position: fixed;
+  position: fixed;
 }
 
 .c-color-c {
-    color: #CCCCCC;
+  color: #cccccc;
 }
 
 .c-color-0 {
-    color: #000000;
+  color: #000000;
 }
 
 .c-color-1 {
-    color: #111111;
+  color: #111111;
 }
 
 .c-color-3 {
-    color: #333333;
+  color: #333333;
 }
 
 .c-color-6 {
-    color: #666666;
+  color: #666666;
 }
 
 .c-color-9 {
-    color: #999999;
+  color: #999999;
 }
 
 .c-color-f {
-    color: #FFFFFF;
+  color: #ffffff;
 }
 
 .c-color-n {
-    color: transparent;
+  color: transparent;
 }
 
 .c-color-theme {
-    color: #FF3456;
+  color: #ff3456;
 }
 
-
 .c-bg-c {
-    background-color: #CCCCCC;
+  background-color: #cccccc;
 }
 
 .c-bg-0 {
-    background-color: #000000;
+  background-color: #000000;
 }
 
 .c-bg-9 {
-    background-color: #999999;
+  background-color: #999999;
 }
 
 .c-bg-f {
-    background-color: #FFFFFF;
+  background-color: #ffffff;
 }
 
 .c-bg-n {
-    background-color: transparent;
-}
+  background-color: transparent;
+}

+ 7 - 2
src/service/merchantManage/index.js

@@ -15,9 +15,14 @@ export function getAdminList(params) {
   return axios.get(`/SZWL-SERVER/tAdmin/pageAdmin?${stringToUrl(params)}`);
 }
 // 获取账户基本详情
-export function getAdmin(params) {
-  return axios.get(`/SZWL-SERVER/tAdmin/getAdmin?${stringToUrl(params)}`);
+// export function getAdmin(params) {
+//   return axios.get(`/SZWL-SERVER/tAdmin/getAdmin?${stringToUrl(params)}`);
+// }
+// 获取账户个人信息详情 getLoginInfo
+export function getLoginInfo() {
+  return axios.get(`/myCenter/getLoginInfo`);
 }
+
 // 通过 adminId 获取上级账号信息
 export function getRelation(params) {
   return axios.get(`/SZWL-SERVER/tAdmin/getRelation?${stringToUrl(params)}`);

+ 6 - 0
src/service/position/index.js

@@ -0,0 +1,6 @@
+import axios from '../../utils/axios';
+
+// 个人挂单历史记录
+export function listMyOrderHis(params) {
+    return axios.get(`/myStock/listMyOrderHis`, params);
+}

+ 9 - 0
src/service/trading/index.js

@@ -1,6 +1,15 @@
 import axios from '../../utils/axios';
 import { stringToUrl } from '@/common/js/utils';
 
+// 股票买卖挂单
+export function addPendOrder(params) {
+    return axios.post(`/tradeOrder/addPendOrder`, params);
+}
+
+// 查询用户可挂单数量(买/卖)
+export function queryAllowPendNum() {
+    return axios.get(`/tradeOrder/queryAllowPendNum`);
+}
 
 // 获取设备列表
 export function getDeviceList(params) {

+ 2 - 2
src/styles/home/homeRank5.less

@@ -87,7 +87,7 @@
     .buy-box {
       margin: auto;
       border-radius: 10px;
-      background-color:	#eaf5ff;
+      background-color:	#fff6ee;
       padding: 15px;
       width: 95%;
       max-width: 600px;
@@ -110,7 +110,7 @@
       margin: auto;
       margin-top: 1px;
       border-radius: 10px;
-      background-color: #eaf5ff;
+      background-color: #fff6ee;
       padding: 15px;
       width: 95%;
       max-width: 600px;

+ 2 - 2
src/styles/position/index.less

@@ -335,7 +335,7 @@ button:active {
       }
     }
 
-    .tradingBox1 {
+    .positionBox1 {
       .searchRow {
         margin: 18px 15px;
 
@@ -467,7 +467,7 @@ button:active {
       .outer4 {
         width: 16px;
         height: 16px;
-        background: url("../../assets/home/titleIcon.png") top center no-repeat;
+        background: url("../../assets/position/hisBillIcon.png") top center no-repeat;
         background-size: 100%;
       }
 

+ 7 - 0
src/styles/user/index.less

@@ -86,6 +86,13 @@
             margin-top: 20px;
             position: relative;
 
+            .l-eye {
+                position: absolute;
+                right: 0;
+                font-size: 18px;
+                color: #FF3456;
+            }   
+
             .filedInpPad {
                 .van-cell {
                     padding: 0 !important;

+ 1 - 1
src/utils/axios.js

@@ -22,7 +22,7 @@ service.interceptors.request.use(config => {
   showLoadingToast({
     message: curLang === 'zh' ? '加载中...' : '加载中...',
     forbidClick: true,
-    duration: 5000,
+    duration: 3000,
   });
   // 把localStorage的token放在Authorization里
   let loginUser = localStorage.getItem('loginUser');

+ 2 - 0
src/views/home/HomeIndex.vue

@@ -95,6 +95,8 @@
 
 
     <div>
+      <!-- 分割线 -->
+      <img class="pic1" src="../../assets/trading/line.png" />
       <br />
     </div>
     <!-- 新闻通知弹窗 -->

+ 103 - 18
src/views/position/PositionIndex.vue

@@ -3,8 +3,7 @@
   <div class="position flex-col">
     <div class="box1 flex-col">
       <s-header :name="$t('position.machineSalesRanking')" :noback="true" :isFixed="false"></s-header>
-
-      <div class="tradingBox1 flex-col">
+      <div class="positionBox1 flex-col">
         <div class="searchRow flex-row justify-between">
           <div class="flex-col">
             <div class="flex-row justify-between bd3">
@@ -16,8 +15,8 @@
       </div>
 
       <img class="pic1" src="../../assets/device/line.png" />
-
     </div>
+
     <div>
       <div class="o-plr-15 o-ptb-20">
         <div class="bd1 flex-col">
@@ -56,11 +55,6 @@
 
     <div class="tradingHistory">
       <!-- 交易历史 -->
-      <!-- <div class="baseRow flex-row justify-between">
-        <div class="group2 flex-col"></div>
-        <span class="baseText">交易历史</span>
-      </div> -->
-      <!-- 交易历史2 -->
       <div class="searchRow flex-row justify-between">
         <div class="flex-col">
           <div class="flex-row justify-between bd3">
@@ -69,32 +63,123 @@
               交易历史</span>
           </div>
         </div>
+        <!-- 搜索 -->
         <div class="flex-col">
-          <div class="main5 flex-row justify-between">
-            <van-popover v-model:show="showPopover" placement="left-start" theme="dark" :actions="actions"
-              @select="selectLabel">
-              <template #reference>
-                <van-icon name="bars" class="fixed-icon o-pr-15" size="23" color="#ff0077" />
-              </template>
-            </van-popover>
-            <img class="label2" src="../../assets/position/searchIcon.png" @click="searchClick" />
+          <div class="main5 flex-row justify-between" @click="searchClick">
+            <img class="label2" src="../../assets/position/searchIcon.png" />
           </div>
-        </div>        
+        </div>
       </div>
     </div>
+
+    <!-- 历史记录明细 -->
+    <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
+      <van-cell v-for="item in orderHisList" :key="item" :title="item" />
+    </van-list>
+
+
     <van-empty image="search" description="暂无交易历史" />
 
 
     <div class="historyList">
-      
+
     </div>
 
+
+    <!-- 使用搜索弹窗组件 -->
+    <SearchPop :showSearchPop="showSearchPop" @update:showSearchPop="handleUpdateShowSearchPop" />
+    <div style="height: 50px;"></div>
+    <TestComp param="哈哈哈" />
   </div>
+
 </template>
 
 <script setup>
 // 导入无数据组件
 import sHeader from "@/components/SimpleHeader"
+import { onMounted, ref } from "vue"
+import SearchPop from './SearchPop.vue';
+import TestComp from './TestComp.vue'
+import { listMyOrderHis } from "@/service/position";
+
+const showSearchPop = ref(false);
+
+const orderHisList = ref([]);
+const loading = ref(false)
+const finished = ref(false)
+
+// const getOrderHisListFunc = async () => {
+//   const params = {
+//     current: 1,
+//     size: 10
+//   }
+//   setTimeout(() => {
+//     const { data } = listMyOrderHis(params).then((res) => {
+//       orderHisList.value = res.data.data;
+//     })
+//     if (data.code === '00000') {
+//       console.log("获取交易历史成功!");
+//       console.log(data.data);
+//       // 加载状态结束
+//       loading.value = false;
+//       // 数据全部加载完成
+//       if (orderHisList.value.length >= 40) {
+//         finished.value = true;
+//       }
+
+//     }
+//   }, 1000);
+// }
+
+// TODO: 2024-04-12
+const onLoad = () => {
+  // 异步更新数据
+  setTimeout(() => {
+
+    const params = {
+      current: 1,
+      size: 10
+    }
+    const { data } = listMyOrderHis(params).then((res) => {
+      orderHisList.value = res.data.data;
+    })
+    if (data.code === '00000') {
+      console.log("获取交易历史成功!");
+      console.log(data.data);
+      // 加载状态结束
+      loading.value = false;
+      // 数据全部加载完成
+      if (orderHisList.value.length >= 40) {
+        finished.value = true;
+      }
+
+    }
+
+    // 加载状态结束
+    loading.value = false;
+
+    // 数据全部加载完成
+    if (orderHisList.value.length >= 4) {
+      finished.value = true;
+    }
+  }, 1000);
+};
+
+
+onMounted(async () => {
+  // getOrderHisListFunc()
+  onLoad
+});
+
+const searchClick = () => {
+  console.log("点击搜索");
+  showSearchPop.value = true;
+}
+
+// 处理子组件传递回来的更新事件
+const handleUpdateShowSearchPop = (val) => {
+  showSearchPop.value = val;
+}
 
 </script>
 

+ 25 - 0
src/views/position/PositionSearch.vue

@@ -0,0 +1,25 @@
+<script setup>
+import { ref } from 'vue'
+const sheetShow = ref(false);
+
+// 定义一个方法来显示搜索弹出框
+const showSearch = () => {
+  sheetShow.value = true;
+};
+showSearch
+</script>
+
+<template>
+  <div class="positionSearch flex-col">
+    <van-popup v-model:show="sheetShow" round class="positionSearchPopup">
+      <div class="content">
+        <van-form @submit="onSubmit">
+          <van-field v-model="userName" name="userName" label="用户名"
+            placeholder="请输入用户姓名" />
+        </van-form>
+      </div>
+    </van-popup>
+  </div>
+</template>
+
+<style scoped></style>

+ 37 - 0
src/views/position/SearchPop.vue

@@ -0,0 +1,37 @@
+<template>
+    <van-popup v-model:show="showPop" round :style="{ padding: '64px' }" @close="handlePopupClose">
+        <div>
+            <p>搜索弹窗的内容</p>
+        </div>
+    </van-popup>
+</template>
+
+<script setup>
+import { ref, watch, defineProps, defineEmits } from 'vue';
+
+const props = defineProps({
+    showSearchPop: Boolean
+});
+
+// const props = defineProps(['showSearchPop']);
+
+const emit = defineEmits(['update:showSearchPop']);
+
+
+const showPop = ref(props.showSearchPop);
+
+// 监听 props 的变化,更新 showPop 的值
+watch(() => props.showSearchPop, (newValue) => {
+  showPop.value = newValue;
+});
+
+// 处理弹窗关闭事件,更新 showSearchPop 的值
+const handlePopupClose = () => {
+  emit('update:showSearchPop', false);
+};
+
+</script>
+
+<style scoped>
+/* 这里可以添加样式 */
+</style>

+ 13 - 0
src/views/position/TestComp.vue

@@ -0,0 +1,13 @@
+<script setup>
+import { defineProps } from "vue"
+
+defineProps(['param'])
+</script>
+
+<template>
+    <div style="background-color: plum; display: flex; justify-content: center;" >
+        <h2>{{ param }}</h2>
+    </div>
+</template>
+
+<style scoped></style>

+ 78 - 24
src/views/trading/TradingBuy.vue

@@ -1,21 +1,65 @@
 <script setup>
-import { ref } from 'vue';
+import { onMounted, ref } from 'vue';
 import sHeader from "@/components/SimpleHeader";
-const buyNum = ref('');
-const unitPrice = ref('');
-const onSubmitBuy = (values) => {
-    console.log('submitBuy', values);
-};
-const handleInput = () => {
-    unitPrice.value = unitPrice.value.replace(/[^\d.]/g, '')
-    const parts = unitPrice.value.split('.');
-    if (parts.length > 2) {
-        unitPrice.value = parts[0] + '.' + parts[1];
+import { showConfirmDialog, showFailToast, showSuccessToast } from 'vant';
+import { addPendOrder, queryAllowPendNum } from "@/service/trading";
+
+const buyNum = ref('100');
+const unitPrice = ref('10');
+const allowMaximum = ref(0);
+const active = ref(0);
+
+
+onMounted(async () => {
+    try {
+        const { data } = await queryAllowPendNum();
+        if (data.code === "00000") {
+            allowMaximum.value = data.data.allowBuyNum
+            // console.log("允许挂单份额 >>>", allowMaximum.value);
+        }
+    } catch (error) {
+        console.error("请求出错", error);
     }
-    if (parts.length === 2) {
-        unitPrice.value = parts[0] + '.' + parts[1].slice(0, 2);
+})
+
+
+const onSubmitBuy = async (values) => {
+  try {
+    const result = await queryAllowPendNum();
+    if (result.data.code === "00000") {
+      allowMaximum.value = result.data.data.allowBuyNum;
+      console.log("允许挂单份额 >>>", allowMaximum.value);
     }
-}
+
+    // 等待用户确认对话框
+    const confirmation = await showConfirmDialog({
+      title: '提醒',
+      message: '挂单后不可撤回',
+    });
+
+    if (confirmation) {
+      console.log('submitBuy', values);
+      const entrustNumber = parseInt(buyNum.value, 10);
+      const price = parseFloat(unitPrice.value);
+      const params = {
+        entrustNumber: entrustNumber,
+        price: price,
+        type: '1', // 1 代表买,2 代表卖
+      };
+      const { data } = await addPendOrder(params);
+      if (data.code === '00000') {
+        showSuccessToast("买入挂单成功");
+      } else {
+        showFailToast(data.message);
+      }
+    } else {
+      // 用户取消了对话框
+      console.log('用户取消了挂单操作');
+    }
+  } catch (error) {
+    console.error('处理买入挂单时发生错误:', error);
+  }
+};
 
 
 </script>
@@ -28,21 +72,31 @@ const handleInput = () => {
             <div style="height: 200px;">
                 <van-tabs v-model:active="active" animated>
                     <van-tab><template #title> <van-icon name="points" />买入股票 </template>
-                        <van-form @submit="onSubmitBuy">
+                        <van-form @submit="onSubmitBuy" style="margin: 10px;">
                             <van-cell-group inset>
-                                <van-field v-model="buyNum" type="digit" name="买入量" label="买入量" placeholder="买入量"
-                                    :rules="[{ required: true, message: '请填写买入量' }]" />
+                                <van-field name="买入量" label="买入量" placeholder="买入量"
+                                    :rules="[{ required: true, message: '请填写买入量' }]">
+                                    <template #input>
+                                        <van-stepper v-model="buyNum" step="100" input-width="70px" integer min='0'
+                                            :max="allowMaximum" />
+                                    </template>
+                                </van-field>
 
-                                <van-field v-model="unitPrice" type="number" name="单价" label="单价"
-                                    placeholder="每股单价,小数点后两位有效" :rules="[{ required: true, message: '请填写单价' }]"
-                                    @input="handleInput" />
+                                <van-field name="单价¥" label="单价¥" placeholder="每股单价,小数点后两位有效"
+                                    :rules="[{ required: true, message: '请填写单价' }]">
+                                    <template #input>
+                                        <van-stepper v-model="unitPrice" step="0.01" input-width="70px"
+                                            :decimal-length="2" />
+                                    </template>
+                                </van-field>
                             </van-cell-group>
-                            <div style="margin: 16px;">
-                                <van-button round block type="warning" native-type="submit" @click="showConfirmPopup">
+
+                            <div style="margin: 20px;">
+                                <van-button round block type="warning" native-type="submit">
                                     提交
                                 </van-button>
-                                
-                                <van-popup v-model:show="showCenter" round :style="{ padding: '64px' }" >挂单后不可撤回</van-popup>
+
+
                             </div>
                         </van-form>
 

+ 25 - 249
src/views/trading/TradingIndex.vue

@@ -56,17 +56,11 @@
           <van-col span="8">交易数量</van-col>
           <van-col span="8">单价¥</van-col>
         </van-row>
-        <van-row justify="center">
-          <van-col span="8">张三</van-col>
-          <van-col span="8">1000</van-col>
-          <van-col span="8">11.01</van-col>
-        </van-row>
-        <van-row justify="center">
-          <van-col span="8">李四</van-col>
-          <van-col span="8">1500</van-col>
-          <van-col span="8">11.21</van-col>
+        <van-row v-for="(item, index) in sellerList" :key="index" justify="center">
+          <van-col span="8">卖家{{ index + 1 }}</van-col>
+          <van-col span="8">{{ item.amount }}</van-col>
+          <van-col span="8">{{ item.price }}</van-col>
         </van-row>
-
       </div>
 
       <!-- 分割线 -->
@@ -139,36 +133,28 @@
 
 <script>
 
-import { onMounted, reactive, toRefs, ref, onActivated } from "vue";
-import { showFailToast, showSuccessToast, showToast, showDialog } from "vant";
+import { onMounted, reactive, toRefs, ref } from "vue";
 import sHeader from "@/components/SimpleHeader";
 import { getLoginUser, Format_calcuDecial, styleUrl } from "@/common/js/utils";
 import {
-  eliminate,
-  Api_getReplenishment,
-  changeSleepDesc,
+ 
 } from "../../service/trading/index";
-import { onBeforeRouteLeave, useRouter } from "vue-router";
-import dateUtil from "../../utils/dateUtil";
-import { useI18n } from "vue-i18n";
-import { onBeforeUnmount } from "vue";
+import { useRouter } from "vue-router";
 
 
 export default {
   name: "trading",
   components: { sHeader },
   setup() {
-    const { t } = useI18n();
+    const router = useRouter();
     const searchRef = ref(null);
     const oprRef = ref(null);
     const list = ref([]);
     const loading = ref(true);
     const error = ref(false);
     const finished = ref(false);
-    const router = useRouter();
     const sys = ref(null);
     const user = getLoginUser();
-    const verticalScrollPosition = ref(0);
     const labelList = ref([]);
 
     const countDownTime = ref(0);
@@ -182,84 +168,30 @@ export default {
       { name: '钱七', amount: 60, price: 70 }
     ];
 
-    const calculateCountDownTime = () => {
-      const nowTime = new Date();
-      const endTime = new Date();
-      endTime.setHours(17, 0, 0, 0);
-
-      let timeDiff = endTime.getTime() - nowTime.getTime();
-      if (timeDiff <= 0) {
-        // 如果目标时间已经过了或者就是现在,则将倒计时时间设置为 0
-        countDownTime.value = 0;
-      } else {
-        countDownTime.value = timeDiff;
-      }
-    };
+    const sellerList = ref([]);
+    sellerList.value = [
+      { name: '张xx', amount: 10000, price: 50 },
+      { name: '李xx', amount: 9000, price: 51 },
+    ];
+
 
     const pushPageList = (url) => {
       router.push(url);
-    };
-
-    // 返回顶部
-    const backTop = () => {
-      window.scrollY = 0;
     }
-
-    onActivated(() => {
-      // 当组件被激活时,可能是从 keep-alive 缓存中激活的
-      // 这时重新添加滚动事件监听器
-      console.log("进入时的位置", verticalScrollPosition.value);
-      document.documentElement.scrollTop = verticalScrollPosition.value;
-      document.body.scrollTop = verticalScrollPosition.value;
-      window.scrollY = verticalScrollPosition.value;
-      // window.addEventListener('scroll', handleScroll);
-    });
-
-
-    onBeforeRouteLeave(() => {
-      verticalScrollPosition.value = document.documentElement.scrollTop || document.body.scrollTop || window.scrollY;
-      console.log("离开时的位置", verticalScrollPosition.value);
-    })
-
-    // 在组件卸载前清除定时器
-    onBeforeUnmount(() => {
-      clearInterval(updateDataInterval);
-    });
-
-
-    const updateDataInterval = () => {
-      // 每隔5分钟更新数据
-      setInterval(() => {
-        init();
-        if (oprRef.value) {
-          oprRef.value.closeOper();
-        }
-        // verticalScrollPosition.value = 0;
-      }, 5 * 60 * 1000); // 5分钟的毫秒数
-    };
-    //控制睡眠描述的显示隐藏
-    const sleepDescBoxShow = ref(true);
+    
+    
     // 页面列表查询参数
     let searchParams = reactive({
-      id: "", // 用户账户id
-      // adminName: '', // 用户登录名
-      current: 1, // 页数
-      size: 10, // 页大小
-      todayDate: dateUtil.formateDate(new Date(), "yyyy-MM-dd"), // 当天时间
-      labelId: "", // 分组标签
+      current: 1, // 当前页,默认第一页,1
+      size: 10, // 每页多少条数据,默认10条
     });
+
     // 初始化页面获取列表
     onMounted(() => {
-      sleepDescBoxShow.value = true;
       init();
-      updateDataInterval();
-      // window.addEventListener('scroll', handleScroll);
       // 加载样式
       styleUrl('trading');
-      calculateCountDownTime();
-      setInterval(() => {
-        calculateCountDownTime();
-      }, 1000);
+     
     });
     // 初始化
     const init = () => {
@@ -270,9 +202,6 @@ export default {
       // }
       list.value = [];
       searchParams.current = 1;
-      if (user) {
-        searchParams.id = user.id;
-      }
     };
 
 
@@ -283,144 +212,8 @@ export default {
         searchParams.current = searchParams.current + 1;
       }
     };
-    // 搜索点击
-    const searchClick = () => {
-      searchRef.value.showSearch();
-    };
-    // 搜索条件触发查询
-    const search = (e) => {
-      list.value = [];
-      loading.value = true;
-      searchParams.current = 1;
-      searchParams = Object.assign(searchParams, e);
-    };
-    // 跳转设备编辑
-    const tradingSet = (e) => {
-      router.push({ path: "tradingSet", query: { tradingId: e.id } });
-    };
-    // 常用操作弹窗展示触发
-    const tradingOprShow = (e) => {
-      oprRef.value.showOper(e);
-    };
-    // 消除报警
-    const clearAlarm = async (e) => {
-      const params = {
-        id: e.id,
-        name: e.name,
-        selfName: e.selfName,
-        areaId: e.areaId,
-        channel: e.channel,
-        contactName: e.contactName,
-        contactPhone: e.contactPhone,
-        flowers: e.flowers,
-        operationalName: e.operationalName,
-        operationalPhone: e.operationalPhone,
-        timeRuleId: e.timeRuleId,
-      };
-      const { data } = await eliminate(Object.assign({}, params));
-      if (data.code) {
-        showSuccessToast(t("trading.successfullyEliminatedTheAlarm"));
-        e.alarmList = [];
-      } else {
-        showFailToast(data.message);
-      }
-      console.log("/tEquipment/eliminate", e);
-    };
-    const showDateTime = (date) => {
-      if (!date) {
-        return "";
-      }
-      const currentDate = new Date(dateUtil.formateDate(new Date(date), "yyyy/MM/dd hh:mm:ss"));
-      return dateUtil.timeZoneDate(currentDate);
-    };
-
-    // 点击查看定位
-    const viewPosiClk = (row) => {
-      console.log("row 是 >>>", row);
-      if (row.latitude) {
-        router.push({
-          path: "viewPosition",
-          query: {
-            latitude: row.latitude,
-            longitude: row.longitude,
-            fullName: row.fullName,
-          },
-        });
-      } else {
-        showToast(`${t("trading.noPosition")}!!!`);
-      }
-    };
-
-    // 点击补料
-    const replenishmentClk = (row) => {
-      console.log("row >>>", row);
-      Api_getReplenishment({ equipmentId: row.id }).then((res) => {
-        console.log("res >>>", res);
-        // Toast(res.data.message);
-        showDialog({
-          message: t('trading.sentSuccessfully'),
-        }).then(() => {
-          //返回上一页
-          router.go(0);
-        });
-        setTimeout(() => {
-        }, 500);
-      });
-    };
-    // 操作弹窗完成的回调
-    const operFinish = () => {
-      init();
-    };
-    // 设备状况
-    const equipStatus = ref({});
-
-    // 点击运行总数和总设备数
-    const eqeStatusClk = (val) => {
-      searchParams.eqeStatus = val;
-      // 初始化
-      searchParams.current = 1;
-      list.value = [];
-    };
-    // 点击修改图标
-    const editSleepDesc = () => {
-      sleepDescBoxShow.value = !sleepDescBoxShow.value;
-    }
-    // 点击睡眠描述的确定按钮
-    const sleepDescChg = async (sleepDesc, id) => {
-      console.log(sleepDesc);
-      if (!sleepDesc) {
-        showToast(t("trading.sleepDescPlace"));
-      } else {
-        const { data } = await changeSleepDesc({
-          equipmentId: id,
-          sleepDesc,
-        });
-        if (data.code === "00000") {
-          sleepDescBoxShow.value = true;
-          showToast(data.message);
-        }
-      }
-    }
-
-    // 点击标签
-    const active = ref("");
-    const clickLabel = (item) => {
-      console.log(item);
-      list.value = [];
-      searchParams.current = 1;
-      searchParams.labelId = item.name;
-    }
-
-
-    const selectLabel = (action) => {
-      // showToast(action.value);
-      if (action.value == '0') {
-        router.push('/labelMan');
-      }
-      if (action.value == '1') {
-        router.push("/labelManAdd");
-      }
-    }
+    
+   
     return {
       ...toRefs(searchParams),
       list,
@@ -429,32 +222,15 @@ export default {
       finished,
       onLoad,
       searchRef,
-      searchClick,
-      search,
-      tradingSet,
-      clearAlarm,
       oprRef,
-      tradingOprShow,
-      showDateTime,
       sys,
-      viewPosiClk,
-      replenishmentClk,
       Format_calcuDecial,
-      operFinish,
-      equipStatus,
-      eqeStatusClk,
-      editSleepDesc,
-      sleepDescBoxShow,
-      sleepDescChg,
-      backTop,
       user,
       labelList,
-      clickLabel,
-      active,
-      selectLabel,
       countDownTime,
-      pushPageList,
-      buyerList
+      buyerList,
+      sellerList,
+      pushPageList
     };
   },
 };

+ 107 - 34
src/views/trading/TradingSell.vue

@@ -1,44 +1,117 @@
 <script setup>
-import { ref } from 'vue';
+import { ref, onMounted } from 'vue';
 import sHeader from "@/components/SimpleHeader";
-const buyNum = ref('');
-const unitPrice = ref('');
-const onSubmitSell = (values) => {
-    console.log('submitSell', values);
+import { showConfirmDialog, showFailToast, showSuccessToast } from 'vant';
+import { addPendOrder, queryAllowPendNum } from "@/service/trading";
+
+const sellNum = ref('100');
+const unitPrice = ref('10');
+const allowMaximum = ref(0);
+const active = ref(0);
+
+// watch(() => user.allowMaximum, (newMax) => {
+//     if (newMax) {
+//         allowMaximum.value = user.allowMaximum;
+//     }
+// }, { immediate: true })// 立即执行一次watch函数,以便在组件创建时设置
+
+onMounted(async () => {
+    try {
+        const { data } = await queryAllowPendNum();
+        if (data.code === "00000") {
+            allowMaximum.value = data.data.allowSellNum
+            // console.log("允许出售的份额 >>>", allowMaximum.value);
+        }
+    } catch (error) {
+        console.error("请求出错", error);
+    }
+})
+
+const onSubmitSell = async (values) => {
+    try {
+        const result = await queryAllowPendNum();
+        if (result.data.code === "00000") {
+            allowMaximum.value = result.data.data.allowSellNum;
+            console.log("允许挂单份额 >>>", allowMaximum.value);
+        }
+
+        // 等待用户确认对话框
+        const confirmation = await showConfirmDialog({
+            title: '提醒',
+            message: '挂单后不可撤回',
+        });
+        // 这里的代码将在确认对话框确定后执行
+        if (confirmation) {
+            console.log('submitSell', values);
+            const entrustNumber = parseInt(sellNum.value, 10);
+            const price = parseFloat(unitPrice.value);
+            console.log("数量+价格", entrustNumber, price);
+            const params = {
+                entrustNumber: entrustNumber,
+                price: price,
+                type: '2' // 1, 买; 2, 卖.
+            }
+            const { data } = await addPendOrder(params);
+            if (data.code === '00000') {
+                console.log("data.data >>>", data.data);
+                showSuccessToast("卖出挂单成功")
+            } else {
+                showFailToast(data.message);
+            }
+        } else {
+            // 用户取消了对话框
+            console.log('用户取消了挂单操作');
+        }
+
+    } catch (error) {
+        // 如果用户取消了对话框,则在这里处理
+        console.log('Confirm dialog cancelled');
+    }
 };
+
+
 </script>
 
 <template>
-  <div class="tradingSell flex-col">
-    <div class="tradingSellBox">
-      <s-header :name="'股票交易'" :noback="false" :isFixed="false"></s-header>
-
-      <div style="height: 200px;">
-            <van-tabs v-model:active="active" animated>
-                <van-tab><template #title> <van-icon name="after-sale" />卖出股票 </template>
-
-                    <van-form @submit="onSubmitSell">
-                        <van-cell-group inset>
-                            <van-field v-model="buyNum" type="digit" name="卖出量" label="卖出量" placeholder="卖出量"
-                                :rules="[{ required: true, message: '请填写卖出量' }]" />
-
-                            <van-field v-model="unitPrice" type="number" name="单价" label="单价" placeholder="每股单价"
-                                :rules="[{ required: true, message: '请填写单价' }]" />
-                        </van-cell-group>
-                        <div style="margin: 16px;">
-                            <van-button round block type="success" native-type="submit">
-                                提交
-                            </van-button>
-                        </div>
-                    </van-form>
-
-                </van-tab>
-            </van-tabs>
-        </div>
+    <div class="tradingSell flex-col">
+        <div class="tradingSellBox">
+            <s-header :name="'股票交易'" :noback="false" :isFixed="false"></s-header>
+
+            <div style="height: 200px;">
+                <van-tabs v-model:active="active" animated>
+                    <van-tab><template #title> <van-icon name="points" />卖出股票 </template>
+                        <van-form @submit="onSubmitSell" style="margin: 10px;">
+                            <van-cell-group inset>
+                                <van-field name="卖出量" label="卖出量" placeholder="卖出量"
+                                    :rules="[{ required: true, message: '请填写卖出量' }]">
+                                    <template #input>
+                                        <van-stepper v-model="sellNum" step="100" input-width="70px" integer min='0'
+                                            :max="allowMaximum" />
+                                    </template>
+                                </van-field>
+
+                                <van-field name="单价¥" label="单价¥" placeholder="每股单价,小数点后两位有效"
+                                    :rules="[{ required: true, message: '请填写单价' }]">
+                                    <template #input>
+                                        <van-stepper v-model="unitPrice" step="0.01" input-width="70px"
+                                            :decimal-length="2" />
+                                    </template>
+                                </van-field>
+                            </van-cell-group>
 
+                            <div style="margin: 20px;">
+                                <van-button round block type="success" native-type="submit">
+                                    提交
+                                </van-button>
+                            </div>
+                        </van-form>
+
+                    </van-tab>
+                </van-tabs>
+            </div>
+
+        </div>
     </div>
-  </div>
 </template>
 
-<style scoped>
-</style>
+<style scoped></style>

+ 20 - 66
src/views/user/UserIndex.vue

@@ -83,7 +83,8 @@
           <!-- 银行卡号 cardNo -->
           <div class="userInfo l-flex-between">
             <span class="userInfoLeft">银行卡号: </span>
-            <span>{{ hiddenCardNo }}</span>
+            <span>{{ eyeOpen ? cardNo : hiddenCardNo }}</span>
+            <van-icon class="l-eye" :name="eyeOpen ? 'eye-o' : 'closed-eye'" size="20" @click="clickEye" />
           </div>
 
         </div>
@@ -97,6 +98,7 @@
           <div class="group2 flex-col"></div>
           <span class="baseText">{{ $t("user.commonOperations") }}</span>
         </div>
+        <!-- TODO: 后面这里改成 Grid 宫格 -->
         <div class="operListBox">
           <!-- 系统消息 -->
           <div class="taskListRow flex-col" @click="pushPageList('/taskMessage')">
@@ -172,17 +174,13 @@
       :confirmBtnTxt="$t('user.confirmLog')" ref="kDialogRef" :dialogContent="$t('user.logOutContent')"
       @confirmclk="confirmClk">
     </kDialog>
-    <!-- 地区弹窗 -->
-    <kCascader @getareaname="getAreaName" :selectId="accountDetail.areaId" @areapopfinish="areaPopFinish"
-      ref="kCascaderRef"></kCascader>
+
   </div>
 </template>
 
 <script>
-// 导入地区弹窗
-import kCascader from "@/components/commom/kCascader/index.vue";
 // 导入接口
-import { getAdmin } from "@/service/merchantManage";
+import { getLoginInfo } from "@/service/merchantManage";
 import { updateAdmin } from "@/service/merchantManage";
 // 引入弹窗
 import kDialog from "@/components/commom/kDialog/index.vue";
@@ -195,13 +193,12 @@ import {
   $M_PhoneTest,
 } from "@/common/js/utils";
 import { useRouter } from "vue-router";
-import { updatePayPlatform } from "@/service/user";
-import { showFailToast, showToast, showSuccessToast, showConfirmDialog } from 'vant';
+import { showToast } from 'vant';
 import { useI18n } from "vue-i18n";
 import { styleUrl } from "@/common/js/utils";
 
 export default {
-  components: { sHeader, kDialog, kCascader },
+  components: { sHeader, kDialog },
   setup() {
     // 引入语言
     const { t } = useI18n();
@@ -223,7 +220,9 @@ export default {
 
     const level = ref('');
     level.value = user.level;
-    // console.log("user等级 >>>", user.level);
+
+    const cardNo = ref('');
+    cardNo.value = user.cardNo;
 
     const starsCount = ref(Math.floor(level.value % 5));
     const moonsCount = ref(Math.floor(level.value / 5));
@@ -315,13 +314,17 @@ export default {
       }
     };
 
-    const hiddenCardNo = "23123123123128479187".replace(/^(.{6})(?:\w+)(.{4})$/, "$1********$2");
-    // const hiddenCardNo = user.cardNo.replace(/^(.{6})(?:\w+)(.{4})$/, "$1********$2");
+    const hiddenCardNo = ref('');
+    hiddenCardNo.value = user.cardNo.replace(/^(\d{4}).*?(\d{4})$/, "$1********$2");
 
+    const eyeOpen = ref(false);
+    const clickEye = () => {
+      eyeOpen.value = !eyeOpen.value;
+    }
 
     // 获取账户详情
     const getAcccountDetail = () => {
-      getAdmin({ id: user.id }).then((res) => {
+      getLoginInfo().then((res) => {
         accountDetail.value = res.data.data;
       });
     };
@@ -352,56 +355,6 @@ export default {
         }, 200);
       }
     };
-    //切换申泽支付平台
-    const changeSunzeePay = (value) => {
-      showConfirmDialog({
-        title: t('user.tips'),
-        message: t('user.changeTips'),
-      }).then(() => {
-        // checked.value = newValue;
-        console.log(value);
-        params.id = 2738;
-        if (value) {
-          params.payPlatform = '1';
-        } else {
-          params.payPlatform = '0';
-        }
-        const { data } = updatePayPlatform(params);
-        if (data.code) {
-          showSuccessToast(t('user.changeSuccess'));
-          sunzeePay.value = value;
-        } else {
-          showFailToast(data.message);
-        }
-      }).catch((error) => {
-        console.error(error);
-      })
-    }
-    //切换七云支付平台
-    const changeSevenCloudPay = (value) => {
-      showConfirmDialog({
-        title: t('user.tips'),
-        message: t('user.changeTips'),
-      }).then(() => {
-        // checked.value = newValue;
-        console.log(value);
-        params.id = 2739;
-        if (value) {
-          params.payPlatform = '1';
-        } else {
-          params.payPlatform = '0';
-        }
-        const { data } = updatePayPlatform(params);
-        if (data.code) {
-          showSuccessToast(t('user.changeSuccess'));
-          sunzeePay.value = value;
-        } else {
-          showFailToast(data.message);
-        }
-      }).catch((error) => {
-        console.error(error);
-      })
-    }
 
     // 初始化页面获取列表
     onMounted(async () => {
@@ -509,14 +462,15 @@ export default {
       diyPassword,
       sunzeePay,
       sevencloudPay,
-      changeSunzeePay,
-      changeSevenCloudPay,
       level,
       icons,
       showTop,
       hiddenCardNo,
       phoneNumberShow,
       mailboxShow,
+      clickEye,
+      eyeOpen,
+      cardNo
     };
   }
 };

+ 10 - 0
vue.config.js

@@ -29,4 +29,14 @@ module.exports = {
     },
     disableHostCheck: true,
   },
+  chainWebpack: (config) => {
+    config.plugin('define').tap((definitions) => {
+      Object.assign(definitions[0], {
+        __VUE_OPTIONS_API__: 'true',
+        __VUE_PROD_DEVTOOLS__: 'false',
+        __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false'
+      })
+      return definitions
+    })
+  }
 };