This commit is contained in:
chengdandan 2024-09-18 17:16:34 +08:00
commit 7ea431d689
55 changed files with 8014 additions and 0 deletions

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

5
.env Normal file
View File

@ -0,0 +1,5 @@
# 基本环境
VITE_APP_NAME=''
# 基本请求地址
VITE_BASE_URL=''
VITE_BASE_URLM='http://172.16.1.253:4000'

4
.env.production Normal file
View File

@ -0,0 +1,4 @@
# 基本环境
VITE_APP_NAME=''
# 基本请求地址
VITE_BASE_URL=''

36
.eslintrc.cjs Normal file
View File

@ -0,0 +1,36 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'standard',
'plugin:vue/vue3-essential'
],
overrides: [
{
env: {
node: true
},
files: [
'.eslintrc.{js,cjs}'
],
parserOptions: {
sourceType: 'script'
}
}
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
},
plugins: [
'vue'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/multi-word-component-names': 'off'
}
}

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).

14
babel.config.js Normal file
View File

@ -0,0 +1,14 @@
{
'plugins'[
[
'import',
{
libraryName: 'element-plus',
customStyleName: (name) => {
// 注意:这里需要确保你的样式文件名是 `style.css`,否则需要进行相应调整
return `element-plus/lib/theme-chalk/${name}.css`
}
}
]
]
}

16
index.html Normal file
View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>阜阳大屏可视化
</title>
<!-- <link rel="stylesheet" href="//at.alicdn.com/t/c/font_4490429_ym69s57vxr.css"> -->
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

5379
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

39
package.json Normal file
View File

@ -0,0 +1,39 @@
{
"name": "databoard",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "vite build",
"build:production": "vite build --mode production",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
"dev": "vite",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.6.7",
"echarts": "^5.5.0",
"element-plus": "^2.5.6",
"font-awesome": "^4.7.0",
"jsencrypt": "^3.3.2",
"pinia": "^2.1.7",
"vue": "^3.4.15",
"vue-router": "^4.2.5",
"vue3-seamless-scroll": "^2.0.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.3",
"babel-plugin-import": "^1.13.8",
"eslint": "^8.57.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.22.0",
"file-loader": "^6.2.0",
"less": "^4.2.0",
"sass": "~1.26.5",
"sass-loader": "^13.3.2",
"vite": "^5.1.0"
},
"type": "module"
}

72
public/demo.html Normal file
View File

