1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252 |
- <template>
- <div class="add-predicedb-page">
- <div class="aside-warp">
- <div class="btn-box">
- <el-button type="primary" @click="saveHandle">保存</el-button>
- <el-button type="primary" plain @click="$router.back()">取消</el-button>
- </div>
- <div class="con">
- <el-form
- ref="formRef"
- hide-required-asterisk
- :model="formData"
- :rules="formRules"
- >
- <el-form-item prop="classify">
- <div class="item">
- <span class="label">添加到分类</span>
- <!-- <el-select
- v-model="formData.classify"
- placeholder="请选择分类"
- style="width: 100%"
- clearable
- >
- <el-option
- v-for="item in classifyArr"
- :key="item.ClassifyId"
- :label="item.ClassifyName"
- :value="item.ClassifyId"
- >
- </el-option>
- </el-select> -->
- <el-cascader
- v-model="formData.classify"
- :options="classifyArr"
- :props="{
- label: 'ClassifyName',
- value: 'ClassifyId',
- children: 'Children',
- }"
- style="width: 90%"
- placeholder="请选择所属分类"
- />
- </div>
- </el-form-item>
- <el-form-item prop="oldEdb" v-if="!formData.edb_id">
- <div class="item">
- <span class="label">选择指标</span>
- <el-select
- v-model="formData.oldEdb"
- v-loadMore="searchLoad"
- style="width: 100%"
- :filterable="!formData.oldEdb"
- remote
- clearable
- placeholder="指标ID/指标名称"
- :remote-method="searchHandle"
- @click.native="inputFocusHandle"
- @change="selectEdbHandle"
- >
- <i slot="prefix" class="el-input__icon el-icon-search"></i>
- <el-option
- v-for="item in searchOptions"
- :key="item.EdbInfoId"
- :label="item.EdbName"
- :value="item.EdbInfoId"
- >
- <edbDetailPopover :info="item">
- <div slot="reference">{{item.EdbName}}</div>
- </edbDetailPopover>
- </el-option>
- </el-select>
- </div>
- </el-form-item>
- <el-form-item prop="edbName">
- <div class="item">
- <span class="label">预测指标名称</span>
- <el-input
- v-model="formData.edbName"
- style="width: 100%"
- placeholder="指标名称"
- />
- </div>
- </el-form-item>
- <el-form-item prop="dateType">
- <div class="item">
- <span class="label">预测日期类型</span>
- <el-select
- v-model="formData.dateType"
- placeholder="请选择日期类型"
- style="width: 100%"
- @change="getChartInfo"
- >
- <el-option label="交易日" value="交易日"></el-option>
- <el-option label="自然日" value="自然日"></el-option>
- </el-select>
- </div>
- </el-form-item>
- <el-form-item v-if="formData.oldEdbName">
- <div class="item" style="margin-top: 30px">
- <span class="label">原指标名称:{{ formData.oldEdbName }}</span>
- </div>
- </el-form-item>
- <el-form-item prop="frequency">
- <div class="item">
- <span class="label">频度:{{ formData.frequency }}</span>
- </div>
- </el-form-item>
- <el-form-item prop="newdata">
- <div class="item">
- <span class="label">最新值:{{ formData.newdata }}</span>
- </div>
- </el-form-item>
- <el-form-item prop="lasetDate">
- <div class="item" style="margin-bottom: 30px">
- <span class="label">最新日期:{{ formData.lasetDate }}</span>
- </div>
- </el-form-item>
- </el-form>
- <!-- 规则 -->
- <el-collapse v-model="activeNames" class="rules-ul">
- <el-collapse-item
- v-for="(item, index) in rulesArr"
- :key="index"
- :name="index"
- >
- <template slot="title">
- <span class="text_oneLine">规则{{ index + 1 }}</span>
- <i
- class="el-icon-delete del-icon"
- @click.stop="removeRuleHandle(item, index)"
- />
- </template>
- <div class="wrap">
- <div class="item">
- <span class="label">预测截止日期</span>
- <el-date-picker
- v-model="item.endDate"
- type="date"
- style="width: 100%"
- value-format="yyyy-MM-dd"
- placeholder="请选择日期"
- :picker-options="timePickerOptions"
- @change="changeDateHandle($event,index)"
- >
- <!-- :disabled="index!==0 && !rulesArr[index-1].endDate" -->
- </el-date-picker>
- </div>
- <div class="item">
- <span class="label">
- 预测规则
- <el-tooltip effect="dark" placement="right">
- <div
- slot="content"
- v-html="rulesTip"
- style="line-height: 20px;max-width:600px"
- ></div>
- <i class="el-icon-question" style="color: #666" />
- </el-tooltip>
- </span>
- <el-select
- v-model="item.predict_type"
- placeholder="请选择分类"
- style="width: 100%"
- @change="changePredictType($event,item,index)"
- >
- <el-option
- v-for="item in predictTypeOptions"
- :key="item.key"
- :label="item.label"
- :value="item.key"
- :disabled="formData.frequency==='年度'&&[5,6,11,12].includes(item.key)"
- >
- </el-option>
- </el-select>
- </div>
- <div class="item" v-if="![1,9,11,12,14,15].includes(item.predict_type)">
- <span class="label">{{labelMap[item.predict_type]}}</span>
- <el-input
- v-model="item.fixedValue"
- style="width: 100%"
- placeholder="请输入值"
- type="number"
- />
- </div>
- <!-- 季节性规则 -->
- <div v-if="[11,15].includes(item.predict_type)">
- <div class="item">
- <span class="label">选择方式</span>
- <el-select
- v-model="item.season_way"
- placeholder="请选择方式"
- style="width: 100%"
- @change="item.n_value = '';item.season_years=[]"
- >
- <el-option label="连续N年" :value="1"/>
- <el-option label="指定N年" :value="2"/>
- </el-select>
- </div>
- <div class="item" v-if="item.season_way===1">
- <span class="label">期数</span>
- <el-input
- v-model="item.n_value"
- style="width: 100%"
- placeholder="请输入值"
- type="number"
- />
- </div>
- <div class="item" v-else>
- <el-date-picker
- v-model="select_year"
- type="year"
- value-format="yyyy"
- placeholder="选择年份"
- @change="pushYear($event,item)"
- />
- <div class="season-year-cont" v-if="item.season_years.length">
- <el-tag
- v-for="year in item.season_years"
- :key="year"
- style="margin: 5px;"
- @close="removeYear(year,item)"
- closable
- >
- {{year}}
- </el-tag>
- </div>
- </div>
- <div class="item" v-if="item.predict_type===11">
- <el-radio-group v-model="item.season_type">
- <el-radio label="公历">公历</el-radio>
- <el-radio label="农历">农历</el-radio>
- </el-radio-group>
- </div>
- </div>
- <!-- 移动平均同比 -->
- <div v-else-if="item.predict_type===12">
- <div class="item">
- <span class="label">期数</span>
- <el-input
- v-model="item.n_value"
- style="width: 100%"
- placeholder="请输入值"
- type="number"
- />
- </div>
- <div class="item">
- <span class="label">同比年份</span>
- <el-date-picker
- v-model="item.move_average_year"
- type="year"
- value-format="yyyy"
- placeholder="选择年份"
- @change="pushYear($event,item)"
- />
- </div>
- </div>
- <!-- 一元线性拟合 -->
- <div v-else-if="item.predict_type===14">
- <div class="item">
- <span class="label">
- 自变量
- <el-radio-group v-model="edbFromType">
- <el-radio :label="0" style="margin-right: 15px">ETA指标</el-radio>
- <el-radio :label="1">ETA预测指标</el-radio>
- </el-radio-group>
- </span>
- <el-select
- v-model="item.self_target"
- v-loadMore="searchLoad"
- ref="searchRef"
- :filterable="!item.self_target"
- remote
- clearable
- placeholder="指标ID/指标名称"
- style="width:88%;margin-top: 10px;display:inline-block"
- :remote-method="searchHandle"
- @click.native="inputFocusHandle($event,'self_target')"
- >
- <i slot="prefix" class="el-input__icon el-icon-search"></i>
- <el-option
- v-for="item in searchOptions"
- :key="item.EdbInfoId"
- :label="item.EdbName"
- :value="item.EdbInfoId"
- >
- </el-option>
- </el-select>
- <i class="el-icon-tickets" style="color:#409EFF;font-size:18px" @click="isLookHistory=true;lookEdbId=item.self_target;" v-if="item.self_target"/>
- </div>
- <div class="item">
- <span class="label">
- 领先天数
- <el-input
- v-model="item.fixedValue"
- style="width: 80px;margin:0 5px;"
- type="number"
- :step="1"
- @keyup.native="filterCode(item)"
- />天
- </span>
- </div>
- <div class="item">
- <span class="label">拟合时间段</span>
- <el-date-picker
- v-model="item.fit_date[0]"
- range-separator="至"
- placeholder="开始日期"
- value-format="yyyy-MM-dd"
- style="width: 90%;margin-bottom: 10px;"
- @change="changeFitDate(item)"
- />
- 至
- <el-date-picker
- v-model="item.fit_date[1]"
- placeholder="结束日期"
- value-format="yyyy-MM-dd"
- style="width: 90%"
- @change="changeFitDate(item)"
- :picker-options="{
- shortcuts: [{
- text: '至今',
- onClick(picker) {
- const date = new Date();
- picker.$et('pick',date);
- }
- }]
- }"
- />
- </div>
- </div>
- <!-- 年度值倒退 -->
- <div v-else-if="item.predict_type===16">
- <div class="item">
- <span class="label">余额分配方式</span>
- <el-select
- v-model="item.distribute_type"
- placeholder="请选择方式"
- style="width: 100%"
- @change="item.on_year=''"
- >
- <el-option label="均值法" :value="1"/>
- <el-option label="同比法" :value="2"/>
- </el-select>
- </div>
- <div class="item" v-if="item.distribute_type===2">
- <span class="label">同比年份</span>
- <el-date-picker
- v-model="item.on_year"
- type="year"
- value-format="yyyy"
- placeholder="选择年份"
- />
- </div>
- </div>
- <el-button type="text" v-if="item.predict_type===9" @click="setRingAddHandle(item,index)">设置环比增加值</el-button>
- </div>
- </el-collapse-item>
- </el-collapse>
- <div class="rules-add" @click="addRuleHandle">
- <img
- src="~@/assets/img/set_m/add_ico.png"
- alt=""
- style="width: 16px; height: 16px; margin-right: 10px"
- />
- <span>添加更多</span>
- </div>
- </div>
- </div>
- <div class="main-wrap" id="right">
- <div class="con-box" v-show="edbData.DataList">
- <div class="top-title">{{ formData.edbName }}</div>
- <chartInfo
- :edbData="edbData"
- @refreshData="refreshData"
- ref="chartInfo"
- />
- </div>
- <div class="empty-box" v-show="!edbData.DataList">
- <tableNoData text="暂无信息"/>
- </div>
- </div>
- <!-- 设置动态环差弹窗 -->
- <dynamic-differ
- :isOpenDialog.sync="isOpenDialog"
- :edbList="dynamicDifferList"
- :dialog_formula="dialog_formula"
- @ensureBack="saveDynamicDifferRule"
- @lookHistory="id => {isLookHistory=true;lookEdbId=id;}"
- />
- <!-- 指标历史记录 -->
- <edbHistoryDialog
- :isOpenDialog.sync="isLookHistory"
- :edbId="lookEdbId"
- />
-
- </div>
- </template>
- <script>
- import * as preDictEdbInterface from "@/api/modules/predictEdbApi.js";
- import { dataBaseInterface } from "@/api/api.js";
- import chartInfo from "./components/chartInfo.vue";
- import dynamicDiffer from './components/dynamicRingdiffer.vue';
- export default {
- components: { chartInfo,dynamicDiffer },
- computed: {
- // 图需要更新的依赖项
- showChart() {
- return {
- oldEdb: this.formData.oldEdb,
- };
- },
- timePickerOptions() {
- let that=this
- let obj={
- disabledDate(time) {
- if(that.formData.lasetDate){
- return time.getTime() < new Date(that.formData.lasetDate).getTime()
- }else{
- return time.getTime() < Date.now()
- }
- }
- }
- return obj
- }
- },
- watch: {
- showChart(n, o) {
- if (n.oldEdb) {
- console.log("更新");
- if (n.oldEdb != o.oldEdb) {
- this.$refs.chartInfo.chartInfo.ChartType = 1;
- }
- //this.getChartInfo();
- }
- },
- rulesArr: {
- handler(newval) {
- this.isNeedWatch && this.formData.oldEdb && this.getChartInfo();
- },
- deep: true
- }
- },
- data() {
- return {
- formData: {
- edb_id: "",
- classify: "",
- oldEdb: "",
- edbName: "",
- frequency: "",
- newdata: "",
- lasetDate: "",
- dateType: '交易日',
- },
- formRules: {
- classify: [
- { required: true, message: "分类不能为空", trigger: "blur" },
- ],
- oldEdb: [{ required: true, message: "指标不能为空", trigger: "blur" }],
- edbName: [
- { required: true, message: "指标名称不能为空", trigger: "blur" },
- ],
- },
- classifyArr: [],
- predictTypeSetting: [
- { key: 1, label: "最新" },
- { key: 2, label: "固定值" },
- { key: 3, label: "同比" },
- { key: 4, label: "同差" },
- { key: 5, label: "环比" },
- { key: 6, label: "环差" },
- { key: 7, label: "N期移动均值" },
- { key: 8, label: "N期段线性外推值" },
- { key: 9, label: '动态环差' },
- { key: 10, label: "给定终值后插值" },
- { key: 11, label: "季节性" },
- { key: 12, label: "移动平均同比" },
- { key: 13, label: "同比增速插值" },
- { key: 14, label: "一元线性拟合" },
- { key: 15, label: "N年均值" },
- { key: 16, label: "年度值倒推" },
- ], //预测规则
- predictTypeOptions:[],
- rulesTip: `预测规则说明:<br>
- 1、最新:预测值全部等于最新值;<br>
- 2、固定值:预测值默认全部等于常数值;<br>
- 3、同比:去年同期值乘同比增速得到预测值;<br>
- 4、同差:去年同期值加同比增加得到预测值;<br>
- 5、环比:上期值乘环比增速得到预测值;<br>
- 6、环差:上期值加同比增加得到预测值;<br>
- 7、N期移动均值:过去N期值的平均值;<br>
- 8、N期段线性外推值:过去N期值生成线性回归方程:Y=aX+b,将未来的期数代入得到预测值;<br>
- 9、动态环差:选择几个指标进行指标计算得到结果值作为动态环差值,预测值=上期值+动态环差值;<br>
- 10、给定终值后插值:计算最新数据和预测终值的期数差T和数据差S,环差值=S/T,预测数值=前一期数值+环差值(本期-上期);<br>
- 11、季节性:计算过去N年同期的环差(本期-上期)均值,预测值=上期值+环差均值;<br>
- 12、移动平均同比:计算过去N期平均值的同比值(本期/上期),选择同比年份,预测值=同比年份同期值*同比值;<br>
- 13、同比增速插值:计算最新数据的同比增速:(本期数值-去年同期数值)/去年同期数值*100%,输入同比增速终值,通过期数差值,计算每一期同比增速,预测值=去年同期值*(1+该期同比增速)。<br>
- 14、一元线性拟合:由指标A(自变量)和指标B(基础指标)在拟合时间段生成线性回归方程:Y=aX+b,将指标A代入该方程得到拟合指标B',拼接指标B的实际值和B'的预测值,生成预测指标;,<br>
- 15、N年均值:过去N年同期均值。过去N年可以连续或者不连续,指标数据均用线性插值补全为日度数据后计算;<br>
- 16、年度值倒推:设定年度值,余额=年度值-年初至今累计值(算法参考累计值),进行余额分配,均值法分配时保证每期数值相等(日度/周度:剩余期数=剩余自然日历天数/今年指标最新日期自然日历天数*今年至今指标数据期数;旬度/月度/季度/半年度:剩余期数=全年期数(36/12/4/2)-今年至今自然日历期数),同比法保证每期同比相等(同比增速=余额/同比年份相应日期的余额,预测值等于同比年份同期值*同比增速)`,
- labelMap: {
- 2: '固定值',
- 3: '同比增速',
- 4: '同比增加值',
- 5: '环比增速',
- 6: '环比增加值',
- 7: '期数',
- 8: '期数',
- 10: '预测终值',
- 11: '期数',
- 12: '期数',
- 13: '同比增速终值',
- 16: '年度值'
- },
- rulesArr: [{
- endDate: "",
- predict_type: 1,
- fixedValue: "",
- edbarr:[],
- season_way: 1,
- season_years: [],
- season_type: '公历',
- n_value:'',
- move_average_year: '',
- self_target: '',
- fit_date:['',this.$moment().format('YYYY-MM-DD')],
- distribute_type: 1,
- on_year: ''
- }],
- activeNames: [0],
- searchOptions: [],
- search_page: 1,
- search_have_more: false,
- current_search: "",
- edbData: {
- DataList: null,
- EdbInfo: {},
- },
- DateType: 10, //年份选择项 默认全部
- isNeedWatch: true,
- /* 动态环差弹窗 */
- isOpenDialog: false,
- dynamicDifferList: [],//依赖指标
- dialog_formula: '',
- click_rule_index: -1,
-
- select_year: '',
- edbFromType: 0,//标准指标
- /* 查看历史弹窗 */
- isLookHistory: false,
- lookEdbId: 0,
- };
- },
- created() {
- if (this.$route.path == "/editpredictEdb") {
- this.formData.edb_id = Number(this.$route.query.id);
- this.getEditInitData();
- }
- this.getClassifyOne();
- this.setRulesArr()
- },
- methods: {
- // 获取详情
- getEditInitData() {
- this.isNeedWatch = false; //控制编辑进来调用多次watch
- preDictEdbInterface
- .edbDetail({
- EdbInfoId: this.formData.edb_id,
- })
- .then((res) => {
- if (res.Ret !== 200) return;
- const {
- ClassifyId,
- EdbName,
- Frequency,
- LatestValue,
- RuleList,
- EdbInfoId,
- LatestDate,
- DataDateType
- } = res.Data;
- this.formData = {
- edb_id: EdbInfoId,
- classify: ClassifyId,
- oldEdb: res.Data.CalculateList[0].FromEdbInfoId,
- oldEdbName: res.Data.CalculateList[0].FromEdbName,
- edbName: EdbName,
- frequency: Frequency,
- newdata: LatestValue,
- lasetDate: LatestDate,
- dateType: DataDateType
- };
- this.rulesArr = RuleList.map(_ => ({
- endDate: this.$moment(_.EndDate).format('YYYY-MM-DD'),
- predict_type: _.RuleType,
- fixedValue: _.RuleType === 14
- ? JSON.parse(_.Value).MoveDay
- : _.RuleType === 16
- ? JSON.parse(_.Value).Value
- : _.Value,
- edbarr: _.RuleType === 9
- ? _.CalculateList.map(item => ({ target:item.FromEdbInfoId,tag:item.FromTag,name:item.FromEdbName,start_date: item.StartDate,end_date:item.EndDate }))
- : [],
- season_way:[11,15].includes(_.RuleType) ? JSON.parse(_.Value).YearType : '',
- season_years: [11,15].includes(_.RuleType) ? JSON.parse(_.Value).YearList.map(_ =>_.toString()) : [],
- season_type: _.RuleType === 11 ? JSON.parse(_.Value).Calendar : '',
- n_value: [11,12,15].includes(_.RuleType) ? JSON.parse(_.Value).NValue : '',
- move_average_year: _.RuleType === 12 ? JSON.parse(_.Value).Year.toString() : '',
- self_target: _.RuleType === 14 ? JSON.parse(_.Value).EdbInfoId : '',
- fit_date: _.RuleType === 14 ? [JSON.parse(_.Value).StartDate,JSON.parse(_.Value).EndDate] : [],
- distribute_type: _.RuleType === 16?JSON.parse(_.Value).Type:1,
- on_year: _.RuleType === 16?JSON.parse(_.Value).Year.toString():'',
- }))
- this.searchOptions = RuleList.map(item => ({
- EdbInfoId: item.CalculateList[0] ? item.CalculateList[0].FromEdbInfoId : '',
- EdbName: item.CalculateList[0] ? item.CalculateList[0].FromEdbName : ''
- }));
- this.edbData.EdbInfo = {
- ...res.Data,
- ChartColor: "",
- ChartStyle: "",
- ChartType: 0,
- ChartWidth: 0,
- MaxData: res.Data.MaxValue,
- MinData: res.Data.MinValue,
- EdbInfoCategoryType: 1,
- EdbInfoType: 1,
- EdbName: this.formData.edbName,
- IsAxis: 1,
- };
- });
- },
- getClassifyOne() {
- preDictEdbInterface.classifyListV2().then((res) => {
- if (res.Ret !== 200) return;
- this.classifyArr = res.Data.AllNodes || [];
- if (this.$route.path == "/editpredictEdb") {
- //将formData.classify转为数组的格式
- this.formData.classify = this.findParentNodeHandle(this.classifyArr,this.formData.classify).reverse()
- }
- });
- },
- findParentNodeHandle(arr, id) {
- // 遍历取父级code push数组
- for (let i of arr) {
- if (i.ClassifyId === id) {
- return [i.ClassifyId];
- }
- if (i.Children) {
- let node = this.findParentNodeHandle(i.Children, id);
- if (node) {
- return node.concat(i.ClassifyId);
- }
- }
- }
- },
- searchLoad() {
- if (!this.search_have_more) return;
- this.searchApi(this.current_search, ++this.search_page);
- },
- async searchApi(query, page = 1) {
- let params = {
- KeyWord: query,
- CurrentIndex: page,
- }
- const res = (this.edbFromType === 1 && this.current_type==='self_target')
- ? await preDictEdbInterface.edbSearch(params)
- : await dataBaseInterface.targetSearchByPage(params)
- if (res.Ret !== 200) return;
- const { List, Paging } = res.Data;
- this.search_have_more = page < Paging.Pages;
- this.searchOptions = page === 1 ? List : this.searchOptions.concat(List);
- },
- /* 聚焦获取当前检索 */
- inputFocusHandle(e,type='') {
- this.search_page = 1;
- this.current_search = e.target.value;
- this.current_type = type;
- this.searchApi(this.current_search);
- },
- /* 选择指标 同步名称频度最新值*/
- async selectEdbHandle(val) {
- if (val) {
- const { Data } = await dataBaseInterface.targetDetail({
- EdbInfoId: val,
- });
- this.formData.edbName = `${Data.EdbName}(预测)`;
- this.formData.frequency = Data.Frequency;
- this.formData.newdata = Data.LatestValue;
- this.formData.lasetDate = Data.LatestDate;
- this.edbData.EdbInfo = {
- ...Data,
- ChartColor: "",
- ChartStyle: "",
- ChartType: 0,
- ChartWidth: 0,
- // MaxData: Data.MaxValue,
- // MinData: Data.MinValue,
- EdbInfoCategoryType: 1,
- EdbInfoType: 1,
- EdbName: this.formData.edbName,
- IsAxis: 1
- };
- this.setRulesArr()
- this.getChartInfo()
- } else {
- this.formData.edbName = "";
- this.formData.frequency = "";
- this.formData.newdata = "";
- this.formData.lasetDate = "";
- }
- },
- /* 搜索 */
- searchHandle(query) {
- this.search_page = 1;
- this.current_search = query;
- this.searchApi(this.current_search);
- },
- // 获取图表数据
- async getChartInfo() {
- console.log(this.rulesArr)
- let rules_params = this.rulesArr.filter(_ => (
- (_.predict_type === 1 && _.endDate)
- || [11,12,15].includes(_.predict_type) && _.endDate && (_.n_value||_.season_years.length)
- || (_.predict_type===14 &&_.endDate && _.fit_date[0] && _.fit_date[1] && _.self_target)
- || ![1,11,12,14,15].includes(_.predict_type) && _.endDate && _.fixedValue
- )).map(_ =>{
- let dynamic_params = {};
- switch(_.predict_type) {
- case 11:
- case 15:
- dynamic_params = {
- Calendar: _.season_type,
- YearType: _.season_way,
- NValue: Number(_.n_value),
- YearList: _.season_years.map(_ =>Number(_)),
- }
- break
- case 12:
- dynamic_params = {
- Year: Number(_.move_average_year),
- NValue: Number(_.n_value)
- }
- break
- case 14:
- dynamic_params = {
- StartDate: _.fit_date[0],
- EndDate: _.fit_date[1],
- MoveDay: Number(_.fixedValue),
- EdbInfoId: _.self_target
- }
- break
- case 16:
- dynamic_params = {
- Type: _.distribute_type,
- Value: Number(_.fixedValue),
- Year: Number(_.on_year)
- }
- break
- }
- return {
- RuleType: _.predict_type,
- EndDate: _.endDate,
- Value: [11,12,14,15,16].includes(_.predict_type) ? JSON.stringify(dynamic_params) : _.fixedValue,
- EdbInfoIdArr: _.predict_type === 9
- ? _.edbarr.map(item => ({ EdbInfoId:item.target,FromTag:item.tag }))
- : _.predict_type === 14
- ? [{EdbInfoId: _.self_target,FromTag: ''}]
- :[]
- }
- })
- let params = {
- SourceEdbInfoId: this.formData.oldEdb,
- DateType: this.$refs.chartInfo.year_select,
- StartDate: this.$refs.chartInfo.select_date[0] || "",
- EndDate: this.$refs.chartInfo.select_date[1] || "",
- Calendar: this.$refs.chartInfo.calendar_type,
- ChartType: this.$refs.chartInfo.chartInfo.ChartType,
- SeasonStartDate: this.$refs.chartInfo.season_year[0] || "",
- SeasonEndDate: this.$refs.chartInfo.season_year[1] || "",
- DataDateType: this.formData.dateType,
- }
- const res = await preDictEdbInterface.edbChartDataForAdd(rules_params.length ? {...params,RuleList: rules_params} : params);
- if (res.Ret != 200) return;
- this.edbData.DataList = res.Data.DataList;
- this.edbData.EdbInfo.MaxData = this.edbData.EdbInfo.MaxData || res.Data.MaxValue;
- this.edbData.EdbInfo.MinData = this.edbData.EdbInfo.MinData || res.Data.MinValue;
- this.isNeedWatch = true; //控制编辑进来调用多次watch
- },
- /* 保存 */
- async saveHandle() {
-
- await this.$refs.formRef.validate();
- // 规则填写是否完整
- let isRulesComplete = this.rulesArr.every(item => {
- return item.predict_type === 1 && item.endDate
- || [11,12,15].includes(item.predict_type) && item.endDate && (item.n_value||item.season_years.length)
- || (item.predict_type===14 && item.endDate && item.fit_date[0] && item.fit_date[1] && item.self_target)
- || ![1,11,12,14,15].includes(item.predict_type) && item.endDate && item.fixedValue
- })
- if(!isRulesComplete) return this.$message.warning('请填写完整的规则')
-
- const { edb_id,classify,oldEdb,edbName,dateType } = this.formData;
- //规则参数
- let RuleList = this.rulesArr.map(_ => {
- let dynamic_params = {};
- switch(_.predict_type) {
- case 11:
- case 15:
- dynamic_params = {
- Calendar: _.season_type,
- YearType: _.season_way,
- NValue: Number(_.n_value),
- YearList: _.season_years.map(_ =>Number(_)),
- }
- break
- case 12:
- dynamic_params = {
- Year: Number(_.move_average_year),
- NValue: Number(_.n_value)
- }
- break
- case 14:
- dynamic_params = {
- StartDate: _.fit_date[0],
- EndDate: _.fit_date[1],
- MoveDay: Number(_.fixedValue),
- EdbInfoId: _.self_target
- }
- break
- case 16:
- dynamic_params = {
- Type: _.distribute_type,
- Value: Number(_.fixedValue),
- Year: Number(_.on_year)
- }
- break
- }
- return {
- RuleType: _.predict_type,
- EndDate: _.endDate,
- Value: [11,12,14,15,16].includes(_.predict_type) ? JSON.stringify(dynamic_params) : _.fixedValue,
- EdbInfoIdArr: _.predict_type === 9
- ? _.edbarr.map(item => ({ EdbInfoId:item.target,FromTag:item.tag }))
- : _.predict_type === 14
- ? [{EdbInfoId: _.self_target,FromTag: ''}]
- :[]
- }
- })
- let params = {
- ClassifyId: classify[classify.length-1],
- EdbName: edbName,
- MaxValue: Number(this.$refs.chartInfo.tableData[0].MaxData),
- MinValue: Number(this.$refs.chartInfo.tableData[0].MinData),
- DataDateType: dateType,
- RuleList
- };
- const { Ret, Data } = edb_id
- ? await preDictEdbInterface.edbEdit({ ...params, EdbInfoId: edb_id })
- : await preDictEdbInterface.edbAdd({
- ...params,
- SourceEdbInfoId: oldEdb,
- });
- if (Ret !== 200) return;
- this.$message.success("保存成功");
- //编辑的话更新图
- edb_id && this.$nextTick(() => {
- this.setChartImage();
- });
- if (!edb_id) {
- const obj = {
- code: Data.UniqueCode,
- id: Data.EdbInfoId,
- };
- sessionStorage.setItem("predictEdbTreeData", JSON.stringify(obj));
- }
- setTimeout(() => {
- this.$router.back();
- }, 1500);
- },
- /* 关联图片 */
- setChartImage() {
- let svg = this.$refs.chartInfo.$refs.chartRef.chart.getSVG({
- chart: {
- width: 340,
- height: 230,
- },
- });
- let form = new FormData();
- form.append("Img", svg);
- this.setImageHandle(form);
- },
- async setImageHandle(form) {
- let { Data } = await dataBaseInterface.uploadImgSvg(form);
- await preDictEdbInterface.setImg({
- EdbInfoId: this.formData.edb_id,
- ImageUrl: Data.ResourceUrl,
- });
- },
- refreshData() {
- this.getChartInfo();
- },
- /* 添加新规则 */
- addRuleHandle() {
- const newItem = {
- endDate: "",
- predict_type: 1,
- fixedValue: "",
- edbarr: [],
- season_way: 1,
- season_years: [],
- season_type: '公历',
- n_value: '',
- move_average_year: '',
- self_target: '',
- fit_date:['',this.$moment().format('YYYY-MM-DD')],
- distribute_type: 1
- };
- this.rulesArr.push(newItem);
- },
- /* 切换预测规则 重置value */
- initRule(e,item) {
- item.fixedValue = '';
- item.edbarr=[];
- item.season_way=1;
- item.season_years=[];
- item.season_type='公历';
- item.n_value='';
- item.move_average_year='';
- item.self_target = '';
- item.fit_date = ['',this.$moment().format('YYYY-MM-DD')];
- item.distribute_type=1;
- },
- /* 设置预测规则数组 */
- setRulesArr(){
- const {frequency} = this.formData
- let filterKey=[]
- //如果是年度,则不显示环比、环差、动态环差、季节性、移动平均同比的选项
- if(frequency==='年度'){
- filterKey = [5,6,11,12]
- }
- //this.predictTypeOptions = this.predictTypeSetting.filter(item=>{return !filterKey.includes(item.key)})
- this.predictTypeOptions = this.predictTypeSetting
- //年度指标时,将不支持的规则类型重置
- this.isNeedWatch = false
- this.rulesArr.forEach(item=>{
- if(filterKey.length&&filterKey.includes(item.predict_type)){
- this.initRule(_,item)
- item.predict_type = 1
- }
- })
- this.$nextTick(()=>{
- this.isNeedWatch=true
- })
- },
- /* 删除规则 */
- removeRuleHandle(item, index) {
- if(this.rulesArr.length===1) return this.$message.warning('请至少保留一条预测规则');
- this.rulesArr.splice(index, 1);
- this.$message.success("删除成功");
- },
- /* 选择日期时提示不能小于上个日期 */
- changeDateHandle(value,index) {
- console.log(value,index)
- let isDateRepeat = this.rulesArr.some((_,_index) => _index!==index&&this.$moment(_.endDate).valueOf()===this.$moment(value).valueOf())
- if(isDateRepeat) {
- this.rulesArr[index].endDate = '';
- return this.$message.warning('所选日期不能和其他规则重复')
-
- }
- // if(index > 0) {
- // let prev_date = this.rulesArr[index-1].endDate;
- // if(this.$moment(prev_date).valueOf() >= this.$moment(value).valueOf()){
- // this.$message.warning('所选日期不能小于上个规则的日期')
- // this.rulesArr[index].endDate = '';
- // }
- // }
- this.rulesArr[index].predict_type===16 && this.rulesArr[index].endDate && this.checkReverseYearDate(index)
- },
- // n年倒推 校验日期时同一年份
- checkReverseYearDate(index) {
- let selectDateYear = new Date(this.rulesArr[index].endDate).getFullYear();
- let prevRuleDateYear = '';
- if(this.rulesArr.length === 1) {
- prevRuleDateYear = new Date(this.formData.lasetDate).getFullYear();
- } else {
- let sortRuleArr = [...this.rulesArr].sort((x,y) => new Date(x.endDate)-new Date(y.endDate));
- let newIndex = sortRuleArr.findIndex(_ => _.endDate===this.rulesArr[index].endDate);
- prevRuleDateYear = newIndex === 0 ? new Date(this.formData.lasetDate).getFullYear() : new Date(sortRuleArr[newIndex-1].endDate).getFullYear()
- }
-
- if(selectDateYear !== prevRuleDateYear) {
- this.rulesArr[index].endDate = ''
- return this.$message.warning('年度值倒推不支持跨年预测')
- }
-
- },
- changePredictType(e,item,index) {
- e===16&&item.endDate&&this.checkReverseYearDate(index);
- this.initRule(e,item)
- },
- /* 拟合选择日期 */
- changeFitDate(item) {
- if(item.fit_date[0] && item.fit_date[1]) {
- let differ = this.$moment(item.fit_date[1]).diff(
- this.$moment(item.fit_date[0]),
- 'days',
- true
- )
- if(differ < 2) {
- item.fit_date = [];
- this.$message.warning(`${differ<0?'开始日期不能晚于结束日期':'日期间隔不得少于两天'}`)
- }
- }
- },
- /* 设置环比增加值 */
- setRingAddHandle({edbarr,fixedValue},index) {
- this.click_rule_index = index;
- this.dynamicDifferList = edbarr;
- this.dialog_formula = fixedValue;
- this.isOpenDialog = true;
- },
-
- /* 规则动态环差信息 */
- saveDynamicDifferRule({arr,formula}) {
- this.rulesArr[this.click_rule_index].edbarr = arr;
- this.rulesArr[this.click_rule_index].fixedValue = formula;
- console.log(this.rulesArr)
- },
- /* 追加年份 */
- pushYear(e,item) {
- this.select_year = '';
- if(item.season_years.includes(e)) return this.$message.warning('年份已存在')
- item.season_years.push(e)
- },
- /* 删除年份 */
- removeYear(year,item) {
- item.season_years.splice(item.season_years.findIndex(_ => _===year),1)
- },
- /*小数点*/
- filterCode(item) {
- item.fixedValue=item.fixedValue.replace('.','');
- },
- },
- };
- </script>
- <style lang="scss">
- .add-predicedb-page {
- .aside-warp {
- /* .el-form-item {
- margin-bottom: 0;
- } */
- .el-form-item__content {
- line-height: 1;
- }
- }
- .el-collapse-item__header {
- background-color: #F0F2F5;
- margin-bottom: 0;
- border-bottom: 1px solid #dcdfe6;
- padding: 0 30px;
- .el-collapse-item__arrow {
- position: absolute;
- left: 8px;
- }
- }
- .el-collapse-item__content {
- padding-bottom: 10px;
- }
- .el-collapse-item.is-disabled .el-collapse-item__header {
- color: #333;
- }
- }
- </style>
- <style lang="scss" scoped>
- div {
- box-sizing: border-box;
- }
- .add-predicedb-page {
- display: flex;
- min-height: calc(100vh - 150px);
- .aside-warp {
- flex-shrink: 0;
- width: 300px;
- background: #ffffff;
- border-radius: 4px;
- border: 1px solid #ececec;
- margin-right: 20px;
- .btn-box {
- height: 80px;
- background: #ffffff;
- box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.06);
- border-radius: 4px 4px 0px 0px;
- opacity: 1;
- border-bottom: 1px solid #ececec;
- padding-top: 20px;
- padding-left: 15px;
- }
- .con {
- padding: 20px;
- max-height: calc(100vh - 200px);
- overflow-y: auto;
- .item {
- margin-bottom: 20px;
- font-size: 14px;
- .label {
- margin-bottom: 10px;
- display: block;
- }
- .season-year-cont {
- padding: 10px;
- margin-top: 15px;
- border: 1px dashed #AAB4CC;
- }
- }
- .tip-wrap {
- color: #999;
- margin-top: 30px;
- }
- }
- }
- .main-wrap {
- flex: 1;
- width: 80%;
- background: #ffffff;
- border-radius: 4px;
- border: 1px solid #ececec;
- }
- .rules-ul {
- border: 1px solid #dcdfe6;
- .del-icon {
- position: absolute;
- right: 10px;
- font-size: 16px;
- color: #f00;
- cursor: pointer;
- }
- .wrap {
- padding: 20px 20px 0;
- li {
- padding-bottom: 20px;
- margin-bottom: 20px;
- border-bottom: 1px solid #dcdfe6;
- &:last-child {
- padding-bottom: 0;
- margin-bottom: 0;
- border-bottom: none;
- }
- }
- }
- }
- .rules-add {
- margin-top: 10px;
- display: flex;
- align-items: center;
- color: #409eff;
- color: pointer;
- }
- }
- .main-wrap {
- .empty-box {
- padding-top: 200px;
- color: #aab4cc;
- text-align: center;
- img {
- width: 150px;
- }
- }
- .con-box {
- .top-title {
- height: 80px;
- background: #ffffff;
- box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.06);
- border-radius: 4px 4px 0px 0px;
- border-bottom: 1px solid #ececec;
- font-size: 18px;
- display: flex;
- padding-left: 30px;
- align-items: center;
- }
- }
- }
- </style>
|