Просмотр исходного кода

Merge branch 'master' into Branch_qinhb

qinhb 1 год назад
Родитель
Сommit
a4a680fb9f
38 измененных файлов с 1569 добавлено и 82 удалено
  1. 1 0
      index.html
  2. 1 0
      package.json
  3. 3 3
      src/api/bom/index.ts
  4. 26 0
      src/api/craft/process/index.ts
  5. 15 0
      src/api/material/index.ts
  6. 17 0
      src/api/productionLine/index.ts
  7. 5 0
      src/api/productionLine/types.ts
  8. 31 0
      src/api/station/index.ts
  9. 27 0
      src/api/station/types.ts
  10. 2 2
      src/api/workShop/index.ts
  11. 3 2
      src/api/workShop/types.ts
  12. 9 0
      src/assets/icons/ESOP.svg
  13. 3 0
      src/assets/icons/dianjian.svg
  14. 3 0
      src/assets/icons/duomeiticaiji.svg
  15. 7 0
      src/assets/icons/jiluxiang.svg
  16. 7 0
      src/assets/icons/jingu.svg
  17. 10 0
      src/assets/icons/mingpai.svg
  18. 10 0
      src/assets/icons/shebeijilu.svg
  19. 4 0
      src/assets/icons/tiaoshipipei.svg
  20. 9 0
      src/assets/icons/wuliaocaiji.svg
  21. 236 0
      src/components/CommonTable/configs/tableConfig.ts
  22. 20 3
      src/components/CommonTable/index.vue
  23. 60 2
      src/hooks/userCrud.ts
  24. 1 1
      src/settings.ts
  25. 2 0
      src/store/modules/dictionary.ts
  26. 8 0
      src/views/base/bom/columns.ts
  27. 132 57
      src/views/base/bom/index.vue
  28. 2 2
      src/views/base/craftManagement/route/bindProcess.vue
  29. 94 0
      src/views/base/craftManagement/route/components/bottomTable.vue
  30. 130 0
      src/views/base/craftManagement/route/components/configs.ts
  31. 283 0
      src/views/base/craftManagement/route/components/processComponent.vue
  32. 61 6
      src/views/base/modeling/factory/index.vue
  33. 115 0
      src/views/base/modeling/production-line/capacity/columns.ts
  34. 6 0
      src/views/base/modeling/production-line/capacity/index.vue
  35. 1 1
      src/views/base/modeling/station/columns.ts
  36. 39 0
      src/views/base/modeling/station/components/columns.ts
  37. 162 0
      src/views/base/modeling/station/components/station-page.vue
  38. 24 3
      src/views/base/modeling/station/index.vue

+ 1 - 0
index.html

@@ -12,6 +12,7 @@
       name="keywords"
       content="vue,element-plus,typescript,vue-element-admin,vue3-element-admin"
     />
+    <script src="https://cdn.staticfile.org/Sortable/1.10.0-rc2/Sortable.min.js"></script>
     <title>综合管控采集平台</title>
   </head>
 

+ 1 - 0
package.json

@@ -81,6 +81,7 @@
     "@types/sockjs-client": "^1.5.4",
     "@types/sortablejs": "^1.15.8",
     "@types/stompjs": "^2.3.9",
+    "@types/uuid": "^9.0.8",
     "@typescript-eslint/eslint-plugin": "^7.1.1",
     "@typescript-eslint/parser": "^7.1.1",
     "@vitejs/plugin-vue": "^5.0.4",

+ 3 - 3
src/api/bom/index.ts

@@ -3,14 +3,14 @@ import { AxiosPromise } from "axios";
 import { BomInfo} from "./types";
 
 /**
- * 修改用户
+ * 批量新增BOM单
  *
  * @param id
  * @param data
  */
-export function getList(data: BomInfo) {
+export function batchAddBom(data: any) {
   return request({
-    url: "/api/v1/base/materialBom/list",
+    url: "/api/v1/base/materialBom/batchAdd",
     method: "post",
     data: data,
   });

+ 26 - 0
src/api/craft/process/index.ts

@@ -7,3 +7,29 @@ export function processTreeList() {
     method: "post",
   });
 }
+
+// 新增自定义工艺工序组件路径
+export function saveCompoents(data: object) {
+  return request({
+    url: "/api/v1/op/compent/saveOrUpdate",
+    method: "post",
+    data: data,
+  });
+}
+
+// 获取工艺工序组件路径信息
+export function getCompoentsList(opId: string) {
+  return request({
+    url: `/api/v1/op/compent/get/${opId}`,
+    method: "get",
+  });
+}
+
+// 批量更新工序记录项信息
+export function sortGXJLList(data: object) {
+  return request({
+    url: `/api/v1/op/operationRecord/batch-update`,
+    method: "post",
+    data: data,
+  });
+}

+ 15 - 0
src/api/material/index.ts

@@ -0,0 +1,15 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+
+/**
+ * 获取物料信息
+ *
+ * @param id
+ * @param data
+ */
+export function getMaterialDetails(materialCode: String): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/base/material/getDetails/" + materialCode,
+    method: "get",
+  });
+}

+ 17 - 0
src/api/productionLine/index.ts

@@ -0,0 +1,17 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import { ProductionLineInfo} from "./types";
+
+/**
+ * 修改产线
+ *
+ * @param id
+ * @param data
+ */
+export function updateProductionLine(data: ProductionLineInfo) {
+  return request({
+    url: "/api/v1/base/productionLine/update",
+    method: "post",
+    data: data,
+  });
+}

+ 5 - 0
src/api/productionLine/types.ts

@@ -0,0 +1,5 @@
+export interface ProductionLineInfo {
+  id?:number;
+  code?: string;
+  parentCode?: string;
+}

+ 31 - 0
src/api/station/index.ts

