2021-08-09前端总结

对一年前端工作以及项目的总结

刚入职时此项目已经建好
同时是第一次写csdn。

PC端

pc端主要用到的技术为vue.js+elementUI框架。
首先电脑上需要安装好git以及node.js环境以及vue.js环境,安装node.js以及vue.js参考node.js以及vue.js,安装和如何使用git参考git,并且已经注册好阿里云账号。

1. 克隆项目到本地

使用git clone命令将阿里云服务器上的项目克隆到本地来使用,参数为项目的URL地址,例如:
2021-08-09前端总结_第1张图片

2. 启动项目

然后打开hbuilder,点击左下角的在这里插入图片描述后建议使用npm install --registry=https://registry.npm.taobao.org来安装依赖,安装成功后使用npm run dev启动项目。
在浏览器地址栏中输入localhost:80来访问项目。

3. 分析项目组件
3.1树形组件

想要完成的效果为下图所示:
2021-08-09前端总结_第2张图片

在前端页面中的代码为:

<el-tree
            :data="deptOptions"
            :props="defaultProps"
            :expand-on-click-node="false"
            :filter-node-method="filterNode"
            ref="tree"
            @node-click="handleNodeClick"
            default-expand-all
/>

其中data的作用是展示数据,将返回结果赋值给deptOptions,后端返回的部分接口结构如下图所示:
2021-08-09前端总结_第3张图片

翻看elementUi官网查看发现它所需的数据结构正好与接口中返回的数据结构一致。其中diffInfo判断是否是部门还是公司,id为数据库中取出的唯一标识,label为树中展示的标签名称,children为子节点的值。

props赋值为

defaultProps: {
        children: "children",
        label: "label"
      },

,其中children对应返回结果中的children,label对应返回结果中的label。

expand-on-click-node属性代表是否在点击节点时候展开节点,默认为true,该为false后只有点击左侧箭头时才展开节点。
filter-node-method属性标识对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏。
ref表示本页面可以引用的dom元素。
@node-click表示点击节点的回调方法,参数data表示该节点所对应的对象。js如下所示:

handleNodeClick(data) {
      // console.log(data)
      // console.log(data.id)
      this.queryParams.deptId = data.id;
      // console.log(this.queryParams.deptId)
      this.queryParams.diffInfo = data.diffInfo
      this.getList();
    },

default-expand-all属性表示是否默认展开全部节点。

3.2input组件

想要完成的功能如下图所示:
在这里插入图片描述
在前端页面的代码为:

<el-input
            v-model="deptName"
            placeholder="请输入部门名称"
            clearable
            size="small"
            prefix-icon="el-icon-search"
            style="margin-bottom: 20px"
          />

其中v-model为绑定值,placeholder为占位文本,即在input框中的内容为空时的默认显示文本,clearable表示此input框会出现一个可以手动清空的按钮,size为input框的尺寸,仅仅在type!='textarea'时有效,并且有medium / small / mini三个可选项,prefix-icon为input框首部图标显示,style为此input框的样式。

3.3select组件

想要完成的功能如下图所示:
2021-08-09前端总结_第4张图片
在前端页面的代码为:

<el-select
           v-model="queryParams.status"
            placeholder="用户状态"
            clearable
            size="small"
            style="width: 240px"
          >
            <el-option
              v-for="dict in statusOptions"
              :key="dict.dictValue"
              :label="dict.dictLabel"
              :value="dict.dictValue"
            />
el-select>

其中el-select代表此组件是一个下拉框,el-option代表的是下拉框中的具体条目,并且el-select中 的v-model值为当前被选中的el-option中的value值。
v-for表示便利statusOptions,其中每一项使用dict来代替,key表示此条目的唯一标识,label表示条目显示的具体内容,value表示次条目所代表的值。

3.4datepicker组件

想要完成的功能如下图所示:
2021-08-09前端总结_第5张图片前端代码如下所示:

<el-date-picker
              v-model="dateRange"
              size="small"
              style="width: 240px"
              value-format="yyyy-MM-dd"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
>el-date-picker>

其中value-format属性表示日期的格式为yyyy-MM-dd格式,如2021-08-09,给后台传值时就是这种格式。typedaterange表示这个时间选择器为日期范围选择器,包括开始时间和终止时间,type可选值为year/month/date/dates/ week/datetime/datetimerange/ daterange/monthrangerange-separator属性代表起止日期的分隔符使用’-'来分割,start-placeholderend-placeholder分别表示开始时间和终止时间的占位符。

3.5button组件

想要完成如下图所示功能:
在这里插入图片描述
前端页面的代码如下所示:

<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置el-button>

其中type属性代表按钮的类型,可选为primary / success / warning / danger / info / texticon表示按钮的图标,@click表示点击按钮触发的事件。

3.6table表格

想要完成如下图所示功能:
2021-08-09前端总结_第6张图片前端页面的代码如下所示:

<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
          <el-table-column type="selection" width="60" align="center" />
          <el-table-column align="center" width="60"   label="序号" prop="index">el-table-column>
          <el-table-column label="用户类型" align="center" prop="userType"  /> -->
          <el-table-column label="登录账号" align="center" prop="userName" :show-overflow-tooltip="true" />
          <el-table-column label="真实姓名" align="center" prop="nickName" :show-overflow-tooltip="true" />
          <el-table-column label="部门" align="center" prop="dept.deptName" :show-overflow-tooltip="true" />
          <el-table-column label="联系电话" align="center" prop="phonenumber" width="120" />
          <el-table-column label="状态" align="center">
            <template slot-scope="scope">
              <el-switch
                v-model="scope.row.status"
                active-value="0"
                inactive-value="1"
                @change="handleStatusChange(scope.row)"
              >el-switch>
            template>
          el-table-column>
          <el-table-column label="创建时间" align="center" prop="createTime" width="160">
            <template slot-scope="scope">
              <span>{{ parseTime(scope.row.createTime) }}span>
            template>
          el-table-column>
          <el-table-column
            label="操作"
            align="center"
            width="180"
            class-name="small-padding fixed-width"
          >
            <template slot-scope="scope">
              <el-button
                size="mini"
                type="text"
                icon="el-icon-edit"
                @click="handleUpdate(scope.row)"
                v-hasPermi="['system:user:edit']"
              >修改el-button>
              <el-button
                v-if="scope.row.userId !== 1"
                size="mini"
                type="text"
                icon="el-icon-delete"
                @click="handleDelete(scope.row)"
                v-hasPermi="['system:user:remove']"
              >删除el-button>
              <el-button
                size="mini"
                type="text"
                icon="el-icon-key"
                @click="handleResetPwd(scope.row)"
                v-hasPermi="['system:user:resetPwd']"
              >重置el-button>
            template>
          el-table-column>
el-table>

其中el-table为表格元素,它的v-loading属性为true时会添加一个加载图案,data属性为显示的数据,@selection-change表示当选择项发生变化时会触发该事件。el-table-column表示表格中的一列,type表示对应列的类型。如果设置了 selection 则显示多选框;如果设置了 index 则显示该行的索引(从 1 开始计算);如果设置了 expand 则显示为一个可展开的按钮,此处是设置了多选框,当选择项发生变化时触发handleSelectionChange事件,width表示此列的宽度,align表示此列内容的对齐方式,label表示此列表头显示的标题,prop表示对应列内容的字段名,show-overflow-tooltip表示当内容过长被隐藏时在提示信息中显示全部的内容,class-name表示列的class的name,template中的slot-scope表示插槽,scope相当于一行的数据, scope.row相当于当前行的数据对象。这里就是用插槽 拿到当前行 row是个内置的属性 ,vue slot的scope传递值是父作用域中的源数据改变,值会同步改变;
el-switch表示此组件是一个开关,active-value属性表示打开开关时的值,inactive-value属性表示关闭开关时的值,@change表示switch状态发生变化时的回调函数,也就是说当开关的状态发生改变时触发handleStatusChange事件。v-hasPermi表示封装好的进行权限校验的属性,在菜单管理目录中给对应的按钮设置权限字段时用的就是它的内容。

3.7pagination分页组件

想要完成如下图所示功能:
在这里插入图片描述
前端页面的代码如下:

<pagination
          v-show="total>0"
          :total="total"
          :page.sync="queryParams.pageNum"
          :limit.sync="queryParams.pageSize"
          @pagination="getList"
/>

我们已经在components/Pagination中的index.vue中封装好了分页组件,代码如下所示:

<template>
  <div :class="{'hidden':hidden}" class="pagination-container">
    <el-pagination
      :background="background"
      :current-page.sync="currentPage"
      :page-size.sync="pageSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :total="total"
      v-bind="$attrs"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  div>
template>

<script>
import { scrollTo } from '@/utils/scroll-to'

export default {
  name: 'Pagination',
  props: {
    total: {
      required: true,
      type: Number
    },
    page: {
      type: Number,
      default: 1
    },
    limit: {
      type: Number,
      default: 20
    },
    pageSizes: {
      type: Array,
      default() {
        return [10, 20, 30, 50]
      }
    },
    layout: {
      type: String,
      default: 'total, sizes, prev, pager, next, jumper'
    },
    background: {
      type: Boolean,
      default: true
    },
    autoScroll: {
      type: Boolean,
      default: true
    },
    hidden: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    currentPage: {
      get() {
        return this.page
      },
      set(val) {
        this.$emit('update:page', val)
      }
    },
    pageSize: {
      get() {
        return this.limit
      },
      set(val) {
        this.$emit('update:limit', val)
      }
    }
  },
  methods: {
    handleSizeChange(val) {
      this.$emit('pagination', { page: this.currentPage, limit: val })
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    },
    handleCurrentChange(val) {
      this.$emit('pagination', { page: val, limit: this.pageSize })
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    }
  }
}
script>

<style scoped>
.pagination-container {
  background: #fff;
  padding: 32px 16px;
}
.pagination-container.hidden {
  display: none;
}
style>

设置layout,表示需要显示的内容,布局元素会依次显示。prev表示上一页,next为下一页,pager表示页码列表,除此以外还提供了jumpertotalsize和特殊的布局符号->->后的元素会靠右显示,jumper表示跳页元素,total表示总条目数,size用于设置每页显示的页码数量。

并且在main.js中注册且全局挂载了此组件,调用时直接使用Pagination标签即可,main.js部分代码如下:

import Pagination from "@/components/Pagination";
Vue.component('Pagination', Pagination)

具体解释查看elementUI官网中的pagination。(使用时最好紧跟在el-table元素下)。

3.8dialog组件和form表单

想要完成如下图所示功能:

2021-08-09前端总结_第7张图片前端页面的代码如下所示:

<el-dialog  :title="title" :visible.sync="open" width="600px">
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-row>
          <el-col :span="12">
            <el-form-item label="真实姓名" prop="nickName">
              <el-input v-model="form.nickName" placeholder="请输入用户真实姓名" />
            el-form-item>
          el-col>
          <el-col :span="12">
            <el-form-item label="归属部门" prop="deptId">
              <treeselect v-model="form.deptId" :options="deptOptions" placeholder="请选择归属部门" />
            el-form-item>
          el-col>
          <el-col :span="12">
            <el-form-item label="联系电话" prop="phonenumber">
              <el-input v-model="form.phonenumber" placeholder="请输入联系电话"  />
            el-form-item>
          el-col>
          <el-col :span="12">
            <el-form-item label="邮箱" prop="email">
              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
            el-form-item>
          el-col>
          <el-col :span="12">
            <el-form-item label="登录账号" prop="userName">
              <el-input v-model="form.userName" placeholder="请输入登录账号" />
            el-form-item>
          el-col>
          <el-col :span="12">
            <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
              <el-input v-model="form.password" placeholder="请输入用户密码" type="password" />
            el-form-item>
          el-col>
          <el-col :span="12">
            <el-form-item label="用户性别">
              <el-select v-model="form.sex" placeholder="请选择">
                <el-option
                  v-for="dict in sexOptions"
                  :key="dict.dictValue"
                  :label="dict.dictLabel"
                  :value="dict.dictValue"
                >el-option>
              el-select>
            el-form-item>
          el-col>
          <el-col :span="12">
            <el-form-item label="状态">
              <el-radio-group v-model="form.status">
                <el-radio
                  v-for="dict in statusOptions"
                  :key="dict.dictValue"
                  :label="dict.dictValue"
                >{{dict.dictLabel}}el-radio>
              el-radio-group>
            el-form-item>
          el-col>
          <el-col :span="12">
            <el-form-item label="岗位">
              <el-select v-model="form.postIds" multiple placeholder="请选择">
                <el-option
                  v-for="item in postOptions"
                  :key="item.postId"
                  :label="item.postName"
                  :value="item.postId"
                  :disabled="item.status == 1"
                >el-option>
              el-select>
            el-form-item>
          el-col>
          <el-col :span="12">
            <el-form-item label="角色">
              <el-select v-model="form.roleIds" multiple placeholder="请选择">
                <el-option
                  v-for="item in roleOptions"
                  :key="item.roleId"
                  :label="item.roleName"
                  :value="item.roleId"
                  :disabled="item.status == 1"
                >el-option>
              el-select>
            el-form-item>
          el-col>
          <el-col :span="24">
            <el-form-item label="备注">
              <el-input v-model="form.remark" type="textarea" placeholder="请输入内容">el-input>
            el-form-item>
          el-col>
        el-row>
      el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm" :disabled="disabledAdd">确 定el-button>
        <el-button @click="cancel">取 消el-button>
      div>
    el-dialog>

通常情况下我们新增或修改时会弹出对应的对话框,并且会进行表单的提交,于是用到了dialog对话框与form表单。
dialog对话框的功能为在保留当前页面状态的情况下,告知用户并承载相关操作。title属性表示Dialog 标题区的内容,visible表示是否显示 Dialog,支持 .sync 修饰符,在官网中有一段解释为如果 visible 属性绑定的变量位于 Vuex 的 store 内,那么 .sync 不会正常工作。此时需要去除 .sync 修饰符,同时监听 Dialog 的 open 和 close 事件,在事件回调中执行 Vuex 中对应的 mutation 更新 visible 属性绑定的变量的值。
form表单由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据。现在秃然发现el-form标签中用的是:model而不是v-model,就很神奇,所以来说一下v-model和:model的区别。

	v-model是vue.js中内置的双向数据绑定指令,
	用于表单控件以外的标签是不起作用的
	(即只对表单控件标签的数据双向绑定有效)。
	:model相当于v-bind:model的缩写,
    v-bind动态绑定指令,默认情况下标签自带属性的值是固定的,
	这种只是将父组件的数据传递到了子组件,并没有实现子组件和父组件数据的双向绑定。
	当然引用类型除外,子组件改变引用类型的数据的话,父组件也会改变的。

rules属性表示表单验证规则,这个相当于每个组件前边的*,具体内容如下所示:

rules: {
        userName: [
          { required: true, message: "登录账号不能为空", trigger: "blur" }
        ],
        nickName: [
          { required: true, message: "真实姓名不能为空", trigger: "blur" }
        ],
        deptId: [
          { required: true, message: "归属部门不能为空", trigger: "blur" }
        ],
        password: [
          { required: true, message: "用户密码不能为空", trigger: "blur" }
        ],
        email: [
          {
            type: "email",
            message: "'请输入正确的邮箱地址",
            trigger: ["blur", "change"]
          }
        ],
        phonenumber: [
          {
            pattern: /(^(\d{3,4}-)?\d{7,8})$|(^0?(13[0-9]|15[012356789]|18[0-9]|14[57])[0-9]{8})$/,
            message: "请输入正确的联系电话",
            trigger: "blur"
          }
        ]
      }

