APS 排产系统 2.0.0 技术升级解析:从 Vue2 到 Vue3 的架构演进

一、前端架构升级亮点

  1. Vue3 核心优势集成

    • 采用 Composition API 重构代码,提升逻辑复用性与可维护性
    • 引入 Vue3 响应式系统,优化数据流转效率
    • 升级 Vite 构建工具,编译速度提升约 40%
  2. 查询逻辑优化

    • 字符串查询默认采用右模糊匹配(示例:输入 "ABC" 可匹配 "ABC123")
    • 支持自定义查询模式(全匹配 / 左模糊 / 右模糊 / 全模糊)
    • 新增查询缓存机制,重复查询响应速度提升 50%
  3. 稳定性增强

    • 修复已知系统 BUG(含跨页排序异常、大数据量渲染卡顿, 查询等)
    • 优化多用户并发操作时的锁机制

二、技术实现细节

1. 业务页面目录结构:

> view
>
>> aps/base
>>
>>> 模块名称 (表名)
>>>
>>>> 模块名称  *AddEditForm.vue 添加或修改页面
>>>> 模块名称  *Index.vue 列表页面,支持table展示与查询
>>>> 模块名称  *Type.ts 数据结构定义, 可以增加通用查询或修改询接口

2. 示例代码

*AddEditForm.vue

<script setup lang="ts">
import { getById, pinyin4jSzm, postNoResult } from "@/common/utils/common-js.ts"
import { supplyModeList } from "@v/aps/ApsBom/ApsBomType.ts"
import { FormInstance, FormRules } from "element-plus"
import { onMounted, ref } from "vue"

const props = defineProps({
  saveFun: {
    type: Function
  },
  editId: {
    type: String,
    required: false
  }
})

