소스 검색

持仓分析

jwyu 2 년 전
부모
커밋
f31a290166

+ 21 - 0
src/api/positionAnalysis.js

@@ -0,0 +1,21 @@
+// 持仓分析模块
+
+import {get,post} from './http'
+
+/**
+ * 持仓分析详情
+ * @param data_time 查询日期,日期为空时,默认返回最新日期
+ * @param classify_name 品种名称
+ * @param classify_type 合约名称
+ * @param exchange 交易所名称
+ */
+export const apiPositionAnalysisInfo=params=>{
+    return get('/trade/analysis/top',params)
+}
+
+/**
+ * 持仓分析列表
+ */
+export const apiPositionAnalysisList=()=>{
+    return get('/trade/analysis/classify',{})
+}

BIN
src/assets/calendar.png


BIN
src/assets/icon-back2.png


BIN
src/assets/leftNav/positionAnalysis-s.png


+ 7 - 0
src/layout/component/Aside.vue

@@ -66,6 +66,13 @@ let menuList = reactive([
     icon_path: new URL('../../assets/leftNav/chart-s.png', import.meta.url).href,
     children: null,
   },
+  {
+    MenuId: 8,
+    name: "持仓分析",
+    path: "/positionanalysis/index",
+    icon_path: new URL('../../assets/leftNav/positionAnalysis-s.png', import.meta.url).href,
+    children: null,
+  },
   {
     MenuId: 3,
     name: "活动",

+ 31 - 0
src/router/index.js

@@ -461,6 +461,37 @@ const routes=[
       }
     ]
   },
