1、增加 vuex 路由标签切换 ,并且保留页面数据
2、PlcParameter.java Plcaction.java 增加读写分开 , 睡眠间隔时间不同
3、增加权限列表中英文json 以及提示框、弹窗等
15个文件已修改
2个文件已添加
1042 ■■■■■ 已修改文件
CanadaMes-ui/run.bat 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/lang/locales/en-US.json 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/lang/locales/zh-CN.json 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/layout/index.vue 265 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/layout/tag.vue 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/store/index.js 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/store/module/tags.js 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/views/Electrical/Action.vue 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/views/Electrical/Parameter.vue 91 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/views/power/index.vue 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/views/role/index.vue 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/src/views/user/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot-vue3/src/main/java/com/example/springboot/AuthorityApplication.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot-vue3/src/main/java/com/example/springboot/component/PlcHold.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot-vue3/src/main/java/com/example/springboot/component/PlcParameter.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot-vue3/src/main/java/com/example/springboot/component/Plcaction.java 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
springboot-vue3/src/main/java/com/example/springboot/config/AppRunnerConfig.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CanadaMes-ui/run.bat
New file
@@ -0,0 +1,5 @@
@echo off
echo Starting frontend development server...
cd /d %~dp0  // 切换到当前批处理脚本所在的目录
cd ..\CanadaMes-ui  // 假设CanadaMes-ui在与批处理脚本相同的目录下
npm run serve
CanadaMes-ui/src/lang/locales/en-US.json
@@ -69,5 +69,57 @@
    "paginationPrev": "Previous",
    "paginationPager": "{currentPage}/{pageCount}",
    "paginationNext": "Next",
    "paginationJumper": "Jump to"
    "paginationJumper": "Jump to",
    "breadcrumb": {
      "home": "Home",
      "permissionManagement": "Permission Management",
      "permissionList": "Permission List"
    },
    "search": {
      "placeholder": "Enter keywords"
    },
    "button": {
      "addPermission": "Add Permission",
      "cancel": "Cancel",
      "confirm": "Confirm"
    },
    "table": {
      "role": "Role",
      "permissionDescription": "Permission Description",
      "permissionValue": "Permission Value",
      "createTime": "Create Time",
      "isActive": "Is Active",
      "operation": "Operation"
    },
    "tooltip": {
      "edit": "Edit",
      "delete": "Delete"
    },
    "dialog": {
      "addPermission": "Add Permission",
      "editPermission": "Edit Permission"
    },
    "form": {
      "role": "Role",
      "select": "Please Select",
      "permission": "Permission",
      "isActive": "Is Active"
    },
    "操作": "Operation",
    "有效": "Valid",
    "无效": "Invalid",
    "请输入名称": "Please enter a name",
    "长度在 2 到 15 个字符": "Length between 2 and 15 characters",
    "请输入状态": "Please enter the status",
    "添加角色": "Add Role",
    "修改角色": "Edit Role",
    "删除角色": "Delete Role",
    "此操作将永久删除该角色, 是否继续?": "This operation will permanently delete the role. Continue?",
    "提示": "Reminder",
    "确定": "Confirm",
    "取消": "Cancel",
    "添加角色成功": "Successfully added role",
    "更新状态成功": "Successfully updated status",
    "修改角色成功": "Successfully modified role",
    "删除角色成功": "Successfully deleted role"
  }
CanadaMes-ui/src/lang/locales/zh-CN.json
@@ -72,6 +72,58 @@
    "paginationPrev": "上一页",
    "paginationPager": "{currentPage}/{pageCount}",
    "paginationNext": "下一页",
    "paginationJumper": "跳至"
    "paginationJumper": "跳至",
    "breadcrumb": {
      "home": "首页",
      "permissionManagement": "权限管理",
      "permissionList": "权限列表"
    },
    "search": {
      "placeholder": "请输入关键字"
    },
    "button": {
      "addPermission": "添加权限",
      "cancel": "取消",
      "confirm": "确认"
    },
    "table": {
      "role": "角色",
      "permissionDescription": "权限描述",
      "permissionValue": "权限值",
      "createTime": "创建时间",
      "isActive": "是否激活",
      "operation": "操作"
    },
    "tooltip": {
      "edit": "修改",
      "delete": "删除"
    },
    "dialog": {
      "addPermission": "添加权限",
      "editPermission": "编辑权限"
    },
    "form": {
      "role": "角色",
      "select": "请选择",
      "permission": "权限",
      "isActive": "是否激活"
    },
    "操作": "操作",
    "有效": "有效",
    "无效": "无效",
    "请输入名称": "请输入名称",
    "长度在 2 到 15 个字符": "长度在 2 到 15 个字符",
    "请输入状态": "请输入状态",
    "添加角色": "添加角色",
    "修改角色": "修改角色",
    "删除角色": "删除角色",
    "此操作将永久删除该角色, 是否继续?": "此操作将永久删除该角色, 是否继续?",
    "提示": "提示",
    "确定": "确定",
    "取消": "取消",
    "添加角色成功": "添加角色成功",
    "更新状态成功": "更新状态成功",
    "修改角色成功": "修改角色成功",
    "删除角色成功": "删除角色成功"
  }
  
CanadaMes-ui/src/layout/index.vue
@@ -1,29 +1,27 @@
<template>
  <el-container style="flex: 1;">
    <div style="width: 200px;background-color: #222f3e" :style="{width: isCollapse?'70px':'250px'}">
      <el-aside :width="isCollapse?'70px':'250px'">
        <el-col :gutter="20">
          <el-row :span="4">
            <div class="logo" @click="goToHome">
  <div class="sys-name" v-show="!isCollapse">{{ $t('northglassMESsystem') }}</div>
</div>
              <div class="sys-name" v-show="!isCollapse">{{ $t('northglassMESsystem') }}</div>
            </div>
          </el-row>
          <el-row :span="20">
            <el-menu :default-active="activePath" class="el-menu-vertical-demo"
                     background-color="#222f3e" text-color="#fff" active-text-color="#ffd04b"
                     :collapse="isCollapse" :unique-opened="true"
                     :collapse-transition="false" :router="true">
                     <el-menu-item index="/" @click="goToHome">
  <template slot="title">
    <!--图标-->
    <i class="el-icon-menu"></i>
    <!--文本-->
    <span>{{ $t('home') }}</span>
  </template>
