Extreme Programming

Wizards_of_codes 团队账号 2023-11-19 22:28:58

catalogs

  • About project
  • Demo Video
  • Users use links
  • Partial code
  • 登录
  • 注册
  • 利率计算器
  • 存款
  • 页面结构
  • 接口
  • 贷款
  • 页面结构
  • 接口
  • 科学计算器
  • connector
  • Interest Rate Calculator
  • controller
  • service
  • serviceImpl
  • mapper
  • mapper.xml
  • controller
  • service
  • serviceImpl
  • mapper
  • mapper.xml
  • interest_rate
  • calculator_history
  • Division of labor among members
  • Project Flowchart

Course for This AssignmentMIEC EE304FZ
Team NameWizards of codes
Assignment RequirementsExtreme Programming
Objectives of This AssignmentBack-end separation calculator programming with login module
Other ReferencesNA

About project

Links of the project

Demo Video

Log in to show history

img

Scientific Calculator

img

Interest Rate Calculator_Deposit

img

Interest Rate Calculator_Loan

img

Register and Login

img

http://8.134.172.149/

Partial code

// 配置为静态路由
  {
    path: '',
    component: Layout,
    redirect: 'calculator',
    children: [
      {
        path: 'calculator',
        component: () => import('@/views/calculator/index.vue'),
        name: 'Index',
        meta: { title: '科学计算器', icon: 'dashboard' }
      }
    ]
  },
  {
    path: '/interestrate',
    component: Layout,
    meta: { title: '利率计算器', icon: 'dashboard' },
    children: [
      {
        path: 'deposit',
        component: () => import('@/views/InterestRate/deposit/index.vue'),
        name: 'Deposit',
        meta: { title: '存款', icon: 'dashboard' }
      },
      {
        path: 'loans',
        component: () => import('@/views/InterestRate/loans/index.vue'),
        name: 'Loans',
        meta: { title: '贷款', icon: 'dashboard' }
      }
    ]
  },

登录

src\views\login.vue

<template>
  <div class="login">
    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
      <h3 class="title">小组作业</h3>
      <el-form-item prop="username">
        <el-input
          v-model="loginForm.username"
          type="text"
          auto-complete="off"
          placeholder="账号"
        >
          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input
          v-model="loginForm.password"
          type="password"
          auto-complete="off"
          placeholder="密码"
          @keyup.enter.native="handleLogin"
        >
          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
        </el-input>
      </el-form-item>
      <el-form-item prop="code" v-if="captchaEnabled">
        <el-input
          v-model="loginForm.code"
          auto-complete="off"
          placeholder="验证码"
          style="width: 63%"
          @keyup.enter.native="handleLogin"
        >
          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
        </el-input>
        <div class="login-code">
          <img :src="codeUrl" @click="getCode" class="login-code-img"/>
        </div>
      </el-form-item>
      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
      <el-form-item style="width:100%;">
        <el-button
          :loading="loading"
          size="medium"
          type="primary"
          style="width:100%;"
          @click.native.prevent="handleLogin"
        >
          <span v-if="!loading">登 录</span>
          <span v-else>登 录 中...</span>
        </el-button>
        <div style="float: right;" v-if="register">
          <router-link class="link-type" :to="'/register'">立即注册</router-link>
        </div>
      </el-form-item>
    </el-form>
    <!--  底部  -->
    <div class="el-login-footer">
      <span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
    </div>
  </div>
</template>

<script>
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt'

export default {
  name: "Login",
  data() {
    return {
      codeUrl: "",
      loginForm: {
        // username: "admin",
        username: "",
        // password: "admin123",
        password: "",
        rememberMe: false,
        code: "",
        uuid: ""
      },
      loginRules: {
        username: [
          { required: true, trigger: "blur", message: "请输入您的账号" }
        ],
        password: [
          { required: true, trigger: "blur", message: "请输入您的密码" }
        ],
        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
      },
      loading: false,
      // 验证码开关
      captchaEnabled: true,
      // 注册开关
      register: true,
      redirect: undefined
    };
  },
  watch: {
    $route: {
      handler: function(route) {
        this.redirect = route.query && route.query.redirect;
      },
      immediate: true
    }
  },
  created() {
    this.getCode();
    this.getCookie();
  },
  methods: {
    getCode() {
      getCodeImg().then(res => {
        this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
        if (this.captchaEnabled) {
          this.codeUrl = "data:image/gif;base64," + res.img;
          this.loginForm.uuid = res.uuid;
        }
      });
    },
    getCookie() {
      const username = Cookies.get("username");
      const password = Cookies.get("password");
      const rememberMe = Cookies.get('rememberMe')
      this.loginForm = {
        username: username === undefined ? this.loginForm.username : username,
        password: password === undefined ? this.loginForm.password : decrypt(password),
        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
      };
    },
    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true;
          if (this.loginForm.rememberMe) {
            Cookies.set("username", this.loginForm.username, { expires: 30 });
            Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
            Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
          } else {
            Cookies.remove("username");
            Cookies.remove("password");
            Cookies.remove('rememberMe');
          }
          this.$store.dispatch("Login", this.loginForm).then(() => {
            this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
          }).catch(() => {
            this.loading = false;
            if (this.captchaEnabled) {
              this.getCode();
            }
          });
        }
      });
    }
  }
};
</script>

