vue医疗项目

1.项目名称:医疗管理

2.技术栈:vue全家桶,element-ui,axios,scss

3.项目亮点:性能优化;百万级项目;新旧系统更迭;权限分配

项目开发流程:

1.根据项目需要配置css,fonts,images

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 导入公共重置样式
import "./assets/css/base.css";
// 导入公共样式
import "./assets/css/reset.css";
// 导入字体图标
import "@/assets/fonts/iconfont.css";
// 导入element依赖
import ElementUI from "element-ui";
// 导入element css样式
import "element-ui/lib/theme-chalk/index.css";
// 导入自己封装的loca
import Local from "./utils/local.js";
Vue.config.productionTip = false
// 挂在在全局 原型对象
Vue.prototype.$local = Local;
Vue.use(ElementUI);
// 这是excel导出
import JsonExcel from "vue-json-excel";
Vue.component("downloadExcel", JsonExcel);
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

2.根据原型图,配置需要的路由模块,首先需要做的就是登录页面.

登录模块

1.配置登录路由懒加载

//  登录页面
  { path: "/", redirect: "/login" },
  { path: "/login", name: "", component: () => import("../views/Login.vue") },

2.路由配置完成之后,排版登录页面,开始布局,样式等

<template>
  <div class="loginbox">
    <div class="mainbox">
      <h1>系统登录</h1>
      <el-form ref="ruleForm" label-width="80px" size="small" :model="loginform" :rules="checkObj" style="width:80%">
        <el-form-item label="账号" prop="username">
          <!-- label就是前面提示文字 size就是改变表单输入框大小 里面三个值-->
          <el-input type="text" v-model.trim="loginform.username" placeholder="请输入账号">
          </el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
          <!-- label就是前面提示文字 size就是改变表单输入框大小 里面三个值-->
          <el-input :type="flag ? 'text' : 'password'" v-model.trim="loginform.password" placeholder="请输入密码">
            <i slot="suffix" :class="['iconfont', flag ? 'icon-yanjing_huaban1' : 'icon-05wangluoanquan_biyanjing']"
              @click="flag = !flag"></i>
          </el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="toLogin" @keyup="keyDown(e)">登录</el-button>
          <el-button type="success" @click="resetForm">重置</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>
<script>
import { api_login } from "../api/user.js"
export default {
  data() {
    return {
      loginform: {
        username: "admin",
        password: "123456",
      },
      flag: false,
      // 表单验证 必须要挂一个prop属性
      checkObj: {
        username: [
          { required: true, message: '账号不能为空', trigger: 'blur' },
          { min: 3, max: 8, message: '长度在 3 到 8 个字符', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '密码不能为空', trigger: 'blur' },
          { min: 3, max: 8, message: '长度在 3 到 8 个字符', trigger: 'blur' }
        ],
      }
    }
  },
  methods: {
    toLogin() {
      this.$refs.ruleForm.validate(async (valid) => {
        if (valid) {
          // 进来之后是检测记录
          let res = await api_login(this.loginform)
          // console.log(res);
          if (res.code === 200) {
            this.$message.success("登录成功")
            // 登录成功之后讲返回来的用户信息存到vuex中
            // 此时全局就有了man_id
            this.$store.commit("setUserInfo", res.data)
            // 设置token值
            this.$local.set("ylmy_token", res.token)
            // 存UserId
            // res.data是一个对象 比较大 因为本地存储有大小 一般是字符串需要转
            // 从这里获取userId 几个地方用到userInfo数据
            this.$local.set("userInfo", res.data)
            // 注意了这里是跳转到自己的一级路由,然后自动重定向
            this.$router.push("/observe")
          } else {
            this.$message.error(res.msg)
          }
        } else {
          return false;
        }
      });
    },
    // 键盘登录
    keyDown(e) {
      if (e.keyCode == 13 || e.keyCode == 200) {
        this.toLogin()
      }
    },
    // 重置表单
    resetForm() {
      this.$refs.ruleForm.resetFields();
    },
  },
  // 生命周期和methods是同级同级
  mounted() {
    // 绑定监听事件
    window.addEventListener("keydown", this.keyDown);
  },
  // 生命周期和methos是同级同级
  destroyed() {
    // 销毁事件
    window.removeEventListener("keydown", this.keyDown, false);
  },
}
</script>

