zhangwenya 8 месяцев назад
Родитель
Сommit
72ff07f6ec

+ 1 - 1
src/views/index/widget/runTendency.vue

@@ -17,7 +17,7 @@
         </div>
       </div>
       <div class="chart-sort">
-        {{trendData[active]?.objName || "-"}}
+        {{trendData[active].objName || "-"}}
         <div ref="chartSort" style="height: 218px;" />
       </div>
     </div>

+ 3 - 3
src/views/obj/obj/component/metricsConfig.vue

@@ -1,13 +1,13 @@
 <template>
   <el-form ref="mcRef" :model="form" :rules="rules" label-width="120px" label-suffix=":">
     <el-form-item label="指标名称">
-      {{form?.metricsName || '-'}}
+      {{form.metricsName || '-'}}
     </el-form-item>
     <el-form-item label="指标类型">
-      {{form?.metricsType || '-'}}
+      {{form.metricsType || '-'}}
     </el-form-item>
     <el-form-item label="指标编码">
-      {{form?.metricsCode || '-'}}
+      {{form.metricsCode || '-'}}
     </el-form-item>
     <el-form-item label="数据接口配置">
       <el-input type="textarea" placeholder="请输入数据接口配置" v-model="form.dataExp" show-word-limit maxlength="900" :autosize="{ minRows: 4, maxRows: 6 }" />

+ 14 - 4
src/views/risk/r2/components/addModel.vue

@@ -12,10 +12,14 @@
         异类分析
       </el-form-item>
       <el-form-item label="定时分析" prop="timeSwitch" required>
-        <el-radio-group v-model="form.timeSwitch">
-          <el-radio label="Y">开启</el-radio>
-          <el-radio label="N">关闭</el-radio>
-        </el-radio-group>
+        <el-select v-model="form.timeSwitch" placeholder="请选择是否定时分析">
+          <el-option
+              v-for="dict in sys_yes_no"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+          />
+        </el-select>
       </el-form-item>
       <el-form-item label="指标对象" prop="objType" required>
         <el-select v-model="form.objType" filterable placeholder="请选择..." style="width: 240px"
@@ -43,6 +47,12 @@ import {addModel, updateModel} from "@/api/risk/model"
 
 const objRef = ref(null)
 const {proxy} = getCurrentInstance()
+const {
+  analy_result,
+  risk_up,
+  sys_yes_no,
+  risk_type
+} = proxy.useDict('risk_type', 'analy_result', 'risk_up', 'sys_yes_no');
 const emit = defineEmits(["cancel", "success"])
 const treeRef = ref(null)
 const riskIds = ref(null)

+ 183 - 0
src/views/risk/r3/components/addHz.vue

