业务介绍

公司开会说需要一个计算播种量的小工具,其实各种参数关系比较简单,估计正常的农民很少会用工具来计算,因为早就熟练了.目前拿到的需求中,参数有以下几个(直接贴自定义的变量了):

  • density: 密度,
  • KWEI: 百粒重(g),
  • preHectareWeight: 公顷用量(Kg),
  • ridgingSpacing: 垄距cm,
  • ridgingSpacingNum: 垄距米间粒数,
  • spacing: 株距cm
  • toFixedNum: 小数点保留位数

其中toFixedNum:(小数点保留位数)是自己加的,用来测试精度.几个参数之间的计算关系已知的有:

  • 公顷用量 = 密度*百粒重/10
  • 垄距米间粒数 = (垄距/100)*密度
  • 株距(cm) = 100/((垄距/100)*密度)
    感觉垄距和密度应该是有换算关系的,但是没有给我.所以暂时无法联动了

项目搭建

为了省去UI,直接用vue的element-ui框架,计算部分使用了math.js库.初始化项目时候加上了vuex等,原因是通过之前保存的模版,省去了自定义的麻烦.

实现部分

路由router.js

router中使用hash模式,直接做了个跳转.如下:

{
    path: "/kftools",
    name: "kftools",
    component: { render: h => h("router-view") },
    children: [
      {
        path: "/kftools/cornsow",
        name: "",
        component: () =>
          import(/* webpackChunkName: "kftools" */ "../views/CornSowTools.vue")
      }
    ]
  }

math.js配置

在使用math.js库的时候直接丢进了全局,main.js的内容如下:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

import "element-ui/lib/theme-chalk/index.css";

Vue.config.productionTip = false;

import * as math from "mathjs";
Vue.prototype.$math = math;

import {
  Form,
  FormItem,
  Input,
  Button,
  Row,
  Col,
  Select,
  Option
} from "element-ui";

Vue.use(Form);
Vue.use(Input);
Vue.use(Button);
Vue.use(FormItem);
Vue.use(Row);
Vue.use(Col);
Vue.use(Select);
Vue.use(Option);

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount("#app");

页面组件

组件起名叫CornSowTools.vue,代码如下:

<template>
  <div>
    <el-col :span="7">
      <el-row>
        <el-form
          :model="ruleForm"
          status-icon
          :rules="rules"
          ref="ruleForm"
          label-width="100px"
          class="demo-ruleForm"
        >
          <el-form-item label="小数点" prop="toFixedNum" style="width:150">
            <el-select v-model="ruleForm.toFixedNum" placeholder="请选择">
              <el-option
                v-for="item in options"
                :key="item"
                :label="item"
                :value="item"
              >
              </el-option>
            </el-select>
            默认2位
          </el-form-item>
          <el-form-item label="密度" prop="density">
            <el-input v-model="ruleForm.density"></el-input>
          </el-form-item>
          <el-form-item label="百粒重(g)" prop="KWEI">
            <el-input v-model="ruleForm.KWEI"></el-input>
          </el-form-item>
          <el-form-item label="公顷用量(Kg)" prop="preHectareWeight">
            <el-input
              :disabled="true"
              v-model="ruleForm.preHectareWeight"
              placeholder="密度*百粒重/10"
            ></el-input>
          </el-form-item>
          <el-form-item label="垄距(cm)" prop="ridgingSpacing">
            <el-input
              v-model="ruleForm.ridgingSpacing"
              placeholder="65"
            ></el-input
            >{{ "垄距和密度的换算关系不知道" }}
          </el-form-item>
          <el-form-item label="垄距米间粒数" prop="ridgingSpacingNum">
            <el-input
              :disabled="true"
              v-model="ruleForm.ridgingSpacingNum"
              placeholder="(垄距/100)*密度"
            ></el-input>
          </el-form-item>
          <el-form-item label="株距(cm)" prop="spacing">
            <el-input
              :disabled="true"
              v-model="ruleForm.spacing"
              placeholder="100/((垄距/100)*密度)"
            ></el-input>
          </el-form-item>

          <el-form-item>
            <el-button type="primary" @click="submitForm('ruleForm')"
              >提交</el-button
            >
            <el-button @click="resetForm('ruleForm')">重置</el-button>
          </el-form-item>
        </el-form>
      </el-row>
    </el-col>
  </div>
</template>

<script>
import { create, all } from "mathjs/number";

