@@ -1,4 +1,5 @@ | |||
module.exports = { | |||
// 取消 自定义eslintrc验证 | |||
/* module.exports = { | |||
root: true, | |||
parserOptions: { | |||
parser: 'babel-eslint', | |||
@@ -11,8 +12,6 @@ module.exports = { | |||
}, | |||
extends: ['plugin:vue/recommended', 'eslint:recommended'], | |||
// add your custom rules here | |||
//it is base on https://github.com/vuejs/eslint-config-vue | |||
rules: { | |||
"vue/max-attributes-per-line": [0, { | |||
"singleline": 10, | |||
@@ -199,3 +198,30 @@ module.exports = { | |||
'array-bracket-spacing': [2, 'never'] | |||
} | |||
} | |||
*/ | |||
module.exports = { | |||
root: true, | |||
env: { | |||
node: true, | |||
}, | |||
extends: ["plugin:vue/essential", "eslint:recommended"], | |||
parserOptions: { | |||
parser: "babel-eslint", | |||
}, | |||
rules: { | |||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off", | |||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", | |||
/* "prettier/prettier": "off" */ | |||
}, | |||
overrides: [ | |||
{ | |||
files: [ | |||
"**/__tests__/*.{j,t}s?(x)", | |||
"**/tests/unit/**/*.spec.{j,t}s?(x)", | |||
], | |||
env: { | |||
jest: true, | |||
}, | |||
}, | |||
], | |||
}; |
@@ -0,0 +1,5 @@ | |||
FROM nginx | |||
RUN mkdir /app | |||
COPY dist /app | |||
COPY nginx/nginx.conf /etc/nginx/nginx.conf | |||
EXPOSE 80 |
@@ -1,7 +1,7 @@ | |||
<!-- | |||
* @Date: 2021-11-29 11:14:13 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-11-30 15:58:34 | |||
* @LastEditTime: 2021-12-03 15:25:57 | |||
* @FilePath: \GpsCardAdmin\README.md | |||
* @description: | |||
--> | |||
@@ -15,3 +15,22 @@ | |||
`2021年11月30日` | |||
FEATURE | |||
- 完成 基本项目开发环境搭建 | |||
## v1.0.1F | |||
`2021年12月1日` | |||
FEATURE | |||
- 完成 静态页面编写与交互 | |||
## v1.0.2F | |||
`2021年12月2日` | |||
FEATURE | |||
- 增加 docker部署文件 | |||
- 修改 docker部署文件 | |||
## v1.0.3F | |||
`2021年12月3日` | |||
FEATURE | |||
- merge off-limits-type | |||
- 增加 禁入类别 |
@@ -0,0 +1,36 @@ | |||
#!/bin/bash | |||
### | |||
# @Date: 2021-11-15 09:37:49 | |||
# @LastEditors: JinxuChen | |||
# @LastEditTime: 2021-12-02 15:19:14 | |||
# @FilePath: \GpsCardAdmin\gps_card_admin_run.sh | |||
# @description: 功能 | |||
### | |||
environment=$1 | |||
version=$2 | |||
echo "环境变量为${environment},版本为$version!" | |||
if [[ ${environment} = 'production' ]]; then | |||
echo "开始远程构建容器" | |||
docker stop gps_card_admin_web || true; | |||
docker rm gps_card_admin_web || true; | |||
docker rmi -f $(docker images | grep registry.cn-shanghai.aliyuncs.com/gps_card/gps_card_admin_web | awk '{print $3}') | |||
#docker login --username=telpo_linwl@1111649216405698 --password=telpo#1234 registry.cn-shanghai.aliyuncs.com; | |||
docker login --username=rzl_wangjx@1111649216405698 --password=telpo.123 registry.cn-shanghai.aliyuncs.com | |||
docker pull registry.cn-shanghai.aliyuncs.com/gps_card/gps_card_admin_web:$version | |||
docker run -p 8803:80 -d --restart=always --name gps_card_admin_web registry.cn-shanghai.aliyuncs.com/gps_card/gps_card_admin_web:$version; | |||
#删除产生的None镜像 | |||
docker rmi -f $(docker images | grep none | awk '{print $3}') | |||
docker ps -a | |||
elif [[ ${environment} == 'test' ]]; then | |||
echo "开始在测试环境远程构建容器" | |||
docker stop gps_card_admin_web || true | |||
docker rm gps_card_admin_web || true | |||
docker rmi -f $(docker images | grep 139.224.254.18:5000/gps_card_admin_web | awk '{print $3}') | |||
docker pull 139.224.254.18:5000/gps_card_admin_web:$version | |||
docker run -p 8803:80 -d --restart=always --name gps_card_admin_web 139.224.254.18:5000/gps_card_admin_web:$version; | |||
#删除产生的None镜像 | |||
docker rmi -f $(docker images | grep none | awk '{print $3}') | |||
docker ps -a | |||
fi |
@@ -0,0 +1,57 @@ | |||
#user nobody; | |||
worker_processes 1; | |||
#error_log logs/error.log; | |||
#error_log logs/error.log notice; | |||
error_log /var/log/nginx/error.log warn; | |||
pid /var/run/nginx.pid; | |||
events { | |||
accept_mutex on; #设置网路连接序列化,防止惊群现象发生,默认为on | |||
multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off | |||
use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport | |||
worker_connections 1024; | |||
} | |||
http { | |||
include mime.types; | |||
default_type application/octet-stream; | |||
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' | |||
'$status $body_bytes_sent "$http_referer" ' | |||
'"$http_user_agent" "$http_x_forwarded_for"'; | |||
#access_log logs/access.log main; | |||
access_log /var/log/nginx/access.log main; | |||
sendfile on; | |||
#tcp_nopush on; | |||
#keepalive_timeout 0; | |||
keepalive_timeout 65; | |||
server { | |||
listen 80; | |||
server_name localhost; | |||
#charset koi8-r; | |||
charset utf-8; | |||
location / { | |||
root /app; # 指向目录 | |||
index index.html; | |||
try_files $uri $uri/ /index.html; | |||
} | |||
error_page 500 502 503 504 /50x.html; | |||
location = /50x.html { | |||
root /usr/share/nginx/html; | |||
} | |||
} | |||
} |
@@ -25,7 +25,8 @@ | |||
"path-to-regexp": "2.4.0", | |||
"vue": "2.6.10", | |||
"vue-router": "3.0.6", | |||
"vuex": "3.1.0" | |||
"vuex": "3.1.0", | |||
"xlsx": "0.14.1" | |||
}, | |||
"devDependencies": { | |||
"@vue/cli-plugin-babel": "4.4.4", | |||
@@ -0,0 +1,30 @@ | |||
### | |||
# @Author: JinxuChen | |||
# @Date: 2021-11-15 | |||
# @LastEditTime: 2021-12-02 15:19:22 | |||
# @LastEditors: JinxuChen | |||
# @Description: In User Settings Edit | |||
# @FilePath: \GpsCardAdmin\setup_development.sh | |||
### | |||
#!/bin/bash | |||
npm -v | |||
npm config set registry https://registry.npm.taobao.org | |||
npm config list | |||
npm install | |||
npm run build-test | |||
image_version=`date +%Y%m%d%H%M`; | |||
docker stop gps_card_admin_web || true; | |||
# 删除gps_parent_web容器 | |||
docker rm gps_card_admin_web || true; | |||
# 删除镜像 | |||
docker rmi -f $(docker images | grep telpo/gps_card_admin_web | awk '{print $3}') | |||
# 构建telpo/gps_card_admin_web:$image_version镜像 | |||
docker build . -t telpo/gps_card_admin_web:$image_version; | |||
#删除产生的None镜像 | |||
docker rmi -f $(docker images | grep none | awk '{print $3}') | |||
# 查看镜像列表 | |||
docker images; | |||
# 启动容器 | |||
docker run -p 8803:80 -d --restart=always --name gps_card_admin_web telpo/gps_card_admin_web:$image_version; | |||
# 查看日志 | |||
docker logs gps_card_admin_web; |
@@ -0,0 +1,28 @@ | |||
### | |||
# @Author: JinxuChen | |||
# @Date: 2021-11-15 | |||
# @LastEditTime: 2021-12-02 15:17:27 | |||
# @LastEditors: JinxuChen | |||
# @Description: In User Settings Edit | |||
# @FilePath: \GpsCardAdmin\setup_production.sh | |||
### | |||
#!/bin/bash | |||
npm -v | |||
npm install | |||
npm run build | |||
image_version=$version; | |||
# 删除镜像 | |||
docker rmi -f $(docker images | grep registry.cn-shanghai.aliyuncs.com/gps_card/gps_card_admin_web | awk '{print $3}') | |||
docker build . -t telpo/gps_card_admin_web:$image_version; | |||
#TODO:推送镜像到阿里仓库 | |||
echo '=================开始推送镜像=======================' | |||
#docker login --username=telpo_linwl@1111649216405698 --password=telpo#1234 registry.cn-shanghai.aliyuncs.com; | |||
docker login --username=rzl_wangjx@1111649216405698 --password=telpo.123 registry.cn-shanghai.aliyuncs.com | |||
docker tag telpo/gps_card_admin_web:$image_version registry.cn-shanghai.aliyuncs.com/gps_card/gps_card_admin_web:$image_version | |||
docker push registry.cn-shanghai.aliyuncs.com/gps_card/gps_card_admin_web:$image_version | |||
echo '=================推送镜像完成=======================' | |||
#删除产生的None镜像 | |||
docker rmi -f $(docker images | grep none | awk '{print $3}') | |||
# 查看镜像列表 | |||
docker images; |
@@ -0,0 +1,31 @@ | |||
### | |||
# @Author: JinxuChen | |||
# @Date: 2021-11-15 | |||
# @LastEditTime: 2021-12-02 15:17:38 | |||
# @LastEditors: JinxuChen | |||
# @Description: In User Settings Edit | |||
# @FilePath: \GpsCardAdmin\setup_test.sh | |||
### | |||
#!/usr/bin/env bash | |||
npm -v | |||
npm config set registry https://registry.npm.taobao.org | |||
npm config list | |||
npm install | |||
npm run build-test | |||
image_version=$version | |||
# 删除镜像 | |||
docker rmi -f $( | |||
docker images | grep 139.224.254.18:5000/gps_card_admin_web | awk '{print $3}' | |||
) | |||
# 构建gps_card_admin:$image_version镜像 | |||
docker build . -t telpo/gps_card_admin_web:$image_version; | |||
#TODO:推送镜像到私有仓库 | |||
echo '=================开始推送镜像=======================' | |||
docker tag telpo/gps_card_admin_web:$image_version 139.224.254.18:5000/gps_card_admin_web:$image_version | |||
docker push 139.224.254.18:5000/gps_card_admin_web:$image_version | |||
echo '=================推送镜像完成=======================' | |||
#删除产生的None镜像 | |||
docker rmi -f $(docker images | grep none | awk '{print $3}') | |||
# 查看镜像列表 | |||
docker images |
@@ -0,0 +1,102 @@ | |||
<template> | |||
<div :class="{'hidden':hidden}" class="pagination-container"> | |||
<el-pagination | |||
:background="background" | |||
:current-page.sync="currentPage" | |||
:page-size.sync="pageSize" | |||
:layout="layout" | |||
:page-sizes="pageSizes" | |||
:total="total" | |||
v-bind="$attrs" | |||
@size-change="handleSizeChange" | |||
@current-change="handleCurrentChange" | |||
/> | |||
</div> | |||
</template> | |||
<script> | |||
import { scrollTo } from '@/utils/scroll-to' | |||
export default { | |||
name: 'Pagination', | |||
props: { | |||
total: { | |||
required: true, | |||
type: Number | |||
}, | |||
page: { | |||
type: Number, | |||
default: 1 | |||
}, | |||
limit: { | |||
type: Number, | |||
default: 20 | |||
}, | |||
pageSizes: { | |||
type: Array, | |||
default() { | |||
return [10, 20, 30, 50] | |||
} | |||
}, | |||
layout: { | |||
type: String, | |||
default: 'total, sizes, prev, pager, next, jumper' | |||
}, | |||
background: { | |||
type: Boolean, | |||
default: true | |||
}, | |||
autoScroll: { | |||
type: Boolean, | |||
default: true | |||
}, | |||
hidden: { | |||
type: Boolean, | |||
default: false | |||
} | |||
}, | |||
computed: { | |||
currentPage: { | |||
get() { | |||
return this.page | |||
}, | |||
set(val) { | |||
this.$emit('update:page', val) | |||
} | |||
}, | |||
pageSize: { | |||
get() { | |||
return this.limit | |||
}, | |||
set(val) { | |||
this.$emit('update:limit', val) | |||
} | |||
} | |||
}, | |||
methods: { | |||
handleSizeChange(val) { | |||
this.$emit('pagination', { page: this.currentPage, limit: val }) | |||
if (this.autoScroll) { | |||
scrollTo(0, 800) | |||
} | |||
}, | |||
handleCurrentChange(val) { | |||
this.$emit('pagination', { page: val, limit: this.pageSize }) | |||
if (this.autoScroll) { | |||
scrollTo(0, 800) | |||
} | |||
} | |||
} | |||
} | |||
</script> | |||
<style scoped> | |||
.pagination-container { | |||
width: 50%; | |||
background: #fff; | |||
padding: 32px 16px; | |||
} | |||
.pagination-container.hidden { | |||
display: none; | |||
} | |||
</style> |
@@ -0,0 +1,97 @@ | |||
<!-- | |||
* @Date: 2021-11-30 17:19:51 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-12-01 15:11:35 | |||
* @FilePath: \GpsCardAdmin\src\components\TTable\TTable.vue | |||
* @description: 封装通用的table组件 | |||
--> | |||
<template> | |||
<div class="app-container"> | |||
<!-- 表格 --> | |||
<el-table :data="tableData" border fit highlight-current-row @sort-change="sortChange" > | |||
<!-- <el-table-column prop="date" label="日期" width="180"></el-table-column> --> | |||
<template v-for="column in columns"> | |||
<!-- 标题 --> | |||
<el-table-column | |||
:key="column.prop" | |||
:prop="column.prop" | |||
:label="column.title" | |||
v-if="!column.action" | |||
height="460" | |||
/> | |||
<!-- 操作列 --> | |||
<el-table-column :label="column.title" :key="column.prop" v-else > | |||
<template slot-scope="scope"> | |||
<el-button-group v-for="(fn,index) in column.actions" :key="index"> | |||
<el-button | |||
type="primary" | |||
@click="handleClick(scope.row,fn.fnName)" | |||
>{{fn.title}}</el-button> | |||
</el-button-group> | |||
</template> | |||
</el-table-column> | |||
</template> | |||
</el-table> | |||
<!-- 分页 --> | |||
<!-- <pagination | |||
v-show="total>0" | |||
:total="total" | |||
:page.sync="listQuery.page" | |||
:limit.sync="listQuery.limit" | |||
@pagination="getList" | |||
/>--> | |||
</div> | |||
</template> | |||
<script> | |||
/* import Pagination from "@/components/Pagination"; */ | |||
import waves from "@/directive/waves"; // waves directive | |||
export default { | |||
name: "", | |||
/* components: { Pagination }, */ | |||
directives: { waves }, | |||
props: { | |||
tableData: { | |||
type: Array, | |||
default: () => [] | |||
}, | |||
columns: { | |||
type: Array, | |||
default: () => [] | |||
}, | |||
btnType: { | |||
type: String | |||
} | |||
}, | |||
data() { | |||
return { | |||
total: 1, | |||
tableKey: 0, | |||
listQuery: { | |||
page: 1, | |||
limit: 10, | |||
importance: "" | |||
}, | |||
importanceOptions: ["1", "2", "3"], | |||
list: [ | |||
{ | |||
date: "2016-05-02", | |||
name: "王小虎", | |||
address: "上海市普陀区金沙江路 1518 弄" | |||
} | |||
] | |||
}; | |||
}, | |||
methods: { | |||
getList() {}, | |||
sortChange() {}, | |||
handleFilter() {}, | |||
handleClick(row, fnName) { | |||
this.$emit(`${fnName}`, row); | |||
} | |||
} | |||
}; | |||
</script> | |||
<style scoped> | |||
</style> |
@@ -0,0 +1,38 @@ | |||
<!-- | |||
* @Date: 2021-11-30 18:18:48 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-11-30 18:56:32 | |||
* @FilePath: \GpsCardAdmin\src\components\TopMenu\index.vue | |||
* @description: 头部组件 | |||
--> | |||
<template> | |||
<div> | |||
<!-- 操作 --> | |||
<!-- 按钮 --> | |||
<el-button | |||
class="filter-item" | |||
v-for="(item,index) in buttonList" | |||
:key="index" | |||
:type="item.type" | |||
@click="item.click" | |||
>{{item.name}}</el-button> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
name: "topMenu", | |||
props: { | |||
buttonList: { | |||
type: Array, | |||
default: [] | |||
} | |||
}, | |||
data() { | |||
return {}; | |||
} | |||
}; | |||
</script> | |||
<style scoped> | |||
</style> |
@@ -0,0 +1,137 @@ | |||
<template> | |||
<div> | |||
<input ref="excel-upload-input" class="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick"> | |||
<div class="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover"> | |||
<el-button :loading="loading" style="margin-left:16px;" size="mini" type="primary" @click="handleUpload"> | |||
上传 | |||
</el-button> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import XLSX from 'xlsx' | |||
export default { | |||
props: { | |||
beforeUpload: Function, // eslint-disable-line | |||
onSuccess: Function// eslint-disable-line | |||
}, | |||
data() { | |||
return { | |||
loading: false, | |||
excelData: { | |||
header: null, | |||
results: null | |||
} | |||
} | |||
}, | |||
methods: { | |||
generateData({ header, results }) { | |||
this.excelData.header = header | |||
this.excelData.results = results | |||
this.onSuccess && this.onSuccess(this.excelData) | |||
}, | |||
handleDrop(e) { | |||
e.stopPropagation() | |||
e.preventDefault() | |||
if (this.loading) return | |||
const files = e.dataTransfer.files | |||
if (files.length !== 1) { | |||
this.$message.error('Only support uploading one file!') | |||
return | |||
} | |||
const rawFile = files[0] // only use files[0] | |||
if (!this.isExcel(rawFile)) { | |||
this.$message.error('Only supports upload .xlsx, .xls, .csv suffix files') | |||
return false | |||
} | |||
this.upload(rawFile) | |||
e.stopPropagation() | |||
e.preventDefault() | |||
}, | |||
handleDragover(e) { | |||
e.stopPropagation() | |||
e.preventDefault() | |||
e.dataTransfer.dropEffect = 'copy' | |||
}, | |||
handleUpload() { | |||
this.$refs['excel-upload-input'].click() | |||
}, | |||
handleClick(e) { | |||
const files = e.target.files | |||
const rawFile = files[0] // only use files[0] | |||
if (!rawFile) return | |||
this.upload(rawFile) | |||
}, | |||
upload(rawFile) { | |||
this.$refs['excel-upload-input'].value = null // fix can't select the same excel | |||
if (!this.beforeUpload) { | |||
this.readerData(rawFile) | |||
return | |||
} | |||
const before = this.beforeUpload(rawFile) | |||
if (before) { | |||
this.readerData(rawFile) | |||
} | |||
}, | |||
readerData(rawFile) { | |||
this.loading = true | |||
return new Promise((resolve, reject) => { | |||
const reader = new FileReader() | |||
reader.onload = e => { | |||
const data = e.target.result | |||
const workbook = XLSX.read(data, { type: 'array' }) | |||
const firstSheetName = workbook.SheetNames[0] | |||
const worksheet = workbook.Sheets[firstSheetName] | |||
const header = this.getHeaderRow(worksheet) | |||
const results = XLSX.utils.sheet_to_json(worksheet) | |||
this.generateData({ header, results }) | |||
this.loading = false | |||
resolve() | |||
} | |||
reader.readAsArrayBuffer(rawFile) | |||
}) | |||
}, | |||
getHeaderRow(sheet) { | |||
const headers = [] | |||
const range = XLSX.utils.decode_range(sheet['!ref']) | |||
let C | |||
const R = range.s.r | |||
/* start in the first row */ | |||
for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */ | |||
const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] | |||
/* find the cell in the first row */ | |||
let hdr = 'UNKNOWN ' + C // <-- replace with your desired default | |||
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell) | |||
headers.push(hdr) | |||
} | |||
return headers | |||
}, | |||
isExcel(file) { | |||
return /\.(xlsx|xls|csv)$/.test(file.name) | |||
} | |||
} | |||
} | |||
</script> | |||
<style scoped> | |||
.excel-upload-input{ | |||
display: none; | |||
z-index: -9999; | |||
} | |||
.drop{ | |||
border: 2px dashed #bbb; | |||
width: 50%; | |||
height: 160px; | |||
line-height: 160px; | |||
margin: 0 auto; | |||
font-size: 24px; | |||
border-radius: 5px; | |||
text-align: center; | |||
color: #bbb; | |||
position: relative; | |||
} | |||
</style> |
@@ -0,0 +1,13 @@ | |||
import waves from './waves' | |||
const install = function(Vue) { | |||
Vue.directive('waves', waves) | |||
} | |||
if (window.Vue) { | |||
window.waves = waves | |||
Vue.use(install); // eslint-disable-line | |||
} | |||
waves.install = install | |||
export default waves |
@@ -0,0 +1,26 @@ | |||
.waves-ripple { | |||
position: absolute; | |||
border-radius: 100%; | |||
background-color: rgba(0, 0, 0, 0.15); | |||
background-clip: padding-box; | |||
pointer-events: none; | |||
-webkit-user-select: none; | |||
-moz-user-select: none; | |||
-ms-user-select: none; | |||
user-select: none; | |||
-webkit-transform: scale(0); | |||
-ms-transform: scale(0); | |||
transform: scale(0); | |||
opacity: 1; | |||
} | |||
.waves-ripple.z-active { | |||
opacity: 0; | |||
-webkit-transform: scale(2); | |||
-ms-transform: scale(2); | |||
transform: scale(2); | |||
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; | |||
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out; | |||
transition: opacity 1.2s ease-out, transform 0.6s ease-out; | |||
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out; | |||
} |
@@ -0,0 +1,72 @@ | |||
import './waves.css' | |||
const context = '@@wavesContext' | |||
function handleClick(el, binding) { | |||
function handle(e) { | |||
const customOpts = Object.assign({}, binding.value) | |||
const opts = Object.assign({ | |||
ele: el, // 波纹作用元素 | |||
type: 'hit', // hit 点击位置扩散 center中心点扩展 | |||
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色 | |||
}, | |||
customOpts | |||
) | |||
const target = opts.ele | |||
if (target) { | |||
target.style.position = 'relative' | |||
target.style.overflow = 'hidden' | |||
const rect = target.getBoundingClientRect() | |||
let ripple = target.querySelector('.waves-ripple') | |||
if (!ripple) { | |||
ripple = document.createElement('span') | |||
ripple.className = 'waves-ripple' | |||
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px' | |||
target.appendChild(ripple) | |||
} else { | |||
ripple.className = 'waves-ripple' | |||
} | |||
switch (opts.type) { | |||
case 'center': | |||
ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px' | |||
ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px' | |||
break | |||
default: | |||
ripple.style.top = | |||
(e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop || | |||
document.body.scrollTop) + 'px' | |||
ripple.style.left = | |||
(e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft || | |||
document.body.scrollLeft) + 'px' | |||
} | |||
ripple.style.backgroundColor = opts.color | |||
ripple.className = 'waves-ripple z-active' | |||
return false | |||
} | |||
} | |||
if (!el[context]) { | |||
el[context] = { | |||
removeHandle: handle | |||
} | |||
} else { | |||
el[context].removeHandle = handle | |||
} | |||
return handle | |||
} | |||
export default { | |||
bind(el, binding) { | |||
el.addEventListener('click', handleClick(el, binding), false) | |||
}, | |||
update(el, binding) { | |||
el.removeEventListener('click', el[context].removeHandle, false) | |||
el.addEventListener('click', handleClick(el, binding), false) | |||
}, | |||
unbind(el) { | |||
el.removeEventListener('click', el[context].removeHandle, false) | |||
el[context] = null | |||
delete el[context] | |||
} | |||
} |
@@ -1,136 +1,150 @@ | |||
<template> | |||
<div class="navbar"> | |||
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> | |||
<breadcrumb class="breadcrumb-container" /> | |||
<div class="right-menu"> | |||
<el-dropdown class="avatar-container" trigger="click"> | |||
<div class="avatar-wrapper"> | |||
<img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> | |||
<i class="el-icon-caret-bottom" /> | |||
<div class="navbar"> | |||
<hamburger | |||
:is-active="sidebar.opened" | |||
class="hamburger-container" | |||
@toggleClick="toggleSideBar" | |||
/> | |||
<breadcrumb class="breadcrumb-container" /> | |||
<div class="left-menu"> | |||
<span class="current-user">当前用户:{{currentUser}}</span> | |||
</div> | |||
<el-dropdown-menu slot="dropdown" class="user-dropdown"> | |||
<router-link to="/"> | |||
<el-dropdown-item> | |||
首页 | |||
</el-dropdown-item> | |||
</router-link> | |||
<!-- <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> | |||
<div class="right-menu"> | |||
<el-dropdown class="avatar-container" trigger="click"> | |||
<div class="avatar-wrapper"> | |||
<img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar" /> | |||
<i class="el-icon-caret-bottom" /> | |||
</div> | |||
<el-dropdown-menu slot="dropdown" class="user-dropdown"> | |||
<router-link to="/"> | |||
<el-dropdown-item>首页</el-dropdown-item> | |||
</router-link> | |||
<!-- <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> | |||
<el-dropdown-item>Docs</el-dropdown-item> | |||
</a> --> | |||
<el-dropdown-item divided @click.native="logout"> | |||
<span style="display:block;">退出登录</span> | |||
</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
</a>--> | |||
<el-dropdown-item divided @click.native="logout"> | |||
<span style="display:block;">退出登录</span> | |||
</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { mapGetters } from 'vuex' | |||
import Breadcrumb from '@/components/Breadcrumb' | |||
import Hamburger from '@/components/Hamburger' | |||
import { mapGetters } from "vuex"; | |||
import Breadcrumb from "@/components/Breadcrumb"; | |||
import Hamburger from "@/components/Hamburger"; | |||
export default { | |||
components: { | |||
Breadcrumb, | |||
Hamburger | |||
}, | |||
computed: { | |||
...mapGetters([ | |||
'sidebar', | |||
'avatar' | |||
]) | |||
}, | |||
methods: { | |||
toggleSideBar() { | |||
this.$store.dispatch('app/toggleSideBar') | |||
components: { | |||
Breadcrumb, | |||
Hamburger | |||
}, | |||
computed: { | |||
...mapGetters(["sidebar", "avatar"]) | |||
}, | |||
data() { | |||
return { | |||
currentUser: this.$store.getters.name | |||
} | |||
}, | |||
async logout() { | |||
await this.$store.dispatch('user/logout') | |||
this.$router.push(`/login?redirect=${this.$route.fullPath}`) | |||
methods: { | |||
toggleSideBar() { | |||
this.$store.dispatch("app/toggleSideBar"); | |||
}, | |||
async logout() { | |||
await this.$store.dispatch("user/logout"); | |||
this.$router.push(`/login?redirect=${this.$route.fullPath}`); | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
</script> | |||
<style lang="scss" scoped> | |||
.navbar { | |||
height: 50px; | |||
overflow: hidden; | |||
position: relative; | |||
background: #fff; | |||
box-shadow: 0 1px 4px rgba(0,21,41,.08); | |||
.hamburger-container { | |||
line-height: 46px; | |||
height: 100%; | |||
float: left; | |||
cursor: pointer; | |||
transition: background .3s; | |||
-webkit-tap-highlight-color:transparent; | |||
&:hover { | |||
background: rgba(0, 0, 0, .025) | |||
} | |||
} | |||
.breadcrumb-container { | |||
float: left; | |||
} | |||
.right-menu { | |||
float: right; | |||
height: 100%; | |||
line-height: 50px; | |||
&:focus { | |||
outline: none; | |||
} | |||
.right-menu-item { | |||
display: inline-block; | |||
padding: 0 8px; | |||
height: 100%; | |||
font-size: 18px; | |||
color: #5a5e66; | |||
vertical-align: text-bottom; | |||
&.hover-effect { | |||
height: 50px; | |||
overflow: hidden; | |||
position: relative; | |||
background: #fff; | |||
width: 100%; | |||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); | |||
.hamburger-container { | |||
float: left; | |||
line-height: 46px; | |||
cursor: pointer; | |||
transition: background .3s; | |||
transition: background 0.3s; | |||
-webkit-tap-highlight-color: transparent; | |||
&:hover { | |||
background: rgba(0, 0, 0, .025) | |||
background: rgba(0, 0, 0, 0.025); | |||
} | |||
} | |||
} | |||
.avatar-container { | |||
margin-right: 30px; | |||
.avatar-wrapper { | |||
margin-top: 5px; | |||
position: relative; | |||
.breadcrumb-container { | |||
line-height: 50px; | |||
float: left; | |||
} | |||
.left-menu { | |||
float: left; | |||
margin-left: 150px; | |||
height: 100%; | |||
line-height: 50px; | |||
// 当前用户 | |||
.current-user { | |||
line-height: 50px; | |||
} | |||
} | |||
.right-menu { | |||
float: right; | |||
height: 100%; | |||
line-height: 50px; | |||
.user-avatar { | |||
cursor: pointer; | |||
width: 40px; | |||
height: 40px; | |||
border-radius: 10px; | |||
&:focus { | |||
outline: none; | |||
} | |||
.right-menu-item { | |||
display: inline-block; | |||
padding: 0 8px; | |||
height: 100%; | |||
font-size: 18px; | |||
color: #5a5e66; | |||
vertical-align: text-bottom; | |||
&.hover-effect { | |||
cursor: pointer; | |||
transition: background 0.3s; | |||
&:hover { | |||
background: rgba(0, 0, 0, 0.025); | |||
} | |||
} | |||
} | |||
.el-icon-caret-bottom { | |||
cursor: pointer; | |||
position: absolute; | |||
right: -20px; | |||
top: 25px; | |||
font-size: 12px; | |||
.avatar-container { | |||
margin-right: 30px; | |||
.avatar-wrapper { | |||
margin-top: 5px; | |||
position: relative; | |||
.user-avatar { | |||
cursor: pointer; | |||
width: 40px; | |||
height: 40px; | |||
border-radius: 10px; | |||
} | |||
.el-icon-caret-bottom { | |||
cursor: pointer; | |||
position: absolute; | |||
right: -20px; | |||
top: 25px; | |||
font-size: 12px; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@@ -1,3 +1,10 @@ | |||
/* | |||
* @Date: 2021-11-30 15:35:16 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-11-30 17:51:56 | |||
* @FilePath: \GpsCardAdmin\src\main.js | |||
* @description: | |||
*/ | |||
import Vue from 'vue' | |||
import 'normalize.css/normalize.css' // A modern alternative to CSS resets | |||
@@ -29,9 +36,9 @@ if (process.env.NODE_ENV === 'production') { | |||
} | |||
// set ElementUI lang to EN | |||
Vue.use(ElementUI, { locale }) | |||
/* Vue.use(ElementUI, { locale }) */ | |||
// 如果想要中文版 element-ui,按如下方式声明 | |||
// Vue.use(ElementUI) | |||
Vue.use(ElementUI) | |||
Vue.config.productionTip = false | |||
@@ -103,7 +103,8 @@ export const constantRoutes = [{ | |||
icon: 'el-icon-user-solid' | |||
} | |||
}, | |||
{ | |||
// todo 一期先不做这个功能 后面原型图确认了再做 | |||
/* { | |||
path: 'related-setting', | |||
name: 'related-setting', | |||
component: () => import('@/views/off-limits-manage/related-setting/index'), | |||
@@ -111,7 +112,7 @@ export const constantRoutes = [{ | |||
title: '相关设置', | |||
icon: 'el-icon-s-tools' | |||
} | |||
}, | |||
}, */ | |||
{ | |||
path: 'alarm-query', | |||
name: 'alarm-query', | |||
@@ -61,5 +61,5 @@ div:focus { | |||
// main-container global css | |||
.app-container { | |||
padding: 20px; | |||
padding: 20px 10px; | |||
} |
@@ -1,8 +1,8 @@ | |||
/* | |||
* @Date: 2021-11-30 15:09:25 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-11-30 15:09:49 | |||
* @LastEditTime: 2021-12-03 15:26:11 | |||
* @FilePath: \GpsCardAdmin\src\utils\model.js | |||
* @description: 版本号 | |||
*/ | |||
export const VersionModel = '1.0.0'; | |||
export const VersionModel = '1.0.3'; |
@@ -0,0 +1,58 @@ | |||
Math.easeInOutQuad = function(t, b, c, d) { | |||
t /= d / 2 | |||
if (t < 1) { | |||
return c / 2 * t * t + b | |||
} | |||
t-- | |||
return -c / 2 * (t * (t - 2) - 1) + b | |||
} | |||
// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts | |||
var requestAnimFrame = (function() { | |||
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } | |||
})() | |||
/** | |||
* Because it's so fucking difficult to detect the scrolling element, just move them all | |||
* @param {number} amount | |||
*/ | |||
function move(amount) { | |||
document.documentElement.scrollTop = amount | |||
document.body.parentNode.scrollTop = amount | |||
document.body.scrollTop = amount | |||
} | |||
function position() { | |||
return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop | |||
} | |||
/** | |||
* @param {number} to | |||
* @param {number} duration | |||
* @param {Function} callback | |||
*/ | |||
export function scrollTo(to, duration, callback) { | |||
const start = position() | |||
const change = to - start | |||
const increment = 20 | |||
let currentTime = 0 | |||
duration = (typeof (duration) === 'undefined') ? 500 : duration | |||
var animateScroll = function() { | |||
// increment the time | |||
currentTime += increment | |||
// find the value with the quadratic in-out easing function | |||
var val = Math.easeInOutQuad(currentTime, start, change, duration) | |||
// move the document.body | |||
move(val) | |||
// do the animation unless its over | |||
if (currentTime < duration) { | |||
requestAnimFrame(animateScroll) | |||
} else { | |||
if (callback && typeof (callback) === 'function') { | |||
// the animation is done so lets callback | |||
callback() | |||
} | |||
} | |||
} | |||
animateScroll() | |||
} |
@@ -1,27 +1,115 @@ | |||
<!-- | |||
* @Date: 2021-11-30 14:25:27 | |||
* @Date: 2021-11-30 09:44:24 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-11-30 14:25:37 | |||
* @LastEditTime: 2021-12-01 14:30:07 | |||
* @FilePath: \GpsCardAdmin\src\views\off-limits-manage\alarm-query\index.vue | |||
* @description:告警查询 | |||
* @description: | |||
--> | |||
<template> | |||
<div> | |||
告警查询 | |||
<div class="app-container"> | |||
<div class="filter-container"> | |||
<!-- 搜索 --> | |||
<el-input | |||
v-model="searchValue" | |||
placeholder="请输入关键字" | |||
style="width: 200px; margin-left: 10px;" | |||
class="filter-item" | |||
@keyup.enter.native="onSearch" | |||
/> | |||
<el-button | |||
class="filter-item" | |||
style="margin-left: 10px;" | |||
type="primary" | |||
icon="el-icon-search" | |||
@click="onSearch" | |||
>搜索</el-button> | |||
</div> | |||
<!-- 表格 --> | |||
<!-- <el-table | |||
:key="tableKey" | |||
v-loading="listLoading" | |||
:data="list" | |||
border | |||
fit | |||
highlight-current-row | |||
style="width: 100%;" | |||
@sort-change="sortChange" | |||
></el-table>--> | |||
<TTable :tableData="list" :columns="columns" @update="onUpdate" @delete="onDelete"></TTable> | |||
<!-- 分页 --> | |||
<pagination | |||
v-show="total>0" | |||
:total="total" | |||
:page.sync="page" | |||
:limit.sync="limit" | |||
@pagination="getList" | |||
/> | |||
</div> | |||
</template> | |||
<script> | |||
import TopMenu from "@/components/TopMenu"; | |||
import TTable from "../../../components/TTable/TTable"; | |||
import Pagination from "@/components/Pagination"; | |||
export default { | |||
name:'', | |||
data(){ | |||
return { | |||
} | |||
} | |||
} | |||
name: "", | |||
components: { TTable, TopMenu, Pagination }, | |||
data() { | |||
return { | |||
model: "", | |||
modelOptions: [ | |||
{ | |||
value: "1", | |||
label: "类别1" | |||
}, | |||
{ | |||
value: "2", | |||
label: "类别1" | |||
} | |||
], | |||
searchValue: "", | |||
columns: [ | |||
{ prop: "alarmType", title: "告警类别" }, | |||
{ prop: "imei", title: "设备IMEI" }, | |||
{ prop: "alarmAddress", title: "告警地址/经纬度" }, | |||
{ prop: "createTime", title: "创建时间" }, | |||
/* { | |||
action: true, | |||
title: "操作", | |||
actions: [ | |||
{ fnName: "delete", title: "删除", type: "error" }, | |||
] | |||
} */ | |||
], | |||
list: [ | |||
{ | |||
alarmType: '出走风险', | |||
imei: "141152552521", | |||
alarmAddress: "广东省佛山市南海区", | |||
createTime: "2021-11-30" | |||
} | |||
], | |||
total: 1, | |||
page: 1, | |||
limit: 10, | |||
}; | |||
}, | |||
methods: { | |||
// 搜索 | |||
onSearch() {}, | |||
// 修改 | |||
onUpdate(row) { | |||
console.log("修改", row); | |||
}, | |||
// 删除 | |||
onDelete(row) { | |||
console.log("删除", row); | |||
}, | |||
// 获取分页数据 | |||
getList() {} | |||
} | |||
}; | |||
</script> | |||
<style scoped> | |||
</style> |
@@ -1,27 +1,298 @@ | |||
<!-- | |||
* @Date: 2021-11-30 09:44:24 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-11-30 09:44:48 | |||
* @LastEditTime: 2021-12-01 17:33:03 | |||
* @FilePath: \GpsCardAdmin\src\views\off-limits-manage\alarm-recognition\index.vue | |||
* @description: | |||
--> | |||
<template> | |||
<div> | |||
告警识别内容 | |||
<div class="app-container"> | |||
<div class="filter-container"> | |||
<el-button | |||
class="filter-item" | |||
style="margin-left: 10px;" | |||
type="primary" | |||
icon="el-icon-circle-plus" | |||
@click="onAdd" | |||
>添加</el-button> | |||
<el-button | |||
class="filter-item" | |||
style="margin-left: 10px;" | |||
type="primary" | |||
icon="el-icon-folder-add" | |||
@click="onImportBatch" | |||
>批量导入</el-button> | |||
<!-- 下拉 --> | |||
<!-- 类型 --> | |||
<el-select | |||
v-model="type" | |||
placeholder="类型" | |||
style="width: 130px; margin-left: 10px;" | |||
filterable | |||
> | |||
<el-option | |||
v-for="item in typeOptions" | |||
:key="item.value" | |||
:label="item.label" | |||
:value="item.value" | |||
class="filter-item" | |||
></el-option> | |||
</el-select> | |||
<!-- 类别 --> | |||
<el-select | |||
v-model="model" | |||
placeholder="类别" | |||
style="width: 130px; margin-left: 10px;" | |||
filterable | |||
> | |||
<el-option | |||
v-for="item in modelOptions" | |||
:key="item.value" | |||
:label="item.label" | |||
:value="item.value" | |||
class="filter-item" | |||
></el-option> | |||
</el-select> | |||
<!-- 搜索 --> | |||
<el-input | |||
v-model="searchValue" | |||
placeholder="请输入关键字" | |||
style="width: 200px; margin-left: 10px;" | |||
class="filter-item" | |||
@keyup.enter.native="onSearch" | |||
/> | |||
<el-button | |||
class="filter-item" | |||
style="margin-left: 10px;" | |||
type="primary" | |||
icon="el-icon-search" | |||
@click="onSearch" | |||
>搜索</el-button> | |||
</div> | |||
<TTable :tableData="list" :columns="columns" @update="onUpdate" @delete="onDelete"></TTable> | |||
<!-- 分页 --> | |||
<pagination | |||
v-show="total>0" | |||
:total="total" | |||
:page.sync="page" | |||
:limit.sync="limit" | |||
@pagination="getList" | |||
/> | |||
<el-dialog :visible.sync="dialogPvVisible" :title="dialogTitle"> | |||
<el-form | |||
ref="dataForm" | |||
v-model="form" | |||
label-position="left" | |||
label-width="70px" | |||
style="width: 400px; margin-left:50px;" | |||
> | |||
<!-- 类型 --> | |||
<el-form-item label="类型" prop="type"> | |||
<el-select v-model="form.type" class="filter-item" filterable> | |||
<el-option | |||
v-for="item in typeOptions" | |||
:key="item.value" | |||
:label="item.label" | |||
:value="item.value" | |||
/> | |||
</el-select> | |||
</el-form-item> | |||
<!-- 类别 --> | |||
<el-form-item label="类别" prop="model"> | |||
<el-select v-model="form.model" class="filter-item" filterable> | |||
<el-option | |||
v-for="item in modelOptions" | |||
:key="item.value" | |||
:label="item.label" | |||
:value="item.value" | |||
/> | |||
</el-select> | |||
</el-form-item> | |||
<!-- 内容名称 --> | |||
<el-form-item label="内容名称" prop="content"> | |||
<el-input v-model="form.content" /> | |||
</el-form-item> | |||
<!-- 创建时间 --> | |||
<el-form-item label="创建时间" prop="timestamp"> | |||
<el-date-picker v-model="form.createTime" type="datetime" /> | |||
</el-form-item> | |||
</el-form> | |||
<span slot="footer" class="dialog-footer"> | |||
<el-button type="error" @click="dialogPvVisible = false">取消</el-button> | |||
<el-button type="primary" @click="dialogStatus === 'update' ? update() : add()">确认</el-button> | |||
</span> | |||
</el-dialog> | |||
<el-dialog :visible.sync="dialogUpload"> | |||
<upload-excel-component :on-success="handleSuccess" :before-upload="beforeUpload" /> | |||
</el-dialog> | |||
</div> | |||
</template> | |||
<script> | |||
import TopMenu from "@/components/TopMenu"; | |||
import TTable from "../../../components/TTable/TTable"; | |||
import Pagination from "@/components/Pagination"; | |||
import UploadExcelComponent from "@/components/UploadExcel/index.vue"; | |||
export default { | |||
name:'', | |||
data(){ | |||
return { | |||
name: "", | |||
components: { TTable, TopMenu, Pagination, UploadExcelComponent }, | |||
data() { | |||
return { | |||
buttonList: [ | |||
{ | |||
name: "添加", | |||
type: "success", | |||
click: () => { | |||
this.onAdd(); | |||
} | |||
}, | |||
{ | |||
name: "批量导入", | |||
type: "success", | |||
click: () => { | |||
this.onImportBatch(); | |||
} | |||
} | |||
], | |||
type: "", | |||
model: "", | |||
typeOptions: [ | |||
{ | |||
value: "1", | |||
label: "类别1" | |||
}, | |||
{ | |||
value: "2", | |||
label: "类别1" | |||
}, | |||
{ | |||
value: "3", | |||
label: "类别1" | |||
}, | |||
{ | |||
value: "4", | |||
label: "类别1" | |||
} | |||
], | |||
modelOptions: [ | |||
{ | |||
value: "1", | |||
label: "类别1" | |||
}, | |||
{ | |||
value: "2", | |||
label: "类别1" | |||
} | |||
], | |||
searchValue: "", | |||
columns: [ | |||
{ prop: "type", title: "类型" }, | |||
{ prop: "model", title: "类别" }, | |||
{ prop: "content", title: "内容名称" }, | |||
{ prop: "createTime", title: "创建时间" }, | |||
{ | |||
action: true, | |||
title: "操作", | |||
actions: [ | |||
{ fnName: "update", title: "修改", type: "primary" }, | |||
{ fnName: "delete", title: "删除", type: "error" } | |||
] | |||
} | |||
], | |||
list: [ | |||
{ | |||
type: "关键子", | |||
model: "出走危险", | |||
content: "港口码头", | |||
createTime: "2021-11-30" | |||
} | |||
], | |||
total: 1, | |||
page: 1, | |||
limit: 10, | |||
dialogPvVisible: false, | |||
dialogStatus: "", | |||
dialogTitle: "修改告警识别内容", | |||
form: { | |||
type: "", | |||
model: "", | |||
content: "", | |||
createTime: "" | |||
}, | |||
dialogUpload: false | |||
}; | |||
}, | |||
methods: { | |||
// 添加 | |||
onAdd() { | |||
console.log("add"); | |||
this.form = ""; | |||
this.dialogTitle = "添加告警识别内容"; | |||
this.dialogPvVisible = true; | |||
this.dialogStatus = "add"; | |||
}, | |||
add() { | |||
console.log("add"); | |||
}, | |||
// 批量导入, ##注意 ,批量导入格式必须跟表格的一样 | |||
onImportBatch() { | |||
this.dialogUpload = true; | |||
}, | |||
// 搜索 | |||
onSearch() {}, | |||
// 修改 | |||
onUpdate(row) { | |||
this.dialogPvVisible = true; | |||
this.dialogStatus = "update"; | |||
this.dialogTitle = "修改告警识别内容"; | |||
this.form = Object.assign({}, row); // copy obj | |||
this.form.createTime = new Date(this.form.createTime); | |||
console.log("修改", row); | |||
}, | |||
update() { | |||
console.log("update"); | |||
}, | |||
// 删除 | |||
onDelete(row) { | |||
console.log("删除", row); | |||
this.$confirm("是否删除?", { | |||
confirmButtonText: "确定", | |||
cancelButtonText: "取消", | |||
type: "warning" | |||
}) | |||
.then(() => { | |||
this.$message({ | |||
type: "success", | |||
message: "删除成功!" | |||
}); | |||
}) | |||
.catch(() => {}); | |||
}, | |||
// 获取分页数据 | |||
getList() {}, | |||
beforeUpload(file) { | |||
const isLt1M = file.size / 1024 / 1024 < 1; | |||
} | |||
} | |||
} | |||
if (isLt1M) { | |||
return true; | |||
} | |||
this.$message({ | |||
message: "导入的文件不能超过1m", | |||
type: "warning" | |||
}); | |||
return false; | |||
}, | |||
handleSuccess({ results, header }) { | |||
this.list = results; | |||
this.columns = header.map(h => { | |||
return { prop: h, title: h } | |||
}); | |||
this.dialogUpload = false; | |||
} | |||
} | |||
}; | |||
</script> | |||
<style scoped> | |||
</style> |
@@ -1,27 +1,210 @@ | |||
<!-- | |||
* @Date: 2021-11-30 14:22:25 | |||
* @Date: 2021-11-30 09:44:24 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-11-30 14:22:37 | |||
* @LastEditTime: 2021-12-01 17:32:44 | |||
* @FilePath: \GpsCardAdmin\src\views\off-limits-manage\common-exception\index.vue | |||
* @description:通用例外 | |||
* @description: | |||
--> | |||
<template> | |||
<div> | |||
通用例外 | |||
<div class="app-container"> | |||
<div class="filter-container"> | |||
<el-button | |||
class="filter-item" | |||
style="margin-left: 10px;" | |||
type="primary" | |||
icon="el-icon-circle-plus" | |||
@click="onAdd" | |||
>添加</el-button> | |||
<!-- 下拉 --> | |||
<!-- 类别 --> | |||
<el-select v-model="model" placeholder="类别" style="width: 130px; margin-left: 10px;" filterable> | |||
<el-option | |||
v-for="item in typeOptions" | |||
:key="item.value" | |||
:label="item.label" | |||
:value="item.value" | |||
class="filter-item" | |||
></el-option> | |||
</el-select> | |||
<!-- 搜索 --> | |||
<el-input | |||
v-model="searchValue" | |||
placeholder="请输入关键字" | |||
style="width: 200px; margin-left: 10px;" | |||
class="filter-item" | |||
@keyup.enter.native="onSearch" | |||
/> | |||
<el-button | |||
class="filter-item" | |||
style="margin-left: 10px;" | |||
type="primary" | |||
icon="el-icon-search" | |||
@click="onSearch" | |||
>搜索</el-button> | |||
</div> | |||
<!-- 表格 --> | |||
<!-- <el-table | |||
:key="tableKey" | |||
v-loading="listLoading" | |||
:data="list" | |||
border | |||
fit | |||
highlight-current-row | |||
style="width: 100%;" | |||
@sort-change="sortChange" | |||
></el-table>--> | |||
<TTable :tableData="list" :columns="columns" @update="onUpdate" @delete="onDelete"></TTable> | |||
<!-- 分页 --> | |||
<pagination | |||
v-show="total>0" | |||
:total="total" | |||
:page.sync="page" | |||
:limit.sync="limit" | |||
@pagination="getList" | |||
/> | |||
<el-dialog :visible.sync="dialogPvVisible" :title="dialogTitle"> | |||
<el-form | |||
ref="dataForm" | |||
v-model="form" | |||
label-position="left" | |||
label-width="70px" | |||
style="width: 400px; margin-left:50px;" | |||
> | |||
<!-- 类别 --> | |||
<el-form-item label="类别" prop="type"> | |||
<el-select v-model="form.model" class="filter-item" filterable> | |||
<el-option | |||
v-for="item in typeOptions" | |||
:key="item.value" | |||
:label="item.label" | |||
:value="item.value" | |||
/> | |||
</el-select> | |||
</el-form-item> | |||
<!-- 内容名称 --> | |||
<el-form-item label="内容名称" prop="content"> | |||
<el-input v-model="form.content" /> | |||
</el-form-item> | |||
<!-- 创建时间 --> | |||
<el-form-item label="创建时间" prop="timestamp"> | |||
<el-date-picker v-model="form.createTime" type="datetime" /> | |||
</el-form-item> | |||
</el-form> | |||
<span slot="footer" class="dialog-footer"> | |||
<el-button type="error" @click="dialogPvVisible = false">取消</el-button> | |||
<el-button type="primary" @click="dialogStatus === 'update' ? update() : add()">确认</el-button> | |||
</span> | |||
</el-dialog> | |||
</div> | |||
</template> | |||
<script> | |||
import TopMenu from "@/components/TopMenu"; | |||
import TTable from "../../../components/TTable/TTable"; | |||
import Pagination from "@/components/Pagination"; | |||
export default { | |||
name:'', | |||
data(){ | |||
return { | |||
} | |||
} | |||
} | |||
name: "", | |||
components: { TTable, TopMenu, Pagination }, | |||
data() { | |||
return { | |||
typeOptions: [ | |||
{ | |||
value: "1", | |||
label: "类别1" | |||
}, | |||
{ | |||
value: "2", | |||
label: "类别1" | |||
}, | |||
{ | |||
value: "3", | |||
label: "类别1" | |||
}, | |||
{ | |||
value: "4", | |||
label: "类别1" | |||
} | |||
], | |||
model: '', | |||
searchValue: "", | |||
columns: [ | |||
{ prop: "model", title: "类别" }, | |||
{ prop: "content", title: "内容名称" }, | |||
{ prop: "createTime", title: "创建时间" }, | |||
{ | |||
action: true, | |||
title: "操作", | |||
actions: [ | |||
{ fnName: "update", title: "修改", type: "primary" }, | |||
{ fnName: "delete", title: "删除", type: "error" } | |||
] | |||
} | |||
], | |||
list: [ | |||
{ | |||
model: "出走危险", | |||
content: "港口码头", | |||
createTime: "2021-11-30" | |||
} | |||
], | |||
total: 1, | |||
page: 1, | |||
limit: 10, | |||
type: "error", | |||
dialogPvVisible: false, | |||
dialogStatus: '', | |||
dialogTitle: "修改通用例外", | |||
form: { | |||
model: "", | |||
content: "", | |||
createTime: "" | |||
} | |||
}; | |||
}, | |||
methods: { | |||
// 添加 | |||
onAdd() { | |||
this.form = ''; | |||
this.dialogTitle = '添加通用例外'; | |||
this.dialogPvVisible = true; | |||
this.dialogStatus = 'add'; | |||
}, | |||
add() { | |||
console.log("addd"); | |||
}, | |||
// 搜索 | |||
onSearch() {}, | |||
// 修改 | |||
onUpdate(row) { | |||
this.dialogPvVisible = true; | |||
this.dialogStatus = 'update'; | |||
this.dialogTitle = '修改通用例外'; | |||
this.form = Object.assign({}, row); // copy obj | |||
this.form.createTime = new Date(this.form.createTime); | |||
console.log("修改", row); | |||
}, | |||
update() { | |||
console.log("update"); | |||
}, | |||
// 删除 | |||
onDelete(row) { | |||
console.log("删除", row); | |||
this.$confirm("是否删除?", { | |||
confirmButtonText: "确定", | |||
cancelButtonText: "取消", | |||
type: "warning" | |||
}).then(() => { | |||
this.$message({ | |||
type: "success", | |||
message: "删除成功!" | |||
}); | |||
}).catch(() => {}); | |||
}, | |||
// 获取分页数据 | |||
getList() {} | |||
} | |||
}; | |||
</script> | |||
<style scoped> | |||
</style> |
@@ -1,27 +1,332 @@ | |||
<!-- | |||
* @Date: 2021-11-30 09:28:55 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-11-30 09:29:14 | |||
* @LastEditTime: 2021-12-03 15:22:29 | |||
* @FilePath: \GpsCardAdmin\src\views\off-limits-manage\off-limits-main\off-limits-type\index.vue | |||
* @description: | |||
--> | |||
<template> | |||
<div> | |||
禁用类别 | |||
<div class="custom-tree-container"> | |||
<div class="block"> | |||
<el-tree | |||
:data="data" | |||
node-key="id" | |||
:default-expand-all="false" | |||
:render-after-expand="true" | |||
:expand-on-click-node="false"> | |||
<span class="custom-tree-node" slot-scope="{ node, data }"> | |||
<span>{{ node.label }} ( {{ data.no }} )</span><span></span> | |||
<div class="Operation"> | |||
<span> | |||
<el-button v-if=" data.children" | |||
type="text" | |||
size="mini" | |||
@click="() => append(node,data)"> | |||
增加类别 | |||
</el-button> | |||
<el-button v-if="!data.children" | |||
type="text" | |||
size="mini" | |||
@click="() => modify(node, data)"> | |||
修改 | |||
</el-button> | |||
<el-button v-if="!data.children" | |||
type="text" | |||
size="mini" | |||
@click="() => remove(node, data)"> | |||
删除 | |||
</el-button> | |||
</span></div> | |||
</span> | |||
</el-tree> | |||
<el-row> | |||
<el-col :span="8"><div class="grid-content bg-purple-light add-btn" > | |||
<el-button type="text" @click="dialogVisible = true"> 增加场景</el-button> | |||
</div></el-col> | |||
</el-row> | |||
<el-dialog | |||
title="新增场景" | |||
:visible.sync="dialogVisible" | |||
width="50%" | |||
> | |||
<el-form :model="currentAddScenes" ref="currentAddScenes"> | |||
<el-form-item label="场景" | |||
prop="inputNew" | |||
:rules="[ | |||
{ required: true, message: '场景不能为空'} | |||
]" | |||
> | |||
<el-input v-model="currentAddScenes.inputNew" placeholder="请输入场景"></el-input> | |||
</el-form-item> | |||
<el-form-item> | |||
<el-button type="primary" @click="submitScenesForm('currentAddScenes')">提交</el-button> | |||
<el-button @click="resetForm('currentAddScenes')">重置</el-button> | |||
<el-button @click="dialogVisible = false">取 消</el-button> | |||
</el-form-item> | |||
</el-form> | |||
</el-dialog> | |||
<el-dialog | |||
:title="titleTypeAddorModify" | |||
:visible.sync="dialogVisibleType" | |||
width="50%" | |||
> | |||
<el-form :model="currentAddType" ref="currentAddType"> | |||
<el-form-item label="类别" | |||
prop="typeLabel" | |||
:rules="[ | |||
{ required: true, message: '类别不能为空'} | |||
]" | |||
> | |||
<el-input v-model="currentAddType.typeLabel" placeholder="请输入类别"></el-input> | |||
</el-form-item> | |||
<el-form-item> | |||
<el-button type="primary" @click="submitForm('currentAddType')">提交</el-button> | |||
<el-button @click="resetForm('currentAddType')">重置</el-button> | |||
<el-button @click="dialogVisibleType = false">取 消</el-button> | |||
</el-form-item> | |||
</el-form> | |||
</el-dialog> | |||
<el-dialog | |||
title="修改类别" | |||
:visible.sync="dialogVisibleM" | |||
width="50%" | |||
> | |||
<el-input v-model="inputModify" placeholder="请输入类别"></el-input> | |||
<span slot="footer" class="dialog-footer"> | |||
<el-button @click="dialogVisibleM = false">取 消</el-button> | |||
<el-button type="primary" @click="() => save()">确 定</el-button> | |||
</span> | |||
</el-dialog> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
let id = 1000; | |||
export default { | |||
name:'', | |||
data(){ | |||
return { | |||
const data = [{ | |||
id: 1, | |||
no:101, | |||
label: '场景1', | |||
children: [{ | |||
id: 4, | |||
no:101001, | |||
label: '类别 1-1' | |||
}] | |||
}, { | |||
id: 2, | |||
no:102, | |||
label: '场景 2', | |||
children: [{ | |||
id: 5, | |||
no:102001, | |||
label: '类别 2-1' | |||
}, { | |||
id: 6, | |||
no:102002, | |||
label: '类别 2-2' | |||
}] | |||
} | |||
]; | |||
return { | |||
titleTypeAddorModify:"新增类别", | |||
inputNew: '', | |||
inputType:'', | |||
inputModify: '', | |||
parentNode:{}, | |||
dialogVisible: false, | |||
dialogVisibleType:false, | |||
dialogVisibleM: false, | |||
currentData:{}, | |||
currentParentData:{}, | |||
currentAddScenes:{ | |||
inputNew:"", | |||
}, | |||
currentAddType:{ | |||
typeLabel:"" | |||
}, | |||
} | |||
} | |||
data: JSON.parse(JSON.stringify(data)) | |||
} | |||
}, | |||
methods: { | |||
submitScenesForm(formName) { | |||
this.$refs[formName].validate((valid) => { | |||
if (valid) { | |||
//alert('submit!'); | |||
this.addScenes(); | |||
} else { | |||
console.log('error submit!!'); | |||
return false; | |||
} | |||
}); | |||
}, | |||
submitForm(formName) { | |||
this.$refs[formName].validate((valid) => { | |||
if (valid) { | |||
//alert('submit!'); | |||
if(this.titleTypeAddorModify=="增加类别") | |||
{ | |||
this.addType(); | |||
} | |||
else | |||
{ | |||
this.save(); | |||
} | |||
} else { | |||
console.log('error submit!!'); | |||
return false; | |||
} | |||
}); | |||
}, | |||
resetForm(formName) { | |||
this.$refs[formName].resetFields(); | |||
}, | |||
append(node,data) { | |||
const parent = node; | |||
this.currentParentData=parent.data; | |||
this.dialogVisibleType=true; | |||
this.titleTypeAddorModify="增加类别"; | |||
if(this.$refs['currentAddType']){ | |||
this.resetForm('currentAddType'); | |||
} | |||
}, | |||
addScenes(){ | |||
this.dialogVisible=false; | |||
let no=this.data[this.data.length-1].no+1; | |||
let id=this.data[this.data.length-1].id+1; | |||
this.data.push( { | |||
id: id, | |||
no:no, | |||
label: this.currentAddScenes.inputNew, | |||
children: [] | |||
}); | |||
}, | |||
addType(){ | |||
this.dialogVisibleType=false; | |||
//模拟保存 | |||
this.data.forEach(i=>{ | |||
if(i.id==this.currentParentData.id) | |||
{ | |||
let no,id; | |||
if(i.children && i.children.length>0){ | |||
no=i.children[i.children.length-1].no+1; | |||
id=i.children[i.children.length-1].id+1; | |||
} | |||
else{ | |||
no=i.no+'001'; | |||
id=i.id+'001'; | |||
} | |||
i.children.push({ | |||
id:id, | |||
label: this.currentAddType.typeLabel, | |||
no:no | |||
}); | |||
} | |||
}); | |||
//this.inputType | |||
}, | |||
remove(node, data) { | |||
const parent = node.parent; | |||
const children = parent.data.children || parent.data; | |||
const index = children.findIndex(d => d.id === data.id); | |||
children.splice(index, 1); | |||
}, | |||
modify(node,data){ | |||
this.titleTypeAddorModify="修改类别"; | |||
this.dialogVisibleType=true; | |||
this.currentData=data; | |||
//this.dialogVisibleM=true; | |||
//this.inputModify=data.label; | |||
this.currentAddType.typeLabel=data.label; | |||
}, | |||
save(){ | |||
//模拟保存: | |||
this.dialogVisibleType = false | |||
this.data.forEach(element => { | |||
if(element.children) | |||
{ | |||
element.children.forEach(i=>{ | |||
if(i.id===this.currentData.id) | |||
{ | |||
i.label=this.currentAddType.typeLabel; | |||
} | |||
}); | |||
} | |||
}); | |||
}, | |||
renderContent(h, { node, data, store }) { | |||
return ( | |||
<span class="custom-tree-node"> | |||
<span>{node.label}</span> | |||
<span> | |||
<el-button size="mini" type="text" on-click={ () => this.append(data) }>Append</el-button> | |||
<el-button v-if="node.children.len==0" size="mini" type="text" on-click={ () => this.remove(node, data) }>Delete</el-button> | |||
</span> | |||
</span>); | |||
} | |||
} | |||
} | |||
</script> | |||
<style scoped> | |||
<style> | |||
.custom-tree-node { | |||
flex: 1; | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
font-size: 14px; | |||
padding-right: 8px; | |||
} | |||
.custom-tree-container .block{ | |||
width: 50%; | |||
margin-top: 5%; | |||
margin-left: 5%; | |||
} | |||
.add-btn { | |||
margin-left:10%; | |||
} | |||
</style> | |||
</style> |
@@ -1,24 +1,177 @@ | |||
<!-- | |||
* @Date: 2021-11-30 14:23:11 | |||
* @Date: 2021-11-30 09:44:24 | |||
* @LastEditors: JinxuChen | |||
* @LastEditTime: 2021-11-30 14:31:21 | |||
* @LastEditTime: 2021-12-01 17:35:09 | |||
* @FilePath: \GpsCardAdmin\src\views\off-limits-manage\user-exception\index.vue | |||
* @description:用户例外 | |||
* @description: | |||
--> | |||
<template> | |||
<div>用户例外</div> | |||
<div class="app-container"> | |||
<div class="filter-container"> | |||
<!-- 搜索 --> | |||
<el-input | |||
v-model="searchValue" | |||
placeholder="请输入关键字" | |||
style="width: 200px; margin-left: 10px;" | |||
class="filter-item" | |||
@keyup.enter.native="onSearch" | |||
/> | |||
<el-button | |||
class="filter-item" | |||
style="margin-left: 10px;" | |||
type="primary" | |||
icon="el-icon-search" | |||
@click="onSearch" | |||
>搜索</el-button> | |||
</div> | |||
<!-- 表格 --> | |||
<!-- <el-table | |||
:key="tableKey" | |||
v-loading="listLoading" | |||
:data="list" | |||
border | |||
fit | |||
highlight-current-row | |||
style="width: 100%;" | |||
@sort-change="sortChange" | |||
></el-table>--> | |||
<TTable :tableData="list" :columns="columns" @update="onUpdate" @delete="onDelete" @transform="onTransform"></TTable> | |||
<!-- 分页 --> | |||
<pagination | |||
v-show="total>0" | |||
:total="total" | |||
:page.sync="page" | |||
:limit.sync="limit" | |||
@pagination="getList" | |||
/> | |||
<el-dialog :visible.sync="dialogPvVisible" :title="dialogTitle"> | |||
<el-form | |||
ref="dataForm" | |||
v-model="form" | |||
label-position="left" | |||
label-width="70px" | |||
style="width: 400px; margin-left:50px;" | |||
> | |||
<!-- 内容名称 --> | |||
<el-form-item label="IMEI" prop="imei"> | |||
<el-input v-model="form.imei" /> | |||
</el-form-item> | |||
<!-- 内容名称 --> | |||
<el-form-item label="内容名称" prop="title"> | |||
<el-input v-model="form.content" /> | |||
</el-form-item> | |||
<!-- 创建时间 --> | |||
<el-form-item label="创建时间" prop="timestamp"> | |||
<el-date-picker v-model="form.createTime" type="datetime" /> | |||
</el-form-item> | |||
</el-form> | |||
<span slot="footer" class="dialog-footer"> | |||
<el-button type="error" @click="dialogPvVisible = false">取消</el-button> | |||
<el-button type="primary" @click="dialogStatus === 'update' ? update() : add()">确认</el-button> | |||
</span> | |||
</el-dialog> | |||
</div> | |||
</template> | |||
<script> | |||
import TopMenu from "@/components/TopMenu"; | |||
import TTable from "../../../components/TTable/TTable"; | |||
import Pagination from "@/components/Pagination"; | |||
export default { | |||
name: "", | |||
components: { TTable, TopMenu, Pagination }, | |||
data() { | |||
return { | |||
model: "", | |||
modelOptions: [ | |||
{ | |||
value: "1", | |||
label: "类别1" | |||
}, | |||
{ | |||
value: "2", | |||
label: "类别1" | |||
} | |||
], | |||
searchValue: "", | |||
columns: [ | |||
{ prop: "imei", title: "IMEI" }, | |||
{ prop: "content", title: "内容名称" }, | |||
{ prop: "createTime", title: "创建时间" }, | |||
{ | |||
action: true, | |||
title: "操作", | |||
actions: [ | |||
{ fnName: "update", title: "修改", type: "primary" }, | |||
{ fnName: "delete", title: "删除", type: "error" }, | |||
{ fnName: "transform", title: "转通用", type: "primary" } | |||
] | |||
} | |||
], | |||
list: [ | |||
{ | |||
imei: "141152552521", | |||
model: "出走危险", | |||
content: "港口码头", | |||
createTime: "2021-11-30" | |||
} | |||
], | |||
total: 1, | |||
page: 1, | |||
limit: 10, | |||
dialogPvVisible: false, | |||
dialogStatus: "", | |||
dialogTitle: "修改用户例外", | |||
form: { | |||
imei: "", | |||
content: "", | |||
createTime: "" | |||
}, | |||
}; | |||
}, | |||
methods: { | |||
// 搜索 | |||
onSearch() {}, | |||
// 修改 | |||
onUpdate(row) { | |||
this.dialogPvVisible = true; | |||
this.dialogStatus = 'update'; | |||
this.dialogTitle = '修改用户例外'; | |||
this.form = Object.assign({}, row); // copy obj | |||
this.form.createTime = new Date(this.form.createTime); | |||
console.log("修改", row); | |||
}, | |||
// 删除 | |||
onDelete(row) { | |||
this.$confirm("是否删除?", { | |||
confirmButtonText: "确定", | |||
cancelButtonText: "取消", | |||
type: "warning" | |||
}).then(() => { | |||
this.$message({ | |||
type: "success", | |||
message: "删除成功!" | |||
}); | |||
}).catch(() => {}); | |||
}, | |||
// 转通用例外 | |||
onTransform(row) { | |||
this.$confirm("是否转到通用列外?", { | |||
confirmButtonText: "确定", | |||
cancelButtonText: "取消", | |||
type: "warning" | |||
}).then(() => { | |||
this.$message({ | |||
type: "success", | |||
message: "转移成功!" | |||
}); | |||
}).catch(() => {}); | |||
}, | |||
// 获取分页数据 | |||
getList() {} | |||
} | |||
}; | |||
</script> | |||
<style scoped> | |||
</style> | |||
</style> |