@@ -0,0 +1,183 @@
+<template>
+  <div>
+    <el-form ref="objRef" :model="form" :rules="rules" label-width="120px" label-suffix=":" size="small">
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="指标" prop="metricsId">
+            <el-select v-model="form.metricsId" filterable placeholder="请输入..." style="width: 100%"
+                       @change="changeMetricsId">
+              <el-option v-for="item in metricsData" :key="item.metricsId" :label="item.metricsName"
+                         :value="item.metricsId"/>
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="分析类型" prop="riskType">
+            <el-select v-model="form.riskType" disabled placeholder="请选择分析类型" clearable style="width: 100%">
+              <el-option
+                  v-for="dict in risk_type"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="趋势恶化方向" prop="upDown">
+            <el-select v-model="form.upDown" placeholder="请选择分析类型" clearable style="width: 100%">
+              <el-option
+                  v-for="dict in risk_up"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="置信区间" required>
+            <el-input-number v-model="form.confidenceLevel" :min="95" :max="99" />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="定时分析" required>
+            <el-select v-model="form.timeSwitch" placeholder="请选择是否定时分析">
+              <el-option
+                  v-for="dict in sys_yes_no"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="指标对象" prop="objType" required>
+            <el-select v-model="form.objType" filterable placeholder="请选择..." style="width: 240px"
+                       :disabled="!form.metricsId" @change="changeObjType">
+              <el-option v-for="item in [{key:'1',label:'全部'},{key:'2',label:'自定义'}]" :key="item.key"
+                         :label="item.label" :value="item.key"/>
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="24" v-if="form.objType === '2'">
+          <el-form-item label="">
+            <div class="tree-row" >
+              <el-tree style="max-width: 600px" :props="props" :data="modelTreeData" show-checkbox ref="treeRef"
+                       node-key="objId"
+                       @check-change="handleCheckChange"/>
+            </div>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+    <div class="btn-row">
+      <el-button type="primary" @click="submitForm">提交</el-button>
+      <el-button @click="emit('cancel')">取消</el-button>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import {onMounted, reactive} from "vue";
+import {listModelMs, listModelObj} from "@/api/risk/r2";
+import {addModel, updateModel} from "@/api/risk/model"
+
+const objRef = ref(null)
+const {proxy} = getCurrentInstance()
+const {
+  analy_result,
+  risk_up,
+  sys_yes_no,
+  risk_type
+} = proxy.useDict('risk_type', 'analy_result', 'risk_up', 'sys_yes_no');
+const emit = defineEmits(["cancel", "success"])
+const treeRef = ref(null)
+const riskIds = ref(null)
+const treeIndex = ref([])
+const data = reactive({
+  form: {
+    metricsName: "",
+    riskType: "1",
+    upDown:"",
+    metricsId: null,
+    objType: "1",
+    timeSwitch:"Y",
+    confidenceLevel:95,
+    objIds: []
+  },
+  rules: {
+    metricsId: {required: true, message: "请选择指标"},
+    riskType: {required: true, message: "请选择分析类型"},
+    upDown: {required: true, message: "请选择趋势恶化方向"},
+  }
+})
+const metricsData = ref([])
+const modelTreeData = ref([])
+const {form, rules} = toRefs(data)
+
+const props = {
+  label: 'objName',
+}
+
+function handleCheckChange(data, checked) {
+  form.value.objIds = checked ? [...form.value.objIds, data.objId] : form.value.objIds.filter(item => item !== data.objId)
+}
+
+function changeMetricsId(id) {
+  form.value.metricsName = metricsData.value.find(item => item.metricsId === id).metricsName
+  changeObjType(form.value.objType)
+}
+
+async function changeObjType(val) {
+  if (val === "2") {
+    form.value.objIds = []
+    const res = await listModelObj(form.value.metricsId)
+    modelTreeData.value = res.data
+  } else {
+    form.value.objIds = []
+  }
+}
+
+onMounted(async () => {
+  const res = await listModelMs()
+  metricsData.value = res.data
+})
+
+async function submitForm() {
+  objRef.value.validate(async valid => {
+    if (valid) {
+      const res = riskIds.value ? await updateModel({...form.value, riskId: riskIds.value}) : await addModel(form.value)
+      proxy.$message.success(res.msg)
+      emit('success')
+    }
+  })
+}
+
+async function editInfo(row) {
+  treeIndex.value = []
+  const {metricsName, riskType,upDown, timeSwitch, metricsId, objType, riskId,confidenceLevel} = row
+  form.value = {metricsName, riskType, upDown,timeSwitch, metricsId, objType, confidenceLevel,objIds:[]}
+  riskIds.value = riskId
+  await changeObjType(objType)
+  treeRef.value!.setCheckedNodes(row.riskObjList)
+}
+
+defineExpose({editInfo})
+
+</script>
+<style scoped lang="scss">
+.tree-row {
+  width: 100%;
+  border: 1px solid #f1f1f1;
+  padding: 5px;
+}
+
+.btn-row {
+  display: flex;
+  justify-content: center;
+  margin: 0px -20px 0 -20px;
+  padding-top: 20px;
+  border-top: 1px solid #f1f1f1;
+}
+</style>

+ 17 - 2
src/views/risk/r3/components/historyAnalyse.vue

@@ -17,9 +17,9 @@
         <el-tag v-else >{{scope.row.result}}</el-tag>
       </template>
     </el-table-column>
-    <el-table-column label="操作" width="120" align="center">
+    <el-table-column label="操作" width="100">
       <template #default="scope">
-        <el-button type="primary" link icon="edit">查看</el-button>
+        <el-button type="primary" link @click="checkAnalyse(scope.row)">查看</el-button>
       </template>
     </el-table-column>
   </el-table>
@@ -34,10 +34,15 @@
       @pagination="getAnalysis"
   />
 
+  <el-dialog v-model="visible" title="分析结果" width="800">
+    <now-analyse :rows="rows"/>
+  </el-dialog>
+
 </template>
 <script setup lang="ts">
 import {listAnalysis} from "@/api/risk/r3"
 import {onMounted} from "vue";
