vue2制作高复用页面

记录一下页面搭建记录,利用vue2组件化开发的思想。这个页面适合于大部分信息管理系统~。模板固定,每次使用,直接修改表单表格参数,api接口等。

以上图页面为例,一个基础数据信息页面可以分为,分类(左侧),数据信息(右侧),搜索表单(右上),数据表格(右下),新增或编辑表单(对话框)。

全局css样式部分

css 复制代码
.top_box {
  // min-height: 10vh;
  width: 100%;
  border-radius: 5px;
  background-color: #fff; /* 背景色为白色 */
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); /* 添加投影效果 */
  padding: 10px 10px 10px;
  margin-bottom: 10px;
}

.down_box {
  min-height: 10vh;
  width: 100%;
  border-radius: 5px;
  background-color: #fff; /* 背景色为白色 */
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); /* 添加投影效果 */
}

.left_box {
  float: left;
  width: 20%;
  border-radius: 5px;
  background-color: #fff; /* 背景色为白色 */
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); /* 添加投影效果 */
  padding-bottom: 5%;
}

.right_box {
  float: left;
  min-height: 90vh;
  width: 79%;
  margin-left: 1%;
  border-radius: 5px;
  background-color: #fff; /* 背景色为白色 */
}

index.vue(主页面)

html 复制代码
<template>
  <div class="app-container">
    <div class="left_box">
      <CategoryMenu @selectNode="selectNode" />
    </div>
    <div class="right_box">
      <div class="top_box">
        <search-form
          :searchForm="searchForm"
          :size="size"
          @search="performSearch"
          @reset="resetSearch"
        />
        <div style="float: left; margin: 5px 0 0 20px">
          <el-button
            :disabled="currentCategoryId === null || currentCategoryId === ''"
            type="primary"
            plain
            :size="size"
            icon="el-icon-circle-plus-outline"
            @click="toAdd"
          >
            新增
          </el-button>
          <el-button
            type="success"
            plain
            :size="size"
            icon="el-icon-document-copy"
            disabled
          >
            迭代
          </el-button>
         
        </div>
        <div style="clear: both"></div>
      </div>
      <div class="down_box">
        <div style="padding: 20px 20px 10px 20px">
          <el-breadcrumb separator-class="el-icon-arrow-right">
            <el-breadcrumb-item
              v-for="(item, index) in currentCategory"
              :key="index"
              >{{ item }}</el-breadcrumb-item
            >
          </el-breadcrumb>
        </div>
        <div style="padding: 10px; min-height: 400px">
          <customTable :list="list" @toEdit="toEdit" @toDelete="toDelete" />
        </div>
        <div style="padding-bottom: 10px">
          <el-pagination
            :page-sizes="[10, 20, 40, 100]"
            :page-size="pageSize"
            layout="total, sizes, prev, pager, next, jumper"
            :total="counts"
            :current-page.sync="page"
            @size-change="(val) => handleSizeChange(val, this)"
            @current-change="(val) => handleCurrentChange(val, this)"
            align="center"
          ></el-pagination>
        </div>
      </div>
    </div>
    <editForm
      :edit-vis="editVis"
      :edit-status="editStatus"
      :edit-form="editForm"
      :rules="rules"
      :userOption="userOption"
      @submit="submitForm"
      @cancel="cancel"
    />
  </div>
</template>
  
