Browse Source

Merge branch 'master' of http://maven.jgiot.com:7012/jiaxiaoqiang/chengfei-test-system

dengrui 4 months ago
parent
commit
d5d05a7842

+ 2 - 1
.env.development

@@ -11,7 +11,8 @@ VITE_APP_BASE_API = '/dev-api'
 
 # 开发接口地址
 
-VITE_APP_API_URL = 'http://test.jgiot.com:7012'
+VITE_APP_API_URL = 'http://192.168.1.43:7205/'
+# VITE_APP_API_URL = 'http://192.168.1.4:18000/'
 
 # 是否启用 Mock 服务
 VITE_MOCK_DEV_SERVER = false

+ 1 - 1
src/api/config/index.ts

@@ -11,7 +11,7 @@ import { AxiosPromise } from "axios";
 //测试仪器配置分页查询
 export function instrumentConfigPage(queryParams?: object): AxiosPromise<any> {
   return request({
-    url: "/api/v1/instrumentConfig/page",
+    url: "/api/v1/test/engrInstrumentConfig/page",
     method: "post",
     data: queryParams,
   });

+ 11 - 0
src/api/project/excute.ts

@@ -0,0 +1,11 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+
+// 查询测试类型
+export function searhTestType(data: object): AxiosPromise {
+  return request({
+    url: "/api/v1/test/engrExecute/selectTestType",
+    method: "post",
+    data: {},
+  });
+}

+ 35 - 0
src/api/project/index.ts

@@ -66,3 +66,38 @@ export function getTestProjectList(data: object): AxiosPromise {
     data: data,
   });
 }
+
+// 获取 工程配置页面  所有功能模块的接口
+export function getProjectConfigMokuaiPage(): AxiosPromise {
+  return request({
+    url: "/api/v1/test/model/selectDetailList",
+    method: "post",
+    data: {},
+  });
+}
+
+// 更新测试模块  后台的将流程信息保存到了 测试项目下
+export function updateTestModule(data: object): AxiosPromise {
+  return request({
+    url: "/api/v1/test/engrProject/update",
+    method: "post",
+    data: data,
+  });
+}
+
+// 获取测试工程项目信息
+export function getTestProjectInfo(id: string): AxiosPromise {
+  return request({
+    url: `/api/v1/test/engrProject/get/${id}`,
+    method: "get",
+  });
+}
+
+// 查询工程全局配置
+export function getProjectGlobalConfig(engineeringId: string): AxiosPromise {
+  return request({
+    url: "/api/v1/test/engineering/selectEngrConfig",
+    method: "post",
+    data: { engineeringId: engineeringId },
+  });
+}

+ 5 - 0
src/assets/icons/addHao.svg

@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
+  <path fill-rule="evenodd" d="M4.5 4a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5h15a.5.5 0 0 0 .5-.5v-15a.5.5 0 0 0-.5-.5h-15ZM2 4.5A2.5 2.5 0 0 1 4.5 2h15A2.5 2.5 0 0 1 22 4.5v15a2.5 2.5 0 0 1-2.5 2.5h-15A2.5 2.5 0 0 1 2 19.5v-15Z" clip-rule="evenodd"/>
+  <path fill-rule="evenodd" d="M12 7a1 1 0 0 1 1 1v8a1 1 0 1 1-2 0V8a1 1 0 0 1 1-1Z" clip-rule="evenodd"/>
+  <path fill-rule="evenodd" d="M7 12a1 1 0 0 1 1-1h8a1 1 0 1 1 0 2H8a1 1 0 0 1-1-1Z" clip-rule="evenodd"/>
+</svg>

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

@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
+  <path fill-rule="evenodd" d="M4.5 4a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5h15a.5.5 0 0 0 .5-.5v-15a.5.5 0 0 0-.5-.5h-15ZM2 4.5A2.5 2.5 0 0 1 4.5 2h15A2.5 2.5 0 0 1 22 4.5v15a2.5 2.5 0 0 1-2.5 2.5h-15A2.5 2.5 0 0 1 2 19.5v-15Z" clip-rule="evenodd"/>
+  <path fill-rule="evenodd" d="M7 12a1 1 0 0 1 1-1h8a1 1 0 1 1 0 2H8a1 1 0 0 1-1-1Z" clip-rule="evenodd"/>
+</svg>

+ 13 - 0
src/components/hjflow/src/hjflow/index.vue

@@ -124,10 +124,23 @@ const updateNodeData = (node: HJNodeData) => {
     // updateNode(node.id, node)
   }
 };