<style lang="scss" scoped>
.loginbox {
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  // background: #3aceec;
  background-image: url(../assets/images/616pic.webp);

  .mainbox {
    width: 500px;
    height: 300px;
    // border: 1px solid #000;

    h1 {
      padding-left: 135px;
      font-weight: 700;
      font-size: 30px;
    }

    .el-form {
      margin-top: 50px;
    }
  }
}

.el-input__suffix-inner {
  cursor: pointer !important;
}
</style>

3.此时需要发异步请求,封装axios,local,设置token值,设置跨域

封装axios-->api-->local

1.先设置跨域问题

第一步:在根据经下新建vue.config.js;根据项目要求进行修改里面的数据

// 配置的意思
module.exports = {
  devServer: {
    // 自动加载这个文件
    // 默认值 为localhost 127.0.0.1
    // 当前端口默认为8080
    host: "localhost",
    // 当前vue服务器的端口
    port: "8081",
    // 默认有的
    // 前端跨域
    proxy: {
      "/api": {
        // 配置你要让那些路径要跨域
        // 你可以让该路径前面添加api
        // login
        // /aa/login
        // 是后台路径
        // target: "http://124.221.12.94/wyyl-s/public",
        target: "http://e.ludir.cn/api/wyyl/public/",
        // true 代表跨域
        changOrigin: true,
        pathRewrite: {
          //重写 login
          "^/api": "",
        },
      },
    },
  },
};

2.二次封装axios请求,需要加请求头

// 引入axios
import axios from "axios";
// 引入qs qs是转化成字符串
// import qs from "qs";
// 需要导入自己封装的local.js
import local from "./local.js";
// 放url的公共的地址
// 因为要解决跨域 这个路径就是自己定义的api
axios.defaults.baseURL = "/api";
// 封装axios方法 企业级封装
// 主要是解决url地址问题 方法method 数据参数data
// 这三个参数如果没有给值 就给一个默认值
// 封装任何方法,必须传的值必须放第一个位置,如果可以没有值的,可以放后面
// axios是基于promise await async
// 响应拦截器 返回的数据要经过这里拦截,我们只需要里面的data数据就行
// Add a response interceptor
axios.interceptors.response.use(
  function (response) {
    // Do something with response data
    // 就是对response的数据拦截
    // 我们只需要data的数据,就只有data数据
    return response.data;
    // response只需要拿到data的值
  },
  function (error) {
    // Do something with response error
    return Promise.reject(error);
  }
);
// 添加请求拦截器 配置所有请求都有请求
axios.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    // 对所有的请求进行拦截
    // 看一下当前本地存储中有没有token
    // config 配置 headers 请求头
    if (local.iskey("ylmy_token")) {
      // config.headers.Authorization = local.get("ylmy_token");
      // 这里不能用Authorization 需要用Token
      // 后台不严格只能用token
      config.headers.Token = local.get("ylmy_token");
      // 此时还是报错,还需要设置请求头 还设置权限
      // 请求头还需要加一个UserId UserId在userInfo里面
      config.headers.UserId = local.get("userInfo").man_id;
      return config;
    } else {
      return config;
    }
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 第一层封装解决了method 对应参数的问题,需要加请求头
let request = function (url, method = "get", data = {}, headers = {}) {
  // 返回的是一个promise 所以要return出去
  return axios({
    url,
    method,
    // 三元表达式 判断是post还是get请求
    // 因为post传参用的是data get用的是params
    // 主要是解决data和params的问题
    // 只对post数据有要求,对get数据没有要求你
    data: method == "post" ? data : "",
    params: method == "get" ? data : "",
    headers,
  });
};
// 把封装的方法暴露出去
// 这是第二层 是解决post和get的问题
// 向外抛出get和post
export default {
  // 封装post方法
  post(url, data, headers = {}) {
    return request(url, "post", data, headers);
  },
  // 封装get方法
  get(url, data, headers = {}) {
    return request(url, "get", data, headers);
  },
};