<style rel="stylesheet/scss" lang="scss">
.login {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  background-image: url("../assets/images/login-background.jpg");
  background-size: cover;
}
.title {
  margin: 0px auto 30px auto;
  text-align: center;
  color: #707070;
}

.login-form {
  border-radius: 6px;
  background: #ffffff;
  width: 400px;
  padding: 25px 25px 5px 25px;
  .el-input {
    height: 38px;
    input {
      height: 38px;
    }
  }
  .input-icon {
    height: 39px;
    width: 14px;
    margin-left: 2px;
  }
}
.login-tip {
  font-size: 13px;
  text-align: center;
  color: #bfbfbf;
}
.login-code {
  width: 33%;
  height: 38px;
  float: right;
  img {
    cursor: pointer;
    vertical-align: middle;
  }
}
.el-login-footer {
  height: 40px;
  line-height: 40px;
  position: fixed;
  bottom: 0;
  width: 100%;
  text-align: center;
  color: #fff;
  font-family: Arial;
  font-size: 12px;
  letter-spacing: 1px;
}
.login-code-img {
  height: 38px;
}
</style>

注册

src\views\register.vue

<template>
  <div class="register">
    <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
      <h3 class="title">小组作业</h3>
      <el-form-item prop="username">
        <el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input
          v-model="registerForm.password"
          type="password"
          auto-complete="off"
          placeholder="密码"
          @keyup.enter.native="handleRegister"
        >
          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
        </el-input>
      </el-form-item>
      <el-form-item prop="confirmPassword">
        <el-input
          v-model="registerForm.confirmPassword"
          type="password"
          auto-complete="off"
          placeholder="确认密码"
          @keyup.enter.native="handleRegister"
        >
          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
        </el-input>
      </el-form-item>
      <el-form-item prop="code" v-if="captchaEnabled">
        <el-input
          v-model="registerForm.code"
          auto-complete="off"
          placeholder="验证码"
          style="width: 63%"
          @keyup.enter.native="handleRegister"
        >
          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
        </el-input>
        <div class="register-code">
          <img :src="codeUrl" @click="getCode" class="register-code-img"/>
        </div>
      </el-form-item>
      <el-form-item style="width:100%;">
        <el-button
          :loading="loading"
          size="medium"
          type="primary"
          style="width:100%;"
          @click.native.prevent="handleRegister"
        >
          <span v-if="!loading">注 册</span>
          <span v-else>注 册 中...</span>
        </el-button>
        <div style="float: right;">
          <router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
        </div>
      </el-form-item>
    </el-form>
    <!--  底部  -->
    <div class="el-register-footer">
      <span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
    </div>
  </div>
</template>

<script>
import { getCodeImg, register } from "@/api/login";

export default {
  name: "Register",
  data() {
    const equalToPassword = (rule, value, callback) => {
      if (this.registerForm.password !== value) {
        callback(new Error("两次输入的密码不一致"));
      } else {
        callback();
      }
    };
    return {
      codeUrl: "",
      registerForm: {
        username: "",
        password: "",
        confirmPassword: "",
        code: "",
        uuid: ""
      },
      registerRules: {
        username: [
          { required: true, trigger: "blur", message: "请输入您的账号" },
          { min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
        ],
        password: [
          { required: true, trigger: "blur", message: "请输入您的密码" },
          { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
        ],
        confirmPassword: [
          { required: true, trigger: "blur", message: "请再次输入您的密码" },
          { required: true, validator: equalToPassword, trigger: "blur" }
        ],
        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
      },
      loading: false,
      captchaEnabled: true
    };
  },
  created() {
    this.getCode();
  },
  methods: {
    getCode() {
      getCodeImg().then(res => {
        this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
        if (this.captchaEnabled) {
          this.codeUrl = "data:image/gif;base64," + res.img;
          this.registerForm.uuid = res.uuid;
        }
      });
    },
    handleRegister() {
      this.$refs.registerForm.validate(valid => {
        if (valid) {
          this.loading = true;
          register(this.registerForm).then(res => {
            const username = this.registerForm.username;
            this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
              dangerouslyUseHTMLString: true,
              type: 'success'
            }).then(() => {
              this.$router.push("/login");
            }).catch(() => {});
          }).catch(() => {
            this.loading = false;
            if (this.captchaEnabled) {
              this.getCode();
            }
          })
        }
      });
    }
  }
};
</script>

