目录
1.项目简介 2
1.1设计背景 3
1.2软件架构 3
1.3所用技术 3
1.4功能模块 4
1.5需求分析 4
1.5.1 需求描述 4
1.5.2 用例建模 4
1.5.1人事信息管理 4
1.5.2货物信息管理 5
1.5.3订单信息管理 6
1.6用例描述 7
3.系统设计 8
3.1数据库设计 8
3.2模块设计 9
3.2.1用户管理类图 9
3.2.2订单管理类图 10
3.2.3用户管理操作流程 10
3.2.4 角色管理操作流程 13
3.3项目设计 13
3.3.1项目配置 13
3.3.2mybatis拦截器 18
3.3.3发送邮件组件 21
3.3.4Shiro安全配置 23
3.3.5swagger配置 27
3.3.6业务代码 28
3.3.7前端代码 31
4.项目部署 38
4.1 数据库配置 38
4.2. 后端配置 40
4.3. 前端配置 43
5.项目截图 45
5.1 登录界面 45
5.2 首页 46
5.3 系统设置 - 可以更改系统主体颜色设置等等 46
5.4 员工管理模块 47
5.5 角色授权 - 通过分配给用户不同的角色,可访问不同的菜单列表 47
5.6. 计划导出 - 通过 excelPoi 技术实现信息导出功能 48
5.7车辆管理 48
5.8数据统计 49
6.总结 50
1.项目简介
物流作为中国经济发展迅速的代表行业之一,在当今时代,它在我们身边无处不在,我们几乎可以随时随地看到它们的身影,为什么我们能在网上买的东西能在几天时间里送到我们手中,都是因为有许许多多的物流企业存在,然而随着社会经济的发展,我们的购买能力的提升,物流企业信息管理面临着巨大的压力,如果还是照以前采用纸笔管理信息的方式,企业信息管理通常比较繁杂,企业工作的效率实在是太低,此时采用计算机来管理企业信息成为了一种趋势,计算机相比人为操作有更高的效率,更安全,也给企业工作人员降低了工作压力,工作管理人员只需要通过操作电脑,就可以管理企业的信息,但是我们如何通过计算机来管理企业信息呢,这时开发一个物流管系统成为了众多中小型物流企业的第一任务,它对于很多企业是发展中必不可少的一部。
在本文中,我将介绍用Java语言实现物流管理系统的基本过程,以及各种使用的技术。在物流管理系统中,主要任务是简化企业信息的增删改查操作,通过一系列的开发,本系统基本实现了物流企业所需要的功能,基本达到了数据的一致性和安全性,为了达到企业内部管理的要求,本系统对人事信息和客户信息进行管理,使物流管理系统更加完善
1.1设计背景
随着中国物流业的高速发展,物流管理的重要性不言而喻。而物流管理的效率更是各个物流企业最看重的地方。近些年来,我国计算机互联网技术高速发展,很多公司和企业都实现了自动化办公及信息管理,这样的管理方式更加高效率,工作人员只需要在电脑前动动手指,就可完成繁琐的管理操作,极大程度上减轻了工作人员的工作量。
我通过在网络上对中小型物流企业的问卷调查,了解到仍有很多中小型企业对物流信息管理仍处于纸笔操作的阶段,我认为这种工作方式效率实在太低,这浪费了太多的人力物力,我认为我们应该采用计算机来管理物流企业信息将传统手工式的物流管理方式改变为以数据流驱动的信息化管理方式,实现信息化仓储,运输,车辆调度的管理系统,人机结合办公,大幅提高工作效率,本文转载自http://www.biyezuopin.vip/onews.asp?id=15082为企业创造更好的效益,这也将会是现代物流管理的主流方式。
1.2软件架构
•jeecg-boot-master 后台项目
•cable.sql 后台管理系统数据库脚本
1.3所用技术
•此系统基于 Jeecg-boot 为脚手架开发的PRD管理系统
•后端技术:SpringBoot 2.1.3 + Shiro 1.4.0 + Redis + Mysql 5.7 + MyBatis-Plus 3.1.2 + Jwt 3.7.0 + Swagger-ui
•前端技术:Vue + Ant-design-vue + Webpack
•其他技术:Druid(数据库连接池)、Logback(日志工具)、poi(Excel工具)、Quartz(定时任务)、lombok(简化代码)
•项目构建:Maven3.5+、JDK1.8+
1.4功能模块
基于Jeecg-boot开发的物流仓储系统,涵盖模块:用户管理、车辆管理、计划管理、仓库管理、库存管理、财务管理、统计报表、系统管理等模块组成