<script>
import {
  addStorageWarehouse,
  pageStorageWarehouse,
  updateStorageWarehouse,
  deleteStorageWarehouse,
} from "@/api/storage/storage-warehouse";
import { list } from "@/api/system/user";
import {
  confirmAction,
  submitWithConfirmation,
} from "@/utils/confirmationHelper";
import paginationMethods from "@/utils/pagination.js";
import searchForm from "./components/searchForm.vue";
import customTable from "./components/customTable.vue";
import editForm from "./components/editForm.vue";
import CategoryMenu from "./components/CategoryMenu.vue";
export default {
  name: "bom",
  components: {
    searchForm,
    customTable,
    editForm,
    CategoryMenu,
  },
  data() {
    return {
      content: "BOM信息",
      size: "small",
      list: [],
      searchForm: {},

      currentCategoryId: "",
      currentCategoryName: "",
      currentCategory: [],

      counts: 0,
      page: 1,
      pageSize: 10,
      userOption: [],

      editVis: false,
      editStatus: false,

      editForm: {},
      rules: {
        code: [{ required: true, message: "BOM编码不能为空", trigger: "blur" }],
      },
    };
  },
  watch: {},
  created() {
    this.init();
  },
  mounted() {
    document.addEventListener("keyup", this.handleKeyUp);
  },
  beforeDestroy() {
    document.removeEventListener("keyup", this.handleKeyUp);
  },
  methods: {
    init() {
      list().then((res) => {
        this.userOption = res.data.list.map((item) => {
          return {
            value: item.id,
            label: item.name,
          };
        });
      });
      this.fetchData();
    },
    handleKeyUp(event) {
      if (event.key === "Enter") {
        this.fetchData();
      }
    },
    fetchData() {
      var vm = this;
      const params = {
        page: vm.page,
        pageSize: vm.pageSize,
        categoryId: vm.currentCategoryId ? vm.currentCategoryId : undefined,
        code: vm.searchForm.code ? vm.searchForm.code : undefined,
        productCode: vm.searchForm.productCode
          ? vm.searchForm.productCode
          : undefined,
      };
      // pageStorageWarehouse(params).then((res) => {
      //   vm.list = res.data.page.records;
      //   vm.counts = res.data.page.total;
      // });
    },
    ...paginationMethods, // 导入分页方法
    performSearch(searchForm) {
      this.searchForm = searchForm;
      this.handleClickSearch(this);
    },
    resetSearch() {
      this.pageSize = 10;
      this.currentCategoryId = "";
      this.currentCategoryName = "";
      this.currentCategory = [];
      this.resetTable(this);
    },
    toAdd() {
      this.editForm = {};
      this.editStatus = false;
      this.editVis = true;
    },
    toEdit(row) {
      this.editForm = { ...row };
      this.editStatus = true;
      this.editVis = true;
    },
    toDelete(row) {
      const message = "是否删除" + this.content + "?";
      const action = () => deleteStorageWarehouse(row.id);
      confirmAction(this, message, action);
    },
    cancel() {
      this.editVis = false;
      this.editForm = {};
    },
    // 提交
    submitForm(editForm) {
      this.editForm.bomCategoryId = this.currentCategoryId;
      const action = this.editStatus
        ? () => updateStorageWarehouse(editForm)
        : () => addStorageWarehouse(editForm);
      submitWithConfirmation(this, action);
    },
    selectNode(id, name, category) {
      this.currentCategoryId = id;
      this.currentCategoryName = name;
      this.currentCategory = category.split(",");
      this.fetchData();
    },
  },
};
</script>
  
  <style lang="less" scoped>
</style>
  

分类菜单(左侧)

html 复制代码
<template>
  <div style="padding: 5px">
    <div>
      <h3 style="margin: 8px 0; color: rgb(111, 111, 111); text-align: center">
        BOM分类
        <span
          style="float: right; margin-right: 10px; cursor: pointer"
          @click="editVis = true"
        >
          <i class="el-icon-edit-outline" />
        </span>
      </h3>
    </div>
    <div style="margin-bottom: 10px">
      <el-input placeholder="输入BOM分类" v-model="filterText" size="mini">
      </el-input>
    </div>
    <el-tree
      :data="data"
      default-expand-all
      :filter-node-method="filterNode"
      :expand-on-click-node="false"
      ref="tree"
    >
      <span slot-scope="{ data }">
        <span style="font-size: 14px" @click="toFind(data)">
          <i class="el-icon-folder" />&nbsp; {{ data.code }} -
          {{ data.name }}
        </span>
      </span>
    </el-tree>
    <el-dialog
      title="BOM分类"
      :visible.sync="editVis"
      width="1280px"
      top="56px"
      append-to-body
    >
      <CategoryEdit />
    </el-dialog>
  </div>
</template>