</el-menu-item>
                     <!--一级菜单-->
                      background-color="#222f3e" text-color="#fff" active-text-color="#ffd04b"
                      :collapse="isCollapse" :unique-opened="true"
                      :collapse-transition="false" :router="true">
              <el-menu-item index="/" @click="goToHome">
                <template slot="title">
                  <!--图标-->
                  <i class="el-icon-menu"></i>
                  <!--文本-->
                  <span>{{ $t('home') }}</span>
                </template>
              </el-menu-item>
              <!--一级菜单-->
              <el-submenu :index="item.id.toString()" v-for="item in menuList" :key="item.id">
                <!--一级菜单模板区域-->
                <template slot="title">
@@ -35,7 +33,7 @@
                <!--二级菜单-->
                <el-menu-item :index="'/'+menu.router"
                              v-for="menu in item.menuLists" :key="menu.id"
                              @click="saveNavState('/'+menu.router)"   @select="saveNavState" :default-active="$route.path">
                              @click="addTag(menu.router)">
                  <template slot="title">
                    <!--图标-->
                    <i :class="menu.icon"></i>
@@ -43,76 +41,71 @@
                    <span>{{ menu.name }}</span>
                  </template>
                </el-menu-item>
              </el-submenu>
            </el-menu>
          </el-row>
        </el-col>
      </el-aside>
    </div>
    <el-container  >
      <el-header class="header-container"    >
    <el-container>
      <el-header class="header-container">
        
        <div class="tagContainer"  >
      <tag v-for="(tag, index) in tags" :key="index" :tag="tag" @removeTag="removeTag"></tag>
    </div>
        <el-menu :default-active="activePath1" class="el-menu-demo" mode="horizontal"
                 background-color="#576574" text-color="#fff" active-text-color="#ffd04b">
                 <div class="header-left"   >
          <el-button :icon="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'" @click="toggleCollapse"   style="height:30px"></el-button>
        </div>
        <template >
          <el-submenu index="1"  class="custom-submenu"  >
             <template slot="title">
              <el-avatar src="../assets/emi.png"  style="width:30px;height:30px;margin-top:2px;">
              </el-avatar>
            </template>
            <el-menu-item index="1-1" @click="logout"  >{{ $t('exit') }}</el-menu-item>
            <el-menu-item index="1-2" @click="showChangePasswordDialog"  >{{ $t('changePassword') }}</el-menu-item>
          </el-submenu>
        </template>
          <div class="header-left">
            <el-button :icon="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'" @click="toggleCollapse" style="height:30px"></el-button>
          </div>
          <div class="tagContainer">
            <tag v-for="(tag, index) in tags" :key="index" :tag="tag" @removeTag="removeTag(index)" @switchTag="switchTag(index)"></tag>
            <!-- <el-button icon="el-icon-circle-close" class="close-all-btn" @click="removeAllTags"></el-button> -->
          </div>
          <template>
  <el-dialog title="修改密码" :visible.sync="dialogVisible" width="30%"   s>
    <el-form ref="form" :model="formData" label-width="100px"   >
      <el-form-item label="旧密码">
        <el-input v-model="formData.oldPassword" type="password" show-password></el-input>
      </el-form-item>
      <el-form-item label="新密码">
        <el-input v-model="formData.newPassword" type="password" show-password></el-input>
      </el-form-item>
      <el-form-item label="确认新密码">
        <el-input v-model="formData.confirmPassword" type="password" show-password></el-input>
      </el-form-item>
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button @click="dialogVisible = false">取消</el-button>
      <el-button type="primary" @click="savePassword">保存</el-button>
    </div>
  </el-dialog>
</template>
            <el-submenu index="1" class="custom-submenu">
              <template slot="title">
                <el-avatar src="../assets/emi.png" style="width:30px;height:30px;margin-top:2px;"></el-avatar>
              </template>
              <el-menu-item index="1-1" @click="logout">{{ $t('exit') }}</el-menu-item>
              <el-menu-item index="1-2" @click="showChangePasswordDialog">{{ $t('changePassword') }}</el-menu-item>
            </el-submenu>
          </template>
          <template>
            <el-dialog title="修改密码" :visible.sync="dialogVisible" width="30%">
              <el-form ref="form" :model="formData" label-width="100px">
                <el-form-item label="旧密码">
                  <el-input v-model="formData.oldPassword" type="password" show-password></el-input>
                </el-form-item>
                <el-form-item label="新密码">
                  <el-input v-model="formData.newPassword" type="password" show-password></el-input>
                </el-form-item>
                <el-form-item label="确认新密码">
                  <el-input v-model="formData.confirmPassword" type="password" show-password></el-input>
                </el-form-item>
              </el-form>
              <div slot="footer" class="dialog-footer">
                <el-button @click="dialogVisible = false">取消</el-button>
                <el-button type="primary" @click="savePassword">保存</el-button>
              </div>
            </el-dialog>
          </template>
        </el-menu>
      </el-header>
      <el-main>
        <router-view/>
        <keep-alive>
          <router-view/>
        </keep-alive>
      </el-main>
    </el-container>
  </el-container>
</template>
<script>
import {selectList} from '../api/menuList'
import {changePassword} from '../api/user'
import {removeToken} from "../utils/auth";
import { selectList } from '../api/menuList'
import { changePassword } from '../api/user'
import { removeToken } from "../utils/auth";
import LanguageMixin from '../lang/LanguageMixin'
import { mapState, mapMutations } from 'vuex';
 import Tag from '../layout/tag.vue';
 import store from '../store';