+  //持仓分析模块
+  {
+    path:"/positionanalysis",
+    name:"PositionAnalysis",
+    component: () => import("@/layout/Index.vue"),
+    meta: {
+      title:"持仓分析"
+    },
+    children:[
+      {
+        path:"index",
+        name:"PositionAnalysisIndex",
+        component:()=>import('@/views/positionAnalysis/Index.vue'),
+        meta: {
+          title: "持仓列表",
+          keepAlive:true,
+          isRoot:true
+        }
+      },
+      {
+        path:"detail",
+        name:"PositionAnalysisDetail",
+        component:()=>import('@/views/positionAnalysis/Detail.vue'),
+        meta: {
+          title: "持仓详情",
+          keepAlive:false,
+          isRoot:false
+        }
+      },
+    ]
+  },
 
   {
     path: '/:pathMatch(.*)',

+ 205 - 0
src/views/positionAnalysis/Detail.vue

@@ -0,0 +1,205 @@
+<script setup>
+import {ref} from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import moment from 'moment'
+import { useStore } from 'vuex';
+
+const route=useRoute()
+const router=useRouter()
+const store=useStore()
+
+const selectDate=ref('')//选择的日期
+// 周六日禁用
+function disabledDate(t){
+    if([5,6].includes(moment(t).weekday())){
+        return true
+    }else{
+        return false
+    }
+}
+
+let url=ref('')
+function init(){
+    const queryObj={
+        classify_name:route.query.classify_name,
+        classify_type:route.query.classify_type,
+        exchange:route.query.exchange,
+        token:localStorage.getItem('token'),
+        timestamp:new Date().getTime(),//防止缓存
+    }
+    let queryObjStr=''
+    for (const key in queryObj) {
+        if(!queryObjStr){
+                queryObjStr=`${key}=${queryObj[key]}`
+        }else{
+            queryObjStr=`${queryObjStr}&${key}=${queryObj[key]}`
+        }
+    }
+    console.log('拼接字符串:',queryObjStr);
+    url.value=`${import.meta.env.MODE==='production'?'https://details.hzinsights.com':'http://192.168.77.19:3000/xcx_h5'}/hzyb/chart/positionanalysis?${queryObjStr}`
+}
+init()
+
+window.addEventListener('message',(e)=>{
+    // 监听iframe高度
+    if(e.data?.opt=="updateIframeHeight"){
+        console.log(e.data.height);
+        const iframeEl=document.getElementById('iframe')
+        iframeEl.style.height=e.data.height+100+'px'
+    }
+    // 监听iframe重新获取数据时的参数
+    if(e.data?.opt=="updateInfo"){
+        selectDate.value=e.data.data_time
+        router.replace({
+            query:{
+                exchange:e.data.exchange,
+                classify_name:e.data.classify_name,
+                classify_type:e.data.classify_type
+            }
+        })
+        store.commit('modifyBreadCrumb',e.data.title)
+    }
+})
+
+// 操作选项
+function handleOpt(type){
+    let obj={}
+    if(type==='date'){
+        obj={
+            opt:type,
+            val:selectDate.value
+        }
+    }else if(type==='beforeDate'){
+        obj={
+            opt:type
+        }
+    }else if(type==='nextDate'){
+        obj={
+            opt:type
+        }
+    }else if(type==='beforeClassifyType'){
+        obj={
+            opt:type
+        }
+    }else if(type==='nextClassifyType'){
+        obj={
+            opt:type
+        }
+    }
+    const target=document.getElementById('iframe')
+    target.contentWindow.postMessage(obj,"*")
+}
+
+</script>
+
+<template>
+    <div class="hasrightaside-box position-analysis-detail-page">
+        <div class="content-box detail-content">
+            <iframe id='iframe' :src="url"></iframe>
+        </div>
+        <div class="right-aside-box right-wrap">
+            <div class="fix-top">
+                <div class="backlist-box" @click="$router.back()">返回持仓列表</div>
+                <div class="item-box">
+                    <div class="lable">日期选择</div>
+                    <el-date-picker
+                        v-model="selectDate"
+                        type="date"
+                        placeholder="请选择日期"
+                        value-format="YYYY-MM-DD"
+                        :disabled-date="disabledDate"
+                        @change="handleOpt('date')"
+                    />
+                </div>
+                <div class="item-box">
+                    <div class="lable">切换合约</div>
+                    <div class="btn" @click="handleOpt('beforeClassifyType')">上一个合约</div>
+                    <div class="btn" @click="handleOpt('nextClassifyType')">下一个合约</div>
+                </div>
+                <div class="item-box">
+                    <div class="lable">切换日期</div>
+                    <div class="btn" @click="handleOpt('beforeDate')">查看前一天</div>
+                    <div class="btn" @click="handleOpt('nextDate')">查看后一天</div>
+                </div>
+                <div class="item-box">
+                    <div class="lable">操作指南</div>
+                    <div style="color:#666;font-size: 14px;line-height: 24px;">上下滑动图表,点击图表中柱体弹出详细信息。</div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss">
+    .el-date-editor--date{
+        width: 180px !important;
+        .el-input__wrapper{
+            background: #F6F6F6;
+            border: 1px solid #EBEBEB;
+            border-radius: 20px;
+            height: 40px;
+            box-shadow: none;
+        }
+    }
+</style>
+
+<style lang="scss" scoped>
+.position-analysis-detail-page{
+    min-height: calc(100vh - 410px);
+    
+    .detail-content{
+        #iframe{
+            width: 100%;
+            min-height: 800px;
+            border: none;
+        }
+    }
+    .right-wrap{
+        .backlist-box{
+            color: #999999;
+            cursor: pointer;
+            vertical-align: middle;
+            &::before{
+                content: '';
+                display: inline-block;
+                width: 16px;
+                height: 16px;
+                background-image: url('@/assets/icon-back2.png');
+                background-size: cover;
+                vertical-align: middle;
+                margin-right: 10px;
+            }
+        }
+        .item-box{
+            margin-top: 40px;
+            .lable{
+                font-size: 18px;
+                margin-bottom: 20px;
+                &::before{
+                    content: '';
+                    display: inline-block;
+                    width: 3px;
+                    height: 20px;
+                    background-color: #F3A52F;
+                    border-radius: 2px;
+                    vertical-align: middle;
+                    margin-right: 10px;
+                }
+            }
+            .btn{
+                width: 140px;
+                height: 40px;
+                background: #FFFFFF;
+                border: 1px solid #F3A52F;
+                border-radius: 20px;
+                font-size: 16px;
+                line-height: 40px;
+                color: #F3A52F;
+                text-align: center;
+                cursor: pointer;
+                margin-bottom: 20px;
+            }
+        }
+    }
+}
+</style>

