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,//控制下一步和完成的
}
},