<style rel="stylesheet/scss" lang="scss">
.register {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  background-image: url("../assets/images/login-background.jpg");
  background-size: cover;
}
.title {
  margin: 0px auto 30px auto;
  text-align: center;
  color: #707070;
}

.register-form {
  border-radius: 6px;
  background: #ffffff;
  width: 400px;
  padding: 25px 25px 5px 25px;
  .el-input {
    height: 38px;
    input {
      height: 38px;
    }
  }
  .input-icon {
    height: 39px;
    width: 14px;
    margin-left: 2px;
  }
}
.register-tip {
  font-size: 13px;
  text-align: center;
  color: #bfbfbf;
}
.register-code {
  width: 33%;
  height: 38px;
  float: right;
  img {
    cursor: pointer;
    vertical-align: middle;
  }
}
.el-register-footer {
  height: 40px;
  line-height: 40px;
  position: fixed;
  bottom: 0;
  width: 100%;
  text-align: center;
  color: #fff;
  font-family: Arial;
  font-size: 12px;
  letter-spacing: 1px;
}
.register-code-img {
  height: 38px;
}
</style>

利率计算器

存款

页面结构

src\views\InterestRate\deposit\index.vue

<template>
  <div class="container">
    <el-form ref="form" :model="form" label-width="80px" :rules="rules">
      <el-form-item label="存款金额" prop="value">
        <el-input v-model="form.value"></el-input>
      </el-form-item>
      <el-form-item label="存款方式">
        <el-select v-model="form.mode" placeholder="请选择存款方式" @change="modeChange">
          <el-option label="活期" value="1"></el-option>
          <el-option label="定期" value="2"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="存款利率">
        <el-input v-model="form.interestRate" disabled>
          <template slot="prepend">
            <el-button @click="updateList">修改利率</el-button>
          </template>
          <template slot="append">%</template>
        </el-input>
      </el-form-item>
      <el-form-item label="存款期限">
        <el-select v-model="form.date" placeholder="请选择存款期限" :disabled="form.mode === '1' ? true : false"
          @change="dateChange">
          <el-option label="三个月" value="3m"></el-option>
          <el-option label="半年" value="6m"></el-option>
          <el-option label="一年" value="1y"></el-option>
          <el-option label="二年" value="2y"></el-option>
          <el-option label="三年" value="3y"></el-option>
          <el-option label="五年" value="5y"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="利息">
        <el-input v-model="form.result" disabled></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSubmit">立即计算</el-button>
      </el-form-item>
    </el-form>
    <!-- 利率 -->
    <el-dialog title="存款利率" :visible.sync="dialogVisible" width="40%">
      <el-table :data="tableData" style="width: 100%">
        <el-table-column prop="name" label="类型" width="180">
        </el-table-column>
        <el-table-column prop="value" label="利率" width="180">
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button type="text" @click="update(scope.row)">修改</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <!-- 修改利率 -->
    <el-dialog title="修改利率" :visible.sync="updateDialogVisible" width="40%">
      <el-form ref="form" :model="updateForm" label-width="80px">
        <el-form-item label="利率类型">
          <el-input v-model="updateForm.name"></el-input>
        </el-form-item>
        <el-form-item label="利率">
          <el-input v-model="updateForm.value"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="updateEnter">确认</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