import Tag from '../layout/tag.vue';
import store from '../store';
export default {
  name: "Layout",
@@ -120,7 +113,6 @@
  mixins: [LanguageMixin],
  data() {
    return {
      activeTag: '', // 当前激活的标签
      dialogVisible: false,
      formData: {
@@ -128,7 +120,6 @@
        newPassword: '',
        confirmPassword: ''
      },
      menuList: [],
      isCollapse: false,
      activePath: '',
@@ -139,13 +130,13 @@
      }
    }
  },
   components: {
   Tag
   },
  components: {
    Tag
  },
  created() {
    selectList(this.menuListForm).then(res => {
      this.menuList = res.data
      const language = this.$i18n.locale;
      if (language === 'en-US') {
        this.replaceChineseWithEnglish(this.menuList);
@@ -163,29 +154,24 @@
      this.$router.push('/login')
    },
    goToHome() {
    this.$router.push('/home');
  },
   // 使用 mapMutations 辅助函数调用 Store 中的 mutations
   ...mapMutations('tags', ['addTag', 'removeTag']),
    // 切换标签时触发的方法
    saveNavState(activePath) {
      window.sessionStorage.setItem('activePath', activePath);
      const menuItem = this.menuList.find(item => item.menuLists.some(menu => menu.router === activePath));
      if (menuItem) {
        const submenuItem = menuItem.menuLists.find(menu => menu.router === activePath);
        if (submenuItem) {
          const tag = submenuItem.name;
          this.$store.commit('tags/addTag', tag);  // 调用 Vuex Store 中的 addTag mutation
        }
      }
      this.$router.push('/home');
    },
    // 关闭标签时触发的方法
    removeTag(tag) {
      this.removeTag(tag); // 从 Vuex Store 中移除标签
    },
    ...mapMutations('tags', ['addTag', 'removeTag', 'switchTag']),
    addTag(router) {
  let submenuItem;
  const menuItem = this.menuList.find(item => item.menuLists.some(menu => menu.router === router));
  if (menuItem) {
    submenuItem = menuItem.menuLists.find(menu => menu.router === router);
  }
  if (submenuItem) {
    const tag = submenuItem.router;
    this.$store.commit('tags/addTag', tag);
  }
},
    removeTag(index) {
      this.$store.commit('tags/removeTag', index); // 从 Vuex Store 中移除标签
    },
    showChangePasswordDialog() {
      this.dialogVisible = true;
    },
@@ -200,25 +186,16 @@
        console.log(res.data);
        this.$message.success('密码修改成功');
        removeToken()
      this.$router.push('/login')
        this.$router.push('/login')
      }).catch(() => {
       
      });
      this.dialogVisible = false;
    },
    toggleCollapse: function () {
      this.isCollapse = !this.isCollapse;
    },
    // saveNavState: function (activePath) {
    //   window.sessionStorage.setItem('activePath', activePath)
    // },
    replaceChineseWithEnglish(menuData) {
      // 定义中英文对照关系对象
      const translation = {
@@ -232,7 +209,8 @@
        '权限管理': 'PermissionManagement',
        '权限列表': 'PermissionList',
        '角色管理': 'RoleManagement',
        '角色列表': 'RoleList'
        '角色列表': 'RoleList',
        '电气管理': 'Electrical management'
        // 根据实际需求继续添加对照关系
      };
@@ -242,79 +220,78 @@
          subMenu.name = translation[subMenu.name] || subMenu.name;
        });
      });
    }
  },
  watch: {
    '$route'(to) {
      // 切换路由时更新激活的标签
      const tag = this.menuList.some(item => item.menuLists.some(menu => '/' + menu.router === to.path));
      if (tag) {
        this.activeTag = tag;
      }
    }
  }
  }
}
</script>
<style scoped lang="less">
// .header-container {
//   display: flex;
//   justify-content: flex-start;
//   height: 10px; /* 设置较小的高度 */
// }
.custom-submenu  {
 
 
  height: 90px   !important;
 height: 90px   !important;
}
.header-container {
  height: 30px   !important; /* 设置较小的高度 */
 }
 height: 30px   !important; /* 设置较小的高度 */
}
.header-left {
  margin-right: auto;
 margin-right: auto;
}
.el-aside {
  height: 100vh;
  background-color: #222f3e;
  line-height: 200px;
 height: 100vh;
 background-color: #222f3e;
 line-height: 200px;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 200px;
  min-height: 400px;
 width: 200px;
 min-height: 400px;
}
.el-menu-demo {
  display: flex;
  width: 100%;
  height: 100%;
  justify-content: flex-end;
  align-items: center;
 display: flex;
 width: 100%;
 height: 100%;
 justify-content: flex-end;
 align-items: center;
}
.el-menu-vertical-demo {
  border: 0;
 border: 0;
}
.logo {
  background-color: #222f3e;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 60px;
 background-color: #222f3e;
 display: flex;
 justify-content: center;
 align-items: center;
 height: 60px;
  .sys-name {
    font-size: 20px;
    color: #ffffff;
    margin-left: 10px;
  }
 .sys-name {
   font-size: 20px;
   color: #ffffff;
   margin-left: 10px;
 }
}
.el-header {
  background-color: #576574;
 background-color: #576574;
}
</style>
</style>
CanadaMes-ui/src/layout/tag.vue
@@ -1,59 +1,70 @@
<template>
  <div class="tagContainer">
    <div v-for="(tag, index) in tags" :key="index" class="tagItem">
      {{ tag }}
      <span class="closeBtn" @click="removeTag(index)">x</span>
  <keep-alive>
    <div
      class="tag"
      :class="{ active: isActive }"
      @click="switchTag(tag)">
      <span>{{ tag }}</span>
      <i class="el-icon-close" @click.stop="removeTag(tag)"></i>
    </div>
  </div>
  </keep-alive>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
