浏览代码

添加因子指标弹窗,跨页多选,计算公式

cxmo 11 月之前
父节点
当前提交
288fa0300f

二进制
src/assets/img/icons/formula-add.png


+ 196 - 0
src/views/chartRelevance_manage/relevance/components/batchSelectFormula.vue

@@ -0,0 +1,196 @@
+<template>
+    <div class="batch-select-formula-wrap">
+        <el-form :model="formulaForm" :rules="formulaRules" label-width="80px" ref="formulaForm">
+            <div class="formula-list">
+                <div class="list-item" v-for="(item,index) in formulaForm.formulaList" :key="index">
+                    <span>
+                        <img @click="deleteFormula(index)" style="width:15px;height:15px;cursor: pointer;" src="~@/assets/img/ai_m/delete.png" alt="">
+                    </span>
+                    <el-select v-model="item.formulaType">
+                        <el-option 
+                            v-for="option in formulaOption"
+                            :key="option.value"
+                            :value="option.value"
+                            :label="option.label"
+                        />
+                    </el-select>
+                    <div class="form-item-box">
+                        <!-- N期 N等于-->
+                        <el-form-item
+                            v-if="[8,12,13].includes(item.formulaType)"
+                            :label="$t('EtaBasePage.label_n_val')"
+                            :prop="`formulaList[${index}].nNum`"
+                            :rules="{required:true,message:'N不能为空',trigger:'blur'}"
+                        >
+                            <el-input v-model="item.nNum" :placeholder="$t('Edb.InputHolderAll.input_n_value')" type="number"></el-input>
+                        </el-form-item>
+                        <!-- 超季节性 N等于 日历-->
+                        <el-form-item 
+                            v-if="item.formulaType===35"
+                            :label="$t('EtaBasePage.label_n_val')"
+                            :prop="`formulaList[${index}].nNum`"
+                            :rules="{required:true,message:'N不能为空',trigger:'blur'}"
+                        >
+                            <el-input v-model="item.nNum" :placeholder="$t('Edb.InputHolderAll.input_n_value')" type="number"></el-input>
+                        </el-form-item>
+                        <el-form-item 
+                            v-if="item.formulaType===35"
+                            :label="$t('EtaBasePage.label_calendar')"
+                        >
+                            <el-select v-model="item.calendarType">
+                                <el-option :label="$t('Chart.calendar_gre')" value="公历"></el-option>
+                                <el-option :label="$t('Chart.calendar_lunar')" value="农历"></el-option>
+                            </el-select>
+                        </el-form-item>
+                        <!-- 指数修匀 alpha值 -->
+                        <el-form-item
+                            v-if="item.formulaType===72"
+                            :label="$t('EtaBasePage.alpha_value_lable')" 
+                            :prop="`formulaList[${index}].alphaValue`"
+                            :rules="[
+                                {required:true,message:'alpha不能为空',trigger:'blur'},
+                                {validator:validator,trigger:['change','blur']}]">
+                            <el-input v-model.trim="item.alphaValue" style="width:140px" :placeholder="$t('Edb.InputHolderAll.input_alpha_val')" type="number"></el-input>
+                        </el-form-item>
+                    </div>
+                    
+                </div>
+            </div>
+            <div class="tool-box-wrap">
+                <div class="add-btn" @click="addFormula">
+                        <img style="width:15px;height:15px;" src="~@/assets/img/icons/formula-add.png" alt="">
+                    添加计算公式
+                </div>
+                <div class="input-box">
+                    <el-form-item
+                        required
+                        label="指标系列名称"
+                        label-width="120px"
+                    >
+                        <el-input v-model.trim="formulaForm.name" style="width:230px" placeholder="请输入指标系列名称"></el-input>
+                    </el-form-item>
+                </div>
+            </div>
+        </el-form>
+        
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        dataFormulaList:{
+            type:Array,
+            default:[]
+        }
+    },
+    computed:{
+        formulaOption(){
+            return [
+                {
+                    value:5,
+                    label:this.$t('Edb.CalculatesAll.on_year'),//同比值
+                },
+                {
+                    value:7,
+                    label:this.$t('Edb.CalculatesAll.differ'),//同差值
+                },
+                {
+                    value:8,
+                    label:this.$t('Edb.CalculatesAll.rule_move_average'),//N期移动均值
+                },
+                {
+                    value:12,
+                    label:this.$t('Edb.CalculatesAll.period_over_period'),//N期环比值
+                },
+                {
+                    value:13,
+                    label:this.$t('Edb.CalculatesAll.period_difference'),//N期环差值
+                },
+                {
+                    value:35,
+                    label:this.$t('Edb.CalculatesAll.super_seasonal'),//超季节性
+                },
+                {
+                    value:72,
+                    label:this.$t('Edb.CalculatesAll.ex_smooth'),//指数修匀
+                },
+            ]
+        }
+    },
+    data() {
+        return {
+            formulaForm:{
+                formulaList:[]
+            },
+            formulaRules:{},
+        };
+    },
+    methods: {
+        //打开弹窗时,在外层组件调用
+        initFormulaList(){
+            this.formulaForm.formulaList = _.cloneDeep(this.dataFormulaList)
+        },
+        validator(rule,value,callback){
+            if(Number(value)<=0||Number(value)>=1){
+                callback(new Error(this.$t('Edb.Valids.alpha_value_vaild')))
+            }else{
+                callback()
+            }
+        },
+        addFormula(){
+            this.formulaForm.formulaList.push({
+                formulaType:5,
+                nNum:'',
+                calendarType:'公历',
+                alphaValue:'',
+            })
+        },
+        deleteFormula(index){
+            if(this.formulaForm.formulaList.length>=5){
+                return this.$message.warning("最多仅能添加5个计算公式")
+            }
+            this.formulaForm.formulaList.splice(index,1)
+        },
+        async checkForm(){
+            return await this.$refs.formulaForm.validate()
+        }
+    },
+};
+</script>
+
+<style lang="scss">
+.batch-select-formula-wrap{
+    .el-input,.el-select{
+        width:140px;
+    }
+    .formula-list{
+        margin-top: 20px;
+        .list-item{
+            margin-bottom: 15px;
+            display: flex;
+            align-items: center;
+            gap:0 15px;
+            .form-item-box{
+                display: flex;
+                .el-form-item{
+                    margin-bottom: 0;
+                }
+            }
+        }
+    }
+    .tool-box-wrap{
+        margin-top: 20px;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        .add-btn{
+            color:#0052D9;
+            display: flex;
+            align-items: center;
+            gap:0 10px;
+            cursor: pointer;
+        }
+    }
+}
+</style>

