Commit 927edc02 by 李俊

chore: 备份最新代码

1 parent 24fbbb4f
Showing with 2595 additions and 624 deletions
src/client/*
\ No newline at end of file
src/client/*
src/components/select/*
\ No newline at end of file
......@@ -24,6 +24,7 @@ module.exports = {
// add your custom rules here
rules: {
"no-control-regex": 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
......@@ -55,7 +56,7 @@ module.exports = {
'no-unneeded-ternary': 2, // 禁止不必要的嵌套
'no-nested-ternary': 2, // 禁用嵌套的三目运算符
'no-nested-ternary': 0, // 禁用嵌套的三目运算符
'no-const-assign': 2, // 禁止修改 const 变量
......
stages:
- build-dev
variables:
CONFIG_DEV: ./public/config.js
# 开发构建
build-dev:
stage: build-dev
script:
- docker-compose build && docker-compose -p device_manage up -d
only:
- develop
tags:
- develop
FROM node:lts-alpine3.12 as build
RUN npm config set registry https://registry.npm.taobao.org
WORKDIR /tmp/cache
COPY package.json .
COPY package-lock.json .
RUN npm install
COPY . .
RUN npm run build
FROM socialengine/nginx-spa:latest as nginx
COPY default.conf /etc/nginx/conf.d/default.conf
COPY --from=build /tmp/cache/dist /app
# pushState friendly!
# The setup:
# * website name is `_`
# * javascript app is located at `/app`
charset utf-8;
tcp_nopush on;
tcp_nodelay off;
client_header_timeout 10s;
client_body_timeout 10s;
client_max_body_size 128k;
reset_timedout_connection on;
gzip on;
gzip_types
text/css
text/javascript
text/xml
text/plain
application/javascript
application/x-javascript
application/json
application/xml
application/rss+xml
application/atom+xml
font/truetype
font/opentype
image/svg+xml;
server {
listen 80;
server_name localhost;
root /app;
expires $expires;
# To make sure any assets can get through :)
location / {
try_files $uri @rewrites;
}
location /front {
proxy_pass https://hzdev.seetatech.com:9997;
proxy_ssl_verify off;
}
# If no asset matches, send it to your javascript app. Hopefully it's a route in the app!
location @rewrites {
rewrite ^(.+)$ /index.html last;
}
}
\ No newline at end of file
version: "3.7"
services:
device_manage:
container_name: device_manage
restart: always
image: device_manage:${CI_COMMIT_REF_NAME}
build:
dockerfile: Dockerfile
context: .
volumes:
- /ssl:/app/ssl
ports:
- 9998:80
\ No newline at end of file
......@@ -18,6 +18,7 @@
"dompurify": "^2.0.7",
"element-ui": "^2.15.3",
"exif-js": "^2.3.0",
"https": "^1.0.0",
"jquery": "^3.3.1",
"lodash": "^4.17.20",
"moment": "^2.24.0",
......@@ -39,6 +40,7 @@
"vue-property-decorator": "^9.1.2",
"vue-router": "^3.1.3",
"vue-showdown": "^2.4.1",
"vuedraggable": "^2.24.3",
"vuex": "^3.0.1",
"vuex-persistedstate": "^4.0.0-beta.3",
"xregexp": "^4.2.4",
......@@ -58,7 +60,11 @@
"@vue/eslint-config-standard": "^4.0.0",
"@vue/eslint-config-typescript": "^4.0.0",
"babel-eslint": "^10.1.0",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-vue-jsx": "^3.7.0",
"babel-preset-env": "^1.7.0",
"echarts": "^4.8.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
......
window.g = {
baseURL: 'http://218.94.122.141:8089/api',
baseURL: 'https://hzdev.seetatech.com:9997',
defaultLang: 'zh-CN', // 目前支持 zh-CN / ja-JP
}
\ No newline at end of file
import axios from './http'
const GET = 'get'
const POST = 'post'
const FRONT = '/front'
const USER = '/user'
export const loginApi = data => axios(POST, FRONT + USER + '/login', data)
export const logoutApi = data => axios(GET, FRONT + USER + '/logout', data)
export const getUsers = data => axios(GET, FRONT + USER + '/query_list', data)
export const createUser = data => axios(POST, FRONT + USER + '/add', data)
export const deleteUser = data => axios(GET, FRONT + USER + '/delete', data)
export const editUser = data => axios(POST, FRONT + USER + '/change', data)
const PARAMETER = '/parameter'
export const getParameter = data => axios(GET, FRONT + PARAMETER + '/query_list', data)
export const createParameter = data => axios(POST, FRONT + PARAMETER + '/create', data)
export const deleteParameter = data => axios(GET, FRONT + PARAMETER + '/delete', data)
export const editParameter = data => axios(POST, FRONT + PARAMETER + '/change', data)
export const detailParameter = data => axios(GET, FRONT + PARAMETER + '/query', data)
const TABLE = '/table'
export const getTable = data => axios(GET, FRONT + TABLE + '/query_list', data)
export const createTable = data => axios(POST, FRONT + TABLE + '/create', data)
export const deleteTable = data => axios(GET, FRONT + TABLE + '/delete', data)
export const addData = data => axios(POST, FRONT + TABLE + '/data/insert', data)
export const getData = data => axios(GET, FRONT + TABLE + '/data/query_list', data)
export const deleteData = data => axios(POST, FRONT + TABLE + '/data/delete', data)
const APPID = '/appid'
export const getApp = data => axios(GET, FRONT + APPID + '/query_list', data)
export const deleteApp = data => axios(GET, FRONT + APPID + '/delete', data)
export const setApp = data => axios(GET, FRONT + APPID + '/set', data)
export const addApp = data => axios(POST, FRONT + APPID + '/add', data)
const DEVICE = '/device'
export const getDevice = data => axios(POST, FRONT + DEVICE + '/query_list', data)
export const getDeviceService = data => axios(GET, FRONT + DEVICE + '/service/query')
export const getTag = data => axios(GET, FRONT + DEVICE + '/tag/query_list')
export const getServiceParamter = data => axios(GET, FRONT + DEVICE + '/service/parameter/query', data)
export const setServiceParamter = data => axios(POST, FRONT + DEVICE + '/service/parameter/change', data)
export const deleteTag = data => axios(GET, FRONT + DEVICE + '/tag/delete', data)
export const addTag = data => axios(POST, FRONT + DEVICE + '/tag/add', data)
export const postServiceRequest = data => axios(POST, FRONT + DEVICE + '/service/direct', data)
export const postServiceCommand = data => axios(POST, FRONT + DEVICE + '/service/command ', data)
const SERVICE = '/service'
export const getService = data => axios(POST, FRONT + SERVICE + '/query_list', data)
export const getServiceDevice = data => axios(GET, FRONT + SERVICE + '/device/query', data)
......@@ -10,12 +10,13 @@
//- body
.confirm-body(slot="body")
//- span.dialog-icon.iconfont(:class="[mode, iconClass]")
.title
//- .title
span.dialog-icon.iconfont(:class="[mode, iconClass]")
span.text {{ title }}
p.caption(v-if="message")
//- 支持html格式
span(v-html="message") {{ message }}
i.el-icon-warning(style="color: #F6AD3D;font-size: 22px;margin-right: 10px;float:left")
span(v-html="message" style="height: 22px;line-height: 22px") {{ message }}
.options(v-if="options && options.length")
.option(v-for="option in options")
......@@ -170,7 +171,7 @@ export default {
.caption
color: #4C4C4C
font-size: 14px
margin-top: 20px
// margin-top: 20px
color: $--color-text-regular
.options
margin-top: 15px
......
......@@ -24,6 +24,7 @@ import seetaTable from './seeta-ui/seeta-table'
// import seetaTooltip from './seeta-ui/seeta-tooltip.vue'
import seetaTabs from './seeta-ui/seeta-tabs.vue'
import seetaSelect from './seeta-ui/seeta-select.vue'
import packSelect from './select'
import seetaMenu from './seeta-ui/seeta-menu.vue'
import seetaCrumb from './seeta-ui/seeta-crumb.vue'
// import dateRange from './list-filter/date-range.vue'
......@@ -68,6 +69,7 @@ Vue.component('popup', popup)
// Vue.component('st-tooltip', seetaTooltip)
Vue.component('st-tabs', seetaTabs)
Vue.component('st-select', seetaSelect)
Vue.component('pack-select', packSelect)
Vue.component('st-menu', seetaMenu)
Vue.component('st-crumb', seetaCrumb)
Vue.component('puzzle-validator', puzzlevalidator)
......@@ -24,15 +24,16 @@ export default class nameFilter extends Vue {
}
search() {
const routeQuery = this.$route.query
// 避免重复搜索
if (this.name === routeQuery.name || this.name === '') return
const query = {
...routeQuery,
name: this.name,
page_index: '1',
}
this.$router.replace({ query: _.omitBy(query, item => item === '') })
this.$emit('startSearch', this.name)
// const routeQuery = this.$route.query
// // 避免重复搜索
// if (this.name === routeQuery.name || this.name === '') return
// const query = {
// ...routeQuery,
// name: this.name,
// page_index: '1',
// }
// this.$router.replace({ query: _.omitBy(query, item => item === '') })
}
}
</script>
......
......@@ -2,7 +2,7 @@
<div class="table-box" ref="tableBox">
<el-table
ref="table"
stripe
:stripe="stripe"
v-bind="$attrs"
v-on="$listeners"
v-loading="isLoading"
......@@ -17,7 +17,7 @@
<template slot-scope="props">
<el-table
stripe
:data="childTableData">
:data="props.row.child">
<template
v-for="col in childOptions">
<!-- 插槽 -->
......@@ -127,6 +127,7 @@
<!-- 普通列 -->
<!-- 表头居中 -->
<el-table-column
show-overflow-tooltip
header-align="left"
align="left"
v-else-if="!(typeof col.render === 'function')"
......@@ -177,6 +178,7 @@
</template>
<slot></slot>
</el-table>
<div class="pagination"><slot name="pagination"></slot></div>
<div class="pagination" v-if="pagination">
<el-pagination
:current-page.sync="currentPage"
......@@ -205,6 +207,7 @@ export default class seetaTableIndex extends Vue {
@Prop({ type: Array, default: () => [] }) options
// 子表格列表参数
@Prop({ type: Array, default: () => [] }) childOptions
@Prop({ type: Boolean, default: true }) stripe
// 数据加载函数
@Prop({ type: Function, default: () => { return {} } }) loadFunction
@Prop({ type: Number, default: 30 }) pageSize
......@@ -303,7 +306,7 @@ export default class seetaTableIndex extends Vue {
// 计算列表高度
getTableHeight() {
this.$nextTick(() => {
this.tableHeight = this.refTableBox.getBoundingClientRect().height - 66
this.tableHeight = this.pagination ? this.refTableBox.getBoundingClientRect().height - 66 : this.refTableBox.getBoundingClientRect().height - 25
// console.log(this.tableHeight)
})
}
......@@ -460,6 +463,8 @@ export default class seetaTableIndex extends Vue {
opacity: 0.6
transform: scale(1)
::v-deep .el-table__row
.status-icon + .any-slot
display: inline-block
.status-icon, .status-icon-animation
width: 6px
height: 6px
......@@ -550,6 +555,7 @@ export default class seetaTableIndex extends Vue {
::v-deep .el-icon-arrow-down:hover
color: #409EFF !important
.any-slot
display: inline-block
// display: inline-block
vertical-align: middle
overflow: hidden
</style>
import Select from './src/select';
/* istanbul ignore next */
Select.install = function(Vue) {
Vue.component(Select.name, Select);
};
export default Select;
export default {
data() {
return {
hoverOption: -1
};
},
computed: {
optionsAllDisabled() {
return this.options.filter(option => option.visible).every(option => option.disabled);
}
},
watch: {
hoverIndex(val) {
if (typeof val === 'number' && val > -1) {
this.hoverOption = this.options[val] || {};
}
this.options.forEach(option => {
option.hover = this.hoverOption === option;
});
}
},
methods: {
navigateOptions(direction) {
if (!this.visible) {
this.visible = true;
return;
}
if (this.options.length === 0 || this.filteredOptionsCount === 0) return;
if (!this.optionsAllDisabled) {
if (direction === 'next') {
this.hoverIndex++;
if (this.hoverIndex === this.options.length) {
this.hoverIndex = 0;
}
} else if (direction === 'prev') {
this.hoverIndex--;
if (this.hoverIndex < 0) {
this.hoverIndex = this.options.length - 1;
}
}
const option = this.options[this.hoverIndex];
if (option.disabled === true ||
option.groupDisabled === true ||
!option.visible) {
this.navigateOptions(direction);
}
this.$nextTick(() => this.scrollToOption(this.hoverOption));
}
}
}
};
<template>
<ul class="el-select-group__wrap" v-show="visible">
<li class="el-select-group__title">{{ label }}</li>
<li>
<ul class="el-select-group">
<slot></slot>
</ul>
</li>
</ul>
</template>
<script type="text/babel">
import Emitter from 'element-ui/src/mixins/emitter';
export default {
mixins: [Emitter],
name: 'ElOptionGroup',
componentName: 'ElOptionGroup',
props: {
label: String,
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
visible: true
};
},
watch: {
disabled(val) {
this.broadcast('ElOption', 'handleGroupDisabled', val);
}
},
methods: {
queryChange() {
this.visible = this.$children &&
Array.isArray(this.$children) &&
this.$children.some(option => option.visible === true);
}
},
created() {
this.$on('queryChange', this.queryChange);
},
mounted() {
if (this.disabled) {
this.broadcast('ElOption', 'handleGroupDisabled', this.disabled);
}
}
};
</script>
<template>
<li
@mouseenter="hoverItem"
@click.stop="selectOptionClick"
class="el-select-dropdown__item"
v-show="visible"
:class="{
'selected': itemSelected,
'is-disabled': disabled || groupDisabled || limitReached,
'hover': hover
}">
<slot>
<span>{{ currentLabel }}</span>
</slot>
</li>
</template>
<script type="text/babel">
import Emitter from 'element-ui/src/mixins/emitter';
import { getValueByPath, escapeRegexpString } from 'element-ui/src/utils/util';
export default {
mixins: [Emitter],
name: 'ElOption',
componentName: 'ElOption',
inject: ['select'],
props: {
value: {
required: true
},
label: [String, Number],
created: Boolean,
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
index: -1,
groupDisabled: false,
visible: true,
hitState: false,
hover: false
};
},
computed: {
isObject() {
return Object.prototype.toString.call(this.value).toLowerCase() === '[object object]';
},
currentLabel() {
return this.label || (this.isObject ? '' : this.value);
},
currentValue() {
return this.value || this.label || '';
},
itemSelected() {
if (!this.select.multiple) {
return this.isEqual(this.value, this.select.value);
} else {
return this.contains(this.select.value, this.value);
}
},
limitReached() {
if (this.select.multiple) {
return !this.itemSelected &&
(this.select.value || []).length >= this.select.multipleLimit &&
this.select.multipleLimit > 0;
} else {
return false;
}
}
},
watch: {
currentLabel() {
if (!this.created && !this.select.remote) this.dispatch('ElSelect', 'setSelected');
},
value(val, oldVal) {
const { remote, valueKey } = this.select;
if (!this.created && !remote) {
if (valueKey && typeof val === 'object' && typeof oldVal === 'object' && val[valueKey] === oldVal[valueKey]) {
return;
}
this.dispatch('ElSelect', 'setSelected');
}
}
},
methods: {
isEqual(a, b) {
if (!this.isObject) {
return a === b;
} else {
const valueKey = this.select.valueKey;
return getValueByPath(a, valueKey) === getValueByPath(b, valueKey);
}
},
contains(arr = [], target) {
if (!this.isObject) {
return arr && arr.indexOf(target) > -1;
} else {
const valueKey = this.select.valueKey;
return arr && arr.some(item => {
return getValueByPath(item, valueKey) === getValueByPath(target, valueKey);
});
}
},
handleGroupDisabled(val) {
this.groupDisabled = val;
},
hoverItem() {
if (!this.disabled && !this.groupDisabled) {
this.select.hoverIndex = this.select.options.indexOf(this);
}
},
selectOptionClick() {
if (this.disabled !== true && this.groupDisabled !== true) {
this.dispatch('ElSelect', 'handleOptionClick', [this, true]);
}
},
queryChange(query) {
this.visible = new RegExp(escapeRegexpString(query), 'i').test(this.currentLabel) || this.created;
if (!this.visible) {
this.select.filteredOptionsCount--;
}
}
},
created() {
this.select.options.push(this);
this.select.cachedOptions.push(this);
this.select.optionsCount++;
this.select.filteredOptionsCount++;
this.$on('queryChange', this.queryChange);
this.$on('handleGroupDisabled', this.handleGroupDisabled);
},
beforeDestroy() {
const { selected, multiple } = this.select;
let selectedOptions = multiple ? selected : [selected];
let index = this.select.cachedOptions.indexOf(this);
let selectedIndex = selectedOptions.indexOf(this);
// if option is not selected, remove it from cache
if (index > -1 && selectedIndex < 0) {
this.select.cachedOptions.splice(index, 1);
}
this.select.onOptionDestroy(this.select.options.indexOf(this));
}
};
</script>
<template>
<div
class="el-select-dropdown el-popper"
:class="[{ 'is-multiple': $parent.multiple }, popperClass]"
:style="{ minWidth: minWidth }">
<slot></slot>
</div>
</template>
<script type="text/babel">
import Popper from 'element-ui/src/utils/vue-popper';
export default {
name: 'ElSelectDropdown',
componentName: 'ElSelectDropdown',
mixins: [Popper],
props: {
placement: {
default: 'bottom-start'
},
boundariesPadding: {
default: 0
},
popperOptions: {
default() {
return {
gpuAcceleration: false
};
}
},
visibleArrow: {
default: true
},
appendToBody: {
type: Boolean,
default: true
}
},
data() {
return {
minWidth: ''
};
},
computed: {
popperClass() {
return this.$parent.popperClass;
}
},
watch: {
'$parent.inputWidth'() {
this.minWidth = this.$parent.$el.getBoundingClientRect().width + 'px';
}
},
mounted() {
this.referenceElm = this.$parent.$refs.reference.$el;
this.$parent.popperElm = this.popperElm = this.$el;
this.$on('updatePopper', () => {
if (this.$parent.visible) this.updatePopper();
});
this.$on('destroyPopper', this.destroyPopper);
}
};
</script>
'use strict'
import Axios from 'axios'
import { getToken } from '@/utils/user'
// import * as api from '../src/client'
import { baseUrl } from '../src/config'
import browserStorage from '@/services/local-storage'
import store from '@/store'
import { Notification } from 'element-ui'
import Router from '@/router/index.js'
// 配置默认进度条事件
Axios.defaults.onUploadProgress = p => {
const obj = document.querySelector('.uploadForm .el-icon-circle-check')
if (obj) {
const percent = ((p.loaded / p.total) * 100) | 0
obj.setAttribute('data-text', percent + '%')
store.dispatch('setChangeUploadPercent', percent)
}
}
import { baseUrl } from '@/config'
function notificationError(title: any, msg: any, duration: number = 1500) {
Notification.error({
......@@ -27,58 +15,24 @@ function notificationError(title: any, msg: any, duration: number = 1500) {
})
}
interface resData { code: string, text: string, msg: string }
interface optionsType {
allow_throw: boolean,
valid_code: boolean,
error_page: boolean,
must_fields?: [],
routerCancel?: boolean,
cancelToken?: any,
}
const m = new Map()
// 获取请求头
function getHeaders() {
const token = getToken()
return token ? { Authorization: token } : null
}
// 全局错误提示
function throwErr(resData: resData) {
vm.$notify.error({
title: resData.text,
message: resData.msg,
})
}
function validBackendCode(resData: resData, options: optionsType) {
if (resData.code === 'Success') return true
// Axios.defaults.baseURL = baseUrl
if (options.error_page) {
if (resData.code === 'NoAuthority') vm.$router.replace('/403')
if (resData.code === 'RecordNotFoundError') vm.$router.replace('/404')
}
if (options.allow_throw) {
const code = resData.code
const d = new Date()
if (m.has(code)) {
if (d.getTime() - m.get(code) > 2000) {
throwErr(resData)
m.set(code, d.getTime())
}
} else {
throwErr(resData)
m.set(code, d.getTime())
}
export default (method, url, data, config) => {
method = method.toLowerCase()
switch (method) {
case 'get':
return Axios({ method: 'get', url, headers: { 'Token': browserStorage.getItem('token') }, params: data })
case 'post':
return Axios({ method: 'post', url, headers: { 'Token': browserStorage.getItem('token') }, data })
default:
return false
}
return false
}
// 添加请求拦截器
Axios.interceptors.request.use(function(config) {
for (const key in config.params) {
if (config.params[key] === '' || config.params[key] === undefined) delete config.params[key]
}
const urlBase = config.url.split('?')[0]
const urlQueryArr = Array.from(new URLSearchParams(config.url.split('?')[1]))
let result = '?'
......@@ -105,6 +59,9 @@ Axios.interceptors.response.use(res => {
store.commit('removeAxiosCancelArr', index)
}
})
if (res && res.data && res.data.code !== 0) {
notificationError('提示', res.data.msg)
}
return res
}, error => {
error.response && error.response.data && notificationError('提示', error.response.data.message)
......@@ -131,13 +88,3 @@ Axios.interceptors.response.use(res => {
// })
}
})
// const configuration = new api.Configuration({
// // basePath: process.env.API_URL,
// basePath: baseUrl,
// apiKey() {
// // TODO: 从localStorage中获取Token,Organization-Id
// return browserStorage.getItem('id')
// }
// })
// export const usersApi = new api.UsersApi(configuration)
......@@ -27,7 +27,7 @@ export default {
return this.$route.name
},
menuList() {
const routerList = JSON.parse(JSON.stringify(this.$router.options.routes.filter(item => item.children)))
const routerList = JSON.parse(JSON.stringify(this.$router.options.routes.filter(item => item.children && !item.meta.hidden)))
const result = []
routerList.map(item => {
const children = []
......
......@@ -16,7 +16,7 @@
</ul>
<template v-slot:reference>
<span class="user-info flex right">
<span v-if="userData.info">{{ userData.info.username }}</span>
<span v-if="userData.info">{{ userData.info.creater }}</span>
<i class="iconfont icon-mianxingxiala"
:class="{
'expand': showInfo,
......@@ -29,6 +29,7 @@
<script lang="ts">
import { Vue, Prop, Component, Watch } from 'vue-property-decorator'
import { getUser, removeUser } from '@/utils/user'
import { logoutApi } from '@/axios'
import Dialog from '@/helpers/dialog'
import seetaPopover from '@/components/seeta-ui/seeta-popover.vue'
......@@ -47,13 +48,14 @@ export default class userInfo extends Vue {
}
toPersonal() {
const routeUrl = this.$router.resolve({ name: 'personal' })
window.open(routeUrl.href, '_blank')
// this.$router.push({ name: 'personal' })
// const routeUrl = this.$router.resolve({ name: 'personal' })
// window.open(routeUrl.href, '_blank')
this.$router.push({ name: 'personal' })
}
async logout() {
removeUser()
const res = await logoutApi()
this.$router.replace({ name: 'login' })
}
......
......@@ -30,13 +30,13 @@ VueRouter.prototype.push = function push(location) {
// 取消转圈圈
NProgress.configure({ showSpinner: false })
router.beforeEach((to, from, next) => {
// if ((!browserStorage.getItem('id') || !browserStorage.getItem('userId')) && to.path !== '/login' && to.path !== '/register') {
// notificationError('提示', 'token无效或过期')
// next({ name: 'login' })
// return
// }
// NProgress.start()
// store.commit('CHNAGE_BREADCRUMB', to.path)
if (!browserStorage.getItem('token') && to.path !== '/login' && to.path !== '/register') {
notificationError('提示', 'token无效或过期')
next({ name: 'login' })
return
}
NProgress.start()
store.commit('CHNAGE_BREADCRUMB', to.path)
next()
})
router.afterEach((to, from) => {
......
export default [
{
path: '/',
redirect: '/device'
redirect: '/login'
},
{
path: '/login',
......@@ -16,7 +16,7 @@ export default [
{
path: '/device',
name: 'device',
meta: { title: '设备列表', icon: 'icon-yingyongguanli' },
meta: { title: '设备列表', icon: 'icon-shebei' },
component: () => import('@layouts/basicLayout'),
children: [{
path: '/device',
......@@ -38,7 +38,7 @@ export default [
{
path: '/service',
name: 'service',
meta: { title: '服务列表', icon: 'icon-jiankongzhongxin' },
meta: { title: '服务列表', icon: 'icon-fuwu' },
component: () => import('@layouts/basicLayout'),
children: [{
path: '/service',
......@@ -50,31 +50,51 @@ export default [
{
path: '/params',
name: 'params',
meta: { title: '参数模板', icon: 'icon-shebeiguanli' },
meta: { title: '参数模板', icon: 'icon-canshumoban' },
component: () => import('@layouts/basicLayout'),
children: [{
path: '/params',
name: 'params',
meta: { title: '参数模板' },
component: () => import('@views/ParamsModel')
}, {
path: '/params/edit',
name: 'params',
meta: { title: '编辑' },
component: () => import('@views/ParamsModel/edit')
}, {
path: '/params/detail',
name: 'params',
meta: { title: '详情' },
component: () => import('@views/ParamsModel/detail')
}, {
path: '/params/add',
name: 'params',
meta: { title: '添加' },
component: () => import('@views/ParamsModel/add')
}]
},
{
path: '/data',
name: 'data',
meta: { title: '数据列表', icon: 'icon-OTA' },
meta: { title: '数据列表', icon: 'icon-shuju' },
component: () => import('@layouts/basicLayout'),
children: [{
path: '/data',
name: 'data',
meta: { title: '数据列表' },
component: () => import('@views/DataList')
}, {
path: '/data/edit',
name: 'data',
meta: { title: '编辑' },
component: () => import('@views/DataList/edit')
}]
},
{
path: '/apply',
name: 'apply',
meta: { title: '应用中心', icon: 'icon-wendanggongju' },
meta: { title: '应用中心', icon: 'icon-yingyong' },
component: () => import('@layouts/basicLayout'),
children: [{
path: '/apply',
......@@ -86,7 +106,7 @@ export default [
{
path: '/setting',
name: 'setting',
meta: { title: '设置中心', icon: 'icon-wendanggongju' },
meta: { title: '设置中心', icon: 'icon-shebeiguanli' },
component: () => import('@layouts/basicLayout'),
children: [{
path: '/setting',
......@@ -98,7 +118,7 @@ export default [
{
path: '/account',
name: 'account',
meta: { title: '账户中心', icon: 'icon-wendanggongju' },
meta: { title: '账户中心', icon: 'icon-qianbao1' },
component: () => import('@layouts/basicLayout'),
children: [{
path: '/account',
......@@ -107,6 +127,18 @@ export default [
component: () => import('@views/Account')
}]
},
{
path: '/personal',
name: 'personal',
meta: { title: '个人中心', icon: 'icon-wendanggongju', hidden: true },
component: () => import('@layouts/basicLayout'),
children: [{
path: '/personal',
name: 'personal',
meta: { title: '个人中心' },
component: () => import('@views/PersonInfo')
}]
},
// 匹配不到,展示404
{
path: '/*',
......
......@@ -3,7 +3,9 @@ import browserStorage from '@/services/local-storage'
const state = () => ({
lang: browserStorage.getItem('lang') || 'zh-CN',
routerStatus: 0,
currentProduct: {}
currentProduct: {},
currentDevice: '',
currentService: {},
})
const mutations = {
......@@ -16,6 +18,12 @@ const mutations = {
},
changeCurrentProduct(state, item) {
state.currentProduct = JSON.parse(JSON.stringify(item))
},
changeCurrentDevice(state, item) {
state.currentDevice = item
},
changeCurrentService(state, item) {
state.currentService = JSON.parse(JSON.stringify(item))
}
}
......@@ -26,7 +34,9 @@ const actions = {
const getters = {
lang: state => state.lang,
routerStatus: state => state.routerStatus,
currentProduct: state => state.currentProduct
currentProduct: state => state.currentProduct,
currentDevice: state => state.currentDevice,
currentService: state => state.currentService
}
export default {
......
@font-face {
font-family: "iconfont"; /* Project id 2598158 */
src: url('iconfont.woff2?t=1623308852405') format('woff2'),
url('iconfont.woff?t=1623308852405') format('woff'),
url('iconfont.ttf?t=1623308852405') format('truetype');
font-family: "iconfont"; /* Project id 2741238 */
src: url('iconfont.woff2?t=1628763203270') format('woff2'),
url('iconfont.woff?t=1628763203270') format('woff'),
url('iconfont.ttf?t=1628763203270') format('truetype');
}
.iconfont {
......@@ -13,64 +13,84 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-tupianzhanshi:before {
content: "\e786";
.icon-shuju:before {
content: "\e60c";
}
.icon-liebiaozhanshi:before {
content: "\e78d";
.icon-fuwu:before {
content: "\e6c7";
}
.icon-duihao:before {
content: "\e77f";
.icon-shebei:before {
content: "\e874";
}
.icon-guanbi:before {
content: "\e780";
.icon-canshumoban:before {
content: "\e78e";
}
.icon-shanchu:before {
content: "\e781";
.icon-yingyong:before {
content: "\e693";
}
.icon-shangchuan:before {
content: "\e782";
.icon-qianbao1:before {
content: "\e621";
}
.icon-fuzhi:before {
content: "\e783";
.icon-guanyuwomen:before {
content: "\e76e";
}
.icon-fanhui:before {
content: "\e784";
.icon-caidanzhankai:before {
content: "\e76f";
}
.icon-right1:before {
content: "\e785";
.icon-chanpinwendang:before {
content: "\e770";
}
.icon-xiazai:before {
content: "\e787";
.icon-caidanshouqi:before {
content: "\e771";
}
.icon-fujian:before {
content: "\e788";
.icon-yingyongguanli:before {
content: "\e772";
}
.icon-riqi:before {
content: "\e789";
.icon-wendanggongju:before {
content: "\e773";
}
.icon-sousuo:before {
content: "\e78a";
.icon-OTA:before {
content: "\e774";
}
.icon-left:before {
content: "\e78b";
.icon-jiankongzhongxin:before {
content: "\e775";
}
.icon-tianjia:before {
content: "\e78c";
.icon-shebeiguanli:before {
content: "\e776";
}
.icon-mianxingxiala:before {
content: "\e777";
}
.icon-mianxingshangla:before {
content: "\e778";
}
.icon-unfold:before {
content: "\e779";
}
.icon-right:before {
content: "\e77a";
}
.icon-fold:before {
content: "\e77b";
}
.icon-jinggao:before {
......@@ -85,59 +105,63 @@
content: "\e77e";
}
.icon-mianxingxiala:before {
content: "\e777";
.icon-duihao:before {
content: "\e77f";
}
.icon-mianxingshangla:before {
content: "\e778";
.icon-guanbi:before {
content: "\e780";
}
.icon-unfold:before {
content: "\e779";
.icon-shanchu:before {
content: "\e781";
}
.icon-right:before {
content: "\e77a";
.icon-shangchuan:before {
content: "\e782";
}
.icon-fold:before {
content: "\e77b";
.icon-fuzhi:before {
content: "\e783";
}
.icon-guanyuwomen:before {
content: "\e76e";
.icon-fanhui:before {
content: "\e784";
}
.icon-caidanzhankai:before {
content: "\e76f";
.icon-right1:before {
content: "\e785";
}
.icon-chanpinwendang:before {
content: "\e770";
.icon-xiazai:before {
content: "\e787";
}
.icon-caidanshouqi:before {
content: "\e771";
.icon-fujian:before {
content: "\e788";
}
.icon-yingyongguanli:before {
content: "\e772";
.icon-riqi:before {
content: "\e789";
}
.icon-wendanggongju:before {
content: "\e773";
.icon-sousuo:before {
content: "\e78a";
}
.icon-OTA:before {
content: "\e774";
.icon-left:before {
content: "\e78b";
}
.icon-jiankongzhongxin:before {
content: "\e775";
.icon-tianjia:before {
content: "\e78c";
}
.icon-shebeiguanli:before {
content: "\e776";
.icon-tupianzhanshi:before {
content: "\e786";
}
.icon-liebiaozhanshi:before {
content: "\e78d";
}
{
"id": "2598158",
"name": "SeetaAIOT",
"id": "2741238",
"name": "设备管理后台",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "22178639",
"name": "图片展示",
"font_class": "tupianzhanshi",
"unicode": "e786",
"unicode_decimal": 59270
"icon_id": "18005150",
"name": "数据 (4)",
"font_class": "shuju",
"unicode": "e60c",
"unicode_decimal": 58892
},
{
"icon_id": "22178640",
"name": "列表展示",
"font_class": "liebiaozhanshi",
"unicode": "e78d",
"unicode_decimal": 59277
"icon_id": "3242865",
"name": "列表",
"font_class": "fuwu",
"unicode": "e6c7",
"unicode_decimal": 59079
},
{
"icon_id": "11564596",
"name": "列表",
"font_class": "shebei",
"unicode": "e874",
"unicode_decimal": 59508
},
{
"icon_id": "23505565",
"name": "参数模板",
"font_class": "canshumoban",
"unicode": "e78e",
"unicode_decimal": 59278
},
{
"icon_id": "13415761",
"name": "应用中心",
"font_class": "yingyong",
"unicode": "e693",
"unicode_decimal": 59027
},
{
"icon_id": "16069276",
"name": "钱包",
"font_class": "qianbao1",
"unicode": "e621",
"unicode_decimal": 58913
},
{
"icon_id": "22095875",
"name": "关于我们",
"font_class": "guanyuwomen",
"unicode": "e76e",
"unicode_decimal": 59246
},
{
"icon_id": "22095876",
"name": "菜单展开",
"font_class": "caidanzhankai",
"unicode": "e76f",
"unicode_decimal": 59247
},
{
"icon_id": "22095877",
"name": "产品文档",
"font_class": "chanpinwendang",
"unicode": "e770",
"unicode_decimal": 59248
},
{
"icon_id": "22095878",
"name": "菜单收起",
"font_class": "caidanshouqi",
"unicode": "e771",
"unicode_decimal": 59249
},
{
"icon_id": "22095879",
"name": "应用管理",
"font_class": "yingyongguanli",
"unicode": "e772",
"unicode_decimal": 59250
},
{
"icon_id": "22095880",
"name": "文档&工具",
"font_class": "wendanggongju",
"unicode": "e773",
"unicode_decimal": 59251
},
{
"icon_id": "22095881",
"name": "OTA",
"font_class": "OTA",
"unicode": "e774",
"unicode_decimal": 59252
},
{
"icon_id": "22095882",
"name": "监控中心",
"font_class": "jiankongzhongxin",
"unicode": "e775",
"unicode_decimal": 59253
},
{
"icon_id": "22095883",
"name": "设备管理",
"font_class": "shebeiguanli",
"unicode": "e776",
"unicode_decimal": 59254
},
{
"icon_id": "22095902",
"name": "面性下拉",
"font_class": "mianxingxiala",
"unicode": "e777",
"unicode_decimal": 59255
},
{
"icon_id": "22095903",
"name": "面性上拉",
"font_class": "mianxingshangla",
"unicode": "e778",
"unicode_decimal": 59256
},
{
"icon_id": "22095904",
"name": "unfold",
"font_class": "unfold",
"unicode": "e779",
"unicode_decimal": 59257
},
{
"icon_id": "22095905",
"name": "right",
"font_class": "right",
"unicode": "e77a",
"unicode_decimal": 59258
},
{
"icon_id": "22095906",
"name": "fold",
"font_class": "fold",
"unicode": "e77b",
"unicode_decimal": 59259
},
{
"icon_id": "22096387",
"name": "警告",
"font_class": "jinggao",
"unicode": "e77c",
"unicode_decimal": 59260
},
{
"icon_id": "22096388",
"name": "错误",
"font_class": "cuowu",
"unicode": "e77d",
"unicode_decimal": 59261
},
{
"icon_id": "22096389",
"name": "正确",
"font_class": "zhengque",
"unicode": "e77e",
"unicode_decimal": 59262
},
{
"icon_id": "22096432",
......@@ -111,123 +258,18 @@
"unicode_decimal": 59276
},
{
"icon_id": "22096387",
"name": "警告",
"font_class": "jinggao",
"unicode": "e77c",
"unicode_decimal": 59260
},
{
"icon_id": "22096388",
"name": "错误",
"font_class": "cuowu",
"unicode": "e77d",
"unicode_decimal": 59261
},
{
"icon_id": "22096389",
"name": "正确",
"font_class": "zhengque",
"unicode": "e77e",
"unicode_decimal": 59262
},
{
"icon_id": "22095902",
"name": "面性下拉",
"font_class": "mianxingxiala",
"unicode": "e777",
"unicode_decimal": 59255
},
{
"icon_id": "22095903",
"name": "面性上拉",
"font_class": "mianxingshangla",
"unicode": "e778",
"unicode_decimal": 59256
},
{
"icon_id": "22095904",
"name": "unfold",
"font_class": "unfold",
"unicode": "e779",
"unicode_decimal": 59257
},
{
"icon_id": "22095905",
"name": "right",
"font_class": "right",
"unicode": "e77a",
"unicode_decimal": 59258
},
{
"icon_id": "22095906",
"name": "fold",
"font_class": "fold",
"unicode": "e77b",
"unicode_decimal": 59259
},
{
"icon_id": "22095875",
"name": "关于我们",
"font_class": "guanyuwomen",
"unicode": "e76e",
"unicode_decimal": 59246
},
{
"icon_id": "22095876",
"name": "菜单展开",
"font_class": "caidanzhankai",
"unicode": "e76f",
"unicode_decimal": 59247
},
{
"icon_id": "22095877",
"name": "产品文档",
"font_class": "chanpinwendang",
"unicode": "e770",
"unicode_decimal": 59248
},
{
"icon_id": "22095878",
"name": "菜单收起",
"font_class": "caidanshouqi",
"unicode": "e771",
"unicode_decimal": 59249
},
{
"icon_id": "22095879",
"name": "应用管理",
"font_class": "yingyongguanli",
"unicode": "e772",
"unicode_decimal": 59250
},
{
"icon_id": "22095880",
"name": "文档&工具",
"font_class": "wendanggongju",
"unicode": "e773",
"unicode_decimal": 59251
},
{
"icon_id": "22095881",
"name": "OTA",
"font_class": "OTA",
"unicode": "e774",
"unicode_decimal": 59252
},
{
"icon_id": "22095882",
"name": "监控中心",
"font_class": "jiankongzhongxin",
"unicode": "e775",
"unicode_decimal": 59253
"icon_id": "22178639",
"name": "图片展示",
"font_class": "tupianzhanshi",
"unicode": "e786",
"unicode_decimal": 59270
},
{
"icon_id": "22095883",
"name": "设备管理",
"font_class": "shebeiguanli",
"unicode": "e776",
"unicode_decimal": 59254
"icon_id": "22178640",
"name": "列表展示",
"font_class": "liebiaozhanshi",
"unicode": "e78d",
"unicode_decimal": 59277
}
]
}
......@@ -83,3 +83,12 @@ export function copyText(item) {
})
document.body.removeChild(transfer)
}
export function calculateByte(base64) {
if (base64.indexOf('base64,') !== -1) {
base64 = base64.substring(base64.indexOf('base64,') + 7)
}
if (base64.indexOf('=') !== -1) {
base64 = base64.substring(0, base64.indexOf('='))
}
return base64.length * 0.75
}
export const fileToBase64 = file => {
return new Promise((resolve, reject) => {
try {
const read = new FileReader()
read.onload = function(e) {
resolve(e.target.result)
}
read.readAsDataURL(file)
} catch (err) {
reject(err)
}
})
}
export const base64ToFile = (base64, fileName) => {
const arr = base64.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
const blob = new Blob([u8arr], { type: mime })
return new File([blob], fileName, { type: mime })
}
export const stringToBase64 = str => {
// 对字符串进行编码
const encode = encodeURI(str)
// 对编码的字符串转化base64
const base64 = btoa(encode)
return base64
}
export const base64ToString = base64 => {
// 对base64转编码
const decode = atob(base64)
const temp = decode.replace(/%/g, '%25')
// 编码转字符串
const str = decodeURI(temp)
return str
}
export const isASCII = str => {
return /^[\x00-\x7F]*$/.test(str)
}
<template>
<div>
<div class="data-list-common flex column main-content flex-1">
<div class="header">
<span class="title">{{'账户中心'}}</span>
</div>
<div class="page-nav">
<div class="search-fields">
<span class="fields">用户名:</span>
<st-input width="240px" class="align contents" id="align-input" v-model="userName"></st-input>
<!-- <input type="text" id="raw-input" autocomplete="off" class="align contents" :style="{borderColor: borderColor}" placeholder="请输入" @blur="getData" v-model.trim="deviceName" @keyup.enter="getData" @input="checkSearchContent"> -->
<span class="fields">用户角色:</span>
<st-select
v-model="userRole"
:options="userRoleOptions"
size="small"
style="width: 240px"
class="contents"
clearable
@change="getData"
>
</st-select>
<span class="fields">创建日期:</span>
<el-date-picker
v-model="created_at"
type="daterange"
@change="getData"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</div>
</div>
<div class="page-content">
<div class="content-header">
<st-button type="primary" @click="handleCreate">
<i class="iconfont icon-tianjia"></i><span class="text">{{'增加用户'}}</span>
</st-button>
</div>
<div class="table-list">
<div class="list-content">
<st-table
ref="vTable"
:options="definitions"
:data="{
list: tokenList,
total: total,
}"
:outerLoading="loadingStatus">
<div slot="operate" slot-scope="row">
<span class="operate" @click="handleEdit(row)">编辑</span>
<span class="operate operate-delete" @click="handleDelete(row)">删除</span>
</div>
</st-table>
</div>
</div>
</div>
<st-dialog
:show.sync="showDialog"
class="update-dialog"
@dismiss="cancelSubmit"
>
<div slot="header" class="popup-header">{{submitType === 'create' ? '增加用户' : '编辑用户'}}</div>
<div slot="body" class="popup-body">
<st-form
label-width="90px"
ref="form"
:model="form"
:rules="rules">
<st-form-item
:label="'账号:'">
<st-input v-model="form.username" :disabled="submitType === 'edit'"></st-input>
</st-form-item>
<st-form-item
:label="'角色:'">
<st-input v-model="form.role"></st-input>
</st-form-item>
<st-form-item
:label="'邮箱:'">
<st-input v-model="form.email"></st-input>
</st-form-item>
<st-form-item v-if="submitType === 'create'"
:label="'初始密码:'">
<st-input v-model="form.passwd" type="password"></st-input>
</st-form-item>
<st-form-item v-if="submitType === 'create'"
:label="'重复密码:'">
<st-input v-model="form.confirmPwd" type="password"></st-input>
</st-form-item>
<st-form-item v-if="submitType === 'edit'"
:label="'原密码:'">
<st-input v-model="form.passwordd" type="password"></st-input>
</st-form-item>
<st-form-item v-if="submitType === 'edit'"
:label="'新密码:'">
<st-input v-model="form.new_passwordd" type="password"></st-input>
</st-form-item>
</st-form>
</div>
<div slot="footer" class="popup-footer flex right">
<st-button @click="cancelSubmit">{{$t('public.cancel')}}</st-button>
<st-button type="primary" @click="submit">{{'确定'}}</st-button>
</div>
</st-dialog>
</div>
</template>
<script>
import { getUsers, createUser, deleteUser, editUser } from '@/axios'
import browserStorage from '@/services/local-storage'
import { rTimeMin } from '@/utils/system.js'
import Dialog from '@/helpers/dialog'
export default {
data() {
const validatePasswordConfirmation = (rule, value, callback) => {
if (value === '') {
callback(new Error('请确认密码'))
} else if (value !== this.form.passwd && value !== this.form.ConfirmPwd) {
callback(new Error('两次密码输入不一致'))
} else {
callback()
}
}
return {
// 查询字段
userName: '',
userRole: '',
created_at: [],
showDialog: false,
submitType: 'create',
form: {},
userRoleOptions: [],
currentPage: 1,
currentSize: 10,
loadingStatus: false,
definitions: [
{
label: '账号',
render: 'username'
},
{
label: '角色',
render: 'role'
},
{
label: '邮箱',
render: 'email'
},
{
label: '创建人',
render: 'creater'
},
{
label: '创建日期',
render: 'create_date'
},
{
label: '备注',
render: 'desc'
},
{
label: '操作',
type: 'slot',
width: '150px',
slotName: 'operate'
},
],
tokenList: [],
total: 0,
rules: { // 表单校验
passwordConfirmation: [
{ required: true, message: '请确认密码', trigger: 'blur' },
{ validator: validatePasswordConfirmation, trigger: 'blur' }
]
},
}
},
watch: {
'$route.query': {
handler(val) {
if (JSON.stringify(val) === '{}') return
this.currentPage = Number(val.page_index) || 1
this.currentSize = Number(val.page_size) || 10
this.getData()
},
immediate: true,
deep: true
}
},
mounted() {
// this.getData()
},
methods: {
async submit() {
this.$refs.form.validate(async valid => {
if (valid) {
let res = ''
let submitForm = ''
switch (this.submitType) {
case 'create':
submitForm = JSON.parse(JSON.stringify(this.form))
delete submitForm.email
delete submitForm.confirmPwd
submitForm.creater = 'admin'
res = await createUser(submitForm)
if (res && res.data && res.data.code === 0) {
this.getData()
}
this.showDialog = false
break
case 'edit':
submitForm = JSON.parse(JSON.stringify(this.form))
delete submitForm.email
delete submitForm.confirmPwd
submitForm.creater = 'admin'
res = await editUser(submitForm)
if (res && res.data && res.data.code === 0) {
this.getData()
}
this.showDialog = false
break
default:
this.showDialog = false
break
}
}
})
},
cancelSubmit() {
this.showDialog = false
},
handleCreate() {
this.submitType = 'create'
this.showDialog = true
this.form = {}
},
handleEdit(row) {
this.submitType = 'edit'
this.showDialog = true
this.form = JSON.parse(JSON.stringify(row))
},
async handleDelete(row) {
const confirmDelete = await Dialog.confirm('提示', { message: '是否删除此账号?' })
if (!confirmDelete) return
const res = await deleteUser({ username: row.username })
if (res) {
Toast.success('操作成功')
this.getData()
}
},
async getData() {
this.loadingStatus = true
const res = await getUsers({ pages: this.currentPage - 1, pagesize: this.currentSize })
if (res && res.data && res.data.code === 0) {
this.tokenList = res.data.data.users
this.total = res.data.data.total
}
this.loadingStatus = false
}
}
},
}
</script>
<style lang="sass" scoped>
.popup-body
::v-deep.el-form-item
height: 32px
line-height: 32px
::v-deep.el-form-item__label
height: 32px!important
line-height: 32px!important
::v-deep.el-form-item__content
height: 32px!important
line-height: 32px!important
.search-fields
::v-deep input
&::placeholder
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
color:#999999
.el-date-editor
width: 240px
height: 32px
float: right
::v-deep .el-range__icon
line-height: 24px
::v-deep .el-range-separator
width: 12%
line-height: 24px
</style>
<template>
<div>
<div class="data-list-common flex column main-content flex-1">
<div class="header">
<span class="title">{{'应用中心'}}</span>
</div>
<div class="page-content">
<div class="content-header">
<st-button type="primary" id="btn" @click="showDialog = true">
<i class="iconfont icon-tianjia"></i><span class="text">{{'申请应用'}}</span></st-button>
</div>
<div class="table-list">
<div class="list-content">
<st-table
ref="vTable"
:options="definitions"
:data="{
list: tokenList,
total: total,
}"
:outerLoading="loadingStatus">
<div slot="secret" slot-scope="row">
<span v-if="showSecret === row.appid" class="secret-box">{{row.secret}}</span>
<span v-else class="secret-box">********</span>
<i class="el-icon-view eye-btn" @mousedown="showSecret = row.appid" @mouseup="showSecret = ''"></i>
</div>
<div slot="operate" slot-scope="row">
<span class="operate" v-if="row.ismainapp === 0" @click="setHostApp(row)">设置为主应用</span>
<span class="operate" v-else @click="cancelHostApp(row)">取消设置为主应用</span>
<span class="operate operate-delete" @click="handleDelete(row)">删除</span>
</div>
</st-table>
</div>
</div>
</div>
<st-dialog
:show.sync="showDialog"
class="update-dialog"
@dismiss="cancelSubmit"
>
<div slot="header" class="popup-header">{{'申请应用'}}</div>
<div slot="body" class="popup-body">
<st-form
label-width="90px"
ref="form"
:model="form">
<st-form-item :label="'appId:'"><st-input v-model="form.appid"></st-input></st-form-item>
<st-form-item :label="'secret:'"><st-input v-model="form.secret"></st-input></st-form-item>
<st-form-item
:label="'说明:'">
<st-input
type="textarea"
placeholder="请输入应用描述"
v-model="form.description"
maxlength="100"
show-word-limit
>
</st-input>
</st-form-item>
</st-form>
</div>
<div slot="footer" class="popup-footer flex right">
<st-button @click="cancelSubmit">{{$t('public.cancel')}}</st-button>
<st-button type="primary" @click="submit">{{'确定'}}</st-button>
</div>
</st-dialog>
</div>
</template>
<script>
import { getApp, deleteApp, setApp, addApp } from '@/axios'
import Dialog from '@/helpers/dialog'
import browserStorage from '@/services/local-storage'
export default {
data() {
return {
showSecret: '',
loadingStatus: false,
form: {},
showDialog: false,
definitions: [
{
label: 'APPID',
render: 'appid'
},
{
label: 'Secret',
type: 'slot',
slotName: 'secret'
},
{
label: '创建时间',
render: 'create_date'
},
{
label: '设备数量',
render: 'devices'
},
{
label: '说明',
render: 'description'
},
{
label: '操作',
type: 'slot',
width: '150px',
slotName: 'operate'
},
],
tokenList: [],
total: 0,
currentPage: 1,
currentSize: 10
}
},
watch: {
'$route.query': {
handler(val) {
if (JSON.stringify(val) === '{}') return
this.currentPage = Number(val.page_index) || 1
this.currentSize = Number(val.page_size) || 10
this.getData()
},
immediate: true,
deep: true
}
},
mounted() {
// this.getData()
},
methods: {
async getData() {
this.loadingStatus = true
const res = await getApp({ pages: this.currentPage - 1, pagesize: this.currentSize })
if (res && res.data && res.data.code === 0) {
this.tokenList = res.data.data.apps
this.total = res.data.data.total
}
this.loadingStatus = false
},
cancelSubmit() {
this.form = {}
this.showDialog = false
},
async submit() {
const userInfo = JSON.parse(browserStorage.getItem('user'))
const res = await addApp({ ...this.form, creater: userInfo.creater })
if (res && res.data && res.data.code === 0) {
Toast.success('操作成功')
this.getData()
}
this.showDialog = false
this.form = {}
},
async handleDelete(row) {
const confirmDelete = await Dialog.confirm('提示', { message: '是否删除此应用?' })
if (!confirmDelete) return
const res = await deleteApp({ appid: row.appid })
if (res && res.data && res.data.code === 0) {
Toast.success('操作成功')
this.getData()
}
},
async setHostApp(row) {
const res = await setApp({ appid: row.appid, mainapp: 1, username: 'test' })
if (res && res.data && res.data.code === 0) {
Toast.success('操作成功')
this.getData()
}
},
async cancelHostApp(row) {
const res = await setApp({ appid: row.appid, mainapp: 0, username: 'test' })
if (res && res.data && res.data.code === 0) {
Toast.success('操作成功')
this.getData()
}
}
}
}
</script>
<style lang="sass" scoped>
.update-dialog
::v-deep input
&::placeholder
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
color:#999999
::v-deep.el-input__inner, ::v-deep.el-textarea, ::v-deep.el-textarea__inner
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
color: #333
&::placeholder
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
color:#999999
.eye-btn
margin-left: 10px
color: #409EFF
.secret-box
display: inline-block
width: 60px
</style>
<template>
<div>
<div class="data-list-common flex column main-content flex-1">
<div class="header">
<span class="title">{{'数据列表'}}</span>
</div>
<div class="page-content">
<div class="content-header">
<st-button type="primary" id="btn" @click="showDialog = true">
<i class="iconfont icon-tianjia"></i><span class="text">{{'创建数据表'}}</span></st-button>
<div class="search">
<input type="text" class="search-input" placeholder="请输入搜索内容" v-model="inputVal">
<i class="el-input__icon el-icon-search"></i>
</div>
</div>
<div class="table-list">
<div class="list-content">
<st-table
ref="vTable"
:options="definitions"
:data="{
list: tokenList,
total: total,
}"
:outerLoading="loadingStatus">
<div slot="operate" slot-scope="row">
<span class="operate" @click="$router.push({ path: '/data/edit', query: { name: row.name, columns: row.columns } })">编辑</span>
<span class="operate operate-delete" @click="handleDelete(row)">删除</span>
</div>
</st-table>
</div>
</div>
</div>
<st-dialog
:show.sync="showDialog"
class="update-dialog"
@dismiss="cancelSubmit"
>
<div slot="header" class="popup-header">{{'创建数据表'}}</div>
<div slot="body" class="popup-body">
<st-form
label-width="90px"
ref="form"
:model="form">
<st-form-item
:label="'名称:'">
<st-input v-model="form.name"></st-input>
</st-form-item>
<st-form-item
:label="'列数:'">
<st-input v-model="form.columns"></st-input>
</st-form-item>
</st-form>
</div>
<div slot="footer" class="popup-footer flex right">
<st-button @click="cancelSubmit">{{$t('public.cancel')}}</st-button>
<st-button type="primary" @click="submit">{{'确定'}}</st-button>
</div>
</st-dialog>
</div>
</template>
<script>
import { createTable, getTable, deleteTable } from '@/axios'
import Dialog from '@/helpers/dialog'
export default {
data() {
return {
inputVal: '',
showDialog: false,
loadingStatus: false,
form: {},
definitions: [
{
label: '序号',
render: 'order'
},
{
label: '名称',
render: 'name'
},
{
label: '列数',
render: 'columns'
},
{
label: '行数',
render: 'rows'
},
{
label: '容量',
render: 'storage'
},
{
label: '创建时间',
render: 'create_date'
},
{
label: '修改时间',
render: 'update_date'
},
{
label: '操作',
type: 'slot',
width: '150px',
slotName: 'operate'
},
],
tokenList: [],
currentPage: 1,
currentSize: 10,
total: 0
}
},
watch: {
'$route.query': {
handler(val) {
if (JSON.stringify(val) === '{}') return
this.currentPage = Number(val.page_index) || 1
this.currentSize = Number(val.page_size) || 10
this.getData()
},
immediate: true,
deep: true
}
},
mounted() {
// this.getData()
},
methods: {
async getData() {
this.loadingStatus = true
const res = await getTable({ pages: this.currentPage - 1, pagesize: this.currentSize })
if (res && res.data && res.data.code === 0) {
this.tokenList = res.data.data.tables.map((item, index) => {
item.order = index + 1 + (this.currentPage - 1) * this.currentSize
return item
})
this.total = res.data.data.total
}
this.loadingStatus = false
},
cancelSubmit() {
this.form = {}
this.showDialog = false
},
async submit() {
const res = await createTable(this.form)
if (res && res.data && res.data.code === 0) {
Toast.success('操作成功')
this.getData()
}
this.showDialog = false
this.form = {}
},
async handleDelete(row) {
const confirmDelete = await Dialog.confirm('提示', { message: '是否删除此数据表?' })
if (!confirmDelete) return
const res = await deleteTable({ name: row.name })
if (res) {
Toast.success('操作成功')
this.getData()
}
},
}
}
</script>
<style lang="sass" scoped>
.page-content
#btn
width: 116px!important
text-align: left
.search
width: 240px
height: 32px
position: relative
float: right
.search-input
width: 100%
padding-right: 35px
.el-icon-search
line-height: 32px
position: absolute
right: 0
font-size: 18px
color: #CCC
cursor: pointer
width: 44px
height: 32px
text-align: center
::v-deep input
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
color:#333
height: 32px
line-height: 32px
&::placeholder
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
color:#999999
</style>
......@@ -17,17 +17,20 @@
:pagination="false"
>
<div slot='codeSlot' slot-scope="row">
<span>{{ simplify(row.code, 3) }}</span>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.code)"></i>
<span>{{ simplify(row.deviceid, 3) }}</span>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.deviceid)"></i>
</div>
<div slot='status' slot-scope="row">
<span class="circleStatus" :style="{color: getStatusColor(row.status)}">{{ getStatusText(row.status) }}</span>
<div slot='status' slot-scope="row" class="status">
<span class="circleStatus" :style="{color: getStatusColor(row.state)}">{{ getStatusText(row.state) }}</span>
</div>
<div slot='ipSlot' slot-scope="row" class="ipSlot">
<span >{{ simplify(row.ip, 14) }}</span>
</div>
<div slot='structureSlot' slot-scope="row">
<span>{{ simplify(row.structure, 6) }}</span>
</div>
<div slot='registerTimeSlot' slot-scope="row">
<span>{{ rTimeMin(row.registerTime) }}</span>
<span>{{ (row.register_date) }}</span>
</div>
<div slot='tagsSlot' slot-scope="row">
<div class="tagsItem">
......@@ -50,15 +53,14 @@
<el-button v-else class="button-new-tag" size="small" @click="showInput">+ 添加标签</el-button>
</div>
</el-tooltip>
<!-- <el-tag v-for="(item, index) in row.tags" :key="index" :disable-transitions="false" @close="handleClose(row, item)" closable class="label label-primary table-label">{{ simplify(item, 7) }}</el-tag> -->
</div>
</div>
<div slot='servicesSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.services ? row.services.join('、') : ''" placement="top">
<el-tooltip class="item" effect="dark" :content="getServiceName(row.services)" placement="top">
<!-- 必须要套一层 -->
<div>
<template v-for="(item, index) in row.services">
<span v-if="[0, 2].indexOf(index) !== -1" :key="index" class="service-item">{{ simplify(item, 4) }}</span>
<span v-if="[0, 1, 2].indexOf(index) !== -1" :key="index" class="service-item">{{ simplify(item.name, 4) }}</span>
</template>
<span v-if="(row.services && row.services.length) > 10">共: {{(row.services && row.services.length) ? row.services.length : 0}} 条</span>
</div>
......@@ -77,22 +79,28 @@
:options="serviceDefinitions"
:data="{
list: serviceTokenList,
total: servicTtotal,
total: servicTotal,
}"
:outerLoading="serviceLoadingStatus"
:pagination="false"
>
<div slot='nameSlot' slot-scope="row">
<span>{{ simplify(row.name, 8) }}</span>
</div>
<div slot='portSlot' slot-scope="row">
<span>{{ simplify(row.port, 6) }}</span>
</div>
<div slot='codeSlot' slot-scope="row">
<span>{{ simplify(row.code, 3) }}</span>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.code)"></i>
<span>{{ simplify(row.potuid, 3) }}</span>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.potuid)"></i>
</div>
<div slot='descSlot' slot-scope="row">
<span>{{ simplify(row.desc, 10) }}</span>
<span>{{ simplify(row.description, 10) }}</span>
</div>
<div slot='operate' slot-scope="row">
<span class="operate-text" @click="seeServiceParams(row.id)">{{ '查看参数' }}</span>
<span class="operate-text" @click="sendReq(row.id)">{{ '发送请求' }}</span>
<span class="operate-text" @click="sendOrder(row.id)">{{ '发送指令' }}</span>
<span class="operate-text" @click="seeServiceParams(row.potuid)">{{ '查看参数' }}</span>
<span class="operate-text" @click="sendReq(row.potuid)">{{ '发送请求' }}</span>
<span class="operate-text" @click="sendOrder(row.potuid)">{{ '发送指令' }}</span>
</div>
</st-table>
</div>
......@@ -105,6 +113,7 @@ import browserStorage from '@/services/local-storage'
import Dialog from '@/helpers/dialog'
import validate from '@/components/seeta-ui/seeta-form/validator'
import { rTimeMin, copyText } from '@/utils/system.js'
import { getServiceDevice, deleteTag, addTag } from '@/axios'
export default {
data() {
return {
......@@ -120,17 +129,12 @@ export default {
time2: '',
// 表格数据
tokenList: [
{ tags: ['标签1', '标签2'], name: '小1', code: '110123124325', child: { service: '11', code: '123', port: '1234', desc: '这是服务1' } },
],
inputVisible: false,
inputValue: '',
serviceTokenList: [
{ service: '11', code: '123', port: '1234', desc: '这是服务1' },
{ service: '12', code: '123', port: '1234', desc: '这是服务2' },
{ service: '13', code: '123', port: '1234', desc: '这是服务3' },
],
total: 1,
servicTtotal: 3,
// 编辑和添加表单
form: {
},
......@@ -138,11 +142,11 @@ export default {
{
label: '服务',
type: 'slot',
slotName: 'childServiceSlot',
slotName: 'nameSlot',
}, {
label: '编号',
type: 'slot',
slotName: 'childCodeSlot'
slotName: 'codeSlot'
}, {
label: '端口',
type: 'slot',
......@@ -154,7 +158,7 @@ export default {
}, {
label: '操作',
type: 'slot',
slotName: 'childOperate',
slotName: 'operate',
},
],
definitions: [
......@@ -167,13 +171,13 @@ export default {
type: 'slot',
slotName: 'status',
statusColor: item => {
switch (item.status) {
case 'online':
switch (item.state) {
case 1:
return '#67C23A'
case 'offline':
return '#999999'
default:
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
}, {
......@@ -186,7 +190,8 @@ export default {
slotName: 'systemSlot'
}, {
label: 'IP',
render: 'IP'
type: 'slot',
slotName: 'ipSlot'
}, {
label: '注册时间',
type: 'slot',
......@@ -212,19 +217,26 @@ export default {
},
tagList: [{ label: '标签一', value: 0 }, { label: '标签二', value: 1 }, { label: '标签三', value: 2 }, { label: '标签四', value: 3 }],
serviceList: [{ label: '标签一', value: 0 }, { label: '标签二', value: 1 }, { label: '标签三', value: 2 }, { label: '标签四', value: 3 }],
currentDeviceId: '',
servicTotal: 0
}
},
computed: {
getServiceName() {
return item => {
return item.map(t1 => t1.name).join()
}
},
// 获取设备状态颜色
getStatusColor() {
return item => {
switch (item) {
case 'online':
case 1:
return '#67C23A'
case 'offline':
return '#999999'
default:
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
},
......@@ -232,12 +244,12 @@ export default {
getStatusText() {
return item => {
switch (item) {
case 'online':
case 1:
return '在线'
case 'offline':
return '离线'
default:
case 2:
return '异常'
default:
return '离线'
}
}
},
......@@ -260,8 +272,9 @@ export default {
},
sendOrder(id) {
},
handleClose(row, tag) {
row.tags.splice(row.tags.indexOf(tag), 1)
async handleClose(row, tag) {
const res = await deleteTag({ name: tag })
this.getData()
},
showInput() {
this.inputVisible = true
......@@ -269,10 +282,14 @@ export default {
this.$refs.saveTagInput.$refs.input.focus()
})
},
handleInputConfirm(row) {
async handleInputConfirm(row) {
const inputValue = this.inputValue
if (inputValue) {
row.tags.push(inputValue)
const res = await addTag({
id: row.id,
tags: [inputValue]
})
this.getData()
}
this.inputVisible = false
this.inputValue = ''
......@@ -300,6 +317,20 @@ export default {
detail(id) {
},
delete(id) {
},
async getData() {
const res = await getServiceDevice({ deviceid: this.currentDeviceId })
if (res && res.data && res.data.device) {
this.tokenList = [JSON.parse(JSON.stringify(res.data.device))]
this.serviceTokenList = JSON.parse(JSON.stringify(res.data.device.services))
this.total = 1
this.servicTotal = res.data.device.services.length
} else {
this.tokenList = []
this.total = 0
this.serviceTokenList = []
this.servicTotal = 0
}
}
},
watch: {
......@@ -311,6 +342,11 @@ export default {
}
},
mounted() {
if (this.$store.getters.currentDevice !== '') {
sessionStorage.setItem('currentDevice', this.$store.getters.currentDevice)
}
this.currentDeviceId = sessionStorage.getItem('currentDevice')
this.getData()
},
destroyed() {
},
......
......@@ -15,49 +15,28 @@
:outerLoading="loadingStatus"
:pagination="false"
>
<div slot='fieldSlot' slot-scope="row">
<template v-if="!row.ifEdit">
<span>{{row.type}}</span>
</template>
<template v-else>
<st-inpt v-model="row.type"></st-inpt>
</template>
<div slot='description' slot-scope="row">
<span>{{ simplify(row.description, 16) }}</span>
</div>
<div slot='valueSlot' slot-scope="row">
<template v-if="!row.ifEdit && row.valueType === 'text'">
<span>{{row.value}}</span>
</template>
<template v-else-if="!row.ifEdit && row.valueType === 'a'">
<a href="#">{{row.value}}</a>
</template>
<template v-else-if="!row.ifEdit && row.valueType === 'img'">
<span></span>
<el-image></el-image>
</template>
<template v-else>
<st-inpt v-model="row.value"></st-inpt>
</template>
</div>
<div slot='childOperate' slot-scope="row">
<span class="operate-text" @click="seeServiceParams(row.id)">{{ '撤销覆盖' }}</span>
<span class="operate-text" @click="sendReq(row.id)">{{ '删除' }}</span>
<span class="operate-text">{{'-'}}</span>
<div slot='operate'>
<span class="operate-text">{{ '-'}}</span>
</div>
</st-table>
</div>
</div>
<div class="content-item">
<span class="content-item-title">{{'指令:'}}</span>
<st-input type="textarea" placeholder="请输入Json" class="content-item-one"></st-input>
<st-input type="textarea" placeholder="请输入Json" class="content-item-one" v-model="commandContent"></st-input>
</div>
</div>
<st-button type="primary" width="80px" class="sendBtn">{{'发送'}}</st-button>
<st-button type="primary" width="80px" class="sendBtn" :loading="buttonLoading" @click="send">{{'发送'}}</st-button>
</div>
</div>
</template>
<script>
import { rTimeMin, copyText } from '@/utils/system.js'
import { postServiceCommand } from '@/axios'
export default {
computed: {
// 获取设备状态颜色
......@@ -98,12 +77,12 @@ export default {
},
data() {
return {
commandContent: '',
buttonLoading: false,
dynamicTags: ['标签一', '标签二', '标签三'],
inputVisible: false,
inputValue: '',
tokenList: [
{ p1: '小1' },
],
tokenList: [],
total: 0,
loadingStatus: false,
activeTab: 'getParams',
......@@ -143,16 +122,17 @@ export default {
definitions: [
{
label: '服务',
render: 'p1'
render: 'name'
}, {
label: '编号',
render: 'p2'
render: 'potuid'
}, {
label: '端口',
render: 'p3'
render: 'port'
}, {
label: '描述',
render: 'p3'
type: 'slot',
slotName: 'description'
}, {
label: '操作',
type: 'slot',
......@@ -161,8 +141,33 @@ export default {
],
}
},
mounted() {
this.getData()
},
methods: {
rTimeMin,
async send() {
const currentService = JSON.parse(sessionStorage.getItem('currentService'))
this.buttonLoading = true
const res = await postServiceCommand({
pots: [currentService.potuid],
command: JSON.parse(this.commandContent)
})
this.buttonLoading = false
if (res && res.data) {
// this.resValue = res.data
}
},
async getData() {
const currentService = JSON.parse(sessionStorage.getItem('currentService'))
this.tokenList = [{
name: currentService.name,
potuid: currentService.potuid,
port: currentService.port,
description: currentService.description,
}]
this.total = 1
},
handleClose(tag) {
this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1)
},
......
......@@ -3,7 +3,7 @@
<div class="wrapper">
<div class="content">
<div class="content-item">
<span class="content-item-title">{{'服务参数:'}}</span>
<span class="content-item-title service-params">{{'服务参数:'}}</span>
<div class="content-table">
<st-table
ref="vTable"
......@@ -15,33 +15,11 @@
:outerLoading="loadingStatus"
:pagination="false"
>
<div slot='fieldSlot' slot-scope="row">
<template v-if="!row.ifEdit">
<span>{{row.type}}</span>
</template>
<template v-else>
<st-inpt v-model="row.type"></st-inpt>
</template>
</div>
<div slot='valueSlot' slot-scope="row">
<template v-if="!row.ifEdit && row.valueType === 'text'">
<span>{{row.value}}</span>
</template>
<template v-else-if="!row.ifEdit && row.valueType === 'a'">
<a href="#">{{row.value}}</a>
</template>
<template v-else-if="!row.ifEdit && row.valueType === 'img'">
<span></span>
<el-image></el-image>
</template>
<template v-else>
<st-inpt v-model="row.value"></st-inpt>
</template>
<div slot='description' slot-scope="row">
<span>{{ simplify(row.description, 16) }}</span>
</div>
<div slot='childOperate' slot-scope="row">
<span class="operate-text" @click="seeServiceParams(row.id)">{{ '撤销覆盖' }}</span>
<span class="operate-text" @click="sendReq(row.id)">{{ '删除' }}</span>
<span class="operate-text">{{'-'}}</span>
<div slot='operate'>
<span class="operate-text">{{ '-'}}</span>
</div>
</st-table>
</div>
......@@ -52,10 +30,12 @@
size="small"
width="200px"
class="content-select"
:options="requestList"
v-model="requestType"
>
</st-select>
<st-input width="400px" placeholder="输入URL" class="content-item-url"></st-input>
<st-button type="primary" width="80px">{{'发送'}}</st-button>
<st-input width="400px" placeholder="输入URL" class="content-item-url" v-model="requestUrl"></st-input>
<st-button type="primary" width="80px" @click="send" :loading="buttonLoading">{{'发送'}}</st-button>
</div>
<div class="content-item">
<span class="content-item-title">{{'Header:'}}</span>
......@@ -102,6 +82,7 @@
<script>
import { rTimeMin, copyText } from '@/utils/system.js'
import { postServiceRequest } from '@/axios'
export default {
computed: {
// 获取设备状态颜色
......@@ -140,6 +121,9 @@ export default {
}
}
},
mounted() {
this.getData()
},
data() {
return {
bodyValue: '',
......@@ -148,20 +132,7 @@ export default {
dynamicTags: ['标签一', '标签二', '标签三'],
inputVisible: false,
inputValue: '',
tokenList: [
{ key: { value: 'A', ifEdit: false }, value: { value: 'B', ifEdit: false } },
{ key: { value: 'C', ifEdit: false }, value: { value: 'D', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
],
tokenList: [],
headDefinitions: [
{
label: '键',
......@@ -174,16 +145,17 @@ export default {
slotName: 'valueSlot'
}
],
headTokenList: [
{ key: { value: 'A', ifEdit: false }, value: { value: 'B', ifEdit: false } },
{ key: { value: 'C', ifEdit: false }, value: { value: 'D', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
{ key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
],
// headTokenList: [
// { key: { value: 'A', ifEdit: false }, value: { value: 'B', ifEdit: false } },
// { key: { value: 'C', ifEdit: false }, value: { value: 'D', ifEdit: false } },
// { key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
// { key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
// { key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
// { key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
// { key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
// { key: { value: 'E', ifEdit: false }, value: { value: 'F', ifEdit: false } },
// ],
headTokenList: [],
total: 0,
loadingStatus: false,
activeTab: 'getParams',
......@@ -201,48 +173,60 @@ export default {
name: 'sendOrder',
},
],
// definitions: [
// {
// label: '字段',
// type: 'slot',
// slotName: 'paramsSlot',
// }, {
// label: '类型',
// type: 'slot',
// slotName: 'typeSlot',
// }, {
// label: '值',
// type: 'slot',
// slotName: 'valueSlot'
// }, {
// label: '操作',
// type: 'slot',
// slotName: 'operate',
// },
// ],
definitions: [
{
label: '服务',
render: 'p1'
render: 'name'
}, {
label: '编号',
render: 'p2'
render: 'potuid'
}, {
label: '端口',
render: 'p3'
render: 'port'
}, {
label: '描述',
render: 'p3'
type: 'slot',
slotName: 'description'
}, {
label: '操作',
type: 'slot',
slotName: 'operate',
},
],
requestList: [
{ label: 'GET', value: 'GET' },
{ label: 'POST', value: 'POST' },
],
requestType: '',
requestUrl: '',
buttonLoading: false
}
},
methods: {
rTimeMin,
async send() {
const currentService = JSON.parse(sessionStorage.getItem('currentService'))
const headers = this.headTokenList.map(item => {
return {
keyname: item.key.value,
keyvalue: item.value.value.trim()
}
})
console.log(typeof this.bodyValue, 'type')
const body = JSON.parse(this.bodyValue)
this.buttonLoading = true
const res = await postServiceRequest({
potuid: currentService.potuid,
method: this.requestType,
url: this.requestUrl,
headers: headers,
body: body
})
this.buttonLoading = false
if (res && res.data) {
// this.resValue = res.data
}
},
handleClose(tag) {
this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1)
},
......@@ -268,23 +252,34 @@ export default {
row[item].value = this.currentInput
}
row[item].ifEdit = status
this.$set(this.tokenList, index, row)
this.$set(this.headTokenList, index, row)
this.$nextTick(() => {
this.$refs.myInput && this.$refs.myInput.$children[0].focus()
})
},
updateScope(row, index) {
row.editing = true
this.$set(this.tokenList, index, row)
this.$set(this.headTokenList, index, row)
},
addRow() {
const newRow = { key: { value: 'newone', ifEdit: false }, value: { value: 'newone', ifEdit: false } }
this.headTokenList.push(newRow)
},
async getData() {
const currentService = JSON.parse(sessionStorage.getItem('currentService'))
this.tokenList = [{
name: currentService.name,
potuid: currentService.potuid,
port: currentService.port,
description: currentService.description,
}]
this.total = 1
}
}
}
</script>
<style lang="sass" scoped>
.service-params
::v-deep .el-table__body-wrapper.is-scrolling-none
max-height: 224px !important
.table-box
......
......@@ -5,7 +5,7 @@
</div>
<div class="page-nav">
<div class="page-nav-title">
<span>{{'AIPS'}}</span>
<span>{{$store.getters.currentService.serviceName}}</span>
</div>
<st-table
ref="vTable"
......@@ -18,17 +18,17 @@
:pagination="false"
>
<div slot='codeSlot' slot-scope="row">
<span>{{ simplify(row.code, 3) }}</span>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.code)"></i>
<span>{{ simplify(row.deviceid, 3) }}</span>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.deviceid)"></i>
</div>
<div slot='status' slot-scope="row">
<span class="circleStatus" :style="{color: getStatusColor(row.status)}">{{ getStatusText(row.status) }}</span>
<div slot='status' slot-scope="row" class="status">
<span class="circleStatus" :style="{color: getStatusColor(row.state)}">{{ getStatusText(row.state) }}</span>
</div>
<div slot='structureSlot' slot-scope="row">
<span>{{ simplify(row.structure, 6) }}</span>
</div>
<div slot='registerTimeSlot' slot-scope="row">
<span>{{ rTimeMin(row.registerTime) }}</span>
<span>{{ (row.register_date) }}</span>
</div>
<div slot='tagsSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.tags ? row.tags.join('、') : ''" placement="top">
......@@ -42,11 +42,11 @@
</el-tooltip>
</div>
<div slot='servicesSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.services ? row.services.join('、') : ''" placement="top">
<el-tooltip class="item" effect="dark" :content="getServiceName(row.services)" placement="top">
<!-- 必须要套一层 -->
<div>
<template v-for="(item, index) in row.services">
<span v-if="[0, 2].indexOf(index) !== -1" :key="index" class="service-item">{{ simplify(item, 4) }}</span>
<span v-if="[0, 1, 2].indexOf(index) !== -1" :key="index" class="service-item">{{ simplify(item.name, 4) }}</span>
</template>
<span v-if="(row.services && row.services.length) > 10">共: {{(row.services && row.services.length) ? row.services.length : 0}} 条</span>
</div>
......@@ -56,7 +56,7 @@
<span>{{ simplify(row.system, 7) }}</span>
</div>
<div slot='operate' slot-scope="row">
<span class="operate-text" @click="delete(row.id)">{{'详情'}}</span>
<span class="operate-text" @click="detail(row.deviceid)">{{'详情'}}</span>
</div>
</st-table>
</div>
......@@ -77,6 +77,8 @@ import getParams from './components/GetParams.vue'
import sendRequest from './components/SendRequest.vue'
import sendOrder from './components/SendOrder.vue'
import { rTimeMin, copyText } from '@/utils/system.js'
import { getService, getServiceDevice } from '@/axios'
export default {
components: {
getParams,
......@@ -84,16 +86,21 @@ export default {
sendOrder
},
computed: {
getServiceName() {
return item => {
return item.map(t1 => t1.name).join()
}
},
// 获取设备状态颜色
getStatusColor() {
return item => {
switch (item) {
case 'online':
case 1:
return '#67C23A'
case 'offline':
return '#999999'
default:
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
},
......@@ -101,12 +108,12 @@ export default {
getStatusText() {
return item => {
switch (item) {
case 'online':
case 1:
return '在线'
case 'offline':
return '离线'
default:
case 2:
return '异常'
default:
return '离线'
}
}
},
......@@ -123,7 +130,6 @@ export default {
data() {
return {
tokenList: [
{ name: '小1', code: '110123124325' },
],
total: 0,
loadingStatus: false,
......@@ -152,13 +158,13 @@ export default {
type: 'slot',
slotName: 'status',
statusColor: item => {
switch (item.status) {
case 'online':
switch (item.state) {
case 1:
return '#67C23A'
case 'offline':
return '#999999'
default:
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
}, {
......@@ -171,7 +177,7 @@ export default {
slotName: 'systemSlot'
}, {
label: 'IP',
render: 'IP'
render: 'ip'
}, {
label: '注册时间',
type: 'slot',
......@@ -190,14 +196,44 @@ export default {
slotName: 'operate',
},
],
currentDeviceId: '',
}
},
methods: {
rTimeMin
}
rTimeMin,
async getServiceParams() {
const res = await getServiceParams(this.serviceId)
},
async getData() {
const res = await getServiceDevice({ deviceid: this.currentDeviceId })
if (res && res.data && res.data.device) {
this.tokenList = [JSON.parse(JSON.stringify(res.data.device))]
this.total = 1
} else {
this.tokenList = []
this.total = 0
}
},
// 跳转到设备详情页面
detail(deviceid) {
this.$store.commit('changeCurrentDevice', deviceid)
this.$router.push({ name: 'device-detail' })
},
},
mounted() {
if (this.$store.getters.currentDevice !== '') {
sessionStorage.setItem('currentDevice', this.$store.getters.currentDevice)
}
this.currentDeviceId = sessionStorage.getItem('currentDevice')
this.getData()
},
}
</script>
<style lang="sass" scoped>
.service-item
margin-right: 20px
.circleStatus
margin-left: 6px
.icon-fuzhi-text
margin-left: 6px
color: #409EFF
......@@ -227,6 +263,12 @@ export default {
flex: 1 0 0
overflow-y: visible
overflow-x: hidden
.page-nav
::v-deep.el-table__body-wrapper
max-height: none !important
::v-deep.pagination
margin-top: 0
margin-bottom: 0
.table-list
flex: 1 0 0 !important
overflow: visible !important
......
......@@ -9,9 +9,9 @@
<div class="search-item">
<span class="search-title">状态:</span>
<el-checkbox-group v-model="search.checkList" class="inline-div">
<el-checkbox label="1" class="check-title">在线</el-checkbox>
<el-checkbox label="2" class="check-title">离线</el-checkbox>
<el-checkbox label="3" class="check-title">异常</el-checkbox>
<el-checkbox :label="1" class="check-title">在线</el-checkbox>
<el-checkbox :label="0" class="check-title">离线</el-checkbox>
<el-checkbox :label="2" class="check-title">异常</el-checkbox>
</el-checkbox-group>
</div>
<div v-if="!isCollapse">
......@@ -94,7 +94,8 @@
<div class="page-content">
<div class="content-header flex-right-content">
<nameFilter
placeholder="请输入搜索内容">
placeholder="请输入搜索内容"
@startSearch="startSearch">
</nameFilter>
</div>
<div class="table-list">
......@@ -111,17 +112,17 @@
:childOptions="childDefinitions"
>
<div slot='codeSlot' slot-scope="row">
<span>{{ simplify(row.code, 3) }}</span>
<span>{{ simplify(row.deviceid, 3) }}</span>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.code)"></i>
</div>
<div slot='status' slot-scope="row">
<span class="circleStatus" :style="{color: getStatusColor(row.status)}">{{ getStatusText(row.status) }}</span>
<div slot='status' slot-scope="row" class="status">
<span class="circleStatus" :style="{color: getStatusColor(row.state)}">{{ getStatusText(row.state) }}</span>
</div>
<div slot='structureSlot' slot-scope="row">
<span>{{ simplify(row.structure, 6) }}</span>
</div>
<div slot='registerTimeSlot' slot-scope="row">
<span>{{ rTimeMin(row.registerTime) }}</span>
<span>{{ (row.register_date) }}</span>
</div>
<div slot='tagsSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.tags ? row.tags.join('、') : ''" placement="top">
......@@ -135,11 +136,11 @@
</el-tooltip>
</div>
<div slot='servicesSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.services ? row.services.join('、') : ''" placement="top">
<el-tooltip class="item" effect="dark" :content="getServiceName(row.services)" placement="top">
<!-- 必须要套一层 -->
<div>
<template v-for="(item, index) in row.services">
<span v-if="[0, 2].indexOf(index) !== -1" :key="index" class="service-item">{{ simplify(item, 4) }}</span>
<span v-if="[0, 1, 2].indexOf(index) !== -1" :key="index" class="service-item">{{ simplify(item.name, 4) }}</span>
</template>
<span v-if="(row.services && row.services.length) > 10">共: {{(row.services && row.services.length) ? row.services.length : 0}} 条</span>
</div>
......@@ -149,23 +150,23 @@
<span>{{ simplify(row.system, 7) }}</span>
</div>
<div slot='operate' slot-scope="row">
<span class="operate-text" @click="detail(row.id)">{{ '详情 '}}</span>
<span class="operate-text" @click="detail(row.deviceid)">{{ '详情 '}}</span>
</div>
<!-- eslint-disable-next-line -->
<div slot='childServiceSlot' slot-scope="row">
<span>{{ row.service }}</span>
<span>{{ row.name }}</span>
</div>
<div slot='childCodeSlot' slot-scope="row">
<span>{{ row.code }}</span>
<span>{{ row.potuid }}</span>
</div>
<div slot='portSlot' slot-scope="row">
<span>{{ row.port }}</span>
</div>
<div slot='descSlot' slot-scope="row">
<span>{{ simplify(row.desc, 10) }}</span>
<span>{{ simplify(row.description, 10) }}</span>
</div>
<div slot='childOperate' slot-scope="row">
<span class="operate-text" @click="seeServiceParams(row.id)">{{ '查看参数' }}</span>
<span class="operate-text" @click="seeServiceParams(row)">{{ '查看参数' }}</span>
<span class="operate-text" @click="sendReq(row.id)">{{ '发送请求' }}</span>
<span class="operate-text" @click="sendOrder(row.id)">{{ '发送指令' }}</span>
</div>
......@@ -180,6 +181,7 @@ import browserStorage from '@/services/local-storage'
import Dialog from '@/helpers/dialog'
import validate from '@/components/seeta-ui/seeta-form/validator'
import { rTimeMin, copyText } from '@/utils/system.js'
import { getDevice, getDeviceService, getTag } from '@/axios'
export default {
data() {
return {
......@@ -194,9 +196,8 @@ export default {
time2: '',
// 表格数据
tokenList: [
{ name: '小1', code: '110123124325', child: { service: '11', code: '123', port: '1234', desc: '这是服务1' } },
],
total: 1,
total: 0,
// 编辑和添加表单
form: {
},
......@@ -227,7 +228,7 @@ export default {
definitions: [
{
label: '序号',
render: 'orderNumber',
render: 'id',
}, {
label: '编号',
type: 'slot',
......@@ -237,13 +238,13 @@ export default {
type: 'slot',
slotName: 'status',
statusColor: item => {
switch (item.status) {
case 'online':
switch (item.state) {
case 1:
return '#67C23A'
case 'offline':
return '#999999'
default:
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
}, {
......@@ -256,7 +257,7 @@ export default {
slotName: 'systemSlot'
}, {
label: 'IP',
render: 'IP'
render: 'ip'
}, {
label: '注册时间',
type: 'slot',
......@@ -284,16 +285,21 @@ export default {
}
},
computed: {
getServiceName() {
return item => {
return item.map(t1 => t1.name).join()
}
},
// 获取设备状态颜色
getStatusColor() {
return item => {
switch (item) {
case 'online':
case 1:
return '#67C23A'
case 'offline':
return '#999999'
default:
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
},
......@@ -301,12 +307,12 @@ export default {
getStatusText() {
return item => {
switch (item) {
case 'online':
case 1:
return '在线'
case 'offline':
return '离线'
default:
case 2:
return '异常'
default:
return '离线'
}
}
},
......@@ -323,7 +329,12 @@ export default {
methods: {
rTimeMin,
copyText,
seeServiceParams(id) {
startSearch(value) {
this.getData()
},
seeServiceParams(row) {
this.$store.commit('changeCurrentDevice', row.deviceId)
this.$store.commit('changeCurrentService', row)
this.$router.push({ name: 'device-service' })
},
sendReq(id) {
......@@ -350,8 +361,57 @@ export default {
}
},
// 跳转到设备详情页面
detail(id) {
detail(deviceid) {
this.$store.commit('changeCurrentDevice', deviceid)
this.$router.push({ name: 'device-detail' })
},
async getData() {
const res = await getDevice({
state: this.search.checkList,
pages: this.pi,
pagesize: this.ps,
structure: this.search.structure,
system: this.search.system,
register_date: this.search.registerTime && this.search.registerTime.length ? this.search.registerTime[0] : '',
online_date: this.search.onlineTime && this.search.onlineTime.length ? this.search.onlineTime[0] : '',
tag: this.search.tags,
service: this.search.services
})
if (res && res.data) {
this.tokenList = JSON.parse(JSON.stringify(res.data.data.devices))
this.tokenList.forEach(item => {
item.services.forEach(s1 => {
s1.deviceId = item.deviceid
})
item.child = JSON.parse(JSON.stringify(item.services))
})
this.total = res.data.data.total
} else {
this.tokenList = []
this.total = 0
}
},
async getService() {
const res = await getDeviceService()
if (res) {
this.serviceList = res.data.services.map(item => {
return {
label: item,
value: item
}
})
}
},
async getTag() {
const res = await getTag()
if (res) {
this.tagList = res.data.tags.map(item => {
return {
label: item,
value: item
}
})
}
}
},
watch: {
......@@ -363,6 +423,9 @@ export default {
}
},
mounted() {
this.getData()
this.getService()
this.getTag()
},
destroyed() {
},
......@@ -373,6 +436,11 @@ export default {
</script>
<style lang="sass" scoped>
.service-item
margin-right: 20px
.cell
::v-deep .any-slot
display: inline-block
.page-nav
font-family: PingFangSC-Regular
font-size: 14px
......
<template>
<div class="data-list-common flex column main-content flex-1">
<div class="header">
<span class="title">{{'参数模板 / 详情'}}</span>
</div>
<div class="page-content">
<st-form class="flex-form"
ref="form"
label-width="100px"
:model="form">
<st-form-item :label="'模板名称'+':'">
<span>{{form.name}}</span>
</st-form-item>
<st-form-item :label="'模板类型'+':'">
<span>{{form.type}}</span>
</st-form-item>
<st-form-item :label="'基础模板'+':'">
<span>{{form.base}}</span>
</st-form-item>
<st-form-item :label="'描述'+':'">
<span>{{form.description}}</span>
</st-form-item>
<st-form-item :label="'参数'+':'" class="flex1">
<st-table
ref="vTable"
:options="definitions"
:pagination="false"
:data="{
list: tokenList,
total: total,
}"
:outerLoading="loadingStatus">
<div slot="value" slot-scope="row">
<span v-if="row.type === 'number' || row.type === 'string'">{{row.value}}</span>
<span v-if="row.type === 'blob'" style="line-height: 28px">
<!-- TODO -->
<span style="float: left;margin-right: 10px">{{calculateByte(row.value)}}字节</span>
<el-image style="width: 42px; height: 28px;overflow: visible" :src="row.value" fit="fit">
<div slot="error" style="width: 80px; height: 28px;overflow: visible">(不可预览)</div>
</el-image>
</span>
<span v-if="row.type === 'table'" style="color: #409EFF; cursor: pointer" @click="$router.push({ path: '/data' })">{{row.value}}</span>
</div>
</st-table>
</st-form-item>
</st-form>
</div>
</div>
</template>
<script>
import { detailParameter } from '@/axios'
import { calculateByte } from '@/utils/system'
export default {
data() {
return {
form: {},
loadingStatus: false,
definitions: [
{
label: '字段',
render: 'field'
},
{
label: '类型',
render: 'type'
},
{
label: '值',
type: 'slot',
slotName: 'value'
}
],
tokenList: [],
total: 0
}
},
async mounted() {
this.loadingStatus = true
const res = await detailParameter({ name: this.$route.query.name })
if (res && res.data && res.data.code === 0) {
this.form = res.data
const binaryObj = res.data.parameters.binary
const scalarsObj = res.data.parameters.scalars
const tableObj = res.data.parameters.table
for (const key in binaryObj) {
this.tokenList.push({ field: key, type: 'blob', value: binaryObj[key] })
}
for (const key in scalarsObj) {
this.tokenList.push({ field: key, type: typeof scalarsObj[key], value: scalarsObj[key] })
}
for (const key in tableObj) {
this.tokenList.push({ field: key, type: 'table', value: tableObj[key] })
}
}
this.loadingStatus = false
},
methods: {
calculateByte: base64 => calculateByte(base64),
}
}
</script>
<style lang="sass" scoped>
.page-content
::v-deep.el-form-item
margin-bottom: 20px
.flex-form
display: flex
flex-direction: column
height: 100%
text-align: left
.flex1
flex: 1
::v-deep.el-form-item__content
height: 100%!important
::v-deep .el-table__row
height: 48px
::v-deep td
padding: 10px 0
::v-deep .cell
height: 28px
line-height: 28px!important
</style>
<template>
<div>
<div class="data-list-common flex column main-content flex-1">
<div class="header">
<span class="title">{{'参数模板'}}</span>
</div>
<div class="page-content">
<div class="level level-one">
<div class="content-header">
<st-button type="primary" @click="$router.push({ path: '/params/add', query: { level: 1 } })">
<i class="iconfont icon-tianjia"></i><span class="text">{{'添加'}}</span></st-button>
<div class="search">
<input type="text" class="search-input" placeholder="请输入搜索内容" v-model="oneVal">
<i class="el-input__icon el-icon-search"></i>
</div>
</div>
<div class="table-list">
<div class="list-content">
<st-table
ref="vTable"
:options="definitions"
:data="{
list: oneList,
total: oneTotal,
}"
:pagination="false"
highlight-current-row
@row-click="handleClickRow"
:outerLoading="loadingOne">
<div slot="operate" slot-scope="row">
<span class="operate" @click="$router.push({ path: '/params/detail', query: { name: row.name }})">详情</span>
<span class="operate" @click="$router.push({ path: '/params/edit', query: { name: row.name, level: 1 } })">编辑</span>
<span class="operate operate-delete" @click="handleDelete(row, 1)">删除</span>
</div>
<el-pagination slot="pagination" layout="prev, pager, next"
@current-change="handleOneCurrentChange"
:current-page="oneCurrentPage"
:total="oneTotal">
</el-pagination>
</st-table>
</div>
</div>
</div>
<div class="blanking"></div>
<div class="level level-two">
<div class="content-header">
<st-button type="primary" @click="$router.push({ path: '/params/add', query: { level: 2 } })">
<i class="iconfont icon-tianjia"></i><span class="text">{{'添加'}}</span></st-button>
<div class="search">
<input type="text" class="search-input" placeholder="请输入搜索内容" v-model="twoVal">
<i class="el-input__icon el-icon-search"></i>
</div>
</div>
<div class="table-list">
<div class="list-content">
<st-table
ref="vTable"
:options="definitions"
:pagination="false"
:data="{
list: twoList,
total: twoTotal,
}"
:empty-text="parentLevel ? '暂无数据' : '未选择一级参数模板'"
:outerLoading="loadingTwo">
<div slot="operate" slot-scope="row">
<span class="operate" @click="$router.push({ path: '/params/detail', query: { name: row.name } })">详情</span>
<span class="operate" @click="$router.push({ path: '/params/edit', query: { name: row.name, level: 2 } })">编辑</span>
<span class="operate operate-delete" @click="handleDelete(row, 2)">删除</span>
</div>
<el-pagination slot="pagination" layout="prev, pager, next"
@current-change="handleTwoCurrentChange"
:current-page="twoCurrentPage"
:total="twoTotal">
</el-pagination>
</st-table>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { getParameter, deleteParameter } from '@/axios'
import Dialog from '@/helpers/dialog'
export default {
data() {
return {
oneVal: '',
twoVal: '',
oneList: [],
twoList: [],
oneTotal: 0,
twoTotal: 0,
oneCurrentPage: 1,
twoCurrentPage: 1,
loadingOne: false,
loadingTwo: false,
parentLevel: '',
definitions: [
{
label: '序号',
render: 'order'
},
{
label: '名称',
render: 'name'
},
{
label: '类别',
render: 'type'
},
{
label: '描述',
render: 'description'
},
{
label: '操作',
type: 'slot',
width: '200px',
slotName: 'operate'
},
],
}
},
mounted() {
this.getOneData()
this.getTwoData()
},
methods: {
async getOneData() {
this.loadingOne = true
const oneLevel = await getParameter({ base: 1, pages: this.oneCurrentPage - 1, pagesize: 10 })
if (oneLevel && oneLevel.data && oneLevel.data.code === 0) {
this.oneList = oneLevel.data.parameters.datas.map((item, index) => {
item.order = index + 1 + (this.oneCurrentPage - 1) * 10
return item
})
this.oneTotal = oneLevel.data.parameters.total
}
this.loadingOne = false
},
async getTwoData() {
this.loadingTwo = true
const twoLevel = await getParameter({ parent: this.parentLevel === '' ? 0 : this.parentLevel, pages: this.twoCurrentPage - 1, pagesize: 10 })
if (twoLevel && twoLevel.data && twoLevel.data.code === 0) {
this.twoList = twoLevel.data.parameters.datas.map((item, index) => {
item.order = index + 1 + (this.twoCurrentPage - 1) * 10
return item
})
this.twoTotal = twoLevel.data.parameters.total
}
this.loadingTwo = false
},
async handleDelete(row, level) {
const confirmDelete = await Dialog.confirm('提示', { message: '是否删除此模板?' })
if (!confirmDelete) return
const res = await deleteParameter({ name: row.name })
if (res) {
Toast.success('操作成功')
if (level === 1) this.getOneData()
if (level === 2) this.getTwoData()
}
},
handleClickRow(row, column, event) {
this.parentLevel = row.name
this.getTwoData()
},
handleOneCurrentChange(val) {
this.oneCurrentPage = val
this.getOneData()
},
handleTwoCurrentChange(val) {
this.twoCurrentPage = val
this.getTwoData()
}
}
}
</script>
<style lang="sass" scoped>
.page-content
display: flex
flex-direction: row
padding: 0
.blanking
width: 20px
background: #EBEEF5
.level
width: calc(50% - 10px)
padding: 14px 20px
.table-list
height: calc(100% - 60px)
.list-content
height: 100%
.table-box
height: 100%
::v-deep.el-table
max-height: 100%!important
.content-header
display: flex
justify-content: space-between
margin-bottom: 20px
.search
width: 240px
height: 32px
position: relative
display: inline-block
.search-input
width: 100%
padding-right: 35px
.el-icon-search
line-height: 32px
position: absolute
right: 0
font-size: 18px
color: #CCC
cursor: pointer
width: 44px
height: 32px
text-align: center
::v-deep.el-pagination__total
display: none
::v-deep.el-pagination__sizes
display: none
::v-deep.el-pagination__jump
display: none
::v-deep.current-row td
background: #ecf5ff!important
::v-deep input
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
color:#333
height: 32px
line-height: 32px
&::placeholder
font-size: 14px
font-family: PingFangSC-Regular, PingFang SC
font-weight: 400
color:#999999
</style>
<template>
<div class="data-list-common flex column main-content flex-1">
<div class="header">
<span class="title">{{'个人中心'}}</span>
</div>
<div class="page-content">
<st-form
ref="form"
label-width="70px"
:model="userData">
<st-form-item
style="margin-bottom:10px"
:label="'头像'+':'">
<el-image style="width: 80px; height: 80px" :src="userData.image" fit="fit"></el-image>
</st-form-item>
<st-form-item
style="margin-bottom:10px"
:label="'账户'+':'">
<span>{{userData.role}}</span>
</st-form-item>
<st-form-item
style="margin-bottom:10px"
:label="'姓名'+':'">
<span>{{userData.creater}}</span><span class="btn-text" @click="showDialog = true;type = 'name'">编辑</span>
</st-form-item>
<st-form-item
style="margin-bottom:10px"
:label="'邮箱'+':'">
<span>{{userData.email}}</span><span class="btn-text" @click="showDialog = true;type = 'email'">编辑</span>
</st-form-item>
<st-form-item
style="margin-bottom:10px"
:label="'密码'+':'">
<span class="btn-text" style="margin-left: 0" @click="showDialog = true;type = 'password'">修改密码</span>
</st-form-item>
</st-form>
</div>
<st-dialog
:show.sync="showDialog"
class="update-dialog"
@dismiss="cancelSubmit"
>
<div slot="header" class="popup-header">{{'编辑'}}</div>
<div slot="body" class="popup-body">
<st-form
:label-width="type === 'password' ? '90px' : ''"
ref="form">
<st-form-item v-if="type === 'email'"
:label="'邮箱:'">
<st-input v-model="email"></st-input>
</st-form-item>
<st-form-item v-if="type === 'name'"
:label="'姓名:'">
<st-input v-model="name"></st-input>
</st-form-item>
<div v-if="type === 'password'">
<st-form-item
:label="'当前密码:'">
<st-input v-model="password"></st-input>
</st-form-item>
<st-form-item
:label="'新密码:'">
<st-input v-model="newPwd"></st-input>
</st-form-item>
<st-form-item
:label="'新密码:'">
<st-input v-model="confirmPwd"></st-input>
</st-form-item>
</div>
</st-form>
</div>
<div slot="footer" class="popup-footer flex right">
<st-button @click="cancelSubmit">{{$t('public.cancel')}}</st-button>
<st-button type="primary" @click="submit">{{'确定'}}</st-button>
</div>
</st-dialog>
</div>
</template>
<script>
import { getUser } from '@/utils/user'
export default {
data() {
return {
showDialog: false,
userData: {},
type: '',
email: '',
name: '',
password: '',
newPwd: '',
confirmPwd: ''
}
},
mounted() {
this.userData = getUser().info
},
methods: {
submit() {
this.showDialog = false
},
cancelSubmit() {
this.showDialog = false
}
}
}
</script>
<style lang="sass" scoped>
.page-content
text-align: left
.btn-text
color: #409EFF
margin-left: 30px
font-size: 14px
</style>
<template>
<div class="data-list-common flex column main-content flex-1">
<div class="header">
<span class="title">{{'设备列表'}}</span>
<span class="title">{{'服务列表'}}</span>
</div>
<div class="page-nav">
<div class="search-fields" :class="{'search-fields-collapse': isCollapse}">
......@@ -9,9 +9,9 @@
<div class="search-item">
<span class="search-title">状态:</span>
<el-checkbox-group v-model="search.checkList" class="inline-div">
<el-checkbox label="1" class="check-title">在线</el-checkbox>
<el-checkbox label="2" class="check-title">离线</el-checkbox>
<el-checkbox label="3" class="check-title">异常</el-checkbox>
<el-checkbox :label="1" class="check-title">在线</el-checkbox>
<el-checkbox :label="0" class="check-title">离线</el-checkbox>
<el-checkbox :label="2" class="check-title">异常</el-checkbox>
</el-checkbox-group>
</div>
<div v-if="!isCollapse">
......@@ -94,7 +94,8 @@
<div class="page-content">
<div class="content-header flex-right-content">
<nameFilter
placeholder="请输入搜索内容">
placeholder="请输入搜索内容"
@startSearch="startSearch">
</nameFilter>
</div>
<div class="table-list">
......@@ -107,19 +108,20 @@
total: total,
}"
:outerLoading="loadingStatus"
:doubleTable="false"
>
<div slot='codeSlot' slot-scope="row">
<span>{{ simplify(row.code, 3) }}</span>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.code)"></i>
<span>{{ simplify(row.potuid, 3) }}</span>
<i class="iconfont icon-fuzhi icon-fuzhi-text" @click="copyText(row.potuid)"></i>
</div>
<div slot='status' slot-scope="row">
<span class="circleStatus" :style="{color: getStatusColor(row.status)}">{{ getStatusText(row.status) }}</span>
<span class="circleStatus" :style="{color: getStatusColor(row.state)}">{{ getStatusText(row.state) }}</span>
</div>
<div slot='structureSlot' slot-scope="row">
<span>{{ simplify(row.structure, 6) }}</span>
</div>
<div slot='registerTimeSlot' slot-scope="row">
<span>{{ rTimeMin(row.registerTime) }}</span>
<span>{{ (row.register_date) }}</span>
</div>
<div slot='tagsSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.tags ? row.tags.join('、') : ''" placement="top">
......@@ -133,14 +135,8 @@
</el-tooltip>
</div>
<div slot='servicesSlot' slot-scope="row">
<el-tooltip class="item" effect="dark" :content="row.services ? row.services.join('、') : ''" placement="top">
<!-- 必须要套一层 -->
<div>
<template v-for="(item, index) in row.services">
<span v-if="[0, 2].indexOf(index) !== -1" :key="index" class="service-item">{{ simplify(item, 4) }}</span>
</template>
<span v-if="(row.services && row.services.length) > 10">共: {{(row.services && row.services.length) ? row.services.length : 0}} 条</span>
</div>
<el-tooltip class="item" effect="dark" :content="row.name" placement="top">
<span>{{row.name.length > 10 ? row.name.slice(0, 9) + '...' : row.name}}</span>
</el-tooltip>
</div>
<div slot='systemSlot' slot-scope="row">
......@@ -163,6 +159,7 @@ import browserStorage from '@/services/local-storage'
import Dialog from '@/helpers/dialog'
import validate from '@/components/seeta-ui/seeta-form/validator'
import { rTimeMin, copyText } from '@/utils/system.js'
import { getService, getDeviceService, getTag } from '@/axios'
export default {
data() {
return {
......@@ -210,7 +207,11 @@ export default {
definitions: [
{
label: '序号',
render: 'orderNumber',
render: 'id',
}, {
label: '服务',
type: 'slot',
slotName: 'servicesSlot'
}, {
label: '编号',
type: 'slot',
......@@ -220,13 +221,13 @@ export default {
type: 'slot',
slotName: 'status',
statusColor: item => {
switch (item.status) {
case 'online':
switch (item.state) {
case 1:
return '#67C23A'
case 'offline':
return '#999999'
default:
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
}, {
......@@ -239,24 +240,22 @@ export default {
slotName: 'systemSlot'
}, {
label: 'IP',
render: 'IP'
render: 'ip'
}, {
label: '注册时间',
type: 'slot',
slotName: 'registerTimeSlot'
slotName: 'registerTimeSlot',
width: 110
}, {
label: '标签',
type: 'slot',
slotName: 'tagsSlot'
}, {
label: '服务',
type: 'slot',
slotName: 'servicesSlot'
slotName: 'tagsSlot',
width: 120
}, {
label: '操作',
type: 'slot',
slotName: 'operate',
width: 300
width: 200
},
],
/* 搜索栏条件 */
......@@ -268,16 +267,21 @@ export default {
}
},
computed: {
getServiceName() {
return item => {
return item.map(t1 => t1.name).join()
}
},
// 获取设备状态颜色
getStatusColor() {
return item => {
switch (item) {
case 'online':
case 1:
return '#67C23A'
case 'offline':
return '#999999'
default:
case 2:
return '#F56C6C'
default:
return '#999999'
}
}
},
......@@ -285,12 +289,12 @@ export default {
getStatusText() {
return item => {
switch (item) {
case 'online':
case 1:
return '在线'
case 'offline':
return '离线'
default:
case 2:
return '异常'
default:
return '离线'
}
}
},
......@@ -307,7 +311,54 @@ export default {
methods: {
rTimeMin,
copyText,
seeServiceParams(id) {
startSearch(value) {
this.getData()
},
async getData() {
const res = await getService({
state: this.search.checkList,
pages: this.pi,
pagesize: this.ps,
structure: this.search.structure,
system: this.search.system,
register_date: this.search.registerTime && this.search.registerTime.length ? this.search.registerTime[0] : '',
online_date: this.search.onlineTime && this.search.onlineTime.length ? this.search.onlineTime[0] : '',
tag: this.search.tags,
service: this.search.services
})
if (res && res.data) {
this.tokenList = JSON.parse(JSON.stringify(res.data.data.services))
this.total = res.data.data.total
} else {
this.tokenList = []
this.total = 0
}
},
async getServiceList() {
const res = await getDeviceService()
if (res) {
this.serviceList = res.data.services.map(item => {
return {
label: item,
value: item
}
})
}
},
async getTag() {
const res = await getTag()
if (res) {
this.tagList = res.data.tags.map(item => {
return {
label: item,
value: item
}
})
}
},
seeServiceParams(row) {
this.$store.commit('changeCurrentDevice', row.deviceId)
this.$store.commit('changeCurrentService', row)
this.$router.push({ name: 'device-service' })
},
sendReq(id) {
......@@ -334,9 +385,10 @@ export default {
}
},
// 跳转到设备详情页面
detail(id) {
detail(deviceid) {
this.$store.commit('changeCurrentDevice', deviceid)
this.$router.push({ name: 'device-detail' })
}
},
},
watch: {
// 监听route的改变进行pi ,ps的改变
......@@ -347,6 +399,9 @@ export default {
}
},
mounted() {
this.getData()
this.getServiceList()
this.getTag()
},
destroyed() {
},
......
<template>
<div>
<div class="data-list-common flex column main-content flex-1">
<div class="header">
<span class="title">{{'设置中心'}}</span>
</div>
<div class="page-content">
</div>
</div>
</template>
......@@ -7,8 +12,11 @@
export default {
data() {
return {
}
},
mounted() {
},
methods: {
}
}
</script>
......
......@@ -122,9 +122,10 @@ import crypto from 'crypto-js'
import browserStorage from '@/services/local-storage'
import seetaPopover from '@/components/seeta-ui/seeta-popover'
import { saveUser } from '@/utils/user'
// import { usersApi } from '../../http'
import { loginApi } from '@/axios'
import { langList } from '@/i18n/utils'
import axios from 'axios'
import https from 'https'
export default {
name: 'login',
components: {
......@@ -271,40 +272,30 @@ export default {
async prelogin(val) {
},
async login() {
const res = await usersApi.login({
const res = await loginApi({
username: this.userName,
password: this.userPassWord
})
if (res) {
// const res = await axios({
// httpsAgent: new https.Agent({
// rejectUnauthorized: false
// }),
// data: {
// username: this.userName,
// password: this.userPassWord
// },
// method: 'post',
// url: '/front/user/login',
// })
// .then(response => console.log(response.data))
// .catch(e => console.log(e))
if (res && res.data && res.data.code === 0) {
// TokenId
browserStorage.setItem('id', res.data.id)
const resInfo = await usersApi.getUser(res.data.subject_id)
if (resInfo) {
// 如果subjectID和个人信息ID重复则只存一个
if (res.data.subject_id === resInfo.data.id) {
// 用户ID
browserStorage.setItem('userId', res.data.subject_id)
} else {
// 个人信息的ID
browserStorage.setItem('reqId', resInfo.data.id)
// 用户ID
browserStorage.setItem('userId', res.data.subject_id)
}
browserStorage.setItem('username', resInfo.data.username)
// UUID
browserStorage.setItem('uuid', resInfo.data.uuid)
// 页面右上角用户名显示
browserStorage.setItem('user', JSON.stringify({ username: this.userName }))
// 进入欢迎页
this.$router.push({ name: 'apply' })
} else {
vm.$notify.error({
title: '请求错误',
message: '获取用户信息失败,请重新登录',
})
}
browserStorage.setItem('token', res.data.token)
browserStorage.setItem('user', JSON.stringify(res.data))
this.$router.push({ path: '/params' })
} else {
this.errmsg = this.$store.getters.errorInfo.msg
Toast.danger(res.data.msg)
}
},
// 管理员登录
......
......@@ -28,34 +28,46 @@ module.exports = {
.rule('typescript')
.test(/\.tsx?$/)
.use('babel-loader')
.loader('babel-loader')
.end()
.loader('babel-loader')
.end()
.use('ts-loader')
.loader('ts-loader')
.options({
transpileOnly: true,
appendTsSuffixTo: [
'\\.vue$'
],
happyPackMode: false
})
.loader('ts-loader')
.options({
transpileOnly: true,
appendTsSuffixTo: [
'\\.vue$'
],
happyPackMode: false
})
.end()
.end()
config.module
.rule('thejs')
.test(/\.js$/)
.include
.add(resolve('src'))
.add(resolve('node_modules/element-ui/packages'))
.end()
.use('babel-loader')
.loader('babel-loader')
.end()
},
devServer: {
// development server port 8000
// port: 8080,
// If you want to turn on the proxy, please remove the mockjs /src/main.jsL11
// 配置代理,解决跨域
proxy: {
// 匹配到/api才使用代理,避免路由冲突
'/front': {
target: 'https://218.94.122.141:9997',
secure: false,
changeOrigin: true,
pathRewrite: {
// 路径重写
'^/front': '/front' // 这个意思就是以api开头的,定向到哪里, 如果你的后边还有路径的话, 会自动拼接上
}
}
}
},
// devServer: {
// // development server port 8000
// port: 9000,
// // If you want to turn on the proxy, please remove the mockjs /src/main.jsL11
// // 配置代理,解决跨域
// proxy: {
// // 匹配到/api才使用代理,避免路由冲突
// '/api': {
// target: 'http://218.94.122.141:8089',
// changeOrigin: true,
// pathRewrite: {
// // 路径重写
// '^/api': '/' // 这个意思就是以api开头的,定向到哪里, 如果你的后边还有路径的话, 会自动拼接上
// }
// }
// }
// },
}
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!