export default {
  props: {
    tag: {
      type: String,
      required: true
    },
    activeTag: {
      type: String,
      required: true
    }
  },
  computed: {
    ...mapState('tags', { // 这里添加了 'tags' 模块的命名空间前缀
      tags: state => state.tags.tags
    })
    isActive() {
      return this.tag === this.activeTag;
    },
    tagData() {
      return this.$store.getters.getTagData(this.tag);
    }
  },
  methods: {
    ...mapMutations('tag', ['removeTag']),
    saveNavState(activePath) {
    window.sessionStorage.setItem('activePath', activePath);
    removeTag(tag) {
      this.$emit('removeTag', tag);
    },
    switchTag(tag) {
  this.$emit('switchTag', tag);
  this.$router.push('/' + tag); // 切换到指定路由
}
    
    const menuItem = this.menuList.find(item => item.menuLists.some(menu => menu.router === activePath));
    if (menuItem) {
      const submenuItem = menuItem.menuLists.find(menu => menu.router === activePath);
      if (submenuItem) {
        const tag = submenuItem.name;
        this.addTag(tag); // 添加标签到 Vuex Store
      }
    }
  }
  }
}
</script>
<style scoped>
.tagContainer {
  display: flex;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.tagItem {
  background-color: #eee;
.tag {
  display: inline-block;
  margin-right: 10px;
  padding: 4px 10px;
  border-radius: 4px;
  padding: 4px 8px;
  margin-right: 8px;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
}
.closeBtn {
  margin-left: 4px;
  color: red;
  background-color: #f0f0f0;
  cursor: pointer;
}
</style>
.tag.active {
  background-color: #409eff;
  color: #fff;
}
.tag span {
  margin-right: 5px;
}
.tag i {
  margin-left: 5px;
  font-size: 12px;
  cursor: pointer;
}
</style>
CanadaMes-ui/src/store/index.js
@@ -10,5 +10,29 @@
  modules: {
    tags,
  },
  state: {
    tagData: {} // 存储标签数据的对象
  },
  mutations: {
    // 更新标签数据
    updateTagData(state, payload) {
      state.tagData[payload.tag] = payload.data;
    }
  },
  actions: {
    // 异步操作更新标签数据
    updateTagDataAsync({ commit }, payload) {
      // 执行异步操作,比如发送请求获取数据
      // 然后通过commit触发mutation来更新数据
      setTimeout(() => {
        commit('updateTagData', payload);
      }, 1000);
    }
  },
  getters: {
    getTagData: (state) => (tag) => {
      return state.tagData[tag] || null; // 获取指定标签的数据
    }
  }
  // 其他配置
});
CanadaMes-ui/src/store/module/tags.js
@@ -1,6 +1,6 @@
const state = {
  tags: []
};
}
const mutations = {
  addTag(state, tag) {
@@ -8,15 +8,20 @@
      state.tags.push(tag);
    }
  },
  removeTag(state, tag) {
    const index = state.tags.indexOf(tag);
    if (index !== -1) {
      state.tags.splice(index, 1);
    }
  removeTag(state, index) {
    state.tags.splice(index, 1);
  },
  removeAllTags(state) {
    state.tags = [];
  },
  switchTag(tag) {
    this.$emit('switchTag', tag);
    this.$router.push('/' + tag); // 添加这行代码以切换路由
  }
};
}
export default {
  namespaced: true,
  state,
  mutations
};
}
CanadaMes-ui/src/views/Electrical/Action.vue
@@ -12,11 +12,15 @@
    </el-breadcrumb>
    <div>Action</div>
    <el-form label-width="100px" style="display: flex;flex-wrap: wrap;" :model="{ messagepack }">
      <div class="kuai_div" v-for="item in this.record.xyData" :key="item.name">
      <!-- <div class="kuai_div" v-for="item in record.xyData" :key="item.value">
        <el-input v-model="item.name" style="width: 240px;" class="in_mc"></el-input>
        <!-- <el-input v-model="item[0]" style="width: 80px;"></el-input> -->
        <el-switch v-model="item.value" active-value="0" inactive-value="1"></el-switch>
      </div>
      </div> -->
      <div class="kuai_div" v-for="(item, index) in record.xyData" :key="index">
        <el-input v-model="item.name" style="width: 240px;" class="in_mc" readonly></el-input>
        <el-switch v-model="item.value" active-value="1" inactive-value="0"  @change="send()"></el-switch>
    </div>
    </el-form>
@@ -31,7 +35,7 @@
  data () {
    return {
      record: {
        params: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        params: [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        canshu: [
          'D01 VFD conveyor',
          'D02 VFD conveyor',
@@ -61,13 +65,34 @@
          'B02 YV UP DOWN',
        ],
        xyData: [
          { name: 'D01 VFD conveyor', value: 0 },
          { name: "D02 VFD conveyor", value: 0 },
          { name: "D03 VFD conveyor", value: 0 },
          { name: "D04 VFD conveyor", value: 0 },
          { name: "B01 B02 TRAVEL JOG Velocity", value: 0 },
          { name: "conveyor Velocity(Manual)", value: 0 },
        ],
  { name: 'D01 VFD conveyor', value: "0" },
  { name: 'D02 VFD conveyor', value: "0" },
  { name: 'D03 VFD conveyor', value: "1" },
  { name: 'D04 VFD conveyor', value: "0" },
  { name: 'D05 VFD conveyor', value: "0" },
  { name: 'D06 VFD conveyor', value: "0" },
  { name: 'A01 VFD conveyor', value: "0" },
  { name: 'A02 VFD conveyor', value: "0" },
  { name: 'B01 VFD conveyor', value: "0" },
  { name: 'B02 VFD conveyor', value: "0" },
  { name: 'A01 SERVE TURN JOG+', value: "0" },
  { name: 'A02 SERVE TURN JOG-', value: "0" },
  { name: 'A01 SERVE TRAVEL JOG+', value: "0" },
  { name: 'A02 SERVE TRAVEL JOG-', value: "0" },
  { name: 'B01 SERVE TRAVEL JOG+', value: "0" },
  { name: 'B02 SERVE TRAVEL JOG-', value: "0" },
  { name: 'A01 SERVE TURN POS', value: "0" },
  { name: 'A02 SERVE TURN POS', value: "0" },
  { name: 'A01 SERVE TRAVEL POS', value: "0" },
  { name: 'A02 SERVE TRAVEL POS', value: "0" },
  { name: 'B01 SERVE TRAVEL POS', value: "0" },
  { name: 'B02 SERVE TRAVEL POS', value: "0" },
  { name: 'B01 YV TURN', value: "0" },
  { name: 'B01 YV UP DOWN', value: "0" },
  { name: 'B02 YV TURN', value: "0" },
  { name: 'B02 YV UP DOWN', value: "0" },
]
,
      },
@@ -86,7 +111,7 @@
  },
  methods: {
    init () {
      let viewname = "Action";
      let viewname = "action";
      if (typeof (WebSocket) == "undefined") {
        console.log("您的浏览器不支持WebSocket");
@@ -105,25 +130,26 @@
          console.log("websocket已打开");
        };
        //  浏览器端收消息,获得从服务端发送过来的文本消息
        socket.onmessage = function (msg) {
        socket.onmessage = (msg) => {
  if (!msg.data) {
    return; // 如果收到空数据,则直接返回,不执行后续逻辑
  }
          //console.log("收到数据====" + msg.data);
          let obj = JSON.parse(msg.data);
  let obj = JSON.parse(msg.data);
  this.record.params[0] = obj.params[0];
          this.record.params[0] = obj.acion[0].join(",");
          this.record.params[0] = this.record.params[0].split(",");
  for (let a = 0; a <= this.record.params[0].length - 1; a++) {
    if (!this.record.xyData[a]) {
      this.record.xyData[a] = { name: this.record.canshu[a], value: this.record.params[0][a].toString() };
    } else {
      this.record.xyData[a].value = this.record.params[0][a].toString();
    }
  }
          for (let a = 0; a <= this.record.params.length - 1; a++) {
            // if (!this.record.xyData[a]) {
            //   this.record.xyData[a] = { name: this.record.canshu[a], value: this.record.params[0][a] };
            // } else {
            //   this.record.xyData[a].value = this.record.params[0][a];
            // }
            this.record.xyData[a] = { name: this.record.canshu[a], value: this.record.params[0][a] };
          }
          console.log(this.record.xyData)
          this.$forceUpdate();
        }.bind(this);
  console.log(this.record.xyData);
  this.$forceUpdate();
};
        //关闭事件
        socket.onclose = function () {
          console.log("websocket已关闭");
@@ -135,10 +161,11 @@
      }
    },
    send () {
      this.messagepack.data = { taskname: "前端到后台" };
      socket?.send(JSON.stringify(this.messagepack));  // 将组装好的json发送给服务端,由服务端进行转发
    }
    send() {
  this.messagepack.data = this.record.xyData.map(item => parseInt(item.value)); // 转换为整数数组
  console.log(this.messagepack);
  socket?.send(JSON.stringify(this.messagepack));
}
  }
@@ -161,16 +188,18 @@
  border: none;
  .el-input__inner {
}
.el-input__inner {
    border: 1 solid black;
  }
}
.in_mc {
  .el-input__inner {
}
.el-input__inner {
    border: none;
  }
}
</style>
CanadaMes-ui/src/views/Electrical/Parameter.vue
@@ -8,6 +8,7 @@
  <router-link to="/Electrical/Action" tag="el-button" type="text">Action</router-link>
  <router-link to="/Electrical/Sign" tag="el-button" type="text">Sign</router-link>
  <router-link to="/Electrical/State" tag="el-button" type="text">State</router-link>
  <router-link to="/Electrical/alarm" tag="el-button" type="text">Alarm</router-link>
  </el-breadcrumb>
  <div>Parameter</div>
  