@@ -0,0 +1,31 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import {Station, StationDevice} from "./types";
+
+/**
+ * 修改工位
+ *
+ * @param id
+ * @param data
+ */
+export function updateStation(data: Station) {
+  return request({
+    url: "/api/v1/base/station/update",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 工位绑定设备
+ *
+ * @param id
+ * @param data
+ */
+export function addStationDevice(data: StationDevice) {
+  return request({
+    url: "/api/v1/base/stationDevice/add",
+    method: "post",
+    data: data,
+  });
+}

+ 27 - 0
src/api/station/types.ts

@@ -0,0 +1,27 @@
+/**
+ *
+ * 工位绑定产线参数
+ *
+ */
+
+export interface Station {
+  id?:number;
+  //工位编码
+  code?: string;
+  //上级产线编码
+  parentCode?: string;
+}
+
+
+/**
+ *
+ * 工位绑定设备参数
+ *
+ */
+
+export interface StationDevice {
+  //工位id
+  stationId?: number;
+  //设备编号
+  deviceNo?: string;
+}

+ 2 - 2
src/api/workShop/index.ts

@@ -3,14 +3,14 @@ import { AxiosPromise } from "axios";
 import { WorkShopInfo} from "./types";
 
 /**
- * 修改用户
+ * 修改车间
  *
  * @param id
  * @param data
  */
 export function updateWorkShop(data: WorkShopInfo) {
   return request({
-    url: "/api/v1/base/materialBom/list",
+    url: "/api/v1/base/workShop/update",
     method: "post",
     data: data,
   });

+ 3 - 2
src/api/workShop/types.ts

@@ -1,4 +1,5 @@
 export interface WorkShopInfo {
-  id?: number;
-  parentId?: number;
+  id?:number;
+  code?: string;
+  parentCode?: string;
 }

Разница между файлами не показана из-за своего большого размера
+ 9 - 0
src/assets/icons/ESOP.svg


Разница между файлами не показана из-за своего большого размера
+ 3 - 0
src/assets/icons/dianjian.svg


Разница между файлами не показана из-за своего большого размера
+ 3 - 0
src/assets/icons/duomeiticaiji.svg


Разница между файлами не показана из-за своего большого размера
+ 7 - 0
src/assets/icons/jiluxiang.svg


Разница между файлами не показана из-за своего большого размера
+ 7 - 0
src/assets/icons/jingu.svg


Разница между файлами не показана из-за своего большого размера
+ 10 - 0
src/assets/icons/mingpai.svg


Разница между файлами не показана из-за своего большого размера
+ 10 - 0
src/assets/icons/shebeijilu.svg


+ 4 - 0
src/assets/icons/tiaoshipipei.svg

@@ -0,0 +1,4 @@
+<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19.1923 1.81634C19.4871 1.99855 19.6666 2.32042 19.6666 2.66699V8.00033H17.6666V4.28503L6.33325 9.95169V26.3823L12.886 23.1059L13.7805 24.8948L5.78047 28.8948C5.47048 29.0497 5.10234 29.0332 4.80752 28.851C4.5127 28.6688 4.33325 28.3469 4.33325 28.0003V9.33366C4.33325 8.95489 4.54725 8.60862 4.88604 8.43923L18.2194 1.77257C18.5294 1.61757 18.8975 1.63414 19.1923 1.81634Z" fill="black" fill-opacity="0.9"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M27.1923 3.14968C27.4871 3.33188 27.6666 3.65375 27.6666 4.00033V22.667C27.6666 23.0458 27.4526 23.392 27.1138 23.5614L13.7805 30.2281C13.4705 30.3831 13.1023 30.3665 12.8075 30.1843C12.5127 30.0021 12.3333 29.6802 12.3333 29.3337V10.667C12.3333 10.2882 12.5473 9.94196 12.886 9.77257L26.2194 3.1059C26.5294 2.95091 26.8975 2.96747 27.1923 3.14968ZM14.3333 11.285V27.7156L25.6666 22.049V5.61836L14.3333 11.285Z" fill="black" fill-opacity="0.9"/>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 9 - 0
src/assets/icons/wuliaocaiji.svg


+ 236 - 0
src/components/CommonTable/configs/tableConfig.ts

@@ -176,4 +176,240 @@ export const tableConfig = {
   },
 
 
+  PRODUCTIONLINE: {
+    url: "/api/v1/base/productionLine",
+    column: [
+      {
+        label: "产线名称",
+        prop: "name",
+        search: true,
+        rules: [{
+          required: true,
+          message: "请填写产线名称",
+          trigger: "blur"
+        }],
+      },
+      {
+        label: "产线负责人",
+        prop: "manager",
+        rules: [{
+          required: true,
+          message: "请选择产线负责人",
+          trigger: "blur"
+        }],
+        type: 'select',
+        dicUrl:import.meta.env.VITE_APP_BASE_API+"/api/v1/sys/user/list",
+        dicMethod:"post",
+        props: {
+          label: "userName", // 下拉菜单显示的字段
+          value: "userName" // 下拉菜单值的字段
+        },
+      },
+      {
+        label: "产线位置",
+        prop: "position",
+      },
+      {
+        label: "所属车间",
+        prop: "workShopName",
+        display:false
+      },
+      {
+        label: "产线描述",
+        prop: "remark",
+      },
+      {
+        label: "创建人",
+        prop: "creator",
+        display:false
+      },
+      {
+        label: "创建时间",
+        prop: "created",
+        display:false
+      },
+    ],
+  },
+
+  STATION: {
+    url: "/api/v1/base/station",
+    column: [
+      {
+        label: "工位编号",
+        prop: "stationCode",
+        search: true,
+        rules: [{
+          required: true,
+          message: "请填写工位编号",
+          trigger: "blur"
+        }],
+      },
+      {
+        label: "工位名称",
+        prop: "name",
+        search: true,
+        rules: [{
+          required: true,
+          message: "请填写工位名称",
+          trigger: "blur"
+        }],
+      },
+      {
+        label: "工位类型",
+        prop: "stationDictValue",
+        search: true,
+        rules: [{
+          required: true,
+          message: "请选择工位类型",
+          trigger: "blur"
+        }],
+        type: 'select',
+        dicData:dicts.station_type,
+        searchClearable: false, //可清空的输入框,默认为true
+        filterable: true, //添加filterable属性即可启用搜索功能
+        props: {
+          label: "dictLabel", // 下拉菜单显示的字段
+          value: "dictValue" // 下拉菜单值的字段
+        },
+      },
+      {
+        label: "工位操作方式",
+        prop: "operateDictValue",
+        rules: [{
+          required: true,
+          message: "请选择工位方式",
+          trigger: "blur"
+        }],
+        type: 'select',
+        dicData:dicts.station_operate_type,
+        props: {
+          label: "dictLabel", // 下拉菜单显示的字段
+          value: "dictValue" // 下拉菜单值的字
+        },
+      },
+      {
+        label: "工位负责人",
+        prop: "manager",
+        rules: [{
+          required: true,
+          message: "请选择工位负责人",
+          trigger: "blur"
+        }],
+        type: 'select',
+        dicUrl:import.meta.env.VITE_APP_BASE_API+"/api/v1/sys/user/list",
+        dicMethod:"post",
+        props: {
+          label: "userName", // 下拉菜单显示的字段
+          value: "userName" // 下拉菜单值的字段
+        },
+      },
+      {
+        label: "所属产线",
+        prop: "productionLineName",
+        display:false
+      },
+      {
+        label: "工位地址",
+        prop: "position",
+        rules: [{
+          required: true,
+          message: "请填写工位地址",
+          trigger: "blur"
+        }],
+      },
+      {
+        label: "工位IP地址",
+        prop: "stationIp",
+        rules: [{
+          required: true,
+          message: "请填写工位IP地址",
+          trigger: "blur",
+        }],
+
+      },
+      {
+        label: "工位描述",
+        prop: "remark",
+        type: 'textarea',
+        span: 24,
+      },
+      {
+        label: "创建人",
+        prop: "creator",
+        display:false
+      },
+      {
+        label: "创建时间",
+        prop: "created",
+        display:false
+      },
+    ],
+  },
+
+
+  DEVICE: {
+    url: "/api/v1/device",
+    column: [
+      {
+        label: "设备编号",
+        prop: "deviceNo",
+        search: true,
+        width: '120',
+        rules: [
+          {
+            required: true,
+            message: "设备编号不能为空",
+            trigger: "trigger",
+          },
+        ],
+      },
+      {
+        label: "设备名称",
+        prop: "deviceName",
+        search: true,
+        width: '120',
+        rules: [
+          {
+            required: true,
+            message: "设备名称不能为空",
+            trigger: "trigger",
+          },
+        ],
+      },
+      {
+        label: "设备类型",
+        prop: "deviceType",
+        type: "select",
+        search: true,
+        width: '100',
+        dicData:
+          dicts.device_type,
+        props: {
+          label: "dictLabel",
+          value: "dictValue",
+        },
+      },
+      {
+        label: "负责人",
+        width: '100',
+        prop: "head",
+      },
+      {
+        label: "设备位置",
+        width: '150',
+        prop: "devicePosition",
+      },
+      {
+        label: "规格",
+        width: '150',
+        prop: "specifications",
+      },
+      {
+        label: "品牌",
+        width: '150',
+        prop: "brand",
+      },
+    ],
+  },
+
 };

+ 20 - 3
src/components/CommonTable/index.vue

@@ -16,6 +16,10 @@
       @row-save="createRow"
       @row-update="updateRow"
       @row-del="deleteRow"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+      @size-change="dataList"
+      @current-change="dataList"
       @selection-change="selectionChange"
     />
 
@@ -50,18 +54,18 @@ const startSelect = () => {
 };
 
 // 传入一个url,后面不带/
-const { url, form, data, option, search, page, toDeleteIds, Methords, Utils } =
+const { url, form, data, option, search, page, toDeleteIds, Methords, Utils, } =
   useCrud({
     src: tableConfig[props.tableType].url,
   });
-const { dataList, createRow, updateRow, deleteRow } = Methords; //增删改查
+const { dataList, createRow, updateRow, deleteRow , searchChange, resetChange} = Methords; //增删改查
 const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
 
 const crudRef = ref(null); //crudRef.value 获取avue-crud对象
 
 const commonTableEmits = defineEmits(["selectedSure"]);
 
-watchEffect(async () => {
+onMounted(() => {
   url.value = tableConfig[props.tableType].url;
   option.value = Object.assign(option.value, {
     menu: false,
@@ -71,6 +75,19 @@ watchEffect(async () => {
   });
   dataList();
 });
+watch(
+  () => props.tableType,
+  () => {
+    url.value = tableConfig[props.tableType].url;
+    option.value = Object.assign(option.value, {
+      menu: false,
+      highlightCurrentRow: true,
+      addBtn: false,
+      column: tableConfig[props.tableType].column,
+    });
+    dataList();
+  }
+);
 
 const selectRowValue = ref({});
 const rowClick = (row) => {

+ 60 - 2
src/hooks/userCrud.ts

@@ -7,6 +7,11 @@ import { checkPerm } from "@/directive/permission";
 interface UseCrudConfig {
   // 模块的url,用来进行增删改查
   src?: string;
+  // getUrl?: string;
+  // getUrl?: string;
+  // getUrl?: string;
+  // getUrl?: string;
+
   // 需要操作的数据
   row?: any;
   // done用于结束操作
@@ -27,7 +32,7 @@ export const useCrud = (config?: UseCrudConfig) => {
   /** 表格配置属性 */
   const option = ref({
     searchIcon: true,
-   // searchSpan: 4,
+    // searchSpan: 4,
     searchIndex: 3, //searchIcon是否启用功能按钮, searchIndex配置收缩展示的个数,默认为2个
     index: true, //是否显示第几项
     indexLabel: "序号",
@@ -116,7 +121,30 @@ export const useCrud = (config?: UseCrudConfig) => {
         config?.done && config?.done();
       }
     },
-
+    dataNoPageList: async (config?: UseCrudConfig) => {
+      handleSearchData();
+      try {
+        const res = await request({
+          url: `${url.value}/list`,
+          method: "post",
+          data: {
+            ...search.value,
+          },
+        });
+        if (res?.data) {
+          data.value = res?.data || [];
+        }
+        for (let i = 0; i < data.value.length; i++) {
+          data.value[i].$cellEdit=true;
+        }
+        console.info(data);
+        config?.done && config?.done();
+      } catch (err) {
+        config?.loading && config?.loading();
+      } finally {
+        config?.done && config?.done();
+      }
+    },
     createRow: (row: any, done: () => void, loading: () => void) => {
       save({ row: row, done: done, loading: loading });
     },
@@ -192,6 +220,36 @@ export const useCrud = (config?: UseCrudConfig) => {
     },
 
     /**
+     *  表格拖拽后批量保存
+     * */
+    multipleUpdate: async () => {
+      try {
+        for (let i = 0; i < data.value.length; i++) {
+          let cur = page.value.currentPage ?? 1;
+          cur = cur - 1;
+          const size = page.value.pageSize ?? 10;
+          let sortNum = cur * size;
+          sortNum = sortNum + i;
+          console.log("sortNum", cur, size, sortNum);
+          data.value[i].sortNum = sortNum;
+        }
+        const p = {
+          dtos: data.value,
+        };
+        const res = await request({
+          url: `${url.value}/batch-update`,
+          method: "post",
+          data: p,
+        });
+        Methords.dataList();
+        config?.done && config?.done();
+      } catch (err) {
+        config?.loading && config?.loading();
+      } finally {
+        config?.done && config?.done();
+      }
+    },
+    /**
      * 点击搜索按钮触发
      */
     searchChange: async (params: any, done: () => void) => {

+ 1 - 1
src/settings.ts

@@ -7,7 +7,7 @@ const defaultSettings: AppSettings = {
   tagsView: true,
   fixedHeader: true,
   sidebarLogo: true,
-  layout: "left",
+  layout: "mix",
   theme: "light",
   size: "default",
   language: "zh-cn",

+ 2 - 0
src/store/modules/dictionary.ts

@@ -16,12 +16,14 @@ export const useDictionaryStore = defineStore("dictionaryStore", {
       "packaging_method",
       "quality_grade",
       "selection_type",
+      "device_type",
       "stage",
       "danwei_type",
       "process_type",
       "workshop_section",
       "skill_requirements",
       "station_type",
+      "danwei_type",
     ],
     dicts: [],
   }),

+ 8 - 0
src/views/base/bom/columns.ts

@@ -25,10 +25,18 @@ export const columns = [
   {
     label: "物料属性",
     prop: "bomMaterialAttribute",
+    type: 'select',
+    dicData:dicts.material_properties,
+    props: { label: "dictLabel", value: "dictValue" },
   },
   {
     label: "物料数量",
     prop: "bomMaterialNumber",
+    min:0,
+    slot:true,
+    cell: true,
+    type: "number",
+    precision: 2,
   },
 
 

+ 132 - 57
src/views/base/bom/index.vue

@@ -1,41 +1,45 @@
 <template>
   <div class="mainContentBox">
+    <!--{{dataDetail}}-->
+    <!--{{dicts}}-->
+    <div class="detail">
+      <div class="title-detail">物料名称:{{dataDetail.materialCode}}</div>
+      <div class="title-detail">物料编码:{{dataDetail.materialName}}</div>
+      <div class="title-detail">物料属性:{{dataDetail.attributeDictLabel}}</div>
+    </div>
     <avue-crud
       ref="crudRef"
       v-model:search="search"
       v-model="form"
       :data="data"
       :option="option"
-      v-model:page="page"
       @row-update="updateRow"
       @row-del="deleteRow"
       @search-change="searchChange"
       @search-reset="resetChange"
-      @size-change="dataBomList"
-      @current-change="dataBomList"
       @selection-change="selectionChange"
     >
       <template #menu-left="{ size }">
         <el-button
-          type="danger"
+          type="primary"
           icon="el-icon-plus"
           @click="openMaterial"
           >新增</el-button
         ></template>
-        <template #menu="{row,index,type}">
-          <el-button @click="binding(row)"
-                     icon="el-icon-link"
-                     text
-                     type="primary"
-          >BOM</el-button>
-        </template>
+
         <CommonTable
           ref="ctableRef"
-          tableTitle="绑定子项"
+          tableTitle="物料选择"
           tableType="BOM"
           @selected-sure="onSelectedFinish"
         />
+      <template #footer>
+        <div class="detail-footer">
+          <el-button type="primary" @click="onSelected"> 保存 </el-button>
+          <el-button @click="routeBack">取消</el-button>
 
+        </div>
+      </template>
       <template #menu-right="{}">
         <el-dropdown split-button
           >导入
@@ -52,17 +56,11 @@
             </el-dropdown-menu>
           </template>
         </el-dropdown>
-        <el-button
-          class="ml-3"
-          @click="exportData('/api/v1/plan/order/export')"
-        >
-          <template #icon> <i-ep-download /> </template>导出
-        </el-button>
       </template>
     </avue-crud>
     <CommonTable
       ref="ctableRef"
-      tableTitle="绑定子项"
+      tableTitle="BOM添加"
       tableType="MARTERIAL"
       @selected-sure="onSelectedFinish"
     />
@@ -78,30 +76,33 @@ import { useCommonStoreHook, useDictionaryStoreHook } from "../../../store/index
 import {
   getList,
 } from "@/api/bom";
+import {
+  getMaterialDetails,
+} from "@/api/material";
+
+import {
+  batchAddBom,
+} from "@/api/bom";
 const { isShowTable, tableType } = toRefs(useCommonStoreHook());
 // 数据字典相关
 const { dicts } = useDictionaryStoreHook();
 const router = useRouter();
 const route = useRoute();
+
+const dataDetail=ref({});
 const test = () => {
   isShowTable.value = true;
   tableType.value = tableType.value == 1 ? 2 : 1;
 };
-
 const openMaterial=()=>{
   if (ctableRef.value) {
     ctableRef.value.startSelect();
   }
 }
 const formData=ref({});
-const dataBomList=()=>{
-  formData.materialCode=route.params.materialCode;
-  getList(formData).then((data: any) => {
-    ElMessage({
-      message: data.msg,
-      type: "success",
-    });
-  });
+const dataBomLists=()=>{
+  search.value.materialCode=route.value.materialCode;
+  dataNoPageList();
 }
 
 const ctableRef = ref(null);
@@ -111,16 +112,47 @@ const binding = (row) => {
     ctableRef.value.startSelect();
   }
 };
-const dialog = reactive({
-  title: "绑定子项",
-  visible: false,
-});
+const onSelected=()=>{
+  for(var i=0;i<data.value.length;i++){
+    if(data.value[i].bomMaterialNumber<=0){
+      ElMessage({
+        message: data.value[i].bomMaterialName+"数量不能为0",
+        type: "error",
+      });
+      return;
+    }
+  }
+  if(data.value.length===0){
+    ElMessage({
+      message: "物料记录不能为空!",
+      type: "error",
+    });
+    return;
+  }
+  batchAddBom(data.value).then(
+    (data: any)=>{
+      if(data.code==="200") {
+        ElMessage({
+          message: data.msg,
+          type: "success",
+        });
+        router.back();
+      }
+      else {
+        ElMessage({
+          message: data.msg,
+          type: "error",
+        });
+      }
+    }
+  );
+}
 // 传入一个url,后面不带/
 const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
   useCrud({
     src: "/api/v1/base/materialBom",
   });
-const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
+const { dataNoPageList,createRow, updateRow, deleteRow, searchChange, resetChange } =
   Methords; //增删改查
 const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
 const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等工具
@@ -136,16 +168,10 @@ const crudRef = ref(null); //crudRef.value 获取avue-crud对象
 
 onMounted(() => {
   // console.log("crudRef", crudRef)
-  formData.materialCode=route.params.materialCode;
-  getList(formData).then((data: any) => {
-    ElMessage({
-      message: data.msg,
-      type: "success",
-    });
-    // 上传完成后的刷新操作
-    page.currentPage = 1;
-    dataList();
-  });
+  search.value.materialCode=route.params.materialCode;
+  queryMaterialDetail();
+  dataNoPageList();
+
 });
 
 /**
@@ -154,8 +180,7 @@ onMounted(() => {
 const uploadRef = ref(null);
 const uploadFinished = () => {
   // 上传完成后的刷新操作
-  page.currentPage = 1;
-  dataList();
+  dataNoPageList();
 };
 const importExcelData = () => {
   if (uploadRef.value) {
@@ -166,20 +191,70 @@ const importExcelData = () => {
 // 设置表格列或者其他自定义的option
 option.value = Object.assign(option.value, {
   selection: true,
+  addBtn: false,
+  viewBtn: false,
+  editBtn:false,
+  saveBtn:false,
+  cellBtn: true,
   column: columns,
 });
-
+const routeBack =()=>{
+  router.back();
+}
 const onSelectedFinish = (selectedValue) => {
- /* formData.id=selectedValue.id;
-  formData.parentId=factory.value.id;
-  updateWorkShop(formData).then((data: any) => {
-    ElMessage({
-      message: data.msg,
-      type: "success",
-    });
-    // 上传完成后的刷新操作
-    page.currentPage = 1;
-    dataList();
-  });*/
+  for(var i=0;i<data.value.length;i++){
+    if(data.value[i].bomMaterialCode===selectedValue.materialCode){
+      ElMessage({
+        message: data.value[i].bomMaterialName+"已经添加过了",
+        type: "error",
+      });
+      return;
+    }
+  }
+  const bom=ref({
+    materialCode:route.params.materialCode,
+    bomMaterialCode:selectedValue.materialCode,
+    bomMaterialName:selectedValue.materialName,
+    bomMaterialAttribute:selectedValue.attributeDictValue,
+    bomMaterialNumber:0,
+    $cellEdit:true,
+  });
+  data.value.push(bom.value);
+};
+const queryMaterialDetail = () => {
+  getMaterialDetails(route.params.materialCode).then(
+
+    ({ data }) => {
+      dataDetail.value=data;
+      dicts.material_properties;
+      for(var i=0;i<dicts.material_properties.length;i++){
+        if(data.attributeDictValue===dicts.material_properties[i].dictValue){
+          dataDetail.value.attributeDictLabel=dicts.material_properties[i].dictLabel;
+        }
+      }
+
+    }
+  );
 };
 </script>
+<style type="text/css">
+  .title-detail{
+    width: 30%;
+    height: 50px;
+    line-height: 50px;
+    margin: 25px 20px 25px 0;
+    float: left;
+  }
+  .detail{
+    margin: 0 auto;
+    width: 100%;
+  }
+  .avue-crud{
+    float: left;
+  }
+  .detail-footer{
+    float: right;
+    margin-top:15px;
+  }
+
+</style>

+ 2 - 2
src/views/base/craftManagement/route/bindProcess.vue

@@ -96,7 +96,7 @@
     </div>
   </div>
 </template>
-<script setup lang="ts">
+<script setup>
 import {
   Back,
   Download,
@@ -182,7 +182,7 @@ const loadTreeData = () => {
 };
 
 // 中间列表====================
-const list2 = ref([]);
+const list2 = ref < any > [];
 const selectIndex = ref(-1);
 
 const clickFlowItem = (item, index) => {

+ 94 - 0
src/views/base/craftManagement/route/components/bottomTable.vue

@@ -0,0 +1,94 @@
+<template>
+  <avue-crud
+    ref="crudRef"
+    v-model:search="search"
+    v-model="form"
+    :data="data"
+    :option="option"
+    v-model:page="page"
+    @row-save="createRow"
+    @row-update="updateRow"
+    @row-del="deleteRow"
+    @selection-change="selectionChange"
+    @sortable-change="onSortChange"
+    @search-change="searchChange"
+    @search-reset="resetChange"
+    @size-change="dataList"
+    @current-change="dataList"
+  />
+</template>
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import { useCrud } from "@/hooks/userCrud";
+import { getTableConfig } from "./configs";
+import { saveCompoents } from "@/api/craft/process/index";
+
+const props = defineProps({
+  tableTitle: {
+    default: "",
+    type: String,
+  },
+  tableType: {
+    default: "",
+    type: String,
+  },
+});
+
+const route = useRoute();
+const tableConfig = getTableConfig(route.params.id);
+
+// 传入一个url,后面不带/
+const { url, form, data, option, search, page, toDeleteIds, Methords, Utils } =
+  useCrud({
+    src: tableConfig[props.tableType].url,
+  });
+
+const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
+  Methords; //增删改查
+const { selectionChange, multipleUpdate } = Methords; //选中和批量删除事件
+
+const crudRef = ref(null); //crudRef.value 获取avue-crud对象
+
+const startCreat = () => {
+  crudRef.value && crudRef.value.rowAdd();
+};
+
+const saveSortData = async () => {
+  multipleUpdate();
+};
+
+defineExpose({ startCreat, saveSortData });
+
+const onSortChange = () => {
+  data.value.forEach((item) => {
+    console.log(item.id);
+  });
+};
+
+onMounted(() => {
+  url.value = tableConfig[props.tableType].url;
+  option.value = Object.assign(option.value, {
+    addBtn: false,
+    searchShow: false,
+    header: false,
+    sortable: true,
+    column: tableConfig[props.tableType].column,
+  });
+  dataList();
+});
+
+watch(
+  () => props.tableType,
+  () => {
+    console.log("faslegb");
+    url.value = tableConfig[props.tableType].url;
+    option.value = Object.assign(option.value, {
+      menu: false,
+      highlightCurrentRow: true,
+      addBtn: false,
+      column: tableConfig[props.tableType].column,
+    });
+    dataList();
+  }
+);
+</script>

+ 130 - 0
src/views/base/craftManagement/route/components/configs.ts

@@ -0,0 +1,130 @@
+import { useDictionaryStoreHook } from "@/store";
+const { dicts } = useDictionaryStoreHook();
+
+export const getTableConfig = (id: string) => {
+  return {
+    // 获取工序记录项信息信息
+    jiluxiang: {
+      url: `/api/v1/op/operationRecord`,
+      column: [
+        {
+          label: "工序id",
+          prop: "operationId",
+          display: false,
+          hide: true,
+          value: id,
+        },
+        { label: "记录项", prop: "thName" },
+        {
+          label: "单位",
+          prop: "unit",
+          search: true,
+          filterable: true,
+          type: "select",
+          dataType: "string",
+          dicData: dicts.danwei_type,
+          props: { label: "dictLabel", value: "dictValue" },
+        },
+        { label: "标准值", prop: "standard" },
+        { label: "上限值", prop: "upper" },
+        { label: "下限值", prop: "lower" },
+      ],
+    },
+
+    FACTORY: {
+      url: "/api/v1/base/workShop",
+      column: [
+        {
+          label: "车间名称",
+          prop: "name",
+          search: true,
+        },
+        {
+          label: "车间负责人",
+          prop: "manager",
+          rules: [
+            {
+              required: true,
+              message: "请选择厂区负责人",
+              trigger: "blur",
+            },
+          ],
+          type: "select",
+          dicUrl: import.meta.env.VITE_APP_BASE_API + "/api/v1/sys/user/list",
+          dicMethod: "post",
+          props: {
+            label: "userName", // 下拉菜单显示的字段
+            value: "userName", // 下拉菜单值的字段
+          },
+        },
+        {
+          label: "车间位置",
+          prop: "position",
+        },
+        {
+          label: "所属工厂",
+          prop: "factoryName",
+          display: false,
+        },
+        {
+          label: "车间描述",
+          prop: "remark",
+        },
+        {
+          label: "创建人",
+          prop: "creator",
+          display: false,
+        },
+        {
+          label: "创建时间",
+          prop: "created",
+          display: false,
+        },
+      ],
+    },
+  };
+};
+
+// 工艺工序组件路径的组件类别
+interface comType {
+  compentName: string;
+  compentType: string;
+}
+export const comTypes: comType[] = [
+  {
+    compentName: "记录项",
+    compentType: "jiluxiang",
+  },
+  {
+    compentName: "物料采集",
+    compentType: "wuliaocaiji",
+  },
+  {
+    compentName: "ESOP",
+    compentType: "ESOP",
+  },
+  {
+    compentName: "点检",
+    compentType: "dianjian",
+  },
+  {
+    compentName: "设备记录",
+    compentType: "shebeijilu",
+  },
+  {
+    compentName: "紧固",
+    compentType: "jingu",
+  },
+  {
+    compentName: "调试配对",
+    compentType: "tiaoshipipei",
+  },
+  {
+    compentName: "铭牌绑定",
+    compentType: "mingpai",
+  },
+  {
+    compentName: "多媒体采集",
+    compentType: "duomeiticaiji",
+  },
+];

+ 283 - 0
src/views/base/craftManagement/route/components/processComponent.vue

@@ -0,0 +1,283 @@
+<template>
+  <div
+    class="mainContentBox"
+    style="padding: 0; box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.1)"
+  >
+    <div class="header">
+      <div class="title">绑定工序</div>
+      <el-space>
+        <el-button :icon="Back" size="small" @click="back">返回</el-button>
+        <el-button type="primary" :icon="Document" size="small" @click="save"
+          >保存</el-button
+        >
+      </el-space>
+    </div>
+    <div class="types">
+      <el-dropdown @command="handleCommand">
+        <div class="typeBox addBtn">
+          <el-icon class="icon"><CirclePlus /></el-icon>
+          <div class="name">添加组件</div>
+        </div>
+        <template #dropdown>
+          <el-dropdown-menu>
+            <el-dropdown-item
+              v-for="(com, index) in comTypes"
+              :key="index"
+              :command="com"
+            >
+              {{ com.compentName }}</el-dropdown-item
+            >
+          </el-dropdown-menu>
+        </template>
+      </el-dropdown>
+      <VueDraggable
+        v-model="selectProComs"
+        :animation="150"
+        ghostClass="ghost"
+        @update="onUpdate"
+        style="display: flex"
+      >
+        <div
+          class="typeContainer"
+          v-for="(item, index) in selectProComs"
+          :key="index"
+          @click="clickToolCom(item, index)"
+        >
+          <div class="typeBox others" :class="getNameClass(index)">
+            <svg-icon :icon-class="item.compentType" size="30" />
+            <div class="name">{{ item.compentName }}</div>
+          </div>
+          <Delete class="delete" @click.stop="clickDelete(index)" />
+        </div>
+      </VueDraggable>
+    </div>
+    <div class="binContainer">
+      <div v-if="isChanged || selectIndex === -1">
+        <el-empty
+          :image-size="200"
+          description="请先保存组件,然后再进行操作"
+        />
+      </div>
+      <div v-else>
+        <div class="tipTitle">{{ tipTitle }}</div>
+        <el-button
+          type="primary"
+          @click="creatNewData"
+          style="margin-bottom: 15px"
+          >新增</el-button
+        >
+        <el-button
+          type="primary"
+          @click="saveSortData"
+          style="margin-bottom: 15px"
+          >保存顺序</el-button
+        >
+        <BottomTable ref="bottomTableRef" :tableType="tableType" />
+      </div>
+    </div>
+  </div>
+</template>
+<script setup>
+import { Back, Document, CirclePlus, Delete } from "@element-plus/icons-vue";
+import { VueDraggable } from "vue-draggable-plus";
+import BottomTable from "@/views/base/craftManagement/route/components/bottomTable.vue";
+import { comTypes } from "@/views/base/craftManagement/route/components/configs";
+import { saveCompoents, getCompoentsList } from "@/api/craft/process/index";
+import { useCommonStoreHook, useDictionaryStoreHook } from "@/store";
+import {
+  processesByRouteId,
+  saveProcessInRoute,
+} from "@/api/craft/route/index";
+
+const router = useRouter();
+const route = useRoute();
+
+//组件是否已经改变,如果改变了需要点击保存,才能展示下面的table
+const isChanged = ref(true);
+
+const loadTopList = () => {
+  getCompoentsList(route.params.id).then((res) => {
+    selectProComs.value = res.data || [];
+    selectIndex.value = -1;
+    isChanged.value = false;
+  });
+};
+
+onMounted(async () => {
+  await loadTopList();
+  isChanged.value = false;
+});
+
+// 顶部====================
+const back = () => {};
+
+const save = async () => {
+  for (let i = 0; i < selectProComs.value.length; i++) {
+    selectProComs.value[i].operationId = route.params.id;
+    selectProComs.value[i].sortNum = i;
+  }
+  let p = {
+    operationId: route.params.id,
+    dtos: selectProComs.value,
+  };
+  let res = await saveCompoents(p);
+  // Elmessage.success("保存成功");
+  loadTopList();
+};
+
+// Tools顶部组件 ==================
+// 已经存在的工序组件
+const selectProComs = ref([]);
+const selectIndex = ref(-1);
+const currentCom = ref({});
+const handleCommand = (itme) => {
+  console.log(itme);
+  selectProComs.value.push(itme);
+  isChanged.value = true;
+};
+
+// 点击某一个改变下面的table
+const clickToolCom = (com, index) => {
+  selectIndex.value = index;
+  currentCom.value = com;
+
+  tableType.value = com.compentType;
+};
+
+const onUpdate = () => {
+  console.log("update");
+  isChanged.value = true;
+};
+
+const clickDelete = (index) => {
+  selectProComs.value.splice(index, 1);
+  selectIndex.value = -1;
+  isChanged.value = true;
+};
+
+const getNameClass = (index) => {
+  return index === selectIndex.value ? "selected" : "normal";
+};
+
+// 底部table ===============
+const tipTitle = ref("编辑物料采集");
+const bottomTableRef = ref({});
+const tableType = ref("MARTERIAL");
+
+const creatNewData = () => {
+  bottomTableRef.value && bottomTableRef.value.startCreat();
+};
+
+const saveSortData = () => {
+  bottomTableRef.value && bottomTableRef.value.saveSortData();
+};
+</script>
+
+<style lang="scss" scoped>
+.header {
+  height: 50px;
+  display: flex;
+  background-color: #f5f7f9;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+}
+.types {
+  width: 100%;
+  height: 116px;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+  padding: 12px 20px;
+  display: flex;
+  .typeContainer {
+  }
+  .typeBox {
+    height: 80px;
+    width: 80px;
+    border-radius: 4px 4px 4px 4px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    .icon {
+      height: 32px;
+      width: 32px;
+    }
+    .name {
+      width: 56px;
+      height: 16px;
+      font-weight: 500;
+      font-size: 14px;
+      line-height: 16px;
+      text-align: center;
+      font-style: normal;
+      text-transform: none;
+    }
+  }
+
+  .addBtn {
+    border: 1px solid #0a59f7;
+    color: #0a59f7;
+  }
+  .others {
+    color: rgba(0, 0, 0, 0.9);
+    border: 1px solid rgba(0, 0, 0, 0.9);
+    margin-left: 20px;
+    position: relative;
+  }
+  .delete {
+    //position: absolute;
+    //bottom: -20px;
+    //left: 0;
+    margin-left: 50px;
+    width: 1em;
+    height: 1em;
+    color: red;
+    visibility: hidden;
+  }
+  .typeContainer:hover {
+    .delete {
+      visibility: visible;
+    }
+  }
+  .normal {
+    background: #ffffff;
+    border: 1px solid rgba(35, 32, 50, 0.1);
+  }
+  .selected {
+    background: rgba(10, 89, 247, 0.2);
+    border: 1px solid #0a59f7;
+  }
+}
+
+.title {
+  line-height: 44px;
+  color: #6f7991;
+  font-size: 14px;
+  font-weight: bold;
+  text-align: left;
+  margin-left: 20px;
+}
+
+.binContainer {
+  height: calc(100vh - 165px);
+  width: 100%;
+  background-color: #f5f7f9;
+  overflow-y: auto;
+  background-color: white;
+  //margin-top: 16px;
+  //margin-left: 20px;
+  padding: 16px 20px;
+}
+.tipTitle {
+  width: 84px;
+  height: 16px;
+  font-weight: 500;
+  font-size: 14px;
+  color: rgba(0, 0, 0, 0.9);
+  line-height: 16px;
+  text-align: left;
+  font-style: normal;
+  text-transform: none;
+  margin-bottom: 16px;
+}
+</style>

+ 61 - 6
src/views/base/modeling/factory/index.vue

@@ -1,5 +1,3 @@
-
-
 <template>
   <div class="mainContentBox">
     <avue-crud
@@ -44,6 +42,18 @@
         tableType="FACTORY"
         @selected-sure="onSelectedFinish"
       />
+    <CommonTable
+      ref="workShopRef"
+      tableTitle="绑定子项"
+      tableType="PRODUCTIONLINE"
+      @selected-sure="onSelectedLineFinish"
+    />
+    <CommonTable
+      ref="productionLineRef"
+      tableTitle="绑定子项"
+      tableType="STATION"
+      @selected-sure="onSelectedStationFinish"
+    />
 
     <ExcelUpload ref="uploadRef" @finished="uploadFinished" />
   </div>
@@ -57,14 +67,30 @@
   import {
     updateWorkShop,
   } from "@/api/workShop";
+
+  import {
+    updateProductionLine,
+  } from "@/api/productionLine";
+  import {
+    updateStation,
+  } from "@/api/station";
   // 公共弹窗相关
   const ctableRef = ref(null);
+  const workShopRef=ref(null);
+  const productionLineRef=ref(null);
   const factory=ref({});
   const binding = (row) => {
     factory.value=row;
-    if (ctableRef.value) {
+    if (row.level==="first") {
       ctableRef.value.startSelect();
     }
+    if(row.level==="second"){
+      workShopRef.value.startSelect();
+    }
+    if(row.level==="third"){
+      productionLineRef.value.startSelect();
+    }
+
   };
   const dialog = reactive({
     title: "绑定子项",
@@ -116,8 +142,8 @@
     menuWidth: 320,
     border: true,
     index: true,
-    rowKey: 'id',
-    rowParentKey: 'parentId',
+    rowKey: 'code',
+    rowParentKey: 'parentCode',
     column: [
       {
         label: "厂区名称",
@@ -177,8 +203,9 @@
 
 
   const onSelectedFinish = (selectedValue) => {
+    formData.code=selectedValue.code;
+    formData.parentCode=factory.value.code;
     formData.id=selectedValue.id;
-    formData.parentId=factory.value.id;
     updateWorkShop(formData).then((data: any) => {
       ElMessage({
         message: data.msg,
@@ -189,6 +216,34 @@
       dataList();
     });
   };
+  const onSelectedLineFinish = (selectedValue) => {
+    formData.code=selectedValue.code;
+    formData.parentCode=factory.value.code;
+    formData.id=selectedValue.id;
+    updateProductionLine(formData).then((data: any) => {
+      ElMessage({
+        message: data.msg,
+        type: "success",
+      });
+      // 上传完成后的刷新操作
+      page.currentPage = 1;
+      dataList();
+    });
+  };
+  const onSelectedStationFinish = (selectedValue) => {
+    formData.code=selectedValue.code;
+    formData.parentCode=factory.value.code;
+    formData.id=selectedValue.id;
+    updateStation(formData).then((data: any) => {
+      ElMessage({
+        message: data.msg,
+        type: "success",
+      });
+      // 上传完成后的刷新操作
+      page.currentPage = 1;
+      dataList();
+    });
+  };
 </script>
 
 

+ 115 - 0
src/views/base/modeling/production-line/capacity/columns.ts

@@ -0,0 +1,115 @@
+import { useDictionaryStoreHook } from "@/store";
+const { dicts } = useDictionaryStoreHook();
+export const columns = [
+  {
+    label: "物料编号",
+    prop: "materialCode",
+    search: true,
+    rules: [{
+      required: true,
+      message: "请选择物料编号",
+      trigger: "blur"
+    }],
+  },
+  {
+    label: "产能",
+    prop: "capacity",
+    search: true,
+    rules: [{
+      required: true,
+      message: "请填写产能",
+      trigger: "blur"
+    }],
+  },
+  {
+    label: "工位类型",
+    prop: "stationDictValue",
+    search: true,
+    rules: [{
+      required: true,
+      message: "请选择工位类型",
+      trigger: "blur"
+    }],
+    type: 'select',
+    dicData:dicts.station_type,
+    searchClearable: false, //可清空的输入框,默认为true
+    filterable: true, //添加filterable属性即可启用搜索功能
+    props: {
+      label: "dictLabel", // 下拉菜单显示的字段
+      value: "dictValue" // 下拉菜单值的字段
+    },
+  },
+  {
+    label: "工位操作方式",
+    prop: "operateDictValue",
+    rules: [{
+      required: true,
+      message: "请选择工位方式",
+      trigger: "blur"
+    }],
+    type: 'select',
+    dicData:dicts.station_operate_type,
+    props: {
+      label: "dictLabel", // 下拉菜单显示的字段
+      value: "dictValue" // 下拉菜单值的字
+    },
+  },
+  {
+    label: "工位负责人",
+    prop: "manager",
+    rules: [{
+      required: true,
+      message: "请选择工位负责人",
+      trigger: "blur"
+    }],
+    type: 'select',
+    dicUrl:import.meta.env.VITE_APP_BASE_API+"/api/v1/sys/user/list",
+    dicMethod:"post",
+    props: {
+      label: "userName", // 下拉菜单显示的字段
+      value: "userName" // 下拉菜单值的字段
+    },
+  },
+  {
+    label: "所属产线",
+    prop: "productionLineName",
+    display:false
+  },
+  {
+    label: "工位地址",
+    prop: "position",
+    rules: [{
+      required: true,
+      message: "请填写工位地址",
+      trigger: "blur"
+    }],
+  },
+  {
+    label: "工位IP地址",
+    prop: "stationIp",
+    rules: [{
+      required: true,
+      message: "请填写工位IP地址",
+      trigger: "blur",
+    }],
+
+  },
+  {
+    label: "工位描述",
+    prop: "remark",
+    type: 'textarea',
+    span: 24,
+  },
+  {
+    label: "创建人",
+    prop: "creator",
+    display:false
+  },
+  {
+    label: "创建时间",
+    prop: "created",
+    display:false
+  },
+]
+
+

+ 6 - 0
src/views/base/modeling/production-line/capacity/index.vue

@@ -0,0 +1,6 @@
+<template>
+  <avue-form ref="formRef"
+             :option="option"
+             v-model="form"
+             @submit="handleSubmit"></avue-form>
+</template>

+ 1 - 1
src/views/base/modeling/station/columns.ts

@@ -3,7 +3,7 @@ const { dicts } = useDictionaryStoreHook();
 export const columns = [
   {
     label: "工位编号",
-    prop: "stationCode",
+    prop: "code",
     search: true,
     rules: [{
       required: true,

+ 39 - 0
src/views/base/modeling/station/components/columns.ts

@@ -0,0 +1,39 @@
+import { useDictionaryStoreHook } from "@/store";
+const { dicts } = useDictionaryStoreHook();
+export const columns = [
+  {
+    label: "设备编号",
+    prop: "deviceNo",
+    search: true,
+    rules: [{
+      required: true,
+      message: "请填写工位编号",
+      trigger: "blur"
+    }],
+  },
+  {
+    label: "设备名称",
+    prop: "deviceName",
+    search: true,
+  },
+  {
+    label: "设备类型",
+    prop: "device_type",
+    search: true,
+    rules: [{
+      required: true,
+      message: "请选择工位类型",
+      trigger: "blur"
+    }],
+    type: 'select',
+    dicData:dicts.device_type,
+    searchClearable: false, //可清空的输入框,默认为true
+    filterable: true, //添加filterable属性即可启用搜索功能
+    props: {
+      label: "dictLabel", // 下拉菜单显示的字段
+      value: "dictValue" // 下拉菜单值的字段
+    },
+  },
+]
+
+

+ 162 - 0
src/views/base/modeling/station/components/station-page.vue

@@ -0,0 +1,162 @@
+<template>
+  <div class="mainContentBox">
+    <avue-crud
+      ref="crudRef"
+      v-model:search="search"
+      v-model="form"
+      :data="data"
+      :option="option"
+      v-model:page="page"
+      @row-save="deviceList"
+      @row-update="updateRow"
+      @row-del="deleteRow"
+      @search-change="searchChange"
+      @search-reset="resetChange"
+      @size-change="dataList"
+      @current-change="dataList"
+      @selection-change="selectionChange"
+    >
+      <template #menu-left="{ size }">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          @click="deviceList"
+        >新增</el-button
+        >
+        <el-button
+          :disabled="toDeleteIds.length < 1"
+          type="danger"
+          icon="el-icon-delete"
+          :size="size"
+          @click="multipleDelete"
+        >删除</el-button
+        >
+      </template>
+    </avue-crud>
+    <CommonTable
+      ref="ctableRef"
+      tableTitle="设备列表"
+      tableType="DEVICE"
+      @selected-sure="onSelectedFinish"
+    />
+  </div>
+</template>
+<script setup lang="ts">
+  import { ref, getCurrentInstance } from "vue";
+  import { useCrud } from "@/hooks/userCrud";
+  import ButtonPermKeys from "@/common/configs/buttonPermission";
+  import { useCommonStoreHook } from "@/store";
+
+  const { isShowTable, tableType } = toRefs(useCommonStoreHook());
+  import { useDictionaryStoreHook } from "@/store";
+  import { columns } from "./columns";
+  import {
+    addStationDevice,
+  } from "@/api/station";
+  const test = () => {
+    isShowTable.value = true;
+    tableType.value = tableType.value == 1 ? 2 : 1;
+  };
+
+  // 传入一个url,后面不带/
+  const { form, data, option, search, page, toDeleteIds, Methords, Utils } =
+    useCrud({
+      src: "/api/v1/base/stationDevice",
+    });
+  const { dataList, createRow, updateRow, deleteRow, searchChange, resetChange } =
+    Methords; //增删改查
+  const { selectionChange, multipleDelete } = Methords; //选中和批量删除事件
+  const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等工具
+  // checkBtnPerm(ButtonPermKeys.PLAN.BTNS.order_add) :permission="permission"
+  // const permission = reactive({
+  //   delBtn: checkPerm(buttonPermission.PLAN.BTNS.order_del),
+  //   addBtn: checkPerm(buttonPermission.PLAN.BTNS.order_add),
+  //   editBtn: checkPerm(buttonPermission.PLAN.BTNS.order_edit),
+  //   menu: true,
+  // });
+  function rowSave(form,done,loading) {
+    console.info(form);
+    createRow(form,done,loading);
+
+  }
+  const crudRef = ref(null); //crudRef.value 获取avue-crud对象
+
+  onMounted(() => {
+    // console.log("crudRef", crudRef)
+    dataList();
+  });
+
+  /**
+   * 上传excel相关
+   */
+  const uploadRef = ref(null);
+  const uploadFinished = () => {
+    // 上传完成后的刷新操作
+    page.currentPage = 1;
+    dataList();
+  };
+  const importExcelData = () => {
+    if (uploadRef.value) {
+      uploadRef.value.show("/api/v1/base/stationDevice");
+    }
+  };
+  const ctableRef=ref(null);
+  const deviceList=()=>{
+    ctableRef.value.startSelect();
+  }
+
+  // 设置表格列或者其他自定义的option
+  option.value = Object.assign(option.value, {
+    selection: true,
+    column: columns,
+    saveBtn:false,
+    delBtn: false,
+    editBtn: false,
+    addBtn: false,
+    viewBtn: false,
+    menu: false,
+  });
+  const props = defineProps({
+    stationId: {
+      type: Number,
+      default: () => {
+        return 0;
+      }
+    }
+  })
+
+  watch?.(
+    () => props.stationId,
+    (newVal: string) => {
+      alert(newVal)
+      search.value.stationId = newVal
+      dataList()
+    }
+  );
+  const onSelectedFinish=(selectedValue)=>{
+    const selectDevice=ref({
+      deviceNo: selectedValue.deviceNo,
+      stationId:props.stationId,
+  });
+    console.info(selectDevice);
+    addStationDevice(selectDevice.value).then(
+      (data:any)=>{
+        if(data.code==="200") {
+          ElMessage({
+            message: data.msg,
+            type: "success",
+          });
+          router.back();
+        }
+        else {
+          ElMessage({
+            message: data.msg,
+            type: "error",
+          });
+        }
+      }
+    );
+
+  }
+</script>
+

+ 24 - 3
src/views/base/modeling/station/index.vue

@@ -26,9 +26,22 @@
         >删除</el-button
         >
       </template>
-
+      <template #menu="{row,index,type}">
+        <el-button @click="binding(row)"
+                   icon="el-icon-link"
+                   text
+                   type="primary"
+        >设备</el-button>
+      </template>
     </avue-crud>
-
+    <el-dialog
+      v-model="dialog.visible"
+      :title="dialog.title"
+      width="900px"
+      @close="dialog.visible = false"
+    >
+      <station-page  :stationId="stationDevice.id"/>
+    </el-dialog>
   </div>
 </template>
 <script setup="ts">
@@ -87,7 +100,15 @@
       uploadRef.value.show("/api/v1/base/station");
     }
   };
-
+  const dialog = reactive({
+    title: "设备绑定",
+    visible: false,
+  });
+  const stationDevice=ref(null);
+  const binding=(row)=>{
+    dialog.visible=true;
+    stationDevice.value=row;
+  }
   // 设置表格列或者其他自定义的option
   option.value = Object.assign(option.value, {
     selection: true,