This commit is contained in:
谷成伟 2024-06-17 17:28:23 +08:00
commit 26699c4910
23 changed files with 96 additions and 280 deletions

View File

@ -4,9 +4,6 @@ ENV = 'development'
# base路径
VITE_BASE_PATH = './'
# 网站是否不需要权限认证: NoAuth Auth
VITE_APP_NO_AUTH='NoAuth'
# 代理配置(开发使用),必须在一行中
VITE_APP_PROXY=[["/api","https://usp2.jsspisoft.com/api"]]

View File

@ -42,6 +42,7 @@
"@typescript-eslint/parser": "7.12.0",
"@vitejs/plugin-vue": "5.0.5",
"async-validator": "4.2.5",
"crypto-js": "^4.2.0",
"eslint": "8.56.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-vue": "9.26.0",

View File

@ -24,12 +24,9 @@ export function login(method: 'get' | 'post', params: object = {}) {
}
export function logout() {
const adminInfo = useAdminInfo()
// const adminInfo = useAdminInfo()
return createAxios({
url: '/api/auth/token/revoke',
method: 'POST',
data: {
refreshToken: adminInfo.getToken('refresh'),
},
})
}

View File

@ -1,12 +0,0 @@
/**
* frontend common language package
*/
export default {
Integral: 'Integral',
Balance: 'Balance',
Language: 'Language',
Copyright: 'Copyright',
'Member Center': 'Member Center',
'Logout login': 'Logout',
'Member center disabled': 'The member center has been disabled. Please contact the webmaster to turn it on.',
}

View File

@ -1,3 +0,0 @@
export default {
'Steve Jobs': "Great art don't have to follow the trend, it alone can lead.-- Steve Jobs",
}

View File

@ -1,6 +0,0 @@
export default {
'Change time': 'Change time',
'Current balance': 'Current balance',
'Balance after change': 'Balance after change',
'Balance change record': 'Balance change record',
}

View File

@ -1,8 +0,0 @@
export default {
'Change Password': 'Change Password',
'Old password': 'Old password',
'New password': 'New password',
'Confirm new password': 'Confirm new password',
'Please enter your current password': 'Please enter your current password',
'The duplicate password does not match the new password': 'The duplicate password does not match the new password',
}

View File

@ -1,6 +0,0 @@
export default {
'Change time': 'Change time',
'Current points': 'Current points',
'Points after change': 'Points after change',
'Score change record': 'Score change record',
}

View File

@ -1,11 +0,0 @@
export default {
'Account information': 'Account information',
'personal data': 'personal data',
'Filled in': 'Filled in',
'Not filled in': 'Not filled in',
mobile: 'mobile',
email: 'email',
'Last login IP': 'Last login IP',
'Last login': 'Last login',
'Growth statistics': 'Growth statistics',
}

View File

@ -1,32 +0,0 @@
export default {
'personal data': 'personal data',
'Change Password': 'Change Password',
'head portrait': 'head portrait',
'User name': 'User name',
'User nickname': 'User nickname',
mail: 'mail',
email: 'email',
'Operation via right button': 'Operation via right button',
'Click Modify': 'Click Modify',
bind: 'bind',
mobile: 'mobile',
Gender: 'Gender',
secrecy: 'secrecy',
male: 'male',
female: 'female',
birthday: 'birthday',
'Personal signature': 'Personal signature',
'Account verification': 'Account verification',
'Account password verification': 'Account password verification',
'Mail verification': 'Mail verification',
'SMS verification': 'SMS verification',
password: 'password',
accept: 'accept',
'next step': 'next step',
'New email': 'New email',
'New mobile': 'New mobile',
'Verification Code': 'Captcha',
send: 'send',
seconds: 'seconds',
nickname: 'nickname',
}

View File

@ -1,24 +0,0 @@
export default {
reach: ' Reach ',
login: 'Login',
register: 'Register',
'Via email': 'By email',
'Via mobile number': 'By mobile number',
'User name': 'User name',
account: 'Username/Email/Mobile',
password: 'Password',
'Verification Code': 'Captcha',
mobile: 'mobile',
email: 'email',
send: 'send',
seconds: 'seconds',
'Remember me': 'Remember me',
'Forgot your password?': 'Forgot your password?',
'Back to login': 'Back to login',
'No account yet? Click Register': 'No account yet? Click Register',
'Retrieve password': 'Retrieve password',
'Retrieval method': 'Retrieval method',
'New password': 'New password',
second: 'second',
'Account name': 'Account name',
}

View File

@ -1,13 +0,0 @@
/**
*
* 使 key
*/
export default {
Integral: '积分',
Balance: '余额',
Language: '语言',
Copyright: '版权所有',
'Member Center': '会员中心',
'Logout login': '注销登录',
'Member center disabled': '会员中心已禁用,请联系网站管理员开启。',
}