3.二次封装local本地存储,需要转化token值

注意:此时你需要再main.js中进行引入和全局挂载,不然会报错

// 导入自己封装的loca
import Local from "./utils/local.js";
// 挂在在全局 原型对象
Vue.prototype.$local = Local;
// 封装本地存储的方法
let loaclObj = {
  // getItem 需要返回值
  get(key) {
    // 携带参数 取的时候解开
    return JSON.parse(window.localStorage.getItem(key));
  },
  // setItem 设置不需要返回 每一个值都转化一下字符串
  set(key,value) {
    window.localStorage.setItem(key, JSON.stringify(value));
  },
  // removeItem
  remove(key) {
    window.localStorage.removeItem(key)
  },
  // clear 清空
  clear() {
    window.localStorage.clear()
  },
  // 判断是否有对应的名称值
  iskey(key) {
    return window.localStorage.getItem(key) ? true : false
  }
}
//一定要暴露暴露出去 本身就是一个对象
export default loaclObj;

注意:封装axios,主要是解决三个问题,url问题,method问题,get和post问题,包括需要解决响应拦截和请求拦截,以及请求头

4.此时需要在api文件夹下新建项目对应的模块api接口,先引入自己封装的request.js文件

// 工程化开发
// 跟用户有关的url 此时封装的url api是后台请求的接口
// 发异步请求
import request from "../utils/request";
// 调用这个方法只需要传一个data参数
// 这个是登录的url
// export const api_login = function (data) {
//    return request.post("/users/checkLogin",data);
// }
// 简写 如果只有一个返回值 省略{} 登录
export const api_login = (data) => request.post("/index/login", data);
// 左侧导航
export const api_aside = (data) => request.get("/user/menu", data);
// 个人中心查询我的权限
export const api_myauth = (data) => request.get("/auth/myauth", data);
// 头像上传 需要请求头
export const api_updImg = (data, headers) =>request.post("/user/upimg", data, headers);

5.根据接口文档得知,几个地方用到用户man_id,可以在vuex中设置一个变量,把用户信息存到vuex中,方便后面取值,在登陆成功之后,进行存值;先在store index.js中设置

import Vue from "vue";
import Vuex from "vuex";
import { api_notass } from "../api/ass";
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    // 定义一个全局变量,存的是个人信息所有信息
    userInfo: {},
    // 未完成的任务序号 为什么是给字符串 初始值为字符串,在没有未完成任务的时候不需要显示
    notAssNumber: "",
  },
  mutations: {
    // 设置一个方法 专门修改state中的值
    setUserInfo(state, payload) {
      state.userInfo = payload;
    },
  },
  actions: {
    async getNotAssNumber(context, payload) {
      // man_id用户id
      // context里面有state,getters,commit,dispatch
      // 然后state里面有userInfo再取到man_id
      let res = await api_notass({ man_id: context.state.userInfo.man_id });
      // console.log(res);
      // console.log(context);
      // 写好了需要调用触发
      if (res.code === 200) {
        // 数组的长度就是未完成的个数
        // 从context中拿到state再拿到notAssNumber
        context.state.notAssNumber = res.data.length > 0 ? res.data.length : "";
      }
    },
  },
  modules: {},
});

6.然后在登陆成功之后进行设置