+import nowAnalyse from "./nowAnalyse.vue"
 const params = ref({
   riskType:1,
   metricsName:"",
@@ -45,9 +50,11 @@ const params = ref({
   pageNum:1,
   pageSize:10
 })
+const visible = ref(false)
 const analysisList = ref([])
 const total = ref(0)
 const loading = ref(true)
+const rows = ref({})
 
 onMounted(()=>{
   getAnalysis()
@@ -61,4 +68,12 @@ async function getAnalysis(){
   loading.value = false
 }
 
+function checkAnalyse(row){
+  rows.value = row
+  visible.value = true
+}
+
+
+defineExpose({getAnalysis})
+
 </script>

+ 78 - 13
src/views/risk/r3/components/hzAnalyse.vue

@@ -1,8 +1,9 @@
 <template>
   <el-row :gutter="20">
     <el-col :span="18">
-      <el-input v-model="params.metricsName" placeholder="请输入指标名称" style="width: 200px;margin-right: 10px" size="small"/>
-      <el-button type="primary" icon="Search" @click="getAnalysis" size="small">搜索</el-button>
+      <el-input v-model="params.metricsName" placeholder="请输入指标名称" style="width: 200px;margin-right: 10px"
+                size="small"/>
+      <el-button type="primary" icon="Search" @click="getModelList" size="small">搜索</el-button>
     </el-col>
     <el-col :span="6" style="text-align: right">
       <el-button type="primary" icon="Plus" @click="addModel" size="small">新增</el-button>
@@ -10,10 +11,10 @@
   </el-row>
   <el-table v-loading="loading" :data="modelList" border width="100%" size="small" style="margin-top:10px">
     <el-table-column label="#" type="index" width="80" align="center"/>
-    <el-table-column label="指标名称" prop="metricsName" />
-    <el-table-column label="运行业务对象"  width="250">
+    <el-table-column label="指标名称" prop="metricsName"/>
+    <el-table-column label="运行业务对象" width="250">
       <template #default="scope">
-        <span v-for="(item,index) in scope.row.riskObjList" :key="item.objId">{{item.objName}}
+        <span v-for="(item,index) in scope.row.riskObjList" :key="item.objId">{{ item.objName }}
           <span v-if="index != scope.row.riskObjList.length-1">,</span>
         </span>
       </template>
@@ -33,32 +34,96 @@
         <dict-tag :options="risk_up" :value="scope.row.upDown"/>
       </template>
     </el-table-column>
+    <el-table-column label="操作" width="180">
+      <template #default="scope">
+        <el-link type="primary" :underline="false" @click="handleEdit(scope.row)" class="link-text">编辑</el-link>
+        <el-link type="primary" :underline="false" @click="handleNowAnalyse(scope.row)" class="link-text">立即分析
+        </el-link>
+        <el-popconfirm title="确认要删除该条信息吗?" @confirm="handleDelete(scope.row)" width="200">
+          <template #reference>
+            <el-link type="danger" :underline="false" class="link-text">删除</el-link>
+          </template>
+        </el-popconfirm>
+      </template>
+    </el-table-column>
   </el-table>
+  <pagination
+      style="margin-top:10px"
+      v-show="total>0"
+      layout="prev, pager, next"
+      :total="total"
+      :background="false"
+      v-model:page="params.pageNum"
+      v-model:limit="params.pageSize"
+      @pagination="getModelList"
+  />
+
+  <el-dialog v-model="visible" :title="dialogInfo[active].title" width="50%" :close-on-click-modal="false">
+    <component :is="dialogInfo[active].component" @success="getModelList" v-if="visible" @cancel="visible=false"
+               ref="acRef" :rows="rows"/>
+  </el-dialog>
 </template>
 <script setup lang="ts">
 import {listModel} from "@/api/risk/r3"
+import {delModel} from "@/api/risk/model"
 import {onMounted} from "vue";
+import addHz from "./addHz.vue"
+import {analysisAtOnce} from "@/api/risk/r2"
+
 const {proxy} = getCurrentInstance()
-const { analy_result ,risk_up,sys_yes_no} = proxy.useDict('analy_result','risk_up','sys_yes_no');
+const emit = defineEmits(["success"])
+const {analy_result, risk_up, sys_yes_no} = proxy.useDict('analy_result', 'risk_up', 'sys_yes_no');
 const params = ref({
-  riskType:1,
-  metricsName:"",
-  pageNum:1,
-  pageSize:10
+  riskType: 1,
+  metricsName: "",
+  pageNum: 1,
+  pageSize: 10
 })
+const visible = ref(false)
+const dialogInfo = [
+  {title: "新增指标", component: addHz},
+  {title: "编辑指标", component: addHz},
+]
+const active = ref(0)
 const total = ref(0)
 const modelList = ref([])
 const loading = ref(true)
+const acRef = ref(null)
+const rows = ref({})
 
-onMounted(()=>{
+onMounted(() => {
   getModelList()
 })
 
-function addModel(){
+async function handleNowAnalyse(row) {
+  loading.value = true
+  const res = await analysisAtOnce(row.riskId)
+  loading.value = false
+  proxy.$message.success(res.msg)
+  emit("success")
+}
+
+function addModel() {
+  visible.value = true
+  active.value = 0
+}
+
+async function handleDelete(row) {
+  const res = await delModel(row.riskId)
+  proxy.$message.success(res.msg)
+  await getModelList()
+}
 
+function handleEdit(row) {
+  visible.value = true
+  active.value = 1
+  proxy.$nextTick(() => {
+    acRef.value.editInfo(row)
+  })
 }
 
-async function getModelList(){
+async function getModelList() {
+  visible.value = false
   loading.value = true
   const res = await listModel(params.value)
   modelList.value = res.rows

+ 119 - 0
src/views/risk/r3/components/nowAnalyse.vue

@@ -0,0 +1,119 @@
+<template>
+  <div class="risk-detail">
+    <div class="risk-row">
+      <el-form ref="objRef" label-width="80px" label-suffix=":" size="small">
+        <el-form-item label="数据有效性">
+          <el-row :gutter="20">
+            <el-col :span="24">
+              <el-tag effect="light" :type="rows.normalValid === '通过'?'success':'info'">正态检测: {{ rows.normalValid }}</el-tag>
+            </el-col>
+            <el-col :span="24">
+              <el-tag effect="light" :type="rows.varianceValid === '通过'?'success':'info'">方差齐性检测: {{ rows.varianceValid }}
+              </el-tag>
+            </el-col>
+          </el-row>
+        </el-form-item>
+        <el-form-item label="结果">
+          <el-tag v-if="rows.result=='趋势恶化'" type="danger">{{rows.result}}</el-tag>
+          <el-tag v-else >{{rows.result}}</el-tag>
+        </el-form-item>
+        <el-form-item label="置信区间">
+          {{ rows.confidenceLevel }}
+        </el-form-item>
+        <el-form-item label="p值">
+          {{ rows.pvalue }}
+        </el-form-item>
+      </el-form>
+      <div>
+        <div class="top-title">均值比较</div>
+        <el-image style="width: 400px" :src="rows.imgPath" fit="scale-down"/>
+      </div>
+    </div>
+  </div>
+  <div class="chart-row" v-if="activeTop">
+    <div ref="chartTop" style="height: 300px;"/>
+  </div>
+</template>
+<script setup lang="ts">
+import {parseTime} from "@/utils/ruoyi"
+import {analysisAtOnce, analysisTypeTrend} from "@/api/risk/r2"
+import {watchEffect} from "vue";
+import * as echarts from "echarts";
+
+const chartTop = ref(null)
+const maxNum = ref(0)
+const props = defineProps(['rows'])
+const analysisData = ref({})
+const colors = ['#f56c6c', '#e6a23c', '#409EFF']
+const activeTop = ref(null)
+watchEffect(() => {
+  // getAnalysisData()
+})
+
+async function getAnalysisData() {
+  const res = await analysisAtOnce(props.rows.riskId)
+  analysisData.value = res.data
+  maxNum.value = Math.max(...analysisData.value.top.map(item => item.num)) + 20
+}
+
+async function initChart(item) {
+  activeTop.value = item
+  const {data} = await analysisTypeTrend(item.id)
+  const myChart = echarts.init(chartTop.value);
+  const option = {
+    tooltip: {
+      trigger: 'axis'
+    },
+    grid: {
+      left: '0%',
+      right: '0%',
+      bottom: '3%',
+      top: '15%',
+      containLabel: true
+    },
+    xAxis: {
+      type: 'category',
+      boundaryGap: false,
+      data: data.times.map(item => parseTime(item, '{y}-{m}-{d} {h}:{i}:{s}')),
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: "#9FB9E7",
+          width: 0,
+        }
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: {
+      type: 'value',
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: "#9FB9E7",
+          width: 0,
+        }
+      },
+      splitLine: {
+        lineStyle: {
+          color: "#6B8AC080",
+          type: 'dashed',
+        }
+      },
+    },
+    series: {
+      type: 'line',
+      stack: 'Total',
+      smooth: true,
+      symbolSize: 0,
+      data: data.values
+    }
+  };
+  myChart.setOption(option)
+}
+
+</script>
+<style lang="scss">
+@import "../../r2/css/style.scss";
+</style>

+ 5 - 0
src/views/risk/r3/css/style.scss

@@ -15,4 +15,9 @@
   .el-card__header{
     padding:5px 5px 5px !important;
   }
+  .link-text{
+    margin-right:10px;
+    font-size: 12px;
+  }
 }
+

+ 6 - 2
src/views/risk/r3/index.vue

@@ -2,18 +2,22 @@
   <div class="app-container state-err">
     <el-card class="state-row">
       <template #header>成史分析</template>
-      <history-analyse/>
+      <history-analyse ref="haRef"/>
     </el-card>
 
     <el-card class="state-row">
       <template #header>频次分析指标</template>
-      <hz-analyse/>
+      <hz-analyse @success="handleReload"/>
     </el-card>
   </div>
 </template>
 <script setup lang="ts">
 import historyAnalyse from "./components/historyAnalyse.vue"
 import hzAnalyse from "./components/hzAnalyse.vue"
+const haRef = ref(null)
+function handleReload(){
+  haRef.value.getAnalysis()
+}
 </script>
 <style lang="scss">
 @import "./css/style.scss";