|
@@ -1,648 +1,649 @@
|
|
|
<template>
|
|
|
- <!-- 招商 - littlegreen - 补充form和label -->
|
|
|
- <div
|
|
|
- :class="className"
|
|
|
- :style="{ height: '100%', width: width, padding: '20px' }"
|
|
|
- >
|
|
|
- <div class="select-container">
|
|
|
- <el-form
|
|
|
- :model="form"
|
|
|
- :rules="rules"
|
|
|
- ref="ruleForm"
|
|
|
- style="
|
|
|
- display: grid;
|
|
|
- grid-template-columns: 1fr 1fr;
|
|
|
- align-items: center;
|
|
|
- grid-gap: 20px;
|
|
|
- "
|
|
|
- >
|
|
|
- <el-form-item
|
|
|
- label="新增企业月均工业产值"
|
|
|
- label-width="200px"
|
|
|
- prop="newMonthValue"
|
|
|
+ <!-- 招商 - littlegreen - 补充form和label -->
|
|
|
+ <div
|
|
|
+ :class="className"
|
|
|
+ :style="{ height: '100%', width: width, padding: '20px' }"
|
|
|
+ >
|
|
|
+ <div class="select-container">
|
|
|
+ <el-form
|
|
|
+ :model="form"
|
|
|
+ :rules="rules"
|
|
|
+ ref="ruleForm"
|
|
|
+ style="
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
+ align-items: center;
|
|
|
+ grid-gap: 5px;
|
|
|
+ "
|
|
|
>
|
|
|
- <div style="display: flex; align-items: cente">
|
|
|
- <el-input
|
|
|
- v-model.number="form.newMonthValue"
|
|
|
- placeholder="请输入企业月均工业产值"
|
|
|
- clearable
|
|
|
- />
|
|
|
- <p style="flex: 0 0 auto; margin: 0 10px">万元</p>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="行业代码" label-width="100px" prop="selectedCode">
|
|
|
- <el-select v-model="form.selectedCode" style="width: 100%" filterable>
|
|
|
- <el-option
|
|
|
- v-for="item in selectedIndustryArray"
|
|
|
- :key="item.key"
|
|
|
- :label="item.value"
|
|
|
- :value="item.key"
|
|
|
- >
|
|
|
- </el-option> </el-select
|
|
|
- ></el-form-item>
|
|
|
- <el-form-item
|
|
|
- label="新增企业年实缴税金"
|
|
|
- label-width="200px"
|
|
|
- prop="newYearTax"
|
|
|
- >
|
|
|
- <!-- <el-input
|
|
|
- v-model="form.newYearTax"
|
|
|
- placeholder="请输入企业年实缴税金"
|
|
|
- clearable
|
|
|
- /> -->
|
|
|
- <div style="display: flex; align-items: center">
|
|
|
- <el-input
|
|
|
- v-model.number="form.newYearTax"
|
|
|
+ <el-form-item
|
|
|
+ label="新增企业年工业产值"
|
|
|
+ label-width="200px"
|
|
|
+ prop="newMonthValue"
|
|
|
+ >
|
|
|
+ <div style="display: flex; align-items: cente">
|
|
|
+ <el-input
|
|
|
+ v-model.number="form.newMonthValue"
|
|
|
+ placeholder="请输入企业年工业产值"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ <p style="flex: 0 0 auto; margin: 0 10px">万元</p>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="行业代码" label-width="100px" prop="selectedCode">
|
|
|
+ <el-select v-model="form.selectedCode" style="width: 100%" filterable>
|
|
|
+ <el-option
|
|
|
+ v-for="item in selectedIndustryArray"
|
|
|
+ :key="item.key"
|
|
|
+ :label="item.value"
|
|
|
+ :value="item.key"
|
|
|
+ >
|
|
|
+ </el-option> </el-select
|
|
|
+ ></el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ label="新增企业年实缴税金"
|
|
|
+ label-width="200px"
|
|
|
+ prop="newYearTax"
|
|
|
+ >
|
|
|
+ <!-- <el-input
|
|
|
+ v-model="form.newYearTax"
|
|
|
placeholder="请输入企业年实缴税金"
|
|
|
clearable
|
|
|
- />
|
|
|
- <p style="flex: 0 0 auto; margin: 0 10px">万元</p>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="年度" style="margin-bottom: 0" label-width="100px" prop="selectedYear">
|
|
|
- <el-select v-model="form.selectedYear" style="width: 100%">
|
|
|
- <el-option
|
|
|
- v-for="item in selectedYearArray"
|
|
|
- :key="item.key"
|
|
|
- :label="item.value"
|
|
|
- :value="item.key"
|
|
|
+ /> -->
|
|
|
+ <div style="display: flex; align-items: center">
|
|
|
+ <el-input
|
|
|
+ v-model.number="form.newYearTax"
|
|
|
+ placeholder="请输入企业年实缴税金"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ <p style="flex: 0 0 auto; margin: 0 10px">万元</p>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="年度" label-width="100px" prop="selectedYear">
|
|
|
+ <el-select v-model="form.selectedYear" style="width: 100%">
|
|
|
+ <el-option
|
|
|
+ v-for="item in selectedYearArray"
|
|
|
+ :key="item.key"
|
|
|
+ :label="item.value"
|
|
|
+ :value="item.key"
|
|
|
+ >
|
|
|
+ </el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label-width="100px" style="margin-top: 20px;">
|
|
|
+ <el-button type="primary" size="mini" @click="submit">计算</el-button>
|
|
|
+ <el-button icon="el-icon-refresh" size="mini" @click="resetForm"
|
|
|
+ >重置</el-button
|
|
|
>
|
|
|
- </el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label-width="100px">
|
|
|
- <el-button type="primary" size="mini" @click="submit">计算</el-button>
|
|
|
- <el-button icon="el-icon-refresh" size="mini" @click="resetForm"
|
|
|
- >重置</el-button
|
|
|
- >
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <h4 v-show="calShow == 'low'" style="padding: 10px; text-align: center">
|
|
|
- 重新计算后输出:企业新增后比新增前行业得分平均降低{{ rate }}%
|
|
|
- </h4>
|
|
|
- <h4 v-show="calShow == 'high'" style="padding: 10px; text-align: center">
|
|
|
- 重新计算后输出:企业新增后比新增前行业得分平均提高{{ rate }}%
|
|
|
- </h4>
|
|
|
- <h4 v-show="calShow == 'same'" style="padding: 10px; text-align: center">
|
|
|
- 重新计算后输出:企业新增后与新增前行业得分平均一致
|
|
|
- </h4>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <h4 v-show="calShow == 'low'" style="padding: 10px; text-align: center">
|
|
|
+ 重新计算后输出:企业新增后比新增前行业得分平均降低{{ rate }}%
|
|
|
+ </h4>
|
|
|
+ <h4 v-show="calShow == 'high'" style="padding: 10px; text-align: center">
|
|
|
+ 重新计算后输出:企业新增后比新增前行业得分平均提高{{ rate }}%
|
|
|
+ </h4>
|
|
|
+ <h4 v-show="calShow == 'same'" style="padding: 10px; text-align: center">
|
|
|
+ 重新计算后输出:企业新增后与新增前行业得分平均一致
|
|
|
+ </h4>
|
|
|
+ </div>
|
|
|
+ <div ref="chart" :style="{ height: height, width: width }"></div>
|
|
|
+ <el-table :data="tableData" border style="width: 100%">
|
|
|
+ <el-table-column prop="year" label="年度" width="200"> </el-table-column>
|
|
|
+ <el-table-column prop="enterpriseId" label="企业ID"></el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ prop="totalIndustrialValue"
|
|
|
+ label="企业月均工业产值"
|
|
|
+ width="200"
|
|
|
+ ></el-table-column>
|
|
|
+ <el-table-column
|
|
|
+ prop="value"
|
|
|
+ label="Z-score得分"
|
|
|
+ width="200"
|
|
|
+ ></el-table-column>
|
|
|
+ </el-table>
|
|
|
</div>
|
|
|
- <div ref="chart" :style="{ height: height, width: width }"></div>
|
|
|
- <el-table :data="tableData" border style="width: 100%">
|
|
|
- <el-table-column prop="year" label="年度" width="200"> </el-table-column>
|
|
|
- <el-table-column prop="enterpriseId" label="企业ID"></el-table-column>
|
|
|
- <el-table-column
|
|
|
- prop="totalIndustrialValue"
|
|
|
- label="企业月均工业产值"
|
|
|
- width="200"
|
|
|
- ></el-table-column>
|
|
|
- <el-table-column
|
|
|
- prop="value"
|
|
|
- label="Z-score得分"
|
|
|
- width="200"
|
|
|
- ></el-table-column>
|
|
|
- </el-table>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script>
|
|
|
-import * as echarts from "echarts";
|
|
|
-import { listAllIndustry } from "@/api/industry/industry"; // 导入行业数据的接口
|
|
|
-import { listAllIndustry_run } from "@/api/industry_run/industry_run"; // 导入行业数据的接口
|
|
|
-require("echarts/theme/macarons"); // echarts theme
|
|
|
-import resize from "@/views/dashboard/mixins/resize";
|
|
|
-import { Decimal } from "decimal.js";
|
|
|
-import { getIndexData } from "@/api/home";
|
|
|
-
|
|
|
-export default {
|
|
|
- mixins: [resize],
|
|
|
- props: {
|
|
|
- className: {
|
|
|
- type: String,
|
|
|
- default: "chart",
|
|
|
- },
|
|
|
- width: {
|
|
|
- type: String,
|
|
|
- default: "100%",
|
|
|
- },
|
|
|
- height: {
|
|
|
- type: String,
|
|
|
- default: "400px",
|
|
|
- },
|
|
|
- },
|
|
|
- data() {
|
|
|
- return {
|
|
|
- selectedYearArray: [],
|
|
|
- calShow: "init",
|
|
|
- rate: null,
|
|
|
- chart: null,
|
|
|
- chartData: [],
|
|
|
- industryData: [],
|
|
|
- industryMap: new Map(),
|
|
|
- selectedDataKey: "totalIndustrialValueScore", // 默认选择的字段
|
|
|
- form: {
|
|
|
- selectedCode: null,
|
|
|
- newMonthValue: null,
|
|
|
- newYearTax: null,
|
|
|
- selectedYear: null
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <script>
|
|
|
+ import * as echarts from "echarts";
|
|
|
+ import { listAllIndustry } from "@/api/industry/industry"; // 导入行业数据的接口
|
|
|
+ import { listAllIndustry_run } from "@/api/industry_run/industry_run"; // 导入行业数据的接口
|
|
|
+ require("echarts/theme/macarons"); // echarts theme
|
|
|
+ import resize from "@/views/dashboard/mixins/resize";
|
|
|
+ import { Decimal } from "decimal.js";
|
|
|
+ import { getIndexData } from "@/api/home";
|
|
|
+
|
|
|
+ export default {
|
|
|
+ mixins: [resize],
|
|
|
+ props: {
|
|
|
+ className: {
|
|
|
+ type: String,
|
|
|
+ default: "chart",
|
|
|
},
|
|
|
- rules: {
|
|
|
- selectedCode: [
|
|
|
- { required: true, message: "请选择行业", trigger: "blur" },
|
|
|
- ],
|
|
|
- newMonthValue: [
|
|
|
- {
|
|
|
- required: true,
|
|
|
- message: "请输入企业月均工业产值",
|
|
|
- trigger: "blur",
|
|
|
- },
|
|
|
- { type: "number", message: "企业月均工业产值必须为数字" },
|
|
|
- ],
|
|
|
- newYearTax: [
|
|
|
- {
|
|
|
- type: "number",
|
|
|
- message: "企业年实缴税金必须为数字",
|
|
|
- trigger: "blur",
|
|
|
- },
|
|
|
- ],
|
|
|
- selectedYear: [
|
|
|
- { required: true, message: "请选择年度", trigger: "blur" },
|
|
|
- ]
|
|
|
+ width: {
|
|
|
+ type: String,
|
|
|
+ default: "100%",
|
|
|
+ },
|
|
|
+ height: {
|
|
|
+ type: String,
|
|
|
+ default: "400px",
|
|
|
},
|
|
|
- selectedIndustryArray: [],
|
|
|
- selectedYear: null,
|
|
|
- selectedRange: 0.1, // 不能为 0, - littlegreen - 固定0.1
|
|
|
- // littlegreen - 检测区间 和 表格数据
|
|
|
- detectMin: null,
|
|
|
- detectMax: null,
|
|
|
- tableData: [],
|
|
|
- scoreData: [],
|
|
|
- };
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- this.$nextTick(() => {
|
|
|
- this.fetchData();
|
|
|
- });
|
|
|
- },
|
|
|
- beforeDestroy() {
|
|
|
- if (this.chart) {
|
|
|
- this.chart.dispose();
|
|
|
- }
|
|
|
- },
|
|
|
- methods: {
|
|
|
- // 拉取初始数据
|
|
|
- async fetchData() {
|
|
|
- const that = this;
|
|
|
- // 获得所有行业
|
|
|
- // that.selectedYear = new Date().getUTCFullYear() + "";
|
|
|
- await listAllIndustry()
|
|
|
- .then((res) => {
|
|
|
- if (res && res?.rows) {
|
|
|
- that.selectedIndustryArray = res.rows.map((item) => {
|
|
|
- return {
|
|
|
- key: item.code,
|
|
|
- value: item.code + item.industryName,
|
|
|
- };
|
|
|
- });
|
|
|
- }
|
|
|
- })
|
|
|
- .catch((error) => {
|
|
|
- console.error("Error fetching data:", error);
|
|
|
- });
|
|
|
-
|
|
|
- await getIndexData({
|
|
|
- year: 0,
|
|
|
- })
|
|
|
- .then((res) => {
|
|
|
- if (res && res?.rows) {
|
|
|
- that.selectedYearArray = res.rows[0].years.map((v) => {
|
|
|
- return {
|
|
|
- key: v,
|
|
|
- value: v,
|
|
|
- };
|
|
|
- });
|
|
|
- }
|
|
|
- })
|
|
|
- .catch((error) => {
|
|
|
- console.error("Error fetching data:", error);
|
|
|
- });
|
|
|
},
|
|
|
- // 提交表单
|
|
|
- submit() {
|
|
|
- this.$refs.ruleForm.validate((valid) => {
|
|
|
- if (valid) {
|
|
|
- this.handleData();
|
|
|
- } else {
|
|
|
- console.error("error submit!!");
|
|
|
- return false;
|
|
|
- }
|
|
|
- });
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ selectedYearArray: [],
|
|
|
+ calShow: "init",
|
|
|
+ rate: null,
|
|
|
+ chart: null,
|
|
|
+ chartData: [],
|
|
|
+ industryData: [],
|
|
|
+ industryMap: new Map(),
|
|
|
+ selectedDataKey: "totalIndustrialValueScore", // 默认选择的字段
|
|
|
+ form: {
|
|
|
+ selectedCode: null,
|
|
|
+ newMonthValue: null,
|
|
|
+ newYearTax: null,
|
|
|
+ selectedYear: null
|
|
|
+ },
|
|
|
+ rules: {
|
|
|
+ selectedCode: [
|
|
|
+ { required: true, message: "请选择行业", trigger: "blur" },
|
|
|
+ ],
|
|
|
+ newMonthValue: [
|
|
|
+ {
|
|
|
+ required: true,
|
|
|
+ message: "请输入企业月均工业产值",
|
|
|
+ trigger: "blur",
|
|
|
+ },
|
|
|
+ { type: "number", message: "企业月均工业产值必须为数字" },
|
|
|
+ ],
|
|
|
+ newYearTax: [
|
|
|
+ {
|
|
|
+ type: "number",
|
|
|
+ message: "企业年实缴税金必须为数字",
|
|
|
+ trigger: "blur",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ selectedYear: [
|
|
|
+ { required: true, message: "请选择年度", trigger: "blur" },
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ selectedIndustryArray: [],
|
|
|
+ selectedYear: null,
|
|
|
+ selectedRange: 0.1, // 不能为 0, - littlegreen - 固定0.1
|
|
|
+ // littlegreen - 检测区间 和 表格数据
|
|
|
+ detectMin: null,
|
|
|
+ detectMax: null,
|
|
|
+ tableData: [],
|
|
|
+ scoreData: [],
|
|
|
+ };
|
|
|
},
|
|
|
- // 处理数据
|
|
|
- handleData() {
|
|
|
- // 1.拿当前年份和code的企业运行数据过来
|
|
|
- // 2.计算每个企业的z-score
|
|
|
- // 3.画图
|
|
|
- const that = this;
|
|
|
- listAllIndustry_run({
|
|
|
- code: that.form.selectedCode,
|
|
|
- year: that.form.selectedYear,
|
|
|
- })
|
|
|
- .then((res) => {
|
|
|
- if (res && res.rows) {
|
|
|
- that.scoreData = res.rows;
|
|
|
- that.initChart();
|
|
|
- }
|
|
|
- })
|
|
|
- .catch((error) => {
|
|
|
- console.error("Error fetching data:", error);
|
|
|
- });
|
|
|
+ mounted() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.fetchData();
|
|
|
+ });
|
|
|
},
|
|
|
- initChart() {
|
|
|
+ beforeDestroy() {
|
|
|
if (this.chart) {
|
|
|
this.chart.dispose();
|
|
|
}
|
|
|
- this.chart = echarts.init(this.$refs.chart, "macarons");
|
|
|
- this.updateChart();
|
|
|
},
|
|
|
- updateChart() {
|
|
|
- const that = this;
|
|
|
- if (!this.chart) {
|
|
|
- return;
|
|
|
- }
|
|
|
- let newMonthValue = new Decimal(that.form.newMonthValue).toNumber();
|
|
|
- let total = [newMonthValue]; //总值
|
|
|
- const result = Object.values(
|
|
|
- that.scoreData.reduce((acc, item) => {
|
|
|
- const key = item.enterpriseName; // 根据企业名称分组
|
|
|
- let totalIndustrialValue = new Decimal(item.totalIndustrialValue);
|
|
|
- if (!acc[key]) {
|
|
|
- acc[key] = {
|
|
|
- name: key,
|
|
|
- data: [],
|
|
|
- totalValue: new Decimal(0),
|
|
|
- count: 0,
|
|
|
- }; // 创建对象并初始化
|
|
|
+ methods: {
|
|
|
+ // 拉取初始数据
|
|
|
+ async fetchData() {
|
|
|
+ const that = this;
|
|
|
+ // 获得所有行业
|
|
|
+ // that.selectedYear = new Date().getUTCFullYear() + "";
|
|
|
+ await listAllIndustry()
|
|
|
+ .then((res) => {
|
|
|
+ if (res && res?.rows) {
|
|
|
+ that.selectedIndustryArray = res.rows.map((item) => {
|
|
|
+ return {
|
|
|
+ key: item.code,
|
|
|
+ value: item.code + item.industryName,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error("Error fetching data:", error);
|
|
|
+ });
|
|
|
+
|
|
|
+ await getIndexData({
|
|
|
+ year: 0,
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ if (res && res?.rows) {
|
|
|
+ that.selectedYearArray = res.rows[0].years.map((v) => {
|
|
|
+ return {
|
|
|
+ key: v,
|
|
|
+ value: v,
|
|
|
+ };
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error("Error fetching data:", error);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 提交表单
|
|
|
+ submit() {
|
|
|
+ this.$refs.ruleForm.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ this.handleData();
|
|
|
+ } else {
|
|
|
+ console.error("error submit!!");
|
|
|
+ return false;
|
|
|
}
|
|
|
-
|
|
|
- acc[key].data.push(item); // 添加到对应的类别中
|
|
|
- acc[key].totalValue = acc[key].totalValue.plus(totalIndustrialValue); // 累加 totalIndustrialValue
|
|
|
- acc[key].count++; // 企业数 +1
|
|
|
- return acc;
|
|
|
- }, {})
|
|
|
- ).map(({ name, data, totalValue, count }) => {
|
|
|
- const totalIndustrialValue = totalValue.dividedBy(count).toNumber(); // 计算均值
|
|
|
- total.push(totalIndustrialValue);
|
|
|
- return { name, data, totalIndustrialValue }; // 返回结果
|
|
|
- });
|
|
|
- result.push({
|
|
|
- name: "新企业",
|
|
|
- data: [],
|
|
|
- totalIndustrialValue: newMonthValue,
|
|
|
- });
|
|
|
-
|
|
|
- // littlegreen --计算增加新企业之后工业产值变化 计算全体企业 totalIndustrialValue 均值
|
|
|
- const totalValues = result.map(
|
|
|
- (e) => new Decimal(e.totalIndustrialValue)
|
|
|
- );
|
|
|
- const overallMean = totalValues
|
|
|
- .reduce((sum, value) => sum.plus(value), new Decimal(0))
|
|
|
- .dividedBy(totalValues.length);
|
|
|
-
|
|
|
- // 计算不包括“新企业”的均值
|
|
|
- const filteredValues = result
|
|
|
- .filter((e) => e.name !== "新企业")
|
|
|
- .map((e) => new Decimal(e.totalIndustrialValue));
|
|
|
-
|
|
|
- const filteredMean = filteredValues
|
|
|
- .reduce((sum, value) => sum.plus(value), new Decimal(0))
|
|
|
- .dividedBy(filteredValues.length);
|
|
|
- const relativeChange = overallMean.minus(filteredMean).dividedBy(filteredMean).mul(new Decimal(100));
|
|
|
- // 显示增加/降低/一致
|
|
|
- that.calShow = relativeChange.greaterThan(0) ? "high" : (relativeChange.lessThan(0)? "low" : "same")
|
|
|
- // 增加的比率
|
|
|
- that.rate = relativeChange.abs().toNumber().toFixed(2)
|
|
|
-
|
|
|
- // 获取基础数据:最大值,最小值,平均值,标准差
|
|
|
- function getBebeQ(numbers, digit = 2) {
|
|
|
- let sum = numbers.reduce(
|
|
|
- (acc, num) => acc.add(new Decimal(num)),
|
|
|
- new Decimal(0)
|
|
|
- );
|
|
|
-
|
|
|
- let max = Math.max.apply(null, numbers);
|
|
|
- let min = Math.min.apply(null, numbers);
|
|
|
-
|
|
|
- // 平均值
|
|
|
- let mean = sum.dividedBy(numbers.length);
|
|
|
-
|
|
|
- // 计算每个数与均值的差的平方
|
|
|
- const squaredDiffs = numbers.map((num) => {
|
|
|
- const diff = new Decimal(num).minus(mean);
|
|
|
- return diff.pow(2);
|
|
|
});
|
|
|
-
|
|
|
- // 计算平方差的均值
|
|
|
- const sumOfSquaredDiffs = squaredDiffs.reduce(
|
|
|
- (acc, diff) => acc.add(diff),
|
|
|
- new Decimal(0)
|
|
|
+ },
|
|
|
+ // 处理数据
|
|
|
+ handleData() {
|
|
|
+ // 1.拿当前年份和code的企业运行数据过来
|
|
|
+ // 2.计算每个企业的z-score
|
|
|
+ // 3.画图
|
|
|
+ const that = this;
|
|
|
+ listAllIndustry_run({
|
|
|
+ code: that.form.selectedCode,
|
|
|
+ year: that.form.selectedYear,
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ if (res && res.rows) {
|
|
|
+ that.scoreData = res.rows;
|
|
|
+ that.initChart();
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error("Error fetching data:", error);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ initChart() {
|
|
|
+ if (this.chart) {
|
|
|
+ this.chart.dispose();
|
|
|
+ }
|
|
|
+ this.chart = echarts.init(this.$refs.chart, "macarons");
|
|
|
+ this.updateChart();
|
|
|
+ },
|
|
|
+ updateChart() {
|
|
|
+ const that = this;
|
|
|
+ if (!this.chart) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let newMonthValue = new Decimal(that.form.newMonthValue).toNumber();
|
|
|
+ let total = [newMonthValue]; //总值
|
|
|
+ const result = Object.values(
|
|
|
+ that.scoreData.reduce((acc, item) => {
|
|
|
+ const key = item.enterpriseName; // 根据企业名称分组
|
|
|
+ let totalIndustrialValue = new Decimal(item.totalIndustrialValue);
|
|
|
+ if (!acc[key]) {
|
|
|
+ acc[key] = {
|
|
|
+ name: key,
|
|
|
+ data: [],
|
|
|
+ totalValue: new Decimal(0),
|
|
|
+ count: 0,
|
|
|
+ }; // 创建对象并初始化
|
|
|
+ }
|
|
|
+
|
|
|
+ acc[key].data.push(item); // 添加到对应的类别中
|
|
|
+ acc[key].totalValue = acc[key].totalValue.plus(totalIndustrialValue); // 累加 totalIndustrialValue
|
|
|
+ acc[key].count++; // 企业数 +1
|
|
|
+ return acc;
|
|
|
+ }, {})
|
|
|
+ ).map(({ name, data, totalValue, count }) => {
|
|
|
+ const totalIndustrialValue = totalValue.dividedBy(count).toNumber(); // 计算均值
|
|
|
+ total.push(totalIndustrialValue);
|
|
|
+ return { name, data, totalIndustrialValue }; // 返回结果
|
|
|
+ });
|
|
|
+ result.push({
|
|
|
+ name: "新企业",
|
|
|
+ data: [],
|
|
|
+ totalIndustrialValue: newMonthValue,
|
|
|
+ });
|
|
|
+
|
|
|
+ // littlegreen --计算增加新企业之后工业产值变化 计算全体企业 totalIndustrialValue 均值
|
|
|
+ const totalValues = result.map(
|
|
|
+ (e) => new Decimal(e.totalIndustrialValue)
|
|
|
);
|
|
|
-
|
|
|
- const variance = sumOfSquaredDiffs.dividedBy(numbers.length);
|
|
|
-
|
|
|
- // 开平方得到标准差
|
|
|
- const standardDeviation = variance.sqrt();
|
|
|
-
|
|
|
- // 向上取整到最近的 0.1
|
|
|
- const ceilingRoundedMax = Math.ceil(max * 10) / 10;
|
|
|
-
|
|
|
- // 向下取整到最近的 0.1
|
|
|
- const floorRoundedMin = Math.floor(min * 10) / 10;
|
|
|
-
|
|
|
- return {
|
|
|
- max: ceilingRoundedMax,
|
|
|
- min: floorRoundedMin,
|
|
|
- avg: parseFloat(mean.toNumber().toFixed(digit)) || 0,
|
|
|
- stdDev: parseFloat(standardDeviation.toNumber().toFixed(digit)),
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- // 示例数据
|
|
|
- const betaData = getBebeQ(total);
|
|
|
- let newZScore;
|
|
|
- const values = result.map((item) => {
|
|
|
- let num = item.totalIndustrialValue;
|
|
|
- const zScore = new Decimal(num)
|
|
|
- .minus(betaData.avg)
|
|
|
- .dividedBy(betaData.stdDev);
|
|
|
- let scoreNum = zScore.toNumber();
|
|
|
- if (new Decimal(num).equals(new Decimal(that.form.newMonthValue))) {
|
|
|
- newZScore = scoreNum;
|
|
|
+ const overallMean = totalValues
|
|
|
+ .reduce((sum, value) => sum.plus(value), new Decimal(0))
|
|
|
+ .dividedBy(totalValues.length);
|
|
|
+
|
|
|
+ // 计算不包括“新企业”的均值
|
|
|
+ const filteredValues = result
|
|
|
+ .filter((e) => e.name !== "新企业")
|
|
|
+ .map((e) => new Decimal(e.totalIndustrialValue));
|
|
|
+
|
|
|
+ const filteredMean = filteredValues
|
|
|
+ .reduce((sum, value) => sum.plus(value), new Decimal(0))
|
|
|
+ .dividedBy(filteredValues.length);
|
|
|
+ const relativeChange = overallMean.minus(filteredMean).dividedBy(filteredMean).mul(new Decimal(100));
|
|
|
+ // 显示增加/降低/一致
|
|
|
+ that.calShow = relativeChange.greaterThan(0) ? "high" : (relativeChange.lessThan(0)? "low" : "same")
|
|
|
+ // 增加的比率
|
|
|
+ that.rate = relativeChange.abs().toNumber().toFixed(2)
|
|
|
+
|
|
|
+ // 获取基础数据:最大值,最小值,平均值,标准差
|
|
|
+ function getBebeQ(numbers, digit = 2) {
|
|
|
+ let sum = numbers.reduce(
|
|
|
+ (acc, num) => acc.add(new Decimal(num)),
|
|
|
+ new Decimal(0)
|
|
|
+ );
|
|
|
+
|
|
|
+ let max = Math.max.apply(null, numbers);
|
|
|
+ let min = Math.min.apply(null, numbers);
|
|
|
+
|
|
|
+ // 平均值
|
|
|
+ let mean = sum.dividedBy(numbers.length);
|
|
|
+
|
|
|
+ // 计算每个数与均值的差的平方
|
|
|
+ const squaredDiffs = numbers.map((num) => {
|
|
|
+ const diff = new Decimal(num).minus(mean);
|
|
|
+ return diff.pow(2);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 计算平方差的均值
|
|
|
+ const sumOfSquaredDiffs = squaredDiffs.reduce(
|
|
|
+ (acc, diff) => acc.add(diff),
|
|
|
+ new Decimal(0)
|
|
|
+ );
|
|
|
+
|
|
|
+ const variance = sumOfSquaredDiffs.dividedBy(numbers.length);
|
|
|
+
|
|
|
+ // 开平方得到标准差
|
|
|
+ const standardDeviation = variance.sqrt();
|
|
|
+
|
|
|
+ // 向上取整到最近的 0.1
|
|
|
+ const ceilingRoundedMax = Math.ceil(max * 10) / 10;
|
|
|
+
|
|
|
+ // 向下取整到最近的 0.1
|
|
|
+ const floorRoundedMin = Math.floor(min * 10) / 10;
|
|
|
+
|
|
|
+ return {
|
|
|
+ max: ceilingRoundedMax,
|
|
|
+ min: floorRoundedMin,
|
|
|
+ avg: parseFloat(mean.toNumber().toFixed(digit)) || 0,
|
|
|
+ stdDev: parseFloat(standardDeviation.toNumber().toFixed(digit)),
|
|
|
+ };
|
|
|
}
|
|
|
- item.score = scoreNum;
|
|
|
- return scoreNum;
|
|
|
- });
|
|
|
- // 计算 z-score 的基础数据
|
|
|
- const scoreBasic = getBebeQ(values);
|
|
|
- const center = new Decimal(scoreBasic.avg); // 确保 center 是 Decimal 类型
|
|
|
- const interval = new Decimal(0.1);
|
|
|
-
|
|
|
- // 使用 Decimal 来处理 minLimit 和 maxLimit
|
|
|
- let minLimit = new Decimal(scoreBasic.min); // 向下取整到最近的0.1
|
|
|
- let maxLimit = new Decimal(scoreBasic.max); // 向上取整到最近的0.1
|
|
|
-
|
|
|
- // 确保 minLimit 和 maxLimit 关于 center 对称
|
|
|
- if (!center.minus(minLimit).equals(maxLimit.minus(center))) {
|
|
|
- const distanceToCenter = center
|
|
|
- .minus(minLimit)
|
|
|
- .gt(maxLimit.minus(center))
|
|
|
- ? center.minus(minLimit)
|
|
|
- : maxLimit.minus(center);
|
|
|
-
|
|
|
- maxLimit = center.plus(distanceToCenter); // 更新 maxLimit 保持对称
|
|
|
- minLimit = center.minus(distanceToCenter); // 更新 minLimit 保持对称
|
|
|
- }
|
|
|
-
|
|
|
- const intervals = [];
|
|
|
- // 乘以1000 是将小数变成整数去计算,小数计算会有误差
|
|
|
- for (
|
|
|
- let i = minLimit * 1000;
|
|
|
- i <= maxLimit * 1000;
|
|
|
- i += interval * 1000
|
|
|
- ) {
|
|
|
- intervals.push(parseFloat((i / 1000).toFixed(2)));
|
|
|
- }
|
|
|
- // // 计算每个间隔的频次
|
|
|
- const frequency = new Array(intervals.length - 1).fill(0); // 初始化频次数组
|
|
|
-
|
|
|
- let intervalArr = intervals.slice(0, -1);
|
|
|
- const intervalStrings = [];
|
|
|
- for (let i = 0; i < intervalArr.length; i++) {
|
|
|
- const start = intervalArr[i].toFixed(1); // 保留一位小数
|
|
|
- const end = ((intervalArr[i] * 1000 + interval * 1000) / 1000).toFixed(
|
|
|
- 1
|
|
|
- ); // 保留一位小数
|
|
|
- intervalStrings.push({
|
|
|
- name: `${start}-${end}`,
|
|
|
- max: end,
|
|
|
- min: start,
|
|
|
- }); // 构建区间字符串
|
|
|
- }
|
|
|
-
|
|
|
- values.forEach((value) => {
|
|
|
- for (let j = 0; j < intervalStrings.length; j++) {
|
|
|
- // 保证包含右边界
|
|
|
- let v = parseFloat(value) * 1000;
|
|
|
- if (
|
|
|
- v >= parseFloat(intervalStrings[j].min) * 1000 &&
|
|
|
- v < parseFloat(intervalStrings[j].max) * 1000
|
|
|
- ) {
|
|
|
- frequency[j]++;
|
|
|
- break; // 找到对应区间后可以跳出循环
|
|
|
+
|
|
|
+ // 示例数据
|
|
|
+ const betaData = getBebeQ(total);
|
|
|
+ let newZScore;
|
|
|
+ const values = result.map((item) => {
|
|
|
+ let num = item.totalIndustrialValue;
|
|
|
+ const zScore = new Decimal(num)
|
|
|
+ .minus(betaData.avg)
|
|
|
+ .dividedBy(betaData.stdDev);
|
|
|
+ let scoreNum = zScore.toNumber();
|
|
|
+ if (new Decimal(num).equals(new Decimal(that.form.newMonthValue))) {
|
|
|
+ newZScore = scoreNum;
|
|
|
}
|
|
|
+ item.score = scoreNum;
|
|
|
+ return scoreNum;
|
|
|
+ });
|
|
|
+ // 计算 z-score 的基础数据
|
|
|
+ const scoreBasic = getBebeQ(values);
|
|
|
+ const center = new Decimal(scoreBasic.avg); // 确保 center 是 Decimal 类型
|
|
|
+ const interval = new Decimal(0.1);
|
|
|
+
|
|
|
+ // 使用 Decimal 来处理 minLimit 和 maxLimit
|
|
|
+ let minLimit = new Decimal(scoreBasic.min); // 向下取整到最近的0.1
|
|
|
+ let maxLimit = new Decimal(scoreBasic.max); // 向上取整到最近的0.1
|
|
|
+
|
|
|
+ // 确保 minLimit 和 maxLimit 关于 center 对称
|
|
|
+ if (!center.minus(minLimit).equals(maxLimit.minus(center))) {
|
|
|
+ const distanceToCenter = center
|
|
|
+ .minus(minLimit)
|
|
|
+ .gt(maxLimit.minus(center))
|
|
|
+ ? center.minus(minLimit)
|
|
|
+ : maxLimit.minus(center);
|
|
|
+
|
|
|
+ maxLimit = center.plus(distanceToCenter); // 更新 maxLimit 保持对称
|
|
|
+ minLimit = center.minus(distanceToCenter); // 更新 minLimit 保持对称
|
|
|
}
|
|
|
- });
|
|
|
-
|
|
|
- // // 确保处理最大值等于maxLimit的情况
|
|
|
- if (
|
|
|
- values.some(
|
|
|
- (value) => parseFloat(value) * 1000 == parseFloat(maxLimit) * 1000
|
|
|
- )
|
|
|
- ) {
|
|
|
- frequency[frequency.length - 1]++;
|
|
|
- }
|
|
|
- // 1.计算正态分布值
|
|
|
- const normalDistributionValues = intervals
|
|
|
- .slice(0, -1)
|
|
|
- .map((intervalStart, index) => {
|
|
|
- const intervalEnd = intervals[index + 1];
|
|
|
- const midpoint = (intervalStart + intervalEnd) / 2;
|
|
|
-
|
|
|
- // 使用 Decimal 进行更高精度的计算
|
|
|
- const midPointDecimal = new Decimal(midpoint);
|
|
|
- const avgDecimal = new Decimal(scoreBasic.avg);
|
|
|
- const stdDevDecimal = new Decimal(scoreBasic.stdDev);
|
|
|
-
|
|
|
- const exponent = midPointDecimal
|
|
|
- .minus(avgDecimal)
|
|
|
- .dividedBy(stdDevDecimal)
|
|
|
- .pow(2)
|
|
|
- .negated()
|
|
|
- .dividedBy(new Decimal(2));
|
|
|
- const exponentValue = new Decimal(Math.exp(exponent.toNumber())); // 取自然指数
|
|
|
- const coefficient = new Decimal(1).dividedBy(
|
|
|
- stdDevDecimal.times(new Decimal(Math.sqrt(2 * Math.PI)))
|
|
|
- );
|
|
|
-
|
|
|
- return coefficient.times(exponentValue).toNumber(); // 返回计算结果
|
|
|
+
|
|
|
+ const intervals = [];
|
|
|
+ // 乘以1000 是将小数变成整数去计算,小数计算会有误差
|
|
|
+ for (
|
|
|
+ let i = minLimit * 1000;
|
|
|
+ i <= maxLimit * 1000;
|
|
|
+ i += interval * 1000
|
|
|
+ ) {
|
|
|
+ intervals.push(parseFloat((i / 1000).toFixed(2)));
|
|
|
+ }
|
|
|
+ // // 计算每个间隔的频次
|
|
|
+ const frequency = new Array(intervals.length - 1).fill(0); // 初始化频次数组
|
|
|
+
|
|
|
+ let intervalArr = intervals.slice(0, -1);
|
|
|
+ const intervalStrings = [];
|
|
|
+ for (let i = 0; i < intervalArr.length; i++) {
|
|
|
+ const start = intervalArr[i].toFixed(1); // 保留一位小数
|
|
|
+ const end = ((intervalArr[i] * 1000 + interval * 1000) / 1000).toFixed(
|
|
|
+ 1
|
|
|
+ ); // 保留一位小数
|
|
|
+ intervalStrings.push({
|
|
|
+ name: `${start}-${end}`,
|
|
|
+ max: end,
|
|
|
+ min: start,
|
|
|
+ }); // 构建区间字符串
|
|
|
+ }
|
|
|
+
|
|
|
+ values.forEach((value) => {
|
|
|
+ for (let j = 0; j < intervalStrings.length; j++) {
|
|
|
+ // 保证包含右边界
|
|
|
+ let v = parseFloat(value) * 1000;
|
|
|
+ if (
|
|
|
+ v >= parseFloat(intervalStrings[j].min) * 1000 &&
|
|
|
+ v < parseFloat(intervalStrings[j].max) * 1000
|
|
|
+ ) {
|
|
|
+ frequency[j]++;
|
|
|
+ break; // 找到对应区间后可以跳出循环
|
|
|
+ }
|
|
|
+ }
|
|
|
});
|
|
|
- const option = {
|
|
|
- color: ["rgba(245,0,0,0.6)"],
|
|
|
- dataZoom: [
|
|
|
- {
|
|
|
- type: "inside", // 内置于坐标系中
|
|
|
- start: 0,
|
|
|
- end: 100,
|
|
|
- xAxisIndex: [0],
|
|
|
- },
|
|
|
- ],
|
|
|
- tooltip: {
|
|
|
- trigger: "axis",
|
|
|
- axisPointer: {
|
|
|
- type: "shadow",
|
|
|
- },
|
|
|
- formatter: (params) => {
|
|
|
- // 使用箭头函数来保持 this 的上下文
|
|
|
- const seriesName = params[0].name; // 系列名称
|
|
|
- const dataIndex = params[0].dataIndex; // 数据索引
|
|
|
- const value = params[0].data; // 实际的数据值
|
|
|
- const xAxisLabel = params[0].axisValueLabel; // x轴的标签
|
|
|
- const yAxisLabel = params[0].seriesName;
|
|
|
- // 构建自定义的 tooltip 内容,包含年份
|
|
|
- return `${xAxisLabel}</br> ${yAxisLabel}: ${value} `;
|
|
|
+
|
|
|
+ // // 确保处理最大值等于maxLimit的情况
|
|
|
+ if (
|
|
|
+ values.some(
|
|
|
+ (value) => parseFloat(value) * 1000 == parseFloat(maxLimit) * 1000
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ frequency[frequency.length - 1]++;
|
|
|
+ }
|
|
|
+ // 1.计算正态分布值
|
|
|
+ const normalDistributionValues = intervals
|
|
|
+ .slice(0, -1)
|
|
|
+ .map((intervalStart, index) => {
|
|
|
+ const intervalEnd = intervals[index + 1];
|
|
|
+ const midpoint = (intervalStart + intervalEnd) / 2;
|
|
|
+
|
|
|
+ // 使用 Decimal 进行更高精度的计算
|
|
|
+ const midPointDecimal = new Decimal(midpoint);
|
|
|
+ const avgDecimal = new Decimal(scoreBasic.avg);
|
|
|
+ const stdDevDecimal = new Decimal(scoreBasic.stdDev);
|
|
|
+
|
|
|
+ const exponent = midPointDecimal
|
|
|
+ .minus(avgDecimal)
|
|
|
+ .dividedBy(stdDevDecimal)
|
|
|
+ .pow(2)
|
|
|
+ .negated()
|
|
|
+ .dividedBy(new Decimal(2));
|
|
|
+ const exponentValue = new Decimal(Math.exp(exponent.toNumber())); // 取自然指数
|
|
|
+ const coefficient = new Decimal(1).dividedBy(
|
|
|
+ stdDevDecimal.times(new Decimal(Math.sqrt(2 * Math.PI)))
|
|
|
+ );
|
|
|
+
|
|
|
+ return coefficient.times(exponentValue).toNumber(); // 返回计算结果
|
|
|
+ });
|
|
|
+ const option = {
|
|
|
+ color: ["rgba(245,0,0,0.6)"],
|
|
|
+ dataZoom: [
|
|
|
+ {
|
|
|
+ type: "inside", // 内置于坐标系中
|
|
|
+ start: 0,
|
|
|
+ end: 100,
|
|
|
+ xAxisIndex: [0],
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ tooltip: {
|
|
|
+ trigger: "axis",
|
|
|
+ axisPointer: {
|
|
|
+ type: "shadow",
|
|
|
+ },
|
|
|
+ formatter: (params) => {
|
|
|
+ // 使用箭头函数来保持 this 的上下文
|
|
|
+ const seriesName = params[0].name; // 系列名称
|
|
|
+ const dataIndex = params[0].dataIndex; // 数据索引
|
|
|
+ const value = params[0].data; // 实际的数据值
|
|
|
+ const xAxisLabel = params[0].axisValueLabel; // x轴的标签
|
|
|
+ const yAxisLabel = params[0].seriesName;
|
|
|
+ // 构建自定义的 tooltip 内容,包含年份
|
|
|
+ return `${xAxisLabel}</br> ${yAxisLabel}: ${value} `;
|
|
|
+ },
|
|
|
},
|
|
|
- },
|
|
|
- legend: {
|
|
|
- data: [`${that.form.selectedYear}工业生产总值企业数统计`, "正态分布"],
|
|
|
- },
|
|
|
- grid: {
|
|
|
- left: "3%",
|
|
|
- right: "4%",
|
|
|
- bottom: "50px",
|
|
|
- containLabel: true,
|
|
|
- },
|
|
|
- xAxis: {
|
|
|
- type: "category",
|
|
|
- name: "分布区间",
|
|
|
- // data: histogramData.map((item) => item.name),
|
|
|
- data: intervalStrings.map((item) => item.name),
|
|
|
- axisLabel: {
|
|
|
- fontSize: 12,
|
|
|
- rotate: 0,
|
|
|
- // padding: [0, 0, 0, -200]
|
|
|
+ legend: {
|
|
|
+ data: [`${that.form.selectedYear}工业生产总值企业数统计`, "正态分布"],
|
|
|
},
|
|
|
- },
|
|
|
- yAxis: [
|
|
|
- {
|
|
|
- name: "企业数",
|
|
|
- type: "value",
|
|
|
- minInterval: 1,
|
|
|
+ grid: {
|
|
|
+ left: "3%",
|
|
|
+ right: "4%",
|
|
|
+ bottom: "50px",
|
|
|
+ containLabel: true,
|
|
|
},
|
|
|
- {
|
|
|
- name: "正态分布",
|
|
|
- type: "value",
|
|
|
+ xAxis: {
|
|
|
+ type: "category",
|
|
|
+ name: "分布区间",
|
|
|
+ // data: histogramData.map((item) => item.name),
|
|
|
+ data: intervalStrings.map((item) => item.name),
|
|
|
+ axisLabel: {
|
|
|
+ fontSize: 12,
|
|
|
+ rotate: 0,
|
|
|
+ // padding: [0, 0, 0, -200]
|
|
|
+ },
|
|
|
},
|
|
|
- ],
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: `${that.form.selectedYear}工业生产总值企业数统计`,
|
|
|
- type: "bar",
|
|
|
- barWidth: "30%",
|
|
|
- itemStyle: {
|
|
|
- // color: "rgba(245,0,0,0.6)",
|
|
|
- normal: {
|
|
|
- color: function (params) {
|
|
|
- const value = params.dataIndex; // 获取当前柱子在数据中的索引
|
|
|
- let min = parseFloat(intervalStrings[value].min) * 1000;
|
|
|
- let max = parseFloat(intervalStrings[value].max) * 1000;
|
|
|
- if (newZScore * 1000 >= min && newZScore * 1000 < max) {
|
|
|
- return "#ffcc00";
|
|
|
- } else if (
|
|
|
- newZScore * 1000 == maxLimit * 1000 &&
|
|
|
- max == maxLimit * 1000
|
|
|
- ) {
|
|
|
- return "#ffcc00";
|
|
|
- }
|
|
|
- return "rgba(245,0,0,0.6)";
|
|
|
- // 默认颜色
|
|
|
+ yAxis: [
|
|
|
+ {
|
|
|
+ name: "企业数",
|
|
|
+ type: "value",
|
|
|
+ minInterval: 1,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "正态分布",
|
|
|
+ type: "value",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: `${that.form.selectedYear}工业生产总值企业数统计`,
|
|
|
+ type: "bar",
|
|
|
+ barWidth: "30%",
|
|
|
+ itemStyle: {
|
|
|
+ // color: "rgba(245,0,0,0.6)",
|
|
|
+ normal: {
|
|
|
+ color: function (params) {
|
|
|
+ const value = params.dataIndex; // 获取当前柱子在数据中的索引
|
|
|
+ let min = parseFloat(intervalStrings[value].min) * 1000;
|
|
|
+ let max = parseFloat(intervalStrings[value].max) * 1000;
|
|
|
+ if (newZScore * 1000 >= min && newZScore * 1000 < max) {
|
|
|
+ return "#ffcc00";
|
|
|
+ } else if (
|
|
|
+ newZScore * 1000 == maxLimit * 1000 &&
|
|
|
+ max == maxLimit * 1000
|
|
|
+ ) {
|
|
|
+ return "#ffcc00";
|
|
|
+ }
|
|
|
+ return "rgba(245,0,0,0.6)";
|
|
|
+ // 默认颜色
|
|
|
+ },
|
|
|
},
|
|
|
},
|
|
|
+ // data: histogramData.map((item) => item.value),
|
|
|
+ data: frequency,
|
|
|
+ label: {
|
|
|
+ show: false, // 将show属性设置为false,去掉柱子上的数字
|
|
|
+ },
|
|
|
},
|
|
|
- // data: histogramData.map((item) => item.value),
|
|
|
- data: frequency,
|
|
|
- label: {
|
|
|
- show: false, // 将show属性设置为false,去掉柱子上的数字
|
|
|
- },
|
|
|
- },
|
|
|
- {
|
|
|
- name: "正态分布",
|
|
|
- yAxisIndex: 1,
|
|
|
- type: "line",
|
|
|
- data: normalDistributionValues,
|
|
|
- lineStyle: {
|
|
|
- color: "#1a7cc8",
|
|
|
+ {
|
|
|
+ name: "正态分布",
|
|
|
+ yAxisIndex: 1,
|
|
|
+ type: "line",
|
|
|
+ data: normalDistributionValues,
|
|
|
+ lineStyle: {
|
|
|
+ color: "#1a7cc8",
|
|
|
+ },
|
|
|
+ symbol: "none",
|
|
|
},
|
|
|
- symbol: "none",
|
|
|
- },
|
|
|
- ],
|
|
|
- };
|
|
|
- this.chart.setOption(option);
|
|
|
- this.chart.on("click", function (param) {
|
|
|
- if (
|
|
|
- typeof param.dataIndex === "number" &&
|
|
|
- param.dataIndex >= 0 &&
|
|
|
- param.dataIndex < intervalStrings.length
|
|
|
- ) {
|
|
|
- let dataIndexValue = intervalStrings[param.dataIndex];
|
|
|
- const filteredArray = result.filter((item) => {
|
|
|
- let score = new Decimal(item.score);
|
|
|
- let max = new Decimal(dataIndexValue.max);
|
|
|
- let min = new Decimal(dataIndexValue.min);
|
|
|
- let maxL = new Decimal(maxLimit);
|
|
|
- const isMaxValEqual = max.equals(maxL);
|
|
|
- const lowerBoundCheck = score.greaterThan(min) || score.equals(min);
|
|
|
- const upperBoundCheck = isMaxValEqual
|
|
|
- ? score.lessThan(max) || score.equals(max)
|
|
|
- : score.lessThan(max);
|
|
|
- return lowerBoundCheck && upperBoundCheck;
|
|
|
- });
|
|
|
- that.tableData = filteredArray.map((item) => {
|
|
|
- return {
|
|
|
- totalIndustrialValue: item.totalIndustrialValue.toFixed(2),
|
|
|
- enterpriseId: item.name,
|
|
|
- year: that.form.selectedYear,
|
|
|
- value: item.score.toFixed(2),
|
|
|
- };
|
|
|
- });
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- // 重置表单
|
|
|
- resetForm() {
|
|
|
- this.$refs.ruleForm.resetFields();
|
|
|
- this.calShow = "init";
|
|
|
+ ],
|
|
|
+ };
|
|
|
+ this.chart.setOption(option);
|
|
|
+ this.chart.on("click", function (param) {
|
|
|
+ if (
|
|
|
+ typeof param.dataIndex === "number" &&
|
|
|
+ param.dataIndex >= 0 &&
|
|
|
+ param.dataIndex < intervalStrings.length
|
|
|
+ ) {
|
|
|
+ let dataIndexValue = intervalStrings[param.dataIndex];
|
|
|
+ const filteredArray = result.filter((item) => {
|
|
|
+ let score = new Decimal(item.score);
|
|
|
+ let max = new Decimal(dataIndexValue.max);
|
|
|
+ let min = new Decimal(dataIndexValue.min);
|
|
|
+ let maxL = new Decimal(maxLimit);
|
|
|
+ const isMaxValEqual = max.equals(maxL);
|
|
|
+ const lowerBoundCheck = score.greaterThan(min) || score.equals(min);
|
|
|
+ const upperBoundCheck = isMaxValEqual
|
|
|
+ ? score.lessThan(max) || score.equals(max)
|
|
|
+ : score.lessThan(max);
|
|
|
+ return lowerBoundCheck && upperBoundCheck;
|
|
|
+ });
|
|
|
+ that.tableData = filteredArray.map((item) => {
|
|
|
+ return {
|
|
|
+ totalIndustrialValue: item.totalIndustrialValue.toFixed(2),
|
|
|
+ enterpriseId: item.name,
|
|
|
+ year: that.form.selectedYear,
|
|
|
+ value: item.score.toFixed(2),
|
|
|
+ };
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 重置表单
|
|
|
+ resetForm() {
|
|
|
+ this.$refs.ruleForm.resetFields();
|
|
|
+ this.calShow = "init";
|
|
|
+ },
|
|
|
},
|
|
|
- },
|
|
|
- watch: {},
|
|
|
-};
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.select-container {
|
|
|
- margin: 10px 0;
|
|
|
- font-size: 16px; /* 调整字号大小 */
|
|
|
-}
|
|
|
-
|
|
|
-.select-container select {
|
|
|
- padding: 10px 20px; /* 增加内边距 */
|
|
|
- margin-right: 10px; /* 增加右边距 */
|
|
|
- border: 1px solid #121315; /* 蓝色边框 */
|
|
|
- border-radius: 4px; /* 圆角边框 */
|
|
|
- background-color: white; /* 背景色 */
|
|
|
- color: #121315; /* 文字颜色 */
|
|
|
- font-size: 16px; /* 调整字号大小 */
|
|
|
- cursor: pointer; /* 鼠标悬停时的指针样式 */
|
|
|
- outline: none; /* 移除焦点时的轮廓 */
|
|
|
-}
|
|
|
-
|
|
|
-.select-container select:hover {
|
|
|
- border-color: #1a7cc8; /* 鼠标悬停时的边框颜色 */
|
|
|
-}
|
|
|
-
|
|
|
-.select-container select:focus {
|
|
|
- border-color: #121315; /* 焦点时的边框颜色 */
|
|
|
- box-shadow: 0 0 0 2px rgba(64, 159, 255, 0.2); /* 焦点时的阴影效果 */
|
|
|
-}
|
|
|
-</style>
|
|
|
+ watch: {},
|
|
|
+ };
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <style scoped>
|
|
|
+ .select-container {
|
|
|
+ margin: 10px 0;
|
|
|
+ font-size: 16px; /* 调整字号大小 */
|
|
|
+ }
|
|
|
+
|
|
|
+ .select-container select {
|
|
|
+ padding: 10px 20px; /* 增加内边距 */
|
|
|
+ margin-right: 10px; /* 增加右边距 */
|
|
|
+ border: 1px solid #121315; /* 蓝色边框 */
|
|
|
+ border-radius: 4px; /* 圆角边框 */
|
|
|
+ background-color: white; /* 背景色 */
|
|
|
+ color: #121315; /* 文字颜色 */
|
|
|
+ font-size: 16px; /* 调整字号大小 */
|
|
|
+ cursor: pointer; /* 鼠标悬停时的指针样式 */
|
|
|
+ outline: none; /* 移除焦点时的轮廓 */
|
|
|
+ }
|
|
|
+
|
|
|
+ .select-container select:hover {
|
|
|
+ border-color: #1a7cc8; /* 鼠标悬停时的边框颜色 */
|
|
|
+ }
|
|
|
+
|
|
|
+ .select-container select:focus {
|
|
|
+ border-color: #121315; /* 焦点时的边框颜色 */
|
|
|
+ box-shadow: 0 0 0 2px rgba(64, 159, 255, 0.2); /* 焦点时的阴影效果 */
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+
|