View File

@ -1,3 +0,0 @@
export default {
'Steve Jobs': '伟大的艺术品不必追随潮流,他本身就能引领潮流。 -- 乔布斯',
}

View File

@ -1,6 +0,0 @@
export default {
'Change time': '变更时间',
'Current balance': '当前余额',
'Balance after change': '变更后余额',
'Balance change record': '余额变更记录',
}

View File

@ -1,8 +0,0 @@
export default {
'Change Password': '修改密码',
'Old password': '旧密码',
'New password': '新密码',
'Confirm new password': '确认新密码',
'Please enter your current password': '请输入现在的密码',
'The duplicate password does not match the new password': '重复密码与新密码不相符',
}

View File

@ -1,6 +0,0 @@
export default {
'Change time': '变更时间',
'Current points': '当前积分',
'Points after change': '变更后积分',
'Score change record': '积分变更记录',
}

View File

@ -1,11 +0,0 @@
export default {
'Account information': '账户信息',
'personal data': '个人资料',
'Filled in': '已填写',
'Not filled in': '未填写',
mobile: '手机号',
email: '电子邮箱',
'Last login IP': '最后登录IP',
'Last login': '最后登录',
'Growth statistics': '增长统计',
}

View File

@ -1,32 +0,0 @@
export default {
'personal data': '个人资料',
'Change Password': '修改密码',
'head portrait': '头像',
'User name': '用户名',
'User nickname': '用户昵称',
mail: '邮箱',
email: '电子邮箱',
'Operation via right button': '通过右侧按钮操作',
'Click Modify': '点击修改',
bind: '绑定',
mobile: '手机号',
Gender: '性别',
secrecy: '保密',
male: '男',
female: '女',
birthday: '生日',
'Personal signature': '个性签名',
'Account verification': '账户验证',
'Account password verification': '账户密码验证',
'Mail verification': '邮件验证',
'SMS verification': '短信验证',
password: '密码',
accept: '接受',
'next step': '下一步',
'New email': '新邮箱',
'New mobile': '新手机号',
'Verification Code': '验证码',
send: '发送',
seconds: '秒',
nickname: '昵称',
}

View File

@ -1,24 +0,0 @@
export default {
reach: '到',
login: '登录',
register: '注册',
'Via email': '通过邮箱',
'Via mobile number': '通过手机号',
'User name': '用户名',
account: '用户名/邮箱/手机号',
password: '密码',
'Verification Code': '验证码',
mobile: '手机号',
email: '电子邮箱',
send: '发送',
seconds: '秒',
'Remember me': '记住我',
'Forgot your password?': '忘记密码?',
'Back to login': '回到登录',
'No account yet? Click Register': '还没有账户?点击注册',
'Retrieve password': '找回密码',
'Retrieval method': '找回方式',
'New password': '新密码',
second: '确定',
'Account name': '账户',
}

View File

