Plan

  • 优化白名单功能,增加修改数据模块,使可以通过前端CRUD单个服务名。

难点:

  • 要考虑设计问题:整条服务名列表是一个字符串,单条服务名以”;"间隔,如com.ids;com.systemui; 现在需要实现点击“修改按钮”,能对单条服务名进行增删改。讨论过后可以两种实现方案,一种是仿造微信白名单功能,一种是用列表来展示出整条服务名列表中的每一个服务名。
  • 要考虑用户乱输入数据情况,比如输入多个“;;;”输入中文“;”,忘记输入“;",加了很多空格等的情况
  • 不能在数据库新建表,因为导师说会造成数据冗余。
  • 要实现点击“修改数据”出现的弹窗实现全覆盖页面,给用户感觉是新打开了一个页面,但其实是一个弹窗。

效果

优化前:

ingress白名单 网段 ssid白名单_数据


优化后:

第一种:1.仿造微信白名单实现效果如下,这种导师说用户改动自由度太高,容易造成数据错误,所以不行

ingress白名单 网段 ssid白名单_ingress白名单 网段_02

最终采用第二种:列表来实现,效果如下:

ingress白名单 网段 ssid白名单_javascript_03

点击"修改数据"后弹出如下:

ingress白名单 网段 ssid白名单_数据_04

新增功能:

ingress白名单 网段 ssid白名单_ingress白名单 网段_05


编辑功能:

ingress白名单 网段 ssid白名单_java_06


用户可在此弹出框对单个服务名进行增删改,操作完后可点击“提交”按钮,就实现了修改服务名列表数据,同时版本号会+1。点击“关闭”会提示如下:

ingress白名单 网段 ssid白名单_数据_07

Do

第一步:增加"修改数据"按钮,和对应弹出框

<template>
  <div class="execution">
    <basic-container>
      <el-row :gutter="10">
        <el-col :span="this.clickObj ? 0 : 24">
          <el-button type="primary" @click="handleAdd">新增</el-button>
          <avue-crud
            ref="crud"
            :page.sync="page"
            :data="tableData"
            :table-loading="tableLoading"
            :option="tableOption"
            v-model="form"
            @on-load="getPage"
            @refresh-change="refreshChange"
            @row-update="handleUpdate"
            @row-save="handleSave"
            @row-del="handleDel"
            @sort-change="sortChange"
            @search-change="searchChange"
          >
            <template slot="menu" slot-scope="scope">
              <el-button
                type="text"
                icon="el-icon-view"
                size="small"
                plain
                @click="handleItem(scope.row, scope.index)"
                >修改数据
              </el-button>
            </template>
          </avue-crud>
          <!-- 用户新增对话框 -->
          <el-dialog
            :title="dialog.title"
            :visible.sync="dialog.open"
            width="1000px"
            append-to-body
            row-key="id"
          >
            <template>
              <div>
                <span style="margin-left: 10px">服务名称列表</span>
              </div>
              <el-input
                required="true"
                v-model="dialog.serviceNameList"
                :rows="3"
                type="textarea"
                placeholder="请输入服务名称列表"
              />
              <div>
                <span style="margin-left: 10px">车厂名称</span>
              </div>
              <el-select
                placeholder="请选择车厂"
                v-model="dialog.vehicleFactoryName"
              >
                <el-option
                  required="true"
                  v-for="item in dialog.options"
                  :key="item.value"
                  :label="item.label"
                  :value="item.value"
                />
              </el-select>
            </template>
            <div slot="footer" class="dialog-footer">
              <el-button type="primary" @click="handleSave">确 定</el-button>
              <el-button @click="dialog.open = false">取 消</el-button>
            </div>
          </el-dialog>
        </el-col>
        <el-col :span="24" v-if="this.clickObj">
          <el-card class="box-card">
            <el-header>
              <h3 style="float: left">
                <i class="el-icon-document-copy"></i>
                服务名列表{{ this.clickObj.type }}
              </h3>
              <el-row style="float: right">
                <el-button type="success" @click="handleUpdate">提交</el-button>
                <el-button type="danger" @click="handleItem()">关闭</el-button>
              </el-row>
            </el-header>
            <avue-crud
              ref="crud"
              :page.sync="page2"
              :data="tableData2"
              :table-loading="tableLoading"
              :option="tableOption2"
              :before-open="beforeOpen2"
              v-model="form2"
              @on-load="getPage2"
              @refresh-change="refreshChange2"
              @row-update="handleUpdate2"
              @row-save="handleSave2"
              @row-del="handleDel2"
              @sort-change="sortChange2"
              @search-change="searchChange2"
            >
            </avue-crud>
          </el-card>
        </el-col>
      </el-row>
    </basic-container>
  </div>