@@ -16,8 +17,8 @@
      <el-button type="primary" @click="send()">下发参数</el-button>
    </div>
    <div class="kuai_div" v-for="(item, index) in record.xyData" :key="index">
      <el-input style="width: 280px;" class="in_mc" v-model="item.name"  readonly></el-input>
      <el-input v-model="item.value" style="width: 80px;"></el-input>
      <el-input style="width: 280px;" class="in_mc" v-model="item.name" readonly></el-input>
      <el-input v-model.number="item.value" style="width: 80px;" @input="handleChange(index, $event.target.value)"></el-input>
    </div>
  </el-form>
  </div>
@@ -32,20 +33,21 @@
  return {
  record: {
  params: [100, 200, 10, 10, 10, 10],
  xyData: [{ name: "conveyor Velocity(Auto SLOW)", value: 100 },
    { name: "B01 B02 TRAVEL POS Velocity AUTO", value: 10 },
    { name: "B01 B02 TRAVEL JOG Velocity", value: 10 },
    { name: "conveyor Velocity(Manual)", value: 10},
    { name: "B01 B02 TRAVEL JOG Velocity", value: 10},
    { name: "conveyor Velocity(Manual)", value: 10 }],
  canshu: [
  'conveyor Velocity(Auto SLOW)',
  'B01 B02 TRAVEL POS Velocity AUTO',
  'B01 B02 TRAVEL JOG Velocity',
  'conveyor Velocity(Manual)',
  'B01 B02 TRAVEL JOG Velocity',
  'conveyor Velocity(Manual)'
  xyData: [
  { name: "conveyor Velocity(Auto FAST)", value: 0 },
  { name: "conveyor Velocity(Auto SLOW)", value: 0 },
  { name: "conveyor Velocity(Manual)", value: 0 },
  { name: "A01 A02 TURN JOG Velocity", value: 0 },
  { name: "A01 A02 TRAVEL JOG Velocity", value: 0 },
  { name: "B01 B02 TRAVEL JOG Velocity", value: 0 },
  { name: "A01 A02 TURN POS Velocity AUTO", value: 0 },
  { name: "A01 A02 TURN POS Velocity manual", value: 0 },
  { name: "A01 A02 TRAVEL POS Velocity AUTO", value: 0 },
  { name: "A01 A02 TRAVEL POS Velocity manual", value: 0 },
  { name: "B01 B02 TRAVEL POS Velocity AUTO", value: 0 },
  { name: "B01 B02 TRAVEL POS Velocity manual", value: 0 }
  ],
  canshu: []
  },
  messagepack: {
  data: { taskname: "" }
@@ -53,21 +55,19 @@
  queryInfo: {
  data: "1",
  pageSize: 10
  },
  }
  };
  },
  created() {
  this.initWebSocket();
  },
  methods: {
  initWebSocket() {
  let viewname = "action";
  let viewname = "Parameter";
  
    if (typeof WebSocket == "undefined") {
    if (typeof WebSocket === "undefined") {
      console.log("您的浏览器不支持WebSocket");
    } else {
      //console.log("您的浏览器支持WebSocket");
      let socketUrl = "ws://" + "localhost:8888" + "/springboot-vue3/api/talk/" + viewname;
  
      if (socket != null) {
@@ -85,24 +85,24 @@
  
      // 收到消息
      socket.onmessage = (msg) => {
  if (!msg.data) {
    return; // 如果收到空数据,则直接返回,不执行后续逻辑
  }
  let obj = JSON.parse(msg.data);
  this.record.params[0] = obj.params[0];
  for (let a = 0; a <= this.record.params[0].length - 1; a++) {
    if (!this.record.xyData[a]) {
      this.record.xyData[a] = { name: this.record.canshu[a], value: this.record.params[0][a] };
    } else {
      this.record.xyData[a].value = this.record.params[0][a];
    }
  }
  console.log(this.record.xyData);
  this.$forceUpdate();
};
        if (!msg.data) {
          return; // 如果收到空数据,则直接返回,不执行后续逻辑
        }
        let obj = JSON.parse(msg.data);
        this.record.params[0] = obj.params[0];
        for (let a = 0; a <= this.record.params[0].length - 1; a++) {
          if (!this.record.xyData[a]) {
            this.record.xyData[a] = { name: this.record.canshu[a], value: this.record.params[0][a] };
          } else {
            this.record.xyData[a].value = this.record.params[0][a];
          }
        }
        console.log(this.record.xyData);
        this.$forceUpdate();
      };
  
      // 关闭事件
      socket.onclose = function () {
@@ -112,16 +112,19 @@
      // 发生错误事件
      socket.onerror = function () {
        console.log("websocket发生了错误");
      }
      };
    }
  },
  send() {
  this.messagepack.data = this.record.xyData.map(item => parseInt(item.value)); // 转换为整数数组
  console.log(this.messagepack);
  socket?.send(JSON.stringify(this.messagepack));
}
    this.messagepack.data = this.record.xyData.map((item) => parseInt(item.value)); // 转换为整数数组
    console.log(this.messagepack);
    socket?.send(JSON.stringify(this.messagepack));
  },
  handleChange(index, value) {
    this.record.xyData[index].value = value;
  }
  }
  };
  </script>
  
  <style>
@@ -149,4 +152,4 @@
  #btn_div .el-button {
  float: right;
  }
  </style>
  </style>