export default {
  data() {
    const validateNull = (rule, value, callback) => {
      if (value === "") {
        callback(new Error(rule.messageNull));
      } else {
        callback();
      }
    };
    const validateNumber = (rule, value, callback) => {
      const reg = /^[0-9]+.?[0-9]*$/;
      if (!reg.test(value)) {
        callback(new Error(rule.message));
      } else {
        callback();
      }
    };

    return {
      /**
       *  
       * density: 密度,
        KWEI: 百粒重(g),
        preHectareWeight: 公顷用量(Kg),
        ridgingSpacing: 垄距cm,
        ridgingSpacingNum: 垄距米间粒数,
        spacing: 株距cm
        toFixedNum: 小数点保留位数
       */
      ruleForm: {
        density: "",
        KWEI: "",
        preHectareWeight: "",
        ridgingSpacing: 65,
        ridgingSpacingNum: "",
        spacing: null,
        toFixedNum: ""
      },
      rules: {
        density: [
          {
            required: true,
            validator: validateNull,
            trigger: "blur",
            messageNull: "密度不能为空,请输入密度"
          },
          {
            type: "number",
            validator: validateNumber,
            message: "密度必须为正数值"
          }
        ],
        KWEI: [
          {
            required: true,
            validator: validateNull,
            trigger: "blur",
            messageNull: "百粒重不能为空,请输入百粒重"
          },
          {
            type: "number",
            validator: validateNumber,
            message: "百粒重必须为正数值"
          }
        ],
        ridgingSpacing: [
          {
            required: true,
            validator: validateNull,
            trigger: "blur",
            messageNull: "垄距不能为空,请输入垄距"
          },
          {
            type: "number",
            validator: validateNumber,
            message: "垄距必须为正数值"
          }
        ]
      },

      options: this.$math.range(0, 4, true)._data
    };
  },
  methods: {
    roundFixedNum(value, n) {
      return Math.round(value * Math.pow(10, n)) / Math.pow(10, n);
    },
    submitForm(formName) {
      if (this.ruleForm.toFixedNum === "") {
        this.ruleForm.toFixedNum = 2;
      }
      this.$math = create(all);
      this.$refs[formName].validate(valid => {
        if (valid) {
          this.ruleForm.preHectareWeight = this.roundFixedNum(
            this.$math
              .chain(this.ruleForm.density)
              .multiply(this.ruleForm.KWEI)
              .divide(10)
              .done(),
            this.ruleForm.toFixedNum
          );

          const temp = this.$math
            .chain(this.ruleForm.ridgingSpacing)
            .divide(100)
            .multiply(this.ruleForm.density)
            .done();

          this.ruleForm.ridgingSpacingNum = this.roundFixedNum(
            temp,
            this.ruleForm.toFixedNum
          );
          this.ruleForm.spacing = this.roundFixedNum(
            this.$math
              .chain(100)
              .divide(temp)
              .done(),
            this.ruleForm.toFixedNum
          );
        } else {
          alert("error:错误提示");
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    }
  }
};
</script>

TIPS

自定义校验

在使用自定义校验规则时,如以下示例中:

 rules: {
     density: [
        {
          required: true,
          validator: validateNull,
          trigger: "blur",
          messageNull: "密度不能为空,请输入密度"
        },
        {
          type: "number",
          validator: validateNumber,
          message: "密度必须为正数值"
        }
      ],
     ...略
      ]
    },

messageNull为自定义的一个属性,在rule的对象中,已经有message这个属性可以用.对应初始化在data()中的校验规则如下,分别用来判断""和是否为数字.

const validateNull = (rule, value, callback) => {
      if (value === "") {
        callback(new Error(rule.messageNull));
      } else {
        callback();
      }
    };
 const validateNumber = (rule, value, callback) => {
    const reg = /^[0-9]+.?[0-9]*$/;
    if (!reg.test(value)) {
      callback(new Error(rule.message));
    } else {
      callback();
    }
  };

math.js的常用方法

API地址

  • math.sqrt(4) 开方
  • math.add( ) 加
  • math.subtract( )减
  • math.divide( ) 除
  • math.multiply( )乘

进行链式操作时可以如下(这里的math放到了vue的全局中,正式使用时注意改代码)

const tmp0 = 9000/100*2
const tmp1 = this.$math.chain(9000)
              .divide(100)
              .multiply(2)
              .done(),

在math.js中要保留多少个数字可以使用math.format(),官方示例如下:

const ans = math.add(0.1, 0.2)     //  0.30000000000000004
math.format(ans, {precision: 14})  // '0.3'

本次代码中如果使用此种需求,可以这样:

 this.ruleForm.ridgingSpacingNum = this.$math.format(
          this.$math
             .chain(this.ruleForm.ridgingSpacing)
             .divide(100)
             .multiply(this.ruleForm.density)
             .done(),
           4
         );

或者

this.ruleForm.ridgingSpacingNum = this.$math.format(
this.$math
  .chain(this.ruleForm.ridgingSpacing)
  .divide(100)
  .multiply(this.ruleForm.density)
  .done(),
{ precision: 14 }
);

在初始化下拉选择保留几位小数时,偷懒了下,直接生成数组,如下.其中_data的内部属性是Array类型,而直接返回的类型是Matrix,这块和官网的API说明有歧义,不知道为什么.

this.$math.range(0, 4, true)._data

小数点精度

开始使用toFixed来判断精度,但是后来想起来这个是银行的精度计算.目前的需求是完全的四舍五入.所以只能使用Math.round()来处理,所以定义了一个方法,根据选择的精度,来处理响应的数据,代码如下:

/**
* value 参数数值
* n 保留的小数点位数
*/
roundFixedNum(value, n) {
return Math.round(value * Math.pow(10, n)) / Math.pow(10, n);
},
posted on 2020-04-21 22:07  学业未成  阅读(276)  评论(0编辑  收藏  举报