import { update, list, get } from '@/api/InterestRate/deposit.js'
export default {
  data() {
    return {
      form: {
        value: '',
        mode: '1',
        interestRate: '',
        date: '',
        result: ''
      },
      rules: {
        value: [
          { required: true, message: '请输入金额', trigger: 'blur' },
        ],
        date: [
          { required: true, message: '请选择贷款期限', trigger: 'blur' },
        ]
      },
      dialogVisible: false,
      updateDialogVisible: false,
      tableData: [],
      updateForm: {
        id: '',
        value: '',
        name: ''
      }
    }
  },
  mounted() {
    this.get('hq')
  },
  methods: {
    async list() {
      const { data } = await list()
      this.tableData = data;
    },
    onSubmit() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          if (this.form.mode === '2' && this.form.date === '') {
            this.$message({
              type: 'warning',
              message: '请选择存款期限'
            })
            return false
          }
          this.form.result = this.form.value * this.form.interestRate * 0.01
        }
      });
    },
    updateList() {
      this.list()
      this.dialogVisible = true
    },
    async update(data) {
      const { msg } = await update(data);
      this.updateDialogVisible = false
      this.$message({
        type: 'success',
        message: msg
      })
    },
    update(row) {
      const { name, value, id } = row
      this.updateForm.name = name
      this.updateForm.value = value
      this.updateForm.id = id
      this.updateDialogVisible = true
    },
    async updateEnter() {
      const result = await update(this.updateForm)
      this.list()
      this.updateDialogVisible = false
      this.$message({
        type: 'success',
        message: result.msg
      })
    },
    modeChange(mode) {
      if (mode === '1') {
        this.get('hq')
        return
      }
      this.form.interestRate = ''
    },
    async get(date) {
      const { data } = await get(date)
      this.form.interestRate = data.value
    },
    dateChange(date) {
      this.get(date)
    }
  }
}
</script>

<style scoped>
.container {
  width: 500px;
  padding: 20px;
  background-color: rgba(242, 231, 231, 0.627);
  border-radius: 20px;
  margin: 20px auto;
}
</style>

接口

src\api\InterestRate\deposit.js

import request from '@/utils/request'

export function update(data) {
  return request({
    url: '/interestrate/deposit',
    method: 'put',
    data
  })
}

export function list() {
  return request({
    url: '/interestrate/deposit',
  })
}

export function get(date) {
  return request({
    url: `/interestrate/deposit/${date}`
  })
}

贷款

页面结构

src\views\InterestRate\loans\index.vue

<template>
  <div class="container">
    <el-form ref="form" :model="form" label-width="80px" :rules="rules">
      <el-form-item label="贷款金额" prop="value">
        <el-input v-model="form.value"></el-input>
      </el-form-item>
      <el-form-item label="贷款利率">
        <el-input v-model="form.interestRate" disabled>
          <template slot="prepend">
            <el-button @click="updateList">修改利率</el-button>
          </template>
          <template slot="append">%</template>
        </el-input>
      </el-form-item>
      <el-form-item label="贷款期限" prop="date">
        <el-select v-model="form.date" placeholder="请选择贷款期限" @change="dateChange">
          <el-option label="六个月" value="6m"></el-option>
          <el-option label="一年" value="1y"></el-option>
          <el-option label="一至三年" value="1y-3y"></el-option>
          <el-option label="三至五年" value="3y-5y"></el-option>
          <el-option label="五年" value="5y"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="利息">
        <el-input v-model="form.result" disabled></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSubmit">立即计算</el-button>
      </el-form-item>
    </el-form>
    <!-- 利率 -->
    <el-dialog title="贷款利率" :visible.sync="dialogVisible" width="40%">
      <el-table :data="tableData" style="width: 100%">
        <el-table-column prop="name" label="类型" width="180">
        </el-table-column>
        <el-table-column prop="value" label="利率" width="180">
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button type="text" @click="update(scope.row)">修改</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <!-- 修改利率 -->
    <el-dialog title="修改利率" :visible.sync="updateDialogVisible" width="30%">
      <el-form ref="form" :model="updateForm" label-width="80px">
        <el-form-item label="利率类型">
          <el-input v-model="updateForm.name"></el-input>
        </el-form-item>
        <el-form-item label="利率">
          <el-input v-model="updateForm.value"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="updateEnter">确认</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