@ -160,6 +160,7 @@ const onAdminInfo = () => {
const onLogout = () => {
logout().then(() => {
debugger
Local.remove(ADMIN_INFO)
router.go(0)
})

View File

@ -18,7 +18,7 @@ export const useSiteConfig = defineStore('siteConfig', {
},
headNav: [],
initialize: false,
userInitialize: false,
userInitialize: true,
}
},
actions: {

View File

@ -8,7 +8,7 @@ import adminBaseRoute from '/@/router/static/adminBase'
import { useAdminInfo } from '/@/stores/adminInfo'
import { useConfig } from '/@/stores/config'
import { useUserInfo } from '/@/stores/userInfo'
import { isAdminApp } from '/@/utils/common'
import { encrypt_aes, decrypt_aes, generateRandomNumber } from './crypto'
window.requests = []
window.tokenRefreshing = false
@ -50,7 +50,6 @@ function createAxios<Data = any, T = ApiPromise<Data>>(axiosConfig: AxiosRequest
headers: {
'think-lang': config.lang.defaultLang,
server: true,
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
responseType: 'json',
})
@ -59,6 +58,7 @@ function createAxios<Data = any, T = ApiPromise<Data>>(axiosConfig: AxiosRequest
// if (adminBaseRoute.path != '/admin' && isAdminApp() && /^\/admin\//.test(axiosConfig.url!)) {
// axiosConfig.url = axiosConfig.url!.replace(/^\/admin\//, adminBaseRoute.path + '.php/')
// }
alert(axiosConfig.data)
// 合并默认请求选项
options = Object.assign(
@ -89,8 +89,11 @@ function createAxios<Data = any, T = ApiPromise<Data>>(axiosConfig: AxiosRequest
// 自动携带token
if (config.headers) {
const v = generateRandomNumber(16)
config.headers.v = v
const token = adminInfo.getToken()
if (token) (config.headers as anyObj).token = token
if (token) (config.headers as anyObj).token = encrypt_aes(token, v)
// const userToken = options.anotherToken || userInfo.getToken()
// if (userToken) (config.headers as anyObj)['token'] = userToken
}
@ -105,76 +108,54 @@ function createAxios<Data = any, T = ApiPromise<Data>>(axiosConfig: AxiosRequest
// 响应拦截
Axios.interceptors.response.use(
(response) => {
debugger
removePending(response.config)
options.loading && closeLoading(options) // 关闭loading
if (response.config.responseType == 'json') {
if (response.data && response.data.code !== 200) {
if (response.data.code == 409) {
if (!window.tokenRefreshing) {
window.tokenRefreshing = true
return refreshToken()
.then((res) => {
if (res.data.type == 'admin-refresh') {
adminInfo.setToken(res.data.token, 'auth')
response.headers.batoken = `${res.data.token}`
window.requests.forEach((cb) => cb(res.data.token, 'admin-refresh'))
} else if (res.data.type == 'user-refresh') {
userInfo.setToken(res.data.token, 'auth')
response.headers['ba-user-token'] = `${res.data.token}`
window.requests.forEach((cb) => cb(res.data.token, 'user-refresh'))
}
window.requests = []
return Axios(response.config)
})
.catch((err) => {
adminInfo.removeToken()
if (router.currentRoute.value.name != 'adminLogin') {
router.push({ name: 'adminLogin' })
return Promise.reject(err)
} else {
response.headers.batoken = ''
window.requests.forEach((cb) => cb('', 'admin-refresh'))
window.requests = []
return Axios(response.config)
}
})
.finally(() => {
window.tokenRefreshing = false
})
} else {
return new Promise((resolve) => {
// 用函数形式将 resolve 存入,等待刷新后再执行
window.requests.push((token: string, type: string) => {
if (type == 'admin-refresh') {
response.headers.batoken = `${token}`
} else {
response.headers['ba-user-token'] = `${token}`
}
resolve(Axios(response.config))
})
})
}
}
if (options.showCodeMessage) {
ElNotification({
type: 'error',
message: response.data.msg,
})
}
// 自动跳转到路由name或path
if (response.data.code == 302) {
router.push({ path: response.data.data.routePath ?? '', name: response.data.data.routeName ?? '' })
}
if (response.data.code == 303) {
// if (response.data.code == 409) {
// if (!window.tokenRefreshing) {
// window.tokenRefreshing = true
// return refreshToken()
// .then((res) => {
// adminInfo.setToken(res.data.token, 'auth')
// response.headers.token = `${res.data.token}`
// window.requests.forEach((cb) => cb(res.data.token, 'admin-refresh'))
// window.requests = []
// return Axios(response.config)
// })
// .catch((err) => {
// adminInfo.removeToken()
// router.push({ name: 'adminLogin' })
// return Promise.reject(err)
// })
// .finally(() => {
// window.tokenRefreshing = false
// })
// } else {
// return new Promise((resolve) => {
// // 用函数形式将 resolve 存入,等待刷新后再执行
// window.requests.push((token: string, type: string) => {
// response.headers.token = `${token}`
// resolve(Axios(response.config))
// })
// })
// }
// }
// if (options.showCodeMessage) {
// ElNotification({
// type: 'error',
// message: response.data.msg,
// })
// }
// // 自动跳转到路由name或path
// if (response.data.code == 302) {
// router.push({ path: response.data.data.routePath ?? '', name: response.data.data.routeName ?? '' })
// }
if (response.data.code == 401) {
let routerPath = adminBaseRoute.path
// 需要登录,清理 token转到登录页
if (response.data.data.type == 'need login') {
userInfo.removeToken()
routerPath += '/login'
}
userInfo.removeToken()
routerPath += '/login'
router.push({ path: routerPath })
}
// code不等于1, 页面then内的具体逻辑就不执行了

View File

@ -0,0 +1,44 @@
import CryptoJS from 'crypto-js'
const key = ''
export function encrypt_aes(plaintText: string, iv: string) {
const encryptedData = CryptoJS.AES.encrypt(plaintText, key, {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
})
const encryptedBase64Str = encryptedData.toString()
// 需要读取encryptedData上的ciphertext.toString()才能拿到跟Java一样的密文
const encryptedStr = encryptedData.ciphertext.toString()
return encryptedData.toString(CryptoJS.format.Base64)
}
export function decrypt_aes(word: string, iv: string) {
var decrypt = CryptoJS.AES.decrypt(word, key, {
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
})
//解密后需要按照Utf8的方式将明文转位字符串
var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
return decryptedStr
}
export function generateRandomNumber(length: number) {
// 生成一个指定长度的随机数字字符串
let result = ''
const characters = '0123456789'
const charactersLength = characters.length
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength))
}
return result
}