label-width表示表单域标签的的宽度,即每个el-form-item标签中的label属性内容的宽度;
通过 rowcol 组件,并通过 col 组件的 span 属性我们就可以自由地组合布局。
prop属性是表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的。
el-radio-group为一个单选框组,结合el-radio-group元素和子元素el-radio可以实现单选组,在el-radio-group中绑定v-model,在el-radio中设置好label即可,无需再给每一个el-radio绑定变量,另外,还提供了change事件来响应变化,它会传入一个参数value。在el-select标签上添加`multiple属性即可使下拉框变为复选框。

3.9upload上传组件

想要完成的功能如下:
2021-08-09前端总结_第8张图片前端页面的代码如下所示:

<el-upload
        ref="upload"
        :limit="1"
        accept=".xlsx, .xls"
        :headers="upload.headers"
        :action="upload.url + '?updateSupport=' + upload.updateSupport"
        :disabled="upload.isUploading"
        :on-progress="handleFileUploadProgress"
        :on-success="handleFileSuccess"
        :auto-upload="false"
        drag
      >
        <i class="el-icon-upload">i>
        <div class="el-upload__text">
          将文件拖到此处,或
          <em>点击上传em>
        div>
        <div class="el-upload__tip" slot="tip">
          <el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
          <el-link type="info" style="font-size:12px" @click="importTemplate">下载模板el-link>
        div>
        <div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“xls”或“xlsx”格式文件!div>
      el-upload>

其中el-upload标签的ref属性表示可以获取到的本页面的dom元素,limit表示最大允许上传个数,accept表示接受上传的文件类型,headers表示设置上传的请求头部,action表示必选参数,上传的地址,disabled表示是否禁用,on-progress表示文件上传时的钩子,on-success表示文件上传成功时的钩子,auto-upload表示是否在选取文件后立即进行上传,drag表示是否启用拖拽上传。

4.分析功能
4.1.新增与修改
submitForm: function() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          let params = this.form;
          let diffInfo = this.validDeptId(params.deptId, this.deptOptions);
          params.diffInfo = diffInfo;
          // console.log(params.diffInfo)
          if (this.form.userId != undefined) {
            updateUser(params).then(response => {
              if (response.code === 200) {
                this.msgSuccess("修改成功");
                this.open = false;
                this.getList();
              } else {
                this.msgError(response.msg);
              }
            });
          } else {
            this.disabledAdd = true;
            addUser(params).then(response => {
              if (response.code === 200) {
                this.msgSuccess("新增成功");
                this.open = false;
                this.getList();
              } else {
                this.disabledAdd = false
                this.msgError(response.msg);
              }
            });
          }
        }
      });
    },
4.2.删除
handleDelete(row) {
      const userIds = row.userId || this.ids;
      this.$confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', "警告", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }).then(function() {
          return delUser(userIds);
        }).then(() => {
          this.getList();
          this.msgSuccess("删除成功");
        }).catch(function() {});
    },
4.3.查询
getList() {
      this.loading = true;
      let params = {
          types:'01,02,03,04,05,06,07,08,09',
          pageNum: 1,
          pageSize : 1000
      }
      findCompanyListByType(params).then((res) => {
        if (res.code === 200) {
          // console.log(res.data)
          this.danWeiOptions = res.data
        } else {
          this.$message({
            type: 'error',
            message: res.msg
          })
        }
      })
      listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
          // console.log(response)
          this.userList = response.rows;
          this.userList.map((item,index) => {
            item.userType = this.selectDictLabel(this.userTypeOptions, item.userType);
            item.index = (this.queryParams.pageNum - 1) * this.queryParams.pageSize + index + 1;
          })
          this.total = response.total;
          this.loading = false;
          // console.log(response)
        }
      );
    },
4.4.单查
handleUpdate(row) {
      this.disabledAdd = false
      this.reset();
      this.getTreeselect();
      const userId = row.userId || this.ids;
      getUser(userId).then(response => {
        this.form = response.data;
        this.postOptions = response.posts;
        this.roleOptions = response.roles;
        this.form.postIds = response.postIds;
        this.form.roleIds = response.roleIds;
        this.open = true;
        this.title = "修改用户";
        this.form.password = "";
      });
    },
4.5.导入
/** 导入按钮操作 **/
    handleImport() {
      this.upload.title = "用户导入";
      this.upload.open = true;
    },
    /** 下载模板操作 */
    importTemplate() {
      importTemplate().then(response => {
        this.download(response.msg);
      });
    },
    // 文件上传中处理
    handleFileUploadProgress(event, file, fileList) {
      this.upload.isUploading = true;
    },
    // 文件上传成功处理
    handleFileSuccess(response, file, fileList) {
      this.upload.open = false;
      this.upload.isUploading = false;
      this.$refs.upload.clearFiles();
      this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
      this.getList();
    },
    // 提交上传文件
    submitFileForm() {
      this.$refs.upload.submit();
    },

其中this.download方法封装在其他位置,如图所示具体方法:

export function download(fileName) {
	window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
}
4.6.导出

下边为使用后端接口进行导出:

handleExport() {
      const queryParams = this.queryParams;
      this.$confirm('是否确认导出所有用户数据项?', "警告", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }).then(function() {
          return exportUser(queryParams);
        }).then(response => {
          this.download(response.msg);
        }).catch(function() {});
    },

下边为纯前端导出:
使用此功能需要引入两个文件:Export2Excel.js与util.js

此处为导出json格式的数据。

async exportExcel() {
        let params = {
          pageSize: this.total,
          pageNum: 1,
          conditions: this.conditions,
          effectHours: this.effectHours,
          isEffectWork: this.isEffectWork,
          windDirection: this.windDirection
        }
        if (this.searchDate && this.searchDate.length > 0) {
          if (typeof (this.searchDate[0]) == 'object') {
            params.dateStart = formatDate(this.searchDate[0], 'yyyy-MM-dd')
          } else {
            params.dateStart = this.searchDate[0]
          }
          if (typeof (this.searchDate[1]) == 'object') {
            params.dateEnd = formatDate(this.searchDate[1], 'yyyy-MM-dd')
          } else {
            params.dateEnd = this.searchDate[1]
          }
        } else {
          params.dateStart = ''
          params.dateEnd = ''
        }
        let res = await listWeather(params)
        if (res.code === 200) {
          this.exportList = res.data.list
          this.exportList.map((item) => {
            if(item.influenceState.indexOf(",") >= 0){
              let temp = item.influenceState.split(",")
              for(let i = 0;i < temp.length; i++){
                temp[i] = this.selectDictLabel(this.effectSituationOpetion, temp[i])
              }
              item.influenceState = temp.toString()
            }else{
              item.influenceState = this.selectDictLabel(this.effectSituationOpetion, item.influenceState);
            }
            // item.influenceState = this.selectDictLabel(this.effectSituationOpetion, item.influenceState);
            item.isEffectWork = this.selectDictLabel(this.isEffectWorkOpetion, item.isEffectWork);
            item.temperature = item.minTemperature + '~' + item.maxTemperature
            item.id = item.id + ''
          })
        }
        //开始尝试
        if (this.updateMonth != null) {
          this.exportMonth = this.updateMonth
        } else {
          this.exportMonth = formatDate(new Date(), 'yyyy')
        }
        import('@/api/tool/Export2Excel1').then(excel => {
          const multiHeader = []
          const tHeader = ['日期(必填)', '天气情况(必填)', '最低气温(℃)', '最高气温(℃)', '风向', '风力', '降雨量(mm)', '开始时间', '结束时间',
            '影响作业', '影响类别', '影响时长(小时)', '影响作业情况描述', '填写人(必填)'
          ] //表头
          const title = []
          //表头对应字段
          const filterVal = ['reportDate', 'conditions', 'minTemperature', 'maxTemperature', 'windDirection',
            'windSize', 'rainfall', 'startTime', 'endTime', 'isEffectWork', 'influenceState', 'effectHours', 'workDescribe', 'creater'
          ]
          const list = this.exportList
          const data = this.formatJson(filterVal, list)
          data.map(item => {
            // console.log(item)
            item.map((i, index) => {
              if (!i) {
                item[index] = ''
              }
            })
          })
          const merges = [] //合并单元格
          try {
            excel.export_json_to_excel({
              multiHeader,
              header: tHeader,
              merges,
              data,
              filename: '天气情况统计',
              autoWidth: true,
              bookType: 'xlsx',
              type: 'weather',
              title
            })
            this.$message({
              type: "success",
              message: "导出成功"
            })
          } catch (e) {
            console.log(e)
          }

        })
        //尝试结束

      },

此处为导出将数据导出为表格形式。

async exportExcel() {
        const that = this
        let xiechuanLength = 0 //卸船作业变化
        let dangrichukujihua = 0 //当日出库计划变化
        let weather = 0         //港口天气设备影响情况变化
        let weatherContent = 0  //天气内容
        let weatherHeji = 0     //天气合计
        let siteHotCoal = 0     //场地高温煤变化
        let siteHotCoalContent = 0 //场地高温煤内容
        const borderAll = {  //单元格外侧框线
            top: {
              style: 'thin'
            },
            bottom: {
              style: 'thin'
            },
            left: {
              style: 'thin'
            },
            right: {
              style: 'thin'
            }
          };
        const titleClass = {
          font: {
            name:'黑体',
            sz: 10,
            bold: false,
          },
          alignment: {
            horizontal: "center",
            vertical: "center"
          },
          border: borderAll,
          fill: {
            fgColor: {rgb: "cccccc"},
          },
        }
        const numClass = {
          font: {
            name:'黑体',
            sz: 10,
            bold: false,
            color:{
              rgb: 'e43927'
            }
          },
          alignment: {
            horizontal: "center",
            vertical: "center"
          },
          border: borderAll,
        }
        const defaultClass = {
          font: {
            name:'黑体',
            sz: 8,
            bold: false,
          },
          alignment: {
            horizontal: "center",
            vertical: "center"
          },
          border: borderAll
        }
        import("@/api/tool/Export2Excel1").then(excel => {
          excel.export_table_to_excel({
            id: 'exportTable',
            filename: '调度日报',
            bookType: 'xlsx',
            styleFun: function(ws) { // 自定义样式
              //给合并的单元格赋值空,不然四周的线不会显示
              const merges = ws['!merges']
              merges.map((item) => {
                  const s = item.s
                  const e = item.e
                  let index = 0
                  for(let i = s.r; i <= e.r; i++){
                    for(let j = s.c; j <= e.c; j++){
                      index++
                      if(index === 1){
                        //跳过第一个,这是原来应该有的值
                        continue;
                      }
                      const cellTemp = {
                        v: '',
                        t: 's'
                      };
                      const cell_refTemp = XLSX.utils.encode_cell({
                        c: j,
                        r: i
                      });
                      ws[cell_refTemp] = cellTemp;
                    }
                  }
              })

              let result = []
              for(let i = 0; i < 15; i++){
                result.push({'wch':12})
              }
              ws['!cols'] = result;
              for (let item in ws) {
                if(item === "!ref"){
                  continue;
                } else if(item === "!merges"){
                  continue;
                } else if(item === "A1"){
                  ws['A1'].s = {
                    font: {
                      name:'黑体',
                      sz: 12,
                      bold: false,
                      color: {
                        rgb: "ff0000"
                      }
                    },
                    border:{
                      top: {
                        style: 'thin'
                      },
                      bottom: {
                        style: 'thin'
                      },
                      left: {
                        style: 'thin'
                      },
                      right: {
                        style: 'thin'
                      }
                    },
                    alignment: {
                      horizontal: "center",
                      vertical: "center"
                    }
                  };
                  continue;
                } else {
                  ws[item].t = 's'
                  let temp = ws[item].v
                  if (typeof(temp)=='string'){
                    temp = temp.replace("^","")
                    ws[item].v = temp
                  }
                  let col = item.substring(0,1)
                  const rowNum = Number(item.substring(1))
                  if(item.length === 2 && item.indexOf('2') === 1){
                    let tempPosition = 'left'
                    if(col === 'A' || col === 'H' || col === 'M'){
                      tempPosition = 'right'
                    }
                    //第二行
                    ws[item].s = {
                      font: {
                        name:'仿宋',
                        sz: 8,
                        bold: false,
                        color: {
                          rgb: "ff0000"
                        }
                      },
                      alignment: {
                        horizontal: tempPosition,
                        vertical: "center"
                      },
                      border: {
                        top: {
                          style: 'thin'
                        },
                        bottom: {
                          style: 'thin'
                        },
                        left: {
                          style: 'thin'
                        },
                        right: {
                          style: 'thin'
                        }
                      }
                    };
                  } else if(item.length === 2 && (item.indexOf('3') === 1 || item.indexOf('4') === 1
                    || item.indexOf('5') === 1 || item.indexOf('9') === 1)){
                    //第三四五行,9,
                    ws[item].s = titleClass
                  } else if(item.length === 3 && (item.indexOf('10') === 1 || item.indexOf('15') === 1)){
                    //10 15
                    ws[item].s = titleClass
                  } else if(item.length === 2 && (item.indexOf('6') === 1 || item.indexOf('7') === 1 || item.indexOf('8') === 1 )
                            && col != 'A' && col != 'B' && col != 'G' ){
                    // 6 7 8行 不包括 A B G列
                    ws[item].s = numClass
                  } else if(item.length === 3 &&  item.indexOf('11') === 1 ){
                    //第十一行
                    if(col === 'A' || col === 'B' || col === 'C' || col === 'D'){
                      // 第十一行的abcd列
                      ws[item].s = defaultClass
                    } else if(col === 'E' || col === 'F'){
                      // 第十一行的ef列
                      ws[item].s = numClass
                    } else {
                      // 第十一行剩下的列
                      ws[item].s = titleClass
                    }
                  } else if(item.length === 3 && (item.indexOf('12') === 1 || item.indexOf('13') === 1 || item.indexOf('14') === 1)){
                    //第12,13,14行
                    if(col === 'A' || col === 'D' || col === 'G'){
                      ws[item].s = defaultClass
                    } else {
                      ws[item].s = numClass
                    }
                  } else if(item.length === 3 && (item.indexOf('16') === 1 || item.indexOf('17') === 1
                      || item.indexOf('18') === 1 || item.indexOf('19') === 1 || item.indexOf('20') === 1 || item.indexOf('21') === 1)){
                    //第16-21行
                    if(col === 'A' || col === 'M' || col === 'N'){
                      ws[item].s = titleClass
                    } else if(col === 'O'){
                      ws[item].s = numClass
                    } else if(item.indexOf('17') === 1 || item.indexOf('19') === 1 || item.indexOf('21') === 1){
                      ws[item].s = numClass
                    } else {
                      ws[item].s = defaultClass
                    }
                    // 22-23行
                  } else if(item.length === 3 && (item.indexOf('22') === 1 || item.indexOf('23') === 1 )){
                    if(col === 'O'){
                      ws[item].s = numClass
                    }else{
                      ws[item].s = titleClass
                    }
                    // 24
                  } else if(item.length === 3 && (item.indexOf('24') === 1 && col != 'M')){
                    if(col === 'A'){
                      ws[item].s = titleClass
                    }else
                     ws[item].s = numClass
                     // 25 26
                  } else if(item.length === 3 && (item.indexOf('25') === 1 || item.indexOf('26') === 1 )){
                    if(col === 'B' || col === 'C' || col === 'D' || col === 'E'){
                      ws[item].s = numClass
                    }else{
                      ws[item].s = titleClass
                    }
                    // 27 31 32 36 37
                  } else if(item.length === 3 && (item.indexOf('27') === 1 || item.indexOf('31') === 1 || item.indexOf('32') === 1 || item.indexOf('36') === 1 || item.indexOf('37') === 1)){
                    ws[item].s = titleClass
                    // 28
                  } else if(item.length === 3 && item.indexOf('28') === 1){
                    if(col === 'B' || col === 'C' || col === 'D' || col === 'E' || col === 'F'){
                      ws[item].s = titleClass
                    } else{
                      ws[item].s = numClass
                    }
                    // 29 30
                  } else if(item.length === 3 && (item.indexOf('29') === 1 || item.indexOf('30') === 1)){
                    if(col === 'A' || col === 'F'){
                      ws[item].s = titleClass
                    }else{
                      ws[item].s = numClass
                    }
                    // 33 34 35
                  } else if(item.length === 3 && (item.indexOf('33') === 1 || item.indexOf('34') === 1 || item.indexOf('35') === 1)){
                    if(col === 'A'){
                      ws[item].s = titleClass
                    }else{
                      ws[item].s = numClass
                    }
                    // 卸船作业38+
                  } else if(item.indexOf('38') === 1){
                    if(that.dataList_7_xiechuan.length != 0){
                      for(let i = 0;i < that.dataList_7_xiechuan.length;i++){
                        xiechuanLength = 38 + i
                        if(item.indexOf(xiechuanLength + '') === 1){
                          if(col === 'J' || col === 'M'){
                            ws[item].t = 's'
                            let temp = ws[item].v
                            if (typeof(temp)=='string'){
                              temp = temp.replace("^","")
                              ws[item].v = temp
                            }
                            ws[item].s = defaultClass
                          }
                          ws[item].s = defaultClass
                        }
                      }
                      dangrichukujihua = xiechuanLength + 1
                    }else{
                      ws[item].s = titleClass
                      dangrichukujihua = 38
                    }

                    //当日出库计划行
                  } else if(item.indexOf(dangrichukujihua + '') === 1 || item.indexOf(dangrichukujihua + 1 + '') === 1 || item.indexOf(dangrichukujihua + 2 + '') === 1){
                    ws[item].s = titleClass
                  } else if(item.indexOf(dangrichukujihua +3 + '') === 1 || item.indexOf(dangrichukujihua + 4 + '') === 1 || item.indexOf(dangrichukujihua + 5 + '') === 1){
                      if(col === 'A' || col === 'D' || col === 'G' || col === 'K'){
                        ws[item].s = titleClass
                      }else{
                        ws[item].s = numClass
                      }
                    weather = dangrichukujihua + 6
                    // 天气设备行 标题
                  } else if(item.indexOf(weather + '') === 1 || item.indexOf(weather + 1 + '') === 1){
                    ws[item].s = titleClass
                    weatherContent = weather + 2
                    // 天气设备行 内容
                  } else if(item.indexOf(weatherContent + '') === 1){
                    // 判断长度是否为0 遍历
                    if(that.dataList_11_tianqi.length != 0){
                      for(let i = 0;i < that.dataList_11_tianqi.length; i++){
                        weatherContent = weatherContent + i
                        if(item.indexOf(weatherContent + '') === 1){
                          if(col === 'H' || col === 'I'){
                            ws[item].t = 's'
                            let temp = ws[item].v
                            if (typeof(temp)=='string'){
                              temp = temp.replace("^","")
                              ws[item].v = temp
                            }
                            ws[item].s = defaultClass
                          }
                          ws[item].s = defaultClass
                        }
                      }
                      weatherHeji = weatherContent + 1
                    } else{
                      if(col === 'A'){
                        ws[item].s = titleClass
                      }else{
                        if(col === 'H' || col === 'I'){
                          ws[item].t = 's'
                          let temp = ws[item].v
                          if (typeof(temp)=='string'){
                            temp = temp.replace("^","")
                            ws[item].v = temp
                          }
                          ws[item].s = defaultClass
                        }
                        ws[item].s = defaultClass
                      }
                      weatherHeji = weatherContent
                      siteHotCoal = weatherHeji + 1
                    }
                    // 天气合计行
                  } else if(item.indexOf(weatherHeji + '') === 1){
                    if(col === 'A'){
                      ws[item].s = titleClass
                    }else{
                      if(col === 'H' || col === 'I'){
                        ws[item].t = 's'
                        let temp = ws[item].v
                        if (typeof(temp)=='string'){
                          temp = temp.replace("^","")
                          ws[item].v = temp
                        }
                        ws[item].s = defaultClass
                      }
                      ws[item].s = defaultClass
                    }
                    siteHotCoal = weatherHeji + 1
                    // 场地高温煤标题
                  } else if(item.indexOf(siteHotCoal + '') === 1 || item.indexOf(siteHotCoal + 1 + '') === 1){
                    ws[item].s = titleClass
                    siteHotCoalContent = siteHotCoal + 2
                  } else if(item.indexOf(siteHotCoalContent + '') === 1){
                    if(that.dataList_12_gaowen.length != 0){
                      for(let i = 0;i < that.dataList_12_gaowen.length; i++){
                        siteHotCoalContent = siteHotCoalContent + i
                        if(item.indexOf(siteHotCoalContent + '') === 1){
                          if(col === 'D' || col === 'E' || col === 'F' || col === 'G'){
                            ws[item].t = 's'
                            let temp = ws[item].v
                            if (typeof(temp)=='string'){
                              temp = temp.replace("^","")
                              ws[item].v = temp
                            }
                            ws[item].s = defaultClass
                          }
                          ws[item].s = defaultClass
                        }
                      }
                    }
                  }
                  else {
                  ws[item].t = 's'
                  let temp = ws[item].v
                  if (typeof(temp)=='string'){
                    temp = temp.replace("^","")
                    ws[item].v = temp
                  }
                    ws[item].s = defaultClass
                  }
                }
              }
            }
          });
        });
      },
4.7.echarts的使用

想要完成的效果图如下所示:
2021-08-09前端总结_第9张图片前端页面的代码如下所示:

showCharts(){
        let myChart = this.$echarts.init(this.$refs.chart_right);

        const option = {
          tooltip: {
            trigger: 'axis',
            axisPointer: {
              type: 'cross',
              crossStyle: {
                color: '#999'
              }
            }
          },
          legend: {
            left: 'center',
            top: '0px',
            textStyle: { //图例文字的样式
              color: '#444',
              fontSize: 12
            },
            data: ['计划量', '动力煤装出量', '块煤装出量','合计', '超欠']
          },
          grid: {
            left: '6%',
            right: '4%',
            bottom: '3%',
            containLabel: true
          },
          xAxis: [{
            type: 'category',
            data: this.dateTypeValue,
            axisPointer: {
              type: 'shadow'
            },
            axisLabel: {
              show: true,
              textStyle: {
                color: '#444'
              }
            },
          }],
          yAxis: [{
              type: 'value',
              name: '量(吨)',
              nameTextStyle: {
                color: "#444"
              },
              // min: 100,
              // max: 600,
              // interval: 100,
              // axisLabel: {
              //   formatter: '{value} 元'
              // },
              axisLabel: {
                show: true,
                textStyle: {
                  color: '#444'
                }
              },
            },
            {
              type: 'value',
              name: '超/欠(吨)',
              nameTextStyle: {
                color: "#444"
              },
              // min: -20000000,
              // max: 20000000,
              axisLabel: {
                  margin: 10,
                  color: function (value, index) {
                    return value.indexOf('-') >= 0 ? '#ff596f' : '#444444';
                  },
                  fontSize: 12
              }
            }
          ],
          series: [{
              name: '计划量',
              type: 'bar',
              label: {
                show: true,
                position: 'inside'
              },
              data: this.taskPlanCount
            },
            {
              name: '动力煤装出量',
              type: 'bar',
              stack: '总量',
              label: {
                show: true,
                position: 'inside'
              },
              data: this.powerCoalCount
            },
            {
              name: '块煤装出量',
              type: 'bar',
              stack: '总量',
              label: {
                show: true,
                position: 'inside'
              },
              data: this.pieceCoalCount
            },
            {
              name: '合计',
              type: 'bar',
              label: {
                show: true,
                position: 'inside'
              },
              data: this.total
            },
            {
              name: '超欠',
              type: 'line',
              yAxisIndex: 1,
              data: this.overUnder
            }
          ]
        };
        console.warn(this.overUnder)
        myChart.setOption(option)
      },

具体使用说明清查看echarts官网。

5.nginx、redis、以及打包、启动项目
5.1.nginx(示例)
1、在/home/zhzy/下创建nginx目录:mkdir nginx
2、在/home/zhzy/下创建pcre目录:mkdir pcre,访问https://ftp.pcre.org/pub/pcre/,选择版本下载,将下载好的pcre-8.33.tar.gz依赖包放入到pcre目录中,并解压:
  (1)、tar zxvf pcre-8.33.tar.gz
(2)、解压完后配置自动管理目录:./configure
(3)、编译:make
IF 出现make: *** No targets specified and no makefile found.  Stop. 错误
执行 yum update命令 添加环境C++ yum install -y gcc gcc-c++

(5)、编译安装:make install
3、将下载的nginx-1.9.10.tar.gz放在/home/zhzy/nginx目录下,并解压:
(1)tar zxvf nginx-1.9.10.tar.gz
(2)、解压完后配置自动管理目录:./configure
当执行./configure时报下面的错误

则需要安装zlib-devel即可。SSH执行以下命令	yum install -y zlib-devel

(3)、编译:make
(4)、编译安装:make install1
4、此时进入/home/zhzy/nginx/sbin/目录下,启动nginx:./nginx,如出现如下页面则安装成功。

启动完成(注意将防火墙关闭或者改iptables对外提供端口)。
5、进入/home/zhzy/nginx/conf/目录下,编辑nginx.conf文件:
vi nginx.conf
将server监听(listen)端口改为80(所需的端口),在第一个location块内将root的内容改为/home/zhzy/dist(打包后的页面内容),在第二个location块内首先将location改为
location/prod-api/,再将块内的proxy_pass改为http://192.168.1.80:9080/

6、将dist(打包后的页面)放入到/home/zhzy/下
7、进入到/home/zhzy/nginx/sbin/下,重启nginx:
   ./nginx -s reload
  重启成功后访问192.168.1.29:端口号即可,

2021-08-09前端总结_第10张图片2021-08-09前端总结_第11张图片
2021-08-09前端总结_第12张图片
2021-08-09前端总结_第13张图片
在这里插入图片描述

5.2.redis(示例)
将下载的redis-5.0.3.tar.gz放置/home/zhzy目录下,并解压:
tar xzf redis-5.0.3.tar.gz

tar -xzvf redis-5.0.3.tar.gz 
2、进入redis-5.0.3目录下,编译并安装:///yum install gcc-c++
  ①、make
  ②、make install
当我执行编译时,报错:

因为未安装gcc,安装gcc及相关依赖包(XXXX为相关版本号,视自己情况而定),可以使用linux光驱挂载,直接使用linux的系统盘内置rpm包:
rpm -ivh glibc-devel-XXXX.rpm
rpm -ivh cpp-XXXX.rpm
rpm -ivh binutils-XXXX.rpm
rpm -ivh gcc-XXXX.rpm
rpm -ivh mpfr-XXXX.rpm
rpm -ivh jemalloc-XXXX.rpm
补充:rpm -ivh jemalloc-XXXX.rpm
需要后加rpm格式的压缩包

3.将光驱挂载到Linux系统上;
创建挂载点: mkdir /mnt/cdrom
挂载光驱 : mount /dev/sr0 /mnt/cdrom 
注意:/dev/sr0代表光驱 


Packages目录下有4621个rpm包,其中包含了第二步骤里面的6个rpm包和依赖包。
从第一个rpm包开始装,先查看有多少个glibc-devel包:

这里面结果为两个,选择白色框框里面的版本(64)安装,安装时可能会出现 xxx被xxx需要(例:libpng-1.5.13-7.el7_2.i686.rpm 被glibc-devel-2.17-105.el7.x86_64.rpm需要),这时候一步一步查询所需要的rpm,输入ls xxx*(例:ls libpng*)

然后将查询出来的结果按照所需挨个安装(注意只安装64或者32位),每次安装应该都会有所需要的依赖包直到全部安装完成。
4:执行第二步骤
make
make install
5:进入redis-5.0.3目录下的redis.conf
1.将bind的127.0.0.1注掉
2.将daemonize的no改为yes 
3.启动redis:  redis-server redis.conf
启动完成(注意将防火墙关闭或者改iptables对外提供端口)

2021-08-09前端总结_第14张图片在这里插入图片描述
2021-08-09前端总结_第15张图片
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.3.打包启动项目
将后台程序打包后命名为glg_server.jar后放到服务器上,将以前的包保存好后在当前目录下进行启动,
输入命令启动后台jar包,
nohup java -jar glg_server.jar & tail -f nohup.out		//启动服务器(自建系统接口)
				//打印日志

nohup java -jar glg_webservice-api.jar & tail -f nohup.out //启动服务器(TSW接口)

之后将前台包(dist)打好后放到对应的目录下(看nginx的配置了),

然后进入到nginx的sbin目录下输入
 Nginx -s reload
重启nginx,如果第一次启动则输入
Nginx -s start
到此部署完毕。

2021-08-09前端总结_第16张图片2021-08-09前端总结_第17张图片2021-08-09前端总结_第18张图片

你可能感兴趣的:(2021-08-09前端总结)