|
@@ -0,0 +1,637 @@
|
|
|
+<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"
|
|
|
+ >
|
|
|
+ <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: cente">
|
|
|
+ <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-width="100px">
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ icon="el-icon-search"
|
|
|
+ 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 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";
|
|
|
+
|
|
|
+export default {
|
|
|
+ mixins: [resize],
|
|
|
+ props: {
|
|
|
+ className: {
|
|
|
+ type: String,
|
|
|
+ default: "chart",
|
|
|
+ },
|
|
|
+ width: {
|
|
|
+ type: String,
|
|
|
+ default: "100%",
|
|
|
+ },
|
|
|
+ height: {
|
|
|
+ type: String,
|
|
|
+ default: "400px",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ chart: null,
|
|
|
+ chartData: [],
|
|
|
+ industryData: [],
|
|
|
+ industryMap: new Map(),
|
|
|
+ selectedDataKey: "totalIndustrialValueScore", // 默认选择的字段
|
|
|
+ form: {
|
|
|
+ selectedCode: null,
|
|
|
+ newMonthValue: null,
|
|
|
+ newYearTax: null,
|
|
|
+ },
|
|
|
+ rules: {
|
|
|
+ selectedCode: [
|
|
|
+ { required: true, message: "请选择行业", trigger: "blur" },
|
|
|
+ ],
|
|
|
+ newMonthValue: [
|
|
|
+ {
|
|
|
+ required: true,
|
|
|
+ message: "请输入企业月均工业产值",
|
|
|
+ trigger: "blur",
|
|
|
+ },
|
|
|
+ { type: "number", message: "企业月均工业产值必须为数字" },
|
|
|
+ ],
|
|
|
+ newYearTax: [
|
|
|
+ {
|
|
|
+ type: "number",
|
|
|
+ message: "企业年实缴税金必须为数字",
|
|
|
+ trigger: "blur",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ selectedIndustryArray: [],
|
|
|
+ // dataKeys: [
|
|
|
+ // "totalIndustrialValueScore",
|
|
|
+ // // 'gdpScore',
|
|
|
+ // "taxableIncomeScore",
|
|
|
+ // "paidTaxScore",
|
|
|
+ // "fundingScore",
|
|
|
+ // "energyConsumeScore",
|
|
|
+ // "powerConsumeScore",
|
|
|
+ // // 其他得分字段...
|
|
|
+ // ], // 可选项
|
|
|
+ // keyToChinese: {
|
|
|
+ // mainBusinessScore: "主营业务活动得分",
|
|
|
+ // landAreaScore: "用地面积得分",
|
|
|
+ // totalIndustrialValueScore: "工业总产值得分",
|
|
|
+ // gdpScore: "工业增加值得分",
|
|
|
+ // taxableIncomeScore: "应税收入得分",
|
|
|
+ // paidTaxScore: "实缴税金得分",
|
|
|
+ // mainBusinessIncomeScore: "主营业务收入得分",
|
|
|
+ // employeeNumberScore: "从业人员数得分",
|
|
|
+ // profitScore: "利润总额得分",
|
|
|
+ // ownerEquityScore: "所有者权益得分",
|
|
|
+ // fundingScore: "研发经费得分",
|
|
|
+ // energyConsumeScore: "能源消费量得分",
|
|
|
+ // powerConsumeScore: "电力消费量得分",
|
|
|
+ // },
|
|
|
+ // keyToLevel: {
|
|
|
+ // totalIndustrialValueScore: "totalIndustrialValueLevel",
|
|
|
+ // taxableIncomeScore: "taxableIncomeLevel",
|
|
|
+ // paidTaxScore: "paidTaxLevel",
|
|
|
+ // fundingScore: "fundingLevel",
|
|
|
+ // energyConsumeScore: "energyConsumeLevel",
|
|
|
+ // powerConsumeScore: "powerConsumeLevel",
|
|
|
+ // },
|
|
|
+ selectedYear: null,
|
|
|
+ // queryParams: {
|
|
|
+ // pageNum: 1,
|
|
|
+ // pageSize: 2000000, // 默认 2000000 条(全部一次性数据)
|
|
|
+ // enterpriseName: null,
|
|
|
+ // location: null,
|
|
|
+ // code: null,
|
|
|
+ // mainBusiness: null,
|
|
|
+ // landArea: null,
|
|
|
+ // totalIndustrialValue: null,
|
|
|
+ // gdp: null,
|
|
|
+ // taxableIncome: null,
|
|
|
+ // paidTax: null,
|
|
|
+ // mainBusinessIncome: null,
|
|
|
+ // employeeNumber: null,
|
|
|
+ // profit: null,
|
|
|
+ // ownerEquity: null,
|
|
|
+ // funding: null,
|
|
|
+ // energyConsume: null,
|
|
|
+ // year: null,
|
|
|
+ // month: null,
|
|
|
+ // },
|
|
|
+ // industryQueryParams: {
|
|
|
+ // pageNum: 1,
|
|
|
+ // pageSize: 2000000,
|
|
|
+ // industryName: null,
|
|
|
+ // code: null,
|
|
|
+ // }, // 查询行业信息
|
|
|
+ // availableYears: [],
|
|
|
+ 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: {
|
|
|
+ // 拉取初始数据
|
|
|
+ fetchData() {
|
|
|
+ const that = this;
|
|
|
+ // 获得所有行业
|
|
|
+ that.selectedYear = new Date().getUTCFullYear() + "";
|
|
|
+ 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);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 提交表单
|
|
|
+ submit() {
|
|
|
+ this.$refs.ruleForm.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ this.handleData();
|
|
|
+ } else {
|
|
|
+ console.error("error submit!!");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 处理数据
|
|
|
+ handleData() {
|
|
|
+ // 1.拿当前年份和code的企业运行数据过来
|
|
|
+ // 2.计算每个企业的z-score
|
|
|
+ // 3.画图
|
|
|
+ const that = this;
|
|
|
+ listAllIndustry_run({
|
|
|
+ code: that.form.selectedCode,
|
|
|
+ year: that.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 = parseFloat(that.form.newMonthValue);
|
|
|
+ let total = [parseFloat(newMonthValue)]; //总值
|
|
|
+ const result = Object.values(
|
|
|
+ that.scoreData.reduce((acc, item) => {
|
|
|
+ const key = item.enterpriseName; // 根据企业名称分组
|
|
|
+ if (!acc[key]) {
|
|
|
+ acc[key] = { name: key, data: [], totalValue: 0, count: 0 }; // 创建对象并初始化
|
|
|
+ }
|
|
|
+ acc[key].data.push(item); // 添加到对应的类别中
|
|
|
+ acc[key].totalValue += item.totalIndustrialValue; // 累加 totalIndustrialValue
|
|
|
+ acc[key].count++; // 企业数 +1
|
|
|
+ return acc;
|
|
|
+ }, {})
|
|
|
+ ).map(({ name, data, totalValue, count }) => {
|
|
|
+ const totalIndustrialValue = totalValue / count; // 计算均值
|
|
|
+ total.push(totalIndustrialValue);
|
|
|
+ return { name, data, totalIndustrialValue }; // 返回结果
|
|
|
+ });
|
|
|
+ result.push({
|
|
|
+ name: "新企业",
|
|
|
+ data: [],
|
|
|
+ totalIndustrialValue: newMonthValue,
|
|
|
+ });
|
|
|
+ // 获取基础数据:最大值,最小值,平均值,标准差
|
|
|
+ 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)),
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 示例数据
|
|
|
+ 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 保持对称
|
|
|
+ }
|
|
|
+
|
|
|
+ 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; // 找到对应区间后可以跳出循环
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // // 确保处理最大值等于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.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]
|
|
|
+ },
|
|
|
+ },
|
|
|
+ yAxis: [
|
|
|
+ {
|
|
|
+ name: "企业数",
|
|
|
+ type: "value",
|
|
|
+ minInterval: 1,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "正态分布",
|
|
|
+ type: "value",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: `${that.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,去掉柱子上的数字
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "正态分布",
|
|
|
+ yAxisIndex: 1,
|
|
|
+ type: "line",
|
|
|
+ data: normalDistributionValues,
|
|
|
+ lineStyle: {
|
|
|
+ color: "#1a7cc8",
|
|
|
+ },
|
|
|
+ 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.selectedYear,
|
|
|
+ value: item.score.toFixed(2)
|
|
|
+ };
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 重置表单
|
|
|
+ resetForm() {
|
|
|
+ this.$refs.ruleForm.resetFields();
|
|
|
+ },
|
|
|
+ },
|
|
|
+ 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>
|