import { update, list, get } from '@/api/InterestRate/loans.js'
export default {
  data() {
    return {
      form: {
        value: '',
        interestRate: '',
        date: '',
        result: ''
      },
      rules: {
        value: [
          { required: true, message: '请输入金额', trigger: 'blur' },
        ],
        date: [
          { required: true, message: '请选择贷款期限', trigger: 'blur' },
        ]
      },
      dialogVisible: false,
      updateDialogVisible: false,
      tableData: [],
      updateForm: {
        id: '',
        value: '',
        name: ''
      }
    }
  },
  methods: {
    async list() {
      const { data } = await list()
      this.tableData = data;
    },
    updateList() {
      this.list();
      this.dialogVisible = true;
    },
    onSubmit() {
      this.$refs.form.validate((valid) => {
        if (valid) {
          this.form.result = this.form.value * this.form.interestRate * 0.01
        }
      });
    },
    update(row) {
      const { name, value, id } = row
      this.updateForm.name = name
      this.updateForm.value = value
      this.updateForm.id = id
      this.updateDialogVisible = true
    },
    async updateEnter() {
      const result = await update(this.updateForm)
      this.list()
      this.updateDialogVisible = false
      this.$message({
        type: 'success',
        message: result.msg
      })
    },
    async get(date) {
      const { data } = await get(date)
      this.form.interestRate = data.value
    },
    dateChange(date) {
      this.get(date)
    }
  }
}
</script>

<style scoped>
.container {
  width: 500px;
  padding: 20px;
  background-color: rgba(242, 231, 231, 0.627);
  border-radius: 20px;
  margin: 20px auto;
}
</style>

接口

import request from '@/utils/request'

export function update(data) {
  return request({
    url: '/interestrate/loans',
    method: 'put',
    data
  })
}

export function list() {
  return request({
    url: '/interestrate/loans',
  })
}

export function get(date) {
  return request({
    url: `/interestrate/loans/${date}`
  })
}

科学计算器

<template>
  <div class="container">
    <div class="main">
      <div class="top">
        <span class="expression">
          {{ expression }}
        </span>
      </div>
      <div class="body">
        <div class="row">
          <div class="item item-type2" @click="clickItem('(')">(</div>
          <div class="item item-type2" @click="clickItem(')')">)</div>
          <div class="item item-type2" @click="clickItem('%')">%</div>
          <div class="item item-type3" @click="clickItem('del')">DEL</div>
          <div class="item item-type3" @click="clickItem('ac')">AC</div>
          <div class="item-count item-type5">已计算:{{ count }}</div>
        </div>
        <div class="row">
          <div class="item item-type1" @click="clickItem('7')">7</div>
          <div class="item item-type1" @click="clickItem('8')">8</div>
          <div class="item item-type1" @click="clickItem('9')">9</div>
          <div class="item item-type2" @click="clickItem('÷')">÷</div>
          <div class="item item-type2" @click="clickItem('sin()')">sin</div>
          <div class="item item-type2" @click="clickItem('pow()')">pow</div>
        </div>
        <div class="row">
          <div class="item item-type1" @click="clickItem('4')">4</div>
          <div class="item item-type1" @click="clickItem('5')">5</div>
          <div class="item item-type1" @click="clickItem('6')">6</div>
          <div class="item item-type2" @click="clickItem('x')">x</div>
          <div class="item item-type2" @click="clickItem('cos()')">cos</div>
          <div class="item item-type2" @click="clickItem('ln()')">ln</div>
        </div>
        <div class="row">
          <div class="item item-type1" @click="clickItem('1')">1</div>
          <div class="item item-type1" @click="clickItem('2')">2</div>
          <div class="item item-type1" @click="clickItem('3')">3</div>
          <div class="item item-type2" @click="clickItem('-')">-</div>
          <div class="item item-type2" @click="clickItem('tan()')">tan</div>
          <div class="item item-type2" @click="clickItem('√()')"></div>
        </div>
        <div class="row">
          <div class="item item-type1" @click="clickItem('0')">0</div>
          <div class="item item-type1" @click="clickItem('.')">.</div>
          <div class="item item-type4" @click="clickItem('=')">=</div>
          <div class="item item-type2" @click="clickItem('+')">+</div>
          <div class="item item-type1" @click="clickItem('π')">π</div>
          <div class="item item-type1" @click="clickItem('e')">e</div>
        </div>
      </div>
    </div>
    <div class="list">
      <el-table :data="tableData" style="width: 100%" @row-dblclick="clickRow">
        <el-table-column label="历史记录" width="180">
          <template slot-scope="scope">
            <el-tooltip effect="dark" content="双击列表项可替换输入框内容" placement="top">
              <span>{{ scope.row.expression }}</span>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>
    </div>
  </div>
</template>