CanadaMes-ui/src/views/power/index.vue
@@ -2,32 +2,32 @@
  <div class="app">
    <!--面包屑导航区域-->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>权限管理</el-breadcrumb-item>
      <el-breadcrumb-item>权限列表</el-breadcrumb-item>
      <el-breadcrumb-item :to="{ path: '/home' }">{{$t('breadcrumb.home')}}</el-breadcrumb-item>
      <el-breadcrumb-item>{{$t('breadcrumb.permissionManagement')}}</el-breadcrumb-item>
      <el-breadcrumb-item>{{$t('breadcrumb.permissionList')}}</el-breadcrumb-item>
    </el-breadcrumb>
    <!--卡片视图区域-->
    <el-card class="el-card">
      <el-row :gutter="20">
        <!--搜索与添加区域-->
        <el-col :span="6">
          <el-input placeholder="请输入权限名称" v-model="queryInfo.name" clearable @clear="getPowerList()">
          <el-input :placeholder="$t('search.placeholder')" v-model="queryInfo.name" clearable @clear="getPowerList()">
            <el-button slot="append" icon="el-icon-search" @click="getPowerList()"></el-button>
          </el-input>
        </el-col>
        <!--添加区域-->
        <el-col :span="4">
          <el-button type="primary" @click="showAddDialog">添加权限</el-button>
          <el-button type="primary" @click="showAddDialog">{{$t('button.addPermission')}}</el-button>
        </el-col>
      </el-row>
      <!--权限列表区域-->
      <el-table :data="powerList.records" border stripe>
        <el-table-column label="#" type="index"></el-table-column>
        <el-table-column label="角色" prop="role.name"></el-table-column>
        <el-table-column label="权限描述" prop="permission.description"></el-table-column>
        <el-table-column label="权限值" prop="permission.name"></el-table-column>
        <el-table-column label="创建时间" prop="createTime"></el-table-column>
        <el-table-column label="是否生效">
        <el-table-column :label="$t('table.role')" prop="role.name"></el-table-column>
        <el-table-column :label="$t('table.permissionDescription')" prop="permission.description"></el-table-column>
        <el-table-column :label="$t('table.permissionValue')" prop="permission.name"></el-table-column>
        <el-table-column :label="$t('table.createTime')" prop="createTime"></el-table-column>
        <el-table-column :label="$t('table.isActive')">
          <template slot-scope="scope">
            <el-switch :active-value=1
                       :inactive-value=0
@@ -36,15 +36,15 @@
            </el-switch>
          </template>
        </el-table-column>
        <el-table-column label="操作">
        <el-table-column :label="$t('table.operation')">
          <template slot-scope="scope">
            <!--修改-->
            <el-tooltip effect="dark" content="修改" placement="top" :enterable="false">
            <el-tooltip effect="dark" :content="$t('tooltip.edit')" placement="top" :enterable="false">
              <el-button type="primary" icon="el-icon-edit" size="mini"
                         @click="showEditDialog(scope.row)"></el-button>
            </el-tooltip>
            <!--删除-->
            <el-tooltip effect="dark" content="删除" placement="top" :enterable="false">
            <el-tooltip effect="dark" :content="$t('tooltip.delete')" placement="top" :enterable="false">
              <el-button type="danger" icon="el-icon-delete" size="mini"
                         @click="removeById(scope.row)"></el-button>
            </el-tooltip>
@@ -64,14 +64,14 @@
    </el-card>
    <!--添加权限的对话框-->
    <el-dialog
        title="添加权限"
        :title="$t('dialog.addPermission')"
        :visible.sync="addDialogVisible"
        width="50%"
        @close="addDialogClosed">
      <!--内容主体区域-->
      <el-form :model="addPowerForm" :rules="powerRules" ref="powerRef" label-width="70px">
        <el-form-item label="角色" prop="roleId">
          <el-select filterable v-model="addPowerForm.roleId" placeholder="请选择">
        <el-form-item :label="$t('form.role')" prop="roleId">
          <el-select filterable v-model="addPowerForm.roleId" :placeholder="$t('form.select')">
            <el-option v-for="item in roleList"
                       :key="item.id"
                       :value="item.id"
@@ -79,8 +79,8 @@
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="权限" prop="permissionId">
          <el-select filterable v-model="addPowerForm.permissionId" placeholder="请选择">
        <el-form-item :label="$t('form.permission')" prop="permissionId">
          <el-select filterable v-model="addPowerForm.permissionId" :placeholder="$t('form.select')">
            <el-option v-for="item in permissionList"
                       :key="item.id"
                       :value="item.id"
@@ -88,8 +88,8 @@
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="是否生效" prop="state">
          <el-select v-model="addPowerForm.state" placeholder="请选择">
        <el-form-item :label="$t('form.isActive')" prop="state">
          <el-select v-model="addPowerForm.state" :placeholder="$t('form.select')">
            <el-option v-for="(item,index) in options"
                       :key="index"
                       :value="item.value"
@@ -99,19 +99,19 @@
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
    <el-button @click="addDialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="addPower">确 定</el-button>
    <el-button @click="addDialogVisible = false">{{$t('button.cancel')}}</el-button>
    <el-button type="primary" @click="addPower">{{$t('button.confirm')}}</el-button>
  </span>
    </el-dialog>
    <!--修改权限的对话框-->
    <el-dialog
        title="修改权限"
        :title="$t('dialog.editPermission')"
        :visible.sync="editDialogVisible"
        width="50%">
      <!--内容主体区域-->
      <el-form :model="editRoleForm" :rules="powerRules" ref="powerRef" label-width="70px">
        <el-form-item label="角色" prop="roleId">
          <el-select filterable v-model="editRoleForm.roleId" placeholder="请选择">
        <el-form-item :label="$t('form.role')" prop="roleId">
          <el-select filterable v-model="editRoleForm.roleId" :placeholder="$t('form.select')">
            <el-option v-for="item in roleList"
                       :key="item.id"
                       :value="item.id"
@@ -119,8 +119,8 @@
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item filterable label="权限" prop="permissionId">
          <el-select v-model="editRoleForm.permissionId" placeholder="请选择">
        <el-form-item filterable :label="$t('form.permission')" prop="permissionId">
          <el-select v-model="editRoleForm.permissionId" :placeholder="$t('form.select')">
            <el-option v-for="item in permissionList"
                       :key="item.id"
                       :value="item.id"
@@ -128,8 +128,8 @@
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="是否生效" prop="state">
          <el-select v-model="editRoleForm.state" placeholder="请选择">
        <el-form-item :label="$t('form.isActive')" prop="state">
          <el-select v-model="editRoleForm.state" :placeholder="$t('form.select')">
            <el-option v-for="(item,index) in options"
                       :key="index"
                       :value="item.value"
