mirror of
https://gitee.com/xiongmao1988/rax-medical.git
synced 2025-08-23 20:44:58 +08:00
This commit is contained in:
parent
ac4a4fc26b
commit
5d3741e95a
|
@ -1,3 +1,10 @@
|
|||
/// <reference types="vite/client" />
|
||||
//解决ts文件引入vue文件出现红色警告问题
|
||||
declare module '*.vue' {
|
||||
import { defineComponent } from 'vue'
|
||||
const Component: ReturnType<typeof defineComponent>
|
||||
export default Component
|
||||
}
|
||||
/// <reference types="vite/client" />
|
||||
declare module 'element-plus/dist/locale/zh-cn.mjs'
|
||||
declare module 'mockjs'
|
|
@ -13,6 +13,7 @@
|
|||
"axios": "^1.3.3",
|
||||
"echarts": "^5.4.1",
|
||||
"element-plus": "2.3.1",
|
||||
"js-cookie": "^3.0.5",
|
||||
"pinia": "^2.1.7",
|
||||
"sass": "^1.58.3",
|
||||
"uuid": "^9.0.1",
|
||||
|
@ -22,7 +23,8 @@
|
|||
"xlsx": "^0.18.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.11.12",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/node": "^18.19.17",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
//用户管理模块的接口
|
||||
import request from '@/utils/request'
|
||||
import type {
|
||||
UserResponseData,
|
||||
User,
|
||||
AllRoleResponseData,
|
||||
SetRoleData,
|
||||
} from './type'
|
||||
//枚举地址
|
||||
enum API {
|
||||
//获取全部已有用户账号信息
|
||||
ALLUSER_URL = '/admin/acl/user/',
|
||||
//添加一个新的用户账号
|
||||
ADDUSER_URL = '/admin/acl/user/save',
|
||||
//更新已有的用户账号
|
||||
UPDATEUSER_URL = '/admin/acl/user/update',
|
||||
//获取全部职位,当前账号拥有的职位接口
|
||||
ALLROLEURL = '/admin/acl/user/toAssign/',
|
||||
//给已有的用户分配角色接口
|
||||
SETROLE_URL = '/admin/acl/user/doAssignRole',
|
||||
//删除某一个账号
|
||||
DELETEUSER_URL = '/admin/acl/user/remove/',
|
||||
//批量删除的接口
|
||||
DELETEALLUSER_URL = '/admin/acl/user/batchRemove',
|
||||
}
|
||||
//获取用户账号信息的接口
|
||||
export const reqUserInfo = (page: number, limit: number, username: string) =>
|
||||
request.get<any, UserResponseData>(
|
||||
API.ALLUSER_URL + `${page}/${limit}/?username=${username}`,
|
||||
)
|
||||
//添加用户与更新已有用户的接口
|
||||
export const reqAddOrUpdateUser = (data: User) => {
|
||||
//携带参数有ID更新
|
||||
if (data.id) {
|
||||
return request.put<any, any>(API.UPDATEUSER_URL, data)
|
||||
} else {
|
||||
return request.post<any, any>(API.ADDUSER_URL, data)
|
||||
}
|
||||
}
|
||||
//获取全部职位以及包含当前用户的已有的职位
|
||||
export const reqAllRole = (userId: number) =>
|
||||
request.get<any, AllRoleResponseData>(API.ALLROLEURL + userId)
|
||||
//分配职位
|
||||
export const reqSetUserRole = (data: SetRoleData) =>
|
||||
request.post<any, any>(API.SETROLE_URL, data)
|
||||
//删除某一个账号的信息
|
||||
export const reqRemoveUser = (userId: number) =>
|
||||
request.delete<any, any>(API.DELETEUSER_URL + userId)
|
||||
//批量删除的接口
|
||||
export const reqSelectUser = (idList: number[]) =>
|
||||
request.delete(API.DELETEALLUSER_URL, { data: idList })
|
||||
*/
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
//账号信息的ts类型
|
||||
export interface ResponseData {
|
||||
code: number
|
||||
message: string
|
||||
ok: boolean
|
||||
}
|
||||
//代表一个账号信息的ts类型
|
||||
export interface User {
|
||||
id?: number
|
||||
createTime?: string
|
||||
updateTime?: string
|
||||
username?: string
|
||||
password?: string
|
||||
name?: string
|
||||
phone?: null
|
||||
roleName?: string
|
||||
}
|
||||
//数组包含全部的用户信息
|
||||
export type Records = User[]
|
||||
//获取全部用户信息接口返回的数据ts类型
|
||||
export interface UserResponseData extends ResponseData {
|
||||
data: {
|
||||
records: Records
|
||||
total: number
|
||||
size: number
|
||||
current: number
|
||||
pages: number
|
||||
}
|
||||
}
|
||||
|
||||
//代表一个职位的ts类型
|
||||
export interface RoleData {
|
||||
id?: number
|
||||
createTime?: string
|
||||
updateTime?: string
|
||||
roleName: string
|
||||
remark: null
|
||||
}
|
||||
//全部职位的列表
|
||||
export type AllRole = RoleData[]
|
||||
//获取全部职位的接口返回的数据ts类型
|
||||
export interface AllRoleResponseData extends ResponseData {
|
||||
data: {
|
||||
assignRoles: AllRole
|
||||
allRolesList: AllRole
|
||||
}
|
||||
}
|
||||
|
||||
//给用户分配职位接口携带参数的ts类型
|
||||
export interface SetRoleData {
|
||||
roleIdList: number[]
|
||||
userId: number
|
||||
}
|
||||
*/
|
|
@ -1,9 +1,9 @@
|
|||
:root {
|
||||
--main-color: #006080;
|
||||
--main-color: #085a75;
|
||||
--el-color-primary: var(--main-color);
|
||||
--el-font-size-base: 16px;
|
||||
}
|
||||
$main-color: #006080;
|
||||
$main-color: #085a75;
|
||||
$red: #ea3323;
|
||||
$border-color: #EBEEF5;
|
||||
$border1-color: #E4E7ED;
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
<script setup lang="ts" name="global-websocket">
|
||||
import { ElNotification } from 'element-plus';
|
||||
import { Session } from '/@/utils/storage';
|
||||
|
||||
const emit = defineEmits(['rollback']);
|
||||
|
||||
const props = defineProps({
|
||||
uri: {
|
||||
type: String,
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
webSocket: ref(), // webSocket实例
|
||||
lockReconnect: false, // 重连锁,避免多次重连
|
||||
maxReconnect: 6, // 最大重连次数, -1 标识无限重连
|
||||
reconnectTime: 0, // 重连尝试次数
|
||||
heartbeat: {
|
||||
interval: 30 * 1000, // 心跳间隔时间
|
||||
timeout: 10 * 1000, // 响应超时时间
|
||||
pingTimeoutObj: ref(), // 延时发送心跳的定时器
|
||||
pongTimeoutObj: ref(), // 接收心跳响应的定时器
|
||||
pingMessage: JSON.stringify({ type: 'ping' }), // 心跳请求信息
|
||||
},
|
||||
});
|
||||
|
||||
const token = computed(() => {
|
||||
return Session.getToken();
|
||||
});
|
||||
|
||||
const tenant = computed(() => {
|
||||
return Session.getTenant();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
initWebSocket();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
state.webSocket.close();
|
||||
clearTimeoutObj(state.heartbeat);
|
||||
});
|
||||
|
||||
const initWebSocket = () => {
|
||||
// ws地址
|
||||
let host = window.location.host;
|
||||
// baseURL
|
||||
let baseURL = import.meta.env.VITE_API_URL;
|
||||
let wsUri = `ws://${host}${baseURL}${props.uri}?access_token=${token.value}&TENANT-ID=${tenant.value}`;
|
||||
// 建立连接
|
||||
state.webSocket = new WebSocket(wsUri);
|
||||
// 连接成功
|
||||
state.webSocket.onopen = onOpen;
|
||||
// 连接错误
|
||||
state.webSocket.onerror = onError;
|
||||
// 接收信息
|
||||
state.webSocket.onmessage = onMessage;
|
||||
// 连接关闭
|
||||
state.webSocket.onclose = onClose;
|
||||
};
|
||||
|
||||
const reconnect = () => {
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
if (state.lockReconnect || (state.maxReconnect !== -1 && state.reconnectTime > state.maxReconnect)) {
|
||||
return;
|
||||
}
|
||||
state.lockReconnect = true;
|
||||
setTimeout(() => {
|
||||
state.reconnectTime++;
|
||||
// 建立新连接
|
||||
initWebSocket();
|
||||
state.lockReconnect = false;
|
||||
}, 5000);
|
||||
};
|
||||
/**
|
||||
* 清空定时器
|
||||
*/
|
||||
const clearTimeoutObj = (heartbeat: any) => {
|
||||
heartbeat.pingTimeoutObj && clearTimeout(heartbeat.pingTimeoutObj);
|
||||
heartbeat.pongTimeoutObj && clearTimeout(heartbeat.pongTimeoutObj);
|
||||
};
|
||||
/**
|
||||
* 开启心跳
|
||||
*/
|
||||
const startHeartbeat = () => {
|
||||
const webSocket = state.webSocket;
|
||||
const heartbeat = state.heartbeat;
|
||||
// 清空定时器
|
||||
clearTimeoutObj(heartbeat);
|
||||
// 延时发送下一次心跳
|
||||
heartbeat.pingTimeoutObj = setTimeout(() => {
|
||||
// 如果连接正常
|
||||
if (webSocket.readyState === 1) {
|
||||
//这里发送一个心跳,后端收到后,返回一个心跳消息,
|
||||
webSocket.send(heartbeat.pingMessage);
|
||||
// 心跳发送后,如果服务器超时未响应则断开,如果响应了会被重置心跳定时器
|
||||
heartbeat.pongTimeoutObj = setTimeout(() => {
|
||||
webSocket.close();
|
||||
}, heartbeat.timeout);
|
||||
} else {
|
||||
// 否则重连
|
||||
reconnect();
|
||||
}
|
||||
}, heartbeat.interval);
|
||||
};
|
||||
|
||||
/**
|
||||
* 连接成功事件
|
||||
*/
|
||||
const onOpen = () => {
|
||||
//开启心跳
|
||||
startHeartbeat();
|
||||
state.reconnectTime = 0;
|
||||
};
|
||||
/**
|
||||
* 连接失败事件
|
||||
* @param e
|
||||
*/
|
||||
const onError = () => {
|
||||
//重连
|
||||
reconnect();
|
||||
};
|
||||
|
||||
/**
|
||||
* 连接关闭事件
|
||||
* @param e
|
||||
*/
|
||||
const onClose = () => {
|
||||
//重连
|
||||
reconnect();
|
||||
};
|
||||
/**
|
||||
* 接收服务器推送的信息
|
||||
* @param msgEvent
|
||||
*/
|
||||
const onMessage = (msgEvent: any) => {
|
||||
//收到服务器信息,心跳重置并发送
|
||||
startHeartbeat();
|
||||
const text = msgEvent.data;
|
||||
|
||||
if (text.indexOf('pong') > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ElNotification.warning({
|
||||
title: '消息提醒',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: text + '请及时处理',
|
||||
offset: 60,
|
||||
});
|
||||
|
||||
emit('rollback', text);
|
||||
};
|
||||
</script>
|
|
@ -78,16 +78,23 @@ const validatorPassword = (rule: any, value: any, callback: any) => {
|
|||
}
|
||||
|
||||
const validatorPhone = (rule: any, value: any, callback: any) => {
|
||||
if (value.length == 11) {
|
||||
callback();
|
||||
var isPhone = /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
|
||||
|
||||
|
||||
if (value.indexOf('****') >= 0) {
|
||||
return callback().trim();
|
||||
}
|
||||
|
||||
if (!isPhone.test(value)) {
|
||||
callback(new Error('请输入合法手机号'));
|
||||
} else {
|
||||
callback(new Error('手机号码长度为11位'));
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
const rules = reactive({
|
||||
phone: [
|
||||
{ required: true, validator:validatorPhone, trigger: 'change' },
|
||||
{ required: true, validator:validatorPhone, trigger: 'blur' },
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '请输入姓名', trigger: 'blur' },
|
||||
|
|
|
@ -8,6 +8,7 @@ import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
|||
import { ElDialog } from 'element-plus'
|
||||
import TableAbility from '@/components/table-ability.vue'
|
||||
|
||||
|
||||
import 'element-plus/dist/index.css';
|
||||
import './assets/css/global.scss';
|
||||
import './assets/font/iconfont.css';
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import type { CategoryObj } from '@/api/product/attr/type'
|
||||
//定义小仓库数据state类型
|
||||
export interface UserState {
|
||||
token: string | null
|
||||
menuRoutes: RouteRecordRaw[]
|
||||
username: string
|
||||
avatar: string
|
||||
buttons: string[]
|
||||
}
|
||||
|
||||
//定义分类仓库state对象的ts类型
|
||||
export interface CategoryState {
|
||||
c1Id: string | number
|
||||
c1Arr: CategoryObj[]
|
||||
c2Arr: CategoryObj[]
|
||||
c2Id: string | number
|
||||
c3Arr: CategoryObj[]
|
||||
c3Id: string | number
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
//创建用户相关的小仓库
|
||||
import { defineStore } from 'pinia'
|
||||
//引入接口
|
||||
import { reqLogin, reqUserInfo, reqLogout } from '@/api/user'
|
||||
import type {
|
||||
loginFormData,
|
||||
loginResponseData,
|
||||
userInfoReponseData,
|
||||
} from '@/api/user/type'
|
||||
import type { UserState } from './types/type'
|
||||
//引入操作本地存储的工具方法
|
||||
import { SET_TOKEN, GET_TOKEN, REMOVE_TOKEN } from '@/utils/token'
|
||||
//引入路由(常量路由)
|
||||
import { constantRoute, asnycRoute, anyRoute } from '@/router/routes'
|
||||
|
||||
//引入深拷贝方法
|
||||
//@ts-expect-error
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import router from '@/router'
|
||||
//用于过滤当前用户需要展示的异步路由
|
||||
function filterAsyncRoute(asnycRoute: any, routes: any) {
|
||||
return asnycRoute.filter((item: any) => {
|
||||
if (routes.includes(item.name)) {
|
||||
if (item.children && item.children.length > 0) {
|
||||
//硅谷333账号:product\trademark\attr\sku
|
||||
item.children = filterAsyncRoute(item.children, routes)
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//创建用户小仓库
|
||||
const useUserStore = defineStore('User', {
|
||||
//小仓库存储数据地方
|
||||
state: (): UserState => {
|
||||
return {
|
||||
token: GET_TOKEN(), //用户唯一标识token
|
||||
menuRoutes: constantRoute, //仓库存储生成菜单需要数组(路由)
|
||||
username: '',
|
||||
avatar: '',
|
||||
//存储当前用户是否包含某一个按钮
|
||||
buttons: [],
|
||||
}
|
||||
},
|
||||
//异步|逻辑的地方
|
||||
actions: {
|
||||
//用户登录的方法
|
||||
async userLogin(data: loginFormData) {
|
||||
//登录请求
|
||||
const result: loginResponseData = await reqLogin(data)
|
||||
//登录请求:成功200->token
|
||||
//登录请求:失败201->登录失败错误的信息
|
||||
if (result.code == 200) {
|
||||
//pinia仓库存储一下token
|
||||
//由于pinia|vuex存储数据其实利用js对象
|
||||
this.token = result.data as string
|
||||
//本地存储持久化存储一份
|
||||
SET_TOKEN(result.data as string)
|
||||
//能保证当前async函数返回一个成功的promise
|
||||
return 'ok'
|
||||
} else {
|
||||
return Promise.reject(new Error(result.data))
|
||||
}
|
||||
},
|
||||
//获取用户信息方法
|
||||
async userInfo() {
|
||||
//获取用户信息进行存储仓库当中[用户头像、名字]
|
||||
const result: userInfoReponseData = await reqUserInfo()
|
||||
//如果获取用户信息成功,存储一下用户信息
|
||||
if (result.code == 200) {
|
||||
this.username = result.data.name
|
||||
this.avatar = result.data.avatar
|
||||
this.buttons = result.data.buttons
|
||||
//计算当前用户需要展示的异步路由
|
||||
const userAsyncRoute = filterAsyncRoute(
|
||||
cloneDeep(asnycRoute),
|
||||
result.data.routes,
|
||||
)
|
||||
//菜单需要的数据整理完毕
|
||||
this.menuRoutes = [...constantRoute, ...userAsyncRoute, anyRoute]
|
||||
//目前路由器管理的只有常量路由:用户计算完毕异步路由、任意路由动态追加
|
||||
;[...userAsyncRoute, anyRoute].forEach((route: any) => {
|
||||
router.addRoute(route)
|
||||
})
|
||||
return 'ok'
|
||||
} else {
|
||||
return Promise.reject(new Error(result.message))
|
||||
}
|
||||
},
|
||||
//退出登录
|
||||
async userLogout() {
|
||||
//退出登录请求
|
||||
const result: any = await reqLogout()
|
||||
if (result.code == 200) {
|
||||
//目前没有mock接口:退出登录接口(通知服务器本地用户唯一标识失效)
|
||||
this.token = ''
|
||||
this.username = ''
|
||||
this.avatar = ''
|
||||
REMOVE_TOKEN()
|
||||
return 'ok'
|
||||
} else {
|
||||
return Promise.reject(new Error(result.message))
|
||||
}
|
||||
},
|
||||
},
|
||||
getters: {},
|
||||
})
|
||||
//对外暴露获取小仓库方法
|
||||
export default useUserStore
|
||||
*/
|
|
@ -1,4 +1,10 @@
|
|||
//进行axios二次封装:使用请求与响应拦截器
|
||||
import axios from "axios";
|
||||
/*
|
||||
import { ElMessage } from 'element-plus'
|
||||
//引入用户相关的仓库
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
*/
|
||||
|
||||
export const HOST = 'http://localhost:9999';
|
||||
const BASE_URL = import.meta.env.BASE_URL
|
||||
|
@ -30,3 +36,64 @@ export const getData = (url: string, params?: any) => {
|
|||
export const postData = (url: string, params?: any) => {
|
||||
return axios.post(url, params)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
//第一步:利用axios对象的create方法,去创建axios实例(其他的配置:基础路径、超时的时间)
|
||||
const request = axios.create({
|
||||
//基础路径
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API, //基础路径上会携带/api
|
||||
timeout: 5000, //超时的时间的设置
|
||||
})
|
||||
//第二步:request实例添加请求与响应拦截器
|
||||
request.interceptors.request.use((config) => {
|
||||
//获取用户相关的小仓库:获取仓库内部token,登录成功以后携带给服务器
|
||||
const userStore = useUserStore()
|
||||
if (userStore.token) {
|
||||
config.headers.token = userStore.token
|
||||
}
|
||||
//config配置对象,headers属性请求头,经常给服务器端携带公共参数
|
||||
//返回配置对象
|
||||
return config
|
||||
})
|
||||
|
||||
//第三步:响应拦截器
|
||||
request.interceptors.response.use(
|
||||
(response) => {
|
||||
//成功回调
|
||||
//简化数据
|
||||
return response.data
|
||||
},
|
||||
(error) => {
|
||||
//失败回调:处理http网络错误的
|
||||
//定义一个变量:存储网络错误信息
|
||||
let message = ''
|
||||
//http状态码
|
||||
const status = error.response.status
|
||||
switch (status) {
|
||||
case 401:
|
||||
message = 'TOKEN过期'
|
||||
break
|
||||
case 403:
|
||||
message = '无权访问'
|
||||
break
|
||||
case 404:
|
||||
message = '请求地址错误'
|
||||
break
|
||||
case 500:
|
||||
message = '服务器出现问题'
|
||||
break
|
||||
default:
|
||||
message = '网络出现问题'
|
||||
break
|
||||
}
|
||||
//提示错误信息
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message,
|
||||
})
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
//对外暴露
|
||||
export default request*/
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
/!**
|
||||
* window.localStorage 浏览器永久缓存
|
||||
* @method set 设置永久缓存
|
||||
* @method get 获取永久缓存
|
||||
* @method remove 移除永久缓存
|
||||
* @method clear 移除全部永久缓存
|
||||
*!/
|
||||
export const Local = {
|
||||
// 查看 v2.4.3版本更新日志
|
||||
setKey(key: string) {
|
||||
// @ts-ignore
|
||||
return `${__NEXT_NAME__}:${key}`;
|
||||
},
|
||||
// 设置永久缓存
|
||||
set<T>(key: string, val: T) {
|
||||
window.localStorage.setItem(Local.setKey(key), JSON.stringify(val));
|
||||
},
|
||||
// 获取永久缓存
|
||||
get(key: string) {
|
||||
let json = <string>window.localStorage.getItem(Local.setKey(key));
|
||||
return JSON.parse(json);
|
||||
},
|
||||
// 移除永久缓存
|
||||
remove(key: string) {
|
||||
window.localStorage.removeItem(Local.setKey(key));
|
||||
},
|
||||
// 移除全部永久缓存
|
||||
clear() {
|
||||
window.localStorage.clear();
|
||||
},
|
||||
};
|
||||
|
||||
/!**
|
||||
* window.sessionStorage 浏览器临时缓存
|
||||
* @method set 设置临时缓存
|
||||
* @method get 获取临时缓存
|
||||
* @method remove 移除临时缓存
|
||||
* @method clear 移除全部临时缓存
|
||||
*!/
|
||||
export const Session = {
|
||||
// 设置临时缓存
|
||||
set(key: string, val: any) {
|
||||
if (key === 'token' || key === 'refresh_token') {
|
||||
Cookies.set(key, val);
|
||||
}
|
||||
window.sessionStorage.setItem(key, JSON.stringify(val));
|
||||
},
|
||||
// 获取临时缓存
|
||||
get(key: string) {
|
||||
if (key === 'token' || key === 'refresh_token') return Cookies.get(key);
|
||||
let json = <string>window.sessionStorage.getItem(key);
|
||||
return JSON.parse(json);
|
||||
},
|
||||
// 移除临时缓存
|
||||
remove(key: string) {
|
||||
if (key === 'token' || key === 'refresh_token') return Cookies.remove(key);
|
||||
window.sessionStorage.removeItem(key);
|
||||
},
|
||||
// 移除全部临时缓存
|
||||
clear() {
|
||||
Cookies.remove('token');
|
||||
Cookies.remove('refresh_token');
|
||||
Cookies.remove('tenantId');
|
||||
window.sessionStorage.clear();
|
||||
},
|
||||
// 获取当前存储的 token
|
||||
getToken() {
|
||||
return this.get('token');
|
||||
},
|
||||
// 获取当前的租户
|
||||
getTenant() {
|
||||
return Local.get('tenantId') ? Local.get('tenantId') : 1;
|
||||
},
|
||||
};
|
||||
*/
|
|
@ -4,14 +4,20 @@ export const getTime = () => {
|
|||
//通过内置构造函数Date
|
||||
const hours = new Date().getHours()
|
||||
//情况的判断
|
||||
if (hours <= 9) {
|
||||
if (hours < 9) {
|
||||
message = '早上'
|
||||
} else if (hours <= 12) {
|
||||
} else if (hours < 12) {
|
||||
message = '上午'
|
||||
} else if (hours <= 18) {
|
||||
} else if (hours < 14) {
|
||||
message = '中午'
|
||||
} else if (hours < 17) {
|
||||
message = '下午'
|
||||
} else {
|
||||
} else if (hours < 19) {
|
||||
message = '傍晚'
|
||||
} else if (hours < 22) {
|
||||
message = '晚上'
|
||||
} else {
|
||||
message = '夜里'
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ import TimeBarChart from "./time-bar-chart.vue";
|
|||
import WeekCalendar from "./week-calendar.vue";
|
||||
import SystemLogs from "@/components/system-logs.vue";
|
||||
|
||||
|
||||
const router = useRouter()
|
||||
const userInfo = useLoginStore().getlogin()
|
||||
|
||||
|
|
|
@ -207,15 +207,16 @@ function fn1(res:any) {
|
|||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
|
||||
.menu-item {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 17px;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: $main-color;
|
||||
height: 70px;
|
||||
padding: 0 10px;
|
||||
padding: 0 15px;
|
||||
margin: 0;
|
||||
transition: all .5s;
|
||||
-webkit-transition: all .5s;
|
||||
|
|
|
@ -114,8 +114,8 @@
|
|||
<el-button type="primary" @click="register">注 册</el-button>
|
||||
<span @click="isShowRegister = false">已有账号?</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<SliderVerify v-model:isShowSelf="sliderVConf.isShowSelf" :width="sliderVConf.width" :imgUrl="sliderImgUrl"
|
||||
|
@ -123,6 +123,9 @@
|
|||
</template>
|
||||
|
||||
<script lang='ts' setup>
|
||||
import { ElNotification } from 'element-plus';
|
||||
//引入获取当前时间的函数
|
||||
import { getTime } from '@/utils/time';
|
||||
import {onMounted, reactive, ref, toRefs, watch} from 'vue'
|
||||
import {useRouter,useRoute} from 'vue-router'
|
||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||
|
@ -131,9 +134,8 @@ import {getHospitalsData, getPhoneAreasData} from '@/static-data/core'
|
|||
import {v4} from "uuid";
|
||||
import {HOST} from "@/utils/request";
|
||||
import SliderVerify from "@/components/SliderVerify/index.vue";
|
||||
import { ElNotification } from 'element-plus';
|
||||
//引入获取当前时间的函数
|
||||
import { getTime } from '@/utils/time';
|
||||
|
||||
|
||||
//引入用户相关的小仓库
|
||||
//import useUserStore from "@/stores/user-info-store";
|
||||
//let useStore = useUserStore();
|
||||
|
@ -171,11 +173,19 @@ const validatorPassword = (rule: any, value: any, callback: any) => {
|
|||
}
|
||||
|
||||
const validatorPhone = (rule: any, value: any, callback: any) => {
|
||||
if (value.length == 11) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error('手机号码长度为11位'));
|
||||
var isPhone = /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
|
||||
|
||||
|
||||
if (value.indexOf('****') >= 0) {
|
||||
return callback().trim();
|
||||
}
|
||||
|
||||
if (!isPhone.test(value)) {
|
||||
callback(new Error('请输入合法手机号'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const loginRules = reactive({
|
||||
|
@ -186,7 +196,7 @@ const loginRules = reactive({
|
|||
{ required: true, validator: validatorPassword, trigger: 'change' },
|
||||
],
|
||||
phone: [
|
||||
{ required: true, validator:validatorPhone, trigger: 'change' },
|
||||
{ required: true, validator:validatorPhone, trigger: 'blur' },
|
||||
],
|
||||
code: [
|
||||
{ required: true, message: '请输入验证码', trigger: 'blur' },
|
||||
|
@ -308,30 +318,33 @@ const login = async (type: string) => {
|
|||
if (valid) {
|
||||
// console.log('submit!')
|
||||
sliderVConf.value.isShowSelf = true
|
||||
|
||||
} else {
|
||||
// console.log('error submit!', fields)
|
||||
}
|
||||
|
||||
//加载效果:开始加载
|
||||
loading.value = true;
|
||||
|
||||
/*try {
|
||||
//保证登录成功
|
||||
await useStore.userLogin(loginFormRef);
|
||||
|
||||
}*/
|
||||
|
||||
//编程式导航跳转到展示数据首页
|
||||
//判断登录的时候,路由路径当中是否有query参数,如果有就往query参数挑战,没有跳转到首页
|
||||
let redirect: any = $route.query.redirect;
|
||||
$router.push({ path: redirect || '/' });
|
||||
//登录成功提示信息
|
||||
ElNotification({
|
||||
type: 'success',
|
||||
message: '欢迎回来',
|
||||
title: `HI,${getTime()}好`
|
||||
});
|
||||
|
||||
/*try {
|
||||
//保证登录成功
|
||||
await useStore.userLogin(loginFormRef);
|
||||
//编程式导航跳转到展示数据首页
|
||||
//判断登录的时候,路由路径当中是否有query参数,如果有就往query参数挑战,没有跳转到首页
|
||||
let redirect: any = $route.query.redirect;
|
||||
$router.push({ path: redirect || '/' });
|
||||
|
||||
//登录成功加载效果也消失
|
||||
loading.value = false;
|
||||
}*/
|
||||
|
||||
|
||||
/*} catch (error) {
|
||||
//登录失败加载效果消息
|
||||
loading.value = false;
|
||||
|
@ -342,6 +355,8 @@ const login = async (type: string) => {
|
|||
})*/
|
||||
|
||||
})
|
||||
//登录成功加载效果也消失
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
function getCaptchaCode() {
|
||||
|
@ -395,7 +410,6 @@ const toHome = () => {
|
|||
background: url(@/assets/imgs/login/login_bck.png) no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.right-content {
|
||||
position: relative;
|
||||
width: 50%;
|
||||
|
@ -407,8 +421,8 @@ const toHome = () => {
|
|||
|
||||
.select-hospital-box {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
right: 50px;
|
||||
top: 25px;
|
||||
right: 25px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
@ -535,5 +549,6 @@ const toHome = () => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -31,10 +31,10 @@ function initChart(chartData: any) {
|
|||
}
|
||||
},
|
||||
grid: {
|
||||
left: 20,
|
||||
left: 30,
|
||||
right: 50,
|
||||
bottom: 5,
|
||||
top: 20,
|
||||
top: 50,
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
|
@ -50,6 +50,7 @@ function initChart(chartData: any) {
|
|||
data: chartData.xData,
|
||||
},
|
||||
yAxis: {
|
||||
name: '数量',
|
||||
show: true,
|
||||
type: 'value',
|
||||
min: 0,
|
||||
|
@ -62,6 +63,7 @@ function initChart(chartData: any) {
|
|||
type: 'line',
|
||||
symbol: 'none',
|
||||
smooth: true,
|
||||
color: 'rgb(0, 96, 128)',
|
||||
showSymbol: false,
|
||||
lineStyle: {
|
||||
color: 'rgb(0, 96, 128)',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="table-page custom-table-table">
|
||||
<h3 class="main-color" style="font-size: 30px;line-height: 1;padding: 10px 0;">近30天登陆汇总</h3>
|
||||
<h3 class="main-color" style="font-size: 25px;line-height: 1;padding: 8px 0;">近30天登陆汇总</h3>
|
||||
<div style="width: 100%;height: 35%;">
|
||||
<LoginChart />
|
||||
</div>
|
||||
|
|
|
@ -64,6 +64,22 @@ const roleOption = [
|
|||
{ label: '中级管理员', value: '中级管理员' },
|
||||
{ label: '高级管理员', value: '高级管理员' },
|
||||
]
|
||||
|
||||
const validatorPhone = (rule: any, value: any, callback: any) => {
|
||||
var isPhone = /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/;
|
||||
|
||||
|
||||
if (value.indexOf('****') >= 0) {
|
||||
return callback().trim();
|
||||
}
|
||||
if (!isPhone.test(value)) {
|
||||
callback(new Error('请输入合法手机号'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const rules = reactive({
|
||||
userName: [
|
||||
{ required: true, message: '请输入用户名', trigger: ['blur', 'change'] },
|
||||
|
@ -75,7 +91,7 @@ const rules = reactive({
|
|||
{ required: true, message: '请选择角色', trigger: ['blur', 'change'] },
|
||||
],
|
||||
phone: [
|
||||
{ required: true, message: '请输入电话', trigger: ['blur', 'change'] },
|
||||
{ required: true, validator:validatorPhone, trigger: ['blur', 'change'] },
|
||||
],
|
||||
})
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ const breakRemote = () => {
|
|||
.input-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&>span {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
|
|
@ -254,8 +254,8 @@ $size: 20px;
|
|||
}
|
||||
|
||||
.right-box .value {
|
||||
color: #f8b300;
|
||||
border-color: #f8b300;
|
||||
color: $main-color;
|
||||
border-color: $main-color;
|
||||
}
|
||||
|
||||
.row-item.alarm {
|
||||
|
@ -341,12 +341,12 @@ $size: 20px;
|
|||
|
||||
.row-item.yellow {
|
||||
.label {
|
||||
background: #f8b300;
|
||||
background: $main-color;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #f8b300;
|
||||
border-color: #f8b300;
|
||||
color: $main-color;
|
||||
border-color: $main-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,7 +242,7 @@ const breakRemote = () => {
|
|||
.right-box {
|
||||
@extend .common-box;
|
||||
.label {
|
||||
background: #f8b300;
|
||||
background: $main-color;
|
||||
}
|
||||
}
|
||||
.row-item {
|
||||
|
@ -288,8 +288,8 @@ const breakRemote = () => {
|
|||
}
|
||||
}
|
||||
.right-box .value {
|
||||
color: #f8b300;
|
||||
border-color: #f8b300;
|
||||
color: $main-color;
|
||||
border-color: $main-color;
|
||||
}
|
||||
.row-item.alarm {
|
||||
.label {
|
||||
|
@ -361,11 +361,11 @@ const breakRemote = () => {
|
|||
}
|
||||
.row-item.yellow {
|
||||
.label {
|
||||
background: #f8b300;
|
||||
background: $main-color;
|
||||
}
|
||||
.value {
|
||||
color: #f8b300;
|
||||
border-color: #f8b300;
|
||||
color:$main-color;
|
||||
border-color: $main-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,6 @@ onMounted(() => {
|
|||
.main-box {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
height: calc(100% - 60px);
|
||||
background: white;
|
||||
padding: 20px;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user