Explorar o código

1.工艺路线组件。2.avue拖拽。3.组件svgs。4.useCrud添加批量更新。

jiaxiaoqiang hai 1 ano
pai
achega
b7f7547476

+ 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",

+ 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,
+  });
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 9 - 0
src/assets/icons/ESOP.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 3 - 0
src/assets/icons/dianjian.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 3 - 0
src/assets/icons/duomeiticaiji.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 7 - 0
src/assets/icons/jiluxiang.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 7 - 0
src/assets/icons/jingu.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 10 - 0
src/assets/icons/mingpai.svg


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 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>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 9 - 0
src/assets/icons/wuliaocaiji.svg


+ 14 - 1
src/components/CommonTable/index.vue

@@ -61,7 +61,7 @@ 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 +71,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) => {

+ 36 - 1
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: "序号",
@@ -192,6 +197,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",

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

@@ -22,6 +22,7 @@ export const useDictionaryStore = defineStore("dictionaryStore", {
       "workshop_section",
       "skill_requirements",
       "station_type",
+      "danwei_type",
     ],
     dicts: [],
   }),

+ 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>