<script>
import { calculate, getCount, getHistory } from '@/api/calculator.js';
export default {
  data() {
    return {
      expression: '',
      tableData: [],
      count: 0
    }
  },
  mounted() {
    this.getCount()
    this.getHistory()
  },
  methods: {
    clickItem(value) {
      if (value === '=') {
        this.calculate()
        return
      }
      if (value === 'del') {
        this.expression = this.expression.substring(0, this.expression.length - 1)
        return
      }
      if (value === 'ac') {
        this.expression = ''
        return
      }
      this.expression = this.expression + value
    },
    async calculate() {
      const { data } = await calculate(this.expression)
      this.expression = data
      this.getCount()
      this.getHistory()
    },
    async getCount() {
      const { data } = await getCount()
      this.count = data
    },
    async getHistory() {
      const { data } = await getHistory()
      this.tableData = data
    },
    clickRow(row) {
      this.expression = row.expression
    }
  }
}
</script>

<style scoped>
.container {
  width: 800px;
  height: 440px;
  padding: 20px;
  border-radius: 20px;
  display: flex;
  justify-content: space-between;
  background-color: rgba(242, 231, 231, 0.627);
  margin: 20px auto;
}

.main {
  width: 600px;
  margin-right: 20px;
}

.top {
  widows: 550px;
  height: 100px;
  border: 2px solid rgba(174, 169, 169, 0.627);
  border-radius: 10px;
  background-color: #fff;
  line-height: 100px;
}

.expression {
  font-size: 24px;
}

.row {
  width: 550px;
  display: flex;
  justify-content: space-between;
  margin: 10px 0;
}

.item {
  width: 70px;
  height: 50px;
  border-radius: 10px;
  border: 2px solid rgba(174, 169, 169, 0.627);
  text-align: center;
  line-height: 50px;
  font-size: 20px;
  font-weight: 700;
}

.item-count {
  width: 70px;
  height: 50px;
  border-radius: 10px;
  line-height: 50px;
  border: 2px solid rgba(174, 169, 169, 0.627);
  text-align: center;
  font-size: 10px;
  font-weight: 700;
}

.item-type1 {
  background-color: #fff;
}

.item-type2 {
  background-color: rgba(174, 169, 169, 0.627);
}

.item-type3 {
  background-color: #ffb52f;
}

.item-type4 {
  background-color: #4f6ef2;
}

.item-type5 {
  background-color: rgb(79, 242, 171);
}

.list {
  width: 200px;
  border: 2px solid rgba(174, 169, 169, 0.627);
  border-radius: 10px;
  overflow: auto;
}
</style>

connector

import request from '@/utils/request'

export function calculate(data) {
  return request({
    url: `/calculator`,
    method: 'post',
    data
  })
}

export function getCount() {
  return request({
    url: '/calculator/count'
  })
}

export function getHistory(){
  return request({
    url: '/calculator/history'
  })
}

Interest Rate Calculator

controller

package com.ruoyi.web.controller.calculator;

import com.ruoyi.calculator.domain.InterestRate;
import com.ruoyi.calculator.service.InterestRateService;
import com.ruoyi.common.core.domain.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/interestrate")
public class InterestRateController {
    @Autowired
    private InterestRateService interestRateService;

    @GetMapping("/deposit")
    public AjaxResult listDeposit(){
        List<InterestRate> list = interestRateService.listDeposit();
        return AjaxResult.success(list);
    }

    @GetMapping("/deposit/{date}")
    public AjaxResult getDeposit(@PathVariable String date) {
        InterestRate interestRate = interestRateService.getDeposit(date);
        return AjaxResult.success(interestRate);
    }

    @PutMapping("/deposit")
    public AjaxResult updateDeposit(@RequestBody InterestRate interestRate){
        interestRateService.updateDeposit(interestRate);
        return AjaxResult.success("修改成功");
    }

    @GetMapping("/loans")
    public AjaxResult listLoans(){
        List<InterestRate> list = interestRateService.listLoans();
        return AjaxResult.success(list);
    }

    @GetMapping("/loans/{date}")
    public AjaxResult getLoans(@PathVariable String date) {
        InterestRate interestRate = interestRateService.getLoans(date);
        return AjaxResult.success(interestRate);
    }

    @PutMapping("/loans")
    public AjaxResult updateLoans(@RequestBody InterestRate interestRate){
        interestRateService.updateLoans(interestRate);
        return AjaxResult.success("修改成功");
    }
}

service

package com.ruoyi.calculator.service;

import com.ruoyi.calculator.domain.InterestRate;

import java.util.List;

public interface InterestRateService {
    List<InterestRate> listDeposit();

    void updateDeposit(InterestRate interestRate);

    List<InterestRate> listLoans();

    void updateLoans(InterestRate interestRate);

    InterestRate getDeposit(String date);

    InterestRate getLoans(String date);
}

serviceImpl

package com.ruoyi.calculator.service.impl;