+// 清空状态 比如选中某一个节点的状态
+const clearStatus = () => {
+  currentHeaderOperationNodeData.value = null;
+  currentClickEdgeData.value = null;
+  historyList = [];
+};
+
+// 获取是否是正在编辑的状态 目前只判断节点的新增和删除  外面保存之后要清空状态
+const getChangedStatus = () => {
+  return historyList.length > 0;
+};
 
 defineExpose({
   updateNodeData,
   initFlow,
+  clearStatus,
+  getChangedStatus,
 });
 
 // ======= Panel =======

+ 1 - 1
src/components/hjflow/src/nodes/universal/UniversalNode.vue

@@ -15,7 +15,7 @@ import OperationHeader from "../com/operationHeader.vue";
 const props = defineProps<HJInterNodeData>();
 
 onMounted(() => {
-  console.log("mounted", props);
+  // console.log("mounted", props);
 });
 </script>
 

+ 2 - 0
src/components/hjflow/src/types/comTypes.ts

@@ -117,4 +117,6 @@ export interface HJFlowProps {
 export interface HJFlowInstance {
   updateNodeData: (node: HJNodeData) => void;
   initFlow: (nodes: HJNodeData[], edges: any[]) => void;
+  clearStatus: () => void;
+  getChangedStatus: () => boolean;
 }

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

@@ -16,6 +16,7 @@ export const useCommonStore = defineStore("commonStore", {
     pageSize: 9, // 首页每页显示的条数
 
     currentProjectId: "", //在首页点击某一项的配置工程的时候使用
+    currentTestItemId: "", //选择的测试项目
   }),
   persist: true,
 });

+ 1 - 1
src/views/main/components/menu.vue