<script>
import { getBomCategoryList } from "@/api/product/bom-category";
import CategoryEdit from "./CategoryEdit.vue";
export default {
  components: {
    CategoryEdit,
  },
  data() {
    return {
      filterText: "",
      data: [],
      editVis: false,
    };
  },
  watch: {
    filterText(val) {
      this.$refs.tree.filter(val);
    },
  },
  created() {
    this.fetchData();
  },
  methods: {
    fetchData() {
      getBomCategoryList().then((res) => {
        this.data = res.data.list;
      });
    },
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    toFind(data) {
      // 返回目录id和目录分级
      this.$parent.selectNode(data.id, data.name, this.findParentById(data.id));
    },
    findParentById(id) {
      const findParentRecursive = (data, id, path = []) => {
        for (let item of data) {
          if (item.id === id) {
            return path.concat(item);
          } else if (item.children) {
            const result = findParentRecursive(
              item.children,
              id,
              path.concat(item)
            );
            if (result) {
              return result;
            }
          }
        }
        return null;
      };
      const result = findParentRecursive(this.data, id);
      if (result) {
        return result.map((item) => item.name).join(",");
      } else {
        return "未找到父级元素";
      }
    },
  },
};
</script>

搜索表单

html 复制代码
<template>
  <el-form label-width="100px" v-model="searchForm">
    <el-form-item :size="size" label="BOM编码:" class="searchItem">
      <el-input
        v-model="searchForm.code"
        placeholder="请输入"
        class="searchInput"
        clearable
      />
    </el-form-item>
    <el-form-item :size="size" label="产品编码:" class="searchItem">
      <el-input
        v-model="searchForm.productCode"
        placeholder="请输入"
        class="searchInput"
        clearable
      />
    </el-form-item>
    <div class="searchItem">
      <el-button
        type="primary"
        :size="size"
        icon="el-icon-search"
        @click="handleClickSearch()"
      >
        搜索
      </el-button>
      <el-button
        icon="el-icon-refresh-right"
        :size="size"
        @click="() => resetTable()"
      >
        重置
      </el-button>
    </div>
    <div style="clear: both"></div>
    <!-- 清除浮动 -->
  </el-form>
</template>
  
  <script>
export default {
  name: "SearchForm",
  props: {
    searchForm: {
      type: Object,
      required: true,
    },
    size: {
      type: String,
      default: "mini",
    },
  },
  methods: {
    handleClickSearch() {
      this.$emit("search", this.searchForm);
    },
    resetTable() {
      this.$emit("reset");
    },
  },
};
</script>
  
<style scoped>
.searchItem {
  float: left;
  margin-left: 20px;
}
.searchInput {
  width: 160px;
}
</style>

数据表格

html 复制代码
<template>
  <div>
    <el-table :data="list" fit highlight-current-row>
      <el-table-column type="selection" width="55"> </el-table-column>
      <el-table-column label="BOM编码" align="center" prop="code" width="230">
        <template slot-scope="scope">
          <span>
            <el-link
              :underline="false"
              type="primary"
              @click="toEdit(scope.row)"
              >{{ scope.row.code }}</el-link
            ></span
          >
        </template>
      </el-table-column>
      <el-table-column
        label="关联产品"
        align="center"
        prop="productCode"
        width="230"
      />
      <el-table-column label="版本号" align="center" prop="version" />
      <el-table-column label="状态" align="center" prop="status" />
      <!-- 操作栏 -->
      <el-table-column
        label="操作"
        align="center"
        width="230"
        fixed="right"
        prop="operation"
      >
        <template slot-scope="{ row, $index }">
          <el-button size="mini" type="success" @click="toCopy(row)">
            迭代
          </el-button>
          <el-button size="mini" type="success" v-if="row.status === 1">
            提交
          </el-button>
          <el-button size="mini" type="warning" v-if="row.status === 2">
            审核
          </el-button>
          <el-button size="mini" type="primary" @click="toEdit(row)">
            查看
          </el-button>
          <el-button size="mini" type="danger" @click="toDelete(row)">
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: "custom-table",
  props: {
    list: {
      type: Array,
      required: true,
    },
  },
  data() {
    return {
      size: "small",
    };
  },
  watch: {
    list(newVal, oldVal) {},
  },
  methods: {
    toEdit(row) {
      this.$emit("toEdit", row);
    },
    toCopy(row) {},
    toDelete(row) {
      this.$emit("toDelete", row);
    },
  },
};
</script>