toLogin() {
      this.$refs.ruleForm.validate(async (valid) => {
        if (valid) {
          // 进来之后是检测记录
          let res = await api_login(this.loginform)
          // console.log(res);
          if (res.code === 200) {
            this.$message.success("登录成功")
            // 登录成功之后讲返回来的用户信息存到vuex中
            // 此时全局就有了man_id
            this.$store.commit("setUserInfo", res.data)
            // 设置token值
            this.$local.set("ylmy_token", res.token)
            // 存UserId
            // res.data是一个对象 比较大 因为本地存储有大小 一般是字符串需要转
            // 从这里获取userId 几个地方用到userInfo数据
            this.$local.set("userInfo", res.data)
            // 注意了这里是跳转到自己的一级路由,然后自动重定向
            this.$router.push("/observe")
          } else {
            this.$message.error(res.msg)
          }
        } else {
          return false;
        }
      });
    },

 7.登录页面还没有完成,此时添加键盘事件,enter也可以实现登录效果

keyDown(e) {
      if (e.keyCode == 13 || e.keyCode == 0) {
        this.login()
      }
    },
 
//和生命周期和methods是同级同级
mounted() {
    // 绑定监听事件
    window.addEventListener("keydown", this.keyDown);
  },
  // 生命周期和methos是同级同级
  destroyed() {
    // 销毁事件
    window.removeEventListener("keydown", this.keyDown, false);
  },

最后:登录页面完成,继续下一个模块制作.

主页面模块

1.先封装组件,设置一个主页面即可,Layout,再封装头部,左侧,卡片,面包屑

第一步:封装一个面包屑,主要是利用父子组件传值

<template>
  <div>
    <el-breadcrumb separator="/">
      <el-breadcrumb-item :to="{ path: '/observe' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item v-for="(item,index) in title" :key="index">{{ item }}</el-breadcrumb-item>
    </el-breadcrumb>
    <el-divider></el-divider>
  </div>
</template>

<script>
export default {
  props: {
    title: {
      type: Array,
      required: true,
      default: function () {
        return []
      }
    }
  },

}
</script>

<style lang="scss" scoped>

</style>

 第二步:子组件代码块

<template>
  <div>
    <comm-breadcrumb :title="commBreadcrumbTitle"></comm-breadcrumb>
  </div>
</template>

<script>
import commBreadcrumb from "../../components/commBreadcrumb"
  export default {
    components: {
      commBreadcrumb,
  },
    data() {
      return {
        commBreadcrumbTitle:["任务管理","我的任务"],
      }
    },
  }
</script>

<style lang="scss" scoped>

</style>

2.封装头部组件

 第一步:用户相关信息在vuex中进行取值,在登陆的时候已经把值存到了vuex中

<template>
  <div class="headerbox">

    <div class="left">
      <span class="el-icon-refresh" @click="shuxin"></span>
      <span>万云医疗检测消毒平台</span>
    </div>
    <div class="right">
      <el-dropdown trigger="click">
        <el-avatar size="medium" :src="$store.state.userInfo.avatar">
        </el-avatar>
        <el-dropdown-menu slot="dropdown">
          <el-dropdown-item icon="el-icon-user-solid">{{ $store.state.userInfo.username }}</el-dropdown-item>
          <el-dropdown-item icon="el-icon-user">{{ $store.state.userInfo.role_name }}</el-dropdown-item>
          <el-dropdown-item icon="el-icon-setting" @click.native="$router.push('/userzx')">用户设置</el-dropdown-item>
          <el-dropdown-item icon="el-icon-switch-button" @click.native="goback">退出登录</el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
      <span>{{ $store.state.userInfo.truename }}</span>
    </div>
  </div>
</template>

头部样式:

<style lang="scss" scoped>
.headerbox {
  height: 60px;
  background: #636269;
  display: flex;
  justify-content: space-between;
  align-items: center;

  .left {
    padding: 20px;

    span {
      font-size: 25px;
      color: #fff;

      &:nth-child(2) {
        font-style: italic;
        font-weight: 700;
        margin-left: 15px;
        ;
      }

      &:nth-child(1) {
        cursor: pointer;
      }
    }
  }

  .right {
    display: flex;
    align-items: center;
    padding: 30px;

    span {
      margin-left: 20px;
    }
  }
}