@@ -46,7 +46,7 @@ const router = useRouter();
 const handleMenuClick = (menu: MenuItem) => {
   if (menu.route != currentMenu.value.route) {
     // 如果工程配置没有值,就不跳转,并提示   && !currentProjectId.value
-    if (menu.route === "/main/project-config") {
+    if (menu.route === "/main/project-config" && !currentProjectId.value) {
       ElMessage.warning("请先在首页选择工程");
       return;
     }

+ 4 - 0
src/views/modules/global-config/global-config.vue

@@ -265,6 +265,10 @@ const globalHandledel = (index: number, row: any) => {
           </div>
         </div>
       </el-tab-pane>
+      <el-tab-pane label="执行终端" name="执行终端"
+        >跟仪器配置一样只是 instrumentProperty 仪器属性(1工程仪器 2执行仪器)
+        仪器类型接口 在仪器配置接口API里面</el-tab-pane
+      >
     </el-tabs>
 
     <configAddVue ref="configChildRef" @save="configSaveFun"></configAddVue>

+ 2 - 1
src/views/modules/home/home.vue

@@ -154,7 +154,7 @@ import {
 } from "@/api/project";
 
 import { useCommonStoreHook } from "@/store";
-const { currentProjectId, currentMenu, pageSize } =
+const { currentProjectId, currentMenu, pageSize, currentTestItemId } =
   toRefs(useCommonStoreHook());
 
 const checkAll = ref(false);
@@ -281,6 +281,7 @@ const deleteConfirm = async (item) => {
 const router = useRouter();
 const gotoConfigProject = (project) => {
   currentProjectId.value = project.id;
+  currentTestItemId.value = ""; // 要清空数据,不然进入配置页面会导致数据错误
 
   currentMenu.value = {
     name: "工程配置",

+ 44 - 3
src/views/modules/person-manager/person-manager.vue

@@ -1,6 +1,47 @@
+<template>
+  <el-mention
+    v-model="value1"
+    whole
+    :options="options1"
+    style="width: 320px"
+    placeholder="Please input"
+  />
+  <el-divider />
+  <el-mention
+    v-model="value2"
+    :options="options2"
+    :prefix="['@', '#']"
+    whole
+    :check-is-whole="checkIsWhole"
+    style="width: 320px"
+    placeholder="input @ to mention people, # to mention tag"
+    @search="handleSearch"
+  />
+  <p style="color: red">{{ value1 }}||</p>
+</template>
+
 <script setup lang="ts">
-</script>
+import { ref } from "vue";
+import type { MentionOption } from "element-plus";
 
-<template><div>person-manager</div></template>
+const MOCK_DATA: Record<string, string[]> = {
+  "@": ["Fuphoenixes", "kooriookami", "Jeremy", "btea"],
+  "#": ["1.0", "2.0", "3.0"],
+};
+const value1 = ref("");
+const value2 = ref("");
+const options1 = ref<MentionOption[]>(
+  MOCK_DATA["@"].map((value) => ({ value }))
+);
+const options2 = ref<MentionOption[]>([]);
 
-<style scoped lang="scss"></style>
+const handleSearch = (_: string, prefix: string) => {
+  options2.value = (MOCK_DATA[prefix] || []).map((value) => ({
+    value,
+  }));
+};
+
+const checkIsWhole = (pattern: string, prefix: string) => {
+  return (MOCK_DATA[prefix] || []).includes(pattern);
+};
+</script>

+ 30 - 16
src/views/modules/project-config/com/function-col.vue

@@ -2,6 +2,7 @@
 // import useDragAndDrop from "../configs/useDnD";
 
 // import useDragAndDrop from "jxq-ui";
+import { FunctionTypeModel } from "../configs/properites";
 
 import useDragAndDrop from "@/components/hjflow/src/hooks/useDnD";
 
@@ -9,6 +10,7 @@ const { onDragStart } = useDragAndDrop();
 
 import TitleHeader from "./titleHeader.vue";
 import { propertyData } from "../configs/properites";
+import { getProjectConfigMokuaiPage } from "@/api/project";
 
 const activeNames = ref(["1"]);
 const handleChange = (val: any) => {
@@ -18,29 +20,42 @@ const handleChange = (val: any) => {
 const test = (data) => {
   console.log("test", data?.data?.information?.properties);
 };
+
+const allMokuaiDataList = ref<FunctionTypeModel[]>([]);
+const getList = () => {
+  getProjectConfigMokuaiPage().then((res) => {
+    allMokuaiDataList.value = res.data;
+  });
+};
+
+onMounted(() => {
+  getList();
+});
 </script>
 
 <template>
   <div class="function-col">
     <TitleHeader> 添加功能模块</TitleHeader>
     <el-scrollbar class="collapse-container">
-      <el-collapse v-model="activeNames" @change="handleChange">
+      <el-collapse v-model="activeNames" @change="handleChange" accordion>
         <el-collapse-item
-          :name="funType.name"
-          v-for="(funType, index) in propertyData"
+          :name="funType.id"
+          v-for="(funType, index) in allMokuaiDataList"
           :key="funType.id"
-          :title="funType.name"
+          :title="funType?.moduleName"
         >
-          <el-scrollbar class="drag-container">
-            <div
-              class="drag-item"
-              v-for="(dragData, index) in funType.functions"
-              :key="index"
-              :draggable="true"
-              @dragstart="onDragStart($event, dragData)"
-              @click="test(dragData)"
-            >
-              {{ dragData?.data?.information?.functionName ?? "-" }}
+          <el-scrollbar max-height="400px">
+            <div class="drag-container-scroll">
+              <div
+                class="drag-item"
+                v-for="(dragData, index) in funType.functions"
+                :key="index"
+                :draggable="true"
+                @dragstart="onDragStart($event, dragData)"
+                @click="test(dragData)"
+              >
+                {{ dragData?.data?.information?.functionName ?? "-" }}
+              </div>
             </div>
           </el-scrollbar>
         </el-collapse-item>
@@ -60,12 +75,11 @@ const test = (data) => {
   height: calc(100vh - $main-header-height - 65px);
   overflow-y: auto;
 }
-.drag-container {
+.drag-container-scroll {
   display: flex;
   flex-direction: column;
   justify-content: start;
   align-items: center;
-  max-height: 500px;
   width: 100%;
   overflow-y: auto;
   background-color: $hj-black-2;

+ 24 - 17
src/views/modules/project-config/com/project-message.vue

@@ -4,7 +4,7 @@ import TitleHeader from "@/views/modules/project-config/com/titleHeader.vue";
 
 import { useCommonStoreHook } from "@/store";
 import { getProjectById, getTestProjectList } from "@/api/project/index";
-const { currentProjectId } = toRefs(useCommonStoreHook());
+const { currentProjectId, currentTestItemId } = toRefs(useCommonStoreHook());
 
 const emits = defineEmits(["onClickItem"]);
 
@@ -26,7 +26,7 @@ onMounted(() => {
 });
 
 const testProjectList = ref([]);
-const currentSelectedTestProject = ref();
+
 const toGetTestProjectList = () => {
   // 获取完配置工程信息后,获取测试项目列表
   getTestProjectList({
@@ -38,8 +38,10 @@ const toGetTestProjectList = () => {
 // 当点击了项目
 const clickTestProjectItem = (item) => {
   let data = JSON.parse(JSON.stringify(item));
+
+  currentTestItemId.value = item.id;
+
   emits("onClickItem", data);
-  currentSelectedTestProject.value = data;
 };
 </script>
 
@@ -50,9 +52,9 @@ const clickTestProjectItem = (item) => {
     <div class="project-msg-item">
       <span class="text-l">产品:</span>
       <span class="text-r">{{ currentProject?.engineeringProductName }}</span>
-      <span class="edit">
-        <svg-icon icon-class="homeIcon2" />
-      </span>
+      <!--      <span class="edit">-->
+      <!--        <svg-icon icon-class="homeIcon2" />-->
+      <!--      </span>-->
     </div>
     <div class="project-msg-item">
       <span class="text-l">工程类型:</span
@@ -75,8 +77,15 @@ const clickTestProjectItem = (item) => {
     <div class="project-test-btn">
       <div class="name">测试项目</div>
       <div class="btn">
-        <span>-</span>
-        <span>+</span>
+        <span class="edit">
+          <svg-icon icon-class="jianHao" />
+        </span>
+        <span class="edit">
+          <svg-icon icon-class="addHao" />
+        </span>
+        <span class="edit">
+          <svg-icon icon-class="homeIcon2" />
+        </span>
       </div>
     </div>
 
@@ -85,9 +94,7 @@ const clickTestProjectItem = (item) => {
         <div
           class="project-list-item"
           :class="[
-            item.id === currentSelectedTestProject?.id
-              ? 'selected-item'
-              : 'normal-item',
+            item.id === currentTestItemId ? 'selected-item' : 'normal-item',
           ]"
           v-for="item in testProjectList"
           :key="item.id"
@@ -162,16 +169,16 @@ const clickTestProjectItem = (item) => {
       span {
         cursor: pointer;
         display: inline-block;
-        width: 18px;
-        height: 18px;
+        //width: 18px;
+        //height: 18px;
         text-align: center;
         line-height: 16px;
         border-radius: 0px 0px 0px 0px;
-        border: 2px solid #ffffff;
+        //border: 1px solid #ffffff;
         color: var(--hj-white-1);
-        &:nth-of-type(2) {
-          margin-left: 12px;
-        }
+        //&:nth-of-type(2) {
+        margin-left: 8px;
+        //}
       }
     }
   }

+ 5 - 2
src/views/modules/project-config/configs/properites.ts

@@ -1,9 +1,10 @@
 import { Node } from "@vue-flow/core";
 
 // 功能块类别
-interface FunctionTypeModel {
+export interface FunctionTypeModel {
   id: string;
-  name: string;
+  moduleName: string;
+  moduleType: string;
   functions: AutoTestNodeData[]; //指的是功能模块 不是函数
 }
 export enum ExcelTypeName {
@@ -30,6 +31,8 @@ export interface InforPropertyModel {
   maxValue?: string;
   inputOrOutput?: "input" | "output";
   bindValue?: string; //这个是el-form 会绑定的值
+  bindCode?: string; //  //编号
+  bindLabel?: string; //这个是el-mention 会绑定的值 然后将id给 bindCode
 }
 
 interface HJNodeData2 {

+ 110 - 7
src/views/modules/project-config/project-config.vue

@@ -12,6 +12,15 @@ import FunctionModule from "./com/function-col.vue";
 import TitleHeader from "@/views/modules/project-config/com/titleHeader.vue";
 import { AutoTestNodeData, InforPropertyModel } from "./configs/properites";
 import type { FormInstance } from "element-plus";
+import {
+  getProjectGlobalConfig,
+  getTestProjectInfo,
+  updateTestModule,
+} from "@/api/project";
+
+import { useCommonStoreHook } from "@/store";
+
+const { currentTestItemId, currentProjectId } = toRefs(useCommonStoreHook());
 
 const flowRef = ref<HJFlowInstance>();
 const nodes = ref<HJNodeData[]>([]);
@@ -23,7 +32,35 @@ const onNodeOperation = (name: HJMethodName, node: HJNodeData): void => {
     selectedNode.value = JSON.parse(JSON.stringify(node));
     infoVisible.value = true;
   } else if (name === HJMethodName.SaveTemplate) {
-    console.log("保存模版数据");
+    //   如果没有选测试项目 给提示
+    if (!currentTestItemId.value) {
+      ElMessage.warning("请选择测试项目");
+      return;
+    }
+
+    if (nodes.value.length === 0) {
+      ElMessage.warning("请编辑功能");
+      return;
+    }
+
+    if (selectedNode.value) {
+      ElMessage.warning("请先保存节点信息");
+      return;
+    }
+
+    //   保存模版数据
+    let flowData = {
+      nodes: nodes.value,
+      edges: edges.value,
+    };
+    let p = {
+      id: currentTestItemId.value,
+      routeData: JSON.stringify(flowData),
+    };
+    updateTestModule(p).then(() => {
+      ElMessage.success("保存模版成功");
+      flowRef.value && flowRef.value.clearStatus();
+    });
   }
 };
 
@@ -33,6 +70,9 @@ const infoVisible = ref(false);
 const selectedNode = ref<AutoTestNodeData | null>(null); //双击的节点数据
 const onSaveConfigs = () => {
   console.log("onSaveConfigs", selectedNode.value);
+  if (!selectedNode.value) {
+    return;
+  }
   flowRef.value &&
     flowRef.value.updateNodeData(
       JSON.parse(JSON.stringify(selectedNode.value))
@@ -41,15 +81,50 @@ const onSaveConfigs = () => {
   selectedNode.value = null;
 };
 
-onMounted(() => {
-  // 接口调用完成要初始化 ,为的是保存一个最初的数据
-  flowRef.value && flowRef.value.initFlow([], []);
+onMounted(async () => {
+  //   如果选择的测试项目id有值,就获取数据
+  if (currentTestItemId.value) {
+    getFlowData();
+  }
+
+  let res = await getProjectGlobalConfig(currentProjectId.value);
+  configData.value = res.data;
 });
+
+const getFlowData = () => {
+  nodes.value = [];
+  edges.value = [];
+  getTestProjectInfo(currentTestItemId.value).then((result) => {
+    if (result.data.routeData) {
+      let data = JSON.parse(result.data.routeData);
+      nodes.value = data.nodes;
+      edges.value = data.edges;
+      // 接口调用完成要初始化 ,为的是保存一个最初的数据
+      flowRef.value && flowRef.value.initFlow([], []);
+    }
+  });
+};
+
+//选择测试项目相关  每次点击需要重新获取中间的流程的数据
+const onSelectTestPro = () => {
+  flowRef.value && flowRef.value.clearStatus();
+  selectedNode.value = null;
+  infoVisible.value = false;
+  getFlowData();
+};
+
+// 全局变量和仪器列表选择相关
+const configData: Record<string, any[]> = ref({});
+const configOptions = ref([]);
+
+const handleSearch = (_: string, prefix: string) => {
+  configOptions.value = configData.value[prefix] || [];
+};
 </script>
 
 <template>
   <div class="project-config-container">
-    <ProjectMessage />
+    <ProjectMessage @onClickItem="onSelectTestPro" />
     <FunctionModule />
     <HJFlow
       class="hjflow-box"
@@ -64,17 +139,40 @@ onMounted(() => {
       <TitleHeader>属性配置</TitleHeader>
       <div class="form-box" v-if="infoVisible">
         <el-form rer="formRef" label-position="top">
-          <el-form-item label="节点名称">
+          <el-form-item label="节点标识名称">
             <el-input
               v-model="selectedNode!.data.information.nodeName"
             ></el-input>
           </el-form-item>
+          <el-form-item>
+            <el-text class="mx-1" type="warning">
+              输入@选择全局变量或#选择仪器
+            </el-text>
+          </el-form-item>
           <el-form-item
             v-for="property in selectedNode?.data?.information?.properties"
             :label="property.proName"
             :key="property.proName"
           >
-            <el-input v-model="property.bindValue"></el-input>
+            <el-mention
+              v-model="property.bindLabel"
+              :options="configOptions"
+              :prefix="['@', '#']"
+              whole
+              @search="handleSearch"
+              @select="
+                (opt) => {
+                  property.bindCode = opt.code;
+                }
+              "
+              @blur="
+                () => {
+                  if (property.bindLabel === '') {
+                    property.bindCode = '';
+                  }
+                }
+              "
+            />
           </el-form-item>
         </el-form>
       </div>
@@ -94,6 +192,7 @@ onMounted(() => {
   width: 100%;
   height: calc(100vh - $main-header-height);
 }
+
 .hjflow-box {
   //width: 100%;
   flex: 1;
@@ -143,4 +242,8 @@ onMounted(() => {
   line-height: 16px;
   text-align: left;
 }
+
+:deep(.el-collapse-item__wrap) {
+  border: 0;
+}
 </style>