新增账户管理页面,修复一些问题
This commit is contained in:
parent
914dc61571
commit
5028451710
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -49,3 +49,4 @@ pnpm*
|
||||||
#auto-imports.d.ts
|
#auto-imports.d.ts
|
||||||
#components.d.ts
|
#components.d.ts
|
||||||
stats.html
|
stats.html
|
||||||
|
ts-out-dir
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
"useConfigStore": true,
|
"useConfigStore": true,
|
||||||
"useCssModule": true,
|
"useCssModule": true,
|
||||||
"useCssVars": true,
|
"useCssVars": true,
|
||||||
|
"useDebuggerStore": true,
|
||||||
"useElement": true,
|
"useElement": true,
|
||||||
"useErrorLog": true,
|
"useErrorLog": true,
|
||||||
"useLink": true,
|
"useLink": true,
|
||||||
|
|
|
@ -44,7 +44,7 @@ export default [
|
||||||
{
|
{
|
||||||
order_no: '@guid()',
|
order_no: '@guid()',
|
||||||
timestamp: +Mock.Random.date('T'),
|
timestamp: +Mock.Random.date('T'),
|
||||||
userName: '@name()',
|
username: '@name()',
|
||||||
price: '@float(1000, 15000, 0, 2)',
|
price: '@float(1000, 15000, 0, 2)',
|
||||||
'status|1': ['success', 'pending']
|
'status|1': ['success', 'pending']
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ export function getList(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/role/queryRoleByPage',
|
url: '/role/queryRoleByPage',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,14 +12,14 @@ export function doAdd(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/role/create',
|
url: '/role/create',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export function doUpdate(data) {
|
export function doUpdate(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/role/update',
|
url: '/role/update',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ export function doDelete(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/role/destroy',
|
url: '/role/destroy',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +37,7 @@ export function doDelete(data) {
|
||||||
export function getRoleList() {
|
export function getRoleList() {
|
||||||
return request({
|
return request({
|
||||||
url: '/role/list',
|
url: '/role/list',
|
||||||
method: 'get',
|
method: 'post'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,9 +47,9 @@ export function getRoleList() {
|
||||||
export function getRoleByUserId(userId) {
|
export function getRoleByUserId(userId) {
|
||||||
return request({
|
return request({
|
||||||
url: '/userRole/getByUserId',
|
url: '/userRole/getByUserId',
|
||||||
method: 'get',
|
method: 'post',
|
||||||
params: {
|
data: {
|
||||||
userId,
|
userId
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//获取用户信息
|
//获取用户信息
|
||||||
import { post } from '@/utils/request'
|
import { post } from '@/utils/request'
|
||||||
|
|
||||||
export interface IUser {
|
export interface IUser {
|
||||||
id: string
|
id: string
|
||||||
userName: string
|
userName: string
|
||||||
|
@ -36,3 +37,12 @@ export async function login(data): Promise<IUser> {
|
||||||
export async function logout(): Promise<void> {
|
export async function logout(): Promise<void> {
|
||||||
return post('/logout')
|
return post('/logout')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按照文本搜索前十条用户
|
||||||
|
* @param keys
|
||||||
|
* @return {Promise<any[]>}
|
||||||
|
*/
|
||||||
|
export function userSearching(keys) {
|
||||||
|
return post('user/searching', { keys })
|
||||||
|
}
|
||||||
|
|
42
src/api/userManagement.ts
Normal file
42
src/api/userManagement.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getList(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/list',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doEdit(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/edit',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doCreate(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/create',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDelete(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/delete',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询学生信息
|
||||||
|
export function getStudentInfoByStudentId(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/getStudentInfoByStudentId',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
|
@ -30,14 +30,14 @@
|
||||||
<!-- <SizeSelect />-->
|
<!-- <SizeSelect />-->
|
||||||
<!-- <LangSelect />-->
|
<!-- <LangSelect />-->
|
||||||
<el-dropdown trigger="click" size="medium">
|
<el-dropdown trigger="click" size="medium">
|
||||||
<div class="avatar-wrapper" :title="(userInfo?.realName || userInfo?.userName) + ' - 在线'">
|
<div class="avatar-wrapper" :title="(userInfo?.realName || userInfo?.username) + ' - 在线'">
|
||||||
<img :src="userInfo.avatar ?? userImage" alt="用户头像" class="user-avatar" />
|
<img :src="userInfo.avatar ?? userImage" alt="用户头像" class="user-avatar" />
|
||||||
<div class="user-avatar-status" />
|
<div class="user-avatar-status" />
|
||||||
</div>
|
</div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu class="drop-down">
|
<el-dropdown-menu class="drop-down">
|
||||||
<el-dropdown-item class="welcome-user">
|
<el-dropdown-item class="welcome-user">
|
||||||
{{ time }}好,<b>{{ userInfo.realName || userImage.userName || "平台用户" }}</b>
|
{{ time }}好,<b>{{ userInfo.realName || userImage.username || "平台用户" }}</b>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<el-dropdown-item divided>{{ langTitle("Home") }}</el-dropdown-item>
|
<el-dropdown-item divided>{{ langTitle("Home") }}</el-dropdown-item>
|
||||||
|
|
34
src/layout/app-main/component/Debugger.vue
Normal file
34
src/layout/app-main/component/Debugger.vue
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<div class="debugger" title="调试器">
|
||||||
|
<el-button class="btn" type="primary" link @click="data.dialog = true">
|
||||||
|
<menu-icon icon="bug-fill" />
|
||||||
|
</el-button>
|
||||||
|
<el-dialog v-model="data.dialog" :append-to-body="true" title="Debugger" :width="600">
|
||||||
|
<div>
|
||||||
|
显示调试网格
|
||||||
|
<el-switch v-model="showLayoutGrid" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<div v-if="showLayoutGrid" v-html="data.gridHtml" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import MenuIcon from "@/layout/sidebar/MenuIcon.vue";
|
||||||
|
import { useDebuggerStore } from "@/store/debuger";
|
||||||
|
|
||||||
|
const store = useDebuggerStore()
|
||||||
|
const {showLayoutGrid} = storeToRefs(store)
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
dialog: false,
|
||||||
|
gridHtml: `<style>*{ box-shadow: 0 0 1px 0 blue }</style>`
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.btn{
|
||||||
|
padding: 0.3em !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -11,7 +11,7 @@ export const useBasicStore = defineStore('basic', {
|
||||||
token: '',
|
token: '',
|
||||||
getUserInfo: false,
|
getUserInfo: false,
|
||||||
userInfo: {
|
userInfo: {
|
||||||
userName: '',
|
username: '',
|
||||||
realName: '',
|
realName: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
|
@ -72,7 +72,7 @@ export const useBasicStore = defineStore('basic', {
|
||||||
state.filterAsyncRoutes = []
|
state.filterAsyncRoutes = []
|
||||||
//reset userInfo
|
//reset userInfo
|
||||||
state.userInfo = {
|
state.userInfo = {
|
||||||
userName: '',
|
username: '',
|
||||||
realName: '',
|
realName: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
|
|
18
src/store/debuger.ts
Normal file
18
src/store/debuger.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
|
export const useDebuggerStore = defineStore('debugger',{
|
||||||
|
state(){
|
||||||
|
return {
|
||||||
|
showLayoutGrid: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
persist:{
|
||||||
|
storage: localStorage,
|
||||||
|
paths: ['showLayoutGrid']
|
||||||
|
},
|
||||||
|
actions:{
|
||||||
|
setShowLayoutGrid(value){
|
||||||
|
this.showLayoutGrid = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
337
src/utils/validate.ts
Normal file
337
src/utils/validate.ts
Normal file
|
@ -0,0 +1,337 @@
|
||||||
|
/**
|
||||||
|
* @description 判读是否为外链
|
||||||
|
* @param path
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isExternal(path) {
|
||||||
|
return /^(https?:|mailto:|tel:)/.test(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 校验密码是否小于6位
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isPassword(str) {
|
||||||
|
return str.length >= 6
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否为数字
|
||||||
|
* @param value
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isNumber(value) {
|
||||||
|
const reg = /^[0-9]*$/
|
||||||
|
return reg.test(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是名称
|
||||||
|
* @param value
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isName(value) {
|
||||||
|
const reg = /^[\u4E00-\u9FA5a-zA-Z0-9]+$/
|
||||||
|
return reg.test(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否为IP
|
||||||
|
* @param ip
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isIP(ip) {
|
||||||
|
const reg =
|
||||||
|
/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
|
||||||
|
return reg.test(ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是传统网站
|
||||||
|
* @param url
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isUrl(url) {
|
||||||
|
const reg =
|
||||||
|
/^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
|
||||||
|
return reg.test(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是小写字母
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isLowerCase(str) {
|
||||||
|
const reg = /^[a-z]+$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是大写字母
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isUpperCase(str) {
|
||||||
|
const reg = /^[A-Z]+$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是大写字母开头
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isAlphabets(str) {
|
||||||
|
const reg = /^[A-Za-z]+$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是字符串
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isString(str) {
|
||||||
|
return typeof str === 'string' || str instanceof String
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是数组
|
||||||
|
* @param arg
|
||||||
|
* @returns {arg is any[]|boolean}
|
||||||
|
*/
|
||||||
|
export function isArray(arg) {
|
||||||
|
if (typeof Array.isArray === 'undefined') {
|
||||||
|
return Object.prototype.toString.call(arg) === '[object Array]'
|
||||||
|
}
|
||||||
|
return Array.isArray(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是数组
|
||||||
|
* @param arg
|
||||||
|
* @returns {arg is any[]|boolean}
|
||||||
|
*/
|
||||||
|
export function isObject(arg) {
|
||||||
|
return Object.prototype.toString.call(arg) === '[object Object]'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是端口号
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isPort(str) {
|
||||||
|
const reg =
|
||||||
|
/^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是手机号
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isPhone(str) {
|
||||||
|
const reg = /^1\d{10}$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是身份证号(第二代)
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isIdCard(str) {
|
||||||
|
const reg =
|
||||||
|
/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否是邮箱
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isEmail(str) {
|
||||||
|
const reg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否中文
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isChina(str) {
|
||||||
|
const reg = /^[\u4E00-\u9FA5]{2,4}$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否为空
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isBlank(str) {
|
||||||
|
return (
|
||||||
|
str == null ||
|
||||||
|
false ||
|
||||||
|
str === '' ||
|
||||||
|
str.trim() === '' ||
|
||||||
|
str.toLocaleLowerCase().trim() === 'null'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否为固话
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isTel(str) {
|
||||||
|
const reg =
|
||||||
|
/^(400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})(-| )?)?([0-9]{7,8})((-| |转)*([0-9]{1,4}))?$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 判断是否为数字且最多两位小数
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isNum(str) {
|
||||||
|
const reg = /^\d+(\.\d{1,2})?$/
|
||||||
|
return reg.test(str)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 检验18位身份证号码
|
||||||
|
* @param cid 18为的身份证号码
|
||||||
|
* @return Boolean 是否有效
|
||||||
|
**/
|
||||||
|
export function isIdentityNumber(cid) {
|
||||||
|
const arrExp = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] //加权因子
|
||||||
|
const arrValid = '1 0 X 9 8 7 6 5 4 3 2'.split(' ') //校检码
|
||||||
|
if (/^\d{17}\d|x$/i.test(cid)) {
|
||||||
|
let sum = 0
|
||||||
|
for (let i = 0; i < cid.length - 1; i++) {
|
||||||
|
// 对前17位数字与权值乘积求和
|
||||||
|
sum += Number.parseInt(cid.substr(i, 1), 10) * arrExp[i]
|
||||||
|
}
|
||||||
|
// 计算模(固定算法)
|
||||||
|
const idx = sum % 11
|
||||||
|
// 检验第18为是否与校验码相等
|
||||||
|
return arrValid[idx] === cid.slice(17, 18).toUpperCase()
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* EL表单检测
|
||||||
|
* @author 一七年夏
|
||||||
|
*/
|
||||||
|
export class ElValidate {
|
||||||
|
/**
|
||||||
|
* 创建一个空值检查 Validate
|
||||||
|
* @param canEmpty {boolean | string} 是否可空,或非空提示文本
|
||||||
|
* @param validate {[any]} Validate列表
|
||||||
|
* @return {[any]}
|
||||||
|
*/
|
||||||
|
static createValidate(canEmpty, validate) {
|
||||||
|
if (isString(canEmpty) || (typeof canEmpty == 'boolean' && canEmpty)) {
|
||||||
|
validate.forEach((v) => {
|
||||||
|
v.required = undefined
|
||||||
|
const va = v.validator
|
||||||
|
v.validator = function (a, b, c) {
|
||||||
|
if (!b) c()
|
||||||
|
else va(a, b, c)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return validate
|
||||||
|
} else {
|
||||||
|
validate.push({
|
||||||
|
required: true,
|
||||||
|
trigger: 'blur',
|
||||||
|
message: isString(canEmpty) ? canEmpty : '请输入文本',
|
||||||
|
})
|
||||||
|
return validate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取是否是手机号的表单验证对象数组
|
||||||
|
* @return {[any]}
|
||||||
|
*/
|
||||||
|
static getIsPhoneRule(canEmpty = false) {
|
||||||
|
return this.createValidate(canEmpty ? '请输入手机号' : false, [
|
||||||
|
{
|
||||||
|
trigger: 'blur',
|
||||||
|
message: '请输入有效的手机号',
|
||||||
|
validator (rule, value, callback) {
|
||||||
|
if (/^1[3456789]\d{9}$/g.test(value)) callback()
|
||||||
|
else callback(new Error('无效的手机号'))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取是否是身份证号的表单验证数组
|
||||||
|
* @return {[any]}
|
||||||
|
*/
|
||||||
|
static getIsIdentityNumberRule(canEmpty = false) {
|
||||||
|
return this.createValidate(canEmpty ? '请输入身份证号' : false, [
|
||||||
|
{
|
||||||
|
trigger: 'blur',
|
||||||
|
message: '请输入有效的身份证号',
|
||||||
|
validator (rule, value, callback) {
|
||||||
|
if (isIdentityNumber(value)) {
|
||||||
|
callback()
|
||||||
|
} else {
|
||||||
|
callback(new Error('无效的身份证号'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取限制文本长度的的表单验证数组
|
||||||
|
* @param canEmpty 是否允许空文本
|
||||||
|
* @param max 最大长度,“-1”为无限制
|
||||||
|
* @param min 最小长度,默认为“0”
|
||||||
|
* @return {[any]}
|
||||||
|
*/
|
||||||
|
static getLengthLimitRule(canEmpty = false, max = -1, min = 0) {
|
||||||
|
let lint = `文本长度应在${min}到${max}之间`
|
||||||
|
if (min <= 0) lint = `最大输入${max}个字`
|
||||||
|
else if (max >= -1) lint = `最少输入${min}个字`
|
||||||
|
return this.createValidate(canEmpty ? '请输入文本' : false, [
|
||||||
|
{
|
||||||
|
trigger: 'change',
|
||||||
|
message: lint,
|
||||||
|
validator (rule, value, callback) {
|
||||||
|
if (value.length < min) {
|
||||||
|
callback(new Error(`输入文本太短,最少长度为${min}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (max > -1 && value.length > max) {
|
||||||
|
callback(`输入文本太长,最长长度为${max}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否为空字符串的表单验证数组
|
||||||
|
* @param str 检查失败时显示的文本
|
||||||
|
* @return {[any]}
|
||||||
|
*/
|
||||||
|
static getIsEmptyRule(str = '请输入文本') {
|
||||||
|
return [{ required: true, trigger: 'blur', message: str }]
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
<span class="svg-container">
|
<span class="svg-container">
|
||||||
<ElSvgIcon name="User" :size="14" />
|
<ElSvgIcon name="User" :size="14" />
|
||||||
</span>
|
</span>
|
||||||
<el-input v-model="subForm.userName" placeholder="用户名" />
|
<el-input v-model="subForm.username" placeholder="用户名" />
|
||||||
<!--占位-->
|
<!--占位-->
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="password" :rules="formRules.isNotNull('密码')">
|
<el-form-item prop="password" :rules="formRules.isNotNull('密码')">
|
||||||
|
@ -47,6 +47,7 @@ import { elMessage, useElement } from "@/hooks/use-element";
|
||||||
import { getMyRole, login } from "@/api/user";
|
import { getMyRole, login } from "@/api/user";
|
||||||
import type { FormInstance, InputInstance } from "element-plus";
|
import type { FormInstance, InputInstance } from "element-plus";
|
||||||
import { settings as viteSettings } from "@/settings";
|
import { settings as viteSettings } from "@/settings";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
/* listen router change and set the query */
|
/* listen router change and set the query */
|
||||||
const { settings } = useBasicStore();
|
const { settings } = useBasicStore();
|
||||||
|
@ -54,7 +55,7 @@ const { settings } = useBasicStore();
|
||||||
const formRules = useElement().formRules;
|
const formRules = useElement().formRules;
|
||||||
//form
|
//form
|
||||||
const subForm = reactive({
|
const subForm = reactive({
|
||||||
userName: "",
|
username: "",
|
||||||
password: ""
|
password: ""
|
||||||
});
|
});
|
||||||
const state: any = reactive({
|
const state: any = reactive({
|
||||||
|
@ -94,8 +95,13 @@ const refLoginForm: FormInstance = $ref(null);
|
||||||
|
|
||||||
function handleLogin() {
|
function handleLogin() {
|
||||||
refLoginForm.validate((valid) => {
|
refLoginForm.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
subLoading = true;
|
subLoading = true;
|
||||||
if (valid) loginFunc();
|
loginFunc();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ElMessage.error("请检查输入是否正确")
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,264 @@
|
||||||
|
<template>
|
||||||
|
<el-drawer v-model="drawer" :title="title" :before-close="close">
|
||||||
|
<div v-loading="loading" class="drawer__content">
|
||||||
|
<el-form
|
||||||
|
ref="form"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
label-width="80px"
|
||||||
|
:disabled="detail"
|
||||||
|
size="default"
|
||||||
|
>
|
||||||
|
<el-form-item label="姓名" prop="realName">
|
||||||
|
<el-popover
|
||||||
|
v-model="searchShow"
|
||||||
|
:trigger="title === '新增' ? 'hover' : ''"
|
||||||
|
:width="300"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-input
|
||||||
|
v-model.trim="form.realName"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<el-table
|
||||||
|
:data="searchTable"
|
||||||
|
size="small"
|
||||||
|
:show-header="false"
|
||||||
|
@row-click="selectItem"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
property="realName"
|
||||||
|
label="姓名"
|
||||||
|
:width="100"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
property="userName"
|
||||||
|
label="账号"
|
||||||
|
:width="200"
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
</el-popover>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号" prop="phone">
|
||||||
|
<el-input v-model.trim="form.phone" autocomplete="off"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户账号" prop="userName">
|
||||||
|
<el-input
|
||||||
|
:value="form.userName"
|
||||||
|
autocomplete="off"
|
||||||
|
readonly
|
||||||
|
placeholder="与手机号相同"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<!--<el-form-item label="密码" prop="password">-->
|
||||||
|
<!-- <el-input-->
|
||||||
|
<!-- v-model.trim="form.password"-->
|
||||||
|
<!-- type="password"-->
|
||||||
|
<!-- autocomplete="off"-->
|
||||||
|
<!-- ></el-input>-->
|
||||||
|
<!-- </el-form-item>-->
|
||||||
|
<el-form-item label="角色" prop="roleId">
|
||||||
|
<el-radio-group v-model="form.roleId">
|
||||||
|
<el-radio v-for="item in roleList" :key="item.id" :label="item.id">
|
||||||
|
{{ item.roleName }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态" prop="isUse">
|
||||||
|
<el-radio-group v-model="form.isUse">
|
||||||
|
<el-radio :label="1">正常</el-radio>
|
||||||
|
<el-radio :label="0">禁用</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div v-show="!detail" class="drawer__footer">
|
||||||
|
<el-button size="default" @click="close">取 消</el-button>
|
||||||
|
<el-button size="default" type="primary" @click="save">确 定</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { doCreate, doEdit } from '@/api/userManagement'
|
||||||
|
import { getRoleByUserId, getRoleList } from '@/api/roleManagement'
|
||||||
|
import { isPhone } from '@/utils/validate'
|
||||||
|
import { userSearching } from '@/api/user'
|
||||||
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
export default {
|
||||||
|
name: 'UserManagementEdit',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
password: '',
|
||||||
|
phone: '',
|
||||||
|
realName: '',
|
||||||
|
userName: undefined,
|
||||||
|
roleId: '',
|
||||||
|
isUse: 1,
|
||||||
|
},
|
||||||
|
editForm: {},
|
||||||
|
rules: {
|
||||||
|
password: [
|
||||||
|
{ required: false, trigger: 'blur', message: '请输入密码' },
|
||||||
|
],
|
||||||
|
phone: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
if (!isPhone(value)) {
|
||||||
|
callback(new Error('请输入正确的手机号'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
realName: [
|
||||||
|
{ required: true, trigger: 'blur', message: '请输入姓名' },
|
||||||
|
],
|
||||||
|
roleId: [{ required: true, trigger: 'blur', message: '请选择角色' }],
|
||||||
|
},
|
||||||
|
title: '',
|
||||||
|
loading: false,
|
||||||
|
drawer: false,
|
||||||
|
detail: false,
|
||||||
|
roleList: [],
|
||||||
|
searchTable: [],
|
||||||
|
searchWaiter: 0,
|
||||||
|
searchShow: false,
|
||||||
|
formChanging: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'form.realName': function(value) {
|
||||||
|
const key = Math.random()
|
||||||
|
this.searchWaiter = key
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (this.searchWaiter !== key) return
|
||||||
|
try {
|
||||||
|
this.searchTable = await userSearching(value)
|
||||||
|
} catch {}
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
'form.phone': function() {
|
||||||
|
if (this.formChanging) return
|
||||||
|
this.form.userName = undefined
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showEdit(row, detail) {
|
||||||
|
this.loading = true
|
||||||
|
this.formChanging = true
|
||||||
|
if (!row) {
|
||||||
|
this.title = '新增'
|
||||||
|
} else {
|
||||||
|
this.title = detail ? '查看' : '编辑'
|
||||||
|
this.detail = detail
|
||||||
|
this.form = Object.assign({}, row)
|
||||||
|
// 记录有没有编辑过的form
|
||||||
|
this.editForm = JSON.parse(JSON.stringify(this.form))
|
||||||
|
this.getRole()
|
||||||
|
}
|
||||||
|
this.drawer = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.loading = false
|
||||||
|
this.formChanging = false
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
close(confirm) {
|
||||||
|
let formChanged = false
|
||||||
|
// 判断抽屉是否被编辑过
|
||||||
|
if (this.title === '新增') {
|
||||||
|
formChanged = !(
|
||||||
|
JSON.stringify(this.form) ===
|
||||||
|
JSON.stringify(this.$options.data().form)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
formChanged = !(
|
||||||
|
JSON.stringify(this.form) === JSON.stringify(this.editForm)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (confirm && formChanged && this.title !== '查看') {
|
||||||
|
ElMessageBox.confirm(
|
||||||
|
'编辑数据将会清空,确认退出?',
|
||||||
|
'请仔细确认'
|
||||||
|
).then(() => this.closeEdit(), () => {})
|
||||||
|
} else {
|
||||||
|
this.closeEdit()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectItem(item) {
|
||||||
|
this.formChanging = true
|
||||||
|
this.form.phone = item.phone
|
||||||
|
this.form.userName = item.userName
|
||||||
|
this.form.realName = item.realName
|
||||||
|
this.searchShow = false
|
||||||
|
this.$nextTick(() => (this.formChanging = false))
|
||||||
|
},
|
||||||
|
closeEdit() {
|
||||||
|
this.$refs['form'].resetFields()
|
||||||
|
this.form = this.$options.data().form
|
||||||
|
this.detail = false
|
||||||
|
this.drawer = false
|
||||||
|
},
|
||||||
|
save() {
|
||||||
|
this.$refs['form'].validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
if (this.form.id) {
|
||||||
|
const { msg } = await doEdit(this.form)
|
||||||
|
ElMessage.success(msg)
|
||||||
|
} else {
|
||||||
|
const { msg } = await doCreate(this.form)
|
||||||
|
ElMessage.success(msg)
|
||||||
|
}
|
||||||
|
this.$emit('fetch-data')
|
||||||
|
this.close()
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async fetchData() {
|
||||||
|
this.listLoading = true
|
||||||
|
// 角色
|
||||||
|
const req5 = await getRoleList()
|
||||||
|
this.roleList = req5.data.filter((item) => !item.type.includes('admin'))
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.listLoading = false
|
||||||
|
}, 300)
|
||||||
|
},
|
||||||
|
// 角色
|
||||||
|
async getRole() {
|
||||||
|
const { data } = await getRoleByUserId(this.form.id)
|
||||||
|
this.form.roleId = ref(data.roleId)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.drawer__content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
form {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer__footer {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
button {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
231
src/views/system/userManagement/index.vue
Normal file
231
src/views/system/userManagement/index.vue
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
<template>
|
||||||
|
<app-page class="userManagement-container">
|
||||||
|
<div>
|
||||||
|
<el-form :inline="true" :model="queryForm" @submit.prevent>
|
||||||
|
<!-- <el-form-item>
|
||||||
|
<el-select v-model="queryForm.post" placeholder="专业方向">
|
||||||
|
<el-option
|
||||||
|
v-for="item in postList"
|
||||||
|
:key="item.code"
|
||||||
|
:label="item.value"
|
||||||
|
:value="item.code"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item> -->
|
||||||
|
<el-form-item>
|
||||||
|
<el-input
|
||||||
|
v-model.trim="queryForm.keys"
|
||||||
|
placeholder="请输入关键字"
|
||||||
|
@keyup.enter="queryData"
|
||||||
|
>
|
||||||
|
<template #suffix>
|
||||||
|
<i
|
||||||
|
class="el-icon-search el-input__icon i-search"
|
||||||
|
@click="queryData"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<!-- <el-button icon="el-icon-search" type="primary" @click="queryData">
|
||||||
|
查询
|
||||||
|
</el-button> -->
|
||||||
|
<el-button type="primary" @click="handleEdit">新增</el-button>
|
||||||
|
<!-- <el-button type="danger" @click="handleExport">导出</el-button> -->
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
v-loading="listLoading"
|
||||||
|
:data="list"
|
||||||
|
:element-loading-text="elementLoadingText"
|
||||||
|
:header-cell-style="{ background: '#F7F9FB', textAlign: 'center' }"
|
||||||
|
:cell-style="{ textAlign: 'center' }"
|
||||||
|
@selection-change="setSelectRows"
|
||||||
|
>
|
||||||
|
<!-- <el-table-column show-overflow-tooltip type="selection"></el-table-column> -->
|
||||||
|
<el-table-column label="序号" type="index" />
|
||||||
|
<el-table-column
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
prop="userName"
|
||||||
|
label="账号"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
prop="realName"
|
||||||
|
label="姓名"
|
||||||
|
/>
|
||||||
|
<el-table-column :show-overflow-tooltip="true" label="账号状态">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag v-if="row.isUse === 1" effect="dark">正常</el-tag>
|
||||||
|
<el-tag v-else type="danger" effect="dark">禁用</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :show-overflow-tooltip="true" label="所属角色">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag effect="dark" :style="getRoleTagStyle(row)">
|
||||||
|
{{ row.roleName || "未知" }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
prop="updatedAt"
|
||||||
|
label="修改时间"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<el-table-column label="操作" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="table-btn-list">
|
||||||
|
<el-button class="detail" link type="primary" @click="handleEdit(row, true)">
|
||||||
|
<menu-icon icon="file-earmark-richtext-fill" />
|
||||||
|
</el-button>
|
||||||
|
<el-button class="edit" link type="primary" @click="handleEdit(row, false)">
|
||||||
|
<menu-icon icon="pencil-square" />
|
||||||
|
</el-button>
|
||||||
|
<el-button class="del" link type="primary" @click="handleDelete(row)">
|
||||||
|
<menu-icon icon="trash-fill" />
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-pagination
|
||||||
|
background
|
||||||
|
:current-page="queryForm.pageNo"
|
||||||
|
:page-size="queryForm.pageSize"
|
||||||
|
:layout="layout"
|
||||||
|
:total="total"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
<edit ref="edit" @fetch-data="fetchData" />
|
||||||
|
</app-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { doDelete, getList } from "@/api/userManagement";
|
||||||
|
import Edit from "./components/UserManagementEdit.vue";
|
||||||
|
import { sha1 } from "hash.js";
|
||||||
|
import MenuIcon from "@/layout/sidebar/MenuIcon.vue";
|
||||||
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
|
||||||
|
// 注释
|
||||||
|
export default {
|
||||||
|
name: "UserManagement",
|
||||||
|
components: { MenuIcon, Edit },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
list: null,
|
||||||
|
listLoading: true,
|
||||||
|
layout: "total, sizes, prev, pager, next, jumper",
|
||||||
|
total: 0,
|
||||||
|
selectRows: "",
|
||||||
|
elementLoadingText: "正在加载...",
|
||||||
|
queryForm: {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
keys: ""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setSelectRows(val) {
|
||||||
|
this.selectRows = val;
|
||||||
|
},
|
||||||
|
handleEdit(row, detail) {
|
||||||
|
if (row.id) {
|
||||||
|
this.$refs["edit"].showEdit(row, detail);
|
||||||
|
} else {
|
||||||
|
this.$refs["edit"].showEdit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async handleDelete(row) {
|
||||||
|
if (row.id) {
|
||||||
|
const rs = await ElMessageBox.confirm("你确定要删除当前项吗?");
|
||||||
|
if (rs !== "confirm") return;
|
||||||
|
const { msg } = await doDelete({ ids: row.id });
|
||||||
|
ElMessage.success(msg);
|
||||||
|
await this.fetchData();
|
||||||
|
} else {
|
||||||
|
if (this.selectRows.length > 0) {
|
||||||
|
const ids = this.selectRows.map((item) => item.id).join();
|
||||||
|
const rs = await ElMessageBox.confirm("你确定要删除当前项吗?");
|
||||||
|
if (rs !== "confirm") return;
|
||||||
|
const { msg } = await doDelete({ ids });
|
||||||
|
ElMessage.success(msg);
|
||||||
|
await this.fetchData();
|
||||||
|
} else {
|
||||||
|
ElMessage.error("未选中任何行");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSizeChange(val) {
|
||||||
|
this.queryForm.pageSize = val;
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
handleCurrentChange(val) {
|
||||||
|
this.queryForm.pageNo = val;
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
queryData() {
|
||||||
|
this.queryForm.pageNo = 1;
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
switchChange(row) {
|
||||||
|
},
|
||||||
|
async fetchData() {
|
||||||
|
this.listLoading = true;
|
||||||
|
const { data } = await getList(this.queryForm);
|
||||||
|
this.list = data.data;
|
||||||
|
this.total = data.total;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.listLoading = false;
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取标签的颜色
|
||||||
|
* @param row 角色对象
|
||||||
|
* @return {{backgroundColor: string, borderColor: string, color?: string}}
|
||||||
|
*/
|
||||||
|
getRoleTagStyle(row) {
|
||||||
|
const style = {
|
||||||
|
backgroundColor: undefined,
|
||||||
|
borderColor: undefined,
|
||||||
|
color: undefined
|
||||||
|
};
|
||||||
|
const type = row.roleType || "unknown";
|
||||||
|
if (type.includes("teacher")) style.backgroundColor = "red";
|
||||||
|
else if (type.includes("admin")) style.backgroundColor = "darkorange";
|
||||||
|
else if (type.includes("student")) style.backgroundColor = "#62CAD7";
|
||||||
|
else if (!row.roleName) style.backgroundColor = "darkgray";
|
||||||
|
else {
|
||||||
|
// 根据哈希码计算一个颜色
|
||||||
|
const [r, g, b] = sha1().update(type).digest();
|
||||||
|
const gray = r * 0.299 + g * 0.587 + b * 0.114;
|
||||||
|
style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
|
||||||
|
if (gray < 128) {
|
||||||
|
style.color = "black";
|
||||||
|
style.borderColor = "gray";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!style.borderColor) style.borderColor = style.backgroundColor;
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.table-btn-list {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
:deep(.el-button) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,124 +0,0 @@
|
||||||
{
|
|
||||||
"name": "vue3-admin-ts",
|
|
||||||
"version": "2.0.0-rc2",
|
|
||||||
"license": "MIT",
|
|
||||||
"author": "kuanghua",
|
|
||||||
"packageManager": "pnpm@7.9.0",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "vite --mode serve-dev",
|
|
||||||
"test": "vite --mode serve-test",
|
|
||||||
"build:test": "vite build --mode build-test",
|
|
||||||
"build": "vite build --mode build",
|
|
||||||
"preview:build": "npm run build && vite preview ",
|
|
||||||
"preview": "vite preview ",
|
|
||||||
"lint": "eslint --ext .js,.jsx,.vue,.ts,.tsx src --fix",
|
|
||||||
"prepare": "husky install",
|
|
||||||
"test:unit": "vue-cli-service test:unit",
|
|
||||||
"test:watchAll": "vue-cli-service test:unit --watchAll",
|
|
||||||
"test:cov": "vue-cli-service test:unit --coverage",
|
|
||||||
"test:majestic": "majestic",
|
|
||||||
"vitest": "vitest --ui",
|
|
||||||
"tsc-check": "tsc",
|
|
||||||
"coverage": "vitest run --coverage"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@element-plus/icons-vue": "^2.0.4",
|
|
||||||
"axios": "0.21.3",
|
|
||||||
"echarts": "5.3.2",
|
|
||||||
"element-plus": "^2.2.9",
|
|
||||||
"js-error-collection": "^1.0.7",
|
|
||||||
"mitt": "3.0.0",
|
|
||||||
"moment-mini": "2.22.1",
|
|
||||||
"nprogress": "0.2.0",
|
|
||||||
"path-browserify": "^1.0.1",
|
|
||||||
"path-to-regexp": "^6.2.1",
|
|
||||||
"pinia": "^2.0.16",
|
|
||||||
"pinia-plugin-persistedstate": "2.3.0",
|
|
||||||
"vue": "^3.2.37",
|
|
||||||
"vue-clipboard3": "^2.0.0",
|
|
||||||
"vue-router": "^4.1.5"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/eslint-parser": "7.16.3",
|
|
||||||
"@types/echarts": "4.9.7",
|
|
||||||
"@types/mockjs": "1.0.6",
|
|
||||||
"@types/node": "^17.0.35",
|
|
||||||
"@types/path-browserify": "^1.0.0",
|
|
||||||
"@typescript-eslint/eslint-plugin": "5.30.0",
|
|
||||||
"@typescript-eslint/parser": "5.30.0",
|
|
||||||
"@vitejs/plugin-legacy": "^2.2.0",
|
|
||||||
"@vitejs/plugin-vue": "^2.3.3",
|
|
||||||
"@vitejs/plugin-vue-jsx": "^2.0.1",
|
|
||||||
"@vitest/coverage-c8": "^0.22.1",
|
|
||||||
"@vitest/ui": "^0.22.1",
|
|
||||||
"@vue/cli-plugin-unit-jest": "4.5.17",
|
|
||||||
"@vue/cli-service": "4.5.17",
|
|
||||||
"@vue/test-utils": "^2.0.2",
|
|
||||||
"@vueuse/core": "^8.7.5",
|
|
||||||
"eslint": "8.18.0",
|
|
||||||
"eslint-config-prettier": "8.5.0",
|
|
||||||
"eslint-define-config": "1.5.1",
|
|
||||||
"eslint-plugin-eslint-comments": "3.2.0",
|
|
||||||
"eslint-plugin-import": "2.26.0",
|
|
||||||
"eslint-plugin-jsonc": "^2.3.0",
|
|
||||||
"eslint-plugin-markdown": "^3.0.0",
|
|
||||||
"eslint-plugin-prettier": "4.1.0",
|
|
||||||
"eslint-plugin-unicorn": "^43.0.2",
|
|
||||||
"eslint-plugin-vue": "9.1.1",
|
|
||||||
"husky": "7.0.2",
|
|
||||||
"jsdom": "16.4.0",
|
|
||||||
"jsonc-eslint-parser": "^2.1.0",
|
|
||||||
"majestic": "1.8.1",
|
|
||||||
"mockjs": "1.1.0",
|
|
||||||
"prettier": "2.2.1",
|
|
||||||
"resize-observer-polyfill": "^1.5.1",
|
|
||||||
"rollup-plugin-visualizer": "^5.8.3",
|
|
||||||
"sass": "^1.52.1",
|
|
||||||
"svg-sprite-loader": "6.0.11",
|
|
||||||
"typescript": "^4.7.2",
|
|
||||||
"unocss": "^0.33.5",
|
|
||||||
"unplugin-auto-import": "^0.11.2",
|
|
||||||
"unplugin-vue-components": "^0.22.8",
|
|
||||||
"unplugin-vue-define-options": "^0.12.2",
|
|
||||||
"vite": "^3.1.8",
|
|
||||||
"vite-plugin-html": "^3.2.0",
|
|
||||||
"vite-plugin-mkcert": "^1.7.2",
|
|
||||||
"vite-plugin-mock": "^2.9.6",
|
|
||||||
"vite-plugin-svg-icons": "^2.0.1",
|
|
||||||
"vitest": "^0.22.1",
|
|
||||||
"vue-tsc": "^0.34.16"
|
|
||||||
},
|
|
||||||
"pnpm": {
|
|
||||||
"peerDependencyRules": {
|
|
||||||
"ignoreMissing": [
|
|
||||||
"html-webpack-plugin",
|
|
||||||
"vite-plugin-mock",
|
|
||||||
"unplugin-auto-import",
|
|
||||||
"unplugin-vue-components",
|
|
||||||
"vue-template-compiler",
|
|
||||||
"unocss",
|
|
||||||
"unplugin",
|
|
||||||
"vite-plugin-mock",
|
|
||||||
"@vitejs/plugin-legacy",
|
|
||||||
"@vitejs/plugin-vue",
|
|
||||||
"@vitejs/*",
|
|
||||||
"@babel/*",
|
|
||||||
"vite",
|
|
||||||
"vue",
|
|
||||||
"@unocss/vite",
|
|
||||||
"rollup",
|
|
||||||
"vue-jest",
|
|
||||||
"@babel/*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"browserslist": [
|
|
||||||
"> 1%",
|
|
||||||
"not ie 11",
|
|
||||||
"not op_mini all"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 16 <18",
|
|
||||||
"pnpm": ">= 6 <8"
|
|
||||||
}
|
|
||||||
}
|
|
3
ts-out-dir/src/api/user.d.ts
vendored
3
ts-out-dir/src/api/user.d.ts
vendored
|
@ -1,3 +0,0 @@
|
||||||
export declare const userInfoReq: () => Promise<any>;
|
|
||||||
export declare const loginReq: (subForm: any) => import("axios").AxiosPromise<any>;
|
|
||||||
export declare const loginOutReq: () => import("axios").AxiosPromise<any>;
|
|
|
@ -1,26 +0,0 @@
|
||||||
import request from '@/utils/request'
|
|
||||||
export const userInfoReq = () => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const reqConfig = {
|
|
||||||
url: '/basis-func/user/getUserInfo',
|
|
||||||
params: { plateFormId: 2 },
|
|
||||||
method: 'post'
|
|
||||||
}
|
|
||||||
request(reqConfig).then(({ data }) => {
|
|
||||||
resolve(data)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
export const loginReq = (subForm) => {
|
|
||||||
return request({
|
|
||||||
url: '/basis-func/user/loginValid',
|
|
||||||
params: subForm,
|
|
||||||
method: 'post'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
export const loginOutReq = () => {
|
|
||||||
return request({
|
|
||||||
url: '/basis-func/user/loginValid',
|
|
||||||
method: 'post'
|
|
||||||
})
|
|
||||||
}
|
|
5
ts-out-dir/src/directives/button-codes.d.ts
vendored
5
ts-out-dir/src/directives/button-codes.d.ts
vendored
|
@ -1,5 +0,0 @@
|
||||||
declare const _default: {
|
|
||||||
mounted(el: any, binding: any): void;
|
|
||||||
componentUpdated(el: any, binding: any): void;
|
|
||||||
};
|
|
||||||
export default _default;
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { useBasicStore } from '@/store/basic';
|
|
||||||
function checkPermission(el, { value }) {
|
|
||||||
if (value && Array.isArray(value)) {
|
|
||||||
if (value.length) {
|
|
||||||
const permissionRoles = value;
|
|
||||||
const hasPermission = useBasicStore().buttonCodes?.some((code) => permissionRoles.includes(code));
|
|
||||||
if (!hasPermission)
|
|
||||||
el.parentNode && el.parentNode.removeChild(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(`need roles! Like v-permission="['admin','editor']"`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default {
|
|
||||||
mounted(el, binding) {
|
|
||||||
checkPermission(el, binding);
|
|
||||||
},
|
|
||||||
componentUpdated(el, binding) {
|
|
||||||
checkPermission(el, binding);
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,5 +0,0 @@
|
||||||
declare const _default: {
|
|
||||||
mounted(el: any, binding: any): void;
|
|
||||||
componentUpdated(el: any, binding: any): void;
|
|
||||||
};
|
|
||||||
export default _default;
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { useBasicStore } from '@/store/basic';
|
|
||||||
function checkPermission(el, { value }) {
|
|
||||||
if (value && Array.isArray(value)) {
|
|
||||||
if (value.length > 0) {
|
|
||||||
const permissionRoles = value;
|
|
||||||
const hasPermission = useBasicStore().codes?.some((role) => permissionRoles.includes(role));
|
|
||||||
if (!hasPermission)
|
|
||||||
el.parentNode && el.parentNode.removeChild(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(`need codes! Like v-codes-permission="['admin','editor']"`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default {
|
|
||||||
mounted(el, binding) {
|
|
||||||
checkPermission(el, binding);
|
|
||||||
},
|
|
||||||
componentUpdated(el, binding) {
|
|
||||||
checkPermission(el, binding);
|
|
||||||
}
|
|
||||||
};
|
|
1
ts-out-dir/src/directives/index.d.ts
vendored
1
ts-out-dir/src/directives/index.d.ts
vendored
|
@ -1 +0,0 @@
|
||||||
export default function (app: any): void;
|
|
|
@ -1,8 +0,0 @@
|
||||||
import buttonCodes from './button-codes';
|
|
||||||
import codesPermission from './codes-permission';
|
|
||||||
import rolesPermission from './roles-permission';
|
|
||||||
export default function (app) {
|
|
||||||
app.directive('ButtonCodes', buttonCodes);
|
|
||||||
app.directive('CodesPermission', codesPermission);
|
|
||||||
app.directive('RolesPermission', rolesPermission);
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
declare const _default: {
|
|
||||||
mounted(el: any, binding: any): void;
|
|
||||||
componentUpdated(el: any, binding: any): void;
|
|
||||||
};
|
|
||||||
export default _default;
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { useBasicStore } from '@/store/basic';
|
|
||||||
function checkPermission(el, { value }) {
|
|
||||||
if (value && Array.isArray(value)) {
|
|
||||||
if (value.length > 0) {
|
|
||||||
const permissionRoles = value;
|
|
||||||
const hasPermission = useBasicStore().roles?.some((role) => permissionRoles.includes(role));
|
|
||||||
if (!hasPermission)
|
|
||||||
el.parentNode && el.parentNode.removeChild(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(`need roles! Like v-roles-permission="['admin','editor']"`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default {
|
|
||||||
mounted(el, binding) {
|
|
||||||
checkPermission(el, binding);
|
|
||||||
},
|
|
||||||
componentUpdated(el, binding) {
|
|
||||||
checkPermission(el, binding);
|
|
||||||
}
|
|
||||||
};
|
|
10
ts-out-dir/src/hooks/use-common.d.ts
vendored
10
ts-out-dir/src/hooks/use-common.d.ts
vendored
|
@ -1,10 +0,0 @@
|
||||||
export declare const sleepTimeout: (time: number) => Promise<unknown>;
|
|
||||||
export declare const useCommon: () => {
|
|
||||||
totalPage: import("vue").Ref<number>;
|
|
||||||
startEndArr: import("vue").Ref<never[]>;
|
|
||||||
searchForm: import("vue").Ref<{}>;
|
|
||||||
dialogTitle: import("vue").Ref<string>;
|
|
||||||
detailDialog: import("vue").Ref<boolean>;
|
|
||||||
};
|
|
||||||
export declare function cloneDeep(value: any): any;
|
|
||||||
export declare const copyValueToClipboard: (value: any) => void;
|
|
|
@ -1,31 +0,0 @@
|
||||||
import { reactive, toRefs } from 'vue';
|
|
||||||
import useClipboard from 'vue-clipboard3';
|
|
||||||
import { ElMessage } from 'element-plus';
|
|
||||||
export const sleepTimeout = (time) => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
clearTimeout(timer);
|
|
||||||
resolve(null);
|
|
||||||
}, time);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
export const useCommon = () => {
|
|
||||||
const state = reactive({
|
|
||||||
totalPage: 0,
|
|
||||||
startEndArr: [],
|
|
||||||
searchForm: {},
|
|
||||||
dialogTitle: '',
|
|
||||||
detailDialog: false
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...toRefs(state)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
export function cloneDeep(value) {
|
|
||||||
return JSON.parse(JSON.stringify(value));
|
|
||||||
}
|
|
||||||
const { toClipboard } = useClipboard();
|
|
||||||
export const copyValueToClipboard = (value) => {
|
|
||||||
toClipboard(JSON.stringify(value));
|
|
||||||
ElMessage.success('复制成功');
|
|
||||||
};
|
|
67
ts-out-dir/src/hooks/use-element.d.ts
vendored
67
ts-out-dir/src/hooks/use-element.d.ts
vendored
|
@ -1,67 +0,0 @@
|
||||||
import type { EpPropMergeType } from 'element-plus/es/utils';
|
|
||||||
export declare const useElement: () => {
|
|
||||||
tableData: import("vue").Ref<never[]>;
|
|
||||||
rowDeleteIdArr: import("vue").Ref<never[]>;
|
|
||||||
loadingId: import("vue").Ref<null>;
|
|
||||||
formModel: import("vue").Ref<{}>;
|
|
||||||
subForm: import("vue").Ref<{}>;
|
|
||||||
searchForm: import("vue").Ref<{}>;
|
|
||||||
formRules: import("vue").Ref<{
|
|
||||||
isNull: (msg: string) => {
|
|
||||||
required: boolean;
|
|
||||||
message: string;
|
|
||||||
trigger: string;
|
|
||||||
}[];
|
|
||||||
isNotNull: (msg: string) => {
|
|
||||||
required: boolean;
|
|
||||||
message: string;
|
|
||||||
trigger: string;
|
|
||||||
}[];
|
|
||||||
upZeroInt: (msg: string) => {
|
|
||||||
required: boolean;
|
|
||||||
validator: (rule: any, value: any, callback: any) => void;
|
|
||||||
trigger: string;
|
|
||||||
}[];
|
|
||||||
zeroInt: (msg: string) => {
|
|
||||||
required: boolean;
|
|
||||||
validator: (rule: any, value: any, callback: any) => void;
|
|
||||||
trigger: string;
|
|
||||||
}[];
|
|
||||||
money: (msg: string) => {
|
|
||||||
required: boolean;
|
|
||||||
validator: (rule: any, value: any, callback: any) => void;
|
|
||||||
trigger: string;
|
|
||||||
}[];
|
|
||||||
phone: (msg: string) => {
|
|
||||||
required: boolean;
|
|
||||||
validator: (rule: any, value: any, callback: any) => void;
|
|
||||||
trigger: string;
|
|
||||||
}[];
|
|
||||||
email: (msg: string) => {
|
|
||||||
required: boolean;
|
|
||||||
validator: (rule: any, value: any, callback: any) => void;
|
|
||||||
trigger: string;
|
|
||||||
}[];
|
|
||||||
}>;
|
|
||||||
datePickerOptions: import("vue").Ref<{
|
|
||||||
disabledDate: (time: any) => boolean;
|
|
||||||
}>;
|
|
||||||
startEndArr: import("vue").Ref<never[]>;
|
|
||||||
dialogTitle: import("vue").Ref<string>;
|
|
||||||
detailDialog: import("vue").Ref<boolean>;
|
|
||||||
isDialogEdit: import("vue").Ref<boolean>;
|
|
||||||
dialogVisible: import("vue").Ref<boolean>;
|
|
||||||
tableLoading: import("vue").Ref<boolean>;
|
|
||||||
treeData: import("vue").Ref<never[]>;
|
|
||||||
defaultProps: import("vue").Ref<{
|
|
||||||
children: string;
|
|
||||||
label: string;
|
|
||||||
}>;
|
|
||||||
};
|
|
||||||
export declare const elMessage: (message: string, type?: any) => void;
|
|
||||||
export declare const elLoading: () => void;
|
|
||||||
export declare const closeLoading: () => void;
|
|
||||||
export declare const elNotify: (message: string, type: EpPropMergeType<any, any, any> | undefined, title: string, duration: number) => void;
|
|
||||||
export declare const elConfirmNoCancelBtn: (title: string, message: string) => Promise<import("element-plus").MessageBoxData>;
|
|
||||||
export declare const elConfirm: (title: string, message: string) => Promise<import("element-plus").MessageBoxData>;
|
|
||||||
export declare const casHandleChange: () => void;
|
|
|
@ -1,158 +0,0 @@
|
||||||
import { reactive, ref, toRefs } from 'vue';
|
|
||||||
import { ElLoading, ElMessage, ElMessageBox, ElNotification } from 'element-plus';
|
|
||||||
export const useElement = () => {
|
|
||||||
const upZeroInt = (rule, value, callback, msg) => {
|
|
||||||
if (!value) {
|
|
||||||
callback(new Error(`${msg}不能为空`));
|
|
||||||
}
|
|
||||||
if (/^\+?[1-9]\d*$/.test(value)) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
callback(new Error(`${msg}输入有误`));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const zeroInt = (rule, value, callback, msg) => {
|
|
||||||
if (!value) {
|
|
||||||
callback(new Error(`${msg}不能为空`));
|
|
||||||
}
|
|
||||||
if (/^\+?[0-9]\d*$/.test(value)) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
callback(new Error(`${msg}输入有误`));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const money = (rule, value, callback, msg) => {
|
|
||||||
if (!value) {
|
|
||||||
callback(new Error(`${msg}不能为空`));
|
|
||||||
}
|
|
||||||
if (/((^[1-9]\d*)|^0)(\.\d{0,2}){0,1}$/.test(value)) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
callback(new Error(`${msg}输入有误`));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const phone = (rule, value, callback, msg) => {
|
|
||||||
if (!value) {
|
|
||||||
callback(new Error(`${msg}不能为空`));
|
|
||||||
}
|
|
||||||
if (/^0?1[0-9]{10}$/.test(value)) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
callback(new Error(`${msg}输入有误`));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const email = (rule, value, callback, msg) => {
|
|
||||||
if (!value) {
|
|
||||||
callback(new Error(`${msg}不能为空`));
|
|
||||||
}
|
|
||||||
if (/(^([a-zA-Z]|[0-9])(\w|-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4}))$/.test(value)) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
callback(new Error(`${msg}`));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const state = reactive({
|
|
||||||
tableData: [],
|
|
||||||
rowDeleteIdArr: [],
|
|
||||||
loadingId: null,
|
|
||||||
formModel: {},
|
|
||||||
subForm: {},
|
|
||||||
searchForm: {},
|
|
||||||
formRules: {
|
|
||||||
isNull: (msg) => [{ required: false, message: `${msg}`, trigger: 'blur' }],
|
|
||||||
isNotNull: (msg) => [{ required: true, message: `${msg}`, trigger: 'blur' }],
|
|
||||||
upZeroInt: (msg) => [
|
|
||||||
{ required: true, validator: (rule, value, callback) => upZeroInt(rule, value, callback, msg), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
zeroInt: (msg) => [
|
|
||||||
{ required: true, validator: (rule, value, callback) => zeroInt(rule, value, callback, msg), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
money: (msg) => [
|
|
||||||
{ required: true, validator: (rule, value, callback) => money(rule, value, callback, msg), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
phone: (msg) => [
|
|
||||||
{ required: true, validator: (rule, value, callback) => phone(rule, value, callback, msg), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
email: (msg) => [
|
|
||||||
{ required: true, validator: (rule, value, callback) => email(rule, value, callback, msg), trigger: 'blur' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
datePickerOptions: {
|
|
||||||
disabledDate: (time) => {
|
|
||||||
return time.getTime() < Date.now() - 86400000;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
startEndArr: [],
|
|
||||||
dialogTitle: '添加',
|
|
||||||
detailDialog: false,
|
|
||||||
isDialogEdit: false,
|
|
||||||
dialogVisible: false,
|
|
||||||
tableLoading: false,
|
|
||||||
treeData: [],
|
|
||||||
defaultProps: {
|
|
||||||
children: 'children',
|
|
||||||
label: 'label'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
...toRefs(state)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
export const elMessage = (message, type) => {
|
|
||||||
ElMessage({
|
|
||||||
showClose: true,
|
|
||||||
message: message || '成功',
|
|
||||||
type: type || 'success',
|
|
||||||
center: false
|
|
||||||
});
|
|
||||||
};
|
|
||||||
let loadingId = null;
|
|
||||||
export const elLoading = () => {
|
|
||||||
loadingId = ElLoading.service({
|
|
||||||
lock: true,
|
|
||||||
text: '数据载入中',
|
|
||||||
spinner: 'el-icon-loading',
|
|
||||||
background: 'rgba(0, 0, 0, 0.1)'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
export const closeLoading = () => {
|
|
||||||
loadingId.close();
|
|
||||||
};
|
|
||||||
export const elNotify = (message, type, title, duration) => {
|
|
||||||
ElNotification({
|
|
||||||
title: title || '提示',
|
|
||||||
type: type || 'success',
|
|
||||||
message: message || '请传入提示消息',
|
|
||||||
position: 'top-right',
|
|
||||||
duration: duration || 2500,
|
|
||||||
offset: 40
|
|
||||||
});
|
|
||||||
};
|
|
||||||
export const elConfirmNoCancelBtn = (title, message) => {
|
|
||||||
return ElMessageBox({
|
|
||||||
message: message || '你确定要删除吗',
|
|
||||||
title: title || '确认框',
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
showCancelButton: false,
|
|
||||||
type: 'warning'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
export const elConfirm = (title, message) => {
|
|
||||||
return ElMessageBox({
|
|
||||||
message: message || '你确定要删除吗',
|
|
||||||
title: title || '确认框',
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const cascaderKey = ref();
|
|
||||||
export const casHandleChange = () => {
|
|
||||||
cascaderKey.value += cascaderKey.value;
|
|
||||||
};
|
|
1
ts-out-dir/src/hooks/use-error-log.d.ts
vendored
1
ts-out-dir/src/hooks/use-error-log.d.ts
vendored
|
@ -1 +0,0 @@
|
||||||
export declare const useErrorLog: () => void;
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { jsErrorCollection } from 'js-error-collection'
|
|
||||||
import pack from '../../package.json'
|
|
||||||
import settings from '@/settings'
|
|
||||||
import bus from '@/utils/bus'
|
|
||||||
import request from '@/utils/request'
|
|
||||||
const reqUrl = '/integration-front/errorCollection/insert'
|
|
||||||
const errorLogReq = (errLog) => {
|
|
||||||
request({
|
|
||||||
url: reqUrl,
|
|
||||||
data: {
|
|
||||||
pageUrl: window.location.href,
|
|
||||||
errorLog: errLog,
|
|
||||||
browserType: navigator.userAgent,
|
|
||||||
version: pack.version
|
|
||||||
},
|
|
||||||
method: 'post'
|
|
||||||
}).then(() => {
|
|
||||||
bus.emit('reloadErrorPage', {})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
export const useErrorLog = () => {
|
|
||||||
if (settings.errorLog?.includes(import.meta.env.VITE_APP_ENV)) {
|
|
||||||
jsErrorCollection({ runtimeError: true, rejectError: true, consoleError: true }, (errLog) => {
|
|
||||||
if (!errLog.includes(reqUrl)) errorLogReq(errLog)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
2
ts-out-dir/src/hooks/use-layout.d.ts
vendored
2
ts-out-dir/src/hooks/use-layout.d.ts
vendored
|
@ -1,2 +0,0 @@
|
||||||
export declare function isExternal(path: any): boolean;
|
|
||||||
export declare function resizeHandler(): void;
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { onBeforeMount, onBeforeUnmount, onMounted } from 'vue';
|
|
||||||
import { useBasicStore } from '@/store/basic';
|
|
||||||
export function isExternal(path) {
|
|
||||||
return /^(https?:|mailto:|tel:)/.test(path);
|
|
||||||
}
|
|
||||||
export function resizeHandler() {
|
|
||||||
const { body } = document;
|
|
||||||
const WIDTH = 992;
|
|
||||||
const basicStore = useBasicStore();
|
|
||||||
const isMobile = () => {
|
|
||||||
const rect = body.getBoundingClientRect();
|
|
||||||
return rect.width - 1 < WIDTH;
|
|
||||||
};
|
|
||||||
const resizeHandler = () => {
|
|
||||||
if (!document.hidden) {
|
|
||||||
if (isMobile()) {
|
|
||||||
basicStore.setSidebarOpen(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
basicStore.setSidebarOpen(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
onBeforeMount(() => {
|
|
||||||
window.addEventListener('resize', resizeHandler);
|
|
||||||
});
|
|
||||||
onMounted(() => {
|
|
||||||
if (isMobile()) {
|
|
||||||
basicStore.setSidebarOpen(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
basicStore.setSidebarOpen(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
window.removeEventListener('resize', resizeHandler);
|
|
||||||
});
|
|
||||||
}
|
|
15
ts-out-dir/src/hooks/use-permission.d.ts
vendored
15
ts-out-dir/src/hooks/use-permission.d.ts
vendored
|
@ -1,15 +0,0 @@
|
||||||
import type { RouterTypes } from '~/basic';
|
|
||||||
import 'nprogress/nprogress.css';
|
|
||||||
export declare const filterAsyncRoutesByMenuList: (menuList: any) => RouterTypes;
|
|
||||||
export declare function filterAsyncRoutesByRoles(routes: any, roles: any): RouterTypes;
|
|
||||||
export declare function filterAsyncRouterByCodes(codesRoutes: any, codes: any): RouterTypes;
|
|
||||||
export declare function filterAsyncRouter({ menuList, roles, codes }: {
|
|
||||||
menuList: any;
|
|
||||||
roles: any;
|
|
||||||
codes: any;
|
|
||||||
}): void;
|
|
||||||
export declare function resetRouter(): void;
|
|
||||||
export declare function resetState(): void;
|
|
||||||
export declare function freshRouter(data: any): void;
|
|
||||||
export declare const progressStart: () => void;
|
|
||||||
export declare const progressClose: () => void;
|
|
|
@ -1,146 +0,0 @@
|
||||||
import NProgress from 'nprogress';
|
|
||||||
import Layout from '@/layout/index.vue';
|
|
||||||
import router, { asyncRoutes, constantRoutes, roleCodeRoutes } from '@/router';
|
|
||||||
import 'nprogress/nprogress.css';
|
|
||||||
import { useBasicStore } from '@/store/basic';
|
|
||||||
const buttonCodes = [];
|
|
||||||
export const filterAsyncRoutesByMenuList = (menuList) => {
|
|
||||||
const filterRouter = [];
|
|
||||||
menuList.forEach((route) => {
|
|
||||||
if (route.category === 3) {
|
|
||||||
buttonCodes.push(route.code);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const itemFromReqRouter = getRouteItemFromReqRouter(route);
|
|
||||||
if (route.children?.length) {
|
|
||||||
itemFromReqRouter.children = filterAsyncRoutesByMenuList(route.children);
|
|
||||||
}
|
|
||||||
filterRouter.push(itemFromReqRouter);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return filterRouter;
|
|
||||||
};
|
|
||||||
const getRouteItemFromReqRouter = (route) => {
|
|
||||||
const tmp = { meta: { title: '' } };
|
|
||||||
const routeKeyArr = ['path', 'component', 'redirect', 'alwaysShow', 'name', 'hidden'];
|
|
||||||
const metaKeyArr = ['title', 'activeMenu', 'elSvgIcon', 'icon'];
|
|
||||||
const modules = import.meta.glob('../views/**/**.vue');
|
|
||||||
routeKeyArr.forEach((fItem) => {
|
|
||||||
if (fItem === 'component') {
|
|
||||||
if (route[fItem] === 'Layout') {
|
|
||||||
tmp[fItem] = Layout;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tmp[fItem] = modules[`../views/${route[fItem]}`];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (fItem === 'path' && route.parentId === 0) {
|
|
||||||
tmp[fItem] = `/${route[fItem]}`;
|
|
||||||
}
|
|
||||||
else if (['hidden', 'alwaysShow'].includes(fItem)) {
|
|
||||||
tmp[fItem] = !!route[fItem];
|
|
||||||
}
|
|
||||||
else if (['name'].includes(fItem)) {
|
|
||||||
tmp[fItem] = route['code'];
|
|
||||||
}
|
|
||||||
else if (route[fItem]) {
|
|
||||||
tmp[fItem] = route[fItem];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
metaKeyArr.forEach((fItem) => {
|
|
||||||
if (route[fItem] && tmp.meta)
|
|
||||||
tmp.meta[fItem] = route[fItem];
|
|
||||||
});
|
|
||||||
if (route.extra) {
|
|
||||||
Object.entries(route.extra.parse(route.extra)).forEach(([key, value]) => {
|
|
||||||
if (key === 'meta' && tmp.meta) {
|
|
||||||
tmp.meta[key] = value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tmp[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return tmp;
|
|
||||||
};
|
|
||||||
export function filterAsyncRoutesByRoles(routes, roles) {
|
|
||||||
const res = [];
|
|
||||||
routes.forEach((route) => {
|
|
||||||
const tmp = { ...route };
|
|
||||||
if (hasPermission(roles, tmp)) {
|
|
||||||
if (tmp.children) {
|
|
||||||
tmp.children = filterAsyncRoutesByRoles(tmp.children, roles);
|
|
||||||
}
|
|
||||||
res.push(tmp);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
function hasPermission(roles, route) {
|
|
||||||
if (route?.meta?.roles) {
|
|
||||||
return roles?.some((role) => route.meta.roles.includes(role));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function filterAsyncRouterByCodes(codesRoutes, codes) {
|
|
||||||
const filterRouter = [];
|
|
||||||
codesRoutes.forEach((routeItem) => {
|
|
||||||
if (hasCodePermission(codes, routeItem)) {
|
|
||||||
if (routeItem.children)
|
|
||||||
routeItem.children = filterAsyncRouterByCodes(routeItem.children, codes);
|
|
||||||
filterRouter.push(routeItem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return filterRouter;
|
|
||||||
}
|
|
||||||
function hasCodePermission(codes, routeItem) {
|
|
||||||
if (routeItem.meta?.code) {
|
|
||||||
return codes.includes(routeItem.meta.code) || routeItem.hidden;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export function filterAsyncRouter({ menuList, roles, codes }) {
|
|
||||||
const basicStore = useBasicStore();
|
|
||||||
let accessRoutes = [];
|
|
||||||
const permissionMode = basicStore.settings?.permissionMode;
|
|
||||||
if (permissionMode === 'rbac') {
|
|
||||||
accessRoutes = filterAsyncRoutesByMenuList(menuList);
|
|
||||||
}
|
|
||||||
else if (permissionMode === 'roles') {
|
|
||||||
accessRoutes = filterAsyncRoutesByRoles(roleCodeRoutes, roles);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
accessRoutes = filterAsyncRouterByCodes(roleCodeRoutes, codes);
|
|
||||||
}
|
|
||||||
accessRoutes.forEach((route) => router.addRoute(route));
|
|
||||||
asyncRoutes.forEach((item) => router.addRoute(item));
|
|
||||||
basicStore.setFilterAsyncRoutes(accessRoutes);
|
|
||||||
}
|
|
||||||
export function resetRouter() {
|
|
||||||
const routeNameSet = new Set();
|
|
||||||
router.getRoutes().forEach((fItem) => {
|
|
||||||
if (fItem.name)
|
|
||||||
routeNameSet.add(fItem.name);
|
|
||||||
});
|
|
||||||
routeNameSet.forEach((setItem) => router.removeRoute(setItem));
|
|
||||||
constantRoutes.forEach((feItem) => router.addRoute(feItem));
|
|
||||||
}
|
|
||||||
export function resetState() {
|
|
||||||
resetRouter();
|
|
||||||
useBasicStore().resetState();
|
|
||||||
}
|
|
||||||
export function freshRouter(data) {
|
|
||||||
resetRouter();
|
|
||||||
filterAsyncRouter(data);
|
|
||||||
}
|
|
||||||
NProgress.configure({ showSpinner: false });
|
|
||||||
export const progressStart = () => {
|
|
||||||
NProgress.start();
|
|
||||||
};
|
|
||||||
export const progressClose = () => {
|
|
||||||
NProgress.done();
|
|
||||||
};
|
|
4
ts-out-dir/src/hooks/use-self-router.d.ts
vendored
4
ts-out-dir/src/hooks/use-self-router.d.ts
vendored
|
@ -1,4 +0,0 @@
|
||||||
export declare const getQueryParam: () => any;
|
|
||||||
export declare const routerPush: (name: any, params: any) => void;
|
|
||||||
export declare const routerReplace: (name: any, params: any) => void;
|
|
||||||
export declare const routerBack: () => void;
|
|
|
@ -1,40 +0,0 @@
|
||||||
import router from '@/router';
|
|
||||||
export const getQueryParam = () => {
|
|
||||||
const route = router.currentRoute;
|
|
||||||
if (route.value?.query.params) {
|
|
||||||
return JSON.parse(route.value.query.params);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export const routerPush = (name, params) => {
|
|
||||||
let data = {};
|
|
||||||
if (params) {
|
|
||||||
data = {
|
|
||||||
params: JSON.stringify(params)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data = {};
|
|
||||||
}
|
|
||||||
router.push({
|
|
||||||
name,
|
|
||||||
query: data
|
|
||||||
});
|
|
||||||
};
|
|
||||||
export const routerReplace = (name, params) => {
|
|
||||||
let data = {};
|
|
||||||
if (params) {
|
|
||||||
data = {
|
|
||||||
params: JSON.stringify(params)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data = {};
|
|
||||||
}
|
|
||||||
router.replace({
|
|
||||||
name,
|
|
||||||
query: data
|
|
||||||
});
|
|
||||||
};
|
|
||||||
export const routerBack = () => {
|
|
||||||
router.go(-1);
|
|
||||||
};
|
|
15
ts-out-dir/src/hooks/use-table.d.ts
vendored
15
ts-out-dir/src/hooks/use-table.d.ts
vendored
|
@ -1,15 +0,0 @@
|
||||||
export declare const useTable: (searchForm: any, selectPageReq: any) => {
|
|
||||||
pageNum: import("vue").Ref<number>;
|
|
||||||
pageSize: import("vue").Ref<number>;
|
|
||||||
totalPage: import("vue").Ref<number>;
|
|
||||||
tableListData: import("vue").Ref<never[]>;
|
|
||||||
tableListReq: (config: any) => import("axios").AxiosPromise<any>;
|
|
||||||
dateRangePacking: (timeArr: any) => void;
|
|
||||||
multipleSelection: import("vue").Ref<ObjKeys[]>;
|
|
||||||
handleSelectionChange: (val: any) => void;
|
|
||||||
handleCurrentChange: (val: any) => void;
|
|
||||||
handleSizeChange: (val: any) => void;
|
|
||||||
resetPageReq: () => void;
|
|
||||||
multiDelBtnDill: (reqConfig: any) => void;
|
|
||||||
tableDelDill: (row: any, reqConfig: any) => void;
|
|
||||||
};
|
|
|
@ -1,105 +0,0 @@
|
||||||
import { ref } from 'vue'
|
|
||||||
import momentMini from 'moment-mini'
|
|
||||||
import { elConfirm, elMessage } from './use-element'
|
|
||||||
export const useTable = (searchForm, selectPageReq) => {
|
|
||||||
const tableListData = ref([])
|
|
||||||
const totalPage = ref(0)
|
|
||||||
const pageNum = ref(1)
|
|
||||||
const pageSize = ref(20)
|
|
||||||
const tableListReq = (config) => {
|
|
||||||
const data = Object.assign(
|
|
||||||
{
|
|
||||||
pageNum: pageNum.value,
|
|
||||||
pageSize: pageSize.value
|
|
||||||
},
|
|
||||||
JSON.parse(JSON.stringify(searchForm))
|
|
||||||
)
|
|
||||||
Object.keys(data).forEach((fItem) => {
|
|
||||||
if (['', null, undefined, Number.NaN].includes(data[fItem])) delete data[fItem]
|
|
||||||
if (config.method === 'get') {
|
|
||||||
if (Array.isArray(data[fItem])) delete data[fItem]
|
|
||||||
if (data[fItem] instanceof Object) delete data[fItem]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const reqConfig = {
|
|
||||||
data,
|
|
||||||
...config
|
|
||||||
}
|
|
||||||
return request(reqConfig)
|
|
||||||
}
|
|
||||||
const dateRangePacking = (timeArr) => {
|
|
||||||
if (timeArr && timeArr.length === 2) {
|
|
||||||
searchForm.startTime = timeArr[0]
|
|
||||||
if (searchForm.endTime) {
|
|
||||||
searchForm.endTime = momentMini(timeArr[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
searchForm.startTime = ''
|
|
||||||
searchForm.endTime = ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const handleCurrentChange = (val) => {
|
|
||||||
pageNum.value = val
|
|
||||||
selectPageReq()
|
|
||||||
}
|
|
||||||
const handleSizeChange = (val) => {
|
|
||||||
pageSize.value = val
|
|
||||||
selectPageReq()
|
|
||||||
}
|
|
||||||
const resetPageReq = () => {
|
|
||||||
pageNum.value = 1
|
|
||||||
selectPageReq()
|
|
||||||
}
|
|
||||||
const multipleSelection = ref([])
|
|
||||||
const handleSelectionChange = (val) => {
|
|
||||||
multipleSelection.value = val
|
|
||||||
}
|
|
||||||
const multiDelBtnDill = (reqConfig) => {
|
|
||||||
let rowDeleteIdArr = []
|
|
||||||
let deleteNameTitle = ''
|
|
||||||
rowDeleteIdArr = multipleSelection.value.map((mItem) => {
|
|
||||||
deleteNameTitle = `${deleteNameTitle + mItem.id},`
|
|
||||||
return mItem.id
|
|
||||||
})
|
|
||||||
if (rowDeleteIdArr.length === 0) {
|
|
||||||
elMessage('表格选项不能为空', 'warning')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const stringLength = deleteNameTitle.length - 1
|
|
||||||
elConfirm('删除', `您确定要删除【${deleteNameTitle.slice(0, stringLength)}】吗`).then(() => {
|
|
||||||
const data = rowDeleteIdArr
|
|
||||||
request({
|
|
||||||
data,
|
|
||||||
method: 'DELETE',
|
|
||||||
bfLoading: true,
|
|
||||||
...reqConfig
|
|
||||||
}).then(() => {
|
|
||||||
elMessage('删除成功')
|
|
||||||
resetPageReq()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const tableDelDill = (row, reqConfig) => {
|
|
||||||
elConfirm('确定', `您确定要删除【${row.id}】吗?`).then(() => {
|
|
||||||
request(reqConfig).then(() => {
|
|
||||||
resetPageReq()
|
|
||||||
elMessage(`【${row.id}】删除成功`)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
pageNum,
|
|
||||||
pageSize,
|
|
||||||
totalPage,
|
|
||||||
tableListData,
|
|
||||||
tableListReq,
|
|
||||||
dateRangePacking,
|
|
||||||
multipleSelection,
|
|
||||||
handleSelectionChange,
|
|
||||||
handleCurrentChange,
|
|
||||||
handleSizeChange,
|
|
||||||
resetPageReq,
|
|
||||||
multiDelBtnDill,
|
|
||||||
tableDelDill
|
|
||||||
}
|
|
||||||
}
|
|
1
ts-out-dir/src/lib/element-plus.d.ts
vendored
1
ts-out-dir/src/lib/element-plus.d.ts
vendored
|
@ -1 +0,0 @@
|
||||||
export default function (app: any): void;
|
|
|
@ -1,7 +0,0 @@
|
||||||
import * as AllComponent from 'element-plus';
|
|
||||||
const elementPlusComponentNameArr = ['ElButton'];
|
|
||||||
export default function (app) {
|
|
||||||
elementPlusComponentNameArr.forEach((component) => {
|
|
||||||
app.component(component, AllComponent[component]);
|
|
||||||
});
|
|
||||||
}
|
|
6
ts-out-dir/src/main.d.ts
vendored
6
ts-out-dir/src/main.d.ts
vendored
|
@ -1,6 +0,0 @@
|
||||||
import '@/styles/index.scss';
|
|
||||||
import 'virtual:svg-icons-register';
|
|
||||||
import './permission';
|
|
||||||
import './theme/index.scss';
|
|
||||||
import 'uno.css';
|
|
||||||
import 'element-plus/dist/index.css';
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { createApp } from 'vue';
|
|
||||||
import App from './App.vue';
|
|
||||||
const app = createApp(App);
|
|
||||||
import router from './router';
|
|
||||||
import '@/styles/index.scss';
|
|
||||||
import 'virtual:svg-icons-register';
|
|
||||||
import svgIcon from '@/icons/SvgIcon.vue';
|
|
||||||
import directive from '@/directives';
|
|
||||||
import './permission';
|
|
||||||
import './theme/index.scss';
|
|
||||||
import 'uno.css';
|
|
||||||
import ElementPlus from 'element-plus';
|
|
||||||
import 'element-plus/dist/index.css';
|
|
||||||
app.use(ElementPlus);
|
|
||||||
app.component('SvgIcon', svgIcon);
|
|
||||||
directive(app);
|
|
||||||
import { createPinia } from 'pinia';
|
|
||||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
|
||||||
const pinia = createPinia();
|
|
||||||
pinia.use(piniaPluginPersistedstate);
|
|
||||||
app.use(pinia);
|
|
||||||
app.use(router).mount('#app');
|
|
1
ts-out-dir/src/permission.d.ts
vendored
1
ts-out-dir/src/permission.d.ts
vendored
|
@ -1 +0,0 @@
|
||||||
export {};
|
|
|
@ -1,44 +0,0 @@
|
||||||
import router from '@/router';
|
|
||||||
import { filterAsyncRouter, progressClose, progressStart } from '@/hooks/use-permission';
|
|
||||||
import { useBasicStore } from '@/store/basic';
|
|
||||||
import { userInfoReq } from '@/api/user';
|
|
||||||
const whiteList = ['/login', '/404', '/401'];
|
|
||||||
router.beforeEach(async (to) => {
|
|
||||||
progressStart();
|
|
||||||
const basicStore = useBasicStore();
|
|
||||||
if (basicStore.token) {
|
|
||||||
if (to.path === '/login') {
|
|
||||||
return '/';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!basicStore.getUserInfo) {
|
|
||||||
try {
|
|
||||||
const userData = await userInfoReq();
|
|
||||||
filterAsyncRouter(userData);
|
|
||||||
basicStore.setUserInfo(userData);
|
|
||||||
return { ...to, replace: true };
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(`route permission error${e}`);
|
|
||||||
basicStore.resetState();
|
|
||||||
progressClose();
|
|
||||||
return `/login?redirect=${to.path}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!whiteList.includes(to.path)) {
|
|
||||||
return `/login?redirect=${to.path}`;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
router.afterEach(() => {
|
|
||||||
progressClose();
|
|
||||||
});
|
|
6
ts-out-dir/src/router/index.d.ts
vendored
6
ts-out-dir/src/router/index.d.ts
vendored
|
@ -1,6 +0,0 @@
|
||||||
import type { RouterTypes } from '~/basic';
|
|
||||||
export declare const constantRoutes: RouterTypes;
|
|
||||||
export declare const roleCodeRoutes: RouterTypes;
|
|
||||||
export declare const asyncRoutes: RouterTypes;
|
|
||||||
declare const router: import("vue-router").Router;
|
|
||||||
export default router;
|
|
|
@ -1,203 +0,0 @@
|
||||||
import { createRouter, createWebHashHistory } from 'vue-router';
|
|
||||||
import Layout from '@/layout/index.vue';
|
|
||||||
export const constantRoutes = [
|
|
||||||
{
|
|
||||||
path: '/redirect',
|
|
||||||
component: Layout,
|
|
||||||
hidden: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '/redirect/:path(.*)',
|
|
||||||
component: () => import('@/views/redirect')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/login',
|
|
||||||
component: () => import('@/views/login/index.vue'),
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/404',
|
|
||||||
component: () => import('@/views/error-page/404.vue'),
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/401',
|
|
||||||
component: () => import('@/views/error-page/401.vue'),
|
|
||||||
hidden: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
component: Layout,
|
|
||||||
redirect: '/dashboard',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'dashboard',
|
|
||||||
name: 'Dashboard',
|
|
||||||
component: () => import('@/views/dashboard/index.vue'),
|
|
||||||
meta: { title: 'Dashboard', elSvgIcon: 'Fold' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/setting-switch',
|
|
||||||
component: Layout,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'index',
|
|
||||||
component: () => import('@/views/setting-switch/index.vue'),
|
|
||||||
name: 'SettingSwitch',
|
|
||||||
meta: { title: 'Setting Switch', icon: 'example', affix: true }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/error-collection',
|
|
||||||
component: Layout,
|
|
||||||
meta: { title: 'Error Collection', icon: 'eye' },
|
|
||||||
alwaysShow: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'error-collection-table-query',
|
|
||||||
component: () => import('@/views/error-collection/ErrorCollectionTableQuery.vue'),
|
|
||||||
name: 'ErrorCollectionTableQuery',
|
|
||||||
meta: { title: 'Index' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'error-log-test',
|
|
||||||
component: () => import('@/views/error-log/ErrorLogTest.vue'),
|
|
||||||
name: 'ErrorLogTest',
|
|
||||||
meta: { title: 'ErrorLog Test' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/nested',
|
|
||||||
component: Layout,
|
|
||||||
redirect: '/nested/menu1',
|
|
||||||
name: 'Nested',
|
|
||||||
meta: {
|
|
||||||
title: 'Nested',
|
|
||||||
icon: 'nested'
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'menu1',
|
|
||||||
component: () => import('@/views/nested/menu1/index.vue'),
|
|
||||||
name: 'Menu1',
|
|
||||||
meta: { title: 'Menu1' },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'menu1-1',
|
|
||||||
component: () => import('@/views/nested/menu1/menu1-1/index.vue'),
|
|
||||||
name: 'Menu1-1',
|
|
||||||
meta: { title: 'Menu1-1' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu1-2',
|
|
||||||
component: () => import('@/views/nested/menu1/menu1-2/index.vue'),
|
|
||||||
name: 'Menu1-2',
|
|
||||||
meta: { title: 'Menu1-2' },
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'menu1-2-1',
|
|
||||||
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1/index.vue'),
|
|
||||||
name: 'Menu1-2-1',
|
|
||||||
meta: { title: 'Menu1-2-1' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu1-2-2',
|
|
||||||
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2/index.vue'),
|
|
||||||
name: 'Menu1-2-2',
|
|
||||||
meta: { title: 'Menu1-2-2' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu1-3',
|
|
||||||
component: () => import('@/views/nested/menu1/menu1-3/index.vue'),
|
|
||||||
name: 'Menu1-3',
|
|
||||||
meta: { title: 'Menu1-3' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu2',
|
|
||||||
component: () => import('@/views/nested/menu2/index.vue'),
|
|
||||||
name: 'Menu2',
|
|
||||||
meta: { title: 'menu2' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/external-link',
|
|
||||||
component: Layout,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
component: () => { },
|
|
||||||
path: 'https://github.com/jzfai/vue3-admin-ts.git',
|
|
||||||
meta: { title: 'External Link', icon: 'link' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
export const roleCodeRoutes = [
|
|
||||||
{
|
|
||||||
path: '/roles-codes',
|
|
||||||
component: Layout,
|
|
||||||
redirect: '/roles-codes/page',
|
|
||||||
alwaysShow: true,
|
|
||||||
name: 'Permission',
|
|
||||||
meta: {
|
|
||||||
title: 'Permission',
|
|
||||||
icon: 'lock',
|
|
||||||
roles: ['admin', 'editor']
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'index',
|
|
||||||
component: () => import('@/views/roles-codes/index.vue'),
|
|
||||||
name: 'RolesCodes',
|
|
||||||
meta: {
|
|
||||||
title: 'index'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'roleIndex',
|
|
||||||
component: () => import('@/views/roles-codes/role-index.vue'),
|
|
||||||
name: 'RoleIndex',
|
|
||||||
meta: {
|
|
||||||
title: 'Role Index',
|
|
||||||
roles: ['admin']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'code-index',
|
|
||||||
component: () => import('@/views/roles-codes/code-index.vue'),
|
|
||||||
name: 'CodeIndex',
|
|
||||||
meta: {
|
|
||||||
title: 'Code Index',
|
|
||||||
code: 16
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'button-permission',
|
|
||||||
component: () => import('@/views/roles-codes/button-permission.vue'),
|
|
||||||
name: 'ButtonPermission',
|
|
||||||
meta: {
|
|
||||||
title: 'Button Permission'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
export const asyncRoutes = [
|
|
||||||
{ path: '/:catchAll(.*)', name: 'CatchAll', redirect: '/404', hidden: true }
|
|
||||||
];
|
|
||||||
const router = createRouter({
|
|
||||||
history: createWebHashHistory(),
|
|
||||||
scrollBehavior: () => ({ top: 0 }),
|
|
||||||
routes: constantRoutes
|
|
||||||
});
|
|
||||||
export default router;
|
|
3
ts-out-dir/src/settings.d.ts
vendored
3
ts-out-dir/src/settings.d.ts
vendored
|
@ -1,3 +0,0 @@
|
||||||
import type { SettingsConfig } from '~/basic';
|
|
||||||
declare const settings: SettingsConfig;
|
|
||||||
export default settings;
|
|
|
@ -1,21 +0,0 @@
|
||||||
const settings = {
|
|
||||||
title: 'Vue3 Admin Template',
|
|
||||||
sidebarLogo: true,
|
|
||||||
showNavbarTitle: false,
|
|
||||||
ShowDropDown: true,
|
|
||||||
showHamburger: true,
|
|
||||||
showLeftMenu: true,
|
|
||||||
showTagsView: true,
|
|
||||||
tagsViewNum: 6,
|
|
||||||
showTopNavbar: true,
|
|
||||||
mainNeedAnimation: true,
|
|
||||||
isNeedNprogress: true,
|
|
||||||
isNeedLogin: true,
|
|
||||||
permissionMode: 'roles',
|
|
||||||
openProdMock: true,
|
|
||||||
errorLog: ['prod'],
|
|
||||||
delWindowHeight: '210px',
|
|
||||||
tmpToken: 'tmp_token',
|
|
||||||
viteBasePath: './'
|
|
||||||
};
|
|
||||||
export default settings;
|
|
41
ts-out-dir/src/store/basic.d.ts
vendored
41
ts-out-dir/src/store/basic.d.ts
vendored
|
@ -1,41 +0,0 @@
|
||||||
import type { RouterTypes } from '~/basic';
|
|
||||||
export declare const useBasicStore: import("pinia").StoreDefinition<"basic", {
|
|
||||||
token: string;
|
|
||||||
getUserInfo: boolean;
|
|
||||||
userInfo: {
|
|
||||||
username: string;
|
|
||||||
avatar: string;
|
|
||||||
};
|
|
||||||
allRoutes: RouterTypes;
|
|
||||||
buttonCodes: never[];
|
|
||||||
filterAsyncRoutes: never[];
|
|
||||||
roles: string[];
|
|
||||||
codes: number[];
|
|
||||||
cachedViews: string[];
|
|
||||||
cachedViewsDeep: string[];
|
|
||||||
sidebar: {
|
|
||||||
opened: boolean;
|
|
||||||
};
|
|
||||||
axiosPromiseArr: ObjKeys[];
|
|
||||||
settings: import("~/basic").SettingsConfig;
|
|
||||||
}, {}, {
|
|
||||||
setToken(data: any): void;
|
|
||||||
setFilterAsyncRoutes(routes: any): void;
|
|
||||||
setUserInfo({ userInfo, roles, codes }: {
|
|
||||||
userInfo: any;
|
|
||||||
roles: any;
|
|
||||||
codes: any;
|
|
||||||
}): void;
|
|
||||||
resetState(): void;
|
|
||||||
resetStateAndToLogin(): void;
|
|
||||||
M_settings(data: any): void;
|
|
||||||
setSidebarOpen(data: any): void;
|
|
||||||
setToggleSideBar(): void;
|
|
||||||
addCachedView(view: any): void;
|
|
||||||
delCachedView(view: any): void;
|
|
||||||
M_RESET_CACHED_VIEW(): void;
|
|
||||||
addCachedViewDeep(view: any): void;
|
|
||||||
setCacheViewDeep(view: any): void;
|
|
||||||
M_RESET_CACHED_VIEW_DEEP(): void;
|
|
||||||
A_sidebar_opened(data: any): void;
|
|
||||||
}>;
|
|
|
@ -1,122 +0,0 @@
|
||||||
import { nextTick } from 'vue'
|
|
||||||
import { defineStore } from 'pinia'
|
|
||||||
import defaultSettings from '@/settings'
|
|
||||||
import router, { constantRoutes } from '@/router'
|
|
||||||
export const useBasicStore = defineStore('basic', {
|
|
||||||
state: () => {
|
|
||||||
return {
|
|
||||||
token: '',
|
|
||||||
getUserInfo: false,
|
|
||||||
userInfo: {
|
|
||||||
userName: '',
|
|
||||||
avatar: ''
|
|
||||||
},
|
|
||||||
allRoutes: [],
|
|
||||||
buttonCodes: [],
|
|
||||||
filterAsyncRoutes: [],
|
|
||||||
roles: [],
|
|
||||||
codes: [],
|
|
||||||
cachedViews: [],
|
|
||||||
cachedViewsDeep: [],
|
|
||||||
sidebar: { opened: true },
|
|
||||||
axiosPromiseArr: [],
|
|
||||||
settings: defaultSettings
|
|
||||||
}
|
|
||||||
},
|
|
||||||
persist: {
|
|
||||||
storage: localStorage,
|
|
||||||
paths: ['token']
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
setToken(data) {
|
|
||||||
this.token = data
|
|
||||||
},
|
|
||||||
setFilterAsyncRoutes(routes) {
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.filterAsyncRoutes = routes
|
|
||||||
state.allRoutes = constantRoutes.concat(routes)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setUserInfo({ userInfo, roles, codes }) {
|
|
||||||
const { username, avatar } = userInfo
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.roles = roles
|
|
||||||
state.codes = codes
|
|
||||||
state.getUserInfo = true
|
|
||||||
state.userInfo.username = username
|
|
||||||
state.userInfo.avatar = avatar
|
|
||||||
})
|
|
||||||
},
|
|
||||||
resetState() {
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.token = ''
|
|
||||||
state.roles = []
|
|
||||||
state.codes = []
|
|
||||||
state.allRoutes = []
|
|
||||||
state.buttonCodes = []
|
|
||||||
state.filterAsyncRoutes = []
|
|
||||||
state.userInfo.username = ''
|
|
||||||
state.userInfo.avatar = ''
|
|
||||||
})
|
|
||||||
this.getMyInfo = false
|
|
||||||
},
|
|
||||||
resetStateAndToLogin() {
|
|
||||||
this.resetState()
|
|
||||||
nextTick(() => {
|
|
||||||
router.push({ path: '/login' })
|
|
||||||
})
|
|
||||||
},
|
|
||||||
M_settings(data) {
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.settings = { ...state.settings, ...data }
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setSidebarOpen(data) {
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.sidebar.opened = data
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setToggleSideBar() {
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.sidebar.opened = !state.sidebar.opened
|
|
||||||
})
|
|
||||||
},
|
|
||||||
addCachedView(view) {
|
|
||||||
this.$patch((state) => {
|
|
||||||
if (state.cachedViews.includes(view)) return
|
|
||||||
state.cachedViews.push(view)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
delCachedView(view) {
|
|
||||||
this.$patch((state) => {
|
|
||||||
const index = state.cachedViews.indexOf(view)
|
|
||||||
index > -1 && state.cachedViews.splice(index, 1)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
M_RESET_CACHED_VIEW() {
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.cachedViews = []
|
|
||||||
})
|
|
||||||
},
|
|
||||||
addCachedViewDeep(view) {
|
|
||||||
this.$patch((state) => {
|
|
||||||
if (state.cachedViewsDeep.includes(view)) return
|
|
||||||
state.cachedViewsDeep.push(view)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setCacheViewDeep(view) {
|
|
||||||
this.$patch((state) => {
|
|
||||||
const index = state.cachedViewsDeep.indexOf(view)
|
|
||||||
index > -1 && state.cachedViewsDeep.splice(index, 1)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
M_RESET_CACHED_VIEW_DEEP() {
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.cachedViewsDeep = []
|
|
||||||
})
|
|
||||||
},
|
|
||||||
A_sidebar_opened(data) {
|
|
||||||
this.setSidebarOpen(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
8
ts-out-dir/src/store/tagsView.d.ts
vendored
8
ts-out-dir/src/store/tagsView.d.ts
vendored
|
@ -1,8 +0,0 @@
|
||||||
export declare const useTagsViewStore: import("pinia").StoreDefinition<"tagsView", {
|
|
||||||
visitedViews: never[];
|
|
||||||
}, {}, {
|
|
||||||
addVisitedView(view: any): void;
|
|
||||||
delVisitedView(view: any): Promise<unknown>;
|
|
||||||
delOthersVisitedViews(view: any): Promise<unknown>;
|
|
||||||
delAllVisitedViews(): Promise<unknown>;
|
|
||||||
}>;
|
|
|
@ -1,59 +0,0 @@
|
||||||
import { defineStore } from 'pinia';
|
|
||||||
import setting from '@/settings';
|
|
||||||
export const useTagsViewStore = defineStore('tagsView', {
|
|
||||||
state: () => {
|
|
||||||
return {
|
|
||||||
visitedViews: []
|
|
||||||
};
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
addVisitedView(view) {
|
|
||||||
this.$patch((state) => {
|
|
||||||
if (state.visitedViews.some((v) => v.path === view.path))
|
|
||||||
return;
|
|
||||||
if (state.visitedViews.length >= setting.tagsViewNum) {
|
|
||||||
state.visitedViews.pop();
|
|
||||||
state.visitedViews.push(Object.assign({}, view, {
|
|
||||||
title: view.meta.title || 'no-name'
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
state.visitedViews.push(Object.assign({}, view, {
|
|
||||||
title: view.meta.title || 'no-name'
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
delVisitedView(view) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.$patch((state) => {
|
|
||||||
for (const [i, v] of state.visitedViews.entries()) {
|
|
||||||
if (v.path === view.path) {
|
|
||||||
state.visitedViews.splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resolve([...state.visitedViews]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
delOthersVisitedViews(view) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.visitedViews = state.visitedViews.filter((v) => {
|
|
||||||
return v.meta.affix || v.path === view.path;
|
|
||||||
});
|
|
||||||
resolve([...state.visitedViews]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
delAllVisitedViews() {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
this.$patch((state) => {
|
|
||||||
state.visitedViews = state.visitedViews.filter((tag) => tag.meta?.affix);
|
|
||||||
resolve([...state.visitedViews]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
1
ts-out-dir/src/utils/axios-req.d.ts
vendored
1
ts-out-dir/src/utils/axios-req.d.ts
vendored
|
@ -1 +0,0 @@
|
||||||
export default function request(config: any): import('axios').AxiosPromise<any>
|
|
|
@ -1,56 +0,0 @@
|
||||||
import axios from 'axios'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import { useBasicStore } from '@/store/basic'
|
|
||||||
const service = axios.create()
|
|
||||||
service.interceptors.request.use(
|
|
||||||
(req) => {
|
|
||||||
const { token, axiosPromiseArr } = useBasicStore()
|
|
||||||
req.cancelToken = new axios.CancelToken((cancel) => {
|
|
||||||
axiosPromiseArr.push({
|
|
||||||
url: req.url,
|
|
||||||
cancel
|
|
||||||
})
|
|
||||||
})
|
|
||||||
req.headers['AUTHORIZE_TOKEN'] = token
|
|
||||||
if ('get'.includes(req.method?.toLowerCase())) req.params = req.data
|
|
||||||
return req
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
Promise.reject(err)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
service.interceptors.response.use(
|
|
||||||
(res) => {
|
|
||||||
const { code } = res.data
|
|
||||||
const successCode = '0,200,20000'
|
|
||||||
const noAuthCode = '401,403'
|
|
||||||
if (successCode.includes(code)) {
|
|
||||||
return res.data
|
|
||||||
} else {
|
|
||||||
if (noAuthCode.includes(code) && !location.href.includes('/login')) {
|
|
||||||
ElMessageBox.confirm('请重新登录', {
|
|
||||||
confirmButtonText: '重新登录',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
useBasicStore().resetStateAndToLogin()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return Promise.reject(res.data)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
ElMessage.error({
|
|
||||||
message: err,
|
|
||||||
duration: 2 * 1000
|
|
||||||
})
|
|
||||||
return Promise.reject(err)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
export default function request(config) {
|
|
||||||
return service({
|
|
||||||
baseURL: import.meta.env.VITE_APP_BASE_URL,
|
|
||||||
timeout: 8000,
|
|
||||||
...config
|
|
||||||
})
|
|
||||||
}
|
|
2
ts-out-dir/src/utils/bus.d.ts
vendored
2
ts-out-dir/src/utils/bus.d.ts
vendored
|
@ -1,2 +0,0 @@
|
||||||
declare const _default: import("mitt").Emitter<Record<import("mitt").EventType, unknown>>;
|
|
||||||
export default _default;
|
|
|
@ -1,2 +0,0 @@
|
||||||
import mitt from 'mitt';
|
|
||||||
export default mitt();
|
|
16
ts-out-dir/src/utils/common-util.d.ts
vendored
16
ts-out-dir/src/utils/common-util.d.ts
vendored
|
@ -1,16 +0,0 @@
|
||||||
declare const _default: {
|
|
||||||
getWeek(): string;
|
|
||||||
mobilePhone(str: any): boolean;
|
|
||||||
toSplitNumFor(num: any, numToSpace: any): any;
|
|
||||||
bankCardNo(str: any): boolean;
|
|
||||||
regEmail(str: any): boolean;
|
|
||||||
idCardNumber(str: any): boolean;
|
|
||||||
deleteArrItem(arr: any, arrItem: any): void;
|
|
||||||
arrToRepeat(arr: any): any;
|
|
||||||
deRepeatArr(seriesArr: any): unknown[];
|
|
||||||
byArrObjDeleteArrObj2(arrObj: any, arrObj2: any, objKey: any): any;
|
|
||||||
deleteArrObjByKey(arrObj: any, objKey: any, value: any): any;
|
|
||||||
findArrObjByKey(arrObj: any, objKey: any, value: any): any;
|
|
||||||
byArrObjFindArrObj2(arrObj: any, arrObj2: any, objKey: any): any[];
|
|
||||||
};
|
|
||||||
export default _default;
|
|
|
@ -1,66 +0,0 @@
|
||||||
export default {
|
|
||||||
getWeek() {
|
|
||||||
return `星期${'日一二三四五六'.charAt(new Date().getDay())}`;
|
|
||||||
},
|
|
||||||
mobilePhone(str) {
|
|
||||||
const reg = /^0?1[0-9]{10}$/;
|
|
||||||
return reg.test(str);
|
|
||||||
},
|
|
||||||
toSplitNumFor(num, numToSpace) {
|
|
||||||
return num.replace(/(.{4})/g, '$1 ');
|
|
||||||
},
|
|
||||||
bankCardNo(str) {
|
|
||||||
const reg = /^\d{15,20}$/;
|
|
||||||
return reg.test(str);
|
|
||||||
},
|
|
||||||
regEmail(str) {
|
|
||||||
const reg = /^([a-zA-Z]|[0-9])(\w|-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/;
|
|
||||||
return reg.test(str);
|
|
||||||
},
|
|
||||||
idCardNumber(str) {
|
|
||||||
const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
|
|
||||||
return reg.test(str);
|
|
||||||
},
|
|
||||||
deleteArrItem(arr, arrItem) {
|
|
||||||
arr.splice(arr.indexOf(arrItem), 1);
|
|
||||||
},
|
|
||||||
arrToRepeat(arr) {
|
|
||||||
return arr.filter((ele, index, thisArr) => {
|
|
||||||
return thisArr.indexOf(ele) === index;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deRepeatArr(seriesArr) {
|
|
||||||
return [...new Set(seriesArr)];
|
|
||||||
},
|
|
||||||
byArrObjDeleteArrObj2(arrObj, arrObj2, objKey) {
|
|
||||||
arrObj
|
|
||||||
.map((value) => {
|
|
||||||
return value[objKey];
|
|
||||||
})
|
|
||||||
.forEach((value2) => {
|
|
||||||
arrObj2.splice(arrObj2.findIndex((item) => item[objKey] === value2), 1);
|
|
||||||
});
|
|
||||||
return arrObj2;
|
|
||||||
},
|
|
||||||
deleteArrObjByKey(arrObj, objKey, value) {
|
|
||||||
arrObj.splice(arrObj.findIndex((item) => item[objKey] === value), 1);
|
|
||||||
return arrObj;
|
|
||||||
},
|
|
||||||
findArrObjByKey(arrObj, objKey, value) {
|
|
||||||
return arrObj[arrObj.findIndex((item) => item[objKey] == value)];
|
|
||||||
},
|
|
||||||
byArrObjFindArrObj2(arrObj, arrObj2, objKey) {
|
|
||||||
const arrObj3 = [];
|
|
||||||
arrObj
|
|
||||||
.map((value) => {
|
|
||||||
return value[objKey];
|
|
||||||
})
|
|
||||||
.forEach((value2) => {
|
|
||||||
const arrIndex = arrObj2.findIndex((item) => item[objKey] === value2);
|
|
||||||
if (arrIndex !== -1) {
|
|
||||||
arrObj3.push(arrObj2[arrIndex]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return arrObj3;
|
|
||||||
}
|
|
||||||
};
|
|
2
ts-out-dir/src/views/redirect/index.d.ts
vendored
2
ts-out-dir/src/views/redirect/index.d.ts
vendored
|
@ -1,2 +0,0 @@
|
||||||
declare const _default: import("vue").DefineComponent<{}, () => JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
|
|
||||||
export default _default;
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
export default defineComponent({
|
|
||||||
setup() {
|
|
||||||
const route = useRoute();
|
|
||||||
const router = useRouter();
|
|
||||||
onBeforeMount(() => {
|
|
||||||
const { params, query } = route;
|
|
||||||
const { path } = params;
|
|
||||||
router.replace({ path: `/${path}`, query });
|
|
||||||
});
|
|
||||||
return () => <div> </div>;
|
|
||||||
}
|
|
||||||
});
|
|
1
typings/auto-imports.d.ts
vendored
1
typings/auto-imports.d.ts
vendored
|
@ -90,6 +90,7 @@ declare global {
|
||||||
const useConfigStore: typeof import('../src/store/config')['useConfigStore']
|
const useConfigStore: typeof import('../src/store/config')['useConfigStore']
|
||||||
const useCssModule: typeof import('vue')['useCssModule']
|
const useCssModule: typeof import('vue')['useCssModule']
|
||||||
const useCssVars: typeof import('vue')['useCssVars']
|
const useCssVars: typeof import('vue')['useCssVars']
|
||||||
|
const useDebuggerStore: typeof import('../src/store/debuger')['useDebuggerStore']
|
||||||
const useElement: typeof import('../src/hooks/use-element')['useElement']
|
const useElement: typeof import('../src/hooks/use-element')['useElement']
|
||||||
const useErrorLog: typeof import('../src/hooks/use-error-log')['useErrorLog']
|
const useErrorLog: typeof import('../src/hooks/use-error-log')['useErrorLog']
|
||||||
const useLink: typeof import('vue-router')['useLink']
|
const useLink: typeof import('vue-router')['useLink']
|
||||||
|
|
Loading…
Reference in New Issue
Block a user