.el-dropdown {
  cursor: pointer;
}
</style>

注意:因为vuex中存的值,刷新之后,数据会丢失,这里用的方法是,把值存到本地中,其实可以利用依赖来解决:

方法一:

 // vuex刷新之后就没了 在头部或者侧边栏用的时候  
  // 如果刷新没了  需要在钩子函数 把值存到本地上
  created() {
    let userInfo = this.$local.get("userInfo");
    // console.log(userInfo);
    this.$store.commit("setUserInfo", userInfo);
  },

方法二:

利用插件 vuex-persistedState

第二步:script中的代码块

<script>
export default {
  // vuex刷新之后就没了 在头部或者侧边栏用的时候  
  // 如果刷新没了  需要在钩子函数 把值存到本地上
  created() {
    let userInfo = this.$local.get("userInfo");
    // console.log(userInfo);
    this.$store.commit("setUserInfo", userInfo);
  },
  methods: {
    // 退出登录
    goback() {
      // 清空userInfo 和 token
      this.$local.remove("ylmy_token")
      this.$local.remove("userInfo")
      this.$router.replace("/login")
    },
    shuxin() {
      this.$router.go(0)
    }
  },
}
</script>

3.封装项目左侧,这次项目左侧是通过后台请求过来的,不是写死的左侧数据

 4.根据element-ui选择下拉菜单;包括循环左侧字体图标,主要是定义一个数组,把字体图标存到数组中,然后在菜单栏左侧i标签上进行循环即可

<template>
  <div class="asidebox">
    <!-- 不需要动态绑定 -->
    <el-menu default-active="$route.path" class="el-menu-vertical-demo" background-color="#636269" text-color="#fff"
      active-text-color="#409eff" unique-opened router>
      <!-- 检测管理 -->
      <el-submenu :index="item.path" v-for="(item, index) in menuList" :key="index">
        <template slot="title" class="icon">
          <i :class="arr[index]"></i>
          <!-- 一级菜单 需要判断-->
          <el-badge :value="$store.state.notAssNumber" class="item" v-if="item.name=='任务管理'">
            <span>{{ item.name }}</span>
          </el-badge>
          <!-- 需要加一个span 用于判断 -->
          <span v-else>{{ item.name }}</span>
        </template>
        <!-- 二级菜单是循环item.children -->
        <el-menu-item :index="ele.path" v-for="(ele, i) in item.children" :key="i">
          <!-- 二级菜单 -->
          <el-badge :value="$store.state.notAssNumber" class="item" v-if="ele.name=='我的任务'">
            <span>{{ ele.name }}</span>
          </el-badge>
          <span v-else>{{ ele.name }}</span>
        </el-menu-item>
      </el-submenu>
    </el-menu>
  </div>
</template>

5.script代码块,vuex中的值,需要存到本地,防止刷新之后,数据直接丢失

vuex中的设置的userInfo代码

 script代码块:

<script>
import { api_aside } from "@/api/user"
export default {
  data() {
    return {
      menuList: [],
      // 字体图标
      arr: ["el-icon-view", "el-icon-coin", "el-icon-tickets", "el-icon-attract", "el-icon-pie-chart"],
    }
  },
  methods: {
    async queryMenu() {
      // 请求获取菜单 要求传参man_id 此时是从登录之后给的
      // 这边是左侧页面 包括头部 都需要用 此时用vuex
      // 定义一个对象 然后作为参数传进去
      let userInfo = this.$local.get("userInfo");
      // let man_id = this.$store.state.userInfo.man_id;
      // 这个是从本地取值 比较稳定 如果在vuex中取值 刷新就没了
      let res = await api_aside({ man_id: userInfo.man_id })
      // console.log(res);
      if (res.code === 200) {
        this.menuList = res.data
      }
    }
  },
  created() {
    // 拿到本地储存的vuex值
    let userInfo = this.$local.get("userInfo");
    this.$store.commit("setUserInfo", userInfo);
    this.queryMenu();
    // 触发在vuex中异步编写的查询未完成的记录
    this.$store.dispatch("getNotAssNumber");
  },
}
</script>

