卫星通信服务平台
39
.gitignore
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
coverage
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Cypress
|
||||||
|
/cypress/videos/
|
||||||
|
/cypress/screenshots/
|
||||||
|
|
||||||
|
# Vitest
|
||||||
|
__screenshots__/
|
||||||
|
|
||||||
|
# Vite
|
||||||
|
*.timestamp-*-*.mjs
|
||||||
38
README.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# tqxz-sn-message-platform
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 in Vite.
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||||
|
|
||||||
|
## Recommended Browser Setup
|
||||||
|
|
||||||
|
- Chromium-based browsers (Chrome, Edge, Brave, etc.):
|
||||||
|
- [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
|
||||||
|
- [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
|
||||||
|
- Firefox:
|
||||||
|
- [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
|
||||||
|
- [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
|
||||||
|
|
||||||
|
## Customize configuration
|
||||||
|
|
||||||
|
See [Vite Configuration Reference](https://vite.dev/config/).
|
||||||
|
|
||||||
|
## Project Setup
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile and Hot-Reload for Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compile and Minify for Production
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
52
index.html
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="w-h-full">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="icon" href="/favicon.ico">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>北斗启航科技教育平台</title>
|
||||||
|
<style>
|
||||||
|
/* 当屏幕宽度大于或等于3000px时 */
|
||||||
|
@media (min-width: 3000px) {
|
||||||
|
html {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当屏幕宽度在1920px到2999px之间时 */
|
||||||
|
@media (min-width: 1920px) and (max-width: 2999px) {
|
||||||
|
html {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当屏幕宽度在750px到1919px之间时 */
|
||||||
|
@media (min-width: 750px) and (max-width: 1919px) {
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当屏幕宽度在600px到749px之间时 */
|
||||||
|
@media (min-width: 600px) and (max-width: 749px) {
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 当屏幕宽度小于600px时 */
|
||||||
|
@media (max-width: 599px) {
|
||||||
|
html {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="w-h-full">
|
||||||
|
<div id="app" class="w-h-full text-white"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
8
jsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
50
package.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "tqxz-sn-message-platform",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite --port=7022",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
|
"axios": "^1.6.8",
|
||||||
|
"core-js": "^3.37.0",
|
||||||
|
"crypto-js": "^4.2.0",
|
||||||
|
"element-plus": "^2.7.8",
|
||||||
|
"fingerprintjs2": "^2.1.4",
|
||||||
|
"gbk.js": "^0.3.0",
|
||||||
|
"moment": "^2.30.1",
|
||||||
|
"pinia": "^3.0.4",
|
||||||
|
"pinia-plugin-persist": "^1.0.0",
|
||||||
|
"socket.io-client": "^4.8.0",
|
||||||
|
"terser": "^5.31.5",
|
||||||
|
"vue": "^3.5.29",
|
||||||
|
"vue-i18n": "^9.13.1",
|
||||||
|
"vue-router": "^5.0.3",
|
||||||
|
"zipson": "^0.2.12"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/pluginutils": "^5.3.0",
|
||||||
|
"@vitejs/plugin-legacy": "^5.4.1",
|
||||||
|
"@vitejs/plugin-vue": "^6.0.4",
|
||||||
|
"autoprefixer": "^10.4.19",
|
||||||
|
"esbuild": "^0.27.3",
|
||||||
|
"install": "^0.13.0",
|
||||||
|
"minimatch": "^10.2.4",
|
||||||
|
"npm": "^11.11.0",
|
||||||
|
"postcss": "^8.4.40",
|
||||||
|
"rollup": "^4.59.0",
|
||||||
|
"tailwindcss": "^3.4.7",
|
||||||
|
"unimport": "^6.0.1",
|
||||||
|
"unplugin-auto-import": "^0.17.5",
|
||||||
|
"unplugin-vue-components": "^0.27.0",
|
||||||
|
"vite": "^7.3.1",
|
||||||
|
"vite-plugin-vue-devtools": "^8.0.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
11
src/App.vue
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<script setup>
|
||||||
|
import { RouterView } from 'vue-router'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<RouterView />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
118
src/api/index.js
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import $url from "./url";
|
||||||
|
import router from "../router";
|
||||||
|
import { encrypt } from "../utils/aes";
|
||||||
|
|
||||||
|
// 添加请求拦截器
|
||||||
|
axios.interceptors.request.use(function (config) {
|
||||||
|
// 在发送请求之前做些什么
|
||||||
|
if (config.headers) {
|
||||||
|
config.headers.uid = localStorage.data;
|
||||||
|
if (localStorage.access_token && localStorage.access_token !== "" && localStorage.access_token !== null && localStorage.access_token !== undefined && localStorage.access_token !== NaN) {
|
||||||
|
config.headers.authorization = localStorage.access_token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}, function (error) {
|
||||||
|
// 对请求错误做些什么
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 转到登录页面
|
||||||
|
const toLogin = () => {
|
||||||
|
localStorage.clear();
|
||||||
|
const data = { origin_url: window.location.href };
|
||||||
|
axios.post($url.toLogin, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
window.location.href = res.data.redirect;
|
||||||
|
} else {
|
||||||
|
router.push({ path: '/404page' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加响应拦截器
|
||||||
|
let result = true;
|
||||||
|
axios.interceptors.response.use(function (response) {
|
||||||
|
// 2xx 范围内的状态码都会触发该函数。
|
||||||
|
// 对响应数据做点什么
|
||||||
|
if (response.data.code === 200) {
|
||||||
|
if ("access_token" in response.data) {
|
||||||
|
localStorage.setItem("access_token", response.data.access_token);
|
||||||
|
}
|
||||||
|
if ("refresh_token" in response.data) {
|
||||||
|
localStorage.setItem("refresh_token", response.data.refresh_token);
|
||||||
|
}
|
||||||
|
if ("data" in response.data) {
|
||||||
|
localStorage.setItem("data", response.data.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if (response.data.code === 302) {
|
||||||
|
// localStorage.clear();
|
||||||
|
// //转到主页
|
||||||
|
// router.push({ path: '/main' });
|
||||||
|
// }
|
||||||
|
if(response.data.code === 401 && result) {
|
||||||
|
result = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
result = true;
|
||||||
|
}, 1000);
|
||||||
|
let getCode = window.location.href.indexOf('?');
|
||||||
|
if (getCode != '-1') {
|
||||||
|
let code = window.location.href.substring(getCode + 1);
|
||||||
|
const data = {
|
||||||
|
code: code,
|
||||||
|
type: encrypt('code')
|
||||||
|
};
|
||||||
|
axios.post($url.getToken, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
localStorage.setItem("data", res.data.data);
|
||||||
|
localStorage.setItem("access_token", res.data.access_token);
|
||||||
|
localStorage.setItem("refresh_token", res.data.refresh_token);
|
||||||
|
window.location.href = res.data.redirect;
|
||||||
|
} else {
|
||||||
|
toLogin();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (localStorage.refresh_token && localStorage.refresh_token !== "" && localStorage.refresh_token !== null && localStorage.refresh_token !== undefined && localStorage.refresh_token !== NaN) {
|
||||||
|
const data = {
|
||||||
|
code: localStorage.refresh_token,
|
||||||
|
type: localStorage.data
|
||||||
|
};
|
||||||
|
axios.post($url.getToken, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
localStorage.setItem("data", res.data.data);
|
||||||
|
localStorage.setItem("access_token", res.data.access_token);
|
||||||
|
localStorage.setItem("refresh_token", res.data.refresh_token);
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
toLogin();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toLogin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}, function (error) {
|
||||||
|
// 超出 2xx 范围的状态码都会触发该函数。
|
||||||
|
// 对响应错误做点什么
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
get(url, query = {}) {
|
||||||
|
return axios.get(url, {
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
},
|
||||||
|
post(url, body) {
|
||||||
|
return axios.post(url, body);
|
||||||
|
},
|
||||||
|
put(url, body) {
|
||||||
|
return axios.put(url, body);
|
||||||
|
},
|
||||||
|
del(url) {
|
||||||
|
return axios.delete(url);
|
||||||
|
},
|
||||||
|
}
|
||||||
44
src/api/url.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
export default {
|
||||||
|
// 用于确认哪个网页在进行登录
|
||||||
|
toLogin: "/authentication/toLogin",
|
||||||
|
// 退出登录
|
||||||
|
unLogin: "/authentication/unLogin",
|
||||||
|
// 用于获取token
|
||||||
|
getToken: "/authentication/getToken",
|
||||||
|
// 用于验证token
|
||||||
|
verify: "/authentication/verify",
|
||||||
|
// 获取用户基本信息
|
||||||
|
getUser: "/authentication/getUser",
|
||||||
|
// 修改用户基本信息
|
||||||
|
editUser: "/authentication/editUser",
|
||||||
|
// B端单位管理员编辑用户基本信息
|
||||||
|
editUserManager: "/authentication/editUserManager",
|
||||||
|
// 修改密码
|
||||||
|
changePassword: "/authentication/changePassword",
|
||||||
|
// 重置密码
|
||||||
|
resetPassword: "/authentication/resetPassword",
|
||||||
|
// 获取sn号
|
||||||
|
getSN: "/snShortMessage/getSN",
|
||||||
|
// 搜索sn号
|
||||||
|
searchSN: "/snShortMessage/searchSN",
|
||||||
|
// 搜索可绑定的SN号
|
||||||
|
searchBindSN: "/snShortMessage/searchBindSN",
|
||||||
|
// 搜索可绑定的单位用户
|
||||||
|
searchBindUser: "/snShortMessage/searchBindUser",
|
||||||
|
// 绑定sn号
|
||||||
|
bindSN: "/snShortMessage/bindSN",
|
||||||
|
// 解绑sn号
|
||||||
|
unBindingSN: "/snShortMessage/unBindingSN",
|
||||||
|
// 获取绑定记录
|
||||||
|
getRecord: "/snShortMessage/getRecord",
|
||||||
|
// 获取历史消息
|
||||||
|
getHistoryMsg: "/snShortMessage/getHistoryMsg",
|
||||||
|
// 删除历史消息
|
||||||
|
delHistoryMsg: "/snShortMessage/delHistoryMsg",
|
||||||
|
// 获取单位用户
|
||||||
|
bsideUserManager: "/snShortMessage/bsideUserManager",
|
||||||
|
// 获取可管理的SN号
|
||||||
|
bsideSNManager: "/snShortMessage/bsideSNManager",
|
||||||
|
// webSocket服务端地址
|
||||||
|
snWebSocket: "/snWebSocket/",
|
||||||
|
}
|
||||||
86
src/assets/base.css
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/* color palette from <https://github.com/vuejs/theme> */
|
||||||
|
:root {
|
||||||
|
--vt-c-white: #ffffff;
|
||||||
|
--vt-c-white-soft: #f8f8f8;
|
||||||
|
--vt-c-white-mute: #f2f2f2;
|
||||||
|
|
||||||
|
--vt-c-black: #181818;
|
||||||
|
--vt-c-black-soft: #222222;
|
||||||
|
--vt-c-black-mute: #282828;
|
||||||
|
|
||||||
|
--vt-c-indigo: #2c3e50;
|
||||||
|
|
||||||
|
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||||
|
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||||
|
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||||
|
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||||
|
|
||||||
|
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||||
|
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||||
|
--vt-c-text-dark-1: var(--vt-c-white);
|
||||||
|
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* semantic color variables for this project */
|
||||||
|
:root {
|
||||||
|
--color-background: var(--vt-c-white);
|
||||||
|
--color-background-soft: var(--vt-c-white-soft);
|
||||||
|
--color-background-mute: var(--vt-c-white-mute);
|
||||||
|
|
||||||
|
--color-border: var(--vt-c-divider-light-2);
|
||||||
|
--color-border-hover: var(--vt-c-divider-light-1);
|
||||||
|
|
||||||
|
--color-heading: var(--vt-c-text-light-1);
|
||||||
|
--color-text: var(--vt-c-text-light-1);
|
||||||
|
|
||||||
|
--section-gap: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--color-background: var(--vt-c-black);
|
||||||
|
--color-background-soft: var(--vt-c-black-soft);
|
||||||
|
--color-background-mute: var(--vt-c-black-mute);
|
||||||
|
|
||||||
|
--color-border: var(--vt-c-divider-dark-2);
|
||||||
|
--color-border-hover: var(--vt-c-divider-dark-1);
|
||||||
|
|
||||||
|
--color-heading: var(--vt-c-text-dark-1);
|
||||||
|
--color-text: var(--vt-c-text-dark-2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
|
color: var(--color-text);
|
||||||
|
background: var(--color-background);
|
||||||
|
transition:
|
||||||
|
color 0.5s,
|
||||||
|
background-color 0.5s;
|
||||||
|
line-height: 1.6;
|
||||||
|
font-family:
|
||||||
|
Inter,
|
||||||
|
-apple-system,
|
||||||
|
BlinkMacSystemFont,
|
||||||
|
'Segoe UI',
|
||||||
|
Roboto,
|
||||||
|
Oxygen,
|
||||||
|
Ubuntu,
|
||||||
|
Cantarell,
|
||||||
|
'Fira Sans',
|
||||||
|
'Droid Sans',
|
||||||
|
'Helvetica Neue',
|
||||||
|
sans-serif;
|
||||||
|
font-size: 15px;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
BIN
src/assets/favicon.ico
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
src/assets/img/Q&A/showType.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/img/Q&A/tabelTools.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src/assets/img/Q&A/toolsClick.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
src/assets/img/Q&A/toolsSelect.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
src/assets/img/code/changeMode.png
Normal file
|
After Width: | Height: | Size: 1006 B |
BIN
src/assets/img/code/codeGuide.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
src/assets/img/code/codeScience.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/assets/img/code/codeType.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/img/code/fontGuide.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
src/assets/img/code/showType.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/img/code/transCode.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
src/assets/img/code/transFont.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
src/assets/img/header/headerGuide.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
src/assets/img/header/headerSelect.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
src/assets/img/manager/operateSelect.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
src/assets/img/manager/operateType.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
src/assets/img/msg/msg.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
src/assets/img/msg/operateSelect.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
src/assets/img/msg/operateType.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src/assets/img/msg/showMsg.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
src/assets/img/xor/errorMsg.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/assets/img/xor/input.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
src/assets/img/xor/xor.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
src/assets/img/xor/xorGuide.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
src/assets/logo.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
1
src/assets/logo.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
||||||
|
After Width: | Height: | Size: 276 B |
9
src/assets/main.css
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.w-h-full {
|
||||||
|
@apply w-full h-full m-0 p-0 overflow-hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/assets/qrcode.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
115
src/components/calculationXOR/calculationXOR.vue
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="m-2 font-bold">
|
||||||
|
<el-text class="mx-1 font-bold"> 校验数据 : </el-text>
|
||||||
|
<el-input
|
||||||
|
v-model="check"
|
||||||
|
:style="style"
|
||||||
|
placeholder="请输入将要校验的数据"
|
||||||
|
clearable
|
||||||
|
@input="handleInput"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="m-2 font-bold">
|
||||||
|
<el-text> 校验结果(十六进制): {{ resultHex }} </el-text>
|
||||||
|
</div>
|
||||||
|
<div class="m-2 font-bold">
|
||||||
|
<el-text> 校验结果(十进制): {{ resultDec }} </el-text>
|
||||||
|
</div>
|
||||||
|
<div class="m-2 font-bold">
|
||||||
|
<el-text> 校验结果(二进制): {{ resultBin }} </el-text>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<el-button style="font-weight: bold; width: 25%;" type="primary" size="small" @click="calculation">
|
||||||
|
校验
|
||||||
|
</el-button>
|
||||||
|
<el-button style="font-weight: bold; width: 25%;" type="primary" size="small" @click="clear">
|
||||||
|
清除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const style = ref("width: 80%;");
|
||||||
|
const check = ref("");
|
||||||
|
const resultHex = ref("");
|
||||||
|
const resultDec = ref("");
|
||||||
|
const resultBin = ref("");
|
||||||
|
|
||||||
|
const clear = () => {
|
||||||
|
style.value = "width: 80%";
|
||||||
|
check.value = "";
|
||||||
|
resultHex.value = "";
|
||||||
|
resultBin.value = "";
|
||||||
|
resultDec.value = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
// 判断字符是否为简体汉字
|
||||||
|
const isChinese = (s) => {
|
||||||
|
return /[\u4e00-\u9fa5]/.test(s);
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputFilter = (inputData) => {
|
||||||
|
let infilter = [];
|
||||||
|
inputData.forEach((item) => {
|
||||||
|
if (!isChinese(item)) {
|
||||||
|
infilter.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return infilter.join("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInput = () => {
|
||||||
|
check.value = inputFilter(check.value.split(""));
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkit = (acheck) => {
|
||||||
|
let checkArr = acheck.split("");
|
||||||
|
let resultBox;
|
||||||
|
checkArr.forEach((element) => {
|
||||||
|
if (resultBox == undefined) {
|
||||||
|
resultBox = element.charCodeAt();
|
||||||
|
} else {
|
||||||
|
resultBox = resultBox ^ element.charCodeAt();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let toOverHex, toOverDec, toOverBin;
|
||||||
|
toOverHex = resultBox.toString(16).toUpperCase();
|
||||||
|
if (resultBox.toString(16).toUpperCase().length < 2) {
|
||||||
|
toOverHex = "0" + toOverHex;
|
||||||
|
}
|
||||||
|
toOverDec = resultBox.toString().toUpperCase();
|
||||||
|
if (resultBox.toString().toUpperCase().length < 2) {
|
||||||
|
toOverDec = "0" + toOverDec;
|
||||||
|
}
|
||||||
|
toOverBin = resultBox.toString(2);
|
||||||
|
if (resultBox.toString(2).length < 8) {
|
||||||
|
for (let i = 0; i < 8 - resultBox.toString(2).length; i++) {
|
||||||
|
toOverBin = "0" + toOverBin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { hex: toOverHex, dec: toOverDec, bin: toOverBin };
|
||||||
|
};
|
||||||
|
|
||||||
|
const calculation = () => {
|
||||||
|
resultHex.value = "";
|
||||||
|
resultBin.value = "";
|
||||||
|
resultDec.value = "";
|
||||||
|
if (check.value == "") {
|
||||||
|
style.value = "width: 80%; border-width: 2px; border-color: rgb(239 68 68);";
|
||||||
|
ElMessage.error("校验数据不能为空");
|
||||||
|
} else {
|
||||||
|
const { hex, dec, bin } = checkit(check.value);
|
||||||
|
style.value = "width: 80%;";
|
||||||
|
resultHex.value = hex;
|
||||||
|
resultDec.value = dec;
|
||||||
|
resultBin.value = bin;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
239
src/components/features/bindSN.vue
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card-container">
|
||||||
|
<div class="top-block">
|
||||||
|
<div class="info-block">
|
||||||
|
<el-card class="box-card unbind-users">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>用户ID</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-tag v-show="selectedUser !== ''" type="info" effect="dark">
|
||||||
|
{{ selectedUser }}
|
||||||
|
</el-tag>
|
||||||
|
</el-card>
|
||||||
|
<el-card class="box-card unbind-sn">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>SN号</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-tag v-show="selectedSN !== ''" type="info" effect="dark">
|
||||||
|
{{ selectedSN }}
|
||||||
|
</el-tag>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
<el-button class="bind-button" type="primary" @click="bindSN">确认绑定</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="content-block">
|
||||||
|
<el-card class="box-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>未绑定的用户</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="unbind-users">
|
||||||
|
<el-tag
|
||||||
|
v-for="user in unbindUsers"
|
||||||
|
:key="user"
|
||||||
|
type="info"
|
||||||
|
class="user-tag"
|
||||||
|
:effect="user === selectedUser ? 'dark' : 'plain'"
|
||||||
|
@click="selectUser(user)"
|
||||||
|
>
|
||||||
|
{{ user }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<el-card class="box-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>未绑定的SN号</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="unbind-sn">
|
||||||
|
<el-tag
|
||||||
|
v-for="sn in unbindSN"
|
||||||
|
:key="sn"
|
||||||
|
type="info"
|
||||||
|
class="sn-tag"
|
||||||
|
:effect="sn === selectedSN ? 'dark' : 'plain'"
|
||||||
|
@click="selectSN(sn)"
|
||||||
|
>
|
||||||
|
{{ sn }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, nextTick } from "vue";
|
||||||
|
import { ElCard, ElButton, ElTag, ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
import bindSNActiveStore from "../../stores/bindSN";
|
||||||
|
|
||||||
|
const bindSNActive = bindSNActiveStore();
|
||||||
|
|
||||||
|
const selectedUser = ref("");
|
||||||
|
const selectedSN = ref("");
|
||||||
|
const unbindUsers = ref([]);
|
||||||
|
const userObj = ref({});
|
||||||
|
const unbindSN = ref([]);
|
||||||
|
|
||||||
|
const selectUser = (user) => {
|
||||||
|
selectedUser.value = user;
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectSN = (sn) => {
|
||||||
|
selectedSN.value = sn;
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetCheckForm = () => {
|
||||||
|
selectedUser.value = "";
|
||||||
|
bindSNActive.selectedUser = "";
|
||||||
|
selectedSN.value = "";
|
||||||
|
bindSNActive.selectedSN = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchBindUser = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
$http.get($url.searchBindUser).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
res.data.result.forEach(element => {
|
||||||
|
unbindUsers.value.push(element.account_name);
|
||||||
|
userObj.value[element.account_name] = element.uid;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
unbindUsers.value = [];
|
||||||
|
resetCheckForm();
|
||||||
|
// ElMessage.error("未查找到相关数据!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchBindSN = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
$http.get($url.searchBindSN).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
res.data.result.forEach(element => {
|
||||||
|
unbindSN.value.push(element);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
unbindSN.value = [];
|
||||||
|
resetCheckForm();
|
||||||
|
// ElMessage.error("未查找到相关数据!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const bindSN = () => {
|
||||||
|
if (selectedUser.value === "" || selectedSN.value === "") {
|
||||||
|
ElMessage.warning("请选择用户和SN号!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
userUid: userObj.value[selectedUser.value],
|
||||||
|
snNumber: selectedSN.value,
|
||||||
|
};
|
||||||
|
$http.post($url.bindSN, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
resetCheckForm();
|
||||||
|
searchBindUser();
|
||||||
|
searchBindSN();
|
||||||
|
ElMessage({
|
||||||
|
message: "绑定成功!",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
unbindUsers.value = [];
|
||||||
|
unbindSN.value = [];
|
||||||
|
} else {
|
||||||
|
ElMessage.error("绑定失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
selectedUser.value = bindSNActive.selectedUser;
|
||||||
|
selectedSN.value = bindSNActive.selectedSN;
|
||||||
|
setTimeout(() => {
|
||||||
|
searchBindUser();
|
||||||
|
searchBindSN();
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.card-container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-block {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-block {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-card {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bind-button {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-block {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 20px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unbind-users,
|
||||||
|
.unbind-sn {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tag,
|
||||||
|
.sn-tag {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tag.effect-dark,
|
||||||
|
.sn-tag.effect-dark {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tag.effect-plain:hover,
|
||||||
|
.sn-tag.effect-plain:hover {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
color: #409eff;
|
||||||
|
border-color: #d9ecff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
453
src/components/features/bsideManager.vue
Normal file
@@ -0,0 +1,453 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<el-card>
|
||||||
|
<div class="flex justify-center flex-wrap">
|
||||||
|
<TabelTools @showTools="showTools" :dialogObj="bsideManagerActive" />
|
||||||
|
<el-table
|
||||||
|
ref="userTableRef"
|
||||||
|
:data="tableData"
|
||||||
|
row-key="account_name"
|
||||||
|
style="width: 100%"
|
||||||
|
max-height="32rem"
|
||||||
|
scrollbar-always-on
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
v-if="dialogOperationVisible"
|
||||||
|
fixed="left"
|
||||||
|
type="selection"
|
||||||
|
width="40"
|
||||||
|
column-key="selection"
|
||||||
|
/>
|
||||||
|
<TabelSelect
|
||||||
|
v-if="dialogOperationVisible"
|
||||||
|
ref="EditSelectRef"
|
||||||
|
:holderText="editSelectHold"
|
||||||
|
singleColor="primary"
|
||||||
|
multipleColor="warning"
|
||||||
|
allColor="danger"
|
||||||
|
singleSize="small"
|
||||||
|
multipleSize="small"
|
||||||
|
allSize="small"
|
||||||
|
:singlePlain="true"
|
||||||
|
:multiplePlain="false"
|
||||||
|
:allPlain="false"
|
||||||
|
operateType="edit"
|
||||||
|
@showComfirmDialog="showComfirmDialog"
|
||||||
|
/>
|
||||||
|
<TabelSelect
|
||||||
|
v-if="dialogOperationVisible"
|
||||||
|
ref="DefaultSelectRef"
|
||||||
|
:holderText="defaultSelectHold"
|
||||||
|
singleColor="danger"
|
||||||
|
multipleColor="warning"
|
||||||
|
allColor="danger"
|
||||||
|
singleSize="small"
|
||||||
|
multipleSize="small"
|
||||||
|
allSize="small"
|
||||||
|
:singlePlain="true"
|
||||||
|
:multiplePlain="false"
|
||||||
|
:allPlain="false"
|
||||||
|
operateType="default"
|
||||||
|
@showComfirmDialog="showComfirmDialog"
|
||||||
|
/>
|
||||||
|
<TabelSelect
|
||||||
|
v-if="dialogOperationVisible"
|
||||||
|
ref="ResetSelectRef"
|
||||||
|
:holderText="resetSelectHold"
|
||||||
|
singleColor="danger"
|
||||||
|
multipleColor="warning"
|
||||||
|
allColor="danger"
|
||||||
|
singleSize="small"
|
||||||
|
multipleSize="small"
|
||||||
|
allSize="small"
|
||||||
|
:singlePlain="true"
|
||||||
|
:multiplePlain="false"
|
||||||
|
:allPlain="false"
|
||||||
|
operateType="reset"
|
||||||
|
@showComfirmDialog="showComfirmDialog"
|
||||||
|
/>
|
||||||
|
<TabelSelect
|
||||||
|
v-if="dialogOperationVisible"
|
||||||
|
ref="unBindSNSelectRef"
|
||||||
|
:holderText="unBindSelectHold"
|
||||||
|
singleColor="danger"
|
||||||
|
multipleColor="warning"
|
||||||
|
allColor="danger"
|
||||||
|
singleSize="small"
|
||||||
|
multipleSize="small"
|
||||||
|
allSize="small"
|
||||||
|
:singlePlain="true"
|
||||||
|
:multiplePlain="false"
|
||||||
|
:allPlain="false"
|
||||||
|
operateType="unBindingSN"
|
||||||
|
@showComfirmDialog="showComfirmDialog"
|
||||||
|
/>
|
||||||
|
<el-table-column min-width="100" column-key="account_name">
|
||||||
|
<template #header>
|
||||||
|
<SearchKey
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SearchAccountKeyRef"
|
||||||
|
holderText="输入单位用户名以搜索相关数据"
|
||||||
|
@search="bsideManager"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 单位用户名 </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div>{{ scope.row.account_name }}</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="80" column-key="user_name">
|
||||||
|
<template #header>
|
||||||
|
<SearchKey
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SearchUserKeyRef"
|
||||||
|
holderText="输入用户姓名以搜索相关数据"
|
||||||
|
@search="bsideManager"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 用户姓名 </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div>{{ scope.row.user_name }}</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="120" column-key="phone">
|
||||||
|
<template #header>
|
||||||
|
<SearchKey
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SearchPhoneKeyRef"
|
||||||
|
holderText="输入用户手机号码以搜索相关数据"
|
||||||
|
@search="bsideManager"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 用户手机号码 </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div>{{ scope.row.phone }}</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<Pagination
|
||||||
|
ref="PaginationRef"
|
||||||
|
:active="bsideManagerActive"
|
||||||
|
@sizeChangeBack="changePage"
|
||||||
|
@search="bsideManager"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<EditBsideUser
|
||||||
|
ref="editBsideUserRef"
|
||||||
|
operateLabel="编辑信息"
|
||||||
|
@requestOperate="requestOperate"
|
||||||
|
/>
|
||||||
|
<PasswordOauth
|
||||||
|
ref="defaultPasswordOauthRef"
|
||||||
|
operateLabel="重置账号"
|
||||||
|
@requestOperate="requestOperate"
|
||||||
|
/>
|
||||||
|
<PasswordOauth
|
||||||
|
ref="resetPasswordOauthRef"
|
||||||
|
operateLabel="重置密码"
|
||||||
|
@requestOperate="requestOperate"
|
||||||
|
/>
|
||||||
|
<PasswordOauth
|
||||||
|
ref="unBindSNPasswordOauthRef"
|
||||||
|
operateLabel="解绑用户"
|
||||||
|
@requestOperate="requestOperate"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
import TabelTools from "../operate/tabelTools.vue";
|
||||||
|
import TabelSelect from "../operate/tabelSelect.vue";
|
||||||
|
import SearchKey from "../search/searchKey.vue";
|
||||||
|
import Pagination from "../search/pagination.vue";
|
||||||
|
import EditBsideUser from "../operate/editBsideUser.vue";
|
||||||
|
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||||
|
|
||||||
|
import bsideManagerActiveStore from "../../stores/bsideManager";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
import { encrypt } from "../../utils/aes";
|
||||||
|
import { judgment } from "../../utils/judgment.js";
|
||||||
|
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||||
|
|
||||||
|
const bsideManagerActive = bsideManagerActiveStore();
|
||||||
|
|
||||||
|
const editSelectHold = {
|
||||||
|
single: "编辑",
|
||||||
|
label: "编辑信息"
|
||||||
|
};
|
||||||
|
const EditSelectRef = ref(null);
|
||||||
|
const defaultSelectHold = {
|
||||||
|
single: "重置",
|
||||||
|
multiple: "重置选中",
|
||||||
|
all: "重置所有",
|
||||||
|
label: "重置账号"
|
||||||
|
};
|
||||||
|
const DefaultSelectRef = ref(null);
|
||||||
|
const resetSelectHold = {
|
||||||
|
single: "重置",
|
||||||
|
multiple: "重置选中",
|
||||||
|
all: "重置所有",
|
||||||
|
label: "重置密码"
|
||||||
|
};
|
||||||
|
const ResetSelectRef = ref(null);
|
||||||
|
const unBindSelectHold = {
|
||||||
|
single: "解绑",
|
||||||
|
multiple: "解绑选中",
|
||||||
|
all: "解绑所有",
|
||||||
|
label: "解绑用户"
|
||||||
|
};
|
||||||
|
const unBindSNSelectRef = ref(null);
|
||||||
|
const SearchAccountKeyRef = ref(null);
|
||||||
|
const SearchUserKeyRef = ref(null);
|
||||||
|
const SearchPhoneKeyRef = ref(null);
|
||||||
|
const PaginationRef = ref(null);
|
||||||
|
const editBsideUserRef = ref(null);
|
||||||
|
const defaultPasswordOauthRef = ref(null);
|
||||||
|
const resetPasswordOauthRef = ref(null);
|
||||||
|
const unBindSNPasswordOauthRef = ref(null);
|
||||||
|
const dialogSearchVisible = ref(false);
|
||||||
|
const dialogSortVisible = ref(false);
|
||||||
|
const dialogOperationVisible = ref(false);
|
||||||
|
const userTableRef = ref();
|
||||||
|
const offsetOff = ref(true);
|
||||||
|
const pageCount = ref(0);
|
||||||
|
const searchOptions = reactive({
|
||||||
|
account_name: "",
|
||||||
|
user_name: "",
|
||||||
|
phone: ""
|
||||||
|
});
|
||||||
|
const tableData = ref([]);
|
||||||
|
let operateData = reactive({});
|
||||||
|
let operateDataClone = reactive({});
|
||||||
|
const operate = ref("unBindingSN");
|
||||||
|
let singleData = reactive({});
|
||||||
|
|
||||||
|
const showTools = (operateType) => {
|
||||||
|
switch (operateType) {
|
||||||
|
case "search":
|
||||||
|
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||||
|
bsideManagerActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||||
|
break;
|
||||||
|
case "sort":
|
||||||
|
dialogSortVisible.value = !dialogSortVisible.value;
|
||||||
|
bsideManagerActive.dialogSortVisible = dialogSortVisible.value;
|
||||||
|
break;
|
||||||
|
case "operation":
|
||||||
|
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||||
|
bsideManagerActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const bsideManager = () => {
|
||||||
|
judgment(searchOptions, "account_name", SearchAccountKeyRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "user_name", SearchUserKeyRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "phone", SearchPhoneKeyRef.value, "searchMsg");
|
||||||
|
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||||
|
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||||
|
PaginationRef.value.handleCurrentChange(1);
|
||||||
|
offsetOff.value = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offsetOff.value = true;
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
uid: localStorage.data,
|
||||||
|
offset: PaginationRef.value.offset,
|
||||||
|
limit: PaginationRef.value.limit,
|
||||||
|
searchOptions: searchOptions,
|
||||||
|
};
|
||||||
|
$http.post($url.bsideUserManager, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
tableData.value = res.data.bsideUsers;
|
||||||
|
PaginationRef.value.dataCount = res.data.count;
|
||||||
|
pageCount.value = Math.ceil(
|
||||||
|
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||||
|
);
|
||||||
|
bsideManagerActive.dataCount = PaginationRef.value.dataCount;
|
||||||
|
bsideManagerActive.pageCount = pageCount.value;
|
||||||
|
if (!operateData[PaginationRef.value.offset]) return;
|
||||||
|
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||||
|
tableData.value.forEach((item) => {
|
||||||
|
if (item.account_name == element.account_name) {
|
||||||
|
nextTick(() => {
|
||||||
|
userTableRef.value.toggleRowSelection(item, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
tableData.value = [];
|
||||||
|
// ElMessage.error("未查找到相关数据!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changePage = (val) => {
|
||||||
|
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||||
|
operateData = {};
|
||||||
|
for (let i = 0; i < pageCount.value; i++) {
|
||||||
|
operateData[i + 1] = [];
|
||||||
|
for (const key in operateDataClone) {
|
||||||
|
operateDataClone[key].forEach((element) => {
|
||||||
|
// 判断数据在第几页
|
||||||
|
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||||
|
operateData[i + 1].push(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectionChange = (val) => {
|
||||||
|
operateData[PaginationRef.value.offset] = val;
|
||||||
|
tableData.value.forEach((item, index) => {
|
||||||
|
operateData[PaginationRef.value.offset].forEach((element) => {
|
||||||
|
if (item.account_name == element.account_name) {
|
||||||
|
// 数据在表格中的位置
|
||||||
|
element.location =
|
||||||
|
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
operateDataClone = JSON.parse(JSON.stringify(operateData));
|
||||||
|
};
|
||||||
|
|
||||||
|
const showComfirmDialog = (singleMsg) => {
|
||||||
|
singleData = singleMsg.data;
|
||||||
|
operate.value = singleMsg.operateType;
|
||||||
|
if (singleMsg.operateType == "edit") {
|
||||||
|
const { account_name, user_name, phone } = singleMsg.data;
|
||||||
|
editBsideUserRef.value.ruleForm.account_name = account_name;
|
||||||
|
editBsideUserRef.value.ruleForm.user_name = user_name;
|
||||||
|
editBsideUserRef.value.ruleForm.phone = phone;
|
||||||
|
editBsideUserRef.value.originMsg = { ...singleMsg.data };
|
||||||
|
editBsideUserRef.value.operateDialogVisible = true;
|
||||||
|
}
|
||||||
|
if (singleMsg.operateType == "default") {
|
||||||
|
defaultPasswordOauthRef.value.operateDialogVisible = true;
|
||||||
|
}
|
||||||
|
if (singleMsg.operateType == "reset") {
|
||||||
|
resetPasswordOauthRef.value.operateDialogVisible = true;
|
||||||
|
}
|
||||||
|
if (singleMsg.operateType == "unBindingSN") {
|
||||||
|
unBindSNPasswordOauthRef.value.operateDialogVisible = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const requestOperate = () => {
|
||||||
|
let operateType, url, model, defaultPassword, password;
|
||||||
|
if (operate.value == "edit") {
|
||||||
|
operateType = "编辑信息";
|
||||||
|
url = $url.editUserManager;
|
||||||
|
model = EditSelectRef.value.model;
|
||||||
|
} else if (operate.value == "default") {
|
||||||
|
operateType = "重置账号";
|
||||||
|
url = $url.resetPassword;
|
||||||
|
model = DefaultSelectRef.value.model;
|
||||||
|
defaultPassword = defaultPasswordOauthRef.value.ruleForm.defaultPassword;
|
||||||
|
password = defaultPasswordOauthRef.value.ruleForm.password;
|
||||||
|
} else if (operate.value == "reset") {
|
||||||
|
operateType = "重置密码";
|
||||||
|
url = $url.resetPassword;
|
||||||
|
model = ResetSelectRef.value.model;
|
||||||
|
defaultPassword = resetPasswordOauthRef.value.ruleForm.defaultPassword;
|
||||||
|
password = resetPasswordOauthRef.value.ruleForm.password;
|
||||||
|
} else if (operate.value == "unBindingSN") {
|
||||||
|
operateType = "解绑用户";
|
||||||
|
url = $url.unBindingSN;
|
||||||
|
model = unBindSNSelectRef.value.model;
|
||||||
|
password = unBindSNPasswordOauthRef.value.ruleForm.password;
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
uid: localStorage.data,
|
||||||
|
model: encrypt(model),
|
||||||
|
};
|
||||||
|
if(operate.value == "edit") {
|
||||||
|
data.editMsg = { ...editBsideUserRef.value.ruleForm };
|
||||||
|
data.userMsg = editBsideUserRef.value.originMsg;
|
||||||
|
} else {
|
||||||
|
data.password = encrypt(password);
|
||||||
|
data.userMsg = model == "single" ? singleData : model == "multiple" ? operateDataClone : "";
|
||||||
|
}
|
||||||
|
if(operate.value == "default" || operate.value == "reset") {
|
||||||
|
data.defaultPassword = encrypt(defaultPassword);
|
||||||
|
data.resetType = operate.value;
|
||||||
|
}
|
||||||
|
$http.post(url, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
userTableRef.value.clearSelection();
|
||||||
|
operateData = {};
|
||||||
|
operateDataClone = {};
|
||||||
|
ElMessage({
|
||||||
|
message: `${operateType}成功!`,
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
bsideManager();
|
||||||
|
} else {
|
||||||
|
ElMessage.error(`${operateType}失败!`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ bsideManager });
|
||||||
|
|
||||||
|
watch(searchOptions, (value) => {
|
||||||
|
bsideManagerActive.searchOptions = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
pageCount.value = bsideManagerActive.pageCount;
|
||||||
|
dialogSearchVisible.value = bsideManagerActive.dialogSearchVisible;
|
||||||
|
dialogSortVisible.value = bsideManagerActive.dialogSortVisible;
|
||||||
|
dialogOperationVisible.value = bsideManagerActive.dialogOperationVisible;
|
||||||
|
|
||||||
|
if (dialogSearchVisible.value) {
|
||||||
|
searchOptions.account_name = bsideManagerActive.searchOptions.account_name;
|
||||||
|
searchOptions.user_name = bsideManagerActive.searchOptions.user_name;
|
||||||
|
searchOptions.phone = bsideManagerActive.searchOptions.phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogSortVisible.value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogOperationVisible.value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
bsideManager();
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (dialogSearchVisible.value) {
|
||||||
|
SearchAccountKeyRef.value.searchMsg = bsideManagerActive.searchOptions.account_name;
|
||||||
|
SearchUserKeyRef.value.searchMsg = bsideManagerActive.searchOptions.user_name;
|
||||||
|
SearchPhoneKeyRef.value.searchMsg = bsideManagerActive.searchOptions.phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogSortVisible.value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogOperationVisible.value) {
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
458
src/components/features/historyMsg.vue
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<el-card>
|
||||||
|
<div class="flex justify-center flex-wrap">
|
||||||
|
<TabelTools @showTools="showTools" :dialogObj="historyMsgActive" />
|
||||||
|
<el-table
|
||||||
|
ref="userTableRef"
|
||||||
|
:data="tableData"
|
||||||
|
style="width: 100%"
|
||||||
|
max-height="32rem"
|
||||||
|
table-layout="auto"
|
||||||
|
scrollbar-always-on
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
v-if="dialogOperationVisible"
|
||||||
|
fixed="left"
|
||||||
|
type="selection"
|
||||||
|
width="40"
|
||||||
|
column-key="selection"
|
||||||
|
/>
|
||||||
|
<TabelSelect
|
||||||
|
v-if="dialogOperationVisible"
|
||||||
|
ref="DelSelectRef"
|
||||||
|
:holderText="delSelectHold"
|
||||||
|
singleColor="danger"
|
||||||
|
multipleColor="warning"
|
||||||
|
allColor="danger"
|
||||||
|
singleSize="small"
|
||||||
|
multipleSize="small"
|
||||||
|
allSize="small"
|
||||||
|
:singlePlain="true"
|
||||||
|
:multiplePlain="false"
|
||||||
|
:allPlain="false"
|
||||||
|
operateType="del"
|
||||||
|
@showComfirmDialog="showComfirmDialog"
|
||||||
|
/>
|
||||||
|
<el-table-column min-width="100" column-key="sn_number">
|
||||||
|
<template #header>
|
||||||
|
<div>
|
||||||
|
<SearchKey
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SearchCardIdKeyRef"
|
||||||
|
holderText="输入SN号以搜索相关数据"
|
||||||
|
@search="historyMsg"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> SN号 </el-text>
|
||||||
|
<SortSearch
|
||||||
|
v-if="dialogSortVisible"
|
||||||
|
ref="SortCardIdRef"
|
||||||
|
activeText="顺序"
|
||||||
|
inactiveText="倒序"
|
||||||
|
@search="historyMsg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
style="color: rgb(56, 188, 248);"
|
||||||
|
class="flex justify-start items-center text-base"
|
||||||
|
>
|
||||||
|
{{ scope.row.sn_number }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="200" width="720" column-key="original_msg">
|
||||||
|
<template #header>
|
||||||
|
<SearchKey
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SearchOriginalKeyRef"
|
||||||
|
holderText="输入关键字以搜索相关数据"
|
||||||
|
@search="historyMsg"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 原始数据 </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="flex justify-between items-center text-base">
|
||||||
|
<el-button
|
||||||
|
style="font-size: 1rem; font-weight: bold; margin-right: 1rem;"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{{ scope.row.original_msg.length/2 }}个字节
|
||||||
|
</el-button>
|
||||||
|
<el-text
|
||||||
|
truncated
|
||||||
|
:style="
|
||||||
|
scope.row.original_msg
|
||||||
|
? 'color: rgb(56, 188, 248);'
|
||||||
|
: 'color: rgb(240 70 70);'
|
||||||
|
"
|
||||||
|
style="font-size: 1rem"
|
||||||
|
>
|
||||||
|
{{ scope.row.original_msg ? scope.row.original_msg : "解析错误" }}
|
||||||
|
</el-text>
|
||||||
|
<el-button
|
||||||
|
style="font-size: 1rem; font-weight: bold"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
@click="showAll(scope.row.original_msg)"
|
||||||
|
>
|
||||||
|
展示全部内容
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="200" width="720" column-key="msg_data">
|
||||||
|
<template #header>
|
||||||
|
<SearchKey
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SearchDataKeyRef"
|
||||||
|
holderText="输入关键字以搜索相关数据"
|
||||||
|
@search="historyMsg"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 接收内容 </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="flex justify-between items-center text-base">
|
||||||
|
<el-text
|
||||||
|
truncated
|
||||||
|
:style="
|
||||||
|
scope.row.msg_data
|
||||||
|
? 'color: rgb(56, 188, 248);'
|
||||||
|
: 'color: rgb(240 70 70);'
|
||||||
|
"
|
||||||
|
style="font-size: 1rem"
|
||||||
|
>
|
||||||
|
{{ scope.row.msg_data ? scope.row.msg_data : "解析错误" }}
|
||||||
|
</el-text>
|
||||||
|
<el-button
|
||||||
|
style="font-size: 1rem; font-weight: bold"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
@click="showAll(scope.row.msg_data)"
|
||||||
|
>
|
||||||
|
展示全部内容
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="170" column-key="created_at">
|
||||||
|
<template #header>
|
||||||
|
<DateTimePicker
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="DateTimePickerRef"
|
||||||
|
DateTimePicker="historyMsgDateTimePicker"
|
||||||
|
@search="historyMsg"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 接收时间 </el-text>
|
||||||
|
<SortSearch
|
||||||
|
v-if="dialogSortVisible"
|
||||||
|
ref="SortDateTimeRef"
|
||||||
|
activeText="顺序"
|
||||||
|
inactiveText="倒序"
|
||||||
|
@search="historyMsg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
style="color: rgb(56, 188, 248);"
|
||||||
|
class="flex justify-start items-center text-base"
|
||||||
|
>
|
||||||
|
{{ scope.row.created_at }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<Pagination
|
||||||
|
ref="PaginationRef"
|
||||||
|
:active="historyMsgActive"
|
||||||
|
@sizeChangeBack="changePage"
|
||||||
|
@search="historyMsg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<DataShow ref="DataShowRef" />
|
||||||
|
<PasswordOauth
|
||||||
|
ref="PasswordOauthRef"
|
||||||
|
operateLabel="删除历史消息"
|
||||||
|
@requestOperate="requestOperate"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
import TabelTools from "../operate/tabelTools.vue";
|
||||||
|
import TabelSelect from "../operate/tabelSelect.vue";
|
||||||
|
import SearchKey from "../search/searchKey.vue";
|
||||||
|
import SortSearch from "../search/sortSearch.vue";
|
||||||
|
import SelectSearch from "../search/selectSearch.vue";
|
||||||
|
import DateTimePicker from "../search/dateTimePicker.vue";
|
||||||
|
import Pagination from "../search/pagination.vue";
|
||||||
|
import PasswordOauth from "../operate/passwordOauth.vue";
|
||||||
|
import DataShow from "../operate/dataShow.vue";
|
||||||
|
|
||||||
|
import historyMsgActiveStore from "../../stores/historyMsg";
|
||||||
|
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
import { encrypt } from "../../utils/aes";
|
||||||
|
import { judgment } from "../../utils/judgment.js";
|
||||||
|
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||||
|
|
||||||
|
const historyMsgActive = historyMsgActiveStore();
|
||||||
|
|
||||||
|
const delSelectHold = {
|
||||||
|
single: "删除",
|
||||||
|
multiple: "删除选中",
|
||||||
|
all: "删除所有",
|
||||||
|
label: "删除历史消息",
|
||||||
|
};
|
||||||
|
const DelSelectRef = ref(null);
|
||||||
|
const SearchCardIdKeyRef = ref(null);
|
||||||
|
const SortCardIdRef = ref(null);
|
||||||
|
const SortDateTimeRef = ref(null);
|
||||||
|
const SelectSearchRef = ref(null);
|
||||||
|
const SearchOriginalKeyRef = ref(null);
|
||||||
|
const SearchDataKeyRef = ref(null);
|
||||||
|
const DateTimePickerRef = ref(null);
|
||||||
|
const PaginationRef = ref(null);
|
||||||
|
const PasswordOauthRef = ref(null);
|
||||||
|
const DataShowRef = ref(null);
|
||||||
|
const dialogSearchVisible = ref(false);
|
||||||
|
const dialogSortVisible = ref(false);
|
||||||
|
const dialogOperationVisible = ref(false);
|
||||||
|
const userTableRef = ref();
|
||||||
|
const offsetOff = ref(true);
|
||||||
|
const pageCount = ref(0);
|
||||||
|
const searchOptions = reactive({
|
||||||
|
sn_number: "",
|
||||||
|
original_msg: "",
|
||||||
|
msg_data: "",
|
||||||
|
created_at: "",
|
||||||
|
});
|
||||||
|
const sortOptions = reactive({
|
||||||
|
sn_number: false,
|
||||||
|
created_at: false,
|
||||||
|
});
|
||||||
|
const tableData = ref([]);
|
||||||
|
let singleData = reactive({});
|
||||||
|
let delData = reactive({});
|
||||||
|
let delDataClone = reactive({});
|
||||||
|
|
||||||
|
const showAll = (msg) => {
|
||||||
|
DataShowRef.value.dialogMsg = msg;
|
||||||
|
DataShowRef.value.dialogVisible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const showTools = (operateType) => {
|
||||||
|
switch (operateType) {
|
||||||
|
case "search":
|
||||||
|
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||||
|
historyMsgActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||||
|
break;
|
||||||
|
case "sort":
|
||||||
|
dialogSortVisible.value = !dialogSortVisible.value;
|
||||||
|
historyMsgActive.dialogSortVisible = dialogSortVisible.value;
|
||||||
|
break;
|
||||||
|
case "operation":
|
||||||
|
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||||
|
historyMsgActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const historyMsg = () => {
|
||||||
|
judgment(searchOptions, "sn_number", SearchCardIdKeyRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "original_msg", SearchOriginalKeyRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "msg_data", SearchDataKeyRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "created_at", DateTimePickerRef.value, "searchMsg");
|
||||||
|
judgment(sortOptions, "sn_number", SortCardIdRef.value, "searchMsg");
|
||||||
|
judgment(sortOptions, "created_at", SortDateTimeRef.value, "searchMsg");
|
||||||
|
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||||
|
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||||
|
PaginationRef.value.handleCurrentChange(1);
|
||||||
|
offsetOff.value = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offsetOff.value = true;
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
uid: localStorage.data,
|
||||||
|
offset: PaginationRef.value.offset,
|
||||||
|
limit: PaginationRef.value.limit,
|
||||||
|
searchOptions: searchOptions,
|
||||||
|
sortOptions: sortOptions,
|
||||||
|
};
|
||||||
|
$http.post($url.getHistoryMsg, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
tableData.value = res.data.historyMsg;
|
||||||
|
tableData.value.forEach((item) => {
|
||||||
|
item.origin_time = item.created_at;
|
||||||
|
item.created_at = moment
|
||||||
|
.utc(item.created_at)
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
});
|
||||||
|
PaginationRef.value.dataCount = res.data.count;
|
||||||
|
historyMsgActive.dataCount = PaginationRef.value.dataCount;
|
||||||
|
pageCount.value = Math.ceil(
|
||||||
|
PaginationRef.value.dataCount / PaginationRef.value.limit
|
||||||
|
);
|
||||||
|
historyMsgActive.pageCount = pageCount.value;
|
||||||
|
if (!delData[PaginationRef.value.offset]) return;
|
||||||
|
delData[PaginationRef.value.offset].forEach((element) => {
|
||||||
|
tableData.value.forEach((item) => {
|
||||||
|
if (item.created_at == element.created_at) {
|
||||||
|
nextTick(() => {
|
||||||
|
userTableRef.value.toggleRowSelection(item, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
tableData.value = [];
|
||||||
|
// ElMessage.error("未查找到相关数据!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changePage = (val) => {
|
||||||
|
pageCount.value = Math.ceil(PaginationRef.value.dataCount / val);
|
||||||
|
delData = {};
|
||||||
|
for (let i = 0; i < pageCount.value; i++) {
|
||||||
|
delData[i + 1] = [];
|
||||||
|
for (const key in delDataClone) {
|
||||||
|
delDataClone[key].forEach((element) => {
|
||||||
|
// 判断数据在第几页
|
||||||
|
if (Math.ceil(element.location / PaginationRef.value.limit) == i + 1) {
|
||||||
|
delData[i + 1].push(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectionChange = (val) => {
|
||||||
|
delData[PaginationRef.value.offset] = val;
|
||||||
|
tableData.value.forEach((item, index) => {
|
||||||
|
delData[PaginationRef.value.offset].forEach((element) => {
|
||||||
|
if (item.created_at == element.created_at) {
|
||||||
|
// 数据在表格中的位置
|
||||||
|
element.location =
|
||||||
|
(PaginationRef.value.offset - 1) * PaginationRef.value.limit + (index + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
delDataClone = JSON.parse(JSON.stringify(delData));
|
||||||
|
};
|
||||||
|
|
||||||
|
const showComfirmDialog = (singleMsg) => {
|
||||||
|
singleData = singleMsg.data;
|
||||||
|
PasswordOauthRef.value.operateDialogVisible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const requestOperate = () => {
|
||||||
|
const data = {
|
||||||
|
uid: localStorage.data,
|
||||||
|
model: encrypt(DelSelectRef.value.model),
|
||||||
|
password: encrypt(PasswordOauthRef.value.ruleForm.password),
|
||||||
|
userMsg:
|
||||||
|
DelSelectRef.value.model == "single"
|
||||||
|
? singleData
|
||||||
|
: DelSelectRef.value.model == "multiple"
|
||||||
|
? delDataClone
|
||||||
|
: "",
|
||||||
|
};
|
||||||
|
$http.post($url.delHistoryMsg, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
userTableRef.value.clearSelection();
|
||||||
|
delData = {};
|
||||||
|
delDataClone = {};
|
||||||
|
ElMessage({
|
||||||
|
message: "操作成功!",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
historyMsg();
|
||||||
|
} else {
|
||||||
|
ElMessage.error("操作失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ historyMsg });
|
||||||
|
|
||||||
|
watch(searchOptions, (value) => {
|
||||||
|
historyMsgActive.searchOptions = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(sortOptions, (value) => {
|
||||||
|
historyMsgActive.sortOptions = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
pageCount.value = historyMsgActive.pageCount;
|
||||||
|
dialogSearchVisible.value = historyMsgActive.dialogSearchVisible;
|
||||||
|
dialogSortVisible.value = historyMsgActive.dialogSortVisible;
|
||||||
|
dialogOperationVisible.value = historyMsgActive.dialogOperationVisible;
|
||||||
|
|
||||||
|
if (dialogSearchVisible.value) {
|
||||||
|
searchOptions.sn_number = historyMsgActive.searchOptions.sn_number;
|
||||||
|
searchOptions.original_msg = historyMsgActive.searchOptions.original_msg;
|
||||||
|
searchOptions.msg_data = historyMsgActive.searchOptions.msg_data;
|
||||||
|
searchOptions.created_at = historyMsgActive.searchOptions.created_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogSortVisible.value) {
|
||||||
|
sortOptions.sn_number = historyMsgActive.sortOptions.sn_number;
|
||||||
|
sortOptions.created_at = historyMsgActive.sortOptions.created_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogOperationVisible.value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
historyMsg();
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (dialogSearchVisible.value) {
|
||||||
|
SearchCardIdKeyRef.value.searchMsg = historyMsgActive.searchOptions.sn_number;
|
||||||
|
SearchOriginalKeyRef.value.searchMsg = historyMsgActive.searchOptions.original_msg;
|
||||||
|
SearchDataKeyRef.value.searchMsg = historyMsgActive.searchOptions.msg_data;
|
||||||
|
DateTimePickerRef.value.created_at = historyMsgActive.searchOptions.created_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogSortVisible.value) {
|
||||||
|
SortCardIdRef.value.searchMsg = historyMsgActive.sortOptions.sn_number;
|
||||||
|
SortDateTimeRef.value.searchMsg = historyMsgActive.sortOptions.created_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogOperationVisible.value) {
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
302
src/components/features/record.vue
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
<template>
|
||||||
|
<el-card>
|
||||||
|
<div class="flex justify-center flex-wrap">
|
||||||
|
<TabelTools @showTools="showTools" :dialogObj="recordActive" />
|
||||||
|
<!-- 表格 -->
|
||||||
|
<el-table
|
||||||
|
:data="tableData"
|
||||||
|
style="width: 100%"
|
||||||
|
max-height="400"
|
||||||
|
table-layout="auto"
|
||||||
|
scrollbar-always-on
|
||||||
|
>
|
||||||
|
<el-table-column min-width="100" column-key="account_name">
|
||||||
|
<template #header>
|
||||||
|
<SearchKey
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SearchAccountNameKeyRef"
|
||||||
|
holderText="输入单位用户名以搜索相关数据"
|
||||||
|
@search="bsideManager"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 单位用户名 </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
:style="styleShunt(options, scope.row.type)"
|
||||||
|
class="flex justify-start items-center text-base"
|
||||||
|
>
|
||||||
|
{{ scope.row.account_name }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="100" column-key="sn_number">
|
||||||
|
<template #header>
|
||||||
|
<SearchKey
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SearchSNNumberKeyRef"
|
||||||
|
holderText="输入SN号以搜索相关数据"
|
||||||
|
@search="getRecord"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> SN号 </el-text>
|
||||||
|
<SortSearch
|
||||||
|
v-if="dialogSortVisible"
|
||||||
|
ref="SortSNNumberRef"
|
||||||
|
activeText="顺序"
|
||||||
|
inactiveText="倒序"
|
||||||
|
@search="getRecord"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
:style="styleShunt(options, scope.row.type)"
|
||||||
|
class="flex justify-start items-center text-base"
|
||||||
|
>
|
||||||
|
{{ scope.row.sn_number }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="100" column-key="type">
|
||||||
|
<template #header>
|
||||||
|
<SelectSearch
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SelectSearchRef"
|
||||||
|
holderText="选择操作类型以搜索相关数据"
|
||||||
|
:options="options"
|
||||||
|
@search="getRecord"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 操作类型 </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
:style="styleShunt(options, scope.row.type)"
|
||||||
|
class="flex justify-start items-center text-base"
|
||||||
|
>
|
||||||
|
{{ scope.row.type == true ? "绑定" : "解绑" }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="200" column-key="created_at">
|
||||||
|
<template #header>
|
||||||
|
<DateTimePicker
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="DateTimePickerRef"
|
||||||
|
DateTimePicker="recordDateTimePicker"
|
||||||
|
@search="getRecord"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 操作时间 </el-text>
|
||||||
|
<SortSearch
|
||||||
|
v-if="dialogSortVisible"
|
||||||
|
ref="SortDateTimeRef"
|
||||||
|
activeText="顺序"
|
||||||
|
inactiveText="倒序"
|
||||||
|
@search="getRecord"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
:style="styleShunt(options, scope.row.type)"
|
||||||
|
class="flex justify-start items-center text-base"
|
||||||
|
>
|
||||||
|
{{ scope.row.created_at }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<Pagination ref="PaginationRef" :active="recordActive" @search="getRecord" />
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||||
|
|
||||||
|
import TabelTools from "../operate/tabelTools.vue";
|
||||||
|
import SearchKey from "../search/searchKey.vue";
|
||||||
|
import SortSearch from "../search/sortSearch.vue";
|
||||||
|
import SelectSearch from "../search/selectSearch.vue";
|
||||||
|
import DateTimePicker from "../search/dateTimePicker.vue";
|
||||||
|
import Pagination from "../search/pagination.vue";
|
||||||
|
|
||||||
|
import recordActiveStore from "../../stores/record";
|
||||||
|
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
import { judgment } from "../../utils/judgment.js";
|
||||||
|
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||||
|
|
||||||
|
const recordActive = recordActiveStore();
|
||||||
|
|
||||||
|
const SearchAccountNameKeyRef = ref(null);
|
||||||
|
const SearchSNNumberKeyRef = ref(null);
|
||||||
|
const SortSNNumberRef = ref(null);
|
||||||
|
const SortDateTimeRef = ref(null);
|
||||||
|
const SelectSearchRef = ref(null);
|
||||||
|
const DateTimePickerRef = ref(null);
|
||||||
|
const PaginationRef = ref(null);
|
||||||
|
const dialogSearchVisible = ref(false);
|
||||||
|
const dialogSortVisible = ref(false);
|
||||||
|
const dialogOperationVisible = ref(false);
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const offsetOff = ref(true);
|
||||||
|
const searchOptions = reactive({
|
||||||
|
account_name: "",
|
||||||
|
sn_number: "",
|
||||||
|
type: "",
|
||||||
|
created_at: "",
|
||||||
|
});
|
||||||
|
const sortOptions = reactive({
|
||||||
|
sn_number: false,
|
||||||
|
created_at: false,
|
||||||
|
});
|
||||||
|
const tableData = ref([]);
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: "0",
|
||||||
|
label: "解绑",
|
||||||
|
style: "color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "1",
|
||||||
|
label: "绑定",
|
||||||
|
style: "color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const styleShunt = (options, data) => {
|
||||||
|
let nowStyle;
|
||||||
|
options.forEach((item) => {
|
||||||
|
if (data == item.value) {
|
||||||
|
nowStyle = item.style;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return nowStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
const showTools = (operateType) => {
|
||||||
|
switch (operateType) {
|
||||||
|
case "search":
|
||||||
|
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||||
|
recordActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||||
|
break;
|
||||||
|
case "sort":
|
||||||
|
dialogSortVisible.value = !dialogSortVisible.value;
|
||||||
|
recordActive.dialogSortVisible = dialogSortVisible.value;
|
||||||
|
break;
|
||||||
|
case "operation":
|
||||||
|
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||||
|
recordActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRecord = () => {
|
||||||
|
judgment(searchOptions, "account_name", SearchAccountNameKeyRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "sn_number", SearchSNNumberKeyRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "type", SelectSearchRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "created_at", DateTimePickerRef.value, "searchMsg");
|
||||||
|
judgment(sortOptions, "sn_number", SortSNNumberRef.value, "searchMsg");
|
||||||
|
judgment(sortOptions, "created_at", SortDateTimeRef.value, "searchMsg");
|
||||||
|
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||||
|
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||||
|
PaginationRef.value.handleCurrentChange(1);
|
||||||
|
offsetOff.value = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offsetOff.value = true;
|
||||||
|
}
|
||||||
|
nextTick(() => {
|
||||||
|
if (PaginationRef.value !== null) {
|
||||||
|
const data = {
|
||||||
|
uid: localStorage.data,
|
||||||
|
offset: PaginationRef.value.offset,
|
||||||
|
limit: PaginationRef.value.limit,
|
||||||
|
searchOptions: searchOptions,
|
||||||
|
sortOptions: sortOptions,
|
||||||
|
};
|
||||||
|
$http.post($url.getRecord, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
tableData.value = res.data.recordMsg;
|
||||||
|
tableData.value.forEach((item) => {
|
||||||
|
item.created_at = moment
|
||||||
|
.utc(item.created_at)
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
});
|
||||||
|
PaginationRef.value.dataCount = res.data.count;
|
||||||
|
recordActive.dataCount = PaginationRef.value.dataCount;
|
||||||
|
} else {
|
||||||
|
tableData.value = [];
|
||||||
|
// ElMessage.error("未查找到相关数据!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ getRecord, dialogVisible });
|
||||||
|
|
||||||
|
watch(searchOptions, (value) => {
|
||||||
|
recordActive.searchOptions = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(sortOptions, (value) => {
|
||||||
|
recordActive.sortOptions = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(dialogVisible, (value) => {
|
||||||
|
if (value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
SearchAccountNameKeyRef.value.searchMsg = recordActive.searchOptions.account_name;
|
||||||
|
searchOptions.account_name = recordActive.searchOptions.account_name;
|
||||||
|
SearchSNNumberKeyRef.value.searchMsg = recordActive.searchOptions.sn_number;
|
||||||
|
SelectSearchRef.value.searchMsg = recordActive.searchOptions.type;
|
||||||
|
searchOptions.sn_number = recordActive.searchOptions.sn_number;
|
||||||
|
DateTimePickerRef.value.created_at = recordActive.searchOptions.created_at;
|
||||||
|
searchOptions.created_at = recordActive.searchOptions.created_at;
|
||||||
|
SortSNNumberRef.value.searchMsg = recordActive.sortOptions.sn_number;
|
||||||
|
SortDateTimeRef.value.searchMsg = recordActive.sortOptions.created_at;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
dialogSearchVisible.value = recordActive.dialogSearchVisible;
|
||||||
|
dialogSortVisible.value = recordActive.dialogSortVisible;
|
||||||
|
dialogOperationVisible.value = recordActive.dialogOperationVisible;
|
||||||
|
|
||||||
|
if (dialogSearchVisible.value) {
|
||||||
|
searchOptions.account_name = recordActive.searchOptions.account_name;
|
||||||
|
searchOptions.sn_number = recordActive.searchOptions.sn_number;
|
||||||
|
searchOptions.type = recordActive.searchOptions.type;
|
||||||
|
searchOptions.created_at = recordActive.searchOptions.created_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogSortVisible.value) {
|
||||||
|
sortOptions.sn_number = recordActive.sortOptions.sn_number;
|
||||||
|
sortOptions.created_at = recordActive.sortOptions.created_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogOperationVisible.value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
getRecord();
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
275
src/components/features/snManager.vue
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
<template>
|
||||||
|
<el-card>
|
||||||
|
<div class="flex justify-center flex-wrap">
|
||||||
|
<TabelTools @showTools="showTools" :dialogObj="snManagerActive" />
|
||||||
|
<!-- 表格 -->
|
||||||
|
<el-table
|
||||||
|
:data="tableData"
|
||||||
|
style="width: 100%"
|
||||||
|
max-height="400"
|
||||||
|
table-layout="auto"
|
||||||
|
scrollbar-always-on
|
||||||
|
>
|
||||||
|
<el-table-column min-width="100" column-key="sn_number">
|
||||||
|
<template #header>
|
||||||
|
<SearchKey
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SearchSNNumberKeyRef"
|
||||||
|
holderText="输入SN号以搜索相关数据"
|
||||||
|
@search="bsideSNManager"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> SN号 </el-text>
|
||||||
|
<SortSearch
|
||||||
|
v-if="dialogSortVisible"
|
||||||
|
ref="SortSNNumberRef"
|
||||||
|
activeText="顺序"
|
||||||
|
inactiveText="倒序"
|
||||||
|
@search="bsideSNManager"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
:style="styleShunt(options, scope.row.status)"
|
||||||
|
class="flex justify-start items-center text-base"
|
||||||
|
>
|
||||||
|
{{ scope.row.sn_number }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="100" column-key="status">
|
||||||
|
<template #header>
|
||||||
|
<SelectSearch
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="SelectSearchRef"
|
||||||
|
holderText="选择绑定状态以搜索相关数据"
|
||||||
|
:options="options"
|
||||||
|
@search="bsideSNManager"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 绑定状态 </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
:style="styleShunt(options, scope.row.status)"
|
||||||
|
class="flex justify-start items-center text-base"
|
||||||
|
>
|
||||||
|
{{ scope.row.status == true ? "已绑定" : "未绑定" }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="200" column-key="updated_at">
|
||||||
|
<template #header>
|
||||||
|
<DateTimePicker
|
||||||
|
v-if="dialogSearchVisible"
|
||||||
|
ref="DateTimePickerRef"
|
||||||
|
DateTimePicker="recordDateTimePicker"
|
||||||
|
@search="bsideSNManager"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> 操作时间 </el-text>
|
||||||
|
<SortSearch
|
||||||
|
v-if="dialogSortVisible"
|
||||||
|
ref="SortDateTimeRef"
|
||||||
|
activeText="顺序"
|
||||||
|
inactiveText="倒序"
|
||||||
|
@search="bsideSNManager"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
:style="styleShunt(options, scope.row.status)"
|
||||||
|
class="flex justify-start items-center text-base"
|
||||||
|
>
|
||||||
|
{{ scope.row.updated_at }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<Pagination ref="PaginationRef" :active="snManagerActive" @search="bsideSNManager" />
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch, onMounted, nextTick } from "vue";
|
||||||
|
|
||||||
|
import TabelTools from "../operate/tabelTools.vue";
|
||||||
|
import SearchKey from "../search/searchKey.vue";
|
||||||
|
import SortSearch from "../search/sortSearch.vue";
|
||||||
|
import SelectSearch from "../search/selectSearch.vue";
|
||||||
|
import DateTimePicker from "../search/dateTimePicker.vue";
|
||||||
|
import Pagination from "../search/pagination.vue";
|
||||||
|
|
||||||
|
import snManagerActiveStore from "../../stores/snManager";
|
||||||
|
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
import { judgment } from "../../utils/judgment.js";
|
||||||
|
import { hasNullOrEmptyPropertyWithTypeof } from "../../utils/hasNullOrEmptyPropertyWithTypeof.js";
|
||||||
|
|
||||||
|
const snManagerActive = snManagerActiveStore();
|
||||||
|
|
||||||
|
const SearchSNNumberKeyRef = ref(null);
|
||||||
|
const SortSNNumberRef = ref(null);
|
||||||
|
const SortDateTimeRef = ref(null);
|
||||||
|
const SelectSearchRef = ref(null);
|
||||||
|
const DateTimePickerRef = ref(null);
|
||||||
|
const PaginationRef = ref(null);
|
||||||
|
const dialogSearchVisible = ref(false);
|
||||||
|
const dialogSortVisible = ref(false);
|
||||||
|
const dialogOperationVisible = ref(false);
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const offsetOff = ref(true);
|
||||||
|
const searchOptions = reactive({
|
||||||
|
sn_number: "",
|
||||||
|
status: "",
|
||||||
|
updated_at: "",
|
||||||
|
});
|
||||||
|
const sortOptions = reactive({
|
||||||
|
sn_number: false,
|
||||||
|
updated_at: false,
|
||||||
|
});
|
||||||
|
const tableData = ref([]);
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: "4",
|
||||||
|
label: "未绑定",
|
||||||
|
style: "color: rgb(16, 184, 130);background-color: rgba(16, 184, 130, 0.1);padding: 0;",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "1",
|
||||||
|
label: "已绑定",
|
||||||
|
style: "color: rgb(56, 188, 248);background-color: rgba(56, 188, 248, 0.1);padding: 0;",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const styleShunt = (options, data) => {
|
||||||
|
let nowStyle;
|
||||||
|
options.forEach((item) => {
|
||||||
|
if (data == item.value) {
|
||||||
|
nowStyle = item.style;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return nowStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
const showTools = (operateType) => {
|
||||||
|
switch (operateType) {
|
||||||
|
case "search":
|
||||||
|
dialogSearchVisible.value = !dialogSearchVisible.value;
|
||||||
|
snManagerActive.dialogSearchVisible = dialogSearchVisible.value;
|
||||||
|
break;
|
||||||
|
case "sort":
|
||||||
|
dialogSortVisible.value = !dialogSortVisible.value;
|
||||||
|
snManagerActive.dialogSortVisible = dialogSortVisible.value;
|
||||||
|
break;
|
||||||
|
case "operation":
|
||||||
|
dialogOperationVisible.value = !dialogOperationVisible.value;
|
||||||
|
snManagerActive.dialogOperationVisible = dialogOperationVisible.value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const bsideSNManager = () => {
|
||||||
|
judgment(searchOptions, "sn_number", SearchSNNumberKeyRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "status", SelectSearchRef.value, "searchMsg");
|
||||||
|
judgment(searchOptions, "updated_at", DateTimePickerRef.value, "searchMsg");
|
||||||
|
judgment(sortOptions, "sn_number", SortSNNumberRef.value, "searchMsg");
|
||||||
|
judgment(sortOptions, "updated_at", SortDateTimeRef.value, "searchMsg");
|
||||||
|
if (hasNullOrEmptyPropertyWithTypeof(searchOptions)) {
|
||||||
|
if (PaginationRef.value.offset !== 1 && offsetOff.value) {
|
||||||
|
PaginationRef.value.handleCurrentChange(1);
|
||||||
|
offsetOff.value = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offsetOff.value = true;
|
||||||
|
}
|
||||||
|
nextTick(() => {
|
||||||
|
if (PaginationRef.value !== null) {
|
||||||
|
const data = {
|
||||||
|
uid: localStorage.data,
|
||||||
|
offset: PaginationRef.value.offset,
|
||||||
|
limit: PaginationRef.value.limit,
|
||||||
|
searchOptions: searchOptions,
|
||||||
|
sortOptions: sortOptions,
|
||||||
|
};
|
||||||
|
$http.post($url.bsideSNManager, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
tableData.value = res.data.bsideSN;
|
||||||
|
tableData.value.forEach((item) => {
|
||||||
|
item.updated_at = moment
|
||||||
|
.utc(item.updated_at)
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
});
|
||||||
|
PaginationRef.value.dataCount = res.data.count;
|
||||||
|
snManagerActive.dataCount = PaginationRef.value.dataCount;
|
||||||
|
} else {
|
||||||
|
tableData.value = [];
|
||||||
|
// ElMessage.error("未查找到相关数据!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ bsideSNManager, dialogVisible });
|
||||||
|
|
||||||
|
watch(searchOptions, (value) => {
|
||||||
|
snManagerActive.searchOptions = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(sortOptions, (value) => {
|
||||||
|
snManagerActive.sortOptions = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(dialogVisible, (value) => {
|
||||||
|
if (value) {
|
||||||
|
setTimeout(() => {
|
||||||
|
SearchSNNumberKeyRef.value.searchMsg = snManagerActive.searchOptions.sn_number;
|
||||||
|
SelectSearchRef.value.searchMsg = snManagerActive.searchOptions.status;
|
||||||
|
searchOptions.sn_number = snManagerActive.searchOptions.sn_number;
|
||||||
|
DateTimePickerRef.value.updated_at = snManagerActive.searchOptions.updated_at;
|
||||||
|
searchOptions.updated_at = snManagerActive.searchOptions.updated_at;
|
||||||
|
SortSNNumberRef.value.searchMsg = snManagerActive.sortOptions.sn_number;
|
||||||
|
SortDateTimeRef.value.searchMsg = snManagerActive.sortOptions.updated_at;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
dialogSearchVisible.value = snManagerActive.dialogSearchVisible;
|
||||||
|
dialogSortVisible.value = snManagerActive.dialogSortVisible;
|
||||||
|
dialogOperationVisible.value = snManagerActive.dialogOperationVisible;
|
||||||
|
|
||||||
|
if (dialogSearchVisible.value) {
|
||||||
|
searchOptions.sn_number = snManagerActive.searchOptions.sn_number;
|
||||||
|
searchOptions.status = snManagerActive.searchOptions.status;
|
||||||
|
searchOptions.updated_at = snManagerActive.searchOptions.updated_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogSortVisible.value) {
|
||||||
|
sortOptions.sn_number = snManagerActive.sortOptions.sn_number;
|
||||||
|
sortOptions.updated_at = snManagerActive.sortOptions.updated_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialogOperationVisible.value) {
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
bsideSNManager();
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
87
src/components/guide/Q&A.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
常见问题指南:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<span class="text-amber-500 font-black">Q:</span
|
||||||
|
>为什么平台在打开状态下且一段时间无任何操作后会显示<span
|
||||||
|
class="text-blue-600 font-black"
|
||||||
|
>未绑定且无连接状态</span
|
||||||
|
>?
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">A:</span
|
||||||
|
>这是由于身份信息过期导致的,进行数据搜索的操作后身份信息会自动刷新,数据也会正常显示。
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<span class="text-amber-500 font-black">Q:</span
|
||||||
|
>为什么平台在使用中有时候会突然跳转到登录页面然后跳转回来?
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">A:</span
|
||||||
|
>这是由于身份信息刷新导致的,不会导致数据丢失,可放心使用。
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<span class="text-amber-500 font-black">Q:</span
|
||||||
|
>为什么平台在登录和刷新后有时会弹出“<span class="text-red-500 font-black"
|
||||||
|
>未查找到相关数据!</span
|
||||||
|
>”的提示?
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">A:</span
|
||||||
|
>这是由于身份信息正在刷新导致的,刷新完毕后数据会正常显示。
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<span class="text-amber-500 font-black">Q:</span>为什么当前消息一直显示“<span
|
||||||
|
class="text-sky-400 font-black"
|
||||||
|
>连接中...</span
|
||||||
|
>”?
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">A:</span
|
||||||
|
>这种情况需要检查您的网络状况或更改连接的网络后重试。
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<span class="text-amber-500 font-black">Q:</span>表格左上角的<span
|
||||||
|
class="text-emerald-500 font-black"
|
||||||
|
>表格工具</span
|
||||||
|
>是什么?
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">A:</span
|
||||||
|
><span class="text-amber-500 font-black">表格工具</span
|
||||||
|
>是用来显示或隐藏用于对表格进行搜索、排序和编辑删除等操作的控件,
|
||||||
|
<br />
|
||||||
|
使用时只需要将鼠标移动到<span class="text-amber-500 font-black">表格工具</span
|
||||||
|
>上,然后选择需要使用的功能并点击即可,附操作图如下:
|
||||||
|
<div class="border-2 flex flex-wrap justify-center items-center">
|
||||||
|
<div class="w-1/4">
|
||||||
|
<span class="text-red-500 font-black">1. </span
|
||||||
|
>鼠标移入表格工具,弹出下拉框
|
||||||
|
<img src="../../assets/img/Q&A/tabelTools.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="w-1/4 border-l-2">
|
||||||
|
<span class="text-red-500 font-black">2. </span
|
||||||
|
>选择需要使用的工具,工具显
|
||||||
|
<br />
|
||||||
|
示,显示状态下右边存在眼睛图标
|
||||||
|
<img src="../../assets/img/Q&A/toolsClick.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="w-1/4 border-l-2">
|
||||||
|
<span class="text-red-500 font-black">3. </span
|
||||||
|
>可选择多个工具同时进行使用
|
||||||
|
<img src="../../assets/img/Q&A/toolsSelect.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="w-1/4 border-l-2">
|
||||||
|
<span class="text-red-500 font-black">4. </span
|
||||||
|
>如果工具使用完毕,可以再次
|
||||||
|
<br />
|
||||||
|
点击下拉框中的对应工具进行隐藏
|
||||||
|
<img src="../../assets/img/Q&A/showType.png" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import tabelTools from "../../assets/img/Q&A/tabelTools.png";
|
||||||
|
import toolsClick from "../../assets/img/Q&A/toolsClick.png";
|
||||||
|
import toolsSelect from "../../assets/img/Q&A/toolsSelect.png";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
92
src/components/guide/code.vue
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
汉字编码使用指南:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-sky-500 font-black">编码科普:</span>
|
||||||
|
如果您不懂汉字编码,建议您先点击链接“<span class="text-sky-500 font-black"
|
||||||
|
>编码科普</span
|
||||||
|
>”以了解汉字编码的基本知识。
|
||||||
|
<img src="../../assets/img/code/codeScience.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-emerald-500 font-black">汉字转换为编码:</span>
|
||||||
|
<br />
|
||||||
|
<span class="text-slate-500 font-black">灰色框</span>为输入区域, 在此区域输入需要转换为编码的汉字
|
||||||
|
<br />
|
||||||
|
<span class="text-amber-500 font-black">黄色框</span>为“<span class="text-amber-500 font-black">显示类型</span>”选择下拉框,共提供两种显示类型
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">绿色框</span>为“<span class="text-emerald-500 font-black">转换汉字</span>”按钮,点击此按钮可将输入框的汉字转换为编码并显示在输出区域
|
||||||
|
<br />
|
||||||
|
<span class="text-sky-500 font-black">蓝色框</span>为“<span class="text-sky-500 font-black">清除</span>”按钮,点击此按钮可清除输入框和输出区域的内容
|
||||||
|
<img src="../../assets/img/code/fontGuide.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-sky-500 font-black">选择显示类型:</span>显示类型分为<span class="text-amber-500 font-black">单字</span>显示和<span class="text-emerald-500 font-black">连续</span>显示两种模式
|
||||||
|
<img src="../../assets/img/code/showType.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-emerald-500 font-black">汉字转换为编码的转换结果:</span>
|
||||||
|
<img src="../../assets/img/code/transFont.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
点击左上角的<span class="text-red-500 font-black">转换模式</span>按钮可切换编码模式
|
||||||
|
<img src="../../assets/img/code/changeMode.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-emerald-500 font-black">编码转换为汉字:</span>
|
||||||
|
<br />
|
||||||
|
<span class="text-slate-500 font-black">灰色框</span>为输入区域, 在此区域输入需要转换为汉字的编码
|
||||||
|
<br />
|
||||||
|
<span class="text-amber-500 font-black">黄色框</span>为“<span class="text-amber-500 font-black">解码类型</span>”选择下拉框,共提供三种解码类型
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">绿色框</span>为“<span class="text-emerald-500 font-black">显示类型</span>”选择下拉框,共提供两种显示类型
|
||||||
|
<br />
|
||||||
|
<span class="text-red-500 font-black">红色框</span>为“<span class="text-red-500 font-black">转换编码</span>”按钮,点击此按钮可将输入框的编码转换为汉字并显示在输出区域
|
||||||
|
<br />
|
||||||
|
<span class="text-sky-500 font-black">蓝色框</span>为“<span class="text-sky-500 font-black">清除</span>”按钮,点击此按钮可清除输入框和输出区域的内容
|
||||||
|
<img src="../../assets/img/code/codeGuide.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-amber-500 font-black">选择解码类型:</span>解码类型分为<span class="text-amber-500 font-black">十进制</span>解码,<span class="text-emerald-500 font-black">十六进制</span>解码和<span class="text-red-500 font-black">二进制</span>解码三种模式
|
||||||
|
<img src="../../assets/img/code/codeType.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-sky-500 font-black">选择显示类型:</span>显示类型分为<span class="text-amber-500 font-black">单字</span>显示和<span class="text-emerald-500 font-black">连续</span>显示两种模式
|
||||||
|
<img src="../../assets/img/code/showType.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-emerald-500 font-black">编码转换为汉字的转换结果:</span>
|
||||||
|
<img src="../../assets/img/code/transCode.png" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import codeGuide from "../../assets/img/code/codeGuide.png";
|
||||||
|
import codeScience from "../../assets/img/code/codeScience.png";
|
||||||
|
import codeType from "../../assets/img/code/codeType.png";
|
||||||
|
import fontGuide from "../../assets/img/code/fontGuide.png";
|
||||||
|
import showType from "../../assets/img/code/showType.png";
|
||||||
|
import transCode from "../../assets/img/code/transCode.png";
|
||||||
|
import transFont from "../../assets/img/code/transFont.png";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
128
src/components/guide/guide.vue
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:show-close="false"
|
||||||
|
style="width: 80%"
|
||||||
|
center
|
||||||
|
align-center
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div
|
||||||
|
style="font-size: 2rem"
|
||||||
|
class="w-full font-bold"
|
||||||
|
:id="titleId"
|
||||||
|
:class="titleClass"
|
||||||
|
>
|
||||||
|
卫星通信服务平台使用帮助
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
@click="close"
|
||||||
|
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-menu
|
||||||
|
class="flex flex-wrap font-bold"
|
||||||
|
:default-active="activeIndex"
|
||||||
|
@select="handleSelect"
|
||||||
|
>
|
||||||
|
<el-menu-item
|
||||||
|
index="0"
|
||||||
|
:style="activeIndex == '0' ? activeStyle : indexStyle"
|
||||||
|
class="border-x-4 border-slate-300"
|
||||||
|
>
|
||||||
|
Q&A
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="1"
|
||||||
|
:style="activeIndex == '1' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
顶部导航栏
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="2"
|
||||||
|
:style="activeIndex == '2' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
查看消息
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="3"
|
||||||
|
:style="activeIndex == '3' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
汉字编码
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="4"
|
||||||
|
:style="activeIndex == '4' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
异或校验
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
v-if="manager"
|
||||||
|
index="5"
|
||||||
|
:style="activeIndex == '5' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
单位管理
|
||||||
|
</el-menu-item>
|
||||||
|
</el-menu>
|
||||||
|
<el-card>
|
||||||
|
<div v-show="activeIndex === '0'">
|
||||||
|
<QA />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '1'">
|
||||||
|
<Header />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '2'">
|
||||||
|
<Msg />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '3'">
|
||||||
|
<Code />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '4'">
|
||||||
|
<Xor />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '5'">
|
||||||
|
<Manager />
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch } from "vue";
|
||||||
|
import { CloseBold } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
import QA from "./Q&A.vue";
|
||||||
|
import Header from "./header.vue";
|
||||||
|
import Msg from "./msg.vue";
|
||||||
|
import Code from "./code.vue";
|
||||||
|
import Xor from "./xor.vue";
|
||||||
|
import Manager from "./manager.vue";
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const activeIndex = ref("1");
|
||||||
|
const indexStyle = "background-color: rgb(241 245 249);";
|
||||||
|
const activeStyle = "background-color: rgb(207 250 254);";
|
||||||
|
const manager = ref(false);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelect = (key, keyPath) => {
|
||||||
|
activeIndex.value = key;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ dialogVisible, manager });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
29
src/components/guide/header.vue
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
顶部导航栏指南:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
导航栏组成:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-amber-500 font-black">左侧:</span>
|
||||||
|
展示了SN号以及帮助按钮
|
||||||
|
<img src="../../assets/img/header/headerGuide.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-emerald-500 font-black">右侧:</span>
|
||||||
|
内容为账户名的下拉框,鼠标移动到下拉框时,会显示一些功能
|
||||||
|
<img src="../../assets/img/header/headerSelect.png" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import headerGuide from "../../assets/img/header/headerGuide.png";
|
||||||
|
import headerSelect from "../../assets/img/header/headerSelect.png";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
38
src/components/guide/manager.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
单位管理指南:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-amber-500 font-black">单位管理操作工具:</span>
|
||||||
|
<br />
|
||||||
|
单位管理功能中最重要的部分是表格的操作工具
|
||||||
|
<br />
|
||||||
|
可以通过表格左上角的下拉框找到操作工具并使其显示
|
||||||
|
<img src="../../assets/img/manager/operateSelect.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-emerald-500 font-black">操作工具介绍:</span>
|
||||||
|
<br />
|
||||||
|
单位管理功能的表格的操作工具具有四种操作类型
|
||||||
|
<br />
|
||||||
|
<span class="text-amber-500 font-black">黄色框</span>内为账号信息的编辑功能,只允许单个账号信息的编辑操作
|
||||||
|
<br />
|
||||||
|
<span class="text-red-500 font-black">红色框</span>内为账号状态的重置功能,可以重置账号的密码、解绑账号所绑定的北斗卡、删除账号现有的姓名和手机号
|
||||||
|
<br />
|
||||||
|
<span class="text-sky-500 font-black">蓝色框</span>内为账号密码的重置功能,可以重置账号的密码
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">绿色框</span>内为账号与北斗卡的的解绑功能,可以解绑账号所绑定的北斗卡
|
||||||
|
<img src="../../assets/img/manager/operateType.png" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import operateSelect from "../../assets/img/manager/operateSelect.png";
|
||||||
|
import operateType from "../../assets/img/manager/operateType.png";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
72
src/components/guide/msg.vue
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
查看消息指南:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-emerald-500 font-black">实时消息:</span>
|
||||||
|
左侧为接收到的实时消息的内容,右侧为接收到实时消息时的时间
|
||||||
|
<img src="../../assets/img/msg/msg.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-sky-500 font-black">查看历史消息的全部内容:</span>
|
||||||
|
消息内容过长时,可以点击右侧的“<span class="text-sky-500 font-black"
|
||||||
|
>展示全部内容</span
|
||||||
|
>”按钮来查看消息的全部内容
|
||||||
|
<img src="../../assets/img/msg/showMsg.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-amber-500 font-black">删除历史消息:</span>
|
||||||
|
想要删除历史消息时,首先需要显示出<span class="text-amber-500 font-black"
|
||||||
|
>表格工具</span
|
||||||
|
>中的“<span class="text-emerald-500 font-black">操作工具</span>”
|
||||||
|
<img src="../../assets/img/msg/operateSelect.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-red-500 font-black">删除历史消息:</span>
|
||||||
|
<br />
|
||||||
|
此处存在三种删除操作:
|
||||||
|
<br />
|
||||||
|
<span class="text-red-500 font-black">1. </span>下图<span
|
||||||
|
class="text-red-500 font-black"
|
||||||
|
>红色框</span
|
||||||
|
>内的按钮“<span class="text-red-500 font-black">删除</span>”可以删除当前行的数据
|
||||||
|
<br />
|
||||||
|
<span class="text-sky-500 font-black">2. </span>下图<span
|
||||||
|
class="text-sky-500 font-black"
|
||||||
|
>蓝色框</span
|
||||||
|
>内的按钮“<span class="text-red-500 font-black">删除选中</span>”可以删除选中行的数据
|
||||||
|
<br />
|
||||||
|
<span class="text-slate-500 font-black">2.1 </span>下图<span
|
||||||
|
class="text-slate-500 font-black"
|
||||||
|
>灰色框</span
|
||||||
|
>内的单选框可以全选中或全不选中所有行的数据
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">2.2 </span>下图<span
|
||||||
|
class="text-emerald-500 font-black"
|
||||||
|
>绿色框</span
|
||||||
|
>内的单选框可以选中或不选中当前行的数据
|
||||||
|
<br />
|
||||||
|
<span class="text-amber-500 font-black">3. </span>下图<span
|
||||||
|
class="text-amber-500 font-black"
|
||||||
|
>黄色框</span
|
||||||
|
>内的按钮“<span class="text-red-500 font-black">删除所有</span>”可以删除所有行的数据
|
||||||
|
<img src="../../assets/img/msg/operateType.png" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import msg from "../../assets/img/msg/msg.png";
|
||||||
|
import operateSelect from "../../assets/img/msg/operateSelect.png";
|
||||||
|
import operateType from "../../assets/img/msg/operateType.png";
|
||||||
|
import showMsg from "../../assets/img/msg/showMsg.png";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
42
src/components/guide/xor.vue
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
异或校验指南:
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-emerald-500 font-black">功能组成:</span>
|
||||||
|
<br />
|
||||||
|
<span class="text-sky-500 font-black">蓝色框</span>内为校验数据的输入框
|
||||||
|
<br />
|
||||||
|
<span class="text-emerald-500 font-black">绿色区域</span>为校验结果的显示区域
|
||||||
|
<br />
|
||||||
|
下方的“<span class="text-amber-500 font-black">校验</span>”按钮用于执行校验
|
||||||
|
<br />
|
||||||
|
下方的“<span class="text-red-500 font-black">清除</span
|
||||||
|
>”按钮用于清除输入框的校验数据和显示区域的校验结果。
|
||||||
|
<img src="../../assets/img/xor/xorGuide.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-red-500 font-black">未输入校验数据时的报错示例:</span>
|
||||||
|
<img src="../../assets/img/xor/input.png" alt="" />
|
||||||
|
<img src="../../assets/img/xor/errorMsg.png" alt="" />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div>
|
||||||
|
<span class="text-amber-500 font-black">校验结果示例:</span>
|
||||||
|
<img src="../../assets/img/xor/xor.png" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import errorMsg from "../../assets/img/xor/errorMsg.png";
|
||||||
|
import input from "../../assets/img/xor/input.png";
|
||||||
|
import xor from "../../assets/img/xor/xor.png";
|
||||||
|
import xorGuide from "../../assets/img/xor/xorGuide.png";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
217
src/components/manager/changePassword.vue
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:show-close="false"
|
||||||
|
style="width: 80%"
|
||||||
|
center
|
||||||
|
align-center
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div
|
||||||
|
style="font-size: 2rem"
|
||||||
|
class="w-full font-bold"
|
||||||
|
:id="titleId"
|
||||||
|
:class="titleClass"
|
||||||
|
>
|
||||||
|
密码管理
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
@click="close"
|
||||||
|
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form
|
||||||
|
ref="ruleFormRef"
|
||||||
|
style="max-width: 600px"
|
||||||
|
:model="ruleForm"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="auto"
|
||||||
|
size="default"
|
||||||
|
status-icon
|
||||||
|
class="mx-auto"
|
||||||
|
>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="原密码" prop="oldPassword">
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
placeholder="请输入原密码"
|
||||||
|
type="password"
|
||||||
|
show-password
|
||||||
|
maxlength="16"
|
||||||
|
autocomplete="off"
|
||||||
|
v-model="ruleForm.oldPassword"
|
||||||
|
@input="filter(ruleForm.oldPassword, 'oldPassword')"
|
||||||
|
oncut="return false"
|
||||||
|
onpaste="return false"
|
||||||
|
oncopy="return false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="新密码" prop="newPassword">
|
||||||
|
<el-text
|
||||||
|
style="color: rgb(240 70 70)"
|
||||||
|
class="mx-1 font-bold"
|
||||||
|
size="small"
|
||||||
|
type="info"
|
||||||
|
>
|
||||||
|
密码必须包含数字、大小写字母以及特殊字符(!@#$%^&*.),且长度在8-16位之间
|
||||||
|
</el-text>
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
placeholder="请输入新密码"
|
||||||
|
type="password"
|
||||||
|
show-password
|
||||||
|
maxlength="16"
|
||||||
|
autocomplete="off"
|
||||||
|
v-model="ruleForm.newPassword"
|
||||||
|
@input="filter(ruleForm.newPassword, 'newPassword')"
|
||||||
|
oncut="return false"
|
||||||
|
onpaste="return false"
|
||||||
|
oncopy="return false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="确认新密码" prop="checkPass">
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
placeholder="请再次输入新密码"
|
||||||
|
type="checkPass"
|
||||||
|
show-password
|
||||||
|
maxlength="16"
|
||||||
|
autocomplete="off"
|
||||||
|
v-model="ruleForm.checkPass"
|
||||||
|
@input="filter(ruleForm.checkPass, 'checkPass')"
|
||||||
|
oncut="return false"
|
||||||
|
onpaste="return false"
|
||||||
|
oncopy="return false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button style="font-weight: bold" @click="resetForm(ruleFormRef)">
|
||||||
|
取消
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
style="font-weight: bold"
|
||||||
|
type="primary"
|
||||||
|
@click="changePassword(ruleFormRef)"
|
||||||
|
>
|
||||||
|
提交修改
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from "vue";
|
||||||
|
import { CloseBold } from "@element-plus/icons-vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
import { encrypt } from "../../utils/aes";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
|
||||||
|
const ruleFormRef = ref(null);
|
||||||
|
const formElClone = ref(null);
|
||||||
|
const ruleForm = reactive({
|
||||||
|
oldPassword: "",
|
||||||
|
newPassword: "",
|
||||||
|
checkPass: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = (value, label) => {
|
||||||
|
if (/[=\s"'+-]/.test(value)) {
|
||||||
|
if (ruleForm[label]) {
|
||||||
|
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const passwordRegex = /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*.]).{8,16}$/;
|
||||||
|
|
||||||
|
const validatePass = (rule, value, callback) => {
|
||||||
|
if (value === "") {
|
||||||
|
callback(new Error("请输入密码"));
|
||||||
|
} else if (!passwordRegex.test(value)) {
|
||||||
|
callback( new Error("密码必须包含数字、大小写字母以及特殊字符(!@#$%^&*.),且长度在8-16位之间"));
|
||||||
|
} else {
|
||||||
|
if (ruleForm.checkPass !== "") {
|
||||||
|
if (!ruleFormRef.value) return;
|
||||||
|
ruleFormRef.value.validateField("checkPass");
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateCheck = (rule, value, callback) => {
|
||||||
|
if (value === "") {
|
||||||
|
callback(new Error("请再次输入密码"));
|
||||||
|
} else if (value !== ruleForm.newPassword) {
|
||||||
|
callback(new Error("两次输入的密码不一致"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const rules = reactive({
|
||||||
|
oldPassword: [{ required: true, message: "请输入原密码", trigger: "blur" }],
|
||||||
|
newPassword: [{ required: true, validator: validatePass, trigger: "blur" }],
|
||||||
|
checkPass: [{ required: true, validator: validateCheck, trigger: "blur" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
if (!ruleFormRef) return;
|
||||||
|
formElClone.value = ruleFormRef.value;
|
||||||
|
formElClone.value.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetForm = (formEl) => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const changePassword = async (formEl) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
let encryptForm = {
|
||||||
|
oldPassword: encrypt(ruleForm.oldPassword),
|
||||||
|
newPassword: encrypt(ruleForm.newPassword),
|
||||||
|
};
|
||||||
|
formEl.resetFields();
|
||||||
|
const data = {
|
||||||
|
passwordForm: encryptForm,
|
||||||
|
uid: localStorage.data,
|
||||||
|
};
|
||||||
|
$http.post($url.changePassword, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
ElMessage({
|
||||||
|
message: "密码修改成功!",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
localStorage.clear();
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
ElMessage.error("密码修改失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ElMessage.error("提交失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ dialogVisible });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
344
src/components/manager/userManager.vue
Normal file
@@ -0,0 +1,344 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:show-close="false"
|
||||||
|
style="width: 80%"
|
||||||
|
center
|
||||||
|
align-center
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div
|
||||||
|
style="font-size: 2rem"
|
||||||
|
class="w-full font-bold"
|
||||||
|
:id="titleId"
|
||||||
|
:class="titleClass"
|
||||||
|
>
|
||||||
|
账户管理
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
@click="close"
|
||||||
|
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form
|
||||||
|
ref="ruleFormRef"
|
||||||
|
style="max-width: 600px"
|
||||||
|
:model="ruleForm"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="auto"
|
||||||
|
size="default"
|
||||||
|
status-icon
|
||||||
|
class="mx-auto"
|
||||||
|
>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="用户名" prop="account_name">
|
||||||
|
<el-input
|
||||||
|
:disabled="acabled"
|
||||||
|
v-model="ruleForm.account_name"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="姓名" prop="user_name">
|
||||||
|
<el-input
|
||||||
|
maxlength="20"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入姓名"
|
||||||
|
v-model="ruleForm.user_name"
|
||||||
|
@input="filter(ruleForm.user_name, 'user_name')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="手机号码" prop="phone">
|
||||||
|
<el-input
|
||||||
|
minlength="11"
|
||||||
|
maxlength="11"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入手机号码"
|
||||||
|
v-model="ruleForm.phone"
|
||||||
|
@input="filter(ruleForm.phone, 'phone')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
class="mx-1 font-bold"
|
||||||
|
v-if="sideMark == 'C'"
|
||||||
|
label="性别"
|
||||||
|
prop="gender"
|
||||||
|
>
|
||||||
|
<el-radio-group v-model="ruleForm.gender">
|
||||||
|
<el-radio value="1"> 男 </el-radio>
|
||||||
|
<el-radio value="0"> 女 </el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="mx-1 font-bold" v-if="sideMark == 'C'" label="年龄" prop="age">
|
||||||
|
<el-input
|
||||||
|
maxlength="2"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入年龄"
|
||||||
|
v-model="ruleForm.age"
|
||||||
|
@input="filter(ruleForm.age, 'age')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
class="mx-1 font-bold"
|
||||||
|
v-if="sideMark == 'C'"
|
||||||
|
label="邮箱号"
|
||||||
|
prop="email"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
maxlength="254"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入邮箱号"
|
||||||
|
v-model="ruleForm.email"
|
||||||
|
@input="filter(ruleForm.email, 'email')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
class="mx-1 font-bold"
|
||||||
|
v-if="sideMark == 'C'"
|
||||||
|
label="通信地址"
|
||||||
|
prop="address"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
maxlength="300"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入通信地址"
|
||||||
|
v-model="ruleForm.address"
|
||||||
|
@input="filter(ruleForm.address, 'address')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
class="mx-1 font-bold"
|
||||||
|
v-if="sideMark == 'C'"
|
||||||
|
label="邮政编码"
|
||||||
|
prop="post_code"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
maxlength="6"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入邮政编码"
|
||||||
|
v-model="ruleForm.post_code"
|
||||||
|
@input="filter(ruleForm.post_code, 'post_code')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button style="font-weight: bold" @click="resetForm(ruleFormRef)">
|
||||||
|
取消
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
style="font-weight: bold"
|
||||||
|
type="primary"
|
||||||
|
@click="editUser(ruleFormRef)"
|
||||||
|
>
|
||||||
|
提交修改
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch, onMounted } from "vue";
|
||||||
|
import { CloseBold } from "@element-plus/icons-vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
import userManagerActiveStore from "../../stores/userManager";
|
||||||
|
|
||||||
|
import { encrypt, decrypt } from "../../utils/aes";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
const phoneRegex = /^(?:13\d|14[579]|15\d|16[67]|17[0135678]|18\d|19[89])\d{8}$/;
|
||||||
|
const emailRegex = /^([a-zA-Z0-9]+[|-|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[|-|.]?)*[a-zA-Z0-9]+(.[a-zA-Z]{2,3})+$/;
|
||||||
|
const postCodeRegex = /^(0[1234567]|1[012356]|2[01234567]|3[0123456]|4[01234567]|5[1234567]|6[1234567]|7[012345]|8[013456])\d{4}$/;
|
||||||
|
|
||||||
|
const userManagerActive = userManagerActiveStore();
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
msg: Object,
|
||||||
|
});
|
||||||
|
|
||||||
|
let sideMark;
|
||||||
|
const acabled = ref(true);
|
||||||
|
const ruleFormRef = ref(null);
|
||||||
|
const formElClone = ref(null);
|
||||||
|
const ruleForm = reactive({
|
||||||
|
account_name: "",
|
||||||
|
user_name: "",
|
||||||
|
phone: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const filter = (value, label) => {
|
||||||
|
let filterValue;
|
||||||
|
if (/[=\s"'+-]/.test(value)) {
|
||||||
|
if (ruleForm[label]) {
|
||||||
|
filterValue = value.replace(/[=\s"'+-]/g, "");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filterValue = value;
|
||||||
|
}
|
||||||
|
if (label == "phone" || label == "age" || label == "post_code") {
|
||||||
|
ruleForm[label] = filterValue.replace(/\D/g, "");
|
||||||
|
} else {
|
||||||
|
ruleForm[label] = filterValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validatePhone = (rule, value, callback) => {
|
||||||
|
if (value && !phoneRegex.test(value)) {
|
||||||
|
callback(new Error("请输入正确的电话号码"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateEmail = (rule, value, callback) => {
|
||||||
|
if (value && !emailRegex.test(value)) {
|
||||||
|
callback(new Error("请输入正确的邮箱地址"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateCode = (rule, value, callback) => {
|
||||||
|
if (value && !postCodeRegex.test(value)) {
|
||||||
|
callback(new Error("请输入正确的邮政编码"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const rules = reactive({
|
||||||
|
account_name: [{ required: false, message: "请输入用户名", trigger: "blur" }],
|
||||||
|
user_name: [],
|
||||||
|
phone: [
|
||||||
|
{ required: false, message: "请输入手机号", trigger: "blur" },
|
||||||
|
{ min: 11, max: 11, message: "输入长度应当为 11 位", trigger: "change" },
|
||||||
|
{ validator: validatePhone },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
if (!ruleFormRef) return;
|
||||||
|
formElClone.value = ruleFormRef.value;
|
||||||
|
formElClone.value.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetForm = (formEl) => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const emit = defineEmits(["resetData"]);
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
ruleForm.account_name = props.msg.account_name;
|
||||||
|
ruleForm.user_name = props.msg.user_name;
|
||||||
|
ruleForm.phone = props.msg.phone;
|
||||||
|
if (sideMark == "C") {
|
||||||
|
ruleForm.gender = props.msg.gender ? "1" : "0";
|
||||||
|
ruleForm.age = props.msg.age;
|
||||||
|
ruleForm.email = props.msg.email;
|
||||||
|
ruleForm.address = props.msg.address;
|
||||||
|
ruleForm.post_code = props.msg.post_code;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const editUser = async (formEl) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
const data = {
|
||||||
|
userMsg: ruleForm,
|
||||||
|
uid: localStorage.data,
|
||||||
|
};
|
||||||
|
$http.post($url.editUser, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
ElMessage({
|
||||||
|
message: "用户信息修改成功!",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
emit("resetData");
|
||||||
|
} else {
|
||||||
|
ElMessage.error("用户信息修改失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ElMessage.error("提交失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ dialogVisible, reset });
|
||||||
|
|
||||||
|
watch(ruleForm, (value) => {
|
||||||
|
if (dialogVisible.value) {
|
||||||
|
userManagerActive.dialogVisible = dialogVisible.value;
|
||||||
|
userManagerActive.ruleForm.account_name = encrypt(value.account_name);
|
||||||
|
userManagerActive.ruleForm.user_name = encrypt(value.user_name);
|
||||||
|
userManagerActive.ruleForm.phone = encrypt(value.phone);
|
||||||
|
if (sideMark == "C") {
|
||||||
|
userManagerActive.ruleForm.gender = encrypt(value.gender);
|
||||||
|
userManagerActive.ruleForm.age = encrypt(value.age.toString());
|
||||||
|
userManagerActive.ruleForm.email = encrypt(value.email);
|
||||||
|
userManagerActive.ruleForm.address = encrypt(value.address);
|
||||||
|
userManagerActive.ruleForm.post_code = encrypt(value.post_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(dialogVisible, (value) => {
|
||||||
|
if (!value) {
|
||||||
|
userManagerActive.dialogVisible = value;
|
||||||
|
userManagerActive.ruleForm = {};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
dialogVisible.value = userManagerActive.dialogVisible;
|
||||||
|
if (localStorage.data) {
|
||||||
|
let decryptData = decrypt(localStorage.data);
|
||||||
|
sideMark = decryptData[decryptData.length - 1];
|
||||||
|
}
|
||||||
|
if (sideMark == "C") {
|
||||||
|
acabled.value = false;
|
||||||
|
ruleForm.gender = "";
|
||||||
|
ruleForm.age = "";
|
||||||
|
ruleForm.email = "";
|
||||||
|
ruleForm.address = "";
|
||||||
|
ruleForm.post_code = "";
|
||||||
|
rules.account_name[0].required = true;
|
||||||
|
rules.phone[0].required = true;
|
||||||
|
rules.age = [];
|
||||||
|
rules.email = [{ validator: validateEmail }];
|
||||||
|
rules.address = [];
|
||||||
|
rules.post_code = [
|
||||||
|
{ min: 6, max: 6, message: "输入长度应当为 6 位", trigger: "change" },
|
||||||
|
{ validator: validateCode },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (userManagerActive.dialogVisible) {
|
||||||
|
ruleForm.account_name = decrypt(userManagerActive.ruleForm.account_name);
|
||||||
|
ruleForm.user_name = decrypt(userManagerActive.ruleForm.user_name);
|
||||||
|
ruleForm.phone = decrypt(userManagerActive.ruleForm.phone);
|
||||||
|
if (sideMark == "C") {
|
||||||
|
ruleForm.gender = decrypt(userManagerActive.ruleForm.gender);
|
||||||
|
ruleForm.age = decrypt(userManagerActive.ruleForm.age);
|
||||||
|
ruleForm.email = decrypt(userManagerActive.ruleForm.email);
|
||||||
|
ruleForm.address = decrypt(userManagerActive.ruleForm.address);
|
||||||
|
ruleForm.post_code = decrypt(userManagerActive.ruleForm.post_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
54
src/components/operate/dataShow.vue
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:show-close="false"
|
||||||
|
style="width: 80%"
|
||||||
|
center
|
||||||
|
align-center
|
||||||
|
>
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div
|
||||||
|
style="font-size: 2rem"
|
||||||
|
class="w-full font-bold"
|
||||||
|
:id="titleId"
|
||||||
|
:class="titleClass"
|
||||||
|
>
|
||||||
|
数据展示
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
@click="close"
|
||||||
|
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-text class="block text-center">
|
||||||
|
{{ dialogMsg }}
|
||||||
|
</el-text>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button style="font-weight: bold" type="primary" @click="resetForm">
|
||||||
|
返回
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { CloseBold } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
const dialogMsg = ref();
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ dialogMsg, dialogVisible });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
140
src/components/operate/editBsideUser.vue
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="operateDialogVisible"
|
||||||
|
:show-close="false"
|
||||||
|
style="width: 80%"
|
||||||
|
center
|
||||||
|
align-center
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div
|
||||||
|
style="font-size: 2rem"
|
||||||
|
class="w-full font-bold"
|
||||||
|
:id="titleId"
|
||||||
|
:class="titleClass"
|
||||||
|
>
|
||||||
|
{{ operateLabel }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
@click="close"
|
||||||
|
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form
|
||||||
|
ref="ruleFormRef"
|
||||||
|
style="max-width: 600px"
|
||||||
|
:model="ruleForm"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="auto"
|
||||||
|
size="default"
|
||||||
|
status-icon
|
||||||
|
class="mx-auto"
|
||||||
|
>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="单位用户名" prop="account_name">
|
||||||
|
<el-input
|
||||||
|
disabled="false"
|
||||||
|
v-model="ruleForm.account_name"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="用户姓名" prop="user_name">
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
placeholder="请输入用户姓名"
|
||||||
|
maxlength="6"
|
||||||
|
autocomplete="off"
|
||||||
|
v-model="ruleForm.user_name"
|
||||||
|
@input="filter(ruleForm.user_name, 'user_name')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="用户手机号码" prop="phone">
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
placeholder="请输入用户手机号码"
|
||||||
|
maxlength="11"
|
||||||
|
autocomplete="off"
|
||||||
|
v-model="ruleForm.phone"
|
||||||
|
@input="filter(ruleForm.phone, 'phone')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||||
|
取消
|
||||||
|
</el-button>
|
||||||
|
<el-button style="font-weight: bold" type="primary" @click="confirm(ruleFormRef)">
|
||||||
|
确定
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from "vue";
|
||||||
|
import { CloseBold } from "@element-plus/icons-vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const operateDialogVisible = ref(false);
|
||||||
|
const ruleFormRef = ref(null);
|
||||||
|
const formElClone = ref(null);
|
||||||
|
|
||||||
|
const ruleForm = reactive({
|
||||||
|
account_name: "",
|
||||||
|
user_name: "",
|
||||||
|
phone: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
const originMsg = reactive({});
|
||||||
|
|
||||||
|
const rules = reactive({});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
operateLabel: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["requestOperate"]);
|
||||||
|
|
||||||
|
const filter = (value, label) => {
|
||||||
|
if (/[=\s"'+-]/.test(value)) {
|
||||||
|
if (ruleForm[label]) {
|
||||||
|
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
operateDialogVisible.value = false;
|
||||||
|
if (!ruleFormRef) return;
|
||||||
|
formElClone.value = ruleFormRef.value;
|
||||||
|
formElClone.value.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetCheckForm = (formEl) => {
|
||||||
|
operateDialogVisible.value = false;
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirm = async (formEl) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
emit("requestOperate");
|
||||||
|
operateDialogVisible.value = false;
|
||||||
|
formEl.resetFields();
|
||||||
|
} else {
|
||||||
|
ElMessage.error("提交失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ operateDialogVisible, ruleForm, originMsg });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
146
src/components/operate/passwordOauth.vue
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="operateDialogVisible"
|
||||||
|
:show-close="false"
|
||||||
|
style="width: 80%"
|
||||||
|
center
|
||||||
|
align-center
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div
|
||||||
|
style="font-size: 2rem"
|
||||||
|
class="w-full font-bold"
|
||||||
|
:id="titleId"
|
||||||
|
:class="titleClass"
|
||||||
|
>
|
||||||
|
{{ operateLabel }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
@click="close"
|
||||||
|
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form
|
||||||
|
ref="ruleFormRef"
|
||||||
|
style="max-width: 600px"
|
||||||
|
:model="ruleForm"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="auto"
|
||||||
|
size="default"
|
||||||
|
status-icon
|
||||||
|
class="mx-auto"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
v-if="operateLabel == '重置密码' || operateLabel == '重置账号'"
|
||||||
|
class="mx-1 font-bold"
|
||||||
|
label="重置后的默认密码"
|
||||||
|
prop="defaultPassword"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
placeholder="请设置重置后的默认密码"
|
||||||
|
maxlength="16"
|
||||||
|
autocomplete="off"
|
||||||
|
v-model="ruleForm.defaultPassword"
|
||||||
|
@input="filter(ruleForm.defaultPassword, 'defaultPassword')"
|
||||||
|
oncut="return false"
|
||||||
|
onpaste="return false"
|
||||||
|
oncopy="return false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="mx-1 font-bold" label="密码" prop="password">
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
placeholder="请输入密码"
|
||||||
|
type="password"
|
||||||
|
show-password
|
||||||
|
maxlength="16"
|
||||||
|
autocomplete="off"
|
||||||
|
v-model="ruleForm.password"
|
||||||
|
@input="filter(ruleForm.password, 'password')"
|
||||||
|
oncut="return false"
|
||||||
|
onpaste="return false"
|
||||||
|
oncopy="return false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button style="font-weight: bold" @click="resetCheckForm(ruleFormRef)">
|
||||||
|
取消
|
||||||
|
</el-button>
|
||||||
|
<el-button style="font-weight: bold" type="primary" @click="confirm(ruleFormRef)">
|
||||||
|
确定
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from "vue";
|
||||||
|
import { CloseBold } from "@element-plus/icons-vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const operateDialogVisible = ref(false);
|
||||||
|
const ruleFormRef = ref(null);
|
||||||
|
const formElClone = ref(null);
|
||||||
|
|
||||||
|
const ruleForm = reactive({
|
||||||
|
defaultPassword: "123456",
|
||||||
|
password: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = reactive({
|
||||||
|
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
operateLabel: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["requestOperate"]);
|
||||||
|
|
||||||
|
const filter = (value, label) => {
|
||||||
|
if (/[=\s"'+-]/.test(value)) {
|
||||||
|
if (ruleForm[label]) {
|
||||||
|
ruleForm[label] = value.replace(/[=\s"'+-]/g, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
operateDialogVisible.value = false;
|
||||||
|
if (!ruleFormRef) return;
|
||||||
|
formElClone.value = ruleFormRef.value;
|
||||||
|
formElClone.value.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetCheckForm = (formEl) => {
|
||||||
|
operateDialogVisible.value = false;
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirm = async (formEl) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
emit("requestOperate");
|
||||||
|
operateDialogVisible.value = false;
|
||||||
|
formEl.resetFields();
|
||||||
|
} else {
|
||||||
|
ElMessage.error("提交失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ operateDialogVisible, ruleForm });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
18
src/components/operate/shortMsg.vue
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<el-card>
|
||||||
|
<div class="flex justify-between items-center flex-wrap">
|
||||||
|
<el-text :style="textColor" class="mx-1 font-bold"> 当前消息: {{ props.socketMsg }} </el-text>
|
||||||
|
<el-text :style="textColor" class="mx-1 font-bold"> 接收时间: {{ props.socketCreatedAt }} </el-text>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
textColor: String,
|
||||||
|
socketMsg: String,
|
||||||
|
socketCreatedAt: String,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
78
src/components/operate/tabelSelect.vue
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<el-table-column min-width="180" width="180" :column-key="holderText.label">
|
||||||
|
<template #header>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<el-button
|
||||||
|
v-if="operateType !== 'edit'"
|
||||||
|
style="margin-left: 0px;font-weight: bold;"
|
||||||
|
:type="multipleColor"
|
||||||
|
:size="multipleSize"
|
||||||
|
:plain="multiplePlain"
|
||||||
|
@click="operateModel('multiple')"
|
||||||
|
>
|
||||||
|
{{ holderText.multiple }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="operateType !== 'edit'"
|
||||||
|
style="margin-left: 0px;font-weight: bold;"
|
||||||
|
:type="allColor"
|
||||||
|
:size="allSize"
|
||||||
|
:plain="allPlain"
|
||||||
|
@click="operateModel('all')"
|
||||||
|
>
|
||||||
|
{{ holderText.all }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-text class="mx-1"> {{ holderText.label }} </el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
style="font-weight: bold;"
|
||||||
|
:type="singleColor"
|
||||||
|
:size="singleSize"
|
||||||
|
:plain="singlePlain"
|
||||||
|
@click="operateMsg(scope.$index, scope.row)"
|
||||||
|
>
|
||||||
|
{{ holderText.single }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const model = ref("single");
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
holderText: Object,
|
||||||
|
singleColor: String,
|
||||||
|
multipleColor: String,
|
||||||
|
allColor: String,
|
||||||
|
singleSize: String,
|
||||||
|
multipleSize: String,
|
||||||
|
allSize: String,
|
||||||
|
singlePlain: Boolean,
|
||||||
|
multiplePlain: Boolean,
|
||||||
|
allPlain: Boolean,
|
||||||
|
operateType: String
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["showComfirmDialog"]);
|
||||||
|
|
||||||
|
const operateModel = (modelType) => {
|
||||||
|
model.value = modelType;
|
||||||
|
emit("showComfirmDialog", { operateType: props.operateType });
|
||||||
|
};
|
||||||
|
|
||||||
|
const operateMsg = (index, row) => {
|
||||||
|
model.value = "single";
|
||||||
|
emit("showComfirmDialog", { data: row, operateType: props.operateType });
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ model });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
113
src/components/operate/tabelTools.vue
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="w-full h-8 flex flex-col justify-center items-center relative top-0 right-0"
|
||||||
|
>
|
||||||
|
<div class="absolute top-0 left-0" style="font-size: 1rem">
|
||||||
|
<el-dropdown>
|
||||||
|
<el-button style="font-weight: bold" type="warning" size="small" plain>
|
||||||
|
表格工具
|
||||||
|
<el-icon class="el-icon--right">
|
||||||
|
<arrow-down />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item :style="searchBgColor" @click="showTools('search')">
|
||||||
|
<el-link style="font-weight: bold" :underline="false" type="success">
|
||||||
|
搜索工具
|
||||||
|
<el-icon v-show="showSearch" class="el-icon--right">
|
||||||
|
<View />
|
||||||
|
</el-icon>
|
||||||
|
</el-link>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item :style="sortBgColor" @click="showTools('sort')">
|
||||||
|
<el-link style="font-weight: bold" :underline="false" type="success">
|
||||||
|
排序工具
|
||||||
|
<el-icon v-show="showSort" class="el-icon--right">
|
||||||
|
<View />
|
||||||
|
</el-icon>
|
||||||
|
</el-link>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item :style="operationBgColor" @click="showTools('operation')">
|
||||||
|
<el-link style="font-weight: bold" :underline="false" type="success">
|
||||||
|
操作工具
|
||||||
|
<el-icon v-show="showOperation" class="el-icon--right">
|
||||||
|
<View />
|
||||||
|
</el-icon>
|
||||||
|
</el-link>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, onMounted } from "vue";
|
||||||
|
import { ArrowDown, View } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
const showSearch = ref(false);
|
||||||
|
const searchBgColor = ref("background-color: rgba(16, 184, 130, 0.1);");
|
||||||
|
const showSort = ref(false);
|
||||||
|
const sortBgColor = ref("background-color: rgba(16, 184, 130, 0.1);");
|
||||||
|
const showOperation = ref(false);
|
||||||
|
const operationBgColor = ref("background-color: rgba(16, 184, 130, 0.1);");
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
dialogObj: Object,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["showTools"]);
|
||||||
|
|
||||||
|
const showTools = (operateType) => {
|
||||||
|
switch (operateType) {
|
||||||
|
case "search":
|
||||||
|
emit("showTools", "search");
|
||||||
|
showSearch.value = !showSearch.value;
|
||||||
|
break;
|
||||||
|
case "sort":
|
||||||
|
emit("showTools", "sort");
|
||||||
|
showSort.value = !showSort.value;
|
||||||
|
break;
|
||||||
|
case "operation":
|
||||||
|
emit("showTools", "operation");
|
||||||
|
showOperation.value = !showOperation.value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(showSearch, (value) => {
|
||||||
|
if (value) {
|
||||||
|
searchBgColor.value = "background-color: rgba(16, 184, 130, 0.2);";
|
||||||
|
} else {
|
||||||
|
searchBgColor.value = "background-color: rgba(16, 184, 130, 0.1);";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(showSort, (value) => {
|
||||||
|
if (value) {
|
||||||
|
sortBgColor.value = "background-color: rgba(16, 184, 130, 0.2);";
|
||||||
|
} else {
|
||||||
|
sortBgColor.value = "background-color: rgba(16, 184, 130, 0.1);";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(showOperation, (value) => {
|
||||||
|
if (value) {
|
||||||
|
operationBgColor.value = "background-color: rgba(16, 184, 130, 0.2);";
|
||||||
|
} else {
|
||||||
|
operationBgColor.value = "background-color: rgba(16, 184, 130, 0.1);";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
showSearch.value = props.dialogObj.dialogSearchVisible;
|
||||||
|
showSort.value = props.dialogObj.dialogSortVisible;
|
||||||
|
showOperation.value = props.dialogObj.dialogOperationVisible;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
16
src/components/pageStructure/footer.vue
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<template>
|
||||||
|
<div class="w-full flex justify-center items-center flex-wrap">
|
||||||
|
<el-text class="mx-1 font-bold">
|
||||||
|
卫星通信服务平台
|
||||||
|
</el-text>
|
||||||
|
|
||||||
|
|
||||||
|
<el-text class="mx-1 font-bold">
|
||||||
|
技术支持电话:400-166-5286
|
||||||
|
</el-text>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup></script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
168
src/components/pageStructure/header.vue
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
<template>
|
||||||
|
<div style="width: 120px;" class="flex flex-wrap justify-around items-center">
|
||||||
|
<el-text class="mx-1 font-bold"> SN号: </el-text>
|
||||||
|
<el-text style="color: rgb(50, 100, 200)" class="mx-1 font-bold">
|
||||||
|
{{ snNumber ? snNumber : "未绑定" }}
|
||||||
|
</el-text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex grow justify-around items-center">
|
||||||
|
<el-button style="font-weight: bold" type="warning" @click="guide">
|
||||||
|
帮助
|
||||||
|
<el-icon class="el-icon--right">
|
||||||
|
<QuestionFilled />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
<el-dropdown class="flex flex-auto justify-end items-center">
|
||||||
|
<el-button style="font-weight: bold" type="success" size="small">
|
||||||
|
账户名: {{ userMsg.account_name }}
|
||||||
|
<el-icon class="el-icon--right">
|
||||||
|
<arrow-down />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item
|
||||||
|
style="background-color: rgba(56, 188, 248, 0.1)"
|
||||||
|
@click="editUser"
|
||||||
|
>
|
||||||
|
<el-link style="font-weight: bold" :underline="false" type="primary">
|
||||||
|
账户管理
|
||||||
|
</el-link>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
style="background-color: rgba(56, 188, 248, 0.1)"
|
||||||
|
@click="changePassword"
|
||||||
|
>
|
||||||
|
<el-link style="font-weight: bold" :underline="false" type="primary">
|
||||||
|
密码管理
|
||||||
|
</el-link>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
style="background-color: rgba(240, 70, 70, 0.1)"
|
||||||
|
@click="unLogin"
|
||||||
|
>
|
||||||
|
<el-link style="font-weight: bold" :underline="false" type="danger">
|
||||||
|
退出登录
|
||||||
|
</el-link>
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
<Guide ref="guideRef" />
|
||||||
|
<UserManager @resetData="resetData" ref="userManagerRef" :msg="userMsg" />
|
||||||
|
<PasswordManager ref="passwordManagerRef" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, onMounted } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { QuestionFilled, ArrowDown } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
import $http from "../../api/index";
|
||||||
|
import $url from "../../api/url";
|
||||||
|
|
||||||
|
import Guide from "../guide/guide.vue";
|
||||||
|
import UserManager from "../manager/userManager.vue";
|
||||||
|
import PasswordManager from "../manager/changePassword.vue";
|
||||||
|
|
||||||
|
const snNumber = ref("");
|
||||||
|
const manager = ref(false);
|
||||||
|
const guideRef = ref(null);
|
||||||
|
const userManagerRef = ref(null);
|
||||||
|
const userMsg = ref({});
|
||||||
|
const passwordManagerRef = ref(null);
|
||||||
|
|
||||||
|
const emit = defineEmits(["connect", "disconnect"]);
|
||||||
|
|
||||||
|
const guide = () => {
|
||||||
|
guideRef.value.dialogVisible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const editUser = () => {
|
||||||
|
if (userManagerRef.value) {
|
||||||
|
userManagerRef.value.dialogVisible = true;
|
||||||
|
userManagerRef.value.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const changePassword = () => {
|
||||||
|
if (passwordManagerRef.value) {
|
||||||
|
passwordManagerRef.value.dialogVisible = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const unLogin = () => {
|
||||||
|
const data = {
|
||||||
|
uid: localStorage.data,
|
||||||
|
access_token: localStorage.access_token,
|
||||||
|
refresh_token: localStorage.refresh_token,
|
||||||
|
};
|
||||||
|
$http.post($url.unLogin, data).then((res) => {
|
||||||
|
emit("disconnect");
|
||||||
|
localStorage.clear();
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const connect = () => {
|
||||||
|
emit("connect");
|
||||||
|
};
|
||||||
|
|
||||||
|
const disconnect = () => {
|
||||||
|
emit("disconnect");
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetData = () => {
|
||||||
|
const data = {
|
||||||
|
uid: localStorage.data,
|
||||||
|
};
|
||||||
|
$http.post($url.getUser, data).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
ElMessage({
|
||||||
|
message: "获取用户信息成功!",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
userMsg.value = res.data.userData;
|
||||||
|
if (res.data.userData.role == 1) {
|
||||||
|
manager.value = true;
|
||||||
|
guideRef.value.manager = true;
|
||||||
|
}
|
||||||
|
if (res.data.userData.status == 0) {
|
||||||
|
ElMessage({
|
||||||
|
showClose: true,
|
||||||
|
message: "您的账号正在使用默认密码,请尽快进行更改!",
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (res.data.userData.status == 2) {
|
||||||
|
ElMessage({
|
||||||
|
showClose: true,
|
||||||
|
message: "您的账号已被封禁,请联系管理员进行申诉!",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("404");
|
||||||
|
ElMessage.error("获取用户信息失败!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ snNumber, manager });
|
||||||
|
|
||||||
|
watch(manager, (value) => {
|
||||||
|
if (value) {
|
||||||
|
emit("allowManager");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resetData();
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
193
src/components/pageStructure/main.vue
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
<template>
|
||||||
|
<div style="height: 100%">
|
||||||
|
<div class="flex flex-col justify-center items-center">
|
||||||
|
<el-text style="font-size: 2.4rem" class="mx-1 font-bold" size="large">
|
||||||
|
卫星通信服务平台
|
||||||
|
</el-text>
|
||||||
|
</div>
|
||||||
|
<el-menu
|
||||||
|
class="flex flex-wrap font-bold"
|
||||||
|
:default-active="activeIndex"
|
||||||
|
@select="handleSelect"
|
||||||
|
>
|
||||||
|
<el-menu-item
|
||||||
|
index="1"
|
||||||
|
:style="activeIndex == '1' ? activeStyle : indexStyle"
|
||||||
|
class="border-x-4 border-slate-300"
|
||||||
|
>
|
||||||
|
查看消息
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="2"
|
||||||
|
:style="activeIndex == '2' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
汉字编码
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="3"
|
||||||
|
:style="activeIndex == '3' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
异或校验
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
v-if="manager"
|
||||||
|
index="4"
|
||||||
|
:style="activeIndex == '4' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
单位管理
|
||||||
|
</el-menu-item>
|
||||||
|
</el-menu>
|
||||||
|
<el-card>
|
||||||
|
<div v-show="activeIndex === '1'">
|
||||||
|
<div>
|
||||||
|
<el-button type="primary">
|
||||||
|
<a href="https://prediction.guodiangaoke.com/#/" target="_blank">星历预测系统</a>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<ShortMsg :textColor="color" :socketMsg="message" :socketCreatedAt="created_at" />
|
||||||
|
<br />
|
||||||
|
<HistoryMsg ref="historyMsgRef" />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '2'">
|
||||||
|
<el-button
|
||||||
|
style="font-weight: bold"
|
||||||
|
type="primary"
|
||||||
|
@click="showModel"
|
||||||
|
class="mr-4"
|
||||||
|
>
|
||||||
|
转换模式
|
||||||
|
</el-button>
|
||||||
|
<CodeHelp />
|
||||||
|
<Encode v-if="showCode" />
|
||||||
|
<Decode v-if="!showCode" />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '3'">
|
||||||
|
<CalculationXOR />
|
||||||
|
</div>
|
||||||
|
<div v-show="activeIndex === '4'">
|
||||||
|
<el-menu
|
||||||
|
class="flex flex-wrap font-bold"
|
||||||
|
:default-active="subActiveIndex"
|
||||||
|
@select="handleSubSelect"
|
||||||
|
>
|
||||||
|
<el-menu-item
|
||||||
|
index="1"
|
||||||
|
:style="subActiveIndex == '1' ? activeStyle : indexStyle"
|
||||||
|
class="border-x-4 border-slate-300"
|
||||||
|
>
|
||||||
|
SN号码管理
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="2"
|
||||||
|
:style="subActiveIndex == '2' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
用户管理
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
index="3"
|
||||||
|
:style="subActiveIndex == '3' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
绑定记录
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item
|
||||||
|
v-if="manager"
|
||||||
|
index="4"
|
||||||
|
:style="subActiveIndex == '4' ? activeStyle : indexStyle"
|
||||||
|
class="border-r-4 border-slate-300"
|
||||||
|
>
|
||||||
|
绑定用户
|
||||||
|
</el-menu-item>
|
||||||
|
</el-menu>
|
||||||
|
<div v-show="subActiveIndex === '1'">
|
||||||
|
<SNManager ref="snManagerRef" />
|
||||||
|
</div>
|
||||||
|
<div v-show="subActiveIndex === '2'">
|
||||||
|
<BsideManager ref="bsideManagerRef" />
|
||||||
|
</div>
|
||||||
|
<div v-show="subActiveIndex === '3'">
|
||||||
|
<Record ref="recordRef" />
|
||||||
|
</div>
|
||||||
|
<div v-show="subActiveIndex === '4'">
|
||||||
|
<BindSN ref="bindSNRef" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, onMounted } from "vue";
|
||||||
|
|
||||||
|
import ShortMsg from "../operate/shortMsg.vue";
|
||||||
|
import HistoryMsg from "../features/historyMsg.vue";
|
||||||
|
import CodeHelp from "../transcoding/codeHelp.vue";
|
||||||
|
import Encode from "../transcoding/encode.vue";
|
||||||
|
import Decode from "../transcoding/decode.vue";
|
||||||
|
import CalculationXOR from "../calculationXOR/calculationXOR.vue";
|
||||||
|
import SNManager from "../features/snManager.vue";
|
||||||
|
import BsideManager from "../features/bsideManager.vue";
|
||||||
|
import Record from "../features/record.vue";
|
||||||
|
import BindSN from "../features/bindSN.vue";
|
||||||
|
|
||||||
|
import historyMsgActiveStore from "../../stores/historyMsg";
|
||||||
|
import shortMsgActiveStore from "../../stores/shortMsg";
|
||||||
|
|
||||||
|
const historyMsgActive = historyMsgActiveStore();
|
||||||
|
const shortMsgActive = shortMsgActiveStore();
|
||||||
|
|
||||||
|
const activeIndex = ref("1");
|
||||||
|
const subActiveIndex = ref("1");
|
||||||
|
const indexStyle = "background-color: rgb(241 245 249);";
|
||||||
|
const activeStyle = "background-color: rgb(207 250 254);";
|
||||||
|
const manager = ref(false);
|
||||||
|
const color = ref();
|
||||||
|
const message = ref();
|
||||||
|
const created_at = ref();
|
||||||
|
const showCode = ref(true);
|
||||||
|
const historyMsgRef = ref(null);
|
||||||
|
const snManagerRef = ref(null);
|
||||||
|
const bsideManagerRef = ref(null);
|
||||||
|
const recordRef = ref(null);
|
||||||
|
const bindSNRef = ref(null);
|
||||||
|
|
||||||
|
const handleSelect = (key, keyPath) => {
|
||||||
|
activeIndex.value = key;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubSelect = (key, keyPath) => {
|
||||||
|
subActiveIndex.value = key;
|
||||||
|
};
|
||||||
|
|
||||||
|
const showModel = () => {
|
||||||
|
showCode.value = !showCode.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const historyMsg = () => {
|
||||||
|
historyMsgRef.value.historyMsg();
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ manager, color, message, created_at, historyMsg });
|
||||||
|
|
||||||
|
watch(activeIndex, (value) => {
|
||||||
|
historyMsgActive.activeIndex = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(subActiveIndex, (value) => {
|
||||||
|
historyMsgActive.subActiveIndex = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
activeIndex.value = historyMsgActive.activeIndex;
|
||||||
|
subActiveIndex.value = historyMsgActive.subActiveIndex;
|
||||||
|
message.value = shortMsgActive.message;
|
||||||
|
created_at.value = shortMsgActive.created_at;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
94
src/components/search/dateTimePicker.vue
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="searchMsg"
|
||||||
|
type="datetimerange"
|
||||||
|
size="small"
|
||||||
|
range-separator="到"
|
||||||
|
start-placeholder="开始时间"
|
||||||
|
end-placeholder="结束时间"
|
||||||
|
@change="search"
|
||||||
|
style="width: 100%; font-size: 1rem"
|
||||||
|
:popper-class="DateTimePicker"
|
||||||
|
@visible-change="handleVisibleChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
|
||||||
|
const searchMsg = ref(null);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
DateTimePicker: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["search"]);
|
||||||
|
|
||||||
|
const search = () => {
|
||||||
|
emit("search");
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleVisibleChange = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
let changeNode = window.document.getElementsByClassName(props.DateTimePicker)[0];
|
||||||
|
let Triangles = changeNode.children[1];
|
||||||
|
Triangles.style.display = "none";
|
||||||
|
let elppNode = changeNode.children[0];
|
||||||
|
elppNode.style.width = "30rem";
|
||||||
|
elppNode.style.backgroundColor = "#aaffff";
|
||||||
|
let elppbwNode = elppNode.children[0];
|
||||||
|
elppbwNode.style.width = "30rem";
|
||||||
|
let elppfNode = elppNode.children[1];
|
||||||
|
elppfNode.style.width = "30rem";
|
||||||
|
elppfNode.style.backgroundColor = "#aaffff";
|
||||||
|
let elppbNode = elppbwNode.children[0];
|
||||||
|
elppbNode.style.width = "30rem";
|
||||||
|
let elppbCNode = elppbNode.children;
|
||||||
|
elppbCNode[0].style.width = "30rem";
|
||||||
|
let leftDateSelectNode = elppbCNode[0].children[0].children[1];
|
||||||
|
let leftTimeSelectNode = leftDateSelectNode.children[0];
|
||||||
|
leftTimeSelectNode.addEventListener("click", function () {
|
||||||
|
let leftTimeTableNode = leftDateSelectNode.children[1];
|
||||||
|
leftTimeTableNode.style.width = "10rem";
|
||||||
|
leftTimeTableNode.style.fontSize = "1rem";
|
||||||
|
leftTimeTableNode.style.transform = "translate(-20%, 0)";
|
||||||
|
});
|
||||||
|
let rightDateSelectNode = elppbCNode[0].children[2].children[1];
|
||||||
|
let rightTimeSelectNode = rightDateSelectNode.children[0];
|
||||||
|
rightTimeSelectNode.addEventListener("click", function () {
|
||||||
|
let rightTimeTableNode = rightDateSelectNode.children[1];
|
||||||
|
rightTimeTableNode.style.width = "10rem";
|
||||||
|
rightTimeTableNode.style.fontSize = "1rem";
|
||||||
|
rightTimeTableNode.style.transform = "translate(-20%, 0)";
|
||||||
|
});
|
||||||
|
elppbCNode[1].style.width = "15rem";
|
||||||
|
let elppbCFCNode = elppbCNode[1].children;
|
||||||
|
elppbCFCNode[0].style.fontSize = "1rem";
|
||||||
|
let elppbCFCCNode = elppbCFCNode[0].children;
|
||||||
|
elppbCFCCNode[0].style.margin = "0";
|
||||||
|
elppbCFCCNode[1].style.margin = "0";
|
||||||
|
elppbCFCCNode[2].style.fontSize = "1rem";
|
||||||
|
elppbCFCCNode[2].style.margin = "0";
|
||||||
|
elppbCFCNode[1].style.fontSize = "1rem";
|
||||||
|
elppbCNode[2].style.width = "15rem";
|
||||||
|
let elppbCSCNode = elppbCNode[2].children;
|
||||||
|
elppbCSCNode[0].style.fontSize = "1rem";
|
||||||
|
let elppbCSCCNode = elppbCSCNode[0].children;
|
||||||
|
elppbCSCCNode[0].style.margin = "0";
|
||||||
|
elppbCSCCNode[1].style.margin = "0";
|
||||||
|
elppbCSCCNode[2].style.fontSize = "1rem";
|
||||||
|
elppbCSCCNode[2].style.margin = "0";
|
||||||
|
elppbCSCNode[1].style.fontSize = "1rem";
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ searchMsg });
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
handleVisibleChange();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
57
src/components/search/pagination.vue
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex justify-center my-2">
|
||||||
|
<el-pagination
|
||||||
|
class="flex justify-center flex-wrap"
|
||||||
|
v-model:current-page="offset"
|
||||||
|
v-model:page-size="limit"
|
||||||
|
:page-sizes="pageSizes"
|
||||||
|
size="small"
|
||||||
|
background
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="dataCount"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
|
||||||
|
const offset = ref(1);
|
||||||
|
const limit = ref(10);
|
||||||
|
const dataCount = ref(0);
|
||||||
|
const pageSizes = [10, 20, 50, 100];
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
active: Object,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["search", "sizeChangeBack"]);
|
||||||
|
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
offset.value = 1;
|
||||||
|
props.active.offset = offset.value;
|
||||||
|
emit("sizeChangeBack", val);
|
||||||
|
limit.value = val;
|
||||||
|
props.active.limit = limit.value;
|
||||||
|
emit("search");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
offset.value = val;
|
||||||
|
props.active.offset = offset.value;
|
||||||
|
emit("search");
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ offset, limit, dataCount, handleCurrentChange });
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
offset.value = props.active.offset;
|
||||||
|
limit.value = props.active.limit;
|
||||||
|
dataCount.value = props.active.dataCount;
|
||||||
|
emit("search");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
40
src/components/search/searchKey.vue
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="输入<span class='text-red-500 font-black'> *空 </span>可搜索空数据"
|
||||||
|
raw-content
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
size="small"
|
||||||
|
:placeholder="holderText"
|
||||||
|
clearable
|
||||||
|
v-model="searchMsg"
|
||||||
|
@blur="search"
|
||||||
|
style="width: 100%; font-size: 1rem"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const searchMsg = ref(null);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
holderText: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["search"]);
|
||||||
|
|
||||||
|
const search = () => {
|
||||||
|
emit("search");
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ searchMsg });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
42
src/components/search/selectSearch.vue
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-select
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
:placeholder="holderText"
|
||||||
|
v-model="searchMsg"
|
||||||
|
@change="search"
|
||||||
|
style="width: 100%; font-size: 1rem;"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
class="text-center"
|
||||||
|
:style="item.style"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const searchMsg = ref(null);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
holderText: String,
|
||||||
|
options: Object
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["search"]);
|
||||||
|
|
||||||
|
const search = () => {
|
||||||
|
emit("search");
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ searchMsg });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
32
src/components/search/sortSearch.vue
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<el-switch
|
||||||
|
size="small"
|
||||||
|
v-model="searchMsg"
|
||||||
|
inline-prompt
|
||||||
|
:active-text="activeText"
|
||||||
|
:inactive-text="inactiveText"
|
||||||
|
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949;"
|
||||||
|
@change="search"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
|
||||||
|
const searchMsg = ref(null);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
activeText: String,
|
||||||
|
inactiveText: String
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["search"]);
|
||||||
|
|
||||||
|
const search = () => {
|
||||||
|
emit("search");
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ searchMsg });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
96
src/components/transcoding/codeHelp.vue
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<el-text class="mx-1 font-bold">
|
||||||
|
注: 键盘输入的空格、回车、制表符以及普通英文、数字和标点,将自动转为对应的全角字符进行编码,使用时请注意
|
||||||
|
</el-text>
|
||||||
|
<el-link
|
||||||
|
style="font-weight: bold"
|
||||||
|
:underline="false"
|
||||||
|
type="primary"
|
||||||
|
@click="dialogVisible = true"
|
||||||
|
>
|
||||||
|
编码科普
|
||||||
|
</el-link>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:show-close="false"
|
||||||
|
style="width: 80%"
|
||||||
|
center
|
||||||
|
align-center
|
||||||
|
>
|
||||||
|
<template #header="{ close, titleId, titleClass }">
|
||||||
|
<div
|
||||||
|
style="font-size: 2rem"
|
||||||
|
class="w-full font-bold"
|
||||||
|
:id="titleId"
|
||||||
|
:class="titleClass"
|
||||||
|
>
|
||||||
|
编码帮助
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
@click="close"
|
||||||
|
class="bg-gray-400 hover:bg-red-600 text-3xl absolute top-0 right-0 cursor-pointer flex justify-center items-center"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<CloseBold />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-text class="mx-1">
|
||||||
|
<h1 class="font-bold text-xl">GB2312 编码表</h1>
|
||||||
|
<br />
|
||||||
|
GB 2312 标准由中国国家标准总局 1980 年发布,GB 即国标,共收录
|
||||||
|
6763个汉字,其中一级汉字 3755 个,二级汉字 3008 个。
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<ul class="list-disc">
|
||||||
|
<li class="ml-10">
|
||||||
|
GB 2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆
|
||||||
|
99.75% 的使用频率。
|
||||||
|
</li>
|
||||||
|
<li class="ml-10">
|
||||||
|
对于人名、古汉语等方面出现的罕用字,GB 2312 不能处理,这导致了后来 GBK 及 GB
|
||||||
|
18030 汉字字符集的出现。
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<br />
|
||||||
|
GB 2312收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的
|
||||||
|
682 个全角字符。
|
||||||
|
<br />
|
||||||
|
GB 2312 兼容 ASCII 码(0 -
|
||||||
|
127),之后对任意一个图形字符都采用两个字节表示,高位字节和低位字节都大于127。
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
GB 2312 字符集分成 94
|
||||||
|
个区,每区有94个位,分别对应第一字节和第二字节,这种表示方式也称为区位码。
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<ul class="list-disc">
|
||||||
|
<li class="ml-10">01-09 区为特殊符号</li>
|
||||||
|
<li class="ml-10">10-15 区为用户自定义符号区(未编码)</li>
|
||||||
|
<li class="ml-10">16-55 区为一级汉字,按拼音排序,共 3755 个</li>
|
||||||
|
<li class="ml-10">56-87 区为二级汉字,按部首/笔画排序,共 3008 个</li>
|
||||||
|
<li class="ml-10">88-94 区为用户自定义汉字区(未编码)</li>
|
||||||
|
</ul>
|
||||||
|
</el-text>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button style="font-weight: bold" type="primary" @click="back">
|
||||||
|
返回
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { CloseBold } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
|
||||||
|
const back = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
328
src/components/transcoding/decode.vue
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
<template>
|
||||||
|
<el-input
|
||||||
|
placeholder="请输入编码"
|
||||||
|
v-model="fontcode"
|
||||||
|
type="textarea"
|
||||||
|
resize="none"
|
||||||
|
:rows="10"
|
||||||
|
style="box-shadow: 0 0px 20px -10px rgb(0 0 0 / 0.5)"
|
||||||
|
class="mt-4 mb-4"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-select
|
||||||
|
v-model="decodeType"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
placeholder="选择解码类型"
|
||||||
|
style="width: 106px"
|
||||||
|
class="mr-4"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-select
|
||||||
|
v-model="showType"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
placeholder="选择显示类型"
|
||||||
|
style="width: 106px"
|
||||||
|
class="mr-4"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in showOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-button style="font-weight: bold;" type="primary" @click="transformcode(fontcode)">
|
||||||
|
转换编码
|
||||||
|
</el-button>
|
||||||
|
<el-button style="font-weight: bold;" type="primary" @click="reset">
|
||||||
|
清除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<el-card v-show="showType == 1" class="mt-4 mb-4">
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(十进制): {{ fontcodedec ? fontcodedec.join(" , ") : "" }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(十六进制): {{ fontcodehex ? fontcodehex.join(" , ") : "" }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(二进制): {{ fontcodebin ? fontcodebin.join(" , ") : "" }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text v-show="decodeType == 'transcode'" class="mx-1">
|
||||||
|
汉字: {{ transcode }}
|
||||||
|
</el-text>
|
||||||
|
<el-text v-show="decodeType == 'transcodehex'" class="mx-1">
|
||||||
|
汉字: {{ transcodehex }}
|
||||||
|
</el-text>
|
||||||
|
<el-text v-show="decodeType == 'transcodebin'" class="mx-1">
|
||||||
|
汉字: {{ transcodebin }}
|
||||||
|
</el-text>
|
||||||
|
</el-card>
|
||||||
|
<div class="flex flex-wrap justify-start items-center gap-4 mt-4 mb-4">
|
||||||
|
<el-card
|
||||||
|
v-for="(item, index) in chinafont"
|
||||||
|
v-show="showType == 0"
|
||||||
|
style="width: 300px"
|
||||||
|
>
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(十进制): {{ fontcodedec ? fontcodedec[index] : "" }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(十六进制): {{ fontcodehex ? fontcodehex[index] : "" }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(二进制): {{ fontcodebin ? fontcodebin[index] : "" }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text v-show="decodeType == 'transcode'" class="mx-1">
|
||||||
|
汉字: {{ transcode[index] }}
|
||||||
|
</el-text>
|
||||||
|
<el-text v-show="decodeType == 'transcodehex'" class="mx-1">
|
||||||
|
汉字: {{ transcodehex[index] }}
|
||||||
|
</el-text>
|
||||||
|
<el-text v-show="decodeType == 'transcodebin'" class="mx-1">
|
||||||
|
汉字: {{ transcodebin[index] }}
|
||||||
|
</el-text>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, onMounted } from "vue";
|
||||||
|
|
||||||
|
import decodeActiveStore from "../../stores/decode";
|
||||||
|
|
||||||
|
import { toFullWidth } from "../../utils/toFullWidth";
|
||||||
|
|
||||||
|
import GBK from "gbk.js";
|
||||||
|
|
||||||
|
const decodeActive = decodeActiveStore();
|
||||||
|
|
||||||
|
const decodeType = ref("transcode");
|
||||||
|
const showType = ref("1");
|
||||||
|
const chinafont = ref();
|
||||||
|
const fontcode = ref();
|
||||||
|
const fontcodedec = ref();
|
||||||
|
const fontcodehex = ref();
|
||||||
|
const fontcodebin = ref();
|
||||||
|
const transcode = ref();
|
||||||
|
const transcodehex = ref();
|
||||||
|
const transcodebin = ref();
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: "transcode",
|
||||||
|
label: "十进制",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "transcodehex",
|
||||||
|
label: "十六进制",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "transcodebin",
|
||||||
|
label: "二进制",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const showOptions = [
|
||||||
|
{
|
||||||
|
value: "0",
|
||||||
|
label: "单字",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "1",
|
||||||
|
label: "连续",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const decToHex = (dec) => {
|
||||||
|
let hexArr = [];
|
||||||
|
dec.forEach((element) => {
|
||||||
|
let hex = parseInt(element, 10).toString(16).toUpperCase();
|
||||||
|
if (hex.length == 1) {
|
||||||
|
hex = "0" + hex;
|
||||||
|
}
|
||||||
|
hexArr.push(hex);
|
||||||
|
});
|
||||||
|
return hexArr.join(" , ");
|
||||||
|
};
|
||||||
|
|
||||||
|
const decToBinary = (dec) => {
|
||||||
|
let binaryArr = [];
|
||||||
|
dec.forEach((element) => {
|
||||||
|
let binaryString = parseInt(element, 10).toString(2);
|
||||||
|
while (binaryString.length < 8) {
|
||||||
|
binaryString = "0" + binaryString;
|
||||||
|
}
|
||||||
|
binaryArr.push(binaryString);
|
||||||
|
});
|
||||||
|
return binaryArr.join(" , ");
|
||||||
|
};
|
||||||
|
|
||||||
|
const BinaryToDec = (binary) => {
|
||||||
|
let decArr = [];
|
||||||
|
binary.forEach((element) => {
|
||||||
|
let dec = parseInt(element, 2);
|
||||||
|
decArr.push(dec);
|
||||||
|
});
|
||||||
|
return decArr.join(" , ");
|
||||||
|
};
|
||||||
|
|
||||||
|
const BinaryToHex = (binary) => {
|
||||||
|
let hexArr = [];
|
||||||
|
binary.forEach((element) => {
|
||||||
|
let hex = parseInt(element, 2).toString(16).toUpperCase();
|
||||||
|
if (hex.length == 1) {
|
||||||
|
hex = "0" + hex;
|
||||||
|
}
|
||||||
|
hexArr.push(hex);
|
||||||
|
});
|
||||||
|
return hexArr.join(" , ");
|
||||||
|
};
|
||||||
|
|
||||||
|
const transformcode = (fontcode) => {
|
||||||
|
decodeActive.fontcode = fontcode;
|
||||||
|
let dec = [], hex = [], bin = [];
|
||||||
|
fontcode.replace(/\s+/g, '').replace(/,/g, ",").split(",").forEach((element) => {
|
||||||
|
let newArray;
|
||||||
|
if(element.length >= 4 && decodeType.value == "transcodehex") {
|
||||||
|
newArray = element.split("").reduce((acc, curr, index) => {
|
||||||
|
if (index % 2 === 0 && index + 1 < element.split("").length) {
|
||||||
|
acc.push([curr, element.split("")[index + 1]].join(""));
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
if(newArray.length > 2) {
|
||||||
|
newArray.shift();
|
||||||
|
newArray = newArray.join(",");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newArray = element;
|
||||||
|
}
|
||||||
|
hex.push(parseInt(newArray, 16));
|
||||||
|
dec.push(newArray);
|
||||||
|
bin.push(parseInt(newArray, 2));
|
||||||
|
});
|
||||||
|
transcode.value = "";
|
||||||
|
decodeActive.transcode = "";
|
||||||
|
transcodehex.value = "";
|
||||||
|
decodeActive.transcodehex = "";
|
||||||
|
transcodebin.value = "";
|
||||||
|
decodeActive.transcodebin = "";
|
||||||
|
switch (decodeType.value) {
|
||||||
|
case "transcode":
|
||||||
|
chinafont.value = GBK.decode(dec);
|
||||||
|
transcode.value = GBK.decode(dec);
|
||||||
|
decodeActive.transcode = transcode.value;
|
||||||
|
fontcodedec.value = fontcode.split(",").join(" , ");
|
||||||
|
decodeActive.fontcodedec = fontcode.split(",").join(" , ");
|
||||||
|
fontcodehex.value = decToHex(fontcode.split(","));
|
||||||
|
decodeActive.fontcodehex = decToHex(fontcode.split(","));
|
||||||
|
fontcodebin.value = decToBinary(fontcode.split(","));
|
||||||
|
decodeActive.fontcodebin = decToBinary(fontcode.split(","));
|
||||||
|
break;
|
||||||
|
case "transcodehex":
|
||||||
|
chinafont.value = GBK.decode(hex);
|
||||||
|
transcodehex.value = GBK.decode(hex);
|
||||||
|
decodeActive.transcodehex = transcodehex.value;
|
||||||
|
fontcodedec.value = hex.join(" , ");
|
||||||
|
decodeActive.fontcodedec = hex.join(" , ");
|
||||||
|
fontcodehex.value = fontcode.split(",").join(" , ");
|
||||||
|
decodeActive.fontcodehex = fontcode.split(",").join(" , ");
|
||||||
|
fontcodebin.value = decToBinary(hex);
|
||||||
|
decodeActive.fontcodebin = decToBinary(hex);
|
||||||
|
break;
|
||||||
|
case "transcodebin":
|
||||||
|
chinafont.value = GBK.decode(bin);
|
||||||
|
transcodebin.value = GBK.decode(bin);
|
||||||
|
decodeActive.transcodebin = transcodebin.value;
|
||||||
|
fontcodedec.value = BinaryToDec(fontcode.split(","));
|
||||||
|
decodeActive.fontcodedec = BinaryToDec(fontcode.split(","));
|
||||||
|
fontcodehex.value = BinaryToHex(fontcode.split(","));
|
||||||
|
decodeActive.fontcodehex = BinaryToHex(fontcode.split(","));
|
||||||
|
fontcodebin.value = fontcode.split(",").join(" , ");
|
||||||
|
decodeActive.fontcodebin = fontcode.split(",").join(" , ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let transfont = [];
|
||||||
|
hex = [], bin = [];
|
||||||
|
//将半角字符转为全角字符
|
||||||
|
toFullWidth(chinafont.value).split("").forEach((item) => {
|
||||||
|
transfont.push(GBK.encode(item).join(" , "));
|
||||||
|
let hexSingle = [], binSingle = [];
|
||||||
|
GBK.encode(item).forEach((element) => {
|
||||||
|
hexSingle.push(element.toString(16).toUpperCase().length < 2 ? "0" + element.toString(16).toUpperCase() : element.toString(16).toUpperCase());
|
||||||
|
binSingle.push(element.toString(2));
|
||||||
|
});
|
||||||
|
hex.push(hexSingle.join(""));
|
||||||
|
bin.push(binSingle.join(" , "));
|
||||||
|
});
|
||||||
|
fontcodedec.value = transfont;
|
||||||
|
decodeActive.fontcodedec = transfont;
|
||||||
|
fontcodehex.value = hex;
|
||||||
|
decodeActive.fontcodehex = hex;
|
||||||
|
fontcodebin.value = bin;
|
||||||
|
decodeActive.fontcodebin = bin;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
fontcode.value = "";
|
||||||
|
fontcodedec.value = "";
|
||||||
|
fontcodehex.value = "";
|
||||||
|
fontcodebin.value = "";
|
||||||
|
transcode.value = "";
|
||||||
|
transcodehex.value = "";
|
||||||
|
transcodebin.value = "";
|
||||||
|
chinafont.value = "";
|
||||||
|
decodeActive.fontcode = "";
|
||||||
|
decodeActive.fontcodedec = "";
|
||||||
|
decodeActive.fontcodehex = "";
|
||||||
|
decodeActive.fontcodebin = "";
|
||||||
|
decodeActive.transcode = "";
|
||||||
|
decodeActive.transcodehex = "";
|
||||||
|
decodeActive.transcodebin = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(fontcode, (value) => {
|
||||||
|
decodeActive.fontcode = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(decodeType, (value) => {
|
||||||
|
decodeActive.decodeType = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(showType, (value) => {
|
||||||
|
decodeActive.showType = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
decodeType.value = decodeActive.decodeType;
|
||||||
|
showType.value = decodeActive.showType;
|
||||||
|
fontcode.value = decodeActive.fontcode;
|
||||||
|
fontcodedec.value = decodeActive.fontcodedec;
|
||||||
|
fontcodehex.value = decodeActive.fontcodehex;
|
||||||
|
fontcodebin.value = decodeActive.fontcodebin;
|
||||||
|
transcode.value = decodeActive.transcode;
|
||||||
|
transcodehex.value = decodeActive.transcodehex;
|
||||||
|
transcodebin.value = decodeActive.transcodebin;
|
||||||
|
chinafont.value = decodeActive[decodeType.value];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
159
src/components/transcoding/encode.vue
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<template>
|
||||||
|
<el-input
|
||||||
|
placeholder="请输入汉字"
|
||||||
|
v-model="inputfont"
|
||||||
|
type="textarea"
|
||||||
|
resize="none"
|
||||||
|
:rows="10"
|
||||||
|
style="box-shadow: 0 0px 20px -10px rgb(0 0 0 / 0.5);"
|
||||||
|
class="mt-4 mb-4"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<el-select
|
||||||
|
v-model="showType"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
placeholder="选择显示类型"
|
||||||
|
style="width: 106px"
|
||||||
|
class="mr-4"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
<el-button style="font-weight: bold;" type="primary" @click="transformfont(inputfont)">
|
||||||
|
转换汉字
|
||||||
|
</el-button>
|
||||||
|
<el-button style="font-weight: bold;" type="primary" @click="reset">
|
||||||
|
清除
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<el-card v-show="showType == 1" class="mt-4 mb-4">
|
||||||
|
<el-text class="mx-1">
|
||||||
|
汉字: {{ chinafont }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(十进制): {{ transfont ? transfont.join(" , ") : "" }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(十六进制): {{ transfonthex ? transfonthex.join(" , ") : "" }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(二进制): {{ transfontbin ? transfontbin.join(" , ") : "" }}
|
||||||
|
</el-text>
|
||||||
|
</el-card>
|
||||||
|
<div class="flex flex-wrap justify-start items-center gap-4 mt-4 mb-4">
|
||||||
|
<el-card
|
||||||
|
v-for="(item, index) in chinafont"
|
||||||
|
v-show="showType == 0"
|
||||||
|
style="width: 300px"
|
||||||
|
>
|
||||||
|
<el-text class="mx-1">
|
||||||
|
汉字: {{ item }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(十进制): {{ transfont[index] }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(十六进制): {{ transfonthex[index] }}
|
||||||
|
</el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1">
|
||||||
|
编码(二进制): {{ transfontbin[index] }}
|
||||||
|
</el-text>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, onMounted } from "vue";
|
||||||
|
|
||||||
|
import encodeActiveStore from "../../stores/encode";
|
||||||
|
|
||||||
|
import { toFullWidth } from "../../utils/toFullWidth";
|
||||||
|
|
||||||
|
import GBK from "gbk.js";
|
||||||
|
|
||||||
|
const encodeActive = encodeActiveStore();
|
||||||
|
|
||||||
|
const showType = ref(1);
|
||||||
|
const inputfont = ref();
|
||||||
|
const chinafont = ref();
|
||||||
|
const transfont = ref();
|
||||||
|
const transfonthex = ref();
|
||||||
|
const transfontbin = ref();
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: 0,
|
||||||
|
label: "单字",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 1,
|
||||||
|
label: "连续",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const transformfont = (inputfont) => {
|
||||||
|
chinafont.value = inputfont;
|
||||||
|
encodeActive.inputfont = inputfont;
|
||||||
|
//将半角字符转为全角字符
|
||||||
|
let inputfontFullWidth = toFullWidth(inputfont);
|
||||||
|
transfont.value = [];
|
||||||
|
let hex = [], bin = [];
|
||||||
|
inputfontFullWidth.split("").forEach((item) => {
|
||||||
|
transfont.value.push(GBK.encode(item).join(" , "));
|
||||||
|
let hexSingle = [], binSingle = [];
|
||||||
|
GBK.encode(item).forEach((element) => {
|
||||||
|
hexSingle.push(element.toString(16).toUpperCase().length < 2 ? "0" + element.toString(16).toUpperCase() : element.toString(16).toUpperCase());
|
||||||
|
binSingle.push(element.toString(2));
|
||||||
|
});
|
||||||
|
hex.push(hexSingle.join(""));
|
||||||
|
bin.push(binSingle.join(" , "));
|
||||||
|
});
|
||||||
|
encodeActive.transfont = transfont.value;
|
||||||
|
transfonthex.value = hex;
|
||||||
|
encodeActive.transfonthex = transfonthex.value;
|
||||||
|
transfontbin.value = bin;
|
||||||
|
encodeActive.transfontbin = transfontbin.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
inputfont.value = "";
|
||||||
|
chinafont.value = "";
|
||||||
|
transfont.value = "";
|
||||||
|
transfonthex.value = "";
|
||||||
|
transfontbin.value = "";
|
||||||
|
encodeActive.inputfont = "";
|
||||||
|
encodeActive.transfont = "";
|
||||||
|
encodeActive.transfonthex = "";
|
||||||
|
encodeActive.transfontbin = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(inputfont, (value) => {
|
||||||
|
encodeActive.inputfont = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(showType, (value) => {
|
||||||
|
encodeActive.showType = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
showType.value = encodeActive.showType;
|
||||||
|
inputfont.value = encodeActive.inputfont;
|
||||||
|
chinafont.value = encodeActive.inputfont;
|
||||||
|
transfont.value = encodeActive.transfont;
|
||||||
|
transfonthex.value = encodeActive.transfonthex;
|
||||||
|
transfontbin.value = encodeActive.transfontbin;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
23
src/main.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import './assets/main.css'
|
||||||
|
|
||||||
|
import { createApp } from 'vue';
|
||||||
|
import { createPinia } from 'pinia';
|
||||||
|
import piniaPersist from 'pinia-plugin-persist';
|
||||||
|
import ElementPlus from 'element-plus';
|
||||||
|
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
||||||
|
import 'element-plus/dist/index.css';
|
||||||
|
|
||||||
|
import App from './App.vue';
|
||||||
|
import router from './router';
|
||||||
|
|
||||||
|
const app = createApp(App); // 创建 vue 实例
|
||||||
|
|
||||||
|
const store = createPinia(); // 创建 pinia 实例
|
||||||
|
|
||||||
|
store.use(piniaPersist);
|
||||||
|
|
||||||
|
app.use(store);
|
||||||
|
app.use(ElementPlus, { locale: zhCn });
|
||||||
|
app.use(router);
|
||||||
|
|
||||||
|
app.mount('#app');
|
||||||
31
src/router/index.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/main',
|
||||||
|
name: 'main',
|
||||||
|
component: () => import('../views/Main.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/404page',
|
||||||
|
name: '404',
|
||||||
|
component: () => import('../views/404page.vue')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
if (to.matched.length === 0) {
|
||||||
|
if (to.path == "/") {
|
||||||
|
router.push({ path: '/main' });
|
||||||
|
} else {
|
||||||
|
router.push({ path: '/404page' });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
26
src/stores/bindSN.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
|
const bindSNActiveStore = defineStore('bindSN', {
|
||||||
|
state: () => ({
|
||||||
|
// 持久化数据
|
||||||
|
selectedUser: "",
|
||||||
|
selectedSN: "",
|
||||||
|
}),
|
||||||
|
persist: {
|
||||||
|
enabled: true, // Store 中数据持久化生效
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'bindSNActive', // 存储的 key
|
||||||
|
storage: localStorage, // 存储位置
|
||||||
|
paths: ["selectedUser", "selectedSN"], // 需要持久化的字段
|
||||||
|
serializer: {
|
||||||
|
deserialize: parse,
|
||||||
|
serialize: stringify,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default bindSNActiveStore;
|
||||||
37
src/stores/bsideManager.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
|
const bsideManagerActiveStore = defineStore('bsideManager', {
|
||||||
|
state: () => ({
|
||||||
|
// 持久化数据
|
||||||
|
offset: 1,
|
||||||
|
limit: 10,
|
||||||
|
dataCount: 0,
|
||||||
|
pageCount: 0,
|
||||||
|
searchOptions: {
|
||||||
|
account_name: "",
|
||||||
|
user_name: "",
|
||||||
|
phone: "",
|
||||||
|
},
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogSearchVisible: false,
|
||||||
|
dialogSortVisible: false,
|
||||||
|
dialogOperationVisible: false
|
||||||
|
}),
|
||||||
|
persist: {
|
||||||
|
enabled: true, // Store 中数据持久化生效
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'bsideManagerActive', // 存储的 key
|
||||||
|
storage: localStorage, // 存储位置
|
||||||
|
paths: ["offset", "limit", "dataCount", "pageCount", "searchOptions", "dialogVisible", "dialogSearchVisible", "dialogSortVisible", "dialogOperationVisible"], // 需要持久化的字段
|
||||||
|
serializer: {
|
||||||
|
deserialize: parse,
|
||||||
|
serialize: stringify,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default bsideManagerActiveStore;
|
||||||
33
src/stores/decode.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
|
const decodeActiveStore = defineStore('decode', {
|
||||||
|
state: () => ({
|
||||||
|
// 持久化数据
|
||||||
|
decodeType: "",
|
||||||
|
showType: "",
|
||||||
|
fontcode: "",
|
||||||
|
transcode: "",
|
||||||
|
transcodehex: "",
|
||||||
|
transcodebin: "",
|
||||||
|
fontcodedec: "",
|
||||||
|
fontcodehex: "",
|
||||||
|
fontcodebin: "",
|
||||||
|
}),
|
||||||
|
persist: {
|
||||||
|
enabled: true, // Store 中数据持久化生效
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'decodeActive', // 存储的 key
|
||||||
|
storage: localStorage, // 存储位置
|
||||||
|
paths: ["decodeType", "showType", "fontcode", "transcode", "transcodehex", "transcodebin", "fontcodedec", "fontcodehex", "fontcodebin"], // 需要持久化的字段
|
||||||
|
serializer: {
|
||||||
|
deserialize: parse,
|
||||||
|
serialize: stringify,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default decodeActiveStore;
|
||||||
29
src/stores/encode.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
|
const encodeActiveStore = defineStore('encode', {
|
||||||
|
state: () => ({
|
||||||
|
// 持久化数据
|
||||||
|
showType: "",
|
||||||
|
inputfont: "",
|
||||||
|
transfont: "",
|
||||||
|
transfonthex: "",
|
||||||
|
transfontbin: "",
|
||||||
|
}),
|
||||||
|
persist: {
|
||||||
|
enabled: true, // Store 中数据持久化生效
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'encodeActive', // 存储的 key
|
||||||
|
storage: localStorage, // 存储位置
|
||||||
|
paths: ["showType", "inputfont", "transfont", "transfonthex", "transfontbin"], // 需要持久化的字段
|
||||||
|
serializer: {
|
||||||
|
deserialize: parse,
|
||||||
|
serialize: stringify,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default encodeActiveStore;
|
||||||
43
src/stores/historyMsg.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
|
const historyMsgActiveStore = defineStore('historyMsg', {
|
||||||
|
state: () => ({
|
||||||
|
// 持久化数据
|
||||||
|
activeIndex: "1",
|
||||||
|
subActiveIndex: "1",
|
||||||
|
offset: 1,
|
||||||
|
limit: 10,
|
||||||
|
dataCount: 0,
|
||||||
|
pageCount: 0,
|
||||||
|
searchOptions: {
|
||||||
|
sn_number: "",
|
||||||
|
original_msg: "",
|
||||||
|
msg_data: "",
|
||||||
|
created_at: "",
|
||||||
|
},
|
||||||
|
sortOptions: {
|
||||||
|
sn_number: false,
|
||||||
|
created_at: false,
|
||||||
|
},
|
||||||
|
dialogSearchVisible: false,
|
||||||
|
dialogSortVisible: false,
|
||||||
|
dialogOperationVisible: false
|
||||||
|
}),
|
||||||
|
persist: {
|
||||||
|
enabled: true, // Store 中数据持久化生效
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'historyMsgActive', // 存储的 key
|
||||||
|
storage: localStorage, // 存储位置
|
||||||
|
paths: ["activeIndex", "subActiveIndex", "offset", "limit", "dataCount", "pageCount", "searchOptions", "sortOptions", "dialogSearchVisible", "dialogSortVisible", "dialogOperationVisible"], // 需要持久化的字段
|
||||||
|
serializer: {
|
||||||
|
deserialize: parse,
|
||||||
|
serialize: stringify,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default historyMsgActiveStore;
|
||||||
40
src/stores/record.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
|
const recordActiveStore = defineStore('record', {
|
||||||
|
state: () => ({
|
||||||
|
// 持久化数据
|
||||||
|
offset: 1,
|
||||||
|
limit: 10,
|
||||||
|
dataCount: 0,
|
||||||
|
searchOptions: {
|
||||||
|
account_name: "",
|
||||||
|
sn_number: "",
|
||||||
|
type: "",
|
||||||
|
created_at: "",
|
||||||
|
},
|
||||||
|
sortOptions: {
|
||||||
|
sn_number: false,
|
||||||
|
created_at: false,
|
||||||
|
},
|
||||||
|
dialogSearchVisible: false,
|
||||||
|
dialogSortVisible: false,
|
||||||
|
dialogOperationVisible: false
|
||||||
|
}),
|
||||||
|
persist: {
|
||||||
|
enabled: true, // Store 中数据持久化生效
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'recordActive', // 存储的 key
|
||||||
|
storage: localStorage, // 存储位置
|
||||||
|
paths: ["offset", "limit", "dataCount", "searchOptions", "sortOptions", "dialogSearchVisible", "dialogSortVisible", "dialogOperationVisible"], // 需要持久化的字段
|
||||||
|
serializer: {
|
||||||
|
deserialize: parse,
|
||||||
|
serialize: stringify,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default recordActiveStore;
|
||||||
26
src/stores/shortMsg.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
|
const shortMsgActiveStore = defineStore('shortMsg', {
|
||||||
|
state: () => ({
|
||||||
|
// 持久化数据
|
||||||
|
message: "",
|
||||||
|
created_at: ""
|
||||||
|
}),
|
||||||
|
persist: {
|
||||||
|
enabled: true, // Store 中数据持久化生效
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'shortMsgActive', // 存储的 key
|
||||||
|
storage: localStorage, // 存储位置
|
||||||
|
paths: ["message", "created_at"], // 需要持久化的字段
|
||||||
|
serializer: {
|
||||||
|
deserialize: parse,
|
||||||
|
serialize: stringify,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default shortMsgActiveStore;
|
||||||
39
src/stores/snManager.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
|
const snManagerActiveStore = defineStore('snManager', {
|
||||||
|
state: () => ({
|
||||||
|
// 持久化数据
|
||||||
|
offset: 1,
|
||||||
|
limit: 10,
|
||||||
|
dataCount: 0,
|
||||||
|
searchOptions: {
|
||||||
|
sn_number: "",
|
||||||
|
status: "",
|
||||||
|
updated_at: "",
|
||||||
|
},
|
||||||
|
sortOptions: {
|
||||||
|
sn_number: false,
|
||||||
|
updated_at: false,
|
||||||
|
},
|
||||||
|
dialogSearchVisible: false,
|
||||||
|
dialogSortVisible: false,
|
||||||
|
dialogOperationVisible: false
|
||||||
|
}),
|
||||||
|
persist: {
|
||||||
|
enabled: true, // Store 中数据持久化生效
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'snManagerActive', // 存储的 key
|
||||||
|
storage: localStorage, // 存储位置
|
||||||
|
paths: ["offset", "limit", "dataCount", "searchOptions", "sortOptions", "dialogSearchVisible", "dialogSortVisible", "dialogOperationVisible"], // 需要持久化的字段
|
||||||
|
serializer: {
|
||||||
|
deserialize: parse,
|
||||||
|
serialize: stringify,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default snManagerActiveStore;
|
||||||
35
src/stores/userManager.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { parse, stringify } from 'zipson';
|
||||||
|
|
||||||
|
const userManagerActiveStore = defineStore('userManager', {
|
||||||
|
state: () => ({
|
||||||
|
// 持久化数据
|
||||||
|
dialogVisible: false,
|
||||||
|
ruleForm: {
|
||||||
|
account_name: "",
|
||||||
|
user_name: "",
|
||||||
|
phone: "",
|
||||||
|
gender: "",
|
||||||
|
age: "",
|
||||||
|
email: "",
|
||||||
|
address: "",
|
||||||
|
post_code: "",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
persist: {
|
||||||
|
enabled: true, // Store 中数据持久化生效
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
key: 'userManagerActive', // 存储的 key
|
||||||
|
storage: localStorage, // 存储位置
|
||||||
|
paths: ["dialogVisible", "ruleForm"], // 需要持久化的字段
|
||||||
|
serializer: {
|
||||||
|
deserialize: parse,
|
||||||
|
serialize: stringify,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default userManagerActiveStore;
|
||||||
21
src/utils/aes.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import CryptoJS from 'crypto-js';
|
||||||
|
|
||||||
|
const KEY = CryptoJS.enc.Utf8.parse('BDQH');
|
||||||
|
|
||||||
|
export const encrypt = (plaintext) => {
|
||||||
|
if(plaintext !== null && plaintext !== undefined && plaintext !== "") {
|
||||||
|
return CryptoJS.AES.encrypt(plaintext, KEY, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decrypt = (plaintext) => {
|
||||||
|
if(plaintext !== null && plaintext !== undefined && !plaintext == "") {
|
||||||
|
return CryptoJS.AES.decrypt(plaintext, KEY, {
|
||||||
|
mode: CryptoJS.mode.ECB,
|
||||||
|
padding: CryptoJS.pad.Pkcs7
|
||||||
|
}).toString(CryptoJS.enc.Utf8);
|
||||||
|
}
|
||||||
|
};
|
||||||
9
src/utils/hasNullOrEmptyPropertyWithTypeof.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export const hasNullOrEmptyPropertyWithTypeof = (obj) => {
|
||||||
|
let hasNullOrEmpty = false;
|
||||||
|
for (const prop in obj) {
|
||||||
|
if (!(obj.hasOwnProperty(prop) && ((obj[prop] === null) || obj[prop] === undefined || (typeof obj[prop] === 'string' && obj[prop] === '')))) {
|
||||||
|
hasNullOrEmpty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasNullOrEmpty;
|
||||||
|
}
|
||||||
5
src/utils/judgment.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const judgment = (keyWord, key, value, val) => {
|
||||||
|
if (value !== null) {
|
||||||
|
keyWord[key] = value[val];
|
||||||
|
}
|
||||||
|
};
|
||||||
7
src/utils/toFullWidth.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//将半角空格,制表符,回车和半角字符转为全角空格,全角制表符,全角回车和全角字符
|
||||||
|
export const toFullWidth = (str) => {
|
||||||
|
//全角制表符使用4个全角空格模拟
|
||||||
|
return str.replace(/ /g, '\u3000').replace(/\t/g, '\u3000\u3000\u3000\u3000').replace(/\n/g, '\u21B5').replace(/[\x21-\x7E]/g, (font) => {
|
||||||
|
return String.fromCharCode(font.charCodeAt(0) + 0xFEE0);
|
||||||
|
});
|
||||||
|
};
|
||||||
21
src/views/404page.vue
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div class="common-layout w-h-full">
|
||||||
|
<el-text class="mx-1"> 404 not found </el-text>
|
||||||
|
<br />
|
||||||
|
<el-text class="mx-1"> 您搜索的页面不存在 </el-text>
|
||||||
|
<br />
|
||||||
|
<el-button style="font-weight: bold;" type="primary" @click="backHome">返回首页</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const backHome = () => {
|
||||||
|
router.push("/main");
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
186
src/views/Main.vue
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
<template>
|
||||||
|
<el-container class="w-h-full">
|
||||||
|
<el-header class="flex flex-wrap" style="height: 80px; background-color: #f0f0f0">
|
||||||
|
<Header
|
||||||
|
ref="headerRef"
|
||||||
|
@allowManager="allowManager"
|
||||||
|
@connect="connect"
|
||||||
|
@disconnect="disconnect"
|
||||||
|
/>
|
||||||
|
</el-header>
|
||||||
|
<el-main>
|
||||||
|
<Main ref="mainRef" />
|
||||||
|
</el-main>
|
||||||
|
<el-footer class="flex" style="background-color: #f2f2f9">
|
||||||
|
<Footer />
|
||||||
|
</el-footer>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, onBeforeMount, onBeforeUnmount } from "vue";
|
||||||
|
|
||||||
|
import io from "socket.io-client";
|
||||||
|
|
||||||
|
import GBK from "gbk.js";
|
||||||
|
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
import $http from "../api/index";
|
||||||
|
import $url from "../api/url";
|
||||||
|
|
||||||
|
import shortMsgActiveStore from "../stores/shortMsg";
|
||||||
|
|
||||||
|
import Header from "../components/pageStructure/header.vue";
|
||||||
|
import Main from "../components/pageStructure/main.vue";
|
||||||
|
import Footer from "../components/pageStructure/footer.vue";
|
||||||
|
|
||||||
|
const shortMsgActive = shortMsgActiveStore();
|
||||||
|
|
||||||
|
const headerRef = ref(null);
|
||||||
|
const mainRef = ref(null);
|
||||||
|
|
||||||
|
//开发/测试环境
|
||||||
|
// const socket = io("http://127.0.0.1:8110", {
|
||||||
|
// 生产环境
|
||||||
|
const socket = io("http://tq.hwasmart.com:8110", {
|
||||||
|
// path: "/socket.io/",
|
||||||
|
transports: ["websocket", "polling"],
|
||||||
|
reconnection: true,
|
||||||
|
reconnectionDelay: 1000,
|
||||||
|
reconnectionDelayMax: 6000,
|
||||||
|
reconnectionAttempts: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
const decode = (data) => {
|
||||||
|
let arr = [];
|
||||||
|
data.match(/..?/g).forEach((element) => {
|
||||||
|
arr.push(parseInt(element, 16));
|
||||||
|
});
|
||||||
|
return GBK.decode(arr);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMsg = () => {
|
||||||
|
socket.emit("message", headerRef.value.snNumber);
|
||||||
|
socket.removeListener(headerRef.value.snNumber);
|
||||||
|
if (socket.listeners(headerRef.value.snNumber).length == 0) {
|
||||||
|
socket.on(headerRef.value.snNumber, (msg) => {
|
||||||
|
const { encode_type, msg_data, created_at } = msg;
|
||||||
|
mainRef.value.message = Number(encode_type) == 0 ? decode(msg_data) : msg_data;
|
||||||
|
shortMsgActive.message = mainRef.value.message;
|
||||||
|
mainRef.value.created_at = moment
|
||||||
|
.utc(created_at)
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
shortMsgActive.created_at = mainRef.value.created_at;
|
||||||
|
mainRef.value.historyMsg();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const connect = () => {
|
||||||
|
socket.connect();
|
||||||
|
};
|
||||||
|
|
||||||
|
const disconnect = () => {
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
const allowManager = () => {
|
||||||
|
if (headerRef.value.manager) {
|
||||||
|
mainRef.value.manager = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
mainRef.value.color = "color: rgb(56 188 248);";
|
||||||
|
mainRef.value.message = "连接中...";
|
||||||
|
mainRef.value.created_at = moment
|
||||||
|
.utc(new Date())
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
$http.post($url.getSN, { uid: localStorage.data }).then((res) => {
|
||||||
|
if (res.data.code === 200) {
|
||||||
|
headerRef.value.snNumber = res.data.snNumber;
|
||||||
|
|
||||||
|
let connectStatus = false,
|
||||||
|
reconnectStatus = false;
|
||||||
|
socket.on("connect", () => {
|
||||||
|
connectStatus = true;
|
||||||
|
mainRef.value.color = "color: rgb(16 184 130);";
|
||||||
|
mainRef.value.message = "连接成功!";
|
||||||
|
mainRef.value.created_at = moment
|
||||||
|
.utc(new Date())
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
getMsg();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("disconnect", (reason) => {
|
||||||
|
mainRef.value.color = "color: rgb(240 70 70);";
|
||||||
|
mainRef.value.message = "连接断开!请检查网络状态并刷新网页重试!";
|
||||||
|
mainRef.value.created_at = moment
|
||||||
|
.utc(new Date())
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
if (reason === "io server disconnect" || reason === "io client disconnect") {
|
||||||
|
if (headerRef.value.snNumber !== "") {
|
||||||
|
mainRef.value.color = "color: rgb(56 188 248);";
|
||||||
|
mainRef.value.message = "连接中...";
|
||||||
|
mainRef.value.created_at = moment
|
||||||
|
.utc(new Date())
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
socket.removeListener(headerRef.value.snNumber);
|
||||||
|
socket.connect();
|
||||||
|
reconnectStatus = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("connect_error", (err) => {
|
||||||
|
// 如果连接异常,修改transports传输方式
|
||||||
|
socket.io.opts.transports = ["websocket", "polling"];
|
||||||
|
if (reconnectStatus) {
|
||||||
|
setTimeout(() => {
|
||||||
|
reconnectStatus = false;
|
||||||
|
mainRef.value.color = "color: rgb(240 70 70);";
|
||||||
|
mainRef.value.message = "连接异常!请检查网络状态并刷新网页重试!";
|
||||||
|
mainRef.value.created_at = moment
|
||||||
|
.utc(new Date())
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
}, socket.io.opts.reconnectionAttempts * socket.io.opts.reconnectionDelayMax);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!connectStatus) {
|
||||||
|
mainRef.value.color = "color: rgb(240 70 70);";
|
||||||
|
mainRef.value.message = "连接异常!请检查网络状态并刷新网页重试!";
|
||||||
|
mainRef.value.created_at = moment
|
||||||
|
.utc(new Date())
|
||||||
|
.add(8, "hours")
|
||||||
|
.format("YYYY-MM-DD-HH:mm:ss");
|
||||||
|
}
|
||||||
|
}, socket.io.opts.reconnectionAttempts * socket.io.opts.reconnectionDelayMax);
|
||||||
|
} else {
|
||||||
|
socket.disconnect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
if (socket) {
|
||||||
|
socket.connect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (socket) {
|
||||||
|
socket.disconnect(); // 组件卸载时断开连接
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
13
tailwind.config.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
purge: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
||||||
|
darkMode: false, // or 'media' or 'class'
|
||||||
|
content: [],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
54
vite.config.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import AutoImport from 'unplugin-auto-import/vite'
|
||||||
|
import Components from 'unplugin-vue-components/vite'
|
||||||
|
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||||
|
import legacy from '@vitejs/plugin-legacy'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
base: './',
|
||||||
|
publicPath: './',
|
||||||
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
AutoImport({
|
||||||
|
resolvers: [ElementPlusResolver()],
|
||||||
|
}),
|
||||||
|
Components({
|
||||||
|
resolvers: [ElementPlusResolver()],
|
||||||
|
}),
|
||||||
|
legacy({
|
||||||
|
target: ['ie>=11'],
|
||||||
|
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
//用来配置跨域
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 7003,
|
||||||
|
proxy: {
|
||||||
|
'/authentication': {
|
||||||
|
target: 'http://127.0.0.1:8011',//鉴权服务器地址
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/authentication/, '')
|
||||||
|
},
|
||||||
|
'/snShortMessage': {
|
||||||
|
target: 'http://127.0.0.1:8120',//资源服务器地址
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/snShortMessage/, '')
|
||||||
|
},
|
||||||
|
'/snWebSocket': {
|
||||||
|
target: 'http://127.0.0.1:8110',//webSocket服务器地址
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/snWebSocket/, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||