</template>

其中: 实现点击“修改数据”出现的弹窗实现全覆盖页面,给用户感觉是新打开了一个页面,但其实是一个弹窗。

**答案:**通过定义一个clickObj,并给弹出的avue添加:before-open="beforeOpen2"具体如下:

ingress白名单 网段 ssid白名单_javascript_08


ingress白名单 网段 ssid白名单_前端_09


beforeOpen2方法:

beforeOpen2(done) {
      this.$set(this.form2, "id", this.clickObj.id);
      this.$set(this.form2, "type", this.clickObj.type);
      done();
    },

第二步:添加table

export const tableOption = {
    dialogDrag: true,
    border: true,
    indexLabel: '序号',
    stripe: true,
    menuAlign: 'center',
    align: 'center',
    menuType: 'text',
    searchShow: false,
    excelBtn: false,
    printBtn: false,
    addBtn: false,
    editBtn: false,
    delBtn: false,
    viewBtn: false,
    selection: false,
    column: [
        {
            type: 'textarea',
            label: '服务名列表',
            prop: 'serviceNameList',
            search: false,
            slot: true,
            width: 500,
            headerslot: true,              
        },
        {
            label: '版本',
            prop: 'version',
            search: false,
            slot: true,
            headerslot: true,
        },

        {
            label: '车厂',
            prop: 'vehicleFactoryName',
            search: false,
            slot: true,
            headerslot: true,
            type: 'select',
            dicData: [{
                label: '一',
                value: 'w'
            }, {
                label: '上',
                value: 's'
            }]
        },
        {
            label: '创建时间',
            prop: 'createTime',
            display: false,
            rules: [
                {
                    required: true,
                    message: '请输入创建时间',
                    trigger: 'blur'
                },
            ],
            format: 'yyyy-MM-dd HH:mm:ss',
            valueFormat: 'yyyy-MM-dd HH:mm:ss',
        }
    ]
}
export const tableOption2 = {
    dialogDrag: true,
    border: true,
    indexLabel: '序号',
    stripe: true,
    menuAlign: 'center',
    align: 'center',
    menuType: 'text',
    searchShow: false,
    excelBtn: false,
    printBtn: false,
    addBtn: true,
    editBtn: true,
    delBtn: true,
    viewBtn: false,
    selection: false,
    menu: true,
    columnBtn: false,
    refreshBtn:false,
    searchBtn:false,
    addTitle:"新增单个服务名",
    column: [
        {
            type: 'input',
            label: '服务名列表',
            prop: 'serviceNameModifyList',
            slot: true,
            headerslot: true,              
        }
    ]
}

第三步:前后端交互js

