Browse Source

bug修改。

jxq 3 weeks ago
parent
commit
d37240b331

+ 156 - 0
src/api/system/dict/index.ts

@@ -0,0 +1,156 @@
+import request from "@/utils/request";
+import { AxiosPromise } from "axios";
+import {
+  DictTypeQuery,
+  DictTypePageResult,
+  DictTypeForm,
+  DictQuery,
+  DictForm,
+  DictPageResult,
+} from "./types";
+
+/**
+ * 字典类型分页列表
+ *
+ * @param queryParams
+ */
+export function getDictTypePage(queryParams: object): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/sys/dictType/page",
+    method: "post",
+    data: queryParams,
+  });
+}
+
+/**
+ * 字典类型表单数据
+ *
+ * @param id
+ */
+export function getDictTypeForm(id: number): AxiosPromise<DictTypeForm> {
+  return request({
+    url: "/api/v1/dict/types/" + id + "/form",
+    method: "get",
+  });
+}
+
+/**
+ * 新增字典类型
+ *
+ * @param data
+ */
+export function addDictType(data: DictTypeForm) {
+  return request({
+    url: "/api/v1/sys/dictType/add",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 修改字典类型
+ *
+ * @param id
+ * @param data
+ */
+export function updateDictType(data: DictTypeForm) {
+  return request({
+    url: "/api/v1/sys/dictType/update",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 删除字典类型
+ */
+export function deleteDictTypes(id: string) {
+  return request({
+    url: "/api/v1/sys/dictType/del",
+    method: "post",
+    data: { id: id },
+  });
+}
+
+/**
+ * 获取字典类型的数据项
+ *
+ * @param typeCode 字典类型编码
+ */
+export function getDictOptions(typeCode: string): AxiosPromise<OptionType[]> {
+  return request({
+    url: "/api/v1/dict/" + typeCode + "/options",
+    method: "get",
+  });
+}
+
+/**
+ * 字典分页列表
+ */
+export function getDictPage(queryParams: object): AxiosPromise<any> {
+  return request({
+    url: "/api/v1/sys/dictData/page",
+    method: "post",
+    data: queryParams,
+  });
+}
+
+/**
+ * 获取字典表单数据
+ *
+ * @param id
+ */
+export function getDictFormData(id: number): AxiosPromise<DictForm> {
+  return request({
+    url: "/api/v1/dict/" + id + "/form",
+    method: "get",
+  });
+}
+
+/**
+ * 新增字典
+ *
+ * @param data
+ */
+export function addDict(data: DictForm) {
+  return request({
+    url: "/api/v1/sys/dictData/add",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 修改字典项
+ *
+ * @param id
+ * @param data
+ */
+export function updateDict(data: DictForm) {
+  return request({
+    url: "/api/v1/sys/dictData/update",
+    method: "post",
+    data: data,
+  });
+}
+
+/**
+ * 删除字典
+ *
+ * @param ids 字典项ID,多个以英文逗号(,)分割
+ */
+export function deleteDict(ids: Array<string>) {
+  return request({
+    url: "/api/v1/sys/dictData/batch-del",
+    method: "post",
+    data: { ids: ids },
+  });
+}
+
+
+export function queryDictDataByType(str: string) {
+  return request({
+    url: "/api/v1/sys/dictData/queryByType/" + str,
+    method: "get",
+  });
+}

+ 144 - 0
src/api/system/dict/types.ts

@@ -0,0 +1,144 @@
+/**
+ * 字典类型查询参数
+ */
+export interface DictTypeQuery extends PageQuery {
+  /**
+   * 关键字(字典类型名称/编码)
+   */
+  keywords?: string;
+}
+
+/**
+ * 字典类型分页对象
+ */
+export interface DictTypePageVO {
+  /**
+   * 字典类型ID
+   */
+  id: number;
+  /**
+   * 类型编码
+   */
+  code: string;
+  /**
+   * 类型名称
+   */
+  name: string;
+  /**
+   * 状态(1:启用;0:禁用)
+   */
+  status?: number;
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+/**
+ * 字典分页项类型声明
+ */
+export type DictTypePageResult = PageResult<DictTypePageVO[]>;
+
+/**
+ * 字典表单类型声明
+ */
+export interface DictTypeForm {
+  /**
+   * 字典类型ID
+   */
+  id?: number;
+  /**
+   * 类型名称
+   */
+  dictName?: string;
+  /**
+   * 类型编码
+   */
+  dictType?: string;
+  /**
+   * 类型状态:0-禁用;1-启用
+   */
+  state: number;
+  /**
+   * 备注
+   */
+  remark?: string;
+  // 字典类别 0 用户字典 1 系统字典
+  type?: string;
+}
+
+/**
+ * 字典查询参数
+ */
+export interface DictQuery extends PageQuery {
+  /**
+   * 字典项名称
+   */
+  name?: string;
+  /**
+   * 字典类型编码
+   */
+  typeCode?: string;
+}
+
+/**
+ * 字典分页对象
+ */
+export interface DictPageVO {
+  /**
+   * 字典ID
+   */
+  id?: number;
+  /**
+   * 字典名称
+   */
+  name?: string;
+  /**
+   * 状态(1:启用;0:禁用)
+   */
+  status?: number;
+  /**
+   * 字典值
+   */
+  value?: string;
+}
+
+/**
+ * 字典分页
+ */
+export type DictPageResult = PageResult<DictPageVO[]>;
+
+/**
+ * 字典表单
+ */
+export interface DictForm {
+  /**
+   * 字典ID
+   */
+  id?: number;
+  /**
+   * 字典名称
+   */
+  dictLabel?: string;
+  /**
+   * 排序
+   */
+  dictSort?: number;
+  /**
+   * 状态(1:启用;0:禁用)
+   */
+  state?: number;
+  /**
+   * 类型编码
+   */
+  dictCode?: string;
+  /**
+   * 值
+   */
+  dictValue?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}

+ 7 - 1
src/router/index.ts

@@ -26,6 +26,7 @@ export const constantRoutes: RouteRecordRaw[] = [
     component: () => import("@/views/main/main.vue"),
     component: () => import("@/views/main/main.vue"),
     meta: { hidden: true },
     meta: { hidden: true },
     redirect: "/main/home",
     redirect: "/main/home",
+    name: "MainPage",
     children: [
     children: [
       {
       {
         path: "home",
         path: "home",
@@ -33,7 +34,7 @@ export const constantRoutes: RouteRecordRaw[] = [
       },
       },
       {
       {
         path: "run-test/:engineerId",
         path: "run-test/:engineerId",
-        name: "RunTestPage",
+        name: "RunTesting",
         component: () => import("@/views/modules/runTest/run-test.vue"),
         component: () => import("@/views/modules/runTest/run-test.vue"),
       },
       },
       {
       {
@@ -72,6 +73,11 @@ export const constantRoutes: RouteRecordRaw[] = [
     meta: { hidden: true },
     meta: { hidden: true },
   },
   },
   {
   {
+    path: "/dictionary",
+    component: () => import("@/views/modules/dictionary/index.vue"),
+    meta: { hidden: true },
+  },
+  {
     path: "/detp-management",
     path: "/detp-management",
     component: () =>
     component: () =>
       import("@/views/modules/person-manager/com/dept-manage.vue"),
       import("@/views/modules/person-manager/com/dept-manage.vue"),

+ 5 - 0
src/views/main/components/header.vue

@@ -18,6 +18,7 @@
     >
     >
       <div class="loginOut" @click="deviceResourceFun">仪器资源</div>
       <div class="loginOut" @click="deviceResourceFun">仪器资源</div>
       <div class="loginOut" @click="goToManange">部门管理</div>
       <div class="loginOut" @click="goToManange">部门管理</div>
+      <div class="loginOut" @click="gotoDictPage">字典管理</div>
       <div class="loginOut" @click="userCenter">修改密码</div>
       <div class="loginOut" @click="userCenter">修改密码</div>
       <div class="loginOut" @click="loginOutFun">退出登录</div>
       <div class="loginOut" @click="loginOutFun">退出登录</div>
     </el-popover>
     </el-popover>
@@ -53,6 +54,10 @@ const userCenterRef = ref();
 const userCenter = () => {
 const userCenter = () => {
   userCenterRef.value && userCenterRef.value?.show();
   userCenterRef.value && userCenterRef.value?.show();
 };
 };
+
+const gotoDictPage = () => {
+  router.push("/dictionary");
+};
 </script>
 </script>
 
 
 <style scoped lang="scss">
 <style scoped lang="scss">

+ 4 - 0
src/views/main/main.vue

@@ -2,6 +2,10 @@
 import Menu from "./components/menu.vue";
 import Menu from "./components/menu.vue";
 import Layout from "./components/layout.vue";
 import Layout from "./components/layout.vue";
 import Header from "./components/header.vue";
 import Header from "./components/header.vue";
+
+defineOptions({
+  name: "MainPage",
+});
 </script>
 </script>
 
 
 <template>
 <template>

+ 337 - 0
src/views/modules/dictionary/components/dict-item.vue

@@ -0,0 +1,337 @@
+<!-- 字典数据 -->
+<script setup lang="ts">
+import {
+  getDictPage,
+  getDictFormData,
+  addDict,
+  updateDict,
+  deleteDict,
+} from "@/api/system/dict";
+import { DictPageVO, DictForm, DictQuery } from "@/api/system/dict/types";
+import ButtonPermKeys from "@/common/configs/buttonPermission";
+
+defineOptions({
+  name: "DictData",
+  inheritAttrs: false,
+});
+
+const props = defineProps({
+  typeCode: {
+    type: String,
+    default: () => {
+      return "";
+    },
+  },
+  typeName: {
+    type: String,
+    default: () => {
+      return "";
+    },
+  },
+});
+
+watch?.(
+  () => props.typeCode,
+  (newVal: string) => {
+    queryParams.dictCode = newVal;
+    formData.dictCode = newVal;
+    resetQuery();
+  }
+);
+
+const queryFormRef = ref(ElForm);
+const dataFormRef = ref(ElForm);
+
+const loading = ref(false);
+const ids = ref<string[]>([]);
+const total = ref(0);
+
+const queryParams = reactive<any>({
+  pageNo: 1,
+  pageSize: 10,
+  dictCode: props.typeCode,
+});
+
+const dictList = ref<DictPageVO[]>();
+
+const dialog = reactive({
+  title: "",
+  visible: false,
+});
+
+const formData = reactive<any>({
+  state: 0,
+  dictCode: props.typeCode,
+  dictSort: 1,
+});
+
+const rules = reactive({
+  name: [{ required: true, message: "请输入字典名称", trigger: "blur" }],
+  value: [{ required: true, message: "请输入字典值", trigger: "blur" }],
+});
+
+/**
+ * 查询
+ */
+function handleQuery() {
+  if (queryParams.dictCode) {
+    loading.value = true;
+    getDictPage(queryParams)
+      .then(({ data }) => {
+        dictList.value = data.records;
+        total.value = data.totalCount;
+      })
+      .finally(() => (loading.value = false));
+  }
+}
+
+/**
+ * 重置查询
+ */
+function resetQuery() {
+  queryParams.pageNo = 1;
+  handleQuery();
+}
+
+/**
+ * 行checkbox change事件
+ *
+ * @param selection
+ */
+function handleSelectionChange(selection: any) {
+  ids.value = selection.map((item: any) => item.id);
+}
+
+/**
+ * 打开字典表单弹窗
+ *
+ * @param dictId 字典ID
+ */
+function openDialog(form?: any) {
+  dialog.visible = true;
+  if (form) {
+    dialog.title = "修改字典";
+    Object.assign(formData, form);
+  } else {
+    dialog.title = "新增字典";
+    dataFormRef.value.label = "";
+    dataFormRef.value = "";
+    formData.dictLabel = "";
+    formData.dictValue = "";
+  }
+}
+
+/**
+ * 字典表单提交
+ */
+function handleSubmit() {
+  dataFormRef.value.validate((isValid: boolean) => {
+    if (isValid) {
+      const dictId = formData.id;
+      if (dictId) {
+        updateDict(formData)
+          .then(() => {
+            ElMessage.success("修改成功");
+            closeDialog();
+            resetQuery();
+          })
+          .finally(() => (loading.value = false));
+      } else {
+        addDict(formData)
+          .then(() => {
+            ElMessage.success("新增成功");
+            closeDialog();
+            resetQuery();
+          })
+          .finally(() => (loading.value = false));
+      }
+    }
+  });
+}
+
+/**
+ * 关闭弹窗
+ */
+function closeDialog() {
+  dialog.visible = false;
+  resetForm();
+}
+
+/**
+ * 重置表单
+ */
+function resetForm() {
+  dataFormRef.value.resetFields();
+  dataFormRef.value.clearValidate();
+
+  formData.id = undefined;
+  formData.state = 0;
+  formData.dictSort = 1;
+  formData.dictCode = props.typeCode;
+}
+
+/**
+ * 删除字典
+ */
+function handleDelete(dictId?: string) {
+  if (dictId) {
+    ids.value.push(dictId);
+  }
+  if (!ids.value) {
+    ElMessage.warning("请勾选删除项");
+    return;
+  }
+
+  ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+    deleteDict(ids.value).then(() => {
+      ElMessage.success("删除成功");
+      resetQuery();
+    });
+  });
+}
+
+onMounted?.(() => {
+  handleQuery();
+});
+</script>
+
+<template>
+  <div class="app-container">
+    <!--    <div class="search-container">
+      &lt;!&ndash; 搜索表单 &ndash;&gt;
+      <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+        <el-form-item label="关键字" prop="name">
+          <el-input
+            v-model="queryParams.name"
+            placeholder="字典名称"
+            clearable
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleQuery"
+            ><i-ep-search />搜索</el-button
+          >
+          <el-button @click="resetQuery"> <i-ep-refresh />重置</el-button>
+        </el-form-item>
+      </el-form>
+    </div>-->
+    <el-card shadow="never">
+      <template #header>
+        <el-button type="primary" @click="openDialog()"
+          ><i-ep-plus />新增</el-button
+        >
+        <!--        <el-button
+          v-hasPerm="[ButtonPermKeys.SYSTEM.BTNS.dict_del]"
+          type="danger"
+          :disabled="ids.length === 0"
+          @click="handleDelete()"
+          ><i-ep-delete />删除</el-button
+        >-->
+      </template>
+
+      <!-- 数据表格 -->
+      <el-table
+        v-loading="loading"
+        :data="dictList"
+        border
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="50" />
+        <el-table-column label="字典名称" prop="dictLabel" />
+        <el-table-column label="字典值" prop="dictValue" />
+        <el-table-column label="排序" prop="dictSort" />
+        <el-table-column label="状态" align="center">
+          <template #default="scope">
+            <el-tag v-if="scope.row.state === 0" type="success">启用</el-tag>
+            <el-tag v-else type="info">禁用</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column fixed="right" label="操作" align="center">
+          <template #default="scope">
+            <el-button
+              v-hasPerm="[ButtonPermKeys.SYSTEM.BTNS.dict_edit]"
+              type="primary"
+              link
+              @click="openDialog(scope.row)"
+              ><i-ep-edit />编辑</el-button
+            >
+            <!--            <el-button
+              v-hasPerm="[ButtonPermKeys.SYSTEM.BTNS.dict_del]"
+              type="primary"
+              link
+              @click.stop="handleDelete(scope.row.id)"
+              ><i-ep-delete />删除</el-button
+            >-->
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-if="total > 0"
+        v-model:total="total"
+        v-model:page="queryParams.pageNo"
+        v-model:limit="queryParams.pageSize"
+        @pagination="handleQuery"
+      />
+    </el-card>
+
+    <!-- 表单弹窗 -->
+    <el-dialog
+      v-model="dialog.visible"
+      :title="dialog.title"
+      width="500px"
+      @close="closeDialog"
+    >
+      <el-form
+        ref="dataFormRef"
+        :model="formData"
+        :rules="rules"
+        label-width="100px"
+      >
+        <el-form-item label="字典名称" prop="dictLabel">
+          <el-input v-model="formData.dictLabel" placeholder="请输入字典名称" />
+        </el-form-item>
+        <el-form-item label="字典值" prop="dictValue">
+          <el-input
+            v-if="formData.id"
+            disabled
+            v-model="formData.dictValue"
+            placeholder="字典值"
+          />
+          <el-input
+            v-if="!formData.id"
+            v-model="formData.dictValue"
+            placeholder="字典值"
+          />
+        </el-form-item>
+
+        <el-form-item label="排序" prop="dictSort">
+          <el-input-number
+            v-model="formData.dictSort"
+            controls-position="right"
+            :min="0"
+          />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="formData.state">
+            <el-radio :value="0">正常</el-radio>
+            <el-radio :value="1">停用</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="formData.remark" type="textarea" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="handleSubmit">确 定</el-button>
+          <el-button @click="closeDialog">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>

+ 361 - 0
src/views/modules/dictionary/index.vue

@@ -0,0 +1,361 @@
+<!--字典类型-->
+<script setup lang="ts">
+import SecondHeader from "@/views/modules/conmon/SecondHeader.vue";
+import DictItem from "./components/dict-item.vue";
+import {
+  getDictTypePage,
+  getDictTypeForm,
+  addDictType,
+  updateDictType,
+  deleteDictTypes,
+} from "@/api/system/dict";
+
+import {
+  DictTypePageVO,
+  DictTypeQuery,
+  DictTypeForm,
+} from "@/api/system/dict/types";
+import ButtonPermKeys from "@/common/configs/buttonPermission";
+
+defineOptions({
+  name: "DictType",
+  inheritAttrs: false,
+});
+
+const queryFormRef = ref(ElForm);
+const dataFormRef = ref(ElForm);
+
+const loading = ref(false);
+const ids = ref<number[]>([]);
+const total = ref(0);
+
+const queryParams = reactive<DictTypeQuery>({
+  pageNo: 1,
+  pageSize: 10,
+});
+
+const dictTypeList = ref<DictTypePageVO[]>();
+
+const dialog = reactive({
+  title: "",
+  visible: false,
+});
+
+const formData = reactive<DictTypeForm>({
+  state: 1,
+  type: "0",
+});
+
+const rules = reactive({
+  dictName: [
+    { required: true, message: "请输入字典类型名称", trigger: "blur" },
+  ],
+  dictType: [
+    { required: true, message: "请输入字典类型编码", trigger: "blur" },
+  ],
+});
+
+/** 查询 */
+function handleQuery() {
+  loading.value = true;
+  getDictTypePage(queryParams)
+    .then(({ data }) => {
+      dictTypeList.value = data.records;
+      total.value = data.totalCount;
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+}
+
+/**
+ * 重置查询
+ */
+function resetQuery() {
+  queryFormRef.value.resetFields();
+  queryParams.pageNo = 1;
+  handleQuery();
+}
+
+/** 行复选框选中  */
+function handleSelectionChange(selection: any) {
+  ids.value = selection.map((item: any) => item.id);
+}
+
+/**
+ * 打开字典类型表单弹窗
+ *
+ * @param dicTypeId 字典类型ID
+ */
+function openDialog(row?: any) {
+  dialog.visible = true;
+  console.log(row);
+  if (row) {
+    dialog.title = "修改字典类型";
+    Object.assign(formData, row);
+  } else {
+    formData.id = null;
+    formData.dictName = "";
+    formData.dictType = "";
+    formData.remark = "";
+    dialog.title = "新增字典类型";
+  }
+}
+
+/** 字典类型表单提交 */
+function handleSubmit() {
+  dataFormRef.value.validate((isValid: boolean) => {
+    if (isValid) {
+      const dictTypeId = formData.id;
+      if (dictTypeId) {
+        updateDictType(formData)
+          .then(() => {
+            ElMessage.success("修改成功");
+            closeDialog();
+            handleQuery();
+          })
+          .finally(() => (loading.value = false));
+      } else {
+        addDictType(formData)
+          .then(() => {
+            ElMessage.success("新增成功");
+            closeDialog();
+            handleQuery();
+          })
+          .finally(() => (loading.value = false));
+      }
+    }
+  });
+}
+
+/** 关闭字典类型弹窗 */
+function closeDialog() {
+  dialog.visible = false;
+  resetForm();
+}
+
+/**  重置字典类型表单 */
+function resetForm() {
+  dataFormRef.value.resetFields();
+  dataFormRef.value.clearValidate();
+
+  formData.id = undefined;
+  formData.state = 1;
+}
+
+/** 删除字典类型 */
+function handleDelete(dictTypeId?: number) {
+  const dictTypeIds = [dictTypeId || ids.value].join(",");
+  if (!dictTypeIds) {
+    ElMessage.warning("请勾选删除项");
+    return;
+  }
+
+  ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+    deleteDictTypes(dictTypeIds).then(() => {
+      ElMessage.success("删除成功");
+      resetQuery();
+    });
+  });
+}
+
+const dictDataDialog = reactive({
+  title: "",
+  visible: false,
+});
+
+const selectedDictType = reactive({ typeCode: "", typeName: "" }); // 当前选中的字典类型
+
+/** 打开字典数据弹窗 */
+function openDictDialog(row: DictTypeForm) {
+  dictDataDialog.visible = true;
+  dictDataDialog.title = "【" + row.dictName + "】字典数据";
+
+  selectedDictType.typeCode = row.dictType + "";
+  selectedDictType.typeName = row.dictName + "";
+}
+
+/**  关闭字典数据弹窗 */
+function closeDictDialog() {
+  dictDataDialog.visible = false;
+}
+
+onMounted?.(() => {
+  handleQuery();
+});
+</script>
+
+<template>
+  <div class="app-container">
+    <SecondHeader>仪器资源配置</SecondHeader>
+    <div class="search-container">
+      <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+        <el-form-item label="关键字" prop="name">
+          <el-input
+            v-model="queryParams.keywords"
+            placeholder="字典类型名称/编码"
+            clearable
+            style="width: 200px"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleQuery()"
+            ><i-ep-search />搜索</el-button
+          >
+          <el-button @click="resetQuery()"><i-ep-refresh />重置</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+
+    <el-card shadow="never" class="table-container">
+      <template #header>
+        <el-button
+          v-hasPerm="[ButtonPermKeys.SYSTEM.BTNS.dictType_add]"
+          type="primary"
+          @click="openDialog()"
+          ><i-ep-plus />新增</el-button
+        >
+        <!-- <el-button
+          type="danger"
+          :disabled="ids.length === 0"
+          @click="handleDelete()"
+          ><i-ep-delete />删除</el-button
+        > -->
+      </template>
+      <el-table
+        v-loading="loading"
+        highlight-current-row
+        :data="dictTypeList"
+        border
+        @selection-change="handleSelectionChange"
+      >
+        <!-- <el-table-column type="selection" width="55" align="center" /> -->
+        <el-table-column label="字典类型名称" prop="dictName" />
+        <el-table-column label="字典类型编码" prop="dictType" />
+        <el-table-column label="状态" align="center" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.state === 1" type="success">启用</el-tag>
+            <el-tag v-else type="info">禁用</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="备注" prop="remark" align="center" />
+        <el-table-column fixed="right" label="操作" align="center" width="220">
+          <template #default="scope">
+            <el-button
+              type="primary"
+              link
+              size="small"
+              @click.stop="openDictDialog(scope.row)"
+              ><i-ep-Collection />字典数据</el-button
+            >
+            <el-button
+              v-hasPerm="[ButtonPermKeys.SYSTEM.BTNS.dictType_edit]"
+              type="primary"
+              link
+              size="small"
+              @click.stop="openDialog(scope.row)"
+              ><i-ep-edit />编辑</el-button
+            >
+            <!--            <el-button
+              v-hasPerm="[ButtonPermKeys.SYSTEM.BTNS.dictType_del]"
+              type="primary"
+              link
+              size="small"
+              @click.stop="handleDelete(scope.row.id)"
+              ><i-ep-delete />删除</el-button
+            >-->
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+        v-if="total > 0"
+        v-model:total="total"
+        v-model:page="queryParams.pageNo"
+        v-model:limit="queryParams.pageSize"
+        @pagination="handleQuery"
+      />
+    </el-card>
+
+    <el-dialog
+      v-model="dialog.visible"
+      :title="dialog.title"
+      width="500px"
+      @close="closeDialog"
+    >
+      <el-form
+        ref="dataFormRef"
+        :model="formData"
+        :rules="rules"
+        label-width="80px"
+      >
+        <el-form-item label="字典名称" prop="dictName">
+          <el-input v-model="formData.dictName" placeholder="请输入字典名称" />
+        </el-form-item>
+        <el-form-item label="字典编码" prop="dictType">
+          <el-input
+            v-model="formData.dictType"
+            v-if="formData.id"
+            placeholder="请输入字典编码 sys_test user_test"
+          />
+          <el-input
+            v-model="formData.dictType"
+            v-if="!formData.id"
+            placeholder="请输入字典编码 sys_test user_test"
+          />
+        </el-form-item>
+        <el-form-item label="状态" prop="state">
+          <el-radio-group v-model="formData.state">
+            <el-radio :value="1">正常</el-radio>
+            <el-radio :value="0">停用</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <!--        <el-form-item label="字典类别" prop="type">
+          <el-radio-group v-model="formData.type">
+            <el-radio value="0">用户字典</el-radio>
+            <el-radio value="1">系统字典</el-radio>
+          </el-radio-group>
+        </el-form-item>-->
+        <el-form-item label="备注" prop="remark">
+          <el-input
+            v-model="formData.remark"
+            type="textarea"
+            placeholder="字典类型备注"
+            :autosize="{ minRows: 2, maxRows: 4 }"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="handleSubmit">确 定</el-button>
+          <el-button @click="closeDialog">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!--字典数据弹窗-->
+    <el-dialog
+      v-model="dictDataDialog.visible"
+      :title="dictDataDialog.title"
+      width="1000px"
+      @close="closeDictDialog"
+    >
+      <dict-item
+        v-model:typeCode="selectedDictType.typeCode"
+        v-model:typeName="selectedDictType.typeName"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.app-container {
+  width: 100%;
+  height: 100vh;
+}
+</style>

+ 136 - 0
src/views/modules/global-config/components/GlobalInstrument.vue

@@ -0,0 +1,136 @@
+<script setup lang="ts">
+import ResourceForm from "./resourceForm.vue";
+import ResourceDetail from "./resourceDetail.vue";
+import { delInstrumentResource, selectInstrumentResource } from "@/api/config";
+import { ref } from "vue";
+import type { TabsPaneContext } from "element-plus";
+
+const resourceList = ref<any[]>([]);
+
+const props = defineProps({
+  property: {
+    type: String,
+    default: "1",
+  },
+});
+
+onMounted?.(() => {
+  getList();
+});
+
+const getList = () => {
+  selectInstrumentResource({ instrumentProperty: props.property }).then(
+    (data) => {
+      resourceList.value = data.data;
+    }
+  );
+};
+
+const configHandleDelete = async (index: number, row: any) => {
+  await delInstrumentResource(row.id);
+  resourceList.value.splice(index, 1);
+};
+
+const configHandleEdit = async (index: number, row: any) => {
+  resourceRef.value && resourceRef.value.openDialog("2", row, props.property);
+};
+
+const addConfigFun = () => {
+  resourceRef.value && resourceRef.value.openDialog("1", {}, props.property);
+};
+
+const resourceRef = ref();
+const detailRef = ref();
+
+const showDetail = (row: any) => {
+  detailRef.value && detailRef.value.openDialog(row);
+};
+</script>
+
+<template>
+  <div>
+    <div class="btns">
+      <el-button type="primary" @click="addConfigFun">
+        <span class="add">+</span>
+        新增
+      </el-button>
+    </div>
+    <el-table :data="resourceList" show-overflow-tooltip>
+      <el-table-column label="序号" type="index" width="80" />
+
+      <el-table-column label="波特率" prop="baudRate"> </el-table-column>
+      <el-table-column label="通道号" prop="channel"> </el-table-column>
+      <el-table-column label="校验位" prop="checkBit"> </el-table-column>
+      <el-table-column label="通信配置" prop="commConfig" width="200">
+      </el-table-column>
+      <el-table-column label="连接url" prop="connUrl"> </el-table-column>
+      <el-table-column label="数据位" prop="dataBit"> </el-table-column>
+      <el-table-column label="配置型号" prop="instrumentModule">
+      </el-table-column>
+      <el-table-column label="仪器名称" prop="instrumentName">
+      </el-table-column>
+      <!--      <el-table-column label="仪器属性" prop="instrumentProperty">-->
+      <!--        <el-input v-model="formData.instrumentProperty" />-->
+      <!--      </el-table-column>-->
+      <el-table-column label="设备地址" prop="ip"> </el-table-column>
+      <el-table-column label="设备端口" prop="port"> </el-table-column>
+      <el-table-column label="读url" prop="queryUrl"> </el-table-column>
+      <el-table-column label="槽位号" prop="slot"> </el-table-column>
+      <el-table-column label="停止位" prop="stopBit"> </el-table-column>
+      <el-table-column label="写url" prop="writeUrl"> </el-table-column>
+
+      <el-table-column label="通信类型" prop="commType" />
+      <el-table-column label="仪器类型" prop="instrumentType">
+      </el-table-column>
+
+      <el-table-column label="操作" prop="操作" fixed="right" width="220">
+        <template #default="scope">
+          <el-button
+            text
+            size="small"
+            type="primary"
+            @click="configHandleDelete(scope.$index, scope.row)"
+          >
+            删除
+          </el-button>
+          <el-button
+            text
+            size="small"
+            type="primary"
+            @click="configHandleEdit(scope.$index, scope.row)"
+          >
+            修改
+          </el-button>
+          <el-button
+            text
+            size="small"
+            type="primary"
+            @click="showDetail(scope.row)"
+          >
+            查看
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <ResourceForm ref="resourceRef" @finished="getList"></ResourceForm>
+    <ResourceDetail ref="detailRef"></ResourceDetail>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.btns {
+  text-align: start;
+  margin: 12px;
+}
+.add {
+  width: 12px;
+  height: 12px;
+  line-height: 12px;
+  border-radius: 12px;
+  text-align: center;
+  background-color: #fff;
+  color: #3b7cff;
+  margin-right: 10px;
+  vertical-align: middle;
+}
+</style>

+ 5 - 3
src/views/modules/global-config/components/resourceForm.vue

@@ -21,7 +21,7 @@ const formData = ref({
   dataBit: "",
   dataBit: "",
   instrumentModule: "",
   instrumentModule: "",
   instrumentName: "",
   instrumentName: "",
-  instrumentProperty: "1",
+  instrumentProperty: "",
   instrumentType: "",
   instrumentType: "",
   ip: "",
   ip: "",
   port: "",
   port: "",
@@ -42,7 +42,7 @@ const onCancel = () => {
 
 
 // 1 新增 2 修改
 // 1 新增 2 修改
 
 
-const openDialog = (type: string, data: any) => {
+const openDialog = (type: string, data: any, instrumentType: string) => {
   formData.value.id = "";
   formData.value.id = "";
   dialogType.value = type;
   dialogType.value = type;
 
 
@@ -56,13 +56,15 @@ const openDialog = (type: string, data: any) => {
   } else {
   } else {
     formData.value = data;
     formData.value = data;
   }
   }
+
+  console.log(instrumentType);
+  formData.value.instrumentProperty = instrumentType;
 };
 };
 
 
 const saveFun = () => {
 const saveFun = () => {
   formRef.value
   formRef.value
     ?.validate()
     ?.validate()
     .then(async () => {
     .then(async () => {
-      formData.value.instrumentProperty = "1";
       if (dialogType.value === "1") {
       if (dialogType.value === "1") {
         await addInstrumentResource(formData.value);
         await addInstrumentResource(formData.value);
       } else {
       } else {

+ 25 - 112
src/views/modules/global-config/deviceResources.vue

@@ -1,111 +1,25 @@
 <script lang="ts" setup>
 <script lang="ts" setup>
 import SecondHeader from "@/views/modules/conmon/SecondHeader.vue";
 import SecondHeader from "@/views/modules/conmon/SecondHeader.vue";
-import ResourceForm from "./components/resourceForm.vue";
-import ResourceDetail from "./components/resourceDetail.vue";
-import { delInstrumentResource, selectInstrumentResource } from "@/api/config";
+import GlobalInstrument from "./components/GlobalInstrument.vue";
 
 
-const resourceList = ref<any[]>([]);
-
-onMounted?.(() => {
-  getList();
-});
-
-const getList = () => {
-  selectInstrumentResource({ instrumentProperty: "1" }).then((data) => {
-    resourceList.value = data.data;
-  });
-};
-
-const configHandleDelete = async (index: number, row: any) => {
-  await delInstrumentResource(row.id);
-  resourceList.value.splice(index, 1);
-};
-
-const configHandleEdit = async (index: number, row: any) => {
-  resourceRef.value && resourceRef.value.openDialog("2", row);
-};
-
-const addConfigFun = () => {
-  resourceRef.value && resourceRef.value.openDialog("1");
-};
-
-const resourceRef = ref();
-const detailRef = ref();
-
-const showDetail = (row: any) => {
-  detailRef.value && detailRef.value.openDialog(row);
+const activeName = ref("测试仪器");
+const handleClick = (tab: any, event: Event) => {
+  // console.log(tab, event);
 };
 };
 </script>
 </script>
 
 
 <template>
 <template>
   <div class="global-config">
   <div class="global-config">
-    <SecondHeader>仪器资源配置</SecondHeader>
-    <div class="btns">
-      <el-button type="primary" @click="addConfigFun">
-        <span class="add">+</span>
-        新增
-      </el-button>
-    </div>
-    <el-table :data="resourceList" show-overflow-tooltip>
-      <el-table-column label="序号" type="index" width="80" />
-
-      <el-table-column label="波特率" prop="baudRate"> </el-table-column>
-      <el-table-column label="通道号" prop="channel"> </el-table-column>
-      <el-table-column label="校验位" prop="checkBit"> </el-table-column>
-      <el-table-column label="通信配置" prop="commConfig" width="200">
-      </el-table-column>
-      <el-table-column label="连接url" prop="connUrl"> </el-table-column>
-      <el-table-column label="数据位" prop="dataBit"> </el-table-column>
-      <el-table-column label="配置型号" prop="instrumentModule">
-      </el-table-column>
-      <el-table-column label="仪器名称" prop="instrumentName">
-      </el-table-column>
-      <!--      <el-table-column label="仪器属性" prop="instrumentProperty">-->
-      <!--        <el-input v-model="formData.instrumentProperty" />-->
-      <!--      </el-table-column>-->
-      <el-table-column label="设备地址" prop="ip"> </el-table-column>
-      <el-table-column label="设备端口" prop="port"> </el-table-column>
-      <el-table-column label="读url" prop="queryUrl"> </el-table-column>
-      <el-table-column label="槽位号" prop="slot"> </el-table-column>
-      <el-table-column label="停止位" prop="stopBit"> </el-table-column>
-      <el-table-column label="写url" prop="writeUrl"> </el-table-column>
-
-      <el-table-column label="通信类型" prop="commType" />
-      <el-table-column label="仪器类型" prop="instrumentType">
-      </el-table-column>
-
-      <el-table-column label="操作" prop="操作" fixed="right" width="220">
-        <template #default="scope">
-          <el-button
-            text
-            size="small"
-            type="primary"
-            @click="configHandleDelete(scope.$index, scope.row)"
-          >
-            删除
-          </el-button>
-          <el-button
-            text
-            size="small"
-            type="primary"
-            @click="configHandleEdit(scope.$index, scope.row)"
-          >
-            修改
-          </el-button>
-          <el-button
-            text
-            size="small"
-            type="primary"
-            @click="showDetail(scope.row)"
-          >
-            查看
-          </el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <ResourceForm ref="resourceRef" @finished="getList"></ResourceForm>
-    <ResourceDetail ref="detailRef"></ResourceDetail>
+    <SecondHeader>仪器配置</SecondHeader>
+
+    <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+      <el-tab-pane label="测试仪器" name="测试仪器">
+        <GlobalInstrument></GlobalInstrument>
+      </el-tab-pane>
+      <el-tab-pane label="执行终端" name="执行终端">
+        <GlobalInstrument property="2"></GlobalInstrument
+      ></el-tab-pane>
+    </el-tabs>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -119,19 +33,18 @@ const showDetail = (row: any) => {
       padding: 0 20px;
       padding: 0 20px;
     }
     }
   }
   }
-  .add {
-    width: 12px;
-    height: 12px;
-    line-height: 12px;
-    border-radius: 12px;
-    text-align: center;
-    background-color: #fff;
-    color: #3b7cff;
-    margin-right: 10px;
-    vertical-align: middle;
-  }
 }
 }
-
+.add {
+  width: 12px;
+  height: 12px;
+  line-height: 12px;
+  border-radius: 12px;
+  text-align: center;
+  background-color: #fff;
+  color: #3b7cff;
+  margin-right: 10px;
+  vertical-align: middle;
+}
 .btns {
 .btns {
   text-align: start;
   text-align: start;
   margin: 12px;
   margin: 12px;

+ 23 - 3
src/views/modules/runTest/run-test.vue

@@ -17,6 +17,10 @@ import {
   stopExecuteProjects,
   stopExecuteProjects,
 } from "@/api/project/excute";
 } from "@/api/project/excute";
 
 
+defineOptions({
+  name: "RunTesting",
+});
+
 const route = useRoute();
 const route = useRoute();
 
 
 interface VersionItem {
 interface VersionItem {
@@ -155,12 +159,12 @@ const onClickGlobalConfig = () => {
 };
 };
 // 开始测试相关
 // 开始测试相关
 const isTesting = ref(false);
 const isTesting = ref(false);
+const usedTime = ref(0);
+let interval = 0;
 const currentTestingProject = ref<any>();
 const currentTestingProject = ref<any>();
 const startToRunTest = async () => {
 const startToRunTest = async () => {
   if (!checkStartEnable()) return;
   if (!checkStartEnable()) return;
 
 
-  wsClient.open();
-
   let params = {
   let params = {
     configList: testingMachines.value,
     configList: testingMachines.value,
     engineeringId: route.params.engineerId,
     engineeringId: route.params.engineerId,
@@ -171,10 +175,22 @@ const startToRunTest = async () => {
   };
   };
 
 
   let res = await startExecuteProjects(params);
   let res = await startExecuteProjects(params);
+
+  wsClient.open();
+
   currentTestingProject.value = res.data;
   currentTestingProject.value = res.data;
   isTesting.value = true;
   isTesting.value = true;
+
+  usedTime.value = 0;
+  interval = setInterval(() => {
+    usedTime.value += 1;
+  }, 1000);
 };
 };
 
 
+onUnmounted(async () => {
+  clearInterval(interval);
+});
+
 const stopTesting = async () => {
 const stopTesting = async () => {
   let res = await stopExecuteProjects(currentTestingProject.value?.id);
   let res = await stopExecuteProjects(currentTestingProject.value?.id);
   isTesting.value = false;
   isTesting.value = false;
@@ -580,7 +596,7 @@ const cancelMsgType5 = () => {
         <!--        <el-button type="primary" @click="handleWSMessage"-->
         <!--        <el-button type="primary" @click="handleWSMessage"-->
         <!--          >测试假数据</el-button-->
         <!--          >测试假数据</el-button-->
         <!--        >-->
         <!--        >-->
-        <div>已用时:300s</div>
+        <div class="used-time" v-if="isTesting">已用时:{{ usedTime }}s</div>
         <!--        <div class="test-btn progress" @click="startToRunTest">-->
         <!--        <div class="test-btn progress" @click="startToRunTest">-->
         <!--          <svg-icon icon-class="start-test" />-->
         <!--          <svg-icon icon-class="start-test" />-->
         <!--          开始测试-->
         <!--          开始测试-->
@@ -1014,6 +1030,10 @@ $color-progress: #3cbaff;
   }
   }
 }
 }
 
 
+.used-time {
+  margin-right: 20px;
+}
+
 .content-B-height-2 {
 .content-B-height-2 {
   height: calc(100vh - $main-header-height - 300px - 64px - 228px);
   height: calc(100vh - $main-header-height - 300px - 64px - 228px);
 }
 }