const dtoUrl = ref<string>("/apsBom")
// 表单引用
const addFormRef = ref<FormInstance>()
// 表单校验规则
const checkRules = ref<FormRules>({
  bomCode: [
    { required: true, message: "请输入bom 编码", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  bomName: [
    { required: true, message: "请输入bom 名称", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  bomCostPrice: [
    { required: true, message: "请输入成本价", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  bomCostPriceUnit: [
    { required: true, message: "请输入单位", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  bomInventory: [
    { required: true, message: "请输入库存", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  groupId: [
    { required: true, message: "请输入组ID", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  supplyMode: [
    { required: true, message: "请输入供给方式 make, buy", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  useUnit: [
    { required: true, message: "请输入使用单位", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  bomUnit: [
    { required: true, message: "请输入零件单位", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  produceProcessId: [
    { required: true, message: "请输入制造路径", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  deliveryCycleDay: [
    { required: true, message: "请输入到货周期", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ],
  apsBomSupplierId: [
    { required: true, message: "请输入供应商ID", trigger: "blur" },
    { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  ]

})

onMounted(() => {
  loadById()
})

const addForm = ref({
  bomCode: String,
  bomName: String,
  bomCostPrice: undefined,
  bomCostPriceUnit: undefined,
  bomInventory: undefined,
  groupId: undefined,
  supplyMode: undefined,
  useUnit: undefined,
  bomUnit: undefined,
  produceProcessId: undefined,
  deliveryCycleDay: undefined,
  apsBomSupplierId: undefined,
  id: undefined
})

function loadById() {
  if (!props.editId) {
    return
  }
  console.info("props.editId ", props.editId)
  getById(`${dtoUrl.value}/queryByIdList`, props.editId).then((t) => {
    addForm.value = t
    console.info(" addForm.value ", addForm.value)
  })
}

function saveForm() {
  console.info("addForm ", addForm)
  addFormRef.value?.validate((valid) => {
    if (valid) {
      if (props.editId) {
        postNoResult(`${dtoUrl.value}/updateById`, addForm.value, "修改成功", saveFormAfter)
      } else {
        postNoResult(`${dtoUrl.value}/insert`, addForm.value, "保存成功", saveFormAfter)
      }
    } else {
      ElMessage.error("表单校验失败,请检查必填项")
    }
  })
}

function saveFormAfter() {
  cancelForm()
}

function cancelForm() {
  if (props.saveFun) {
    props.saveFun()
  }
}

function loadSzm() {
  pinyin4jSzm(addForm.value.bomName).then(r => addForm.value.bomCode = r)
}
</script>

<template>
  <el-form label-width="130px" :model="addForm" ref="addFormRef" :rules="checkRules">

    <el-form-item label="零件名称" prop="bomName">
      <el-input v-model="addForm.bomName" placeholder="请输入名称" clearable @blur="loadSzm" />
    </el-form-item>
    <el-form-item label="零件编号" prop="bomCode">
      <el-input v-model="addForm.bomCode" placeholder="请输入编号" clearable />
    </el-form-item>
    <el-form-item label="零件价格" prop="bomCostPrice">
      <el-input v-model="addForm.bomCostPrice" placeholder="请输入价格" />
    </el-form-item>
    <el-form-item label="价格规格" prop="bomCostPriceUnit">
      <el-input v-model="addForm.bomCostPriceUnit" placeholder="请输入价格规格如:  45元/瓶" />
    </el-form-item>

    <el-form-item label="库存" prop="bomInventory">
      <el-input v-model="addForm.bomInventory" placeholder="请输入库存如: 123.909" />
    </el-form-item>
    <el-form-item label="购买方式" prop="supplyMode">
      <el-select v-model="addForm.supplyMode">
        <el-option v-for="(sm) in supplyModeList" :value="sm.value" :key="sm.value" :label="sm.label" />
      </el-select>
    </el-form-item>
    <el-form-item label="规格" prop="bomUnit">
      <el-input v-model="addForm.bomUnit" placeholder="请输入规格如: 550ML" />
    </el-form-item>
    <el-form-item label="使用规格" prop="useUnit">
      <el-input v-model="addForm.useUnit" placeholder="请输入使用规格如:10ML " />
    </el-form-item>
    <el-form-item label="供货周期(天)" prop="deliveryCycleDay">
      <el-input v-model.number="addForm.deliveryCycleDay" placeholder="请输入供货周期 如: 1" />
    </el-form-item>
    <el-form-item label="制造路径" v-show="addForm.supplyMode === 'make'" prop="apsBomSupplierId">
      <!--      <el-select v-model="addForm.produceProcessId">-->
      <!--        <el-option v-for="(p,i) in produceProcessList" :key="p.id" :value="p.id"-->
      <!--                   :label="p.produceProcessName"></el-option>-->
      <!--      </el-select>-->
    </el-form-item>
    <el-form-item label="供应商" v-show="addForm.supplyMode === 'buy'" prop="apsBomSupplierId">
      <!--      <el-select v-model="addForm.apsBomSupplierId">-->
      <!--        <el-option v-for="(p,i) in apsBomSupplierList" :key="p.id" :value="p.id" :label="p.bomSupplierName"></el-option>-->
      <!--      </el-select>-->
    </el-form-item>
    <el-form-item label="零件组" prop="groupId">
      <!--      <tree-select ref="treeSelect" :list="groupData.filter(t=>t.id!=='0')" :multiple="false" :clearable="true"-->
      <!--                   :checkStrictly="true" width="120px" v-model="addForm.groupId"-->
      <!--      ></tree-select>-->
    </el-form-item>

  </el-form>
  <el-row class="addFormBtnRow">
    <el-button @click="cancelForm" type="info" icon="close">
      取消
    </el-button>
    <el-button @click="saveForm" type="primary" icon="check">
      确定
    </el-button>
  </el-row>
</template>



<style scoped lang="scss"></style>

 *Index.vue

<script setup lang="ts">
import type { HeaderInfo } from "@@/utils/common-js.ts"
import type { ApsBom } from "./ApsBomType.ts"
import TableBar from "@/layouts/components/TableBar/index.vue"
import { postResultInfo } from "@@/utils/common-js.ts"
import { ElTable } from "element-plus"
import { ref } from "vue"
import { supplyModeList } from "./ApsBomType.ts"
import { ApsBomGroup, apsGroupDefaultProps, queryApsBomGroupTree } from "@v/aps/ApsBomGroup/ApsBomGroupType.ts"
import AddEditFormVue from "./ApsBomAddEditForm.vue"


const dtoUrl = ref<string>("/apsBom")
const documentTitle = ref<string>("BOM 清单")
const dataBatchDeleteUrl = ref<string>(`${dtoUrl.value}/deleteByIdList`)

const queryForm = ref({
  bomCode: undefined,
  bomName: undefined,
  bomCostPrice: undefined,
  bomCostPriceUnit: undefined,
  bomInventory: undefined,
  groupId: undefined,
  supplyMode: undefined,
  useUnit: undefined,
  bomUnit: undefined,
  produceProcessId: undefined,
  deliveryCycleDay: undefined,
  apsBomSupplierId: undefined,
  id: undefined
})

const multipleSelection = ref<(string | undefined)[]>([])
const dataTableRef = ref<any>({})
// const dataTableRef = ref<InstanceType<typeof ElTable> | null>(null)
const tableBarRef = ref<InstanceType<typeof TableBar> | null>(null)

const currentPageNum = ref<number>(1)
const currentPageSize = ref<number>(10)
const tableTotal = ref<number>(0)
const headerList = ref<HeaderInfo[]>([])

const dataList = ref<ApsBom[]>([])


function handleSelectionChange(val: ApsBom[]) {
  multipleSelection.value = val.map(t => t.id)
  console.info("multipleSelection ", multipleSelection)
}


function getDataList() {
  const req = {
    pageSize: currentPageSize.value,
    pageNum: currentPageNum.value,
    data: queryForm.value
  }
  console.info("getDataList {}", req)
  postResultInfo(`${dtoUrl.value}/queryPageList`, req)
    .then((t) => {
      dataList.value = t.data.dataList
      tableTotal.value = Number.parseInt(t.data.total)
      headerList.value = t.data.headerList
    })
}

const apsBomGroupList = ref<ApsBomGroup[]>([])

onMounted(() => {
  getDataList()
  queryApsBomGroupTree().then(t => apsBomGroupList.value = t)
})

function editData(data: any) {
  // console.info("data ", data)
  tableBarRef.value?.showEditDialog(data.id)
}

function handleSizeChange(val: number) {
  currentPageSize.value = val
  getDataList()
}

function handleCurrentChange(val: number) {
  currentPageNum.value = val
  getDataList()
}
</script>

<template>
  <div class="app-container">
    <el-card class="search-wrapper" shadow="never">
      <el-form v-model="queryForm" inline>
        <el-form-item label="bom 编码" prop="bomCode">
          <el-input v-model="queryForm.bomCode" clearable placeholder="请输入bom 编码" />
        </el-form-item>
        <el-form-item label="bom 名称" prop="bomName">
          <el-input v-model="queryForm.bomName" clearable placeholder="请输入bom 名称" />
        </el-form-item>
        <el-form-item label="组ID" prop="groupId">
          <el-tree-select :props="apsGroupDefaultProps" style="width: 200px" node-key="id" :data="apsBomGroupList"
            v-model="queryForm.groupId" clearable placeholder="请输入组ID" />
        </el-form-item>
        <el-form-item label="供给方式" prop="supplyMode">
          <el-select v-model="queryForm.supplyMode" clearable style="width: 200px">
            <el-option v-for="s in supplyModeList" :label="s.label" :value="s.value" :key="s.value" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="search" @click="getDataList">
            查询
          </el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <el-card shadow="never">
      <TableBar :document-title="documentTitle" :add-component="AddEditFormVue" :refresh-list="getDataList"
        :data-table-ref="dataTableRef" :multiple-selection="multipleSelection" ref="tableBarRef"
        :data-batch-delete-url="dataBatchDeleteUrl" down-load-url="/apsBom/exportQueryPageList" upload-url="/upload" />
      <ElTable ref="dataTableRef" :data="dataList" stripe @selection-change="handleSelectionChange">
        <ElTableColumn type="selection" />
        <ElTableColumn v-for="h in headerList" :key="h.fieldName" :label="h.showName" :prop="h.fieldName" />
        <ElTableColumn fixed="right" label="操作" width="150px">
          <template #default="scope">
            <el-button type="warning" icon="edit" @click="editData(scope.row)">
              编辑
            </el-button>
          </template>
        </ElTableColumn>
      </ElTable>
      <el-row class="paginationDiv">
        <el-pagination background v-model:current-page="currentPageNum" v-model:page-size="currentPageSize"
          layout="total, sizes, prev, pager, next" :total="tableTotal" @size-change="handleSizeChange"
          @current-change="handleCurrentChange" />
      </el-row>
    </el-card>
  </div>
</template>
<style scoped lang="scss"></style>

 *Type.ts

import {request} from "@/http/axios.ts";
import {Result, ResultPageInfo} from "@@/utils/common-js.ts";

export interface ApsBom {
  bomCode: string
  bomName: string
  bomCostPrice: string
  bomCostPriceUnit: string
  bomInventory: string
  groupId: string
  supplyMode: string
  useUnit: string
  bomUnit: string
  produceProcessId: string
  deliveryCycleDay: string
  apsBomSupplierId: string
  id: string
}

export interface supplyModeType {
  label: string
  value: string
}

export const supplyModeList: supplyModeType[] = [{
  value: "make",
  label: "制造"
}, {
  label: "购买",
  value: "buy"
}]

export function queryApsBomList(pageNumber: number, data: any) {
  return request<Result<ResultPageInfo<ApsBom>>>({
    url: "/apsBom/queryPageList",
    method: "post",
    data: {
      pageSize: 10,
      pageNumber: 1,
      data
    }
  }).then(r => {
    return r.data.dataList;
  })
}

三、系统界面优化展示

​​​​​​

四、获取方式
如需获取最新版本,可在 Gitee 搜索项目名称:
项目名称:APS 排产排程系统
仓库地址:https://gitee.com/slsplatform/peanut-web-vue3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值