```javascript
import ajaxRequest from '../ajaxRequest'

export function getPage(query) {
    return ajaxRequest({
        url: '/whitelist/page',
        method: 'get',
        params: query
    })
}

export function addObj(obj) {
    return ajaxRequest({
        url: '/whitelist',
        method: 'post',
        data: obj
    })
}

export function getObj(id) {
    return ajaxRequest({
        url: '/whitelist/' + id,
        method: 'get'
    })
}

export function delObj(id) {
    return ajaxRequest({
        url: '/whitelist/' + id,
        method: 'delete'
    })
}

export function putObj(obj) {
    return ajaxRequest({
        url: '/whitelist',
        method: 'put',
        data: obj
    })
}

第四步:添加相应方法

<script>
import {
  addObj,
  delObj,
  getPage,
  putObj,
  getObj,
} from "@/api/whiteList/whiteList";
import { tableOption, tableOption2 } from "@/constant/whiteList/whiteList";

export default {
  name: "whiteList",
  data() {
    return {
      clickObj: null,
      //白名单列表
      dialog: {
        title: "新增白名单",
        open: false,
        serviceNameList: "",
        vehicleFactoryName: "",
        options: [
          {
            value: "w",
            label: "一",
          },
          {
            value: "s",
            label: "上",
          },
        ],
      },
      tableData: [],
      page: {
        total: 0, // 总页数
        pageNum: 1, // 当前页数
        pageSize: 10, // 每页显示多少条
        ascs: [], //升序字段
        descs: "create_time", //降序字段
      },
      paramsSearch: {},
      tableLoading: false,
      tableOption: tableOption,

      //修改数据列表
      form2: {},
      tableData2: [],
      page2: {
        total: 0, // 总页数
        currentPage: 1, // 当前页数
        pageSize: 10, // 每页显示多少条
      },
      tableLoading2: false,
      tableOption2: tableOption2,
      paramsSubmit: {
        id: "",
        serviceNameList: "",
      },
    };
  },
  created() {},
  mounted: function () {},
  computed: {},
  methods: {
    handleAdd() {
      this.dialog.open = true;
    },
    searchChange(params, done) {
      params = this.filterForm(params);
      this.paramsSearch = params;
      this.page.currentPage = 1;
      this.getPage(this.page, params);
      done();
    },
    sortChange(val) {
      let prop = val.prop
        ? val.prop.replace(/([A-Z])/g, "_$1").toLowerCase()
        : "";
      if (val.order == "ascending") {
        this.page.descs = [];
        this.page.ascs = prop;
      } else if (val.order == "descending") {
        this.page.ascs = [];
        this.page.descs = prop;
      } else {
        this.page.ascs = [];
        this.page.descs = [];
      }
      this.getPage(this.page);
    },
    getPage(page, params) {
      this.tableLoading = true;
      getPage(
        Object.assign(
          {
            status: 1,
            current: page.currentPage,
            size: page.pageSize,
            descs: this.page.descs,
            ascs: this.page.ascs,
          },
          params,
          this.paramsSearch
        )
      )
        .then((response) => {
          this.tableData = response.data.records;
          this.page.total = response.data.total;
          (this.page.currentPage = page.currentPage),
            (this.page.pageSize = page.pageSize),
            (this.tableLoading = false);
        })
        .catch(() => {
          this.tableLoading = false;
        });
    },
    /**
     * @title 数据删除
     * @param row 为当前的数据
     * @param index 为当前删除数据的行数
     *
     **/
    handleDel: function (row, index) {
      var _this = this;
      this.$confirm("是否确认删除此数据", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(function () {
          return delObj(row.id);
        })
        .then((data) => {
          _this.$message({
            showClose: true,
            message: "删除成功",
            type: "success",
          });
          this.getPage(this.page);
        })
        .catch(function (err) {});
    },
    /**
     * @title 数据更新
     * @param row 为当前的数据
     * @param index 为当前更新数据的行数
     * @param done 为表单关闭函数
     *
     **/
    handleUpdate: function (row, index, done, loading) {
        var str = new String();     
        for (let rows of this.tableData2) {
          str += rows.serviceNameModifyList;
        }
        this.paramsSubmit.serviceNameList = str;
        putObj(this.paramsSubmit)
          .then((data) => {
            this.clickObj = null;
            this.$message({
              showClose: true,
              message: "修改成功",
              type: "success",
            });
            this.getPage(this.page);
            done();
          })
          .catch(() => {
            loading();
          });
    },
    /**
     * @title 数据添加
     * @param row 为当前的数据
     * @param done 为表单关闭函数
     *
     **/
    handleSave: function () {
      this.dialog.serviceNameList= this.dialog.serviceNameList.trim(); 
      if(this.dialog.serviceNameList.substr(-1)!=";"){
        this.dialog.serviceNameList+=";";
      } 
      addObj(
        Object.assign({
          vehicleFactoryName: this.dialog.vehicleFactoryName,
          serviceNameList:  this.dialog.serviceNameList,      
        })
      )
        .then((resp) => {
          if (resp.ok === false) {
            this.$message({
              showClose: true,
              message: "添加失败, " + resp.msg,
              type: "fail",
            });
            done();
            this.getPage(this.page);
          } else {
            this.$message({
              showClose: true,
              message: "添加成功",
              type: "success",
            });
            this.resetDialog();
            this.dialog.open = false;
            this.getPage(this.page);
          }
        })
        .catch(() => {
          loading();
        });
    },
    /**
     * 重置表单
     */
    resetDialog() {
      this.dialog.serviceNameList = "";
      this.dialog.vehicleFactoryName = "";
    },

    /**
     * 刷新回调
     */
    refreshChange(page) {
      this.getPage(this.page);
    },

    handleItem: function (row) { 
      let isExecution = true;
      if (row) {
        this.clickObj = row;
        this.paramsSubmit.id = row.id;
        this.page2.currentPage = 1;
        this.getPage2(row, this.page2, isExecution);
      } else {
        this.$confirm("此操作将不会保存你的修改, 是否继续?", "提示", {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
          }).then(() => {
            this.clickObj = null;
          });
        }
      
    },
    beforeOpen2(done) {
      this.$set(this.form2, "id", this.clickObj.id);
      this.$set(this.form2, "type", this.clickObj.type);
      done();
    },
    getPage2(row, index, isExecution, params) {
      this.tableLoading2 = true;
      getObj(row.id).then((response) => {
        if (isExecution) {
          var strs = new Array(); //定义一数组
          strs=response.data.serviceNameList;
          strs = strs.split(";");
          strs = strs.slice(0, -1);//去掉最后的空格
          const returnList = [];
          for (let serviceName of strs) {
            let obj = {
              serviceNameModifyList: serviceName + ";",
            };
            returnList.push(obj);
          }
          this.tableData2 = returnList;
        }

        this.page2.total = returnList.length;
      });
    },
    /**
     * @title 数据更新
     * @param row 为当前的数据
     * @param index 为当前更新数据的行数
     * @param done 为表单关闭函数
     *
     **/
    handleUpdate2: function (row, index, done, loading) {
      this.$message({
        showClose: true,
        message: "修改成功",
        type: "success",
      });
      loading();
      done();
      this.getPage2(row, index);
      var serviceNameModifyStr = this.dealStr(row.serviceNameModifyList);
      this.tableData2[index].serviceNameModifyList = serviceNameModifyStr + ";";
    },
    /**
     * @title 数据删除
     * @param row 为当前的数据
     * @param index 为当前删除数据的行数
     *
     **/
    handleDel2: function (row, index) {
      var _this = this;
      this.$confirm("是否确认删除此数据", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then((data) => {
          _this.$message({
            showClose: true,
            message: "删除成功",
            type: "success",
          });
          this.getPage2(row, index);
          this.tableData2.splice(index, 1);
        })
        .catch(function (err) {});
    },
    /**
     * @title 数据添加
     * @param row 为当前的数据
     * @param done 为表单关闭函数
     *
     **/
    handleSave2: function (row, done, loading) {
      var str = row.serviceNameModifyList;
      str = this.dealStr(str);
      let obj = {
        serviceNameModifyList: str + ";",
      };
      this.tableData2.unshift(obj);
      this.$message({
        showClose: true,
        message: "添加成功",
        type: "success",
      });
      done();
      loading();
    },

    /**
     * @title 处理字符串
     * @param str 为当前的数据
     *
     **/
    dealStr(str) {
      str = str.replaceAll(";", ""); //去掉所有;
      str = str.replaceAll(";", ""); //去掉所有中文;
      str = str.trim(); //把数据进行去前后的空格和换行
      return str;
    },
  },
};
</script>
<style lang="scss" scoped>
@import "~@/styles/commonCss.scss";
</style>

其中,点击提交按钮是 调用handleUpdate方法,把paramsSubmit传入后端进行修改修改服务名列表,因此后端也要修改。

第五步:后端

第一步:WhiteListUpdateDTO

@Data
public class WhiteListUpdateDTO {

    private String id;

    /**
     * 服务名称列表
     */
    private String  serviceNameList;

}

第二步:control

@ApiOperation(value = "修改白名单记录")
    @PutMapping
    public R update(@RequestBody WhiteListUpdateDTO whiteListUpdateDTO) {
        return R.ok(whiteListService.updateWhiteList(whiteListUpdateDTO));
    }

第三步 :WhiteListService

public interface WhiteListService extends IService<WhiteList> {
    R updateWhiteList(WhiteListUpdateDTO whiteListUpdateDTO);
}

第四步:WhiteListServiceImpl

@DubboService(version = "1.0.0")
public class WhiteListServiceImpl extends ServiceImpl<WhiteListDao, WhiteList> implements WhiteListService {

    @Override
    public R updateWhiteList(WhiteListUpdateDTO whiteListUpdateDTO) {
        if (StrUtil.isBlank(whiteListUpdateDTO.getId())) {
            return R.failed("id值不能为空,请检查!");
        }
        WhiteList whiteList = whiteListDao.selectById(whiteListUpdateDTO.getId());
        if(ObjectUtil.isNull(whiteList)){
            return R.failed("id值有误,请检查!");
        }
        //校验变更
        if (ObjectUtil.equal(whiteListUpdateDTO.getServiceNameList(), whiteList.getServiceNameList())) {
            return R.failed("服务名称列表没有变化,请检查!");
        }
        whiteList.setServiceNameList(whiteListUpdateDTO.getServiceNameList());
        whiteList.setVersion(getNewVersionByRecord(whiteList));
        whiteListDao.updateById(whiteList);
        return R.ok();
    }

    /**
     * @Description: 更新版本号进行自增
     */
    private int getNewVersionByRecord(WhiteList whiteListRecord) {
        int newVersion;
        if (ObjectUtil.isNull(whiteListRecord)) {
            return 0;
        }
        newVersion = whiteListRecord.getVersion() + 1;
        return newVersion;
    }
}