6.左侧菜单标记的显示

 第一步:首先在vuex中actions发异步请求,请求所有的未完成任务

 第二步:在左侧组件拿到设置的未完成任务值

 第三步:在菜单栏上设置判断,在进行循环

 7.完成左侧和头部组件的封装,在Layout.vue中显示

<template>
  <div class="layoutbox">
    <el-container class="leftbox">
      <el-header>
        <!-- 头部组件 -->
        <commHeader></commHeader>
      </el-header>
      <el-container style="background-color:#eee">
        <el-aside width="200px">
          <!-- 左侧导航组件 -->
          <commAside></commAside>
        </el-aside>
        <el-main>
          <!-- 右侧配置出口 -->
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script>
import commAside from "../components/commAside"
import commHeader from "../components/commHeader"
export default {
  components: {
    commAside,
    commHeader,
  },
}
</script>

<style lang="scss" scoped>
.layoutbox {
  height: 100%;

  .leftbox {
    height: 100%;
  }

  .el-header {
    width: 100%;
    padding: 0px;
  }

  .el-main {
    background-color:#fff;
    margin: 5px;
  }
}
</style>

 模块开发

配置文件夹,配置相关路由 

 注意:一个父级路由,包含所以子路由

检测管理

检测记录

1.比较简单,请求数据,只需要发页面和条数

两个过滤器:

 完整代码块:

<template>
  <div>
    <comm-breadcrumb :title="commBreadcrumbTitle"></comm-breadcrumb>
    <el-form label-width="80px" :model="form">
      <el-form-item label="完成状态">
        <el-select placeholder="请选择完成状态" v-model="form.dstatus">
          <el-option label="未完成" value="未完成"></el-option>
          <el-option label="已完成" value="已完成"></el-option>
        </el-select>
        <el-button type="success" @click="toSearch" style="margin-left:10px">搜索</el-button>
      </el-form-item>
    </el-form>
    <el-table :data="tableData" style="width: 100%" max-height="500px">
      <el-table-column type="expand">
        <template slot-scope="props">
          <el-form label-position="left" inline class="demo-table-expand">
            <el-form-item label="任务名称:">
              <span>{{ props.row.aname }}</span>
            </el-form-item>
            <el-form-item label="完成状态:">
              <span>{{ props.row.dstatus | chuLiDstatus }}</span>
            </el-form-item>
            <el-form-item label="记录人:">
              <span>{{ props.row.truename }}</span>
            </el-form-item>
            <el-form-item label="记录人账号:">
              <span>{{ props.row.username }}</span>
            </el-form-item>
            <el-form-item label="任务分配:">
              <span>{{ props.row.asst_name }}</span>
            </el-form-item>
            <el-form-item label="科室:">
              <span>{{ props.row.rname }}</span>
            </el-form-item>
            <el-form-item label="完成时间:">
              <span>{{ props.row.over_time }}</span>
            </el-form-item>
          </el-form>
        </template>
      </el-table-column>
      <el-table-column label="任务名称" prop="aname">
      </el-table-column>
      <el-table-column label="完成状态">
        <template #default="{ row }">
          <el-tag type="success" v-if="row.dstatus == 1">已完成</el-tag>
          <el-tag type="danger" v-else>未完成</el-tag>
        </template>
      </el-table-column>
      <el-table-column label="记录人" prop="truename">
      </el-table-column>
      <el-table-column label="完成时间" prop="over_time">
      </el-table-column>
    </el-table>
    <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="myassObj.page"
      :page-sizes="[1, 2, 3, 4, 5, 10, 20]" :page-size="myassObj.pagesize"
      layout="total, sizes, prev, pager, next, jumper" :total="total">
    </el-pagination>
  </div>