1.5需求分析
1.5.1 需求描述
由于本系统只对企业内部人员开放,所以用户就是本企业管理层员工,用户可以通过自己的工作编号注册账号登录本系统进行业务操作,主要业务包括员工信息管理、货物信息管理、运输信息管理、订单信息管理等几个方面。

<template>
  <div class="main" style="background-color: white;width: 550px;margin-left: -85px;border-radius:5px;padding-top: 20px">
    <a-form :form="form" class="user-layout-login" ref="formLogin" id="formLogin" >
      <div style="padding-bottom: 30px">
        <a-tabs
          :activeKey="customActiveKey"
          :tabBarStyle="{ textAlign: 'center', borderBottom: 'unset' }"
          @change="handleTabClick">
          <a-tab-pane key="tab1" tab="账号密码登陆">
            <a-form-item style="width: 400px;margin-left: 85px">
              <a-input
                size="large"
                v-decorator="['username',{initialValue:'admin', rules: validatorRules.username.rules}]"
                type="text"
                placeholder="请输入帐户名 / admin">
                <a-icon slot="prefix" type="user" :style="{ color: 'rgba(0,0,0,.25)' }"/>
              </a-input>
            </a-form-item>

            <a-form-item style="width: 400px;margin-left: 85px">
              <a-input
                v-decorator="['password',{initialValue:'123456', rules: validatorRules.password.rules}]"
                size="large"
                type="password"
                autocomplete="false"
                placeholder="请输入密码">
                <a-icon slot="prefix" type="lock" :style="{ color: 'rgba(0,0,0,.25)' }"/>
              </a-input>
            </a-form-item>

            <a-row :gutter="0" style="width: 400px;margin-left: 85px">
              <a-col :span="16">
                <a-form-item>
                  <a-input
                    v-decorator="['inputCode',validatorRules.inputCode]"
                    size="large"
                    type="text"
                    @change="inputCodeChange"
                    placeholder="请输入验证码">
                    <a-icon slot="prefix" type="smile" :style="{ color: 'rgba(0,0,0,.25)' }"/>
                  </a-input>
                </a-form-item>
              </a-col>
              <a-col :span="8" style="text-align: right" >
                <img v-if="requestCodeSuccess" style="margin-top: 2px;" :src="randCodeImage" @click="handleChangeCheckCode"/>
                <img v-else style="margin-top: 2px;" src="../../assets/checkcode.png" @click="handleChangeCheckCode"/>
              </a-col>
            </a-row>


          </a-tab-pane>
          <!--        <a-tab-pane key="tab2" tab="手机号登陆">-->
          <!--          <a-form-item>-->
          <!--            <a-input-->
          <!--              v-decorator="['mobile',validatorRules.mobile]"-->
          <!--              size="large"-->
          <!--              type="text"-->
          <!--              placeholder="手机号">-->
          <!--              <a-icon slot="prefix" type="mobile" :style="{ color: 'rgba(0,0,0,.25)' }"/>-->
          <!--            </a-input>-->
          <!--          </a-form-item>-->

          <!--          <a-row :gutter="16">-->
          <!--            <a-col class="gutter-row" :span="16">-->
          <!--              <a-form-item>-->
          <!--                <a-input-->
          <!--                  v-decorator="['captcha',validatorRules.captcha]"-->
          <!--                  size="large"-->
          <!--                  type="text"-->
          <!--                  placeholder="请输入验证码">-->
          <!--                  <a-icon slot="prefix" type="mail" :style="{ color: 'rgba(0,0,0,.25)' }"/>-->
          <!--                </a-input>-->
          <!--              </a-form-item>-->
          <!--            </a-col>-->
          <!--            <a-col class="gutter-row" :span="8">-->
          <!--              <a-button-->
          <!--                class="getCaptcha"-->
          <!--                tabindex="-1"-->
          <!--                :disabled="state.smsSendBtn"-->
          <!--                @click.stop.prevent="getCaptcha"-->
          <!--                v-text="!state.smsSendBtn && '获取验证码' || (state.time+' s')"></a-button>-->
          <!--            </a-col>-->
          <!--          </a-row>-->
          <!--        </a-tab-pane>-->
        </a-tabs>


        <a-form-item>
          <a-button
            size="large"
            type="primary"
            htmlType="submit"
            class="login-button"
            :loading="loginBtn"
            @click.stop.prevent="handleSubmit"
            :disabled="loginBtn"
            style="width: 400px;margin-left: 85px">确定
          </a-button>
        </a-form-item>

        <!--      <div class="user-login-other">-->
        <!--        <span>其他登陆方式</span>-->
        <!--        <a @click="onThirdLogin('github')" title="github"><a-icon class="item-icon" type="github"></a-icon></a>-->
        <!--        <a @click="onThirdLogin('wechat_enterprise')" title="企业微信"><a-icon class="item-icon" type="wechat"></a-icon></a>-->
        <!--        <a @click="onThirdLogin('dingtalk')" title="钉钉"><a-icon class="item-icon" type="dingding"></a-icon></a>-->
        <!--      </div>-->
      </div>
    </a-form>

    <two-step-captcha
      v-if="requiredTwoStepCaptcha"
      :visible="stepCaptchaVisible"
      @success="stepCaptchaSuccess"
      @cancel="stepCaptchaCancel"></two-step-captcha>

    <a-modal
      title="登录部门选择"
      :width="450"
      :visible="departVisible"
      :closable="false"
      :maskClosable="false">

      <template slot="footer">
        <a-button type="primary" @click="departOk">确认</a-button>
      </template>

      <a-form>
        <a-form-item
          :labelCol="{span:4}"
          :wrapperCol="{span:20}"
          style="margin-bottom:10px"
          :validate-status="validate_status">
          <a-tooltip placement="topLeft" >
            <template slot="title">
              <span>您隶属于多部门,请选择登录部门</span>
            </template>
            <a-avatar style="backgroundColor:#87d068" icon="gold" />
          </a-tooltip>
          <a-select @change="departChange" :class="{'valid-error':validate_status=='error'}" placeholder="请选择登录部门" style="margin-left:10px;width: 80%">
            <a-icon slot="suffixIcon" type="gold" />
            <a-select-option
              v-for="d in departList"
              :key="d.id"
              :value="d.orgCode">
              {{ d.departName }}
            </a-select-option>
          </a-select>
        </a-form-item>
      </a-form>



    </a-modal>

  </div>