<style>
</style>

新增或编辑表单(对话框)

html 复制代码
<template>
  <el-dialog
    :title="editStatus ? '查看BOM信息' : '新增BOM信息'"
    :visible="vis"
    width="730px"
    top="56px"
    append-to-body
    :before-close="handleClose"
  >
    <el-form
      ref="editForm"
      :model="editForm"
      :rules="rules"
      label-width="115px"
      size="small"
    >
      <el-form-item
        :size="size"
        label="BOM编码:"
        prop="code"
        style="float: left"
      >
        <el-input
          v-model="editForm.code"
          class="editItem"
          placeholder="请输入"
        />
      </el-form-item>
      <el-form-item
        :size="size"
        label="产品信息:"
        prop="name"
        style="float: left"
      >
        <el-input
          v-model="editForm.name"
          class="editItem"
          placeholder="请输入"
        />
      </el-form-item>
      <div style="clear: both"></div>
      <el-form-item label="备注:" prop="remark" style="float: left">
        <el-input
          v-model="editForm.remark"
          type="textarea"
          placeholder="请输入备注"
          style="width: 515px"
        />
      </el-form-item>
      <div style="clear: both"></div>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <div style="margin-right: 60px">
        <el-button
          v-if="editStatus"
          type="primary"
          size="mini"
          @click="submitForm('editForm')"
          >保 存</el-button
        >
        <el-button
          v-if="!editStatus"
          type="primary"
          size="mini"
          @click="submitForm('editForm')"
          >新 增</el-button
        >
        <el-button size="mini" @click="cancel">取 消</el-button>
      </div>
    </div>
  </el-dialog>
</template>

<script>
export default {
  name: "edit",

  props: {
    editVis: {
      type: Boolean,
      required: true,
    },
    editStatus: {
      type: Boolean,
      required: true,
    },
    editForm: {
      type: Object,
      required: true,
    },
    rules: {
      type: Object,
      required: true,
    },
    userOption: {
      type: Array,
      required: true,
    },
  },
  data() {
    return {
      size: "small",
      vis: false,
    };
  },
  watch: {
    editVis(newVal, oldVal) {
      this.vis = this.editVis;
    },
  },
  methods: {
    handleClose(done) {
      this.$confirm("您确定要关闭吗?", "确认", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.cancel();
          done();
        })
        .catch(() => {
          // 用户点击取消时的处理
        });
    },
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.$emit("submit", this.editForm);
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    cancel() {
      this.$refs["editForm"].resetFields();
      this.$emit("cancel");
    },
  },
};
</script>

<style lang="less" scoped>
.editItem {
  width: 200px;
}

/deep/ .el-collapse-item__header {
  padding-left: 50px;
}
</style>
相关推荐
Json____几秒前
学法减分交管12123模拟练习小程序源码前端和后端和搭建教程
前端·后端·学习·小程序·uni-app·学法减分·驾考题库
迂 幵9 分钟前
vue el-table 超出隐藏移入弹窗显示
javascript·vue.js·elementui
上趣工作室13 分钟前
vue2在el-dialog打开的时候使该el-dialog中的某个输入框获得焦点方法总结
前端·javascript·vue.js
家里有只小肥猫13 分钟前
el-tree 父节点隐藏
前端·javascript·vue.js
fkalis14 分钟前
【海外SRC漏洞挖掘】谷歌语法发现XSS+Waf Bypass
前端·xss
陈随易1 小时前
农村程序员-关于小孩教育的思考
前端·后端·程序员
云深时现月1 小时前
jenkins使用cli发行uni-app到h5
前端·uni-app·jenkins
昨天今天明天好多天1 小时前
【Node.js]
前端·node.js
亿牛云爬虫专家2 小时前
Puppeteer教程:使用CSS选择器点击和爬取动态数据
javascript·css·爬虫·爬虫代理·puppeteer·代理ip
2401_857610032 小时前
深入探索React合成事件(SyntheticEvent):跨浏览器的事件处理利器
前端·javascript·react.js