</template>

<script>
import { api_selobs } from "../../api/obs"
import commBreadcrumb from "../../components/commBreadcrumb"
export default {
  filters: {
    chuLiDstatus: function (str) {
      return str == "0" ? "未完成" : "已完成";
    }
  },
  components: {
    commBreadcrumb,
  },
  data() {
    return {
      commBreadcrumbTitle: ["检测管理", "检测记录"],
      tableData: [],
      myassObj: {
        // man_id: "",//用户id
        page: 1,//页码
        pagesize: 5,//条数
      },
      form: {},
      total: 0
    }
  },
  methods: {
    async queryList() {
      // 封装定义的obj man_id没有值 需要赋值
      // 用户id已经存到了vuex中可以直接取值
      // this.myassObj.man_id = this.$store.state.userInfo.man_id;
      let res = await api_selobs(this.myassObj)
      // console.log(res);
      if (res.code === 200) {
        this.tableData = res.data;
        this.total = res.total;
      }
    },
    //条数改变触发
    handleSizeChange(val) {
      // console.log(`每页 ${val} 条`);
      this.myassObj.pagesize = val
      this.queryList();
    },
    //当前页改变触发
    handleCurrentChange(val) {
      // console.log(`当前页: ${val}`);
      this.myassObj.page = val
      this.queryList();
    },
    toSearch() {
      this.queryList();
      // console.log(111);
    }
  },
  created() {
    this.queryList();
  },
}
</script>

<style lang="scss" scoped>
.demo-table-expand {
  font-size: 0;
  margin-left: 60px;
  color: #f00;
}

.demo-table-expand label {
  width: 90px;
  color: #99a9bf;
}

.demo-table-expand .el-form-item {
  margin-right: 0;
  margin-bottom: 0;
  width: 50%;
}
</style>

添加检测

1.点击任务选项,和时间,才会显示下面的数据内容

第一步:上面下拉模块,和时间模块,先发请求获取未完成任务,浮游生物和检测对象

<div>
    <comm-breadcrumb :title="commBreadcrumbTitle"></comm-breadcrumb>
    <div class="smallbox">
      <!-- 未完成任务需要查询出来的 -->
      <el-select placeholder="请选择未完成任务" size="small" v-model="obsObj.ass_id">
        <el-option v-for="item in notAssList" :key="item.ass_id" :label="item.aname" :value="item.ass_id">
          <span style="float: left">任务名称: {{ item.aname }}</span>
          <span style="float: right; color: #8492a6; font-size: 13px">截止时间: {{ item.to_time }}</span>
        </el-option>
      </el-select>
      <el-date-picker type="date" placeholder="选择日期时间" value-format="yyyy-MM-dd" size="small" style="margin-left:6px"
        v-model="obsObj.over_time">
      </el-date-picker>
      <el-divider content-position="left">记录检测结果</el-divider>
    </div>

 代码块

// 获取未完成检测任务
    async queryNotAss() {
      // 用户id就是存在vuex中直接进行取值
      let man_id = this.$store.state.userInfo.man_id;
      let asst_id = 1 //检测任务默认id就是1 固定写
      let { code, data } = await api_notass({ man_id, asst_id })
      // console.log(data)
      if (code == 200) {
        this.notAssList = data
      }
    },
    // 查询出检测对象
    async querySelwp() {
      let res = await api_selwp()
      // console.log(res)
      if (res.code == 200) {
        this.selwpList = res.data
        this.maxIndex = res.data.length
      }
    },
    // 查询浮游生物
    async querySelmit() {
      let res = await api_selmit()
      // console.log(res)
      if (res.code == 200) {
        this.selmitList = res.data
      }
    },

