| | |
| | | "core-js": "^3.41.0", |
| | | "element-ui": "^2.15.6", |
| | | "moment": "^2.30.1", |
| | | "sm-crypto": "^0.3.13", |
| | | "vue": "^2.7.16", |
| | | "vue-router": "^3.6.5", |
| | | "vuex": "^3.6.2" |
| | |
| | | <meta name="viewport" content="width=device-width,initial-scale=1.0"> |
| | | <link rel="icon" href="<%= BASE_URL %>logo.jpg"> |
| | | <!-- <link rel="icon" href="data:,"> --> |
| | | <title>实验室流程</title> |
| | | <title>菌种库</title> |
| | | </head> |
| | | |
| | | <body> |
| | |
| | | // 退出登录 |
| | | outLogin() { |
| | | sessionStorage.clear() |
| | | this.$router.replace({ path: "/" }); |
| | | this.$router.replace({ path: "/login" }); |
| | | }, |
| | | // 关闭标签 |
| | | closeTag(tag) { |
| | |
| | | <div class="image"> |
| | | <img src="../assets/logo.jpg" alt="" srcset="" /> |
| | | </div> |
| | | <div class="title">实验室流程</div> |
| | | <div class="title">菌种库</div> |
| | | </div> |
| | | <!-- 左侧菜单 --> |
| | | <div v-if="!isFold" class="sidebar-container"> |
| | |
| | | import "aieditor/dist/style.css" |
| | | import './assets/tailwind.css' |
| | | import './styles/element-variables.less' |
| | | import { fetchEncryptionKey } from './utils/encryption' |
| | | |
| | | Vue.config.productionTip = false; |
| | | Vue.use(ElementUI, { size: 'small' }) |
| | |
| | | return height |
| | | } |
| | | |
| | | // 获取加密密钥 |
| | | // fetchEncryptionKey() |
| | | |
| | | new Vue({ |
| | | router, |
| | | store, |
| | |
| | | document.title = to.meta.title || '实验室流程'; |
| | | |
| | | // 登录验证 |
| | | // if (to.path === "/login") { |
| | | // sessionStorage.removeItem('userInfo') |
| | | // next() |
| | | // } else if (!sessionStorage.getItem('userInfo')) { |
| | | // next('/login') |
| | | // } else { |
| | | // // 判断是否拥有要跳转菜单权限 |
| | | // let menus = store.state.menus |
| | | // if (to.meta.hasOwnProperty('privilege') && !menus.includes(to.meta.privilege)) { |
| | | // return |
| | | // } |
| | | if (to.path === "/login") { |
| | | sessionStorage.clear(); |
| | | next() |
| | | } else if (!sessionStorage.getItem('token')) { |
| | | next('/login') |
| | | } else { |
| | | // 判断是否拥有要跳转菜单权限 |
| | | let menus = store.state.menus |
| | | if (to.meta.hasOwnProperty('privilege') && !menus.includes(to.meta.privilege)) { |
| | | return |
| | | } |
| | | |
| | | // 设置标签列表 |
| | | if (!to.meta.hide || !to.meta.oneself) { |
| | |
| | | } |
| | | |
| | | next() |
| | | // } |
| | | } |
| | | }); |
| | | |
| | | export default router; |
| | |
| | | const apiConfig = { |
| | | // 开发环境 |
| | | development: { |
| | | baseURL: "", |
| | | baseURL: "http://192.168.110.34:8081", |
| | | imgUrl: "", |
| | | }, |
| | | // 生产环境 |
New file |
| | |
| | | import axios from 'axios' |
| | | import apiConfig from './baseurl' |
| | | |
| | | let encryptionKey = '2022lab02ora12to' // 默认密钥 |
| | | |
| | | // 从接口获取密钥 |
| | | export const fetchEncryptionKey = async () => { |
| | | try { |
| | | const response = await axios.get(`${apiConfig.baseURL}/api/system/getEncryptionKey`) |
| | | if (response.data && response.data.code === 200) { |
| | | // 转换为Buffer并验证字节长度 |
| | | const keyBuffer = Buffer.from(response.data.data, 'utf-8') |
| | | |
| | | if (keyBuffer.length !== 16) { |
| | | console.warn('无效密钥长度,使用默认密钥') |
| | | return encryptionKey // 保持原有密钥 |
| | | } |
| | | |
| | | // 存储原始字符串和Buffer两种格式 |
| | | encryptionKey = response.data.data |
| | | return encryptionKey |
| | | } |
| | | } catch (error) { |
| | | console.error('获取加密密钥失败:', error) |
| | | } |
| | | } |
| | | |
| | | // 新增方法获取Buffer格式的密钥 |
| | | export const getEncryptionKeyBuffer = () => { |
| | | return Buffer.from(encryptionKey, 'utf-8') |
| | | } |
| | | |
| | | // 获取当前密钥(保持字符串格式) |
| | | export const getEncryptionKey = () => encryptionKey |
| | |
| | | import axios from 'axios' |
| | | import apiConfig from './baseurl' |
| | | |
| | | import { |
| | | Message |
| | | } from 'element-ui' |
| | | |
| | | import { Message } from 'element-ui' |
| | | import { encryptBySM4, decryptBySM4 } from './sm4' // 添加decryptBySM4 |
| | | |
| | | const service = axios.create({ |
| | | baseURL: apiConfig.baseURL, |
| | | // baseURL: apiConfig.baseURL, |
| | | withCredentials: false, // 当跨域请求时发送cookie |
| | | timeout: 30000, // request timeout |
| | | }) |
| | |
| | | service.interceptors.request.use( |
| | | config => { |
| | | config['headers']['Authorization'] = `${sessionStorage.getItem('token')}` |
| | | |
| | | // 判断是否需要加密(只对/api开头的请求进行加密) |
| | | const needEncrypt = config.url.startsWith('/api'); |
| | | |
| | | if (config.method == 'get') { |
| | | if (!config.params) config.params = {}; |
| | | config.params = { |
| | |
| | | } |
| | | if (config.method == 'post') { |
| | | if (!config.data) config.data = {}; |
| | | config.data = { |
| | | ...config.data, |
| | | if (needEncrypt) { |
| | | config.data = { param: encryptBySM4(config.data) }; |
| | | } |
| | | } |
| | | return config |
| | |
| | | return |
| | | } |
| | | const res = response; |
| | | |
| | | // 新增解密处理:仅处理/api路径的POST响应 |
| | | if (res.config.method === 'post' && res.config.url.startsWith('/api')) { |
| | | try { |
| | | if (res.data && res.data.data) { |
| | | // 这里假设使用decryptBySM4进行解密 |
| | | res.data.data = decryptBySM4(res.data.data); |
| | | } |
| | | } catch (e) { |
| | | console.error('数据解密失败:', e); |
| | | } |
| | | } |
| | | |
| | | if (res.data.code == 200) { |
| | | if (!res.data.data) { |
| | | if (!res.data) { |
| | | return Promise.resolve({}) |
| | | } |
| | | return Promise.resolve(res.data.data) |
| | | return Promise.resolve(res.data) |
| | | } else { |
| | | if (res.data.code == 103 || res.data.code == 401) { |
| | | Message({ |
New file |
| | |
| | | import { sm4 } from 'sm-crypto'; |
| | | import { getEncryptionKey, fetchEncryptionKey, getEncryptionKeyBuffer } from './encryption'; |
| | | |
| | | // SM4加密函数 |
| | | export const encryptBySM4 = (data) => { |
| | | const key = getEncryptionKeyBuffer(); // 获取当前密钥 |
| | | return sm4.encrypt(JSON.stringify(data), key); |
| | | }; |
| | | |
| | | // SM4解密函数 |
| | | export const decryptBySM4 = (data) => { |
| | | const key = getEncryptionKeyBuffer(); // 获取当前密钥 |
| | | return JSON.parse(sm4.decrypt(data, key)); |
| | | }; |
| | |
| | | <div class="login-form"> |
| | | <div class="form-item flex"> |
| | | <img class="form-item-icon" :src="require('../../assets/login/account@2x.png')" alt=""> |
| | | <el-input v-model="loginForm.account" placeholder="请输入账号"></el-input> |
| | | <el-input v-model="loginForm.username" placeholder="请输入账号"></el-input> |
| | | </div> |
| | | |
| | | <div class="form-item flex mt-40"> |
| | |
| | | </div> |
| | | </template> |
| | | <script> |
| | | import { loginReq } from './service' |
| | | export default { |
| | | name: 'Login', |
| | | data() { |
| | |
| | | windowWidth: window.innerWidth, |
| | | |
| | | loginForm: { |
| | | account: '', |
| | | username: '', |
| | | password: '' |
| | | }, |
| | | viewWidth: '', |
| | |
| | | console.log(this.viewWidth) |
| | | }, |
| | | login() { |
| | | if (this.loginForm.username == '') { |
| | | this.$message.warning('请输入账号') |
| | | return |
| | | } |
| | | if (this.loginForm.password == '') { |
| | | this.$message.warning('请输入密码') |
| | | return |
| | | } |
| | | loginReq(this.loginForm).then(res => { |
| | | sessionStorage.setItem('token', res.token) |
| | | sessionStorage.setItem('userInfo', JSON.stringify(res.userInfo.user)) |
| | | this.$router.push('/') |
| | | console.log(this.loginForm) |
| | | }) |
| | | } |
| | | } |
| | | } |
| | |
| | | import axios from '@/utils/request'; |
| | | |
| | | // 登录 |
| | | export const login = (data) => { |
| | | export const loginReq = (data) => { |
| | | return axios.post('/login', { ...data }) |
| | | } |
| | |
| | | <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <template #search> |
| | | <el-form :model="form" label-width="140px" inline> |
| | | <el-form label-width="140px" inline> |
| | | <el-form-item label="项目组名称:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | <el-input v-model="queryForm.name" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="项目负责人:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | <el-input v-model="queryForm.name" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="创建日期:"> |
| | | <el-date-picker v-model="value1" type="daterange" range-separator="至" start-placeholder="开始日期" |
| | | end-placeholder="结束日期"> |
| | | <el-date-picker v-model="queryForm.createdDate" type="daterange" range-separator="至" |
| | | start-placeholder="开始日期" end-placeholder="结束日期"> |
| | | </el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item class="search-btn-box"> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { getProjectList } from './service' |
| | | export default { |
| | | name: 'ProjectList', |
| | | data() { |
| | | return { |
| | | form: { |
| | | name: '' |
| | | }, |
| | | showDelConfirm: false, |
| | | rowId: '', |
| | | changeStatus: false, |
| | |
| | | }, |
| | | total: 0 |
| | | } |
| | | }, |
| | | created() { |
| | | this.getList() |
| | | }, |
| | | methods: { |
| | | handleAddProject() { |
| | |
| | | this.getList() |
| | | }, |
| | | getList() { |
| | | |
| | | getProjectList(this.queryForm).then(res => { |
| | | console.log(res); |
| | | }) |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | import axios from '@/utils/request'; |
| | | |
| | | // 列表 |
| | | export const getProjectList = (data) => { |
| | | return axios.post('/api/t-project-team/pageList', { ...data }) |
| | | } |
| | |
| | | return path.join(__dirname, dir) |
| | | } |
| | | module.exports = { |
| | | outputDir: 'laboratory', // 配置打包后的文件夹名称 |
| | | outputDir: 'culture', // 配置打包后的文件夹名称 |
| | | lintOnSave: false, |
| | | publicPath: '/', |
| | | devServer: { |
| | | disableHostCheck: true, //禁用主机检查 |
| | | proxy: { |
| | | "/api": { // 设置以什么前缀开头的请求用来代理 |
| | | target: "http://localhost:8080", //要访问的跨域的域名 |
| | | target: "http://192.168.110.34:8081", //要访问的跨域的域名 |
| | | secure: false, // 使用的是http协议则设置为false,https协议则设置为true |
| | | changOrigin: true, //开启代理 |
| | | pathRewrite: { |
| | | "^/api": "", |
| | | "^/api": "/api", |
| | | }, |
| | | }, |
| | | }, |