@@ -139,8 +139,8 @@
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
    <el-button @click="editDialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="editRoleInfo">确 定</el-button>
    <el-button @click="editDialogVisible = false">{{$t('button.cancel')}}</el-button>
    <el-button type="primary" @click="editRoleInfo">{{$t('button.confirm')}}</el-button>
  </span>
    </el-dialog>
  </div>
@@ -150,9 +150,11 @@
import {getById, removeById, saveOrUpdate, selectPage} from "../../api/rolePermission";
import {select} from "../../api/role";
import {selectPermission} from "../../api/permission";
import LanguageMixin from '../../lang/LanguageMixin'
export default {
  name: "Power",
  mixins: [LanguageMixin],
  data() {
    return {
      queryInfo: {
CanadaMes-ui/src/views/role/index.vue
@@ -137,12 +137,13 @@
      addRoleForm: {
        state: 1
      },
      // 修改的角色对象
      editRoleForm: {},
      // 添加角色的验证规则
      addRoleRules: {
        name: [
          {required: true, message: '请输入名称', trigger: 'blur'},
          {required: true, message:  '请输入名称', trigger: 'blur'},
          {min: 2, max: 15, message: '长度在 2 到 15 个字符', trigger: 'blur'}
        ],
        state: [
@@ -177,7 +178,8 @@
    },
    stateChange(info) {
      saveOrUpdate(info).then(() => {
        this.$message.success("更新状态成功")
        const 更新状态成功 = this.$t('更新状态成功');
        this.$message.success(更新状态成功)
      });
    },
@@ -195,7 +197,8 @@
          this.getRoleList();
          // 隐藏添加角色对话框
          this.addDialogVisible = false;
          this.$message.success("添加角色成功");
          const 添加角色成功 = this.$t('添加角色成功');
          this.$message.success(添加角色成功);
        });
      })
    },
@@ -220,26 +223,33 @@
          this.getRoleList();
          // 隐藏添加角色对话框
          this.editDialogVisible = false;
          this.$message.success("修改角色成功");
          const 修改角色成功 = this.$t('修改角色成功');
          this.$message.success(修改角色成功);
        });
      })
    },
    // 根据id删除角色信息
    removeById(role) {
      // 弹框询问用户是否删除角色
      this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
      const 此操作将永久删除该角色是否继续 = this.$t('此操作将永久删除该角色, 是否继续?');
      const 提示 = this.$t('提示');
      const 确定 = this.$t('确定');
      const 取消 = this.$t('取消');
      this.$confirm(此操作将永久删除该角色是否继续, 提示, {
        confirmButtonText: 确定,
        cancelButtonText: 取消,
        type: 'warning'
      }).then(() => {
        // 删除角色
        removeById({id: role.id}).then(() => {
          // 重新获取角色列表
          this.getRoleList();
          this.$message.success("删除角色成功");
          const 删除角色成功 = this.$t('删除角色成功');
          this.$message.success(删除角色成功);
        });
      }).catch(() => {
        this.$message('已取消删除');
        const 已取消删除 = this.$t('已取消删除');
        this.$message(已取消删除);
      });
    }
  }
CanadaMes-ui/src/views/user/index.vue
@@ -11,11 +11,11 @@
      <el-row :gutter="20">
        <!--搜索与添加区域-->
        <el-col :span="6">
          <el-input placeholder="请输入用户名称"  v-model="queryInfo.username" clearable @clear="getUserList">
          <el-input :placeholder= "$t('langUsernamePlaceholder')"  v-model="queryInfo.username" clearable @clear="getUserList">
          </el-input>
        </el-col>
        <el-col :span="6">
          <el-input  placeholder="请输入邮箱" v-model="queryInfo.email" clearable @clear="getUserList">
          <el-input  :placeholder="$t('langEmailPlaceholder')"  v-model="queryInfo.email" clearable @clear="getUserList">
          </el-input>
        </el-col>
        <!--搜索按钮-->
@@ -74,8 +74,7 @@
      :page-sizes="[6, 12, 18, 24]"
      :page-size="queryInfo.pageSize"
      :total="userList.total"
      :prev-text="$t('pagination.prev')"
      :next-text="$t('pagination.next')"
      :pager-count="7"
      :layout="layout"
    >