第二步:拿到数据进行合并

 // 处理数据 数据进行合并
    resolveData() {
      // map返回的是一个对象,然后重新组成一个新的数组
      this.formatData = this.selwpList.map((ele) => {
        // 一级菜单 定一个对象
        let obj1 = {
          wuname: ele.wuname,
          wu_id: ele.wu_id,
          children: [],
        }
        // 第二层 二级
        this.selmitList.forEach((item) => {
          let obj2 = {
            miname: item.miname,
            mit_id: item.mit_id,
            mires: "",
          }
          // 将obj2的值添加到children里面 children都有三个值
          obj1.children.push(obj2)
        })
        return obj1
      })
    },

第三步:数据进行初始化,用async和await

// 初始化
    async init() {
      //使用异步的async await 来处理
      //  promise可以解决异步顺序问题
      // 查询检测对象 只要是被await修改就是同步按顺序执行
      await this.querySelwp();
      // 查询浮游生物
      await this.querySelmit();
      // 处理合并数据,将两个数据合并一起
      this.resolveData();
    },

第四步:处理下一步,点击上面进行切换

 // 下一步
    next(item) {
      // every只要有一个不符合就返回true或者false一个值和some一样
      let yanzhen = item.children.every((ele) => {
        return ele.mires
      })
      if (yanzhen) {
        // 处理下一步
        // 点击下一步就要修改tableIndex的值
        if (this.tableIndex >= this.maxIndex - 1) {
          // this.status = true
          // this.active = this.tableIndex+ 1
        } else {
          // 本来是字符串 要做加法 加完再转化成字符串
          this.tableIndex == this.maxIndex - 2 ? (this.status = true) : '';
          this.tableIndex = +this.tableIndex + 1 + "";
          // this.active = +this.tableIndex
        }
        // 处理步骤条
        if (this.active < this.maxIndex) {
          this.active++
        }
      } else {
        this.$message.error("请填写完整")
      }
    },

第五步:点击切换名字

 fn(tab) {
      this.tableIndex = tab.name;
      this.active = tab.name;
    },

第六步:最后实现完成添加功能

// 添加检测
    async addSel() {
      // 先要得到科室id
      let { room_id } = this.notAssList.find((ele) => {
        return ele.ass_id == this.obsObj.ass_id;
      })
      // 拿到man_id
      this.obsObj.man_id = this.$store.state.userInfo.man_id
      // 封装data里面的数据
      // 定义一个数组,然后把遍历好的数据push进去
      let newArray = [];
      this.formatData.forEach((item) => {
        item.children.forEach((ele) => {
          let obj = {
            ass_id: this.obsObj.ass_id,
            room_id: room_id,
            wu_id: item.wu_id,
            mit_id: ele.mit_id,//children里面的
            mires: ele.mires,//children里面的
          }
          newArray.push(obj)
        })
      })
      // console.log(newArray);
      // 根据后端要求拿到的data需要转化成JSON
      this.obsObj.data = JSON.stringify(newArray)
      // 转化完成之后再发异步请求
      let res = await api_addobs(this.obsObj)
      // console.log(res)
      if (res.code == 200) {
        this.$message.success(res.msg)
        // 成功之后 要更新任务数
        this.$store.dispatch("getNotAssNumber")
        // 调转到检测记录
        this.$router.push("/observe/selobs")
      } else {
        this.$message.error("添加失败")
      }
    },

第七步:data中定义的数据

 data() {
    return {
      commBreadcrumbTitle: ["检测管理", "添加检测"],
      notAssList: [],//未完成检测任务
      obsObj: {
        man_id: "",//用户id
        asst_id: 1,//检测任务id为1,消毒任务id为2
        ass_id: "",//任务id
        over_time: "",//完成时间
        data: "",//检测记录值
      },
      active: 0,//步骤决定的顺序
      selwpList: [],//检测对象
      selmitList: [],//浮游生物
      formatData: [],//合并数据
      tableIndex: "0",//实现点击下一步
      maxIndex: 0,
      // 其实就是左侧的长度
      status: false,//控制下一步和完成的
    }
  },
  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值