import com.ruoyi.calculator.domain.InterestRate;
import com.ruoyi.calculator.mapper.InterestRateMapper;
import com.ruoyi.calculator.service.InterestRateService;
import com.ruoyi.common.constant.CalculateConstants;
import com.ruoyi.common.context.BaseContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class InterestRateServiceImpl implements InterestRateService {

    @Autowired
    private InterestRateMapper interestRateMapper;

    @Override
    public List<InterestRate> listDeposit() {
        return interestRateMapper.list(CalculateConstants.DEPOSIT, BaseContext.getCurrentId());
    }

    @Override
    public void updateDeposit(InterestRate interestRate) {
        interestRateMapper.update(interestRate);
    }

    @Override
    public List<InterestRate> listLoans() {
        return interestRateMapper.list(CalculateConstants.LOANS, BaseContext.getCurrentId());
    }

    @Override
    public void updateLoans(InterestRate interestRate) {
        interestRateMapper.update(interestRate);
    }

    @Override
    public InterestRate getDeposit(String date) {
        InterestRate interestRate = interestRateMapper.get(CalculateConstants.DEPOSIT, date, BaseContext.getCurrentId());
        return interestRate;
    }

    @Override
    public InterestRate getLoans(String date) {
        InterestRate interestRate = interestRateMapper.get(CalculateConstants.LOANS, date, BaseContext.getCurrentId());
        return interestRate;
    }
}

mapper

package com.ruoyi.calculator.mapper;

import com.ruoyi.calculator.domain.InterestRate;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface InterestRateMapper {
    List<InterestRate> list(@Param("type") int type, @Param("userId") long userId);

    void update(@Param("interestRate") InterestRate interestRate);

    void init(long userId);

    InterestRate get(@Param("type") Integer type, @Param("date") String date, @Param("userId") Long currentId);
}

mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.calculator.mapper.InterestRateMapper">
    <insert id="init">
        insert into interest_rate (user_id, name, tag, type, value)
        values (#{userId}, '活期', 'hq', 1, 0.50),
               (#{userId}, '三个月', '3M', 1, 2.85),
               (#{userId}, '六个月', '6M', 1, 3.05),
               (#{userId}, '一年', '1y', 1, 3.25),
               (#{userId}, '二年', '2y', 1, 4.15),
               (#{userId}, '三年', '3y', 1, 4.75),
               (#{userId}, '五年', '5y', 1, 5.25),
               (#{userId}, '六个月', '6M', 2, 5.85),
               (#{userId}, '一年', '1y', 2, 6.31),
               (#{userId}, '一至三年', '1y-3y', 2, 6.40),
               (#{userId}, '三至五年', '3y-5y', 2, 6.65),
               (#{userId}, '五年', '5y', 2, 6.80);
    </insert>
    <update id="update">
        update interest_rate
        set name  = #{interestRate.name},
            value = #{interestRate.value}
        where id = #{interestRate.id}
    </update>

    <select id="list" resultType="com.ruoyi.calculator.domain.InterestRate">
        select * from interest_rate
        where type = #{type} and user_id = #{userId}
    </select>
    <select id="get" resultType="com.ruoyi.calculator.domain.InterestRate">
        select *
        from interest_rate
        where
            type = #{type}
        and user_id = #{userId}
          and tag = #{date}
    </select>
</mapper>

controller

package com.ruoyi.web.controller.calculator;

import com.ruoyi.calculator.domain.CalculatorHistory;
import com.ruoyi.calculator.service.CalculatorService;
import com.ruoyi.common.core.domain.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/calculator")
public class CalculatorController {

    @Autowired
    private CalculatorService calculatorService;

    @PostMapping
    public AjaxResult calculate(@RequestBody String expression) {
        String result = calculatorService.calculate(expression);
        return AjaxResult.success((Object) result);
    }

    @GetMapping("/count")
    public AjaxResult getCount() {
        long count = calculatorService.getCuont();
        return AjaxResult.success(count);
    }

    @GetMapping("/history")
    public AjaxResult getHistory() {
        List<CalculatorHistory> list = calculatorService.getHistory();
        return AjaxResult.success(list);
    }
}

service

package com.ruoyi.calculator.service;

import com.ruoyi.calculator.domain.CalculatorHistory;

import java.util.List;

public interface CalculatorService {
    String calculate(String expression);

    long getCuont();

    List<CalculatorHistory> getHistory();
}

serviceImpl

package com.ruoyi.calculator.service.impl;

import com.ruoyi.calculator.domain.CalculatorHistory;
import com.ruoyi.calculator.mapper.CalculatorMapper;
import com.ruoyi.calculator.service.CalculatorService;
import com.ruoyi.common.context.BaseContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.List;

@Service
public class CalculatorServiceImpl implements CalculatorService {

    @Autowired
    private CalculatorMapper calculatorMapper;

    @Override
    public String calculate(String expression) {
        calculatorMapper.add(BaseContext.getCurrentId(), expression);
        expression = expression
                .replaceAll("x", "*")
                .replaceAll("÷", "/")
                .replaceAll("π", "Math.PI")
                .replaceAll("sin", "Math.sin")
                .replaceAll("cos", "Math.cos")
                .replaceAll("tan", "Math.tan")
                .replaceAll("√", "Math.sqrt")
                .replaceAll("e", "Math.E")
                .replaceAll("ln", "Math.log")
                .replaceAll("pow", "Math.pow");
        String result;
        try {
            result = execute(expression);
        } catch (ScriptException e) {
            result = "ERROR";
        }
        return result;
    }

    @Override
    public long getCuont() {
        return calculatorMapper.count(BaseContext.getCurrentId());
    }

    @Override
    public List<CalculatorHistory> getHistory() {
        return calculatorMapper.listHistory(BaseContext.getCurrentId());
    }

    private String execute(String str) throws ScriptException {
        ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
        return jse.eval(str).toString();
    }
}

mapper

package com.ruoyi.calculator.mapper;

import com.ruoyi.calculator.domain.CalculatorHistory;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface CalculatorMapper {
    long count(long userId);
    void add(@Param("userId") long userId, @Param("expression") String expression);

    List<CalculatorHistory> listHistory(Long userId);
}

mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.calculator.mapper.CalculatorMapper">
    <insert id="add">
        insert into calculator_history (user_id, expression)
            value (#{userId}, #{expression})
    </insert>

    <select id="count" resultType="java.lang.Long">
        select count(id)
        from calculator_history
        where user_id = #{userId}
    </select>
    <select id="listHistory" resultType="com.ruoyi.calculator.domain.CalculatorHistory">
        select * from calculator_history
        where user_id = #{userId}
        order by id desc
    </select>
</mapper>

interest_rate

字段名数据类型约束备注
idbigintprimary key
user_idbigintnot null用户id
namevarchar(20)not null利率名称
tagvarchar(20)not null利率标识
valuedecimal(5,2)not null利率
typeintnot null利率类型。
1:存款利率
2:贷款利率

calculator_history

字段名数据类型约束备注
idbigintprimary key
user_idbigintnot null用户id
expressionvarchar(255)not null表达式

s-3-mapper.dtd">


insert into calculator_history (user_id, expression)
value (#{userId}, #{expression})

<select id="count" resultType="java.lang.Long">
    select count(id)
    from calculator_history
    where user_id = #{userId}
</select>
<select id="listHistory" resultType="com.ruoyi.calculator.domain.CalculatorHistory">
    select * from calculator_history
    where user_id = #{userId}
    order by id desc
</select>
```

Division of labor among members

Student IDWork DescriptionContribution
832101227Front-end: routing, login, registration15%
832101224Frontend: Interest Rate Calculator - Loan - Page Structure5%
832101212Frontend: Interest Rate Calculator - Loan - Interface9%
832101213Frontend: Scientific Calculator - page structure5%
832101208Backend: Database Front-end: interest rate calculator - deposits - page structure Frontend: Interest Rate Calculator - Deposit - Interface15%
832101226Frontend: Scientific Calculator - Interface5%
832101228Backend: Login Registration Backend: Scientific Calculator - mapper7%
832101218Backend : Interest Rate Calculator - controller Backend: Scientific Calculator - service7%
832101216Backend : Interest Rate Calculator - service Backend : Interest Rate Calculator - servicelmpl7%
832101222Backend: Scientific Calculator -- mapper.xml9%
832101205Backend : Interest Rate Calculator - mapper Backend : Interest Rate Calculator -- mapper.xml9%
832101206Backend: Interest Rate Calculator - service Backend : Scientific Calculator -- servicelmpl9%

Project Flowchart

img

...全文
56 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
832101215陈思晟 2023-11-20
  • 打赏
  • 举报
回复

82101218写错了,应为832101215

174

社区成员

发帖
与我相关
我的任务
社区描述
梅努斯软件工程
软件工程 高校 福建省·福州市
社区管理员
  • LinQF39
  • Jcandc
  • 助教-陈锦辉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