+ 48 - 0
src/views/positionAnalysis/Index.vue

@@ -0,0 +1,48 @@
+<script setup>
+import {ref} from 'vue'
+import IndexContent from './components/IndexContent.vue'
+import {apiPositionAnalysisList} from '@/api/positionAnalysis'
+
+let activeType=ref('')
+let list=ref([])
+function getList(){
+    apiPositionAnalysisList().then(res=>{
+        list.value=res.data||[]
+        activeType.value=res.data[0]&&res.data[0].exchange
+    })
+}
+getList()
+
+</script>
+
+<template>
+    <div class="position-analysis-index-page">
+        <el-tabs 
+            class="tabs-wrap"
+            v-model="activeType"
+        >
+            <el-tab-pane 
+                v-for="item in list"
+                :key="item.exchange"
+                :label="item.exchange" 
+                :name="item.exchange"
+            >
+                <indexContent :list="item.items" :num="item.num" :time="item.data_time" :exchange="item.exchange"/>
+            </el-tab-pane>
+            
+        </el-tabs>
+    </div>
+</template>
+
+<style lang="scss">
+.position-analysis-index-page{
+    .tabs-wrap{
+        .el-tabs__nav-wrap::after{
+            display: none;
+        }
+        .el-tabs__item{
+            font-size: 16px;
+        }
+    }
+}
+</style>

+ 106 - 0
src/views/positionAnalysis/components/IndexContent.vue

@@ -0,0 +1,106 @@
+<script setup>
+import { useRouter } from "vue-router"
+
+
+const router=useRouter()
+
+const props=defineProps({
+    num:Number,
+    time:String,
+    exchange:String,
+    list:null
+})
+
+function goDetail(_item,item){
+    // const queryObj={
+    //     classify_name:item.classify_name,
+    //     classify_type:_item.classify_type,
+    //     exchange:props.exchange
+    // }
+
+    router.push({
+        path:"/positionanalysis/detail",
+        query:{
+            classify_name:item.classify_name,
+            classify_type:_item.classify_type,
+            exchange:props.exchange
+        }
+    })
+
+    // let queryObjStr=''
+    //         for (const key in queryObj) {
+    //             if(!queryObjStr){
+    //                     queryObjStr=`${key}=${queryObj[key]}`
+    //             }else{
+    //                 queryObjStr=`${queryObjStr}&${key}=${queryObj[key]}`
+    //             }
+    //         }
+            // uni.navigateTo({
+            //     url: `/pages/positionAnalysis/detail?${queryObjStr}`,
+            //     success: (result) => {},
+            //     fail: () => {},
+            //     complete: () => {}
+            // });
+              
+}
+
+</script>
+
+<template>
+    <div class="index-content-wrap">
+        <div class="top-box">
+            <span style="margin-right:20px">{{num}}品种</span>
+            <span>{{time}}</span>
+        </div>
+        <div class="list-wrap">
+            <div class="flex item" v-for="item in list" :key="item.classify_name">
+                <div class="label">{{item.classify_name}}</div>
+                <div style="flex:1">
+                    <div 
+                        class="opt" 
+                        v-for="_item in item.items" 
+                        :key="_item.classify_type"
+                        @click="goDetail(_item,item)"
+                    >{{_item.classify_type}}</div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.index-content-wrap{
+    .top-box{
+        background: #FFFBF5;
+        padding: 15px 30px;
+        span{
+            display: inline-block;
+        }
+    }
+    .list-wrap{
+        padding: 30px 0;
+        .item{
+            margin-bottom: 40px;
+
+            .label{
+                color: #666;
+                width: 100px;
+                padding-top: 15px;
+                font-size: 14px;
+            }
+            .opt{
+                padding: 6px 10px;
+                min-width: 100px;
+                text-align: center;
+                display: inline-block;
+                margin-right: 20px;
+                margin-bottom: 20px;
+                background: #FFFBF5;
+                border: 1px solid #F3A52F;
+                border-radius: 4px;
+                cursor: pointer;
+            }
+        }
+    }
+}
+</style>