springboot-vue3/src/main/java/com/example/springboot/AuthorityApplication.java
@@ -2,8 +2,10 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
public class AuthorityApplication {
    public static void main(String[] args) {
springboot-vue3/src/main/java/com/example/springboot/component/PlcHold.java
@@ -26,12 +26,12 @@
      // 推送到前端
      // Parameter
      JSONObject jsonObject = new JSONObject();
      jsonObject.append("params", new short[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, });
      WebSocketServer sendwServer = WebSocketServer.sessionMap.get("Parameter");
      if (sendwServer != null) {
        sendwServer.sendMessage(jsonObject.toString());
      }
//      JSONObject jsonObject = new JSONObject();
//      jsonObject.append("params", new short[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, });
//      WebSocketServer sendwServer = WebSocketServer.sessionMap.get("Parameter");
//      if (sendwServer != null) {
//        sendwServer.sendMessage(jsonObject.toString());
//      }
      // Action
      // JSONObject jsonObject2 = new JSONObject();
springboot-vue3/src/main/java/com/example/springboot/component/PlcParameter.java
New file
@@ -0,0 +1,82 @@
package com.example.springboot.component;
import cn.hutool.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class PlcParameter extends Thread {
    private static final int SEND_INTERVAL = 10000;
    private static final int WRITE_INTERVAL = 100;
    @Override
    public void run() {
        try {
            // 发送一次消息
            sendMessages();
            // 延迟一段时间
            Thread.sleep(SEND_INTERVAL);
            while (true) {
                // 写入PLC
                writeToPlc();
                Thread.sleep(WRITE_INTERVAL);
                // 发送消息
                sendMessages();
                Thread.sleep(SEND_INTERVAL);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    private void sendMessages() {
        WebSocketServer sendwServer = WebSocketServer.sessionMap.get("Parameter");
        if (sendwServer != null) {
            List<Short> paramlist = S7control.getinstance().ReadWord("DB100.DBW", 12);
            JSONObject jsonObject = new JSONObject();
//            new short[]{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0}
            jsonObject.append("params", new short[]{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0});
            sendwServer.sendMessage(jsonObject.toString());
        }
    }
    private void writeToPlc() {
        WebSocketServer webSocketServer = WebSocketServer.sessionMap.get("Parameter");
        if (webSocketServer != null) {
            List<String> messages = webSocketServer.getMessages();
            String addressList = "DB100.DBW0";
            if (!messages.isEmpty()) {
                // 将最后一个消息转换为 short 类型的列表
                String lastMessage = messages.get(messages.size() - 1);
                System.out.println("messages:" + messages);
                String[] parts = lastMessage.split(",");
                List<Short> messageValues = new ArrayList<>();
                for (String part : parts) {
                    try {
                        // 使用正则表达式清除非数字字符
                        String cleanedPart = part.replaceAll("[^0-9-]", "");
                        short value = Short.parseShort(cleanedPart.trim());
                        messageValues.add(value);
                    } catch (NumberFormatException e) {
                        // 如果无法解析为 short 类型,则忽略该部分
                        e.printStackTrace();
                    }
                }
                // 将消息值写入 PLC
                S7control.getinstance().WriteWord(addressList, messageValues);
                System.out.println("messageValues:" + messageValues);
                System.out.println("addressList:" + addressList);
                // 清空消息列表
                webSocketServer.clearMessages();
            }
        }
    }
}
springboot-vue3/src/main/java/com/example/springboot/component/Plcaction.java
@@ -6,69 +6,96 @@
import java.util.List;
public class Plcaction extends Thread {
    private static final long SEND_INTERVAL = 2000; // 发送消息的时间间隔
    private static final long WRITE_INTERVAL = 100; // 写入PLC的时间间隔
    @Override
    public void run() {
        while (this != null) {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
        try {
            // 发送一次消息
            sendMessages();
            // 延迟一段时间
            Thread.sleep(SEND_INTERVAL);
            while (true) {
                // 写入PLC
                writeToPlc();
                Thread.sleep(WRITE_INTERVAL);
                // 发送消息
                sendMessages();
                Thread.sleep(SEND_INTERVAL);
            }
            List<Short> paramlist = S7control.getinstance().ReadWord("DB100.DBW", 12);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    private void sendMessages() {
        WebSocketServer sendwServer = WebSocketServer.sessionMap.get("action");
        if (sendwServer != null) {
            List<Boolean> paramlist = S7control.getinstance().ReadBits("DB100.DBW", 12);
            //        new short[]{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0}
            JSONObject jsonObject = new JSONObject();
            jsonObject.append("params", paramlist);
            WebSocketServer sendwServer = WebSocketServer.sessionMap.get("action");
            if (sendwServer != null) {
                sendwServer.sendMessage(jsonObject.toString());
            }
            jsonObject.append("params", new short[]{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0});
            WebSocketServer webSocketServer = WebSocketServer.sessionMap.get("action");
            if (webSocketServer != null) {
                List<String> messages = webSocketServer.getMessages();
            sendwServer.sendMessage(jsonObject.toString());
        }
                String addressList = "DB100.DBW0";
//                addressList.add("DB100.DBW0");
//                addressList.add("DB100.DBW2");
//                addressList.add("DB100.DBW4");
//                addressList.add("DB100.DBW6");
//                addressList.add("DB100.DBW8");
//                addressList.add("DB100.DBW10");
//                addressList.add("DB100.DBW12");
//                addressList.add("DB100.DBW14");
//                addressList.add("DB100.DBW16");
//                addressList.add("DB100.DBW18");
//                addressList.add("DB100.DBW20");
//                addressList.add("DB100.DBW22");
                if (!messages.isEmpty()) {
                    // 将最后一个消息转换为 short 类型的列表
                    String lastMessage = messages.get(messages.size() - 1);
                    System.out.println("messages:" + messages);
                    String[] parts = lastMessage.split(",");
                    List<Short> messageValues = new ArrayList<>();
                    for (String part : parts) {
                        try {
                            // 使用正则表达式清除非数字字符
                            String cleanedPart = part.replaceAll("[^0-9-]", "");
                            short value = Short.parseShort(cleanedPart.trim());
                            messageValues.add(value);
                        } catch (NumberFormatException e) {
                            // 如果无法解析为 short 类型,则忽略该部分
                            e.printStackTrace();
                        }
    }
    private void writeToPlc() {
        WebSocketServer webSocketServer = WebSocketServer.sessionMap.get("action");
        if (webSocketServer != null) {
            List<String> messages = webSocketServer.getMessages();
            String addressList = "DB100.DBW0";
            if (!messages.isEmpty()) {
                // 将最后一个消息转换为整数类型的列表
                String lastMessage = messages.get(messages.size() - 1);
                System.out.println("messages:" + messages);
                String[] parts = lastMessage.split(",");
                List<Integer> messageValues = new ArrayList<>();
                for (String part : parts) {
                    try {
                        // 使用正则表达式清除非数字字符
                        String cleanedPart = part.replaceAll("[^0-9-]", "");
                        Integer value = Integer.parseInt(cleanedPart.trim());
                        messageValues.add(value);
                    } catch (NumberFormatException e) {
                        // 如果无法解析为整数类型,则忽略该部分
                        e.printStackTrace();
                    }
                    // 将消息值写入 PLC
//                    S7control.getinstance().WriteWord(addressList, messageValues);
                    System.out.println("messageValues:" + messageValues);
                    System.out.println("addressList:" + addressList);
                    // 清空消息列表
                    messages.clear();
                }
                // 将消息值转换为布尔列表
                List<Boolean> messageBooleans = new ArrayList<>();
                for (Integer value : messageValues) {
                    messageBooleans.add(value == 0 ? true : false);
                }
                // 将布尔列表写入 PLC
                S7control.getinstance().WriteBit(addressList, messageBooleans);
                System.out.println("messageValues:" + messageBooleans);
                System.out.println("addressList:" + addressList);
                // 清空消息列表
                webSocketServer.clearMessages();
            }
        }
    }
}
    private List<Boolean> paramList() {
        // 获取参数列表的逻辑
        return new ArrayList<>(); // 假设返回空列表
    }
}
springboot-vue3/src/main/java/com/example/springboot/config/AppRunnerConfig.java
@@ -1,5 +1,6 @@
package com.example.springboot.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
@@ -7,10 +8,14 @@
import com.example.springboot.component.PlcHold;
import com.example.springboot.component.Plcaction;
import com.example.springboot.component.PlcParameter;
@Component
@Order(1)
public class AppRunnerConfig implements ApplicationRunner {
  @Override
  public void run(ApplicationArguments args) throws Exception {
    // TODO Auto-generated method stub
@@ -19,6 +24,7 @@
    new PlcHold().start();
    new Plcaction().start();
    new PlcParameter().start();