+ 226 - 0
src/views/chartRelevance_manage/relevance/components/batchSelectTable.vue

@@ -0,0 +1,226 @@
+<template>
+    <!-- 封装表格跨页多选逻辑 -->
+    <div class="batch-select-table">
+        <div class="table-box">
+            <el-table
+                border height="500px"
+                v-loading="tableLoading"
+                ref="tableRef" 
+                :data="tableData"
+                @select="selectHandle" 
+                @select-all="selectAllHandle"
+            >
+                <el-table-column type="selection" min-width="50" align="center"/>
+                <el-table-column 
+                    align="center"
+                    v-for="column in tableColumns" 
+                    :key="column.key"
+                    :label="column.label"
+                    :prop="column.key"
+                    :width="column.width"
+                    :show-overflow-tooltip="column.showOverflowTooltip">
+                    <template slot-scope="{row}">
+                        <span v-if="column.key==='Frequency'">{{ getFrequencyTrans(row.Frequency) }}</span>
+                        <span v-else-if="['UniEn','Unit'].includes(column.key)">{{ getUnitTrans(row.Unit) }}</span>
+                        <span v-else>{{ row[column.key] }}</span>
+                    </template>
+                </el-table-column>
+            </el-table>
+            <m-page 
+                style="margin-top:10px"
+                class="table-page" 
+                v-show="tableParams.total"
+                :total="tableParams.total" 
+                :pageSize="tableParams.pageSize"
+                :page_no="tableParams.pageNo"
+                :pagercount="tableParams.pagerCount"
+                @handleCurrentChange="pageNumberChange"
+            />
+        </div>
+        <el-button type="primary">加入已选指标</el-button>
+        <div class="select-box">
+            <el-table
+                border height="500px"
+                ref="selectRef" 
+                :data="selectData"
+            >
+            <el-table-column
+                align="center"
+                label="指标全称"
+                props="name"
+             />
+             <el-table-column width="50px" align="center" v-if="selectData.length">
+                <template slot="header">
+                    <img @click="handleDelSelect('all')" style="width:15px;height:15px;cursor: pointer;" src="~@/assets/img/ai_m/delete.png" alt="">
+                </template>
+                <template slot-scope="{row}">
+                    <img @click="handleDelSelect(row)" style="width:15px;height:15px;cursor: pointer;" src="~@/assets/img/ai_m/delete.png" alt="">
+                </template>
+            </el-table-column>
+        </el-table>
+        </div>
+    </div>
+</template>
+
+<script>
+import mPage from '@/components/mPage.vue'
+export default {
+    components:{mPage},
+    props:{
+        tableData:{
+            type:Array,
+            default:[]
+        },
+        tableLoading:{
+            type:Boolean,
+            default:false
+        },
+        tableColumns:{
+            type:Array,
+            default:[]
+        },
+        tableParams:{
+            type:Object,
+            default:()=>{
+                return {
+                    total:0,
+                    pageSize:20,
+                    pageNo:1,
+                    pagerCount:5,
+                    uniqueKey:'Id'
+                }
+            }
+        },
+        isSelectAll:{
+            type:Boolean,
+            default:false,
+        }
+    },
+    watch:{
+        isSelectAll(newValue){
+            this.selectList = []
+            this.$refs.tableRef && this.tableData.length && this.$refs.tableRef.clearSelection()
+            if(newValue){
+                //会触发select-all
+                this.$refs.tableRef && this.tableData.length && this.$refs.tableRef.toggleAllSelection()
+                /* //不会触发select-all
+                this.$refs.tableRef && this.tableData.length && this.$refs.tableRef.toggleRowSelection(this.tableData[0],true) */
+            }
+        },
+    },
+    data() {
+        return {
+            selectList:[],
+            selectData:[],
+            selectionReactCancel:false,
+        };
+    },
+    methods: {
+        //点击数据行的checkbox触发 selection:已选择的所有数据行;row:当前点击的数据行
+        selectHandle(selection,row){
+            const {uniqueKey} = this.tableParams
+            //通过判断selection中有无row确定是勾选了checkbox还是取消勾选
+            //当为勾选时,判断selectList是否表示已选择的数据(isSelectAll===false),若不是则不加入
+            //当为取消勾选时,判断selectList是否表示已剔除的数据(isSelectAll===true),若不是则不加入
+            let check = selection.some(i=>i[uniqueKey] == row[uniqueKey])?(!this.isSelectAll):(this.isSelectAll)
+            if(check){
+                this.selectList.push(row[uniqueKey])
+            }else{
+                this.selectList = this.selectList.filter(i=>i!=row[uniqueKey])
+            }
+            this.selectionChange()
+        },
+        //点击表头全选 or 调用toggleAllSelection 触发
+        selectAllHandle(selection){
+            //当前table的所有数据
+            const tableIds = this.tableData.map(it => it[this.tableParams.uniqueKey])
+            //通过判断selection中有无数据确定是全选or取消全选
+            //当为全选时,判断selectList是否表示已选择的数据(isSelectAll===false),若不是则从selectList中剔除
+            //当为取消全选时,判断selectList是否表示已剔除的数据(isSelectAll===true),若不是则从selectList中剔除
+            let check = selection&&selection.length?(!this.isSelectAll):this.isSelectAll
+            if(check){
+                this.selectList =  [...this.selectList,...tableIds]
+            }else{
+                this.selectList = this.selectList.filter(it => !tableIds.includes(it))
+            }
+            this.selectionChange()
+        },
+        //当勾选项改变时 处理数据
+        selectionChange(){
+            //去重 selectList
+            let duplicateArr = Array.from(new Set(this.selectList))
+            let isCheckAll = false,isIndeterminate = false
+            //判断已选择的数据,更改列表全选checkbox的状态
+            /**
+             * 全选:
+             * 1.selectList.length === total && isSelectAll === false (已选择的数据为全部数据)
+             * 2.selectList.length === 0 && isSelectAll === true (已剔除的指标为空)
+             * 以上两种满足其一即可
+             */
+            const selectAll = duplicateArr.length===this.tableParams.total && (!this.isSelectAll)
+                || duplicateArr.length===0 && this.isSelectAll
+            /**
+             * 全不选:
+             * 1.selectList.length === total && isSelectAll === true (剔除了全部数据)
+             * 2.selectList.length === 0 && isSelectAll === false (没选择任何数据)
+             * 以上两种满足其一即可
+             */
+            const selectNone = duplicateArr.length===this.tableParams.total && this.isSelectAll
+                || duplicateArr.length===0 && (!this.isSelectAll)
+            //其余情况均为半选
+
+            if(selectAll){
+                isCheckAll = true
+                isIndeterminate = false
+            }else if(selectNone){
+                isCheckAll = false
+                isIndeterminate = false
+            }else{
+                isCheckAll = false
+                isIndeterminate = true
+            }
+
+            this.$emit('changeCheckAll',{isCheckAll,isIndeterminate})
+        },
+        //切换页面时调整勾选项 (在外层组件调用)
+        adjustSelection(){
+            const {uniqueKey} = this.tableParams
+            this.$refs.tableRef.clearSelection()
+            this.tableData.forEach(data=>{
+                if(this.selectList.includes(data[uniqueKey])){
+                    //isSelectAll===false,selectList为已选择的数据,则对应数据行打勾
+                    //isSelectAll === true,selectList为已剔除的数据,则对应的数据行取消打勾
+                    this.$nextTick(()=>{
+                        this.$refs.tableRef.toggleRowSelection(data,!this.isSelectAll)
+                    })
+                }else{
+                    this.$nextTick(()=>{
+                        this.$refs.tableRef.toggleRowSelection(data,this.isSelectAll)
+                    })
+                }
+            })
+        },
+        pageNumberChange(page){
+            this.$emit('pageChange',page)
+        },
+        handleDelSelect(data){},
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.batch-select-table{
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    gap:0 20px;
+    .table-box,.select-box{
+        flex:1;
+    }
+    &::after{
+        content:'';
+        flex:0 0 auto;
+        visibility: hidden;
+    }
+}
+</style>

+ 180 - 6
src/views/chartRelevance_manage/relevance/components/multipleIndForm.vue

@@ -1,12 +1,12 @@
 <template>
     <div class="multiple-model-form model-form">
         <!-- 标的指标 -->
-        <el-form-item label="标的指标" prop="indTarget" class="select-target" required>
+        <el-form-item label="标的指标" prop="IndTarget" class="select-target">
             <selectTarget 
                 :defaultId="chartInfoData.EdbInfoList?chartInfoData.EdbInfoList[1].EdbInfoId:''"
                 :defaultOpt="chartInfoData.EdbInfoList?[chartInfoData.EdbInfoList[1]]:[]" 
                 :defaultType="chartInfoData.EdbInfoList?chartInfoData.EdbInfoList[1].EdbInfoCategoryType:''"
-                @select="handleSelectTarget"
+                @select="(target)=>handleSelectTarget('IndTarget',target)"
             />
         </el-form-item>
         <!-- 因子指标系列 -->
@@ -17,7 +17,7 @@
                     <div class="list-item">123</div>
                     <div class="list-item">456</div>
                 </div>
-            <div class="add-factor-btn">
+            <div class="add-factor-btn" @click="openAddDialog({})">
                 <img src="~@/assets/img/add-quadrate-blue.png" />
                 添加因子指标系列
             </div>
@@ -67,16 +67,190 @@
                 </el-select>
             </el-form-item>
         </div>
+        <el-dialog
+            :visible.sync="isAddFactorDialogShow"
+            :close-on-click-modal="false"
+            :modal-append-to-body='false'
+            @close="isAddFactorDialogShow=false"
+            center width="70%" top="30px"
+            title="添加因子指标系列"
+            custom-class="add-factor-dialog"
+        >
+            <div class="dialog-content">
+                <!-- 表格筛选项 -->
+                <div class="table-select-box">
+                    <el-cascader></el-cascader>
+                    <el-select></el-select>
+                    <el-cascader></el-cascader>
+                    <el-input style="width:230px;"></el-input>
+                    <el-checkbox 
+                        :indeterminate="isIndeterminate" 
+                        v-model="isCheckAll" 
+                        @change="listCheckAllChange">列表全选</el-checkbox>
+                </div>
+                <!-- 表格 -->
+                <batchSelectTable
+                    ref="batchSelectTable"
+                    :tableColumns="tableColumns"
+                    :tableData="tableData"
+                    :tableParams="tableParams"
+                    :isSelectAll="isSelectAll"
+                    @pageChange="tablePageChange"
+                    @changeCheckAll="changeCheckAll"
+                ></batchSelectTable>
+                <!-- 计算公式 -->
+                <batchSelectFormula
+                    ref="batchSelectFormula"
+                ></batchSelectFormula>
+            </div>
+            <div class="dialog-footer">
+                <el-button type="primary" plain @click="isAddFactorDialogShow=false">{{$t('Dialog.cancel_btn')}}</el-button>
+                <el-button type="primary" @click="handleAddFactor">{{$t('Dialog.next_step')}}</el-button>
+            </div>
+        </el-dialog>
     </div>
 </template>
 
 <script>
+import batchSelectTable from './batchSelectTable.vue'
 import formMixin from './formMixin';
+import batchSelectFormula from './batchSelectFormula.vue'
 export default {
-    mixins:[formMixin]
+    mixins:[formMixin],
+	components: { batchSelectTable, batchSelectFormula },
+    computed:{
+        tableColumns(){
+            return [
+                {
+                    key:this.$i18nt.locale==='en'?'EdbNameEn':'EdbName',
+                    label:this.$t('EtaBasePage.full_metric_name'),//指标全称
+                    width:'',
+                    showOverflowTooltip:true,
+                },
+                {
+                    key:'EndDate',
+                    label:this.$t('Edb.Detail.e_latest_date'),//最新日期
+                    width:'120px',
+                },
+                {
+                    key:'EndValue',
+                    label:this.$t('Edb.Detail.e_latest_value'),//最新值
+                    width:'80px',
+                    showOverflowTooltip:true,
+                },
+                {
+                    key:'SysUserRealName',
+                    label:this.$t('EtaBasePage.table_col_creator'),//创建人
+                    width:'80px',
+                    showOverflowTooltip:true,
+                },
+                {
+                    key:'Frequency',
+                    label:this.$t('Edb.Detail.e_fre'),//频率
+                    width:'50px',
+                    showOverflowTooltip:true,
+                },
+                {
+                    key:this.$i18nt.locale==='en'?'UnitEn':'Unit',
+                    label:this.$t('Edb.Detail.e_unit'),//单位
+                    width:'50px',
+                    showOverflowTooltip:true,
+                },
+            ]
+        }
+    },
+    data(){
+        return {
+            isAddFactorDialogShow:false,
+            factorData:{},
+            tableData:[
+                {Id:1,EdbName:'111',EndDate:'2024-05-24',EndValue:15},
+                {Id:2,EdbName:'222',EndDate:'2024-05-24',EndValue:16},
+                /* {EdbName:'333',EndDate:'2024-05-24',EndValue:17} */
+            ],
+            tableSelectParams:{
+                classify:'',
+                frequency:'',
+                creator:'',
+                name:'',
+            },
+            tableParams:{
+                total:3,
+                pageSize:2,
+                pageNo:1,
+                pagerCount:5,
+                uniqueKey:'Id',//数据行的唯一key
+            },
+            isIndeterminate:false,//与isCheckAll一起表示列表全选的状态
+            isCheckAll:false,//与isIndeterminate一起表示列表全选的状态
+            isSelectAll:false,//是否勾选了列表全选:为true时,selectList是剔除的指标,为false时selectList是已选择的指标
+        }
+    },
+    methods:{
+        openAddDialog(data){
+            this.factorData = data
+            this.isAddFactorDialogShow = true
+        },
+        listCheckAllChange(value){
+            this.isSelectAll = value
+        },
+        changeCheckAll({isCheckAll,isIndeterminate}){
+            this.isCheckAll = isCheckAll
+            this.isIndeterminate = isIndeterminate
+        },
+        tablePageChange(page){
+            if(page===2){
+                this.tableData = [{Id:3,EdbName:'333',EndDate:'2024-05-24',EndValue:17}]
+            }else{
+                this.tableData = [
+                    {Id:1,EdbName:'111',EndDate:'2024-05-24',EndValue:15},
+                    {Id:2,EdbName:'222',EndDate:'2024-05-24',EndValue:16},
+                ]
+            }
+            this.tableParams.pageNo = page
+            this.getTableData('pageChange')
+        },
+        getTableData(type){
+            if(type==='pageChange'){
+                this.$nextTick(()=>{
+                    this.$refs.batchSelectTable.adjustSelection()
+                })
+            }
+        },
+        async handleAddFactor(){
+            //校验 是否选择了指标
+            //校验 计算公式填写
+            await this.$refs.batchSelectFormula.checkForm()
+          
+            this.addFactorIndicators()
+        },
+        addFactorIndicators(){
+            //因子指标系列push
+        }
+    }
 };
 </script>
 
-<style scoped lang="scss">
-
+<style lang="scss">
+.add-factor-dialog{
+    .dialog-content{
+        height: 70%;
+        overflow-y: auto;
+        .table-select-box{
+            margin-bottom: 15px;
+            display: flex;
+            align-items: center;
+            gap:0 15px;
+            .el-cascader,.el-select{
+                .el-input{
+                    width:100%;
+                }
+            }
+        }
+    }
+    .dialog-footer{
+        text-align:center;
+        margin:60px 0 40px 0;
+    }
+}
 </style>

+ 24 - 5
src/views/chartRelevance_manage/relevance/relevanceChartEditorV2.vue

@@ -91,7 +91,16 @@
                 </div>
             </div>
             <!-- 多因子模式 -->
-            <div class="multiple-model-wrap" v-if="infoForm.Model===2"></div>
+            <div class="multiple-model-wrap" v-if="infoForm.Model===2">
+                <!-- 相关性矩阵 -->
+                <div class="relevant-matrix-table-box">
+                    相关性矩阵
+                </div>
+                <!-- 相关性图表 -->
+                <div class="relevant-chart-box">
+                    相关性图表
+                </div>
+            </div>
         </div>
     </div>
 </template>
@@ -112,9 +121,10 @@ export default {
     data() {
         return {
             infoForm:{
-                Model:1,
-                EdbInfoIdA:'',
-                EdbInfoIdB:'',
+                Model:1,//模式
+                EdbInfoIdA:'',//指标A
+                EdbInfoIdB:'',//指标B
+                IndTarget:'',//标的指标
                 Curve:{
                     DateType:3,
                     Date:'',
@@ -215,7 +225,7 @@ export default {
         //确定-预览相关性图表
         async previewChart(){
             //表单校验
-            const test = await this.$refs.infoFormRef.validate()
+            await this.$refs.infoFormRef.validate()
             //相关性值校验
             if(!this.checkValue()) return 
             //单因子:渲染相关性图表,需要保存MultipleGraphConfigId
@@ -422,6 +432,15 @@ export default {
             color: #666;
             padding: 100px 0;
         }
+        .multiple-model-wrap{
+            display: flex;
+            flex-direction: column;
+            height: calc(100vh - 120px);
+            .relevant-matrix-table-box,.relevant-chart-box{
+                flex:1;
+                overflow: auto;
+            }
+        }
     }
 }
 </style>