</template>

<script>
  //import md5 from "md5"
  import api from '@/api'
  import TwoStepCaptcha from '@/components/tools/TwoStepCaptcha'
  import { mapActions } from "vuex"
  import { timeFix } from "@/utils/util"
  import Vue from 'vue'
  import { ACCESS_TOKEN ,ENCRYPTED_STRING} from "@/store/mutation-types"
  import { putAction,postAction,getAction } from '@/api/manage'
  import { encryption , getEncryptedString } from '@/utils/encryption/aesEncrypt'
  import store from '@/store/'
  import { USER_INFO } from "@/store/mutation-types"

  export default {
    components: {
      TwoStepCaptcha
    },
    data () {
      return {
        customActiveKey: "tab1",
        loginBtn: false,
        // login type: 0 email, 1 username, 2 telephone
        loginType: 0,
        requiredTwoStepCaptcha: false,
        stepCaptchaVisible: false,
        form: this.$form.createForm(this),
        encryptedString:{
          key:"",
          iv:"",
        },
        state: {
          time: 60,
          smsSendBtn: false,
        },
        validatorRules:{
          username:{rules: [{ required: true, message: '请输入用户名!'},{validator: this.handleUsernameOrEmail}]},
          password:{rules: [{ required: true, message: '请输入密码!',validator: 'click'}]},
          mobile:{rules: [{validator:this.validateMobile}]},
          captcha:{rule: [{ required: true, message: '请输入验证码!'}]},
          inputCode:{rules: [{ required: true, message: '请输入验证码!'}]}
        },
        verifiedCode:"",
        inputCodeContent:"",
        inputCodeNull:true,

        departList:[],
        departVisible:false,
        departSelected:"",
        currentUsername:"",
        validate_status:"",
        currdatetime:'',
        randCodeImage:'',
        requestCodeSuccess:false
      }
    },
    created () {
      this.currdatetime = new Date().getTime();
      Vue.ls.remove(ACCESS_TOKEN)
      this.getRouterData();
      this.handleChangeCheckCode();
      // update-begin- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉,有点问题
      //this.getEncrypte();
      // update-end- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉,有点问题
    },
    methods: {
      ...mapActions([ "Login", "Logout","PhoneLogin","ThirdLogin" ]),
      //第三方登录
      onThirdLogin(source){
        let url = window._CONFIG['domianURL']+`/thirdLogin/render/${source}`
        window.open(url, `login ${source}`, 'height=500, width=500, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, resizable=no,location=n o, status=no')
        let that = this;
        let receiveMessage = function(event){
          var origin = event.origin
          console.log("origin",origin);

          let token = event.data
          console.log("event.data",token)
          that.ThirdLogin(token).then(res=>{
            if(res.success){
              that.loginSuccess()
            }else{
              that.requestFailed(res);
            }
          })
        }
        window.addEventListener("message", receiveMessage, false);
      },
      // handler
      handleUsernameOrEmail (rule, value, callback) {
        const regex = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/;
        if (regex.test(value)) {
          this.loginType = 0
        } else {
          this.loginType = 1
        }
        callback()
      },
      handleTabClick (key) {
        this.customActiveKey = key
        // this.form.resetFields()
      },
      handleSubmit () {
        let that = this
        let loginParams = {};
        that.loginBtn = true;
        // 使用账户密码登陆
        if (that.customActiveKey === 'tab1') {
          that.form.validateFields([ 'username', 'password','inputCode', 'rememberMe' ], { force: true }, (err, values) => {
            if (!err) {
              loginParams.username = values.username
              // update-begin- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉,有点问题
              //loginParams.password = md5(values.password)
              //loginParams.password = encryption(values.password,that.encryptedString.key,that.encryptedString.iv)
              loginParams.password = values.password
              loginParams.remember_me = values.rememberMe
              // update-begin- --- author:scott ------ date:20190805 ---- for:密码加密逻辑暂时注释掉,有点问题
              loginParams.captcha = that.inputCodeContent
              loginParams.checkKey = that.currdatetime
              console.log("登录参数",loginParams)
              that.Login(loginParams).then((res) => {
                this.departConfirm(res)
              }).catch((err) => {
                that.requestFailed(err);
              });


            }else {
              that.loginBtn = false;
            }
          })
          // 使用手机号登陆
        } else {
          that.form.validateFields([ 'mobile', 'captcha', 'rememberMe' ], { force: true }, (err, values) => {
            if (!err) {
              loginParams.mobile = values.mobile
              loginParams.captcha = values.captcha
              loginParams.remember_me = values.rememberMe
              that.PhoneLogin(loginParams).then((res) => {
                console.log(res.result);
                this.departConfirm(res)
              }).catch((err) => {
                that.requestFailed(err);
              })

            }
          })
        }
      },
      getCaptcha (e) {
        e.preventDefault();
        let that = this;
        this.form.validateFields([ 'mobile' ], { force: true },(err,values) => {
            if(!values.mobile){
              that.cmsFailed("请输入手机号");
            }else if (!err) {
              this.state.smsSendBtn = true;
              let interval = window.setInterval(() => {
                if (that.state.time-- <= 0) {
                  that.state.time = 60;
                  that.state.smsSendBtn = false;
                  window.clearInterval(interval);
                }
              }, 1000);

              const hide = this.$message.loading('验证码发送中..', 0);
              let smsParams = {};
                  smsParams.mobile=values.mobile;
                  smsParams.smsmode="0";
              postAction("/sys/sms",smsParams)
                .then(res => {
                  if(!res.success){
                    setTimeout(hide, 0);
                    this.cmsFailed(res.message);
                  }
                  console.log(res);
                  setTimeout(hide, 500);
                })
                .catch(err => {
                  setTimeout(hide, 1);
                  clearInterval(interval);
                  that.state.time = 60;
                  that.state.smsSendBtn = false;
                  this.requestFailed(err);
                });
            }
          }
        );
      },
      stepCaptchaSuccess () {
        this.loginSuccess()
      },
      stepCaptchaCancel () {
        this.Logout().then(() => {
          this.loginBtn = false
          this.stepCaptchaVisible = false
        })
      },
      handleChangeCheckCode(){
        this.currdatetime = new Date().getTime();
        getAction(`/sys/randomImage/${this.currdatetime}`).then(res=>{
          if(res.success){
            this.randCodeImage = res.result
            this.requestCodeSuccess=true
          }else{
            this.$message.error(res.message)
            this.requestCodeSuccess=false
          }
        }).catch(()=>{
          this.requestCodeSuccess=false
        })
      },
      loginSuccess () {
        // update-begin- author:sunjianlei --- date:20190812 --- for: 登录成功后不解除禁用按钮,防止多次点击
        // this.loginBtn = false
        // update-end- author:sunjianlei --- date:20190812 --- for: 登录成功后不解除禁用按钮,防止多次点击
        this.$router.push({ path: "/dashboard/analysis" })
        this.$notification.success({
          message: '欢迎',
          description: `${timeFix()},欢迎回来`,
        });
      },
      cmsFailed(err){
        this.$notification[ 'error' ]({
          message: "登录失败",
          description:err,
          duration: 4,
        });
      },
      requestFailed (err) {
        this.$notification[ 'error' ]({
          message: '登录失败',
          description: ((err.response || {}).data || {}).message || err.message || "请求出现错误,请稍后再试",
          duration: 4,
        });
        this.loginBtn = false;
      },
      validateMobile(rule,value,callback){
        if (!value || new RegExp(/^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\d{8}$/).test(value)){
          callback();
        }else{
          callback("您的手机号码格式不正确!");
        }

      },
      validateInputCode(rule,value,callback){
        if(!value || this.verifiedCode==this.inputCodeContent){
          callback();
        }else{
          // callback("您输入的验证码不正确!");
          callback();
        }
      },
      generateCode(value){
        this.verifiedCode = value.toLowerCase()
      },
      inputCodeChange(e){
        this.inputCodeContent = e.target.value
      },
      departConfirm(res){
        if(res.success){
          let multi_depart = res.result.multi_depart
          //0:无部门 1:一个部门 2:多个部门
          if(multi_depart==0){
            this.loginSuccess()
            // this.$notification.warn({
            //   message: '提示',
            //   description: `您尚未归属部门,请确认账号信息`,
            //   duration:3
            // });
          }else if(multi_depart==2){
            this.departVisible=true
            this.currentUsername=this.form.getFieldValue("username")
            this.departList = res.result.departs
          }else {
            this.loginSuccess()
          }
        }else{
          this.requestFailed(res)
          this.Logout();
        }
      },
      departOk(){
        if(!this.departSelected){
          this.validate_status='error'
          return false
        }
       let obj = {
          orgCode:this.departSelected,
          username:this.form.getFieldValue("username")
        }
        putAction("/sys/selectDepart",obj).then(res=>{
          if(res.success){
            const userInfo = res.result.userInfo;
            Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000);
            store.commit('SET_INFO', userInfo);
            //console.log("---切换组织机构---userInfo-------",store.getters.userInfo.orgCode);
            this.departClear()
            this.loginSuccess()
          }else{
            this.requestFailed(res)
            this.Logout().then(()=>{
              this.departClear()
            });
          }
        })
      },
      departClear(){
        this.departList=[]
        this.departSelected=""
        this.currentUsername=""
        this.departVisible=false
        this.validate_status=''
      },
      departChange(value){
        this.validate_status='success'
        this.departSelected = value
      },
    getRouterData(){
      this.$nextTick(() => {
        if (this.$route.params.username) {
          this.form.setFieldsValue({
            'username': this.$route.params.username
          });
        }
      })
    },
    //获取密码加密规则
    getEncrypte(){
      var encryptedString = Vue.ls.get(ENCRYPTED_STRING);
      if(encryptedString == null){
        getEncryptedString().then((data) => {
          this.encryptedString = data
        });
      }else{
        this.encryptedString = encryptedString;
      }
    },
    }
  }
</script>

<style lang="less" scoped>

  .user-layout-login {
    label {
      font-size: 14px;
    }

    .getCaptcha {
      display: block;
      width: 100%;
      height: 40px;
    }

    .forge-password {
      font-size: 14px;
    }

    button.login-button {
      padding: 0 15px;
      font-size: 16px;
      height: 40px;
      width: 100%;
    }

    .user-login-other {
      text-align: left;
      margin-top: 24px;
      line-height: 22px;

      .item-icon {
        font-size: 24px;
        color: rgba(0,0,0,.2);
        margin-left: 16px;
        vertical-align: middle;
        cursor: pointer;
        transition: color .3s;

        &:hover {
          color: #1890ff;
        }
      }

      .register {
        float: right;
      }
    }
  }

</style>
<style>
  .valid-error .ant-select-selection__placeholder{
    color: #f5222d;
  }
</style>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Logo

前往低代码交流专区

更多推荐