@ -0,0 +1,72 @@
<!DOCTYPE HTML>
<html>
<body>
<video id="pre" width="100%" height="100%" controls="controls" autoplay="autoplay">
<source src="" type="video/mp4">
Your browser does not support the video tag.
</video>
<script type="text/javascript">
// import md5 from 'js-md5'
// APPKEY = "f8db0c75";
// SECRET = "41455e9d614643569a53bd338d095062";
// OPENAPI_IP_PORT_HTTP = "http://127.0.0.1:80";
// ITF_ADDRESS_GET_DEFAULT_USER_UUID = "/openapi/service/base/user/getDefaultUserUuid";
// ITF_ADDRESS_GET_CAMERAS = "/openapi/service/vss/res/getCameras";
var para = getParams(window.location.href);
console.log(para["CameraUuid"])
document.getElementById("pre").src="http://10.20.146.131:6713/mag/hls/"+para["CameraUuid"]+"/0/live.m3u8";
// var data1 = testGetDefaultUserUUID();
// var data2 = testGetCameras();
// function testGetDefaultUserUUID() {
// url = OPENAPI_IP_PORT_HTTP + ITF_ADDRESS_GET_DEFAULT_USER_UUID;
// data = { "appkey": APPKEY, "time": Date.now() };
// str = JSON.stringify(data);
// callurl = url + "?token=" + md5(url + str + SECRET);
// $.ajax({ /* url 地址可以是 /get-json/ 的方式 * 也可以是 http://www.qfedu.com/get-json/ 的方式 */
// url: callurl,
// type: 'POST',
// async: false,
// dataType: 'json',
// data: str,
// success: function (res) {
// // 成功处理逻辑
// console.log(res)
// }, error: function (res) {
// // 错误时处理逻辑
// console.log(res)
// }
// });
// }
// function testGetCameras() {
// url = OPENAPI_IP_PORT_HTTP + ITF_ADDRESS_GET_CAMERAS;
// data = { "appkey": APPKEY, "time": Date.now() ,"pageNo": 1,"pageSize":1000};
// }
function getParams(url) {
const regex = /[?&]([^=#]+)=([^&#]*)/g;
const params = {};
let match;
while (match = regex.exec(url)) {
params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
}
return params;
}
</script>
</body>
</html>

1
public/vite.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 111 KiB

11
src/App.vue Normal file
View File

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
<router-view />
</template>
<style scoped>
/* @import url('@/assets/fonts/index.css'); */
/* @import "assets/fonts/FontIcon/iconfont.css"; */
</style>

21
src/api/file.js Normal file
View File

@ -0,0 +1,21 @@
import { get, post, download, uploadFile } from './request'
// 导入业务统计接口
export const ImportBusinessStatistics = (params) => {
return uploadFile('/api/ImportBusinessStatistics', params)
}
// 下载业务统计接口
export const DownloadBusinessStatistics = (params) => {
return download('/api/DownloadBusinessStatistics', params)
}
// 获取表格分页接口
export const GetBusinessStatisticsList = (params) => {
return get('/api/GetBusinessStatisticsList', params)
}
// 地图页获取业务统计接口
export const GetBusinessStatistics = (params) => {
return get('/api/GetBusinessStatistics', params)
}
/// /下载业务统计模板接口
export const DownloadTemplate = (params) => {
return download('/api/DownloadTemplate', params)
}

6
src/api/index.js Normal file
View File

@ -0,0 +1,6 @@
import { get, post, download, uploadFile } from './request'
// 登录
export const apiLogin = (params) => {
return post('/api/Login', params)
}

98
src/api/request.js Normal file
View File

@ -0,0 +1,98 @@
import axios from 'axios'
// import { useRouter } from 'vue-router'
// 带cookie请求
axios.defaults.headers.post['Content-Type'] = 'application/json'
const http = axios.create({
// baseURL: 'http://admin.umayle.com'
baseURL: `${import.meta.env.VITE_BASE_URL}`
})
// request 请求拦截器 - 请求之前headers加sid
http.interceptors.request.use(
config => {
if (config.url.indexOf('/login') < 0 && localStorage.getItem('token')) {
config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`
}
// 每次发送请求之前检测都vuex存有token,那么都要放在请求头发送给服务器
return config
},
err => {
return err
}
)
// const router = useRouter()
// // response 错误统一处理
http.interceptors.response.use(
res => {
return res.data
},
err => {
console.log('接口访问失败')
// localStorage.removeItem('token')
// router.push('/Login')
return err
}
)
// 封装请求的api
const callapi = (method = 'GET', url, data = {}) => {
const params = method === 'GET' ? data : {}
const body = ['POST', 'PUT', 'PATCH'].includes(method) ? data : {}
const options = { method, url, params, data: body }
return http(options)
}
export const upload = (url, file) => {
return new Promise((resolve, reject) => {
http
.post(url, file, {
headers: { 'Content-Type': 'multipart/form-data' }
})
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err.data)
})
})
}
export const uploadFile = (url, file) => {
return new Promise((resolve, reject) => {
http
.post(url, file, {
headers: { 'Content-Type': 'multipart/form-data' }
})
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
})
}
export const download = (url, data = {}, method = 'GET') => {
const params = method === 'GET' ? data : {}
const body = ['POST', 'PUT', 'PATCH'].includes(method) ? data : {}
const options = { method, url, params, data: body, responseType: 'blob' }
console.log(options, 'options--')
return http(options)
}
// 导出
export const downloadPost = (url, data = {}, method = 'POST') => {
const params = method === 'GET' ? data : {}
const body = ['POST', 'PUT', 'PATCH'].includes(method) ? data : {}
const options = { method, url, params, data: body, responseType: 'blob' }
console.log(options, 'options--')
return http(options)
}
// 封装GET请求函数
export const get = (url, data) => callapi('GET', url, data)
export const post = (url, data) => callapi('POST', url, data)
export const put = (url, data) => callapi('PUT', url, data)
export const deleteapi = (url, data) => callapi('DELETE', url, data)
export const patchApi = (url, data) => callapi('PATCH', url, data)

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@ -0,0 +1,333 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/>
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/>
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
<link rel="stylesheet" href="demo.css">
<link rel="stylesheet" href="iconfont.css">
<script src="iconfont.js"></script>
<!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
<!-- 代码高亮 -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
<style>
.main .logo {
margin-top: 0;
height: auto;
}
.main .logo a {
display: flex;
align-items: center;
}
.main .logo .sub-title {
margin-left: 0.5em;
font-size: 22px;
color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
</head>
<body>
<div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
</a></h1>
<div class="nav-tabs">
<ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li>
<li class="dib"><span>Font class</span></li>
<li class="dib"><span>Symbol</span></li>
</ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=4490429" target="_blank" class="nav-more">查看项目</a>
</div>
<div class="tab-container">
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe61d;</span>
<div class="name">分析管理</div>
<div class="code-name">&amp;#xe61d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe6d2;</span>
<div class="name">实训管理</div>
<div class="code-name">&amp;#xe6d2;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe821;</span>
<div class="name">学习管理</div>
<div class="code-name">&amp;#xe821;</div>
</li>
<!-- 新增客户端管理 -->
<li class="dib">
<span class="icon iconfont">&#xe821;</span>
<div class="name">客户端管理</div>
<div class="code-name">&amp;#xe821;</div>
</li>
<!-- 新增客户端管理 end-->
<li class="dib">
<span class="icon iconfont">&#xe601;</span>
<div class="name">grade</div>
<div class="code-name">&amp;#xe601;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe602;</span>
<div class="name">exam</div>
<div class="code-name">&amp;#xe602;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe603;</span>
<div class="name">system</div>
<div class="code-name">&amp;#xe603;</div>
</li>
</ul>
<div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2>
<hr>
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul>
<li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul>
<blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
</blockquote>
<p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1716193171193') format('woff2'),
url('iconfont.woff?t=1716193171193') format('woff'),
url('iconfont.ttf?t=1716193171193') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
<pre><code class="language-css"
>.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
<pre>
<code class="language-html"
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-fenxiguanli"></span>
<div class="name">
分析管理
</div>
<div class="code-name">.icon-fenxiguanli
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shixunguanli"></span>
<div class="name">
实训管理
</div>
<div class="code-name">.icon-shixunguanli
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xuexiguanli"></span>
<div class="name">
学习管理
</div>
<div class="code-name">.icon-xuexiguanli
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-chengji"></span>
<div class="name">
grade
</div>
<div class="code-name">.icon-chengji
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-kaoshi"></span>
<div class="name">
exam
</div>
<div class="code-name">.icon-kaoshi
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xitong"></span>
<div class="name">
system
</div>
<div class="code-name">.icon-xitong
</div>
</li>
</ul>
<div class="article markdown">
<h2 id="font-class-">font-class 引用</h2>
<hr>
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
</code></pre>
<blockquote>
<p>"
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p>
</blockquote>
</div>
</div>
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-fenxiguanli"></use>
</svg>
<div class="name">分析管理</div>
<div class="code-name">#icon-fenxiguanli</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shixunguanli"></use>
</svg>
<div class="name">实训管理</div>
<div class="code-name">#icon-shixunguanli</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xuexiguanli"></use>
</svg>
<div class="name">学习管理</div>
<div class="code-name">#icon-xuexiguanli</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-chengji"></use>
</svg>
<div class="name">grade</div>
<div class="code-name">#icon-chengji</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-kaoshi"></use>
</svg>
<div class="name">exam</div>
<div class="code-name">#icon-kaoshi</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xitong"></use>
</svg>
<div class="name">system</div>
<div class="code-name">#icon-xitong</div>
</li>
</ul>
<div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2>
<hr>
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
<ul>
<li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul>
<p>使用步骤如下:</p>
<h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
</code></pre>
<h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
<pre><code class="language-html">&lt;style&gt;
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
&lt;/style&gt;
</code></pre>
<h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
&lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
&lt;/svg&gt;
</code></pre>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('.tab-container .content:first').show()
$('#tabs li').click(function (e) {
var tabContent = $('.tab-container .content')
var index = $(this).index()
if ($(this).hasClass('active')) {
return
} else {
$('#tabs li').removeClass('active')
$(this).addClass('active')
tabContent.hide().eq(index).fadeIn()
}
})
})
</script>
</body>
</html>

View File

@ -0,0 +1,39 @@
@font-face {
font-family: "iconfont"; /* Project id 4490429 */
src: url('iconfont.woff2?t=1716193171193') format('woff2'),
url('iconfont.woff?t=1716193171193') format('woff'),
url('iconfont.ttf?t=1716193171193') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-fenxiguanli:before {
content: "\e61d";
}
.icon-shixunguanli:before {
content: "\e6d2";
}
.icon-xuexiguanli:before {
content: "\e821";
}
.icon-chengji:before {
content: "\e601";
}
.icon-kaoshi:before {
content: "\e602";
}
.icon-xitong:before {
content: "\e603";
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,60 @@
{
"id": "4490429",
"name": "LKJC",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "9096254",
"name": "分析管理",
"font_class": "fenxiguanli",
"unicode": "e61d",
"unicode_decimal": 58909
},
{
"icon_id": "11101584",
"name": "实训管理",
"font_class": "shixunguanli",
"unicode": "e6d2",
"unicode_decimal": 59090
},
{
"icon_id": "36656926",
"name": "学习管理",
"font_class": "xuexiguanli",
"unicode": "e821",
"unicode_decimal": 59425
},
//
{
"icon_id": "36656927",
"name": "客户端管理",
"font_class": "kehuduanguanli",
"unicode": "e821",
"unicode_decimal": 59427
},
// end
{
"icon_id": "39758479",
"name": "grade",
"font_class": "chengji",
"unicode": "e601",
"unicode_decimal": 58881
},
{
"icon_id": "39758508",
"name": "exam",
"font_class": "kaoshi",
"unicode": "e602",
"unicode_decimal": 58882
},
{
"icon_id": "39758529",
"name": "system",
"font_class": "xitong",
"unicode": "e603",
"unicode_decimal": 58883
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,27 @@
@font-face {
font-family: 'Microsoft-YaHei';
src: url('./msyh.ttc') format('truetype');
}
@font-face {
font-family: 'D-DIN-Bold';
src: url('./D-DIN-Bold.otf') format('opentype');
}
@font-face {
font-family: 'DouyinSansBold';
src: url('./DouyinSansBold.otf') format('opentype');
}
@font-face {
font-family: '思源黑体 CN Heavy';
src: url('./SourceHanSansCN-Heavy.ttf') format('opentype');
}
@font-face {
font-family: '思源黑体 CN Regular';
src: url('./SourceHanSansCN-Regular.ttf') format('opentype');
}
@font-face {
font-family: '优设标题黑';
src: url('./优设标题黑.ttf') format('opentype');
}

BIN
src/assets/fonts/msyh.ttc Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
src/assets/login/Login.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

BIN
src/assets/menu/delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

BIN
src/assets/menu/exam.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/assets/menu/grade.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
src/assets/menu/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
src/assets/menu/reset.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

BIN
src/assets/menu/search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

BIN
src/assets/menu/toLead.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

19
src/common/js/public.js Normal file
View File

@ -0,0 +1,19 @@
export const updateCountdown = (targetDate) => {
if (!targetDate) {
targetDate = new Date().getFullYear()
}
const targetTime = new Date(targetDate + '-12-31').getTime()
const currentDate = new Date().getTime()
const timeRemaining = targetTime - currentDate
const days = Math.floor(timeRemaining / (1000 * 60 * 60 * 24))
const hours = Math.floor((timeRemaining % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
const minutes = Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60))
const seconds = Math.floor((timeRemaining % (1000 * 60)) / 1000)
return [days, hours, minutes, seconds]
}
export const getImgName = (imagePath) => {
// const imagePath = 'http://admin.umayle.com/upload/userphoto/郑亚丽.jpg' // 假设这是图片路径
return imagePath.split('/').pop()
}

11
src/fontChart/chart.js Normal file
View File

@ -0,0 +1,11 @@
export function fontChart (res) {
const docEl = document.documentElement
const clientWidth =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth
if (!clientWidth) return
// 此处的3840 为设计稿的宽度,记得修改!
const fontSize = clientWidth / 1920
return res * fontSize
}

76
src/layout/Tab.vue Normal file
View File

@ -0,0 +1,76 @@
<template lang="">
<div class="tag-list">
<el-tag v-for="(tag,index) in tagsList" :key="tag.name" closable :class="{'isActive':tagsActiveIndex===index}"
@click="tagClick(tag,index)" @close="tagClose(index)">
{{ tag.name }}
</el-tag>
</div>
</template>
<script setup>
import { useRoute, useRouter } from 'vue-router'
import { watch, ref } from 'vue'
const route = useRoute()
const router = useRouter()
const tagsList = ref([])
const tagsActiveIndex = ref(1)
const tagClick = (item, index) => {
router.push(item.path)
tagsActiveIndex.value = index
}
const tagClose = (index) => {
const _path = tagsList.value[tagsActiveIndex.value].path
tagsList.value.splice(index, 1)
if (tagsActiveIndex.value === index) {
tagsActiveIndex.value = index > 0 ? index - 1 : 1
router.push(tagsList.value[tagsActiveIndex.value].path)
} else {
const hasIndex = tagsList.value.findIndex((v) => v.path === _path)
tagsActiveIndex.value = hasIndex
}
}
watch(
() => route,
(newValue, oldValue) => {
const hasIndex = tagsList.value.findIndex((v) => v.path === newValue.path)
if (hasIndex < 0 && newValue.meta.title !== '') {
tagsList.value.push({
name: newValue.meta.title,
path: newValue.path
})
tagsActiveIndex.value = tagsList.value.length - 1
} else {
// tagsActiveIndex.value = hasIndex;
}
},
{ immediate: true, deep: true }
)
</script>
<style lang="scss" scoped>
.tag-list {
.el-tag{
background: rgba(69, 85, 82, 0.10);
color:rgba(69, 85, 82, 1);
margin-right: 10px;
cursor: pointer;
&.isActive {
background: rgba(69, 85, 82, 0.10);
color:rgba(69, 85, 82, 1);
::v-deep{
.el-icon{
color:rgba(69, 85, 82, 1);
}
}
}
}
}
:deep(.el-tag__close){
color:rgba(69, 85, 82, 1) !important;
}
:deep(.el-tag__close:hover){
background-color: transparent !important;
}
</style>

196
src/layout/index.vue Normal file
View File

@ -0,0 +1,196 @@
<script setup>
import { ref } from 'vue'
import { ArrowDown } from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus'
import mock from '@/router/menu/index.js'
import Tab from './Tab.vue'
import { useRouter } from 'vue-router'
const router = useRouter()
// import useUserStore from '@/store/index.js'
// const userStore = useUserStore()
//
const isCollapse = ref(false)
const handleOpen = (key, keyPath) => {
console.log(key, keyPath)
}
const handleClose = (key, keyPath) => {
console.log(key, keyPath)
}
// 退
function loginOut () {
ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
router.push('/Login')
})
}
</script>
<template>
<section class="common-layout">
<el-container class="layout">
<el-header>
<el-header>
<div class="img">
</div>
<div class="Administrator">
<el-dropdown trigger="click">
<span class="el-dropdown-link">
超级管理员
<el-icon class="el-icon--right"><arrow-down /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="loginOut">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-header>
</el-header>
<el-container class="ContainerConent">
<el-aside>
<aside>
<div class="Sidebar">
<el-menu
default-active="0"
class="el-menu-vertical-demo"
:collapse="isCollapse"
@open="handleOpen"
@close="handleClose"
>
<!-- <el-menu-item :index="String(0)" @click="$router.push(mock[0].path)">
<template #title>
<i :class="['iconfont', mock[0].meta.icon]"></i>
<span>{{ mock[0].meta.title }}</span>
</template>
</el-menu-item>
<el-menu-item :index="String(1)" @click="$router.push(mock[1].path)">
<template #title>
<i :class="['iconfont', mock[1].meta.icon]"></i>
<span>{{ mock[1].meta.title }}</span>
</template>
</el-menu-item> -->
<el-menu-item :index="String(0)" @click="$router.push(mock[0].path)">
<template #title>
<i :class="['iconfont', mock[0].meta.icon]"></i>
<span>{{ mock[0].meta.title }}</span>
</template>
</el-menu-item>
</el-menu>
</div>
</aside>
</el-aside>
<el-container class="mainContent">
<div class="Tool">
<Tab></Tab>
</div>
<el-main>
<router-view/>
</el-main>
</el-container>
</el-container>
</el-container>
</section>
</template>
<style scoped lang="scss">
.common-layout{
width: 100vw;
height: 100vh;
overflow: hidden;
}
.layout{
width: 100%;
height: 100%;
}
.el-menu{
border: none;
}
.el-header {
width: 100%;
height: 60px;
background-color: white;
padding: 0;
// .img {
// width: 126px;
// height: 37px;
// margin-top: 5px;
// margin-left: 10px;
// background: url("../assets/menu/logo.png") no-repeat;
// background-size: 100% 100%;
// }
}
.ContainerConent{
width: 100%;
height: calc(100% - 60px);
background-color: rgba(246, 249, 248, 1);
}
.el-aside{
width: 200px;
height: 100%;
background-color: #fff;
}
.mainContent{
width: 100%;
height: 100%;
display: block;
padding:17px 20px;
}
.Tool{
width: 100%;
height: 24px;
.el-tabs{
width: 100%;
height: 24px;
}
:deep(.el-tabs__header){
border:none !important;
}
:deep(.el-tabs__item ){
width: 88px;
height: 24px;
background-color: rgba(69, 85, 82, 0.10);
}
}
.el-main{
padding: 0;
height: calc(100% - 34px);
width: 100%;
margin-top:16px ;
overflow: hidden;
}
.el-menu-item.is-active{
color: #0D867F;
}
.iconfont{
margin-right: 16px;
}
.Administrator{
float: right;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 40px;
cursor: pointer;
}
:deep(.el-dropdown-link){
border: none!important;
}
:deep(.el-dropdown-link){
border: none!important;
}
:deep(.example-showcase .el-dropdown-link) {
cursor: pointer;
color: var(--el-color-primary);
display: flex;
align-items: center;
}
</style>

12
src/main.js Normal file
View File

@ -0,0 +1,12 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
import zhCN from 'element-plus/dist/locale/zh-cn.mjs' // 引入中文
import './style/reset.css'
import './assets/fonts/index.css'
import store from '@/store'
import vue3SeamlessScroll from 'vue3-seamless-scroll'
createApp(App).use(router).use(store).use(vue3SeamlessScroll).use(ElementPlus, { locale: zhCN }).mount('#app')

36
src/router/index.js Normal file
View File

@ -0,0 +1,36 @@
import { createRouter, createWebHashHistory } from 'vue-router'
// 引入其他组件...
const routes = [
{
path: '/',
name: '',
redirect: '/TrainingManage'
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/login/index.vue')
},
{
path: '/TrainingManage',
name: 'TrainingManage',
component: () => import('@/layout/index.vue'),
redirect: '/TrainingManage',
children: [
{
path: '/TrainingManage',
component: () => import('@/views/TrainingManage/index.vue'),
meta: { sort: 5, title: '文本管理', icon: '' }
}
]
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router

9
src/router/menu/index.js Normal file
View File

@ -0,0 +1,9 @@
// import {ref} from "vue";
export default [
{
path: 'TrainingManage',
meta: { sort: 1, title: '文本管理', icon: 'icon-chengji' }
}
]

3
src/store/index.js Normal file
View File

@ -0,0 +1,3 @@
import { createPinia } from 'pinia'
const store = createPinia()
export default store

142
src/style/reset.css Normal file
View File

@ -0,0 +1,142 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
box-sizing: border-box;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
width: 100vw;
height: 100vh;
font-family: "Microsoft YaHei", "PingFangSC-Regular", "Helvetica Neue",
"Helvetica", "Hiragino Sans GB", "SimSun", "sans-serif";
font-size: 14px;
overflow: hidden;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: "";
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
#app {
width: 100%;
height: 100%;
overflow: hidden;
}

View File

@ -0,0 +1,41 @@
function _registerEvent (target, eventType, cb) {
if (target.addEventListener) {
target.addEventListener(eventType, cb)
return {
remove: function () {
target.removeEventListener(eventType, cb)
}
}
} else {
target.attachEvent(eventType, cb)
return {
remove: function () {
target.detachEvent(eventType, cb)
}
}
}
}
export function openUriWithTimeoutHack (uri, failCb, successCb) {
console.log('uri', uri)
const timeout = setTimeout(function () {
failCb()
handler.remove()
}, 1000)
// handle page running in an iframe (blur must be registered with top level window)
let target = window
while (target !== target.parent) {
target = target.parent
}
var handler = _registerEvent(target, 'blur', onBlur)
function onBlur () {
clearTimeout(timeout)
handler.remove()
successCb()
}
window.location = uri
}

View File

@ -0,0 +1,531 @@
<template>
<div class="PageContent">
<div class="WebToolbar">
<div class="FormComponent">
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="时间">
<el-date-picker v-model="form.StatisticsTime" value-format="YYYY-MM-DD" type="date" placeholder="请选择时间" />
</el-form-item>
</el-form>
</div>
<div class="ButtonAssembly">
<el-button style="color: #fff" @click="queryData()">
<img src="../../assets/menu/search.png" alt="" />
<span>查询</span>
</el-button>
<el-button style="color: #1d2129" @click="resetFormInline">
<img src="../../assets/menu/reset.png" alt="" />
<span>重置</span>
</el-button>
</div>
</div>
<div class="Tabulation">
<div class="actionBar">
<h1>文本列表</h1>
<div class="Worktop">
<el-button class="BlueBack" @click="dialogToLead = true">
<!-- <img src="../../../assets/menu/toLead.png" alt=""/> -->
<span>新增</span>
</el-button>
</div>
</div>
<div class="ExaminationForm">
<el-table
ref="multipleTableRef"
:data="tableData"
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" />
<el-table-column label="序号" type="index" :index="indexMethod" width="60px"/>
<el-table-column property="StatisticsTime" label="表时间" />
<el-table-column property="CreateTime" label="创建时间" />
<el-table-column property="" label="操作">
<template v-slot="scope">
<el-button @click="handleDown(scope.row)">下载</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="InlineForm.PageIndex"
:page-size="InlineForm.PageSize"
:small="small"
:disabled="disabled"
:background="background"
layout="total, prev, pager, next"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</div>
<!-- 新增 -->
<el-dialog v-model="dialogToLead" title="新增" style="width:30%;height:50%" >
<el-form-item label="上传:" prop="SoftwareName">
<el-upload
ref="uploadRef"
action="#"
:http-request="toUpload"
:auto-upload="false"
:on-change="handleChange"
:limit="1"
:on-exceed="handleExceed"
:before-remove="handleRemove"
>
<template #trigger>
<el-button type="primary" >选择</el-button>
</template>
<el-button class="ml-3" type="success" @click="submitUpload"> 上传 </el-button>
</el-upload>
</el-form-item>
</el-dialog>
</template>
<script setup>
import { ref, reactive, onMounted, nextTick, getCurrentInstance } from 'vue'
import { ElTable, ElMessageBox, ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import {
ImportBusinessStatistics,
DownloadBusinessStatistics,
GetBusinessStatisticsList,
DownloadTemplate
} from '@/api/file.js'
const formInline = reactive({
// StatisticsId: '',
StatisticsTime: '',
PageIndex: 1,
PageSize: 10
})
const resetFormInline = () => {
// formInline.StatisticsId = ''
formInline.StatisticsTime = ''
getTable()
// for (const key in formInline) {
// if ( key !== 'PageIndex' || key !== 'PageIndex' ) formInline[key] = ''
// }
}
//
const indexMethod = (index) => {
return index + 1
}
//
const formRef = ref(null)
const dialogFormVisible = ref(false)
function handleCreate () {
dialogFormVisible.value = true
}
const formLabelWidth = '150px'
const value1 = ref('')
const value2 = ref('')
const state = reactive({
rules: {},
scenemList: [],
platformAreaList: [],
lineList: []
})
const form = reactive({
EnterpriseName: '',
DistrictCode: '',
EnterpriseCode: '',
ModelName: '',
VersionNumber: '',
MapLongitude: '',
MapLatitude: '',
TrainingSize: '',
ModelResourcesPath: '',
ModelResources: '',
UpdateTime: ''
})
//
onMounted(() => {
getTable()
})
//
const total = ref(0)
const tableData = ref([])
const queryData = () => {
formInline.PageIndex = 1
getTable()
}
const getTable = async () => {
try {
const { code, data } = await GetBusinessStatisticsList({
...formInline
})
if (code === 0) {
console.log('data', data)
total.value = data.total
tableData.value = data.list
} else {
total.value = 0
tableData.value = []
}
} catch (error) {}
}
//
// const handleDownloadUser = () => {
// DownloadTemplate({ FileName: 'Upload/Excel/.xlsx' }).then(res => {
// // console.log(res, 'res--')
// const b = new Blob([res])
// const url = window.URL.createObjectURL(b)
// const a = document.createElement('a')
// a.href = url
// a.download = '.xlsx'
// document.body.appendChild(a)
// a.click()
// window.URL.revokeObjectURL(url)
// })
// }
//
const uploadRef = ref()
const handleChange = (file, fileList) => {
// uploadRef.value.clearFiles()
console.log(uploadRef.value)
}
const handleExceed = (files) => {
uploadRef.value.clearFiles()
nextTick(() => {
uploadRef.value.handleStart(files[0])
})
}
const uploadFile = ref({})
const submitUpload = () => {
uploadRef.value.submit()
}
//
const { proxy } = getCurrentInstance()
const handleRemove = (file, fileList) => {}
const toUpload = async (param) => {
// if (!uploadRef.value) return ElMessage.error('')
const formData = new FormData()
uploadFile.value = param.file
console.log(param.file, ' param.file')
formData.append('Files', param.file)
console.log(formData, ' param')
await ImportBusinessStatistics(formData).then((res) => {
if (res.code === 0) {
ElMessage({
message: '上传成功',
type: 'success'
})
// // DOM
getTable()
setTimeout(() => {
dialogToLead.value = false
proxy.$refs.uploadRef.handleRemove(param.file)
}, 600)
} else {
ElMessage.error(res?.data || '操作失败')
}
})
}
const multipleTableRef = ref()
const multipleSelection = ref([])
const handleSelectionChange = (val) => {
if (val.length > 1) {
multipleTableRef.value.clearSelection()
multipleTableRef.value.toggleRowSelection(val.pop())
} else {
// this.currentRow = val.pop();
multipleSelection.value = val
}
}
const textarea = ref('')
const small = ref(false)
const background = ref(false)
const disabled = ref(false)
//
const InlineForm = reactive({
PageIndex: 1,
PageSize: 10
})
const handleSizeChange = (val) => {
// console.log(`${val} items per page`)
formInline.PageSize = val
getTable()
}
const dialogToLead = ref(false)
const handleCurrentChange = (val) => {
// console.log(`current page: ${val}`)
formInline.PageIndex = val
getTable()
}
const StatisticsId = ref('')
const handleDown = (row) => {
// fileListFile.value = ref([])
// const fileListFile1 = ref([])
DownloadBusinessStatistics({ StatisticsId: row.StatisticsId }).then(res => {
// console.log(res, 'res--')
const bNE = new Blob([res])
const urlNE = window.URL.createObjectURL(bNE)
const aNE = document.createElement('a')
aNE.href = urlNE
aNE.download = '业务统计表.xlsx'
document.body.appendChild(aNE)
aNE.click()
window.URL.revokeObjectURL(urlNE)
})
}
//
const closeDialog = () => {
for (const key in form) {
form[key] = ''
}
StatisticsId.value = ''
dialogFormVisible.value = false
}
</script>
<style scoped lang="scss">
.PageContent {
width: 100%;
height: 100%;
}
.WebToolbar {
width: 100%;
height: 72px;
background-color: #fff;
padding: 20px;
display: flex;
justify-content: space-between;
:deep(.el-form-item__content) {
width: 256px !important;
height: 32px !important;
}
:deep(.el-input) {
width: 256px !important;
}
:deep(.el-select) {
width: 256px !important;
}
:deep(.el-form-item__label) {
color: #666 !important;
}
}
.ButtonAssembly {
.el-button {
width: 84px;
height: 32px;
border: none;
font-weight: 400;
font-size: 14px;
border-radius: 2px 2px 2px 2px;
img {
width: 16px;
height: 16px;
margin-right: 8px;
}
}
.el-button:nth-child(1) {
background-color: #0d867f;
}
.el-button:nth-child(2) {
background-color: #f2f3f5;
}
}
.Tabulation {
width: 100%;
height: calc(100% - 72px);
background-color: #fff;
margin-top: 14px;
padding: 20px;
.actionBar {
display: flex;
justify-content: space-between;
h1 {
font-weight: 500;
font-size: 20px;
color: #1d2129;
line-height: 28px;
font-family: Microsoft YaHei, Microsoft YaHei;
}
}
.Worktop {
.el-button {
border: 1px solid #0d867f;
font-weight: 400;
font-size: 14px;
color: #0d867f;
}
.el-button:hover {
background-color: transparent;
}
.BlueBack {
background: #0d867f;
border-radius: 2px 2px 2px 2px;
font-weight: 400;
font-size: 14px;
color: #ffffff;
line-height: 22px;
img {
width: 16px;
height: 16px;
margin-right: 8px;
}
}
.BlueBack:hover {
background-color: #0d867f;
}
.Delete {
background: #f2f3f5;
border-radius: 2px 2px 2px 2px;
font-weight: 400;
font-size: 14px;
color: #1d2129;
line-height: 22px;
border: none;
img {
width: 16px;
height: 16px;
margin-right: 8px;
}
}
.Delete:hover {
background-color: #f2f3f5;
}
}
.ExaminationForm {
margin-top: 16px;
background-color: #0077aa;
}
.el-table tr {
height: 41px;
}
.el-table td {
height: 41px;
}
:deep(th) {
background-color: #e5e6eb;
}
}
.el-pagination {
float: right;
background-color: #fff !important;
margin-top: 18px;
}
:deep(.el-pager li.is-active) {
background-color: #e7f9f8 !important;
font-weight: 400;
color: #0d867f !important;
}
:deep(.el-table--enable-row-hover .el-table__body tr:hover > td) {
background-color: #e7f9f8 !important;
}
:deep(.el-select) {
width: 280px !important;
}
:deep(.el-input) {
width: 280px !important;
}
.example {
margin-left: 20px;
color: red;
}
.backInformation {
:deep(.el-input) {
width: 280px !important;
height: 120px !important;
}
}
.dialog-footer {
width: 100%;
text-align: center;
}
:deep(.el-textarea__inner) {
width: 280px !important;
}
.user-name,.register{
cursor: pointer;
}
.functionalUnit{
margin-left: 20px;
display: flex;
.el-button {
width: 84px;
height: 32px;
border: none;
font-weight: 400;
font-size: 14px;
border-radius: 2px 2px 2px 2px;
color: #fff;
img {
width: 16px;
height: 16px;
margin-right: 8px;
}
}
.el-button:nth-child(1) {
background-color: #2192ba;
}
.el-button:nth-child(2) {
background-color: #17c85f;
}
}
.TabularTitle{
font-size: 14px;
color: #747272;
font-weight: bold;
margin-bottom: 10px;
}
.pagination{
width: 100%;
height:30px;
:deep(.el-pagination){
margin-top: 9px!important;
}
}
.addSlip{
.el-button{
border: none;
background-color: #0077aa;
margin-top: 8px;
color: #fff;
}
:deep(.el-pagination){
margin-top: 8px!important;
}
}
.ml-3{
margin-left: 20px;
}
.upload-file-uploader{
width: 50%;
}
.el-upload-list .el-upload-list__item{
width: 33% !important;
float: left;
margin-left: -385px;
margin-top: 25px;
:deep(.horizontal-list ul .el-upload-list__item) {
width: 33% !important;
float: left; margin-top: 25px;
}
:deep(.el-link__inner ) {
display: inline-flex;
justify-content: center;
align-items: center;
width: 200px;
}
}
</style>

198
src/views/login/index.vue Normal file
View File

@ -0,0 +1,198 @@
<template>
<div class="loginPage">
<div class="loginLayout">
<div class="Login-content">
<div class="loginTitle">
<!-- <img src="../../assets/login/Login-logo.png" alt="" /> -->
<p>后台管理系统</p>
</div>
<div class="loginInput">
<p>欢迎登录</p>
<div class="login_from">
<el-form
ref="ruleFormRef"
style="max-width: 600px"
:model="ruleForm"
:rules="rules"
label-width="auto"
class="demo-ruleForm"
:size="formSize"
status-icon
>
<el-form-item label="" prop="login_name">
<el-input
v-model="ruleForm.login_name"
placeholder="请输入账号"
:prefix-icon="User"
/>
</el-form-item>
<el-form-item label="" prop="password">
<el-input
type="password"
v-model="ruleForm.password"
placeholder="请输入密码"
:prefix-icon="Lock"
/>
</el-form-item>
<el-button @click="handleLogin">登录</el-button>
</el-form>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { User, Lock } from '@element-plus/icons-vue'
import { apiLogin } from '@/api/index.js'
import JSEncrypt from 'jsencrypt'
//
const formSize = ref('default')
const ruleFormRef = ref()
const ruleForm = reactive({
login_name: '',
password: ''
})
const encryptor = ref(null)
onMounted(() => {
encryptor.value = new JSEncrypt() //
const pubKey =
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2TEstfATFdDWntbJTCPer9FOdwTRe58Vjy9T238/uUQYyoTHClfQCCKnys4elHCE0D0B7D/k2hK9U+xu1hWv1v4lH+n+t5duNVGq3sa5+pOq8j1ztec3W+wlcFgplYJq78XBYGYDbyfhmu5KeDeImsiccwnq3WvigfZYPbTvGv2YsqXDpTp+/s0hQsrYeATr2MuhiBhQGynLUvKCEcWvd/GNByMxJdJwl0k+IZW+DiCDmNX9Qwj23HF7U+Om7jEZC+Li/j2MHA5C4eEtVzgVC4VZETVOIcLv/UDufnAlneTJK2Exo+4YFEg9S1shpqUz9shSBl8JF9DM2a3KKmxc4wIDAQAB'
encryptor.value.setPublicKey(pubKey)
})
const router = useRouter()
const handleLogin = async () => {
const rsaPassWord = encryptor.value.encrypt(ruleForm.password) //
try {
const response = await apiLogin({
login_name: ruleForm.login_name,
password: rsaPassWord
})
if (response.code === 0) {
console.log(response.data, 'response.data')
// token
localStorage.setItem('token', response.data.token)
localStorage.setItem('ReviewerId', response.data.user_id)
localStorage.setItem('Reviewer', response.data.real_name)
await router.push('/ExaminationManagement')
} else {
//
alert('密码错误')
}
} catch (error) {
//
alert('请求失败')
}
}
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'))
} else {
const passLength = value.length
if (passLength < 5 || passLength > 20) {
callback(new Error('密码长度为5-20'))
} else {
callback()
}
}
}
const rules = reactive({
password: [
{ required: true, trigger: 'blur', message: '请输入密码' },
{ validator: validatePass, trigger: 'blur' }
]
})
</script>
<style scoped lang="scss">
.loginPage {
width: 100vw;
height: 100vh;
overflow: hidden;
}
.loginLayout {
width: 100%;
height: 100%;
background: url("../../assets/login/Login.png") no-repeat;
background-size: 100% 100%;
display: flex;
align-items: center;
justify-content: center;
}
.loginTitle {
display: flex;
justify-content: center;
margin-bottom: 36px;
img {
width: 60px;
height: 60px;
margin-right: 24px;
}
p {
height: 46px;
line-height: 46px;
font-family: DouyinSansBold;
font-weight: 700;
font-size: 38px;
color: #0d867f;
margin-top: 11px;
letter-spacing: 1px;
}
}
.loginInput {
width: 506px;
height: 402px;
background: #fdfffd;
box-shadow: 0 0 12px 0 rgba(160, 194, 182, 0.29);
border-radius: 10px 10px 10px 10px;
padding: 0 63px;
overflow: hidden;
p {
width: 100%;
text-align: center;
font-weight: 400;
font-size: 20px;
color: #333333;
line-height: 30px;
margin-top: 50px;
margin-bottom: 52px;
}
.el-button {
width: 380px;
height: 50px;
background: #0d867f;
border: none;
border-radius: 2px 2px 2px 2px;
font-weight: 400;
font-size: 16px;
color: #ffffff;
line-height: 24px;
}
}
.login_from {
.el-input {
height: 50px;
border: 1px solid rgba(13, 134, 127, 1);
}
.el-form-item--default {
margin-bottom: 30px;
}
:deep(.el-input__wrapper) {
border-radius: 0 !important;
box-shadow: none !important;
}
:deep(.el-input__wrapper:hover) {
box-shadow: none !important;
}
}
:deep(.el-input) {
--el-input-focus-border-color: transparent !important;
}
</style>

26
vite.config.js Normal file
View File

@ -0,0 +1,26 @@
import { defineConfig } from 'vite'
import { fileURLToPath, URL } from 'node:url'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
base: './',
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
// port: 8080,
host: '0.0.0.0',
cors: true,
proxy: {
'/api': {
target: 'http://172.16.1.253:4000',
changeOrigin: true
// rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})