【私域操盘手】账号密码登录
This commit is contained in:
@@ -3,4 +3,6 @@ VUE_APP_PREVIEW=false
|
||||
VUE_APP_API_BASE_URL=http://yishi.com
|
||||
VUE_APP_WWW_BASE_URL=http://yishi.com
|
||||
VUE_APP_WEB_SOCKET_URL=ws://yishi.com:2348
|
||||
VUE_APP_WEBSITE_NAME="管理后台"
|
||||
VUE_APP_WEBSITE_NAME="管理后台"
|
||||
VUE_APP_TITLE=医师管理系统
|
||||
VUE_APP_API_URL=http://yishi.com
|
||||
@@ -1,6 +1,7 @@
|
||||
NODE_ENV=development
|
||||
VUE_APP_PREVIEW=true
|
||||
VUE_APP_API_BASE_URL=http://yishi.com
|
||||
VUE_APP_WWW_BASE_URL=http://yishi.com
|
||||
VUE_APP_WEB_SOCKET_URL=ws://yishi.com:2348
|
||||
VUE_APP_WEBSITE_NAME="管理后台"
|
||||
VUE_APP_PREVIEW=false
|
||||
VUE_APP_API_BASE_URL=http://localhost:8000
|
||||
VUE_APP_WWW_BASE_URL=http://localhost:8000
|
||||
VUE_APP_WEB_SOCKET_URL=ws://localhost:2348
|
||||
VUE_APP_WEBSITE_NAME="医师管理系统开发环境"
|
||||
VUE_APP_TITLE=医师管理系统
|
||||
@@ -1,12 +1,18 @@
|
||||
import { post } from '@/utils/request'
|
||||
import { post, get } from '@/utils/request'
|
||||
|
||||
// 登录服务接口
|
||||
export const ServeLogin = data => {
|
||||
return post('/backend/user/login', data)
|
||||
return post('/api/auth/login', data)
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
export const ServeGetUser = () => {
|
||||
return post('/backend/user/get')
|
||||
return get('/api/auth/info')
|
||||
}
|
||||
|
||||
// 刷新token
|
||||
export const ServeRefreshToken = () => {
|
||||
return post('/api/auth/refresh')
|
||||
}
|
||||
|
||||
export const ServeSetUserPassword = (data) => {
|
||||
@@ -14,8 +20,9 @@ export const ServeSetUserPassword = (data) => {
|
||||
}
|
||||
|
||||
// 退出登录服务接口
|
||||
export const ServeLogout = data => {
|
||||
return post('/backend/user/logout', data)
|
||||
export const ServeLogout = () => {
|
||||
// JWT不需要服务端登出,直接清除本地token即可
|
||||
return Promise.resolve({ code: 200, msg: '退出成功' })
|
||||
}
|
||||
|
||||
export const UserIndex = data => {
|
||||
|
||||
@@ -7,7 +7,7 @@ export default {
|
||||
{
|
||||
path: '/auth/login',
|
||||
meta: {
|
||||
title: '账号登录?',
|
||||
title: '账号登录',
|
||||
needLogin: false,
|
||||
},
|
||||
component: () => import('@/views/auth/login'),
|
||||
|
||||
@@ -6,6 +6,8 @@ import SystemRouter from './system'
|
||||
import ProductRouter from '@/router/product';
|
||||
import TaskRouter from '@/router/task';
|
||||
import DeviceRouter from '@/router/device';
|
||||
import { isLogin } from '@/utils/auth'
|
||||
import store from '@/store'
|
||||
|
||||
const originalPush = Router.prototype.push
|
||||
Router.prototype.push = function push(location) {
|
||||
@@ -46,7 +48,33 @@ const routes = [
|
||||
},
|
||||
]
|
||||
|
||||
export default new Router({
|
||||
const router = new Router({
|
||||
routes,
|
||||
mode: 'hash',
|
||||
})
|
||||
|
||||
// 全局前置守卫
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 设置页面标题
|
||||
document.title = to.meta.title ? to.meta.title : '医视管理系统'
|
||||
|
||||
// 检查路由是否需要登录
|
||||
if (to.meta.needLogin) {
|
||||
// 检查登录状态
|
||||
if (isLogin()) {
|
||||
next()
|
||||
} else {
|
||||
// 未登录,重定向到登录页
|
||||
next({ path: '/auth/login' })
|
||||
}
|
||||
} else {
|
||||
// 如果是访问登录页且已登录,则跳转到首页
|
||||
if (to.path === '/auth/login' && isLogin()) {
|
||||
next({ path: '/' })
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
@@ -1,56 +1,55 @@
|
||||
import { setUserInfo, getUserInfo, removeAll, getToken } from '@/utils/auth'
|
||||
import { setUserInfo, getUserInfo, removeAll, getToken, isLogin } from '@/utils/auth'
|
||||
|
||||
import { ServeLogout } from '@/api/user'
|
||||
import { ServeLogout, ServeRefreshToken } from '@/api/user'
|
||||
|
||||
let state = {
|
||||
// 用户ID
|
||||
id: 0,
|
||||
// 渠道ID
|
||||
channel_id: 0,
|
||||
// 渠道名称
|
||||
channel_name: '',
|
||||
// 角色
|
||||
role: '',
|
||||
// 权限
|
||||
permissions: [],
|
||||
// 账号
|
||||
username: '',
|
||||
// 姓名
|
||||
name: '',
|
||||
// 手机号
|
||||
mobile: '',
|
||||
// 登录时间
|
||||
login_time: '',
|
||||
// 登录次数
|
||||
login_count: 0,
|
||||
// 登录IP
|
||||
login_ip: '',
|
||||
// 创建时间
|
||||
create_time: '',
|
||||
// 个性头像
|
||||
avatar: require('@/assets/image/detault-avatar.jpg'),
|
||||
// 角色
|
||||
roles: [],
|
||||
// 当前登录状态
|
||||
loginStatus: false,
|
||||
// 是否启动游戏模块
|
||||
// 原有字段保持不变
|
||||
channel_id: 0,
|
||||
channel_name: '',
|
||||
mobile: '',
|
||||
login_time: '',
|
||||
login_count: 0,
|
||||
login_ip: '',
|
||||
create_time: '',
|
||||
mod_game: false,
|
||||
}
|
||||
|
||||
// 判断用户是否登录
|
||||
if (getToken()) {
|
||||
if (isLogin()) {
|
||||
let userInfo = getUserInfo()
|
||||
|
||||
state.id = userInfo.id
|
||||
state.channel_id = userInfo.channel_id
|
||||
state.channel_name = userInfo.channel_name
|
||||
state.username = userInfo.username
|
||||
state.name = userInfo.name
|
||||
state.mobile = userInfo.mobile
|
||||
state.login_time = userInfo.login_time
|
||||
state.login_count = userInfo.login_count
|
||||
state.login_ip = userInfo.login_ip
|
||||
state.create_time = userInfo.create_time
|
||||
state.roles = userInfo.roles ? userInfo.roles: []
|
||||
//state.avatar = userInfo.avatar ? userInfo.avatar : state.avatar
|
||||
// 更新状态
|
||||
state.id = userInfo.id
|
||||
state.username = userInfo.username
|
||||
state.name = userInfo.name
|
||||
state.role = userInfo.role
|
||||
state.permissions = userInfo.permissions || []
|
||||
state.loginStatus = true
|
||||
state.mod_game = userInfo.mod_game
|
||||
|
||||
// 兼容原有字段
|
||||
state.channel_id = userInfo.channel_id || 0
|
||||
state.channel_name = userInfo.channel_name || ''
|
||||
state.mobile = userInfo.mobile || ''
|
||||
state.login_time = userInfo.login_time || ''
|
||||
state.login_count = userInfo.login_count || 0
|
||||
state.login_ip = userInfo.login_ip || ''
|
||||
state.create_time = userInfo.create_time || ''
|
||||
state.mod_game = userInfo.mod_game || false
|
||||
state.roles = userInfo.roles || []
|
||||
|
||||
console.log('userInfo: ', userInfo)
|
||||
}
|
||||
@@ -60,24 +59,28 @@ const User = {
|
||||
mutations: {
|
||||
// 用户退出登录
|
||||
USER_LOGOUT(state) {
|
||||
state.id = 0
|
||||
state.channel_id = 0
|
||||
state.channel_name = ''
|
||||
state.username = ''
|
||||
state.name = ''
|
||||
state.mobile = ''
|
||||
state.login_time = ''
|
||||
state.login_count = 0
|
||||
state.login_ip = ''
|
||||
state.create_time = ''
|
||||
state.roles = []
|
||||
state.id = 0
|
||||
state.username = ''
|
||||
state.name = ''
|
||||
state.role = ''
|
||||
state.permissions = []
|
||||
state.loginStatus = false
|
||||
state.mod_game = false
|
||||
|
||||
// 原有字段重置
|
||||
state.channel_id = 0
|
||||
state.channel_name = ''
|
||||
state.mobile = ''
|
||||
state.login_time = ''
|
||||
state.login_count = 0
|
||||
state.login_ip = ''
|
||||
state.create_time = ''
|
||||
state.roles = []
|
||||
state.mod_game = false
|
||||
},
|
||||
|
||||
// 设置用户登录状态
|
||||
UPDATE_LOGIN_STATUS(state) {
|
||||
state.loginStatus = true
|
||||
UPDATE_LOGIN_STATUS(state, status) {
|
||||
state.loginStatus = status
|
||||
},
|
||||
|
||||
// 更新用户信息
|
||||
@@ -91,18 +94,20 @@ const User = {
|
||||
// 保存用户信息到缓存
|
||||
setUserInfo({
|
||||
id: state.id,
|
||||
channel_id: state.channel_id,
|
||||
channel_name: state.channel_name,
|
||||
username: state.username,
|
||||
name: state.name,
|
||||
role: state.role,
|
||||
permissions: state.permissions || [],
|
||||
// 兼容原有字段
|
||||
channel_id: state.channel_id,
|
||||
channel_name: state.channel_name,
|
||||
mobile: state.mobile,
|
||||
login_time: state.login_time,
|
||||
login_count: state.login_count,
|
||||
login_ip: state.login_ip,
|
||||
create_time: state.create_time,
|
||||
roles: state.roles ? state.roles: [],
|
||||
roles: state.roles || [],
|
||||
mod_game: state.mod_game,
|
||||
//avatar: state.avatar,
|
||||
})
|
||||
},
|
||||
},
|
||||
@@ -115,6 +120,25 @@ const User = {
|
||||
location.reload()
|
||||
})
|
||||
},
|
||||
|
||||
// 刷新令牌
|
||||
ACT_REFRESH_TOKEN({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
ServeRefreshToken()
|
||||
.then(res => {
|
||||
if (res.code === 200) {
|
||||
// 更新token
|
||||
setToken(res.data.token, res.data.token_expired - Math.floor(Date.now() / 1000))
|
||||
resolve(res)
|
||||
} else {
|
||||
reject(res)
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ const USER_SETTING = 'MANAGE_SETTING'
|
||||
/**
|
||||
* 设置用户授权token
|
||||
*
|
||||
* @param {String} token
|
||||
* @param {Number} expires
|
||||
* @param {String} token - JWT令牌
|
||||
* @param {Number} expires - 过期时间戳(秒)
|
||||
*/
|
||||
export function setToken(token, expires) {
|
||||
expires = new Date().getTime() + expires * 1000
|
||||
@@ -23,6 +23,7 @@ export function setToken(token, expires) {
|
||||
|
||||
/**
|
||||
* 获取授权token
|
||||
* @returns {String} token
|
||||
*/
|
||||
export function getToken() {
|
||||
const result = JSON.parse(
|
||||
@@ -33,9 +34,24 @@ export function getToken() {
|
||||
})
|
||||
)
|
||||
|
||||
// 检查token是否过期
|
||||
if (result.expires > 0 && result.expires < new Date().getTime()) {
|
||||
// token已过期,清除token
|
||||
removeAll()
|
||||
return ''
|
||||
}
|
||||
|
||||
return result.token
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否登录
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export function isLogin() {
|
||||
return !!getToken()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户信息
|
||||
*
|
||||
|
||||
@@ -39,7 +39,8 @@ const errorHandler = error => {
|
||||
request.interceptors.request.use(config => {
|
||||
const token = getToken()
|
||||
if (token) {
|
||||
config.headers['token'] = token
|
||||
// 设置JWT认证头
|
||||
config.headers['Authorization'] = 'Bearer ' + token
|
||||
}
|
||||
|
||||
return config
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { setToken } from '@/utils/auth'
|
||||
import { setToken, setUserInfo } from '@/utils/auth'
|
||||
import { ServeLogin } from '@/api/user'
|
||||
|
||||
export default {
|
||||
@@ -85,16 +85,24 @@ export default {
|
||||
let result = res.data
|
||||
|
||||
// 保存授权信息到本地缓存
|
||||
setToken(result.token, result.token_expired)
|
||||
setToken(result.token, result.token_expired - Math.floor(Date.now() / 1000))
|
||||
|
||||
// 保存用户信息到本地缓存
|
||||
setUserInfo(result.member)
|
||||
|
||||
this.$store.commit('UPDATE_USER_INFO', result.member)
|
||||
this.$store.commit('UPDATE_LOGIN_STATUS')
|
||||
this.$store.commit('UPDATE_LOGIN_STATUS', true)
|
||||
|
||||
// 登录成功后连接 WebSocket 服务器
|
||||
this.$notify.success({
|
||||
title: '成功',
|
||||
message: '登录成功',
|
||||
})
|
||||
|
||||
// 跳转到首页
|
||||
this.toLink('/')
|
||||
} else {
|
||||
this.$notify.info({
|
||||
title: '提示',
|
||||
this.$notify.error({
|
||||
title: '错误',
|
||||
message: res.msg,
|
||||
})
|
||||
}
|
||||
|
||||
247
Backend/src/views/device/detail.vue
Normal file
247
Backend/src/views/device/detail.vue
Normal file
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<el-container v-loading="loading" style="height: 100%;">
|
||||
<el-header style="display: flex; align-items: center; padding: 0;">
|
||||
<div style="margin-left: 20px;">
|
||||
<el-page-header @back="goBack" :content="'设备ID: ' + deviceId"></el-page-header>
|
||||
</div>
|
||||
</el-header>
|
||||
<el-main>
|
||||
<el-card v-if="deviceInfo" class="device-card">
|
||||
<div slot="header" class="card-header">
|
||||
<span>设备详情</span>
|
||||
<el-tag :type="getStatusType(deviceInfo.status)" class="status-tag">
|
||||
{{ getStatusText(deviceInfo.status) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">设备ID:</span>
|
||||
<span class="value">{{ deviceInfo.id }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">IMEI:</span>
|
||||
<span class="value">{{ deviceInfo.imei }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">设备手机号:</span>
|
||||
<span class="value">{{ deviceInfo.phone || '--' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">电量:</span>
|
||||
<span class="value">
|
||||
<el-progress
|
||||
:percentage="deviceInfo.battery"
|
||||
:color="getBatteryColor(deviceInfo.battery)"
|
||||
:format="() => `${deviceInfo.battery}%`"
|
||||
style="width: 200px;">
|
||||
</el-progress>
|
||||
</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">微信ID:</span>
|
||||
<span class="value">{{ deviceInfo.wechat_id || '--' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">微信号:</span>
|
||||
<span class="value">{{ deviceInfo.wechat_name || '--' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">分组名称:</span>
|
||||
<span class="value">{{ deviceInfo.group_name || '--' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">保管者:</span>
|
||||
<span class="value">{{ deviceInfo.username || '--' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<div class="info-item">
|
||||
<span class="label">备注:</span>
|
||||
<span class="value">{{ deviceInfo.remark || '--' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">创建时间:</span>
|
||||
<span class="value">{{ formatTime(deviceInfo.create_time) }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">更新时间:</span>
|
||||
<span class="value">{{ formatTime(deviceInfo.update_time) }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-empty v-else description="未找到设备信息"></el-empty>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 引入API请求
|
||||
import request from '@/utils/request'
|
||||
|
||||
export default {
|
||||
name: 'DeviceDetail',
|
||||
data() {
|
||||
return {
|
||||
// 设备ID
|
||||
deviceId: null,
|
||||
// 设备信息
|
||||
deviceInfo: null,
|
||||
// 加载状态
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 获取路由参数中的设备ID
|
||||
this.deviceId = this.$route.params.id
|
||||
// 加载设备详情
|
||||
this.getDeviceDetail()
|
||||
},
|
||||
methods: {
|
||||
// 返回列表页
|
||||
goBack() {
|
||||
this.$router.push('/device/index')
|
||||
},
|
||||
// 获取设备详情
|
||||
getDeviceDetail() {
|
||||
if (!this.deviceId) {
|
||||
this.$message.error('设备ID不能为空')
|
||||
return
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
request({
|
||||
url: `/api/devices/detail/${this.deviceId}`,
|
||||
method: 'get'
|
||||
}).then(res => {
|
||||
this.loading = false
|
||||
if (res.code === 200) {
|
||||
this.deviceInfo = res.data
|
||||
} else {
|
||||
this.$message.error(res.msg || '获取设备详情失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 格式化时间
|
||||
formatTime(timestamp) {
|
||||
if (!timestamp) return '--'
|
||||
const date = new Date(timestamp * 1000)
|
||||
const year = date.getFullYear()
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||
const day = date.getDate().toString().padStart(2, '0')
|
||||
const hour = date.getHours().toString().padStart(2, '0')
|
||||
const minute = date.getMinutes().toString().padStart(2, '0')
|
||||
const second = date.getSeconds().toString().padStart(2, '0')
|
||||
|
||||
return `${year}-${month}-${day} ${hour}:${minute}:${second}`
|
||||
},
|
||||
// 获取状态对应的类型
|
||||
getStatusType(status) {
|
||||
const statusMap = {
|
||||
'0': 'info', // 离线
|
||||
'1': 'success', // 在线
|
||||
'2': 'danger', // 故障
|
||||
'3': 'warning' // 维修中
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
},
|
||||
// 获取状态对应的文本
|
||||
getStatusText(status) {
|
||||
const statusMap = {
|
||||
'0': '离线',
|
||||
'1': '在线',
|
||||
'2': '故障',
|
||||
'3': '维修中'
|
||||
}
|
||||
return statusMap[status] || status
|
||||
},
|
||||
// 获取电量对应的颜色
|
||||
getBatteryColor(battery) {
|
||||
if (battery < 20) {
|
||||
return '#F56C6C' // 红色,电量低
|
||||
} else if (battery < 50) {
|
||||
return '#E6A23C' // 黄色,电量中等
|
||||
} else {
|
||||
return '#67C23A' // 绿色,电量充足
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-header {
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.device-card {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #606266;
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
min-width: 80px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #303133;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user