版本升级:
1. 修复(kinit-admin):页面缓存问题修复 2. 更新(kinit-api,kinit-admin):菜单管理新增是否缓存字段 3. 更新(kinit-admin):将缓存默认存储在localStorage中 4. 更新(kinit-api):将python-jose库更换为pyjwt库 5. 优化(kinit-admin,kinit-uni):退出登录方法优化 6. 优化(kinit-admin,kinit-uni):response拦截优化 7. 新增(kinit-api,kinit-admin,kinit-uni):jwt到期时间缩短,加入刷新token功能 8. (kinit-uni)切换到 vscode 开发 uniapp 项目
This commit is contained in:
parent
06012fda6e
commit
ff56a184ca
@ -5,6 +5,7 @@ import { useAuthStore } from '@/store/modules/auth'
|
||||
import qs from 'qs'
|
||||
import { config } from './config'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import request from '@/config/axios'
|
||||
|
||||
const { result_code, unauthorized_code, request_timeout } = config
|
||||
|
||||
@ -62,33 +63,99 @@ service.interceptors.request.use(
|
||||
// response 拦截器
|
||||
service.interceptors.response.use(
|
||||
(response: AxiosResponse<any>) => {
|
||||
// 这个状态码是和后端约定好的
|
||||
const code = response.data.code || unauthorized_code
|
||||
const message = response.data.message || '后端接口无返回内容'
|
||||
const refresh = response.data.refresh || false
|
||||
|
||||
if (response.config.responseType === 'blob') {
|
||||
// 如果是文件流,直接过
|
||||
return response
|
||||
} else if (response.data.code === result_code) {
|
||||
} else if (code === result_code) {
|
||||
if (refresh) {
|
||||
// 因token快过期,刷新token
|
||||
refreshToken().then((res) => {
|
||||
const appStore = useAppStore()
|
||||
wsCache.set(appStore.getToken, `${res.data.token_type} ${res.data.access_token}`)
|
||||
wsCache.set(appStore.getRefreshToken, res.data.refresh_token)
|
||||
})
|
||||
// .catch(() => {
|
||||
// const authStore = useAuthStore()
|
||||
// authStore.logout()
|
||||
// ElMessage.error('未认证,请登录')
|
||||
// })
|
||||
}
|
||||
return response.data
|
||||
} else if (response.data.code === unauthorized_code) {
|
||||
// 请重新登录
|
||||
ElMessage.error(response.data.message)
|
||||
const authStore = useAuthStore()
|
||||
authStore.logout()
|
||||
} else if (code === unauthorized_code) {
|
||||
// 因token无效,token过期导致
|
||||
refreshToken().then((res) => {
|
||||
const appStore = useAppStore()
|
||||
wsCache.set(appStore.getToken, `${res.data.token_type} ${res.data.access_token}`)
|
||||
wsCache.set(appStore.getRefreshToken, res.data.refresh_token)
|
||||
ElMessage.error('操作失败,请重试')
|
||||
})
|
||||
// .catch(() => {
|
||||
// const authStore = useAuthStore()
|
||||
// authStore.logout()
|
||||
// ElMessage.error('未认证,请登录')
|
||||
// })
|
||||
} else {
|
||||
ElMessage.error(response.data.message)
|
||||
ElMessage.error(message)
|
||||
}
|
||||
},
|
||||
(error: AxiosError) => {
|
||||
console.log('err' + error)
|
||||
let { message } = error
|
||||
if (message == 'Network Error') {
|
||||
message = '后端接口连接异常'
|
||||
} else if (message.includes('timeout')) {
|
||||
message = '系统接口请求超时'
|
||||
} else if (message.includes('Request failed with status code')) {
|
||||
message = '系统接口' + message.substr(message.length - 3) + '异常'
|
||||
const status = error.response?.status
|
||||
switch (status) {
|
||||
case 400:
|
||||
message = '请求错误'
|
||||
break
|
||||
case 401:
|
||||
// 强制要求重新登录,因账号已冻结,账号已过期,手机号码错误,刷新token无效等问题导致
|
||||
const authStore = useAuthStore()
|
||||
authStore.logout()
|
||||
message = '未认证,请登录'
|
||||
break
|
||||
case 403:
|
||||
message = '拒绝访问'
|
||||
break
|
||||
case 404:
|
||||
message = `请求地址出错: ${error.response?.config.url}`
|
||||
break
|
||||
case 408:
|
||||
message = '请求超时'
|
||||
break
|
||||
case 500:
|
||||
message = '服务器内部错误'
|
||||
break
|
||||
case 501:
|
||||
message = '服务未实现'
|
||||
break
|
||||
case 502:
|
||||
message = '网关错误'
|
||||
break
|
||||
case 503:
|
||||
message = '服务不可用'
|
||||
break
|
||||
case 504:
|
||||
message = '网关超时'
|
||||
break
|
||||
case 505:
|
||||
message = 'HTTP版本不受支持'
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
ElMessage.error(message)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 刷新Token
|
||||
const refreshToken = (): Promise<IResponse> => {
|
||||
const appStore = useAppStore()
|
||||
const data = wsCache.get(appStore.getRefreshToken)
|
||||
return request.post({ url: '/auth/token/refresh/', data })
|
||||
}
|
||||
|
||||
export { service }
|
||||
|
@ -1,12 +1,14 @@
|
||||
/**
|
||||
* 配置浏览器本地存储的方式,可直接存储对象数组。
|
||||
* sessionStorage 多标签页情况下互不共享
|
||||
* localStorage 多标签页情况下互相共享
|
||||
*/
|
||||
|
||||
import WebStorageCache from 'web-storage-cache'
|
||||
|
||||
type CacheType = 'sessionStorage' | 'localStorage'
|
||||
|
||||
export const useCache = (type: CacheType = 'sessionStorage') => {
|
||||
export const useCache = (type: CacheType = 'localStorage') => {
|
||||
const wsCache: WebStorageCache = new WebStorageCache({
|
||||
storage: type
|
||||
})
|
||||
|
@ -39,6 +39,7 @@ interface AppState {
|
||||
footerContent: string
|
||||
icpNumber: string
|
||||
token: string
|
||||
refreshToken: string
|
||||
}
|
||||
|
||||
export const useAppStore = defineStore('app', {
|
||||
@ -46,6 +47,7 @@ export const useAppStore = defineStore('app', {
|
||||
return {
|
||||
userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
||||
token: 'Token', // 存储Token字段
|
||||
refreshToken: 'RefreshToken', // 存储刷新Token字段
|
||||
sizeMap: ['default', 'large', 'small'],
|
||||
mobile: false, // 是否是移动端
|
||||
title: import.meta.env.VITE_APP_TITLE, // 标题
|
||||
@ -170,6 +172,9 @@ export const useAppStore = defineStore('app', {
|
||||
getToken(): string {
|
||||
return this.token
|
||||
},
|
||||
getRefreshToken(): string {
|
||||
return this.refreshToken
|
||||
},
|
||||
getIsDark(): boolean {
|
||||
return this.isDark
|
||||
},
|
||||
|
@ -7,6 +7,7 @@ import { useCache } from '@/hooks/web/useCache'
|
||||
import { getCurrentAdminUserInfo } from '@/api/vadmin/auth/user'
|
||||
import { resetRouter } from '@/router'
|
||||
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||
import router from '@/router'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
|
||||
@ -48,6 +49,7 @@ export const useAuthStore = defineStore('auth', {
|
||||
if (res) {
|
||||
const appStore = useAppStore()
|
||||
wsCache.set(appStore.getToken, `${res.data.token_type} ${res.data.access_token}`)
|
||||
wsCache.set(appStore.getRefreshToken, res.data.refresh_token)
|
||||
// 存储用户信息
|
||||
const auth = useAuthStore()
|
||||
await auth.getUserInfo()
|
||||
@ -61,7 +63,7 @@ export const useAuthStore = defineStore('auth', {
|
||||
const tagsViewStore = useTagsViewStore()
|
||||
tagsViewStore.delAllViews()
|
||||
resetRouter()
|
||||
window.location.href = '/login'
|
||||
router.push('/login')
|
||||
},
|
||||
updateUser(data: UserState) {
|
||||
this.user.gender = data.gender
|
||||
|
@ -24,6 +24,7 @@ const rules = reactive({
|
||||
disabled: [required()],
|
||||
hidden: [required()],
|
||||
path: [required()],
|
||||
noCache: [required()],
|
||||
order: [required()]
|
||||
})
|
||||
|
||||
|
@ -44,6 +44,12 @@ export const columns = reactive<TableColumn[]>([
|
||||
label: '组件路径',
|
||||
show: true
|
||||
},
|
||||
{
|
||||
field: 'noCache',
|
||||
label: '页面缓存',
|
||||
width: '120px',
|
||||
show: true
|
||||
},
|
||||
{
|
||||
field: 'hidden',
|
||||
label: '显示状态',
|
||||
@ -224,5 +230,31 @@ export const schema = reactive<FormSchema[]>([
|
||||
span: 12
|
||||
},
|
||||
ifshow: (values) => values.menu_type === '2'
|
||||
},
|
||||
{
|
||||
field: 'noCache',
|
||||
label: '页面缓存',
|
||||
colProps: {
|
||||
span: 12
|
||||
},
|
||||
component: 'Radio',
|
||||
componentProps: {
|
||||
style: {
|
||||
width: '100%'
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: '缓存',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
label: '不缓存',
|
||||
value: true
|
||||
}
|
||||
]
|
||||
},
|
||||
value: false,
|
||||
ifshow: (values) => values.menu_type === '1',
|
||||
labelMessage: '开启页面缓存,需要组件名称必须与xx.vue页面的name一致'
|
||||
}
|
||||
])
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'AuthMenu'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { RightToolbar } from '@/components/RightToolbar'
|
||||
@ -213,12 +219,16 @@ watch(
|
||||
<ElSwitch :value="!row.hidden" disabled />
|
||||
</template>
|
||||
|
||||
<template #noCache="{ row }">
|
||||
<ElSwitch :value="!row.noCache" disabled />
|
||||
</template>
|
||||
|
||||
<template #disabled="{ row }">
|
||||
<ElSwitch :value="!row.disabled" disabled />
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<Dialog v-model="dialogVisible" :title="dialogTitle" width="700px">
|
||||
<Dialog v-model="dialogVisible" :title="dialogTitle" width="800px">
|
||||
<Write ref="writeRef" :current-row="tableObject.currentRow" :parent-id="parentId" />
|
||||
|
||||
<template #footer>
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'AuthRole'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { Table } from '@/components/Table'
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'AuthUser'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { Table } from '@/components/Table'
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'HelpIssueForm'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Form } from '@/components/Form'
|
||||
import { useForm } from '@/hooks/web/useForm'
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'HelpIssue'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { Table } from '@/components/Table'
|
||||
|
@ -118,7 +118,7 @@ export const searchSchema = reactive<FormSchema[]>([
|
||||
},
|
||||
{
|
||||
field: 'platform',
|
||||
label: '展示平台',
|
||||
label: '登录平台',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
style: {
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'HelpIssue'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { Table } from '@/components/Table'
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'SystemDictDetail'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { Table } from '@/components/Table'
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'SystemDict'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { Table } from '@/components/Table'
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'SystemRecordLogin'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { Table } from '@/components/Table'
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'SystemRecordOperation'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ContentWrap } from '@/components/ContentWrap'
|
||||
import { Table } from '@/components/Table'
|
||||
|
@ -1,3 +1,9 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'SystemSettings'
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElTabs, ElTabPane } from 'element-plus'
|
||||
import { ref } from 'vue'
|
||||
|
@ -11,7 +11,7 @@ from fastapi.security import OAuth2PasswordBearer
|
||||
"""
|
||||
系统版本
|
||||
"""
|
||||
VERSION = "1.6.1"
|
||||
VERSION = "1.6.2"
|
||||
|
||||
"""安全警告: 不要在生产中打开调试运行!"""
|
||||
DEBUG = True
|
||||
@ -21,6 +21,7 @@ DEMO = not DEBUG
|
||||
"""演示功能白名单"""
|
||||
DEMO_WHITE_LIST_PATH = [
|
||||
"/auth/login/",
|
||||
"/auth/token/refresh/",
|
||||
"/auth/wx/login/",
|
||||
"/vadmin/system/dict/types/details/",
|
||||
"/vadmin/auth/user/export/query/list/to/excel/"
|
||||
@ -49,8 +50,12 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login/", auto_error=False)
|
||||
SECRET_KEY = 'vgb0tnl9d58+6n-6h-ea&u^1#s0ccp!794=kbvqacjq75vzps$'
|
||||
"""用于设定 JWT 令牌签名算法"""
|
||||
ALGORITHM = "HS256"
|
||||
"""令牌过期时间,9999分钟"""
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 9999
|
||||
"""access_token 过期时间,一天"""
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 1440
|
||||
"""refresh_token 过期时间,用于刷新token使用,两天"""
|
||||
REFRESH_TOKEN_EXPIRE_MINUTES = 1440 * 2
|
||||
"""access_token 缓存时间,用于刷新token使用,30分钟"""
|
||||
ACCESS_TOKEN_CACHE_MINUTES = 30
|
||||
|
||||
"""
|
||||
挂载临时文件目录,并添加路由访问,此路由不会在接口文档中显示
|
||||
|
@ -30,11 +30,11 @@ async def get_banners(auth: Auth = Depends(AllUserAuth())):
|
||||
"id": 3, "image": "https://ktianc.oss-cn-beijing.aliyuncs.com/kinit/system/banner/2022-11-09/banner3.png"
|
||||
},
|
||||
]
|
||||
return SuccessResponse(data)
|
||||
return SuccessResponse(data, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/user/access/source/", summary="用户来源")
|
||||
async def get_user_access_source():
|
||||
async def get_user_access_source(auth: Auth = Depends(AllUserAuth())):
|
||||
data = [
|
||||
{"value": 1000, "name": 'analysis.directAccess'},
|
||||
{"value": 310, "name": 'analysis.mailMarketing'},
|
||||
@ -42,11 +42,11 @@ async def get_user_access_source():
|
||||
{"value": 135, "name": 'analysis.videoAdvertising'},
|
||||
{"value": 1548, "name": 'analysis.searchEngines'}
|
||||
]
|
||||
return SuccessResponse(data)
|
||||
return SuccessResponse(data, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/weekly/user/activity/", summary="每周用户活跃量")
|
||||
async def get_weekly_user_activity():
|
||||
async def get_weekly_user_activity(auth: Auth = Depends(AllUserAuth())):
|
||||
data = [
|
||||
{"value": 13253, "name": 'analysis.monday'},
|
||||
{"value": 34235, "name": 'analysis.tuesday'},
|
||||
@ -56,11 +56,11 @@ async def get_weekly_user_activity():
|
||||
{"value": 1322, "name": 'analysis.saturday'},
|
||||
{"value": 1324, "name": 'analysis.sunday'}
|
||||
]
|
||||
return SuccessResponse(data)
|
||||
return SuccessResponse(data, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/monthly/sales/", summary="每月销售额")
|
||||
async def get_monthly_sales():
|
||||
async def get_monthly_sales(auth: Auth = Depends(AllUserAuth())):
|
||||
data = [
|
||||
{"estimate": 100, "actual": 120, "name": 'analysis.january'},
|
||||
{"estimate": 120, "actual": 82, "name": 'analysis.february'},
|
||||
@ -75,4 +75,4 @@ async def get_monthly_sales():
|
||||
{"estimate": 118, "actual": 99, "name": 'analysis.november'},
|
||||
{"estimate": 123, "actual": 123, "name": 'analysis.december'}
|
||||
]
|
||||
return SuccessResponse(data)
|
||||
return SuccessResponse(data, refresh=auth.refresh)
|
||||
|
@ -4,10 +4,9 @@
|
||||
# @File : current.py
|
||||
# @IDE : PyCharm
|
||||
# @desc : 获取认证后的信息工具
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List, Optional
|
||||
|
||||
from jose import jwt, JWTError
|
||||
import jwt
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import joinedload
|
||||
from apps.vadmin.auth.crud import UserDal
|
||||
@ -43,7 +42,7 @@ class OpenAuth(AuthValidation):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def validate_token(cls, token: str | None, db: AsyncSession) -> str | None:
|
||||
def validate_token(cls, request: Request, token: str | None) -> str | None:
|
||||
"""
|
||||
验证用户 token,没有则返回 None
|
||||
"""
|
||||
@ -52,9 +51,19 @@ class OpenAuth(AuthValidation):
|
||||
try:
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||
telephone: str = payload.get("sub")
|
||||
if telephone is None:
|
||||
exp: int = payload.get("exp")
|
||||
is_refresh: bool = payload.get("is_refresh")
|
||||
if telephone is None or is_refresh:
|
||||
return None
|
||||
except JWTError:
|
||||
# 计算当前时间 + 缓冲时间是否大于等于 JWT 过期时间
|
||||
buffer_time = (datetime.now() + timedelta(minutes=settings.ACCESS_TOKEN_CACHE_MINUTES)).timestamp()
|
||||
if buffer_time >= exp:
|
||||
request.scope["refresh"] = True
|
||||
else:
|
||||
request.scope["refresh"] = False
|
||||
except jwt.exceptions.InvalidSignatureError:
|
||||
return None
|
||||
except jwt.exceptions.ExpiredSignatureError:
|
||||
return None
|
||||
return telephone
|
||||
|
||||
@ -83,7 +92,7 @@ class OpenAuth(AuthValidation):
|
||||
"""
|
||||
每次调用依赖此类的接口会执行该方法
|
||||
"""
|
||||
telephone = self.validate_token(token, db)
|
||||
telephone = self.validate_token(request, token)
|
||||
if telephone:
|
||||
user = await UserDal(db).get_data(telephone=telephone, v_return_none=True)
|
||||
return await self.validate_user(request, user, db)
|
||||
@ -106,7 +115,9 @@ class AllUserAuth(AuthValidation):
|
||||
"""
|
||||
每次调用依赖此类的接口会执行该方法
|
||||
"""
|
||||
telephone = self.validate_token(token, db)
|
||||
if not settings.OAUTH_ENABLE:
|
||||
return Auth(db=db)
|
||||
telephone = self.validate_token(request, token)
|
||||
if isinstance(telephone, Auth):
|
||||
return telephone
|
||||
user = await UserDal(db).get_data(telephone=telephone, v_return_none=True)
|
||||
@ -136,7 +147,9 @@ class FullAdminAuth(AuthValidation):
|
||||
"""
|
||||
每次调用依赖此类的接口会执行该方法
|
||||
"""
|
||||
telephone = self.validate_token(token, db)
|
||||
if not settings.OAUTH_ENABLE:
|
||||
return Auth(db=db)
|
||||
telephone = self.validate_token(request, token)
|
||||
if isinstance(telephone, Auth):
|
||||
return telephone
|
||||
options = [joinedload(VadminUser.roles), joinedload("roles.menus")]
|
||||
|
@ -20,21 +20,20 @@ PassLib 是一个用于处理哈希密码的很棒的 Python 包。它支持许
|
||||
"""
|
||||
|
||||
from datetime import timedelta
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
import jwt
|
||||
from fastapi import APIRouter, Depends, Request, Body
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from core.database import db_getter
|
||||
from utils import status
|
||||
from utils.response import SuccessResponse, ErrorResponse
|
||||
from application import settings
|
||||
from utils.tools import generate_string
|
||||
from .login_manage import LoginManage
|
||||
from .validation import LoginForm, WXLoginForm
|
||||
from apps.vadmin.record.models import VadminLoginRecord
|
||||
from apps.vadmin.auth.crud import MenuDal, UserDal
|
||||
from apps.vadmin.auth.schemas import UserIn
|
||||
from .current import FullAdminAuth
|
||||
from .validation.auth import Auth
|
||||
from utils.wx.oauth import WXOAuth
|
||||
from core.data_types import Telephone
|
||||
|
||||
app = APIRouter()
|
||||
|
||||
@ -57,10 +56,12 @@ async def login_for_access_token(
|
||||
if not result.status:
|
||||
raise ValueError(result.msg)
|
||||
|
||||
token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
token = LoginManage.create_access_token(data={"sub": result.user.telephone}, expires_delta=token_expires)
|
||||
access_token = LoginManage.create_token({"sub": result.user.telephone, "is_refresh": False})
|
||||
expires = timedelta(minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES)
|
||||
refresh_token = LoginManage.create_token({"sub": result.user.telephone, "is_refresh": True}, expires=expires)
|
||||
resp = {
|
||||
"access_token": token,
|
||||
"access_token": access_token,
|
||||
"refresh_token": refresh_token,
|
||||
"token_type": "bearer",
|
||||
"is_reset_password": result.user.is_reset_password,
|
||||
"is_wx_server_openid": result.user.is_wx_server_openid
|
||||
@ -95,10 +96,12 @@ async def wx_login_for_access_token(request: Request, data: WXLoginForm, db: Asy
|
||||
await user.update_login_info(db, request.client.host)
|
||||
|
||||
# 登录成功创建 token
|
||||
token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
token = LoginManage.create_access_token(data={"sub": user.telephone}, expires_delta=token_expires)
|
||||
access_token = LoginManage.create_token({"sub": user.telephone, "is_refresh": False})
|
||||
expires = timedelta(minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES)
|
||||
refresh_token = LoginManage.create_token({"sub": user.telephone, "is_refresh": True}, expires=expires)
|
||||
resp = {
|
||||
"access_token": token,
|
||||
"access_token": access_token,
|
||||
"refresh_token": refresh_token,
|
||||
"token_type": "bearer",
|
||||
"is_reset_password": user.is_reset_password,
|
||||
"is_wx_server_openid": user.is_wx_server_openid
|
||||
@ -110,3 +113,28 @@ async def wx_login_for_access_token(request: Request, data: WXLoginForm, db: Asy
|
||||
@app.get("/getMenuList/", summary="获取当前用户菜单树")
|
||||
async def get_menu_list(auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse(await MenuDal(auth.db).get_routers(auth.user))
|
||||
|
||||
|
||||
@app.post("/token/refresh/", summary="刷新Token")
|
||||
async def token_refresh(refresh: str = Body(..., title="刷新Token")):
|
||||
error_code = status.HTTP_401_UNAUTHORIZED
|
||||
try:
|
||||
payload = jwt.decode(refresh, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||
telephone: str = payload.get("sub")
|
||||
is_refresh: bool = payload.get("is_refresh")
|
||||
if telephone is None or not is_refresh:
|
||||
return ErrorResponse("未认证,请您重新登录", code=error_code, status=error_code)
|
||||
except jwt.exceptions.InvalidSignatureError:
|
||||
return ErrorResponse("无效认证,请您重新登录", code=error_code, status=error_code)
|
||||
except jwt.exceptions.ExpiredSignatureError:
|
||||
return ErrorResponse("登录已超时,请您重新登录", code=error_code, status=error_code)
|
||||
|
||||
access_token = LoginManage.create_token({"sub": telephone, "is_refresh": False})
|
||||
expires = timedelta(minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES)
|
||||
refresh_token = LoginManage.create_token({"sub": telephone, "is_refresh": True}, expires=expires)
|
||||
resp = {
|
||||
"access_token": access_token,
|
||||
"refresh_token": refresh_token,
|
||||
"token_type": "bearer"
|
||||
}
|
||||
return SuccessResponse(resp)
|
||||
|
@ -7,10 +7,9 @@
|
||||
# @desc : 简要说明
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional
|
||||
from fastapi import Request
|
||||
from application import settings
|
||||
from jose import jwt
|
||||
import jwt
|
||||
from apps.vadmin.auth import models
|
||||
from .validation import LoginValidation, LoginForm, LoginResult
|
||||
from utils.aliyun_sms import AliyunSMS
|
||||
@ -44,15 +43,19 @@ class LoginManage:
|
||||
return LoginResult(status=False, msg="验证码错误")
|
||||
|
||||
@staticmethod
|
||||
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
|
||||
def create_token(payload: dict, expires: timedelta = None):
|
||||
"""
|
||||
创建一个生成新的访问令牌的工具函数。
|
||||
|
||||
pyjwt:https://github.com/jpadilla/pyjwt/blob/master/docs/usage.rst
|
||||
jwt 博客:https://geek-docs.com/python/python-tutorial/j_python-jwt.html
|
||||
|
||||
#TODO 传入的时间为UTC时间datetime.datetime类型,但是在解码时获取到的是本机时间的时间戳
|
||||
"""
|
||||
to_encode = data.copy()
|
||||
if expires_delta:
|
||||
expire = datetime.utcnow() + expires_delta
|
||||
if expires:
|
||||
expire = datetime.utcnow() + expires
|
||||
else:
|
||||
expire = datetime.utcnow() + timedelta(minutes=60)
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
||||
expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
payload.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
@ -4,9 +4,9 @@
|
||||
# @File : auth.py
|
||||
# @IDE : PyCharm
|
||||
# @desc : 用户凭证验证装饰器
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from fastapi import Request
|
||||
from jose import jwt, JWTError
|
||||
import jwt
|
||||
from pydantic import BaseModel
|
||||
from application import settings
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@ -17,6 +17,7 @@ from utils import status
|
||||
|
||||
class Auth(BaseModel):
|
||||
user: models.VadminUser = None
|
||||
refresh: bool = False
|
||||
db: AsyncSession
|
||||
|
||||
class Config:
|
||||
@ -29,22 +30,35 @@ class AuthValidation:
|
||||
用于用户每次调用接口时,验证用户提交的token是否正确,并从token中获取用户信息
|
||||
"""
|
||||
|
||||
error_code = status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
@classmethod
|
||||
def validate_token(cls, token: str, db: AsyncSession) -> str | Auth:
|
||||
def validate_token(cls, request: Request, token: str) -> str:
|
||||
"""
|
||||
验证用户 token
|
||||
"""
|
||||
if not settings.OAUTH_ENABLE:
|
||||
return Auth(db=db)
|
||||
if not token:
|
||||
raise CustomException(msg="请您先登录!", code=status.HTTP_ERROR)
|
||||
try:
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||
telephone: str = payload.get("sub")
|
||||
if telephone is None:
|
||||
raise CustomException(msg="认证已过期,请您重新登陆", code=status.HTTP_401_UNAUTHORIZED)
|
||||
except JWTError:
|
||||
raise CustomException(msg="认证已过期,请您重新登陆", code=status.HTTP_401_UNAUTHORIZED)
|
||||
exp: int = payload.get("exp")
|
||||
is_refresh: bool = payload.get("is_refresh")
|
||||
if telephone is None or is_refresh:
|
||||
raise CustomException(msg="未认证,请您重新登录", code=cls.error_code)
|
||||
# 计算当前时间 + 缓冲时间是否大于等于 JWT 过期时间
|
||||
buffer_time = (datetime.now() + timedelta(minutes=settings.ACCESS_TOKEN_CACHE_MINUTES)).timestamp()
|
||||
# print("过期时间", exp, datetime.fromtimestamp(exp))
|
||||
# print("当前时间", buffer_time, datetime.fromtimestamp(buffer_time))
|
||||
# print("剩余时间", exp - buffer_time)
|
||||
if buffer_time >= exp:
|
||||
request.scope["refresh"] = True
|
||||
else:
|
||||
request.scope["refresh"] = False
|
||||
except jwt.exceptions.InvalidSignatureError:
|
||||
raise CustomException(msg="无效认证,请您重新登录", code=cls.error_code)
|
||||
except jwt.exceptions.ExpiredSignatureError:
|
||||
raise CustomException(msg="认证已过期,请您重新登录", code=cls.error_code)
|
||||
return telephone
|
||||
|
||||
@classmethod
|
||||
@ -53,12 +67,13 @@ class AuthValidation:
|
||||
验证用户信息
|
||||
"""
|
||||
if user is None:
|
||||
raise CustomException(msg="认证已过期,请您重新登陆", code=status.HTTP_401_UNAUTHORIZED)
|
||||
raise CustomException(msg="未认证,请您重新登陆", code=cls.error_code, status_code=cls.error_code)
|
||||
elif not user.is_active:
|
||||
raise CustomException(msg="用户已被冻结!", code=status.HTTP_403_FORBIDDEN)
|
||||
raise CustomException(msg="用户已被冻结!", code=cls.error_code, status_code=cls.error_code)
|
||||
request.scope["telephone"] = user.telephone
|
||||
try:
|
||||
request.scope["body"] = await request.body()
|
||||
except RuntimeError:
|
||||
request.scope["body"] = "获取失败"
|
||||
return Auth(user=user, db=db)
|
||||
refresh = request.scope.get("refresh", False)
|
||||
return Auth(user=user, db=db, refresh=refresh)
|
||||
|
@ -31,12 +31,12 @@ async def get_users(
|
||||
schema = schemas.UserOut
|
||||
datas = await crud.UserDal(auth.db).get_datas(**params.dict(), v_options=options, v_schema=schema)
|
||||
count = await crud.UserDal(auth.db).get_count(**params.to_count())
|
||||
return SuccessResponse(datas, count=count)
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/users/", summary="创建用户")
|
||||
async def create_user(data: schemas.UserIn, auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.create"]))):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).create_data(data=data))
|
||||
return SuccessResponse(await crud.UserDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.delete("/users/", summary="批量删除用户", description="软删除,删除后清空所关联的角色")
|
||||
@ -46,7 +46,7 @@ async def delete_users(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAu
|
||||
elif 1 in ids.ids:
|
||||
return ErrorResponse("不能删除超级管理员用户")
|
||||
await crud.UserDal(auth.db).delete_datas(ids=ids.ids, v_soft=True, is_active=False)
|
||||
return SuccessResponse("删除成功")
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.put("/users/{data_id}/", summary="更新用户信息")
|
||||
@ -55,7 +55,7 @@ async def put_user(
|
||||
data: schemas.UserUpdate,
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.update"]))
|
||||
):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).put_data(data_id, data))
|
||||
return SuccessResponse(await crud.UserDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/users/{data_id}/", summary="获取用户信息")
|
||||
@ -66,29 +66,32 @@ async def get_user(
|
||||
model = models.VadminUser
|
||||
options = [joinedload(model.roles)]
|
||||
schema = schemas.UserOut
|
||||
return SuccessResponse(await crud.UserDal(auth.db).get_data(data_id, options, v_schema=schema))
|
||||
return SuccessResponse(
|
||||
await crud.UserDal(auth.db).get_data(data_id, options, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
@app.post("/user/current/reset/password/", summary="重置当前用户密码")
|
||||
async def user_current_reset_password(data: schemas.ResetPwd, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).reset_current_password(auth.user, data))
|
||||
return SuccessResponse(await crud.UserDal(auth.db).reset_current_password(auth.user, data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/user/current/update/info/", summary="更新当前用户基本信息")
|
||||
async def post_user_current_update_info(data: schemas.UserUpdateBaseInfo, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).update_current_info(auth.user, data))
|
||||
return SuccessResponse(await crud.UserDal(auth.db).update_current_info(auth.user, data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/user/current/update/avatar/", summary="更新当前用户头像")
|
||||
async def post_user_current_update_avatar(file: UploadFile, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).update_current_avatar(auth.user, file))
|
||||
return SuccessResponse(await crud.UserDal(auth.db).update_current_avatar(auth.user, file), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/user/admin/current/info/", summary="获取当前管理员信息")
|
||||
async def get_user_admin_current_info(auth: Auth = Depends(FullAdminAuth())):
|
||||
result = schemas.UserOut.from_orm(auth.user).dict()
|
||||
result["permissions"] = list(get_user_permissions(auth.user))
|
||||
return SuccessResponse(result)
|
||||
return SuccessResponse(result, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/user/export/query/list/to/excel/", summary="导出用户查询列表为excel")
|
||||
@ -97,17 +100,17 @@ async def post_user_export_query_list(
|
||||
params: UserParams = Depends(),
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.export"]))
|
||||
):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).export_query_list(header, params))
|
||||
return SuccessResponse(await crud.UserDal(auth.db).export_query_list(header, params), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/user/download/import/template/", summary="下载最新批量导入用户模板")
|
||||
async def get_user_download_new_import_template(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).download_import_template())
|
||||
return SuccessResponse(await crud.UserDal(auth.db).download_import_template(), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/import/users/", summary="批量导入用户")
|
||||
async def post_import_users(file: UploadFile, auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.import"]))):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).import_users(file))
|
||||
return SuccessResponse(await crud.UserDal(auth.db).import_users(file), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/users/init/password/send/sms/", summary="初始化所选用户密码并发送通知短信")
|
||||
@ -116,13 +119,16 @@ async def post_users_init_password(
|
||||
ids: IdList = Depends(),
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.reset"]))
|
||||
):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).init_password_send_sms(ids.ids, request.app.state.redis))
|
||||
return SuccessResponse(
|
||||
await crud.UserDal(auth.db).init_password_send_sms(ids.ids, request.app.state.redis),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
@app.put("/users/wx/server/openid/", summary="更新当前用户服务端微信平台openid")
|
||||
async def put_user_wx_server_openid(request: Request, code: str, auth: Auth = Depends(AllUserAuth())):
|
||||
result = await crud.UserDal(auth.db).update_wx_server_openid(code, auth.user, request.app.state.redis)
|
||||
return SuccessResponse(result)
|
||||
return SuccessResponse(result, refresh=auth.refresh)
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -135,12 +141,12 @@ async def get_roles(
|
||||
):
|
||||
datas = await crud.RoleDal(auth.db).get_datas(**params.dict())
|
||||
count = await crud.RoleDal(auth.db).get_count(**params.to_count())
|
||||
return SuccessResponse(datas, count=count)
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/roles/", summary="创建角色信息")
|
||||
async def create_role(role: schemas.RoleIn, auth: Auth = Depends(FullAdminAuth(permissions=["auth.role.create"]))):
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).create_data(data=role))
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).create_data(data=role), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.delete("/roles/", summary="批量删除角色", description="硬删除, 如果存在用户关联则无法删除")
|
||||
@ -148,7 +154,7 @@ async def delete_roles(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAu
|
||||
if 1 in ids.ids:
|
||||
return ErrorResponse("不能删除管理员角色")
|
||||
await crud.RoleDal(auth.db).delete_datas(ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功")
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.put("/roles/{data_id}/", summary="更新角色信息")
|
||||
@ -159,12 +165,12 @@ async def put_role(
|
||||
):
|
||||
if 1 == data_id:
|
||||
return ErrorResponse("不能修改管理员角色")
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).put_data(data_id, data))
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/roles/options/", summary="获取角色选择项")
|
||||
async def get_role_options(auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.create", "auth.user.update"]))):
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).get_select_datas())
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).get_select_datas(), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/roles/{data_id}/", summary="获取角色信息")
|
||||
@ -175,7 +181,10 @@ async def get_role(
|
||||
model = models.VadminRole
|
||||
options = [joinedload(model.menus)]
|
||||
schema = schemas.RoleOut
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).get_data(data_id, options, v_schema=schema))
|
||||
return SuccessResponse(
|
||||
await crud.RoleDal(auth.db).get_data(data_id, options, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -184,33 +193,33 @@ async def get_role(
|
||||
@app.get("/menus/", summary="获取菜单列表")
|
||||
async def get_menus(auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.list"]))):
|
||||
datas = await crud.MenuDal(auth.db).get_tree_list(mode=1)
|
||||
return SuccessResponse(datas)
|
||||
return SuccessResponse(datas, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/menus/tree/options/", summary="获取菜单树选择项,添加/修改菜单时使用")
|
||||
async def get_menus_options(auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.create", "auth.menu.update"]))):
|
||||
datas = await crud.MenuDal(auth.db).get_tree_list(mode=2)
|
||||
return SuccessResponse(datas)
|
||||
return SuccessResponse(datas, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/menus/role/tree/options/", summary="获取菜单列表树信息,角色权限使用")
|
||||
async def get_menus_treeselect(
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.role.create", "auth.role.update"]))
|
||||
):
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_tree_list(mode=3))
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_tree_list(mode=3), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/menus/", summary="创建菜单信息")
|
||||
async def create_menu(menu: schemas.Menu, auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.create"]))):
|
||||
if menu.parent_id:
|
||||
menu.alwaysShow = False
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).create_data(data=menu))
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).create_data(data=menu), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.delete("/menus/", summary="批量删除菜单", description="硬删除, 如果存在角色关联则无法删除")
|
||||
async def delete_menus(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.delete"]))):
|
||||
await crud.MenuDal(auth.db).delete_datas(ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功")
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.put("/menus/{data_id}/", summary="更新菜单信息")
|
||||
@ -218,7 +227,7 @@ async def put_menus(
|
||||
data_id: int,
|
||||
data: schemas.Menu, auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.update"]))
|
||||
):
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).put_data(data_id, data))
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/menus/{data_id}/", summary="获取菜单信息")
|
||||
@ -227,7 +236,7 @@ async def put_menus(
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.view", "auth.menu.update"]))
|
||||
):
|
||||
schema = schemas.MenuSimpleOut
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_data(data_id, None, v_schema=schema))
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_data(data_id, None, v_schema=schema), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/role/menus/tree/{role_id}/", summary="获取菜单列表树信息以及角色菜单权限ID,角色权限使用")
|
||||
@ -237,4 +246,4 @@ async def get_role_menu_tree(
|
||||
):
|
||||
treeselect = await crud.MenuDal(auth.db).get_tree_list(mode=3)
|
||||
role_menu_tree = await crud.RoleDal(auth.db).get_role_menu_tree(role_id)
|
||||
return SuccessResponse({"role_menu_tree": role_menu_tree, "menus": treeselect})
|
||||
return SuccessResponse({"role_menu_tree": role_menu_tree, "menus": treeselect}, refresh=auth.refresh)
|
||||
|
@ -29,36 +29,42 @@ async def get_issue_categorys(p: params.IssueCategoryParams = Depends(), auth: A
|
||||
schema = schemas.IssueCategoryListOut
|
||||
datas = await crud.IssueCategoryDal(auth.db).get_datas(**p.dict(), v_options=options, v_schema=schema)
|
||||
count = await crud.IssueCategoryDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count)
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/issue/categorys/options/", summary="获取类别选择项")
|
||||
async def get_issue_categorys_options(auth: Auth = Depends(AllUserAuth())):
|
||||
schema = schemas.IssueCategoryOptionsOut
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).get_datas(limit=0, is_active=True, v_schema=schema))
|
||||
return SuccessResponse(
|
||||
await crud.IssueCategoryDal(auth.db).get_datas(limit=0, is_active=True, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
@app.post("/issue/categorys/", summary="创建类别")
|
||||
async def create_issue_category(data: schemas.IssueCategory, auth: Auth = Depends(AllUserAuth())):
|
||||
data.user_id = auth.user.id
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).create_data(data=data))
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.delete("/issue/categorys/", summary="批量删除类别", description="硬删除")
|
||||
async def delete_issue_categorys(ids: IdList = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
await crud.IssueCategoryDal(auth.db).delete_datas(ids=ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功")
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.put("/issue/categorys/{data_id}/", summary="更新类别信息")
|
||||
async def put_issue_category(data_id: int, data: schemas.IssueCategory, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).put_data(data_id, data))
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/issue/categorys/{data_id}/", summary="获取类别信息")
|
||||
async def get_issue_category(data_id: int, auth: Auth = Depends(AllUserAuth())):
|
||||
schema = schemas.IssueCategorySimpleOut
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).get_data(data_id, v_schema=schema))
|
||||
return SuccessResponse(
|
||||
await crud.IssueCategoryDal(auth.db).get_data(data_id, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
@app.get("/issue/categorys/platform/{platform}/", summary="获取平台中的常见问题类别列表")
|
||||
@ -81,24 +87,24 @@ async def get_issues(p: params.IssueParams = Depends(), auth: Auth = Depends(All
|
||||
schema = schemas.IssueListOut
|
||||
datas = await crud.IssueDal(auth.db).get_datas(**p.dict(), v_options=options, v_schema=schema)
|
||||
count = await crud.IssueDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count)
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/issues/", summary="创建问题")
|
||||
async def create_issue(data: schemas.Issue, auth: Auth = Depends(AllUserAuth())):
|
||||
data.user_id = auth.user.id
|
||||
return SuccessResponse(await crud.IssueDal(auth.db).create_data(data=data))
|
||||
return SuccessResponse(await crud.IssueDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.delete("/issues/", summary="批量删除问题", description="硬删除")
|
||||
async def delete_issues(ids: IdList = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
await crud.IssueDal(auth.db).delete_datas(ids=ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功")
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.put("/issues/{data_id}/", summary="更新问题信息")
|
||||
async def put_issue(data_id: int, data: schemas.Issue, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.IssueDal(auth.db).put_data(data_id, data))
|
||||
return SuccessResponse(await crud.IssueDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/issues/{data_id}/", summary="获取问题信息")
|
||||
|
@ -23,7 +23,7 @@ app = APIRouter()
|
||||
async def get_record_login(p: LoginParams = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
datas = await crud.LoginRecordDal(auth.db).get_datas(**p.dict())
|
||||
count = await crud.LoginRecordDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count)
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/operations/", summary="获取操作日志列表")
|
||||
@ -31,14 +31,14 @@ async def get_record_operation(p: OperationParams = Depends(), db: DatabaseManag
|
||||
auth: Auth = Depends(AllUserAuth())):
|
||||
count = await db.get_count("operation_record", **p.to_count())
|
||||
datas = await db.get_datas("operation_record", v_schema=schemas.OpertionRecordSimpleOut, **p.dict())
|
||||
return SuccessResponse(datas, count=count)
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/sms/send/list/", summary="获取短信发送列表")
|
||||
async def get_sms_send_list(p: SMSParams = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
datas = await crud.SMSSendRecordDal(auth.db).get_datas(**p.dict())
|
||||
count = await crud.SMSSendRecordDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count)
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -46,4 +46,4 @@ async def get_sms_send_list(p: SMSParams = Depends(), auth: Auth = Depends(AllUs
|
||||
###########################################################
|
||||
@app.get("/analysis/user/login/distribute/", summary="获取用户登录分布情况列表")
|
||||
async def get_user_login_distribute(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.LoginRecordDal(auth.db).get_user_distribute())
|
||||
return SuccessResponse(await crud.LoginRecordDal(auth.db).get_user_distribute(), refresh=auth.refresh)
|
||||
|
@ -31,18 +31,18 @@ app = APIRouter()
|
||||
async def get_dict_types(p: DictTypeParams = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
datas = await crud.DictTypeDal(auth.db).get_datas(**p.dict())
|
||||
count = await crud.DictTypeDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count)
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/dict/types/", summary="创建字典类型")
|
||||
async def create_dict_types(data: schemas.DictType, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).create_data(data=data))
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.delete("/dict/types/", summary="批量删除字典类型")
|
||||
async def delete_dict_types(ids: IdList = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
await crud.DictTypeDal(auth.db).delete_datas(ids=ids.ids)
|
||||
return SuccessResponse("删除成功")
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.post("/dict/types/details/", summary="获取多个字典类型下的字典元素列表")
|
||||
@ -51,23 +51,26 @@ async def post_dicts_details(
|
||||
dict_types: List[str] = Body(None, title="字典元素列表", description="查询字典元素列表")
|
||||
):
|
||||
datas = await crud.DictTypeDal(auth.db).get_dicts_details(dict_types)
|
||||
return SuccessResponse(datas)
|
||||
return SuccessResponse(datas, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/dict/types/options/", summary="获取字典类型选择项")
|
||||
async def get_dicts_options(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).get_select_datas())
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).get_select_datas(), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.put("/dict/types/{data_id}/", summary="更新字典类型")
|
||||
async def put_dict_types(data_id: int, data: schemas.DictType, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).put_data(data_id, data))
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/dict/types/{data_id}/", summary="获取字典类型详细")
|
||||
async def get_dict_type(data_id: int, auth: Auth = Depends(AllUserAuth())):
|
||||
schema = schemas.DictTypeSimpleOut
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).get_data(data_id, None, v_schema=schema))
|
||||
return SuccessResponse(
|
||||
await crud.DictTypeDal(auth.db).get_data(data_id, None, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -75,7 +78,7 @@ async def get_dict_type(data_id: int, auth: Auth = Depends(AllUserAuth())):
|
||||
###########################################################
|
||||
@app.post("/dict/details/", summary="创建字典元素")
|
||||
async def create_dict_details(data: schemas.DictDetails, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).create_data(data=data))
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/dict/details/", summary="获取单个字典类型下的字典元素列表,分页")
|
||||
@ -84,24 +87,27 @@ async def get_dict_details(params: DictDetailParams = Depends(), auth: Auth = De
|
||||
return ErrorResponse(msg="未获取到字典类型!")
|
||||
datas = await crud.DictDetailsDal(auth.db).get_datas(**params.dict())
|
||||
count = await crud.DictDetailsDal(auth.db).get_count(**params.to_count())
|
||||
return SuccessResponse(datas, count=count)
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.delete("/dict/details/", summary="批量删除字典元素", description="硬删除")
|
||||
async def delete_dict_details(ids: IdList = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
await crud.DictDetailsDal(auth.db).delete_datas(ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功")
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.put("/dict/details/{data_id}/", summary="更新字典元素")
|
||||
async def put_dict_details(data_id: int, data: schemas.DictDetails, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).put_data(data_id, data))
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.get("/dict/details/{data_id}/", summary="获取字典元素详情")
|
||||
async def get_dict_detail(data_id: int, auth: Auth = Depends(AllUserAuth())):
|
||||
schema = schemas.DictDetailsSimpleOut
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).get_data(data_id, None, v_schema=schema))
|
||||
return SuccessResponse(
|
||||
await crud.DictDetailsDal(auth.db).get_data(data_id, None, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -136,17 +142,23 @@ async def sms_send(request: Request, telephone: str):
|
||||
###########################################################
|
||||
@app.get("/settings/tabs/", summary="获取系统配置标签列表")
|
||||
async def get_settings_tabs(classify: str, auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse(await crud.SettingsTabDal(auth.db).get_datas(limit=0, classify=classify))
|
||||
return SuccessResponse(
|
||||
await crud.SettingsTabDal(auth.db).get_datas(limit=0, classify=classify),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
@app.get("/settings/tabs/values/", summary="获取系统配置标签下的信息")
|
||||
async def get_settings_tabs_values(tab_id: int, auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse(await crud.SettingsDal(auth.db).get_tab_values(tab_id=tab_id))
|
||||
return SuccessResponse(await crud.SettingsDal(auth.db).get_tab_values(tab_id=tab_id), refresh=auth.refresh)
|
||||
|
||||
|
||||
@app.put("/settings/tabs/values/", summary="更新系统配置信息")
|
||||
async def put_settings_tabs_values(request: Request, datas: dict = Body(...), auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse(await crud.SettingsDal(auth.db).update_datas(datas, request.app.state.redis))
|
||||
return SuccessResponse(
|
||||
await crud.SettingsDal(auth.db).update_datas(datas, request.app.state.redis),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
@app.get("/settings/base/config/", summary="获取系统基础配置", description="每次进入系统中时使用")
|
||||
@ -156,9 +168,15 @@ async def get_setting_base_config(db: AsyncSession = Depends(db_getter)):
|
||||
|
||||
@app.get("/settings/privacy/", summary="获取隐私协议")
|
||||
async def get_settings_privacy(auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse((await crud.SettingsDal(auth.db).get_data(config_key="web_privacy")).config_value)
|
||||
return SuccessResponse(
|
||||
(await crud.SettingsDal(auth.db).get_data(config_key="web_privacy")).config_value,
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
||||
|
||||
@app.get("/settings/agreement/", summary="获取用户协议")
|
||||
async def get_settings_agreement(auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse((await crud.SettingsDal(auth.db).get_data(config_key="web_agreement")).config_value)
|
||||
return SuccessResponse(
|
||||
(await crud.SettingsDal(auth.db).get_data(config_key="web_agreement")).config_value,
|
||||
refresh=auth.refresh
|
||||
)
|
||||
|
@ -21,6 +21,30 @@ def register_redis(app: FastAPI) -> None:
|
||||
博客:https://blog.csdn.net/wgPython/article/details/107668521
|
||||
博客:https://www.cnblogs.com/emunshe/p/15761597.html
|
||||
官网:https://aioredis.readthedocs.io/en/latest/getting-started/
|
||||
Github: https://github.com/aio-libs/aioredis-py
|
||||
|
||||
aioredis.from_url(url, *, encoding=None, parser=None, decode_responses=False, db=None, password=None, ssl=None,
|
||||
connection_cls=None, loop=None, **kwargs) 方法是 aioredis 库中用于从 Redis 连接 URL 创建 Redis 连接对象的方法。
|
||||
|
||||
以下是该方法的参数说明:
|
||||
url:Redis 连接 URL。例如 redis://localhost:6379/0。
|
||||
encoding:可选参数,Redis 编码格式。默认为 utf-8。
|
||||
parser:可选参数,Redis 数据解析器。默认为 None,表示使用默认解析器。
|
||||
decode_responses:可选参数,是否将 Redis 响应解码为 Python 字符串。默认为 False。
|
||||
db:可选参数,Redis 数据库编号。默认为 None。
|
||||
password:可选参数,Redis 认证密码。默认为 None,表示无需认证。
|
||||
ssl:可选参数,是否使用 SSL/TLS 加密连接。默认为 None。
|
||||
connection_cls:可选参数,Redis 连接类。默认为 None,表示使用默认连接类。
|
||||
loop:可选参数,用于创建连接对象的事件循环。默认为 None,表示使用默认事件循环。
|
||||
**kwargs:可选参数,其他连接参数,用于传递给 Redis 连接类的构造函数。
|
||||
|
||||
aioredis.from_url() 方法的主要作用是将 Redis 连接 URL 转换为 Redis 连接对象。
|
||||
除了 URL 参数外,其他参数用于指定 Redis 连接的各种选项,例如 Redis 数据库编号、密码、SSL/TLS 加密等等。可以根据需要选择使用这些选项。
|
||||
|
||||
health_check_interval 是 aioredis.from_url() 方法中的一个可选参数,用于设置 Redis 连接的健康检查间隔时间。
|
||||
健康检查是指在 Redis 连接池中使用的连接对象会定期向 Redis 服务器发送 PING 命令来检查连接是否仍然有效。
|
||||
该参数的默认值是 0,表示不进行健康检查。如果需要启用健康检查,则可以将该参数设置为一个正整数,表示检查间隔的秒数。
|
||||
例如,如果需要每隔 5 秒对 Redis 连接进行一次健康检查,则可以将 health_check_interval 设置为 5
|
||||
:param app:
|
||||
:return:
|
||||
"""
|
||||
|
@ -16,9 +16,10 @@ from core.logger import logger
|
||||
|
||||
|
||||
class CustomException(Exception):
|
||||
def __init__(self, msg: str, code: int):
|
||||
def __init__(self, msg: str, code: int, status_code: int = status.HTTP_200_OK):
|
||||
self.msg = msg
|
||||
self.code = code
|
||||
self.status_code = status_code
|
||||
|
||||
|
||||
def register_exception(app: FastAPI):
|
||||
|
Binary file not shown.
37
kinit-uni/.eslintrc.js
Normal file
37
kinit-uni/.eslintrc.js
Normal file
@ -0,0 +1,37 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
node: true
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:vue/recommended',
|
||||
'prettier',
|
||||
'plugin:prettier/recommended'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module'
|
||||
},
|
||||
globals: {
|
||||
uni: true,
|
||||
wx: true,
|
||||
ROUTES: true
|
||||
},
|
||||
plugins: ['vue', 'prettier'],
|
||||
rules: {
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'prettier/prettier': 'error',
|
||||
'vue/html-indent': ['error', 2],
|
||||
'vue/max-attributes-per-line': 'off',
|
||||
'no-console': 'off',
|
||||
'no-unused-vars': ['warn', { args: 'none' }],
|
||||
'arrow-parens': ['error', 'always'],
|
||||
'comma-dangle': ['error', 'never'],
|
||||
quotes: ['error', 'single'],
|
||||
semi: ['error', 'never'],
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
indent: ['error', 2, { SwitchCase: 1 }]
|
||||
}
|
||||
}
|
@ -1,21 +1,18 @@
|
||||
<script>
|
||||
import config from './config'
|
||||
import { getToken } from '@/common/utils/auth'
|
||||
|
||||
export default {
|
||||
onLaunch: function() {
|
||||
this.initApp()
|
||||
},
|
||||
methods: {
|
||||
// 初始化应用
|
||||
initApp() {
|
||||
// 初始化应用配置
|
||||
this.$store.dispatch('app/InitConfig')
|
||||
}
|
||||
export default {
|
||||
onLaunch: function () {
|
||||
this.initApp()
|
||||
},
|
||||
methods: {
|
||||
// 初始化应用
|
||||
initApp() {
|
||||
// 初始化应用配置
|
||||
this.$store.dispatch('app/InitConfig')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/static/scss/index.scss';
|
||||
@import '@/static/scss/index.scss';
|
||||
</style>
|
||||
|
@ -47,3 +47,23 @@ RuoYi App 移动解决方案,采用uniapp框架,一份代码多终端适配
|
||||
- 文档地址:https://uviewui.com
|
||||
|
||||
uView UI,是[uni-app](https://uniapp.dcloud.io/)全面兼容nvue的uni-app生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
|
||||
|
||||
## 开发工具
|
||||
|
||||
在此项目中我将开发`uni-app`的开发工具从 Hbuilder X 换到了 VSCode,没有谁好谁坏,只是本人更习惯使用 VSCode,但是在运行项目时依然使用的是 Hbuilder X,VSCode只是用来编写代码。当然使用 Hbuilder X 也是支持的,只做一个分享。
|
||||
|
||||
以下是我在VSCode中安装的几个插件:
|
||||
|
||||
1. 名称: Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code
|
||||
2. 名称: ESLint
|
||||
3. 名称: Image preview
|
||||
4. 名称: Markdown Preview Enhanced
|
||||
5. 名称: Path Intellisense
|
||||
6. 名称: Prettier - Code formatter
|
||||
7. 名称: Sass (.sass only)
|
||||
8. 名称: SCSS IntelliSense
|
||||
9. 名称: Stylelint
|
||||
10. 名称: uni-app-schemas
|
||||
11. 名称: uni-app-snippets
|
||||
12. 名称: uni-create-view
|
||||
13. 名称: Vetur
|
||||
|
@ -8,58 +8,57 @@ import { setUserOpenid } from '@/common/request/api/login.js'
|
||||
import { toast } from '@/common/utils/common'
|
||||
|
||||
export const wxLoginMixins = {
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isUserOpenid',
|
||||
])
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onGetPhoneNumber(e) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取手机号官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
|
||||
if (e.detail.errMsg === "getPhoneNumber:fail user deny") {
|
||||
// 用户拒绝授权
|
||||
toast("已取消授权")
|
||||
reject("已取消授权")
|
||||
} else if (e.detail.errMsg === "getPhoneNumber:fail no permission") {
|
||||
// 微信公众平台未认证或未使用企业认证
|
||||
toast("微信公众平台未认证或未使用企业认证")
|
||||
reject("微信公众平台未认证或未使用企业认证")
|
||||
} else if (e.detail.errMsg === "getPhoneNumber:ok") {
|
||||
// code换取用户手机号。 每个code只能使用一次,code的有效期为5min
|
||||
this.$store.dispatch('auth/wxLogin', e.detail.code).then(res => {
|
||||
this.setOpenid();
|
||||
this.$store.dispatch('auth/GetInfo').then(result => {
|
||||
resolve(result)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
toast("授权失败")
|
||||
reject("授权失败")
|
||||
}
|
||||
})
|
||||
},
|
||||
setOpenid() {
|
||||
let self = this;
|
||||
// uniapp 官方文档:https://uniapp.dcloud.io/api/plugins/login.html#login
|
||||
if (self.isUserOpenid) { return; };
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: function (loginRes) {
|
||||
if (loginRes.code) {
|
||||
setUserOpenid(loginRes.code).then(res => {
|
||||
// console.log("更新openid成功", res)
|
||||
self.$store.commit("auth/SET_IS_USER_OPENID", true);
|
||||
})
|
||||
} else {
|
||||
console.log('登录失败!获取code失败!' + res.errMsg)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
computed: {
|
||||
...mapGetters(['isUserOpenid'])
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
onGetPhoneNumber(e) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取手机号官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
|
||||
if (e.detail.errMsg === 'getPhoneNumber:fail user deny') {
|
||||
// 用户拒绝授权
|
||||
toast('已取消授权')
|
||||
reject('已取消授权')
|
||||
} else if (e.detail.errMsg === 'getPhoneNumber:fail no permission') {
|
||||
// 微信公众平台未认证或未使用企业认证
|
||||
toast('微信公众平台未认证或未使用企业认证')
|
||||
reject('微信公众平台未认证或未使用企业认证')
|
||||
} else if (e.detail.errMsg === 'getPhoneNumber:ok') {
|
||||
// code换取用户手机号。 每个code只能使用一次,code的有效期为5min
|
||||
this.$store.dispatch('auth/wxLogin', e.detail.code).then((res) => {
|
||||
this.setOpenid()
|
||||
this.$store.dispatch('auth/GetInfo').then((result) => {
|
||||
resolve(result)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
toast('授权失败')
|
||||
reject('授权失败')
|
||||
}
|
||||
})
|
||||
},
|
||||
setOpenid() {
|
||||
let self = this
|
||||
// uniapp 官方文档:https://uniapp.dcloud.io/api/plugins/login.html#login
|
||||
if (self.isUserOpenid) {
|
||||
return
|
||||
}
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: function (loginRes) {
|
||||
if (loginRes.code) {
|
||||
setUserOpenid(loginRes.code).then(() => {
|
||||
// console.log("更新openid成功", res)
|
||||
self.$store.commit('auth/SET_IS_USER_OPENID', true)
|
||||
})
|
||||
} else {
|
||||
console.log('登录失败!获取code失败!' + loginRes.errMsg)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +1,46 @@
|
||||
export const wxShareMixins = {
|
||||
data() {
|
||||
return {
|
||||
share: {
|
||||
title: "",
|
||||
path: "",
|
||||
imageUrl: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad: function() {
|
||||
wx.showShareMenu({
|
||||
withShareTicket: true,
|
||||
menus: ["shareAppMessage", "shareTimeline"]
|
||||
})
|
||||
},
|
||||
onShareAppMessage(res) {
|
||||
let that = this;
|
||||
let imageUrl = that.share.imageUrl || '';
|
||||
if (res.from === 'button') {
|
||||
//这块需要传参,不然链接地址进去获取不到数据
|
||||
let path = `/` + that.$scope.route + `?item=` + that.$scope.options.item;
|
||||
return {
|
||||
title: '商品分享~',
|
||||
path: path,
|
||||
imageUrl: imageUrl
|
||||
};
|
||||
}
|
||||
if (res.from === 'menu') {
|
||||
return {
|
||||
title: that.share.title,
|
||||
path: that.share.path,
|
||||
imageUrl: that.share.imageUrl
|
||||
};
|
||||
}
|
||||
},
|
||||
// 分享到朋友圈
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: this.share.title,
|
||||
path: this.share.path,
|
||||
imageUrl: this.share.imageUrl
|
||||
};
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
data() {
|
||||
return {
|
||||
share: {
|
||||
title: '',
|
||||
path: '',
|
||||
imageUrl: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad: function () {
|
||||
wx.showShareMenu({
|
||||
withShareTicket: true,
|
||||
menus: ['shareAppMessage', 'shareTimeline']
|
||||
})
|
||||
},
|
||||
onShareAppMessage(res) {
|
||||
let that = this
|
||||
let imageUrl = that.share.imageUrl || ''
|
||||
if (res.from === 'button') {
|
||||
//这块需要传参,不然链接地址进去获取不到数据
|
||||
let path = '/' + that.$scope.route + '?item=' + that.$scope.options.item
|
||||
return {
|
||||
title: '商品分享~',
|
||||
path: path,
|
||||
imageUrl: imageUrl
|
||||
}
|
||||
}
|
||||
if (res.from === 'menu') {
|
||||
return {
|
||||
title: that.share.title,
|
||||
path: that.share.path,
|
||||
imageUrl: that.share.imageUrl
|
||||
}
|
||||
}
|
||||
},
|
||||
// 分享到朋友圈
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: this.share.title,
|
||||
path: this.share.path,
|
||||
imageUrl: this.share.imageUrl
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
|
@ -5,29 +5,29 @@ export function login(telephone, password) {
|
||||
const data = {
|
||||
telephone,
|
||||
password,
|
||||
method: '0',
|
||||
platform: '1'
|
||||
method: '0',
|
||||
platform: '1'
|
||||
}
|
||||
return request.post(`/auth/login/`, data)
|
||||
return request.post('/auth/login/', data)
|
||||
}
|
||||
|
||||
// 获取用户详细信息
|
||||
export function getInfo() {
|
||||
return request.get(`/vadmin/auth/user/admin/current/info/`)
|
||||
return request.get('/vadmin/auth/user/admin/current/info/')
|
||||
}
|
||||
|
||||
// 更新用户openid
|
||||
export function setUserOpenid(code) {
|
||||
const params = {code}
|
||||
return request.put(`/vadmin/auth/users/wx/server/openid/`, {}, {params: params})
|
||||
const params = { code }
|
||||
return request.put('/vadmin/auth/users/wx/server/openid/', {}, { params: params })
|
||||
}
|
||||
|
||||
// 使用微信一键登录
|
||||
export function wxCodeLogin(code) {
|
||||
const data = {
|
||||
code,
|
||||
method: '2',
|
||||
platform: '1'
|
||||
}
|
||||
return request.post(`/auth/wx/login/`, data)
|
||||
const data = {
|
||||
code,
|
||||
method: '2',
|
||||
platform: '1'
|
||||
}
|
||||
return request.post('/auth/wx/login/', data)
|
||||
}
|
||||
|
@ -2,15 +2,18 @@ import request from '@/common/request/request'
|
||||
|
||||
// 更新当前用户基本信息
|
||||
export function updateCurrentUser(data) {
|
||||
return request.post(`/vadmin/auth/user/current/update/info/`, data)
|
||||
return request.post('/vadmin/auth/user/current/update/info/', data)
|
||||
}
|
||||
|
||||
// 重置当前用户密码
|
||||
export function postCurrentUserResetPassword(data) {
|
||||
return request.post(`/vadmin/auth/user/current/reset/password/`, data)
|
||||
return request.post('/vadmin/auth/user/current/reset/password/', data)
|
||||
}
|
||||
|
||||
// 更新当前用户头像
|
||||
export function postCurrentUserUploadAvatar(filePath) {
|
||||
return request.upload(`/vadmin/auth/user/current/update/avatar/`, {filePath: filePath, name: 'file'})
|
||||
}
|
||||
return request.upload('/vadmin/auth/user/current/update/avatar/', {
|
||||
filePath: filePath,
|
||||
name: 'file'
|
||||
})
|
||||
}
|
||||
|
@ -2,15 +2,15 @@ import request from '@/common/request/request.js'
|
||||
|
||||
// 获取平台中的常见问题类别列表
|
||||
export function getIssueCategoryList() {
|
||||
return request.get(`/vadmin/help/issue/categorys/platform/1/`)
|
||||
return request.get('/vadmin/help/issue/categorys/platform/1/')
|
||||
}
|
||||
|
||||
// 获取问题详情
|
||||
export function getIssue(dataId) {
|
||||
return request.get(`/vadmin/help/issues/${dataId}/`)
|
||||
return request.get(`/vadmin/help/issues/${dataId}/`)
|
||||
}
|
||||
|
||||
// 更新常见问题查看次数+1
|
||||
export function updateIssueAddViewNumber(dataId) {
|
||||
return request.get(`/vadmin/help/issues/add/view/number/${dataId}/`)
|
||||
}
|
||||
return request.get(`/vadmin/help/issues/add/view/number/${dataId}/`)
|
||||
}
|
||||
|
@ -2,5 +2,5 @@ import request from '@/common/request/request.js'
|
||||
|
||||
// 获取多个字典类型下的字典元素列表
|
||||
export function getDictTypeDetailsApi(data) {
|
||||
return request.post(`/vadmin/system/dict/types/details/`, data)
|
||||
return request.post('/vadmin/system/dict/types/details/', data)
|
||||
}
|
||||
|
@ -2,5 +2,5 @@ import request from '@/common/request/request'
|
||||
|
||||
// 获取系统基本配置
|
||||
export function getSystemBaseConfigApi() {
|
||||
return request.get(`/vadmin/system/settings/base/config/`)
|
||||
}
|
||||
return request.get('/vadmin/system/settings/base/config/')
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
export default {
|
||||
"401": "认证失败,无法访问系统资源",
|
||||
"403": "当前操作没有权限",
|
||||
"404": "访问资源不存在",
|
||||
"default": "系统未知错误,请反馈给管理员"
|
||||
};
|
||||
401: '认证失败,无法访问系统资源',
|
||||
403: '当前操作没有权限',
|
||||
404: '访问资源不存在',
|
||||
default: '系统未知错误,请反馈给管理员'
|
||||
}
|
||||
|
@ -1,78 +1,127 @@
|
||||
import luchRequest from '@/components/luch-request' // 使用npm
|
||||
import config from '@/config.js';
|
||||
import errorCode from "@/common/request/errorCode";
|
||||
import { getToken } from '@/common/utils/auth'
|
||||
import { toast, showConfirm } from '@/common/utils/common'
|
||||
import config from '@/config.js'
|
||||
import errorCode from '@/common/request/errorCode'
|
||||
import { getToken, getRefreshToken, setToken, setRefreshToken } from '@/common/utils/auth'
|
||||
import { toast } from '@/common/utils/common'
|
||||
import store from '@/store'
|
||||
import request from '@/common/request/request.js'
|
||||
|
||||
// luch-request插件官网:https://www.quanzhan.co/luch-request/guide/3.x/#%E5%85%A8%E5%B1%80%E8%AF%B7%E6%B1%82%E9%85%8D%E7%BD%AE
|
||||
// 创建luchRequest实例
|
||||
console.log(config.baseUrl)
|
||||
const http = new luchRequest({
|
||||
baseURL: config.baseUrl,
|
||||
timeout: 20000, // 请求超时时间
|
||||
dataType: 'json',
|
||||
custom: {
|
||||
loading: true
|
||||
},
|
||||
sslVerify: true,
|
||||
header: {}
|
||||
loading: true
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// 请求拦截器
|
||||
http.interceptors.request.use(
|
||||
config => {
|
||||
(config) => {
|
||||
// 在发送请求之前
|
||||
let token = getToken()
|
||||
if (token) {
|
||||
// 添加头信息,token验证
|
||||
config.header["Authorization"] = token
|
||||
}
|
||||
let token = getToken()
|
||||
if (token) {
|
||||
// 添加头信息,token验证
|
||||
config.header['Authorization'] = token
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
(error) => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
http.interceptors.response.use(res => {
|
||||
// console.log("响应拦截器:", res)
|
||||
// 未设置状态码则默认成功状态
|
||||
const code = res.data.code || 200;
|
||||
// 获取错误信息
|
||||
const msg = res.data.message || errorCode[code] || errorCode["default"];
|
||||
if (code === 500) {
|
||||
toast(msg)
|
||||
return Promise.reject(new Error(msg));
|
||||
} else if (code === 401) {
|
||||
showConfirm("登录状态已过期,您可以继续留在该页面,或者重新登录?").then(res => {
|
||||
if (res.confirm) {
|
||||
store.dispatch('auth/LogOut')
|
||||
}
|
||||
})
|
||||
return Promise.reject("error");
|
||||
} else if (code !== 200) {
|
||||
toast(msg)
|
||||
return Promise.reject("error");
|
||||
} else {
|
||||
return res.data;
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log("请求状态码服务器直接报错", error);
|
||||
let { errMsg } = error;
|
||||
if (errMsg == "request:fail") {
|
||||
errMsg = "接口连接异常";
|
||||
} else if (errMsg == "request:fail timeout") {
|
||||
errMsg = "接口连接超时";
|
||||
} else {
|
||||
errMsg = error.data.message;
|
||||
}
|
||||
toast(errMsg)
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
http.interceptors.response.use(
|
||||
(res) => {
|
||||
// console.log("响应拦截器:", res)
|
||||
// 未设置状态码则默认401状态
|
||||
const code = res.data.code || 200
|
||||
// 获取错误信息
|
||||
const msg = res.data.message || errorCode[code] || errorCode['default']
|
||||
// 是否刷新token
|
||||
const refresh = res.data.refresh || false
|
||||
if (code === 500) {
|
||||
toast(msg)
|
||||
return Promise.reject(new Error(msg))
|
||||
} else if (code === 401) {
|
||||
// 因token快过期,刷新token
|
||||
refreshToken().then((res) => {
|
||||
setToken(`${res.data.token_type} ${res.data.access_token}`)
|
||||
setRefreshToken(res.data.refresh_token)
|
||||
})
|
||||
toast('操作失败,请重试')
|
||||
return Promise.reject('error')
|
||||
} else if (code !== 200) {
|
||||
toast(msg)
|
||||
return Promise.reject('error')
|
||||
} else if (code === 200) {
|
||||
if (refresh) {
|
||||
// 因token快过期,刷新token
|
||||
refreshToken().then((res) => {
|
||||
setToken(`${res.data.token_type} ${res.data.access_token}`)
|
||||
setRefreshToken(res.data.refresh_token)
|
||||
})
|
||||
}
|
||||
return res.data
|
||||
} else {
|
||||
return res.data
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
console.log('err', error)
|
||||
let message = error.data.message || error.errMsg
|
||||
const status = error.statusCode
|
||||
switch (status) {
|
||||
case 400:
|
||||
message = '请求错误'
|
||||
break
|
||||
case 401:
|
||||
// 强制要求重新登录,因账号已冻结,账号已过期,手机号码错误,刷新token无效等问题导致
|
||||
store.dispatch('auth/LogOut')
|
||||
message = '未认证,请登录'
|
||||
break
|
||||
case 403:
|
||||
message = '拒绝访问'
|
||||
break
|
||||
case 404:
|
||||
message = '请求地址出错'
|
||||
break
|
||||
case 408:
|
||||
message = '请求超时'
|
||||
break
|
||||
case 500:
|
||||
message = '服务器内部错误'
|
||||
break
|
||||
case 501:
|
||||
message = '服务未实现'
|
||||
break
|
||||
case 502:
|
||||
message = '网关错误'
|
||||
break
|
||||
case 503:
|
||||
message = '服务不可用'
|
||||
break
|
||||
case 504:
|
||||
message = '网关超时'
|
||||
break
|
||||
case 505:
|
||||
message = 'HTTP版本不受支持'
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
toast(message)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default http
|
||||
// 刷新 token
|
||||
function refreshToken() {
|
||||
const data = JSON.stringify(getRefreshToken())
|
||||
return request.post('/auth/token/refresh/', data)
|
||||
}
|
||||
|
||||
export default http
|
||||
|
@ -11,3 +11,17 @@ export function setToken(token) {
|
||||
export function removeToken() {
|
||||
return uni.removeStorageSync(TokenKey)
|
||||
}
|
||||
|
||||
const RefreshTokenKey = 'Refresh-Token'
|
||||
|
||||
export function getRefreshToken() {
|
||||
return uni.getStorageSync(RefreshTokenKey)
|
||||
}
|
||||
|
||||
export function setRefreshToken(token) {
|
||||
return uni.setStorageSync(RefreshTokenKey, token)
|
||||
}
|
||||
|
||||
export function removeRefreshToken() {
|
||||
return uni.removeStorageSync(RefreshTokenKey)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 显示消息提示框
|
||||
* @param content 提示的标题
|
||||
*/
|
||||
* 显示消息提示框
|
||||
* @param content 提示的标题
|
||||
*/
|
||||
export function toast(content) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
@ -10,9 +10,9 @@ export function toast(content) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示模态弹窗
|
||||
* @param content 提示的标题
|
||||
*/
|
||||
* 显示模态弹窗
|
||||
* @param content 提示的标题
|
||||
*/
|
||||
export function showConfirm(content) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.showModal({
|
||||
@ -20,7 +20,7 @@ export function showConfirm(content) {
|
||||
content: content,
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
success: function(res) {
|
||||
success: function (res) {
|
||||
resolve(res)
|
||||
}
|
||||
})
|
||||
@ -28,27 +28,27 @@ export function showConfirm(content) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数处理
|
||||
* @param params 参数
|
||||
*/
|
||||
* 参数处理
|
||||
* @param params 参数
|
||||
*/
|
||||
export function tansParams(params) {
|
||||
let result = ''
|
||||
for (const propName of Object.keys(params)) {
|
||||
const value = params[propName]
|
||||
var part = encodeURIComponent(propName) + "="
|
||||
if (value !== null && value !== "" && typeof (value) !== "undefined") {
|
||||
var part = encodeURIComponent(propName) + '='
|
||||
if (value !== null && value !== '' && typeof value !== 'undefined') {
|
||||
if (typeof value === 'object') {
|
||||
for (const key of Object.keys(value)) {
|
||||
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
|
||||
if (value[key] !== null && value[key] !== '' && typeof value[key] !== 'undefined') {
|
||||
let params = propName + '[' + key + ']'
|
||||
var subPart = encodeURIComponent(params) + "="
|
||||
result += subPart + encodeURIComponent(value[key]) + "&"
|
||||
var subPart = encodeURIComponent(params) + '='
|
||||
result += subPart + encodeURIComponent(value[key]) + '&'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result += part + encodeURIComponent(value) + "&"
|
||||
result += part + encodeURIComponent(value) + '&'
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
export const auth = {
|
||||
isUser: 'vuex_auth_isUser',
|
||||
isUserOpenid: 'vuex_auth_isUserOpenid',
|
||||
isResetPassword: 'vuex_auth_isResetPassword',
|
||||
name: 'vuex_auth_name',
|
||||
nickname: 'vuex_auth_nickname',
|
||||
gender: 'vuex_auth_gender',
|
||||
telephone: 'vuex_auth_telephone',
|
||||
isUser: 'vuex_auth_isUser',
|
||||
isUserOpenid: 'vuex_auth_isUserOpenid',
|
||||
isResetPassword: 'vuex_auth_isResetPassword',
|
||||
name: 'vuex_auth_name',
|
||||
nickname: 'vuex_auth_nickname',
|
||||
gender: 'vuex_auth_gender',
|
||||
telephone: 'vuex_auth_telephone',
|
||||
avatar: 'vuex_auth_avatar',
|
||||
createDatetime: 'vuex_auth_createDatetime',
|
||||
roles: 'vuex_auth_roles',
|
||||
|
@ -1,80 +0,0 @@
|
||||
const TokenKey = 'Admin-Token'
|
||||
|
||||
// 获取客户端token
|
||||
export function getToken() {
|
||||
try {
|
||||
const value = uni.getStorageSync(TokenKey);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
return ""
|
||||
} catch (e) {
|
||||
// error
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// 设置客户端token
|
||||
export function setToken(token) {
|
||||
uni.setStorage({
|
||||
key: TokenKey,
|
||||
data: token,
|
||||
success: function (res) {
|
||||
console.log('成功存储token');
|
||||
},
|
||||
fail:function(e){
|
||||
console.log(e)
|
||||
console.log("存储token失败");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 删除客户端token
|
||||
export function removeToken() {
|
||||
uni.removeStorage({
|
||||
key: TokenKey,
|
||||
success: function (res) {
|
||||
console.log('成功删除token');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 获取客户端
|
||||
export function getStorage(key) {
|
||||
try {
|
||||
const value = uni.getStorageSync(key);
|
||||
if (value) {
|
||||
// console.log("成功获取到 Storage:", value);
|
||||
return value;
|
||||
}
|
||||
return ""
|
||||
} catch (e) {
|
||||
// error
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// 设置客户端 Storage
|
||||
export function setStorage(key, value) {
|
||||
uni.setStorage({
|
||||
key: key,
|
||||
data: value,
|
||||
success: function (res) {
|
||||
console.log('成功存储');
|
||||
},
|
||||
fail:function(e){
|
||||
console.log(e)
|
||||
console.log("存储失败");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 删除客户端 Storage
|
||||
export function removeStorage(key) {
|
||||
uni.removeStorage({
|
||||
key: key,
|
||||
success: function (res) {
|
||||
console.log('成功删除Storage');
|
||||
}
|
||||
});
|
||||
}
|
@ -17,14 +17,16 @@ module.exports = {
|
||||
if (!log) return
|
||||
log.error.apply(log, arguments)
|
||||
},
|
||||
setFilterMsg(msg) { // 从基础库2.7.3开始支持
|
||||
setFilterMsg(msg) {
|
||||
// 从基础库2.7.3开始支持
|
||||
if (!log || !log.setFilterMsg) return
|
||||
if (typeof msg !== 'string') return
|
||||
log.setFilterMsg(msg)
|
||||
},
|
||||
addFilterMsg(msg) { // 从基础库2.8.1开始支持
|
||||
addFilterMsg(msg) {
|
||||
// 从基础库2.8.1开始支持
|
||||
if (!log || !log.addFilterMsg) return
|
||||
if (typeof msg !== 'string') return
|
||||
log.addFilterMsg(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ export function checkPermi(value) {
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const permissions = store.getters && store.getters.permissions
|
||||
const permissionDatas = value
|
||||
const all_permission = "*:*:*"
|
||||
const all_permission = '*:*:*'
|
||||
|
||||
const hasPermission = permissions.some(permission => {
|
||||
const hasPermission = permissions.some((permission) => {
|
||||
return all_permission === permission || permissionDatas.includes(permission)
|
||||
})
|
||||
|
||||
@ -20,7 +20,7 @@ export function checkPermi(value) {
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
|
||||
console.error('未获取到校验的字符权限!')
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -34,9 +34,9 @@ export function checkRole(value) {
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const roles = store.getters && store.getters.roles
|
||||
const permissionRoles = value
|
||||
const super_admin = "admin"
|
||||
const super_admin = 'admin'
|
||||
|
||||
const hasRole = roles.some(role => {
|
||||
const hasRole = roles.some((role) => {
|
||||
return super_admin === role || permissionRoles.includes(role)
|
||||
})
|
||||
|
||||
@ -45,7 +45,7 @@ export function checkRole(value) {
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
console.error(`need roles! Like checkRole="['admin','editor']"`)
|
||||
console.error('未获取到校验的角色!')
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,34 +5,32 @@
|
||||
博客:https://www.jianshu.com/p/71ad2f45120c
|
||||
*/
|
||||
|
||||
|
||||
import config from '@/config.js'
|
||||
import { getToken, removeToken } from '@/common/utils/cookies'
|
||||
|
||||
import { getToken } from '@/common/utils/auth'
|
||||
|
||||
// 单个文件上传
|
||||
export function uploadFile(api, file, data={}) {
|
||||
export function uploadFile(api, file, data = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: config.baseUrl + api,
|
||||
filePath: file,
|
||||
name: 'file',
|
||||
timeout: 60000,
|
||||
formData: data,
|
||||
header: {
|
||||
Authorization: getToken()
|
||||
},
|
||||
success: (res) => {
|
||||
let data = JSON.parse(res.data);
|
||||
if (data.code !== 200) {
|
||||
reject(data);
|
||||
}
|
||||
resolve(data);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log("上传失败", err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
uni.uploadFile({
|
||||
url: config.baseUrl + api,
|
||||
filePath: file,
|
||||
name: 'file',
|
||||
timeout: 60000,
|
||||
formData: data,
|
||||
header: {
|
||||
Authorization: getToken()
|
||||
},
|
||||
success: (res) => {
|
||||
let data = JSON.parse(res.data)
|
||||
if (data.code !== 200) {
|
||||
reject(data)
|
||||
}
|
||||
resolve(data)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log('上传失败', err)
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -13,47 +13,47 @@
|
||||
* getDate(new Date(), 3).fullDate # 三天后的日期
|
||||
*/
|
||||
export function getDate(date, AddDayCount = 0) {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
if (typeof date !== 'object') {
|
||||
date = date.replace(/-/g, '/')
|
||||
}
|
||||
const dd = new Date(date)
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
if (typeof date !== 'object') {
|
||||
date = date.replace(/-/g, '/')
|
||||
}
|
||||
const dd = new Date(date)
|
||||
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
|
||||
const y = dd.getFullYear()
|
||||
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
|
||||
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
|
||||
return {
|
||||
fullDate: y + '-' + m + '-' + d,
|
||||
year: y,
|
||||
month: m,
|
||||
date: d,
|
||||
day: dd.getDay()
|
||||
}
|
||||
const y = dd.getFullYear()
|
||||
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
|
||||
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
|
||||
return {
|
||||
fullDate: y + '-' + m + '-' + d,
|
||||
year: y,
|
||||
month: m,
|
||||
date: d,
|
||||
day: dd.getDay()
|
||||
}
|
||||
}
|
||||
|
||||
// 日期格式化
|
||||
export function parseTime(time, pattern) {
|
||||
if (arguments.length === 0 || !time) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
const format = pattern || "{y}-{m}-{d} {h}:{i}:{s}";
|
||||
let date;
|
||||
if (typeof time === "object") {
|
||||
date = time;
|
||||
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
|
||||
let date
|
||||
if (typeof time === 'object') {
|
||||
date = time
|
||||
} else {
|
||||
if ((typeof time === "string") && (/^[0-9]+$/.test(time))) {
|
||||
time = parseInt(time);
|
||||
} else if (typeof time === "string") {
|
||||
time = time.replace(new RegExp(/-/gm), "/");
|
||||
if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
|
||||
time = parseInt(time)
|
||||
} else if (typeof time === 'string') {
|
||||
time = time.replace(new RegExp(/-/gm), '/')
|
||||
}
|
||||
if ((typeof time === "number") && (time.toString().length === 10)) {
|
||||
time = time * 1000;
|
||||
if (typeof time === 'number' && time.toString().length === 10) {
|
||||
time = time * 1000
|
||||
}
|
||||
date = new Date(time);
|
||||
date = new Date(time)
|
||||
}
|
||||
const formatObj = {
|
||||
y: date.getFullYear(),
|
||||
@ -63,129 +63,132 @@ export function parseTime(time, pattern) {
|
||||
i: date.getMinutes(),
|
||||
s: date.getSeconds(),
|
||||
a: date.getDay()
|
||||
};
|
||||
}
|
||||
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
||||
let value = formatObj[key];
|
||||
let value = formatObj[key]
|
||||
// Note: getDay() returns 0 on Sunday
|
||||
if (key === "a") { return ["日", "一", "二", "三", "四", "五", "六"][value]; }
|
||||
if (result.length > 0 && value < 10) {
|
||||
value = "0" + value;
|
||||
if (key === 'a') {
|
||||
return ['日', '一', '二', '三', '四', '五', '六'][value]
|
||||
}
|
||||
return value || 0;
|
||||
});
|
||||
return time_str;
|
||||
if (result.length > 0 && value < 10) {
|
||||
value = '0' + value
|
||||
}
|
||||
return value || 0
|
||||
})
|
||||
return time_str
|
||||
}
|
||||
|
||||
// 表单重置
|
||||
export function resetForm(refName) {
|
||||
if (this.$refs[refName]) {
|
||||
this.$refs[refName].resetFields();
|
||||
this.$refs[refName].resetFields()
|
||||
}
|
||||
}
|
||||
|
||||
// 添加日期范围
|
||||
export function addDateRange(params, dateRange, propName) {
|
||||
const search = JSON.parse(JSON.stringify(params));
|
||||
if (dateRange != null && dateRange !== "" && dateRange.length !== 0) {
|
||||
search.as = JSON.stringify({ create_datetime__range: dateRange });
|
||||
const search = JSON.parse(JSON.stringify(params))
|
||||
if (dateRange != null && dateRange !== '' && dateRange.length !== 0) {
|
||||
search.as = JSON.stringify({ create_datetime__range: dateRange })
|
||||
}
|
||||
return search;
|
||||
return search
|
||||
}
|
||||
|
||||
// 回显数据字典
|
||||
export function selectDictLabel(datas, value) {
|
||||
var actions = [];
|
||||
var actions = []
|
||||
Object.keys(datas).some((key) => {
|
||||
if (String(datas[key].value) === ("" + String(value))) {
|
||||
actions.push(datas[key].label);
|
||||
return true;
|
||||
if (String(datas[key].value) === '' + String(value)) {
|
||||
actions.push(datas[key].label)
|
||||
return true
|
||||
}
|
||||
});
|
||||
return actions.join("");
|
||||
})
|
||||
return actions.join('')
|
||||
}
|
||||
// 获取字典默认值
|
||||
export function selectDictDefault(datas) {
|
||||
var actions = [];
|
||||
var actions = []
|
||||
Object.keys(datas).some((key) => {
|
||||
if (datas[key].is_default === true) {
|
||||
actions.push(datas[key].dictValue);
|
||||
return true;
|
||||
actions.push(datas[key].dictValue)
|
||||
return true
|
||||
}
|
||||
});
|
||||
})
|
||||
if (!actions[0] && datas[0]) {
|
||||
actions.push(datas[0].dictValue);
|
||||
actions.push(datas[0].dictValue)
|
||||
}
|
||||
return actions.join("");
|
||||
return actions.join('')
|
||||
}
|
||||
|
||||
// 回显数据字典(字符串数组)
|
||||
export function selectDictLabels(datas, value, separator) {
|
||||
var actions = [];
|
||||
var currentSeparator = undefined === separator ? "," : separator;
|
||||
var temp = value.split(currentSeparator);
|
||||
var actions = []
|
||||
var currentSeparator = undefined === separator ? ',' : separator
|
||||
var temp = value.split(currentSeparator)
|
||||
Object.keys(value.split(currentSeparator)).some((val) => {
|
||||
Object.keys(datas).some((key) => {
|
||||
if (datas[key].dictValue == ("" + temp[val])) {
|
||||
actions.push(datas[key].dictLabel + currentSeparator);
|
||||
if (datas[key].dictValue == '' + temp[val]) {
|
||||
actions.push(datas[key].dictLabel + currentSeparator)
|
||||
}
|
||||
});
|
||||
});
|
||||
return actions.join("").substring(0, actions.join("").length - 1);
|
||||
})
|
||||
})
|
||||
return actions.join('').substring(0, actions.join('').length - 1)
|
||||
}
|
||||
|
||||
// 转换字符串,undefined,null等转化为""
|
||||
export function praseStrEmpty(str) {
|
||||
if (!str || str == "undefined" || str == "null") {
|
||||
return "";
|
||||
if (!str || str == 'undefined' || str == 'null') {
|
||||
return ''
|
||||
}
|
||||
return str;
|
||||
return str
|
||||
}
|
||||
|
||||
// js模仿微信朋友圈计算时间显示几天/几小时/几分钟/刚刚
|
||||
//datetime 格式为2019-11-22 12:23:59样式
|
||||
export function timeConversion(datetime) { //dateTimeStamp是一个时间毫秒,注意时间戳是秒的形式,在这个毫秒的基础上除以1000,就是十位数的时间戳。13位数的都是时间毫秒。
|
||||
// var dateTimeStamp = new Date(datetime.replace(/ /, 'T')).getTime()-8 * 60 * 60 * 1000;//这里要减去中国的时区8小时
|
||||
var dateTimeStamp = new Date(datetime.replace(/ /, 'T')).getTime();//这里不减去中国的时区8小时
|
||||
var minute = 1000 * 60; //把分,时,天,周,半个月,一个月用毫秒表示
|
||||
var hour = minute * 60;
|
||||
var day = hour * 24;
|
||||
var week = day * 7;
|
||||
var halfamonth = day * 15;
|
||||
var month = day * 30;
|
||||
var now = new Date().getTime(); //获取当前时间毫秒
|
||||
var diffValue = now - dateTimeStamp; //时间差
|
||||
|
||||
if (diffValue < 0) {
|
||||
return '刚刚';
|
||||
}
|
||||
var minC = diffValue / minute; //计算时间差的分,时,天,周,月
|
||||
var hourC = diffValue / hour;
|
||||
var dayC = diffValue / day;
|
||||
var weekC = diffValue / week;
|
||||
var monthC = diffValue / month;
|
||||
var result = "2";
|
||||
if (monthC >= 1 && monthC <= 3) {
|
||||
result = " " + parseInt(monthC) + "月前"
|
||||
} else if (weekC >= 1 && weekC <= 3) {
|
||||
result = " " + parseInt(weekC) + "周前"
|
||||
} else if (dayC >= 1 && dayC <= 6) {
|
||||
result = " " + parseInt(dayC) + "天前"
|
||||
} else if (hourC >= 1 && hourC <= 23) {
|
||||
result = " " + parseInt(hourC) + "小时前"
|
||||
} else if (minC >= 1 && minC <= 59) {
|
||||
result = " " + parseInt(minC) + "分钟前"
|
||||
} else if (diffValue >= 0 && diffValue <= minute) {
|
||||
result = "刚刚"
|
||||
} else {
|
||||
var datetime = new Date();
|
||||
datetime.setTime(dateTimeStamp);
|
||||
var Nyear = datetime.getFullYear(); {}
|
||||
var Nmonth = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1;
|
||||
var Ndate = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
|
||||
var Nhour = datetime.getHours() < 10 ? "0" + datetime.getHours() : datetime.getHours();
|
||||
var Nminute = datetime.getMinutes() < 10 ? "0" + datetime.getMinutes() : datetime.getMinutes();
|
||||
var Nsecond = datetime.getSeconds() < 10 ? "0" + datetime.getSeconds() : datetime.getSeconds();
|
||||
result = Nyear + "-" + Nmonth + "-" + Ndate
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export function timeConversion(datetime) {
|
||||
//dateTimeStamp是一个时间毫秒,注意时间戳是秒的形式,在这个毫秒的基础上除以1000,就是十位数的时间戳。13位数的都是时间毫秒。
|
||||
// var dateTimeStamp = new Date(datetime.replace(/ /, 'T')).getTime()-8 * 60 * 60 * 1000;//这里要减去中国的时区8小时
|
||||
var dateTimeStamp = new Date(datetime.replace(/ /, 'T')).getTime() //这里不减去中国的时区8小时
|
||||
var minute = 1000 * 60 //把分,时,天,周,半个月,一个月用毫秒表示
|
||||
var hour = minute * 60
|
||||
var day = hour * 24
|
||||
var week = day * 7
|
||||
var month = day * 30
|
||||
var now = new Date().getTime() //获取当前时间毫秒
|
||||
var diffValue = now - dateTimeStamp //时间差
|
||||
|
||||
if (diffValue < 0) {
|
||||
return '刚刚'
|
||||
}
|
||||
var minC = diffValue / minute //计算时间差的分,时,天,周,月
|
||||
var hourC = diffValue / hour
|
||||
var dayC = diffValue / day
|
||||
var weekC = diffValue / week
|
||||
var monthC = diffValue / month
|
||||
var result = '2'
|
||||
if (monthC >= 1 && monthC <= 3) {
|
||||
result = ' ' + parseInt(monthC) + '月前'
|
||||
} else if (weekC >= 1 && weekC <= 3) {
|
||||
result = ' ' + parseInt(weekC) + '周前'
|
||||
} else if (dayC >= 1 && dayC <= 6) {
|
||||
result = ' ' + parseInt(dayC) + '天前'
|
||||
} else if (hourC >= 1 && hourC <= 23) {
|
||||
result = ' ' + parseInt(hourC) + '小时前'
|
||||
} else if (minC >= 1 && minC <= 59) {
|
||||
result = ' ' + parseInt(minC) + '分钟前'
|
||||
} else if (diffValue >= 0 && diffValue <= minute) {
|
||||
result = '刚刚'
|
||||
} else {
|
||||
let datetime = new Date()
|
||||
datetime.setTime(dateTimeStamp)
|
||||
let Nyear = datetime.getFullYear()
|
||||
var Nmonth =
|
||||
datetime.getMonth() + 1 < 10 ? '0' + (datetime.getMonth() + 1) : datetime.getMonth() + 1
|
||||
var Ndate = datetime.getDate() < 10 ? '0' + datetime.getDate() : datetime.getDate()
|
||||
var Nhour = datetime.getHours() < 10 ? '0' + datetime.getHours() : datetime.getHours()
|
||||
var Nminute = datetime.getMinutes() < 10 ? '0' + datetime.getMinutes() : datetime.getMinutes()
|
||||
var Nsecond = datetime.getSeconds() < 10 ? '0' + datetime.getSeconds() : datetime.getSeconds()
|
||||
result = Nyear + '-' + Nmonth + '-' + Ndate
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ let storageNodeKeys = [...Object.values(auth)]
|
||||
let storageData = uni.getStorageSync(storageKey) || {}
|
||||
|
||||
const storage = {
|
||||
set: function(key, value) {
|
||||
set: function (key, value) {
|
||||
if (storageNodeKeys.indexOf(key) != -1) {
|
||||
let tmp = uni.getStorageSync(storageKey)
|
||||
tmp = tmp ? tmp : {}
|
||||
@ -21,14 +21,14 @@ const storage = {
|
||||
uni.setStorageSync(storageKey, tmp)
|
||||
}
|
||||
},
|
||||
get: function(key) {
|
||||
return storageData[key] || ""
|
||||
get: function (key) {
|
||||
return storageData[key] || ''
|
||||
},
|
||||
remove: function(key) {
|
||||
remove: function (key) {
|
||||
delete storageData[key]
|
||||
uni.setStorageSync(storageKey, storageData)
|
||||
},
|
||||
clean: function() {
|
||||
clean: function () {
|
||||
uni.removeStorageSync(storageKey)
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import { toast, showConfirm, tansParams } from '@/common/utils/common'
|
||||
let timeout = 10000
|
||||
const baseUrl = config.baseUrl
|
||||
|
||||
const upload = config => {
|
||||
const upload = (config) => {
|
||||
// 是否需要设置 token
|
||||
const isToken = (config.headers || {}).isToken === false
|
||||
config.header = config.header || {}
|
||||
@ -21,47 +21,47 @@ const upload = config => {
|
||||
config.url = url
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
timeout: config.timeout || timeout,
|
||||
url: baseUrl + config.url,
|
||||
filePath: config.filePath,
|
||||
name: config.name || 'file',
|
||||
header: config.header,
|
||||
formData: config.formData,
|
||||
success: (res) => {
|
||||
let result = JSON.parse(res.data)
|
||||
const code = result.code || 200
|
||||
const msg = errorCode[code] || result.msg || errorCode['default']
|
||||
if (code === 200) {
|
||||
resolve(result)
|
||||
} else if (code == 401) {
|
||||
showConfirm("登录状态已过期,您可以继续留在该页面,或者重新登录?").then(res => {
|
||||
if (res.confirm) {
|
||||
store.dispatch('LogOut')
|
||||
}
|
||||
})
|
||||
reject('无效的会话,或者会话已过期,请重新登录。')
|
||||
} else if (code === 500) {
|
||||
toast(msg)
|
||||
reject('500')
|
||||
} else if (code !== 200) {
|
||||
toast(msg)
|
||||
reject(code)
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
let { message } = error
|
||||
if (message == 'Network Error') {
|
||||
message = '后端接口连接异常'
|
||||
} else if (message.includes('timeout')) {
|
||||
message = '系统接口请求超时'
|
||||
} else if (message.includes('Request failed with status code')) {
|
||||
message = '系统接口' + message.substr(message.length - 3) + '异常'
|
||||
}
|
||||
toast(message)
|
||||
reject(error)
|
||||
uni.uploadFile({
|
||||
timeout: config.timeout || timeout,
|
||||
url: baseUrl + config.url,
|
||||
filePath: config.filePath,
|
||||
name: config.name || 'file',
|
||||
header: config.header,
|
||||
formData: config.formData,
|
||||
success: (res) => {
|
||||
let result = JSON.parse(res.data)
|
||||
const code = result.code || 200
|
||||
const msg = errorCode[code] || result.msg || errorCode['default']
|
||||
if (code === 200) {
|
||||
resolve(result)
|
||||
} else if (code == 401) {
|
||||
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then((res) => {
|
||||
if (res.confirm) {
|
||||
store.dispatch('LogOut')
|
||||
}
|
||||
})
|
||||
reject('无效的会话,或者会话已过期,请重新登录。')
|
||||
} else if (code === 500) {
|
||||
toast(msg)
|
||||
reject('500')
|
||||
} else if (code !== 200) {
|
||||
toast(msg)
|
||||
reject(code)
|
||||
}
|
||||
})
|
||||
},
|
||||
fail: (error) => {
|
||||
let { message } = error
|
||||
if (message == 'Network Error') {
|
||||
message = '后端接口连接异常'
|
||||
} else if (message.includes('timeout')) {
|
||||
message = '系统接口请求超时'
|
||||
} else if (message.includes('Request failed with status code')) {
|
||||
message = '系统接口' + message.substr(message.length - 3) + '异常'
|
||||
}
|
||||
toast(message)
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
// 应用全局配置
|
||||
module.exports = {
|
||||
// 测试环境
|
||||
// 测试环境
|
||||
baseUrl: 'http://127.0.0.1:9000',
|
||||
// 生产环境
|
||||
// baseUrl: 'https://api.kinit.ktianc.top',
|
||||
// 应用信息
|
||||
appInfo: {
|
||||
// 应用版本
|
||||
version: "1.1.0",
|
||||
// 隐私政策,不支持本地路径
|
||||
privacy: "http://kinit.ktianc.top/docs/privacy",
|
||||
// 用户协议,不支持本地路径
|
||||
agreement: "http://kinit.ktianc.top/docs/agreement"
|
||||
version: '1.2.0',
|
||||
// 隐私政策,不支持本地路径
|
||||
privacy: 'http://kinit.ktianc.top/docs/privacy',
|
||||
// 用户协议,不支持本地路径
|
||||
agreement: 'http://kinit.ktianc.top/docs/agreement'
|
||||
}
|
||||
}
|
||||
|
8
kinit-uni/jsconfig.json
Normal file
8
kinit-uni/jsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@ import Vue from 'vue'
|
||||
import App from './App'
|
||||
import store from './store' // store
|
||||
import plugins from './plugins' // plugins
|
||||
import {router,RouterMount} from './permission.js' // 路由拦截
|
||||
import uView from "uview-ui"
|
||||
import { router, RouterMount } from './permission.js' // 路由拦截
|
||||
import uView from 'uview-ui'
|
||||
|
||||
Vue.use(uView)
|
||||
Vue.use(router)
|
||||
@ -14,28 +14,28 @@ Vue.use(plugins)
|
||||
// 配置后,很多组件的默认尺寸就变了,需要手动调整,不熟悉不建议开启
|
||||
// 需要在Vue.use(uView)之后执行
|
||||
uni.$u.setConfig({
|
||||
// 修改$u.config对象的属性
|
||||
config: {
|
||||
// 修改默认单位为rpx,相当于执行 uni.$u.config.unit = 'rpx'
|
||||
unit: 'rpx'
|
||||
},
|
||||
// 修改$u.props对象的属性
|
||||
props: {
|
||||
// 修改radio组件的size参数的默认值,相当于执行 uni.$u.props.radio.size = 30
|
||||
radio: {
|
||||
size: 33,
|
||||
labelSize: 30
|
||||
},
|
||||
button: {
|
||||
loadingSize: 28
|
||||
},
|
||||
text: {
|
||||
size: 30,
|
||||
color: '#000'
|
||||
}
|
||||
// 其他组件属性配置
|
||||
// ......
|
||||
}
|
||||
// 修改$u.config对象的属性
|
||||
config: {
|
||||
// 修改默认单位为rpx,相当于执行 uni.$u.config.unit = 'rpx'
|
||||
unit: 'rpx'
|
||||
},
|
||||
// 修改$u.props对象的属性
|
||||
props: {
|
||||
// 修改radio组件的size参数的默认值,相当于执行 uni.$u.props.radio.size = 30
|
||||
radio: {
|
||||
size: 33,
|
||||
labelSize: 30
|
||||
},
|
||||
button: {
|
||||
loadingSize: 28
|
||||
},
|
||||
text: {
|
||||
size: 30,
|
||||
color: '#000'
|
||||
}
|
||||
// 其他组件属性配置
|
||||
// ......
|
||||
}
|
||||
})
|
||||
|
||||
Vue.config.productionTip = false
|
||||
@ -49,9 +49,9 @@ const app = new Vue({
|
||||
|
||||
//v1.3.5起 H5端 你应该去除原有的app.$mount();使用路由自带的渲染方式
|
||||
// #ifdef H5
|
||||
RouterMount(app, router, '#app')
|
||||
RouterMount(app, router, '#app')
|
||||
// #endif
|
||||
|
||||
// #ifndef H5
|
||||
app.$mount(); //为了兼容小程序及app端必须这样写才有效果
|
||||
app.$mount() //为了兼容小程序及app端必须这样写才有效果
|
||||
// #endif
|
||||
|
@ -3,5 +3,11 @@
|
||||
"uni-read-pages": "^1.0.5",
|
||||
"uni-simple-router": "^2.0.8-beta.3",
|
||||
"uview-ui": "^2.0.34"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.7.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-vue": "^9.9.0"
|
||||
}
|
||||
}
|
||||
|
@ -7,42 +7,42 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
content: ''
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.query) {
|
||||
this.title = options.query.title
|
||||
this.content = options.query.content
|
||||
} else {
|
||||
this.title = options.title
|
||||
this.content = options.content
|
||||
}
|
||||
uni.setNavigationBarTitle({
|
||||
title: options.title
|
||||
})
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
content: ''
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.query) {
|
||||
this.title = options.query.title
|
||||
this.content = options.query.content
|
||||
} else {
|
||||
this.title = options.title
|
||||
this.content = options.content
|
||||
}
|
||||
uni.setNavigationBarTitle({
|
||||
title: options.title
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.view-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
.view-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.view-content {
|
||||
font-size: 26rpx;
|
||||
padding: 12px 5px 0;
|
||||
color: #333;
|
||||
line-height: 24px;
|
||||
font-weight: normal;
|
||||
}
|
||||
.view-content {
|
||||
font-size: 26rpx;
|
||||
padding: 12px 5px 0;
|
||||
color: #333;
|
||||
line-height: 24px;
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,35 +1,35 @@
|
||||
<template>
|
||||
<view v-if="params.url">
|
||||
<!-- 不支持本地路径 -->
|
||||
<!-- 不支持本地路径 -->
|
||||
<web-view :webview-styles="webviewStyles" :src="`${params.url}`"></web-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
params: {},
|
||||
webviewStyles: {
|
||||
progress: {
|
||||
color: "#FF3333"
|
||||
}
|
||||
export default {
|
||||
props: {
|
||||
src: {
|
||||
type: [String],
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
params: {},
|
||||
webviewStyles: {
|
||||
progress: {
|
||||
color: '#FF3333'
|
||||
}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
src: {
|
||||
type: [String],
|
||||
default: null
|
||||
}
|
||||
},
|
||||
onLoad(event) {
|
||||
this.params = event
|
||||
if (event.title) {
|
||||
uni.setNavigationBarTitle({
|
||||
title: event.title
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(event) {
|
||||
this.params = event
|
||||
if (event.title) {
|
||||
uni.setNavigationBarTitle({
|
||||
title: event.title
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -8,48 +8,48 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { wxShareMixins } from '@/common/mixins/share.js'
|
||||
|
||||
export default {
|
||||
mixins: [wxShareMixins],
|
||||
computed: {
|
||||
name() {
|
||||
return this.$store.state.auth.name
|
||||
},
|
||||
logo() {
|
||||
return this.$store.state.app.logo
|
||||
},
|
||||
logoImage() {
|
||||
return this.$store.state.app.logoImage
|
||||
}
|
||||
import { wxShareMixins } from '@/common/mixins/share.js'
|
||||
|
||||
export default {
|
||||
mixins: [wxShareMixins],
|
||||
computed: {
|
||||
name() {
|
||||
return this.$store.state.auth.name
|
||||
},
|
||||
logo() {
|
||||
return this.$store.state.app.logo
|
||||
},
|
||||
logoImage() {
|
||||
return this.$store.state.app.logoImage
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.logo {
|
||||
height: 200rpx;
|
||||
width: 200rpx;
|
||||
margin-top: 200rpx;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
|
||||
.text-area {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
color: #8f8f94;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.logo {
|
||||
height: 200rpx;
|
||||
width: 200rpx;
|
||||
margin-top: 200rpx;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 50rpx;
|
||||
}
|
||||
|
||||
.text-area {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
color: #8f8f94;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,201 +1,212 @@
|
||||
<template>
|
||||
<view class="normal-login-container">
|
||||
<view class="logo-content align-center justify-center flex">
|
||||
<image v-if="logo" style="width: 100rpx;height: 100rpx;" :src="logoImage" mode="widthFix">
|
||||
<image v-if="logo" style="width: 100rpx; height: 100rpx" :src="logoImage" mode="widthFix">
|
||||
</image>
|
||||
<text class="title">{{ title }}</text>
|
||||
</view>
|
||||
<view class="login-form-content">
|
||||
<view class="input-item flex align-center">
|
||||
<view class="iconfont icon-user icon"></view>
|
||||
<input v-model="loginForm.telephone" class="input" type="text" placeholder="请输入手机号" maxlength="30" />
|
||||
<input
|
||||
v-model="loginForm.telephone"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="请输入手机号"
|
||||
maxlength="30"
|
||||
/>
|
||||
</view>
|
||||
<view class="input-item flex align-center">
|
||||
<view class="iconfont icon-password icon"></view>
|
||||
<input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" />
|
||||
<input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
class="input"
|
||||
placeholder="请输入密码"
|
||||
maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
<view class="action-btn">
|
||||
<!-- <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">登录</button> -->
|
||||
<u-button type="primary" text="登录" @click="handleLogin" shape="circle"></u-button>
|
||||
<u-button type="primary" text="登录" shape="circle" @click="handleLogin"></u-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="xieyi text-center">
|
||||
<text class="text-grey1">登录即代表同意</text>
|
||||
<text @click="handleUserAgrement" class="text-blue">《用户协议》</text>
|
||||
<text @click="handlePrivacy" class="text-blue">《隐私协议》</text>
|
||||
<text class="text-blue" @click="handleUserAgrement">《用户协议》</text>
|
||||
<text class="text-blue" @click="handlePrivacy">《隐私协议》</text>
|
||||
</view>
|
||||
|
||||
<view class="footer text-center">
|
||||
<u-button
|
||||
type="primary"
|
||||
text="微信一键登录"
|
||||
shape="circle"
|
||||
open-type="getPhoneNumber"
|
||||
@getphonenumber="wxLogin"
|
||||
></u-button>
|
||||
</view>
|
||||
|
||||
<view class="footer text-center">
|
||||
<u-button
|
||||
type="primary"
|
||||
text="微信一键登录"
|
||||
shape="circle"
|
||||
open-type="getPhoneNumber"
|
||||
@getphonenumber="wxLogin"
|
||||
></u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { wxLoginMixins } from '@/common/mixins/auth.js'
|
||||
|
||||
export default {
|
||||
mixins: [wxLoginMixins],
|
||||
data() {
|
||||
return {
|
||||
loginForm: {
|
||||
telephone: "15020221010",
|
||||
password: "kinit2022"
|
||||
}
|
||||
import { wxLoginMixins } from '@/common/mixins/auth.js'
|
||||
|
||||
export default {
|
||||
mixins: [wxLoginMixins],
|
||||
data() {
|
||||
return {
|
||||
loginForm: {
|
||||
telephone: '15020221010',
|
||||
password: 'kinit2022'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.$store.state.app.title
|
||||
},
|
||||
logo() {
|
||||
return this.$store.state.app.logo
|
||||
},
|
||||
logoImage() {
|
||||
return this.$store.state.app.logoImage
|
||||
},
|
||||
privacy() {
|
||||
return this.$store.state.app.privacy
|
||||
},
|
||||
agreement() {
|
||||
return this.$store.state.app.agreement
|
||||
},
|
||||
isResetPassword() {
|
||||
return this.$store.state.auth.isResetPassword
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 隐私政策
|
||||
handlePrivacy() {
|
||||
const title = '隐私政策'
|
||||
this.$tab.navigateTo(`/pages/common/webview/index?title=${title}&url=${this.privacy}`)
|
||||
},
|
||||
// 用户协议
|
||||
handleUserAgrement() {
|
||||
const title = '用户协议'
|
||||
this.$tab.navigateTo(`/pages/common/webview/index?title=${title}&url=${this.agreement}`)
|
||||
},
|
||||
// 登录方法
|
||||
async handleLogin() {
|
||||
if (this.loginForm.telephone === '') {
|
||||
this.$modal.msgError('请输入您的手机号')
|
||||
} else if (this.loginForm.password === '') {
|
||||
this.$modal.msgError('请输入您的密码')
|
||||
} else {
|
||||
this.$modal.loading('正在登录中...')
|
||||
this.pwdLogin()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.$store.state.app.title
|
||||
},
|
||||
logo() {
|
||||
return this.$store.state.app.logo
|
||||
},
|
||||
logoImage() {
|
||||
return this.$store.state.app.logoImage
|
||||
},
|
||||
privacy() {
|
||||
return this.$store.state.app.privacy
|
||||
},
|
||||
agreement() {
|
||||
return this.$store.state.app.agreement
|
||||
},
|
||||
isResetPassword() {
|
||||
return this.$store.state.auth.isResetPassword
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 隐私政策
|
||||
handlePrivacy() {
|
||||
const title = '隐私政策'
|
||||
this.$tab.navigateTo(`/pages/common/webview/index?title=${title}&url=${this.privacy}`)
|
||||
},
|
||||
// 用户协议
|
||||
handleUserAgrement() {
|
||||
const title = '用户协议'
|
||||
this.$tab.navigateTo(`/pages/common/webview/index?title=${title}&url=${this.agreement}`)
|
||||
},
|
||||
// 登录方法
|
||||
async handleLogin() {
|
||||
if (this.loginForm.telephone === "") {
|
||||
this.$modal.msgError("请输入您的手机号")
|
||||
} else if (this.loginForm.password === "") {
|
||||
this.$modal.msgError("请输入您的密码")
|
||||
}else {
|
||||
this.$modal.loading("正在登录中...")
|
||||
this.pwdLogin()
|
||||
}
|
||||
},
|
||||
// 密码登录
|
||||
async pwdLogin() {
|
||||
this.$store.dispatch('auth/Login', this.loginForm).then(() => {
|
||||
this.$modal.closeLoading()
|
||||
this.loginSuccess()
|
||||
})
|
||||
},
|
||||
// 登录成功后,处理函数
|
||||
loginSuccess() {
|
||||
if (this.isResetPassword) {
|
||||
this.$tab.reLaunch('/pages/index')
|
||||
} else {
|
||||
this.$tab.reLaunch('/pages/mine/pwd/index')
|
||||
}
|
||||
},
|
||||
// 微信一键登录
|
||||
wxLogin(detail) {
|
||||
this.onGetPhoneNumber(detail).then(res => {
|
||||
this.loginSuccess()
|
||||
})
|
||||
},
|
||||
// 密码登录
|
||||
async pwdLogin() {
|
||||
this.$store.dispatch('auth/Login', this.loginForm).then(() => {
|
||||
this.$modal.closeLoading()
|
||||
this.loginSuccess()
|
||||
})
|
||||
},
|
||||
// 登录成功后,处理函数
|
||||
loginSuccess() {
|
||||
if (this.isResetPassword) {
|
||||
this.$tab.reLaunch('/pages/index')
|
||||
} else {
|
||||
this.$tab.reLaunch('/pages/mine/pwd/index')
|
||||
}
|
||||
},
|
||||
// 微信一键登录
|
||||
wxLogin(detail) {
|
||||
this.onGetPhoneNumber(detail).then((res) => {
|
||||
this.loginSuccess()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.normal-login-container {
|
||||
.normal-login-container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
|
||||
.logo-content {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
font-size: 21px;
|
||||
text-align: center;
|
||||
padding-top: 15%;
|
||||
|
||||
.logo-content {
|
||||
width: 100%;
|
||||
font-size: 21px;
|
||||
text-align: center;
|
||||
padding-top: 15%;
|
||||
|
||||
image {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 10px;
|
||||
}
|
||||
image {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.login-form-content {
|
||||
text-align: center;
|
||||
.title {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-form-content {
|
||||
text-align: center;
|
||||
margin: 20px auto;
|
||||
margin-top: 15%;
|
||||
width: 80%;
|
||||
|
||||
.input-item {
|
||||
margin: 20px auto;
|
||||
margin-top: 15%;
|
||||
width: 80%;
|
||||
|
||||
.input-item {
|
||||
margin: 20px auto;
|
||||
background-color: #f5f6f7;
|
||||
height: 45px;
|
||||
border-radius: 20px;
|
||||
|
||||
.icon {
|
||||
font-size: 38rpx;
|
||||
margin-left: 10px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
padding-left: 15px;
|
||||
}
|
||||
background-color: #f5f6f7;
|
||||
height: 45px;
|
||||
border-radius: 20px;
|
||||
|
||||
.icon {
|
||||
font-size: 38rpx;
|
||||
margin-left: 10px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
margin-top: 40px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.xieyi {
|
||||
color: #333;
|
||||
margin-top: 20px;
|
||||
.input {
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.easyinput {
|
||||
width: 100%;
|
||||
.login-btn {
|
||||
margin-top: 40px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.xieyi {
|
||||
color: #333;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin: 20px auto;
|
||||
width: 80%;
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
left: 10%;
|
||||
}
|
||||
}
|
||||
|
||||
.login-code-img {
|
||||
height: 45px;
|
||||
.easyinput {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin: 20px auto;
|
||||
width: 80%;
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
left: 10%;
|
||||
}
|
||||
}
|
||||
|
||||
.login-code-img {
|
||||
height: 45px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,8 +1,7 @@
|
||||
<template>
|
||||
<view class="about-container">
|
||||
<view class="header-section text-center">
|
||||
<image style="width: 150rpx;height: 150rpx;" :src="logoImage" mode="widthFix">
|
||||
</image>
|
||||
<image style="width: 150rpx; height: 150rpx" :src="logoImage" mode="widthFix"> </image>
|
||||
<uni-title type="h2" :title="title"></uni-title>
|
||||
</view>
|
||||
|
||||
@ -11,7 +10,7 @@
|
||||
<view class="list-cell list-cell-arrow">
|
||||
<view class="menu-item-box">
|
||||
<view>版本信息</view>
|
||||
<view class="text-right">v{{version}}</view>
|
||||
<view class="text-right">v{{ version }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="list-cell list-cell-arrow">
|
||||
@ -30,7 +29,7 @@
|
||||
<view class="menu-item-box">
|
||||
<view>公司网站</view>
|
||||
<view class="text-right">
|
||||
<uni-link :href="siteUrl" :text="siteUrl" showUnderLine="false"></uni-link>
|
||||
<uni-link :href="siteUrl" :text="siteUrl" show-under-line="false"></uni-link>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -44,52 +43,52 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
version() {
|
||||
return this.$store.state.app.version
|
||||
},
|
||||
computed: {
|
||||
version() {
|
||||
return this.$store.state.app.version
|
||||
},
|
||||
title() {
|
||||
return this.$store.state.app.title
|
||||
},
|
||||
logoImage() {
|
||||
return this.$store.state.app.logoImage
|
||||
},
|
||||
siteUrl() {
|
||||
return this.$store.state.app.siteUrl
|
||||
},
|
||||
WXEmail() {
|
||||
return this.$store.state.app.WXEmail
|
||||
},
|
||||
WXPhone() {
|
||||
return this.$store.state.app.WXPhone
|
||||
},
|
||||
footerContent() {
|
||||
return this.$store.state.app.footerContent
|
||||
}
|
||||
},
|
||||
title() {
|
||||
return this.$store.state.app.title
|
||||
},
|
||||
logoImage() {
|
||||
return this.$store.state.app.logoImage
|
||||
},
|
||||
siteUrl() {
|
||||
return this.$store.state.app.siteUrl
|
||||
},
|
||||
WXEmail() {
|
||||
return this.$store.state.app.WXEmail
|
||||
},
|
||||
WXPhone() {
|
||||
return this.$store.state.app.WXPhone
|
||||
},
|
||||
footerContent() {
|
||||
return this.$store.state.app.footerContent
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
margin-top: 50rpx;
|
||||
text-align: center;
|
||||
line-height: 60rpx;
|
||||
color: #999;
|
||||
}
|
||||
.copyright {
|
||||
margin-top: 50rpx;
|
||||
text-align: center;
|
||||
line-height: 60rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.header-section {
|
||||
display: flex;
|
||||
padding: 30rpx 0 0;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.header-section {
|
||||
display: flex;
|
||||
padding: 30rpx 0 0;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,10 +5,15 @@
|
||||
<view>{{ item.name }}</view>
|
||||
</view>
|
||||
<view class="childList">
|
||||
<view v-for="(issue, zindex) in item.issues" :key="zindex" class="question" hover-class="hover"
|
||||
@click="handleText(issue)">
|
||||
<view
|
||||
v-for="(issue, zindex) in item.issues"
|
||||
:key="zindex"
|
||||
class="question"
|
||||
hover-class="hover"
|
||||
@click="handleText(issue)"
|
||||
>
|
||||
<view class="text-item">{{ issue.title }}</view>
|
||||
<view class="line" v-if="zindex !== item.issues.length - 1"></view>
|
||||
<view v-if="zindex !== item.issues.length - 1" class="line"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -16,68 +21,68 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getIssueCategoryList } from '@/common/request/api/vadmin/help/issue.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
getIssueCategoryList().then(res => {
|
||||
this.list = res.data
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleText(item) {
|
||||
this.$tab.navigateTo(`/pages/mine/help/issue/info?id=${item.id}`)
|
||||
}
|
||||
import { getIssueCategoryList } from '@/common/request/api/vadmin/help/issue.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
getIssueCategoryList().then((res) => {
|
||||
this.list = res.data
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleText(item) {
|
||||
this.$tab.navigateTo(`/pages/mine/help/issue/info?id=${item.id}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.help-container {
|
||||
margin-bottom: 100rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
.help-container {
|
||||
margin-bottom: 100rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.list-title {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.childList {
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 0px 10rpx rgba(193, 193, 193, 0.2);
|
||||
border-radius: 16rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
.childList {
|
||||
background: #ffffff;
|
||||
box-shadow: 0px 0px 10rpx rgba(193, 193, 193, 0.2);
|
||||
border-radius: 16rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 100%;
|
||||
height: 1rpx;
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
.line {
|
||||
width: 100%;
|
||||
height: 1rpx;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.text-title {
|
||||
color: #303133;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
.text-title {
|
||||
color: #303133;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.text-item {
|
||||
font-size: 28rpx;
|
||||
padding: 24rpx;
|
||||
}
|
||||
.text-item {
|
||||
font-size: 28rpx;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.question {
|
||||
color: #606266;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.question {
|
||||
color: #606266;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,70 +1,71 @@
|
||||
<template>
|
||||
<view>
|
||||
<uni-card v-if="isSuccess" class="view-title" :title="model.title">
|
||||
<uni-card v-if="isSuccess" class="view-title">
|
||||
<u--text :text="model.title" bold></u--text>
|
||||
<rich-text class="uni-body view-content" :nodes="model.content"></rich-text>
|
||||
</uni-card>
|
||||
<u-empty
|
||||
v-else
|
||||
mode="data"
|
||||
icon="https://cdn.uviewui.com/uview/empty/data.png"
|
||||
:marginTop="100"
|
||||
:width="300"
|
||||
:height="300"
|
||||
>
|
||||
</u-empty>
|
||||
<u-empty
|
||||
v-else
|
||||
mode="data"
|
||||
icon="https://cdn.uviewui.com/uview/empty/data.png"
|
||||
:margin-top="100"
|
||||
:width="300"
|
||||
:height="300"
|
||||
>
|
||||
</u-empty>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getIssue, updateIssueAddViewNumber } from '@/common/request/api/vadmin/help/issue.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isSuccess: true,
|
||||
model: {},
|
||||
dataId: null
|
||||
import { getIssue, updateIssueAddViewNumber } from '@/common/request/api/vadmin/help/issue.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isSuccess: true,
|
||||
model: {},
|
||||
dataId: null
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.query) {
|
||||
this.dataId = options.query.id
|
||||
} else if (options) {
|
||||
this.dataId = options.id
|
||||
}
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
if (!this.dataId) {
|
||||
return
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.query) {
|
||||
this.dataId = options.query.id
|
||||
} else if (options) {
|
||||
this.dataId = options.id
|
||||
}
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
getData() {
|
||||
if (!this.dataId) { return; }
|
||||
getIssue(this.dataId).then(res => {
|
||||
this.model = res.data;
|
||||
uni.setNavigationBarTitle({
|
||||
title: res.data.title
|
||||
})
|
||||
updateIssueAddViewNumber(this.dataId)
|
||||
}).catch(() => {
|
||||
this.isSuccess = false
|
||||
})
|
||||
}
|
||||
}
|
||||
getIssue(this.dataId)
|
||||
.then((res) => {
|
||||
this.model = res.data
|
||||
uni.setNavigationBarTitle({
|
||||
title: res.data.title
|
||||
})
|
||||
updateIssueAddViewNumber(this.dataId)
|
||||
})
|
||||
.catch(() => {
|
||||
this.isSuccess = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.view-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.view-content {
|
||||
font-size: 26rpx;
|
||||
padding: 12px 5px 0;
|
||||
color: #333;
|
||||
line-height: 24px;
|
||||
font-weight: normal;
|
||||
}
|
||||
.view-content {
|
||||
font-size: 26rpx;
|
||||
padding: 12px 5px 0;
|
||||
color: #333;
|
||||
line-height: 24px;
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="mine-container" :style="{height: `${windowHeight}px`}">
|
||||
<view class="mine-container" :style="{ height: `${windowHeight}px` }">
|
||||
<!--顶部个人信息栏-->
|
||||
<view class="header-section">
|
||||
<view class="flex padding justify-between">
|
||||
@ -7,19 +7,23 @@
|
||||
<view v-if="!avatar" class="cu-avatar xl round bg-white">
|
||||
<view class="iconfont icon-people text-gray icon"></view>
|
||||
</view>
|
||||
<image v-if="avatar" @click="handleToAvatar" :src="avatar" class="cu-avatar xl round" mode="aspectFill">
|
||||
<image
|
||||
v-if="avatar"
|
||||
:src="avatar"
|
||||
class="cu-avatar xl round"
|
||||
mode="aspectFill"
|
||||
@click="handleToAvatar"
|
||||
>
|
||||
</image>
|
||||
<view v-if="!name" @click="handleToLogin" class="login-tip">
|
||||
点击登录
|
||||
</view>
|
||||
<view v-if="name" @click="handleToInfo" class="user-info">
|
||||
<view v-if="!name" class="login-tip" @click="handleToLogin"> 点击登录 </view>
|
||||
<view v-if="name" class="user-info" @click="handleToInfo">
|
||||
<view class="u_title">
|
||||
{{ name }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view @click="handleToInfo" class="flex align-center">
|
||||
<text style="font-size: 30rpx;">个人信息</text>
|
||||
<view class="flex align-center" @click="handleToInfo">
|
||||
<text style="font-size: 30rpx">个人信息</text>
|
||||
<view class="iconfont icon-right1"></view>
|
||||
</view>
|
||||
</view>
|
||||
@ -41,7 +45,9 @@
|
||||
</view>
|
||||
<view class="action-item" @click="praiseMe">
|
||||
<view class="iconfont icon-dianzan text-green icon"></view>
|
||||
<view style="height: 0px;" :animation="animationData" class="praise-me animation-opacity"> +1 </view>
|
||||
<view style="height: 0px" :animation="animationData" class="praise-me animation-opacity">
|
||||
+1
|
||||
</view>
|
||||
<text class="text">点赞我们</text>
|
||||
</view>
|
||||
</view>
|
||||
@ -72,171 +78,167 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import storage from '@/common/utils/storage'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
animation: "",
|
||||
animationData: {}
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 1 在页面创建的时候,创建一个临时动画对象
|
||||
this.animation = uni.createAnimation();
|
||||
this.animationData = {};
|
||||
},
|
||||
onUnload() {
|
||||
// 5 页面卸载的时候,清除动画数据
|
||||
this.animationData = {};
|
||||
},
|
||||
computed: {
|
||||
version() {
|
||||
return this.$store.state.app.version
|
||||
},
|
||||
name() {
|
||||
return this.$store.state.auth.name
|
||||
},
|
||||
avatar() {
|
||||
return this.$store.state.auth.avatar
|
||||
},
|
||||
windowHeight() {
|
||||
return uni.getSystemInfoSync().windowHeight - 50
|
||||
}
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
animation: '',
|
||||
animationData: {}
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// 1 在页面创建的时候,创建一个临时动画对象
|
||||
this.animation = uni.createAnimation()
|
||||
this.animationData = {}
|
||||
},
|
||||
onUnload() {
|
||||
// 5 页面卸载的时候,清除动画数据
|
||||
this.animationData = {}
|
||||
},
|
||||
computed: {
|
||||
version() {
|
||||
return this.$store.state.app.version
|
||||
},
|
||||
methods: {
|
||||
handleToInfo() {
|
||||
this.$tab.navigateTo('/pages/mine/info/index')
|
||||
},
|
||||
handleToEditInfo() {
|
||||
this.$tab.navigateTo('/pages/mine/info/edit')
|
||||
},
|
||||
handleToSetting() {
|
||||
this.$tab.navigateTo('/pages/mine/setting/index')
|
||||
},
|
||||
handleToLogin() {
|
||||
this.$tab.reLaunch('/pages/login/login')
|
||||
},
|
||||
handleToAvatar() {
|
||||
this.$tab.navigateTo('/pages/mine/avatar/index')
|
||||
},
|
||||
handleLogout() {
|
||||
this.$modal.confirm('确定注销并退出系统吗?').then(() => {
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
this.$tab.reLaunch('/pages/index')
|
||||
})
|
||||
name() {
|
||||
return this.$store.state.auth.name
|
||||
},
|
||||
avatar() {
|
||||
return this.$store.state.auth.avatar
|
||||
},
|
||||
windowHeight() {
|
||||
return uni.getSystemInfoSync().windowHeight - 50
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleToInfo() {
|
||||
this.$tab.navigateTo('/pages/mine/info/index')
|
||||
},
|
||||
handleToEditInfo() {
|
||||
this.$tab.navigateTo('/pages/mine/info/edit')
|
||||
},
|
||||
handleToSetting() {
|
||||
this.$tab.navigateTo('/pages/mine/setting/index')
|
||||
},
|
||||
handleToLogin() {
|
||||
this.$tab.reLaunch('/pages/login/login')
|
||||
},
|
||||
handleToAvatar() {
|
||||
this.$tab.navigateTo('/pages/mine/avatar/index')
|
||||
},
|
||||
handleLogout() {
|
||||
this.$modal.confirm('确定注销并退出系统吗?').then(() => {
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
this.$tab.reLaunch('/pages/index')
|
||||
})
|
||||
},
|
||||
handleHelp() {
|
||||
this.$tab.navigateTo('/pages/mine/help/issue/index')
|
||||
},
|
||||
handleAbout() {
|
||||
this.$tab.navigateTo('/pages/mine/about/index')
|
||||
},
|
||||
handleJiaoLiuQun() {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
},
|
||||
handleBuilding() {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
},
|
||||
// 实现点赞动画效果
|
||||
praiseMe() {
|
||||
// 2 调用 step() 来表示一组动画完成
|
||||
this.animation.translateY(-90).opacity(1).step({
|
||||
duration: 400
|
||||
});
|
||||
|
||||
// 3 通过动画实例的export方法导出动画数据传递给组件的animation属性
|
||||
this.animationData = this.animation.export();
|
||||
|
||||
// 4 还原动画
|
||||
setTimeout(()=> {
|
||||
this.animation.translateY(0).opacity(0).step({
|
||||
duration: 0
|
||||
});
|
||||
this.animationData = this.animation.export();
|
||||
}, 300)
|
||||
},
|
||||
})
|
||||
},
|
||||
handleHelp() {
|
||||
this.$tab.navigateTo('/pages/mine/help/issue/index')
|
||||
},
|
||||
handleAbout() {
|
||||
this.$tab.navigateTo('/pages/mine/about/index')
|
||||
},
|
||||
handleJiaoLiuQun() {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
},
|
||||
handleBuilding() {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
},
|
||||
// 实现点赞动画效果
|
||||
praiseMe() {
|
||||
// 2 调用 step() 来表示一组动画完成
|
||||
this.animation.translateY(-90).opacity(1).step({
|
||||
duration: 400
|
||||
})
|
||||
|
||||
// 3 通过动画实例的export方法导出动画数据传递给组件的animation属性
|
||||
this.animationData = this.animation.export()
|
||||
|
||||
// 4 还原动画
|
||||
setTimeout(() => {
|
||||
this.animation.translateY(0).opacity(0).step({
|
||||
duration: 0
|
||||
})
|
||||
this.animationData = this.animation.export()
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.praise-me {
|
||||
font-size: 14px;
|
||||
color: #feab2a;
|
||||
}
|
||||
|
||||
.animation-opacity {
|
||||
font-weight: bold;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
page {
|
||||
background-color: #f5f6f7;
|
||||
.praise-me {
|
||||
font-size: 14px;
|
||||
color: #feab2a;
|
||||
}
|
||||
|
||||
.animation-opacity {
|
||||
font-weight: bold;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
page {
|
||||
background-color: #f5f6f7;
|
||||
}
|
||||
|
||||
.mine-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.header-section {
|
||||
padding: 15px 15px 45px 15px;
|
||||
background-color: #3c96f3;
|
||||
color: white;
|
||||
|
||||
.login-tip {
|
||||
font-size: 18px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.cu-avatar {
|
||||
border: 2px solid #eaeaea;
|
||||
|
||||
.icon {
|
||||
font-size: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-info {
|
||||
margin-left: 15px;
|
||||
|
||||
.u_title {
|
||||
font-size: 37rpx;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mine-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.content-section {
|
||||
position: relative;
|
||||
top: -50px;
|
||||
|
||||
.mine-actions {
|
||||
margin: 15px 15px;
|
||||
padding: 20px 0px;
|
||||
border-radius: 8px;
|
||||
background-color: white;
|
||||
|
||||
.header-section {
|
||||
padding: 15px 15px 45px 15px;
|
||||
background-color: #3c96f3;
|
||||
color: white;
|
||||
|
||||
.login-tip {
|
||||
font-size: 18px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.cu-avatar {
|
||||
border: 2px solid #eaeaea;
|
||||
|
||||
.action-item {
|
||||
.icon {
|
||||
font-size: 40px;
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-info {
|
||||
margin-left: 15px;
|
||||
|
||||
.u_title {
|
||||
font-size: 37rpx;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-section {
|
||||
position: relative;
|
||||
top: -50px;
|
||||
|
||||
.mine-actions {
|
||||
margin: 15px 15px;
|
||||
padding: 20px 0px;
|
||||
border-radius: 8px;
|
||||
background-color: white;
|
||||
|
||||
.action-item {
|
||||
.icon {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.text {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
margin: 8px 0px;
|
||||
}
|
||||
.text {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
margin: 8px 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,168 +1,128 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view style="padding: 20px;">
|
||||
<u--form
|
||||
labelPosition="left"
|
||||
labelWidth="100px"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
>
|
||||
<u-form-item
|
||||
label="用户姓名"
|
||||
prop="name"
|
||||
borderBottom
|
||||
:required="true"
|
||||
>
|
||||
<u--input
|
||||
v-model="form.name"
|
||||
placeholder="请输入用户姓名"
|
||||
border="none"
|
||||
></u--input>
|
||||
</u-form-item>
|
||||
<u-form-item
|
||||
label="用户昵称"
|
||||
prop="nickname"
|
||||
borderBottom
|
||||
:required="false"
|
||||
>
|
||||
<u--input
|
||||
v-model="form.nickname"
|
||||
placeholder="请输入用户昵称"
|
||||
border="none"
|
||||
></u--input>
|
||||
</u-form-item>
|
||||
<u-form-item
|
||||
label="手机号码"
|
||||
prop="telephone"
|
||||
borderBottom
|
||||
:required="true"
|
||||
>
|
||||
<u--input
|
||||
v-model="form.telephone"
|
||||
placeholder="请输入手机号码"
|
||||
border="none"
|
||||
></u--input>
|
||||
</u-form-item>
|
||||
<u-form-item
|
||||
label="用户性别"
|
||||
prop="gender"
|
||||
borderBottom
|
||||
:required="false"
|
||||
>
|
||||
<u-radio-group v-model="form.gender">
|
||||
<u-radio
|
||||
:customStyle="{marginRight: '16px'}"
|
||||
v-for="(item, index) in genderOptions"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:name="item.value"
|
||||
>
|
||||
</u-radio>
|
||||
</u-radio-group>
|
||||
</u-form-item>
|
||||
</u--form>
|
||||
<view style="margin-top: 20px;">
|
||||
<u-button
|
||||
:loading="btnLoading"
|
||||
type="primary"
|
||||
@click="submit"
|
||||
text="提交"
|
||||
>
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
<view style="padding: 20px">
|
||||
<u--form ref="formRef" label-position="left" label-width="100px" :model="form" :rules="rules">
|
||||
<u-form-item label="用户姓名" prop="name" border-bottom :required="true">
|
||||
<u--input v-model="form.name" placeholder="请输入用户姓名" border="none"></u--input>
|
||||
</u-form-item>
|
||||
<u-form-item label="用户昵称" prop="nickname" border-bottom :required="false">
|
||||
<u--input v-model="form.nickname" placeholder="请输入用户昵称" border="none"></u--input>
|
||||
</u-form-item>
|
||||
<u-form-item label="手机号码" prop="telephone" border-bottom :required="true">
|
||||
<u--input v-model="form.telephone" placeholder="请输入手机号码" border="none"></u--input>
|
||||
</u-form-item>
|
||||
<u-form-item label="用户性别" prop="gender" border-bottom :required="false">
|
||||
<u-radio-group v-model="form.gender">
|
||||
<u-radio
|
||||
v-for="(item, index) in genderOptions"
|
||||
:key="index"
|
||||
:custom-style="{ marginRight: '16px' }"
|
||||
:label="item.label"
|
||||
:name="item.value"
|
||||
>
|
||||
</u-radio>
|
||||
</u-radio-group>
|
||||
</u-form-item>
|
||||
</u--form>
|
||||
<view style="margin-top: 20px">
|
||||
<u-button :loading="btnLoading" type="primary" text="提交" @click="submit"> </u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getInfo } from '@/common/request/api/login'
|
||||
import { updateCurrentUser } from '@/common/request/api/vadmin/auth/user.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
btnLoading: false,
|
||||
form: {
|
||||
name: "",
|
||||
nickname: "",
|
||||
telephone: "",
|
||||
gender: ""
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
import { getInfo } from '@/common/request/api/login'
|
||||
import { updateCurrentUser } from '@/common/request/api/vadmin/auth/user.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
btnLoading: false,
|
||||
form: {
|
||||
name: '',
|
||||
nickname: '',
|
||||
telephone: '',
|
||||
gender: ''
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
message: '请填写姓名',
|
||||
trigger: ['blur', 'change']
|
||||
},
|
||||
telephone: [
|
||||
{
|
||||
type: 'string',
|
||||
required: true,
|
||||
message: '请填写姓名',
|
||||
message: '请填写正确手机号',
|
||||
trigger: ['blur', 'change']
|
||||
},
|
||||
telephone: [
|
||||
{
|
||||
type: 'string',
|
||||
required: true,
|
||||
message: '请填写正确手机号',
|
||||
trigger: ['blur', 'change']
|
||||
},
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
// 上面有说,返回true表示校验通过,返回false表示不通过
|
||||
// uni.$u.test.mobile()就是返回true或者false的
|
||||
return uni.$u.test.mobile(value);
|
||||
},
|
||||
message: '手机号码不正确',
|
||||
// 触发器可以同时用blur和change
|
||||
trigger: ['change','blur'],
|
||||
}
|
||||
]
|
||||
},
|
||||
genderOptions: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.$store.dispatch('dict/getDicts', ["sys_vadmin_gender"]).then(result => {
|
||||
this.genderOptions = result.sys_vadmin_gender
|
||||
})
|
||||
// this.resetForm()
|
||||
this.getUser()
|
||||
},
|
||||
onReady() {
|
||||
//onReady 为uni-app支持的生命周期之一
|
||||
this.$refs.formRef.setRules(this.rules)
|
||||
},
|
||||
methods: {
|
||||
resetForm() {
|
||||
this.form = {
|
||||
name: "",
|
||||
nickname: "",
|
||||
telephone: "",
|
||||
gender: ""
|
||||
}
|
||||
},
|
||||
getUser() {
|
||||
this.$modal.loading("加载中")
|
||||
getInfo().then(res => {
|
||||
this.form = res.data
|
||||
}).finally(() => {
|
||||
this.$modal.closeLoading()
|
||||
})
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
// 上面有说,返回true表示校验通过,返回false表示不通过
|
||||
// uni.$u.test.mobile()就是返回true或者false的
|
||||
return uni.$u.test.mobile(value)
|
||||
},
|
||||
message: '手机号码不正确',
|
||||
// 触发器可以同时用blur和change
|
||||
trigger: ['change', 'blur']
|
||||
}
|
||||
]
|
||||
},
|
||||
submit(ref) {
|
||||
this.$refs.formRef.validate().then(res => {
|
||||
this.btnLoading = true
|
||||
updateCurrentUser(this.form).then(res => {
|
||||
this.$store.dispatch('auth/UpdateInfo', res.data)
|
||||
this.$modal.msgSuccess("更新成功");
|
||||
}).finally(() => {
|
||||
this.btnLoading = false
|
||||
})
|
||||
})
|
||||
genderOptions: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.$store.dispatch('dict/getDicts', ['sys_vadmin_gender']).then((result) => {
|
||||
this.genderOptions = result.sys_vadmin_gender
|
||||
})
|
||||
// this.resetForm()
|
||||
this.getUser()
|
||||
},
|
||||
onReady() {
|
||||
//onReady 为uni-app支持的生命周期之一
|
||||
this.$refs.formRef.setRules(this.rules)
|
||||
},
|
||||
methods: {
|
||||
resetForm() {
|
||||
this.form = {
|
||||
name: '',
|
||||
nickname: '',
|
||||
telephone: '',
|
||||
gender: ''
|
||||
}
|
||||
},
|
||||
getUser() {
|
||||
this.$modal.loading('加载中')
|
||||
getInfo()
|
||||
.then((res) => {
|
||||
this.form = res.data
|
||||
})
|
||||
.finally(() => {
|
||||
this.$modal.closeLoading()
|
||||
})
|
||||
},
|
||||
submit(ref) {
|
||||
this.$refs.formRef.validate().then((res) => {
|
||||
this.btnLoading = true
|
||||
updateCurrentUser(this.form)
|
||||
.then((res) => {
|
||||
this.$store.dispatch('auth/UpdateInfo', res.data)
|
||||
this.$modal.msgSuccess('更新成功')
|
||||
})
|
||||
.finally(() => {
|
||||
this.btnLoading = false
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,49 +1,49 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<u-cell-group>
|
||||
<u-cell title="姓名" :value="name">
|
||||
<u-icon slot="icon" class="iconfont icon-user"></u-icon>
|
||||
</u-cell>
|
||||
<u-cell title="昵称" :value="nickname">
|
||||
<u-icon slot="icon" class="iconfont icon-user"></u-icon>
|
||||
</u-cell>
|
||||
<u-cell title="手机号码" :value="telephone">
|
||||
<u-icon slot="icon" class="iconfont icon-dianhua"></u-icon>
|
||||
</u-cell>
|
||||
<u-cell title="角色" :value="roles.join(',')">
|
||||
<u-icon slot="icon" class="iconfont icon-xitongjiaose"></u-icon>
|
||||
</u-cell>
|
||||
<u-cell title="创建日期" :value="createDatetime">
|
||||
<u-icon slot="icon" class="iconfont icon-jiaofuriqi"></u-icon>
|
||||
</u-cell>
|
||||
</u-cell-group>
|
||||
<u-cell-group>
|
||||
<u-cell title="姓名" :value="name">
|
||||
<u-icon slot="icon" class="iconfont icon-user"></u-icon>
|
||||
</u-cell>
|
||||
<u-cell title="昵称" :value="nickname">
|
||||
<u-icon slot="icon" class="iconfont icon-user"></u-icon>
|
||||
</u-cell>
|
||||
<u-cell title="手机号码" :value="telephone">
|
||||
<u-icon slot="icon" class="iconfont icon-dianhua"></u-icon>
|
||||
</u-cell>
|
||||
<u-cell title="角色" :value="roles.join(',')">
|
||||
<u-icon slot="icon" class="iconfont icon-xitongjiaose"></u-icon>
|
||||
</u-cell>
|
||||
<u-cell title="创建日期" :value="createDatetime">
|
||||
<u-icon slot="icon" class="iconfont icon-jiaofuriqi"></u-icon>
|
||||
</u-cell>
|
||||
</u-cell-group>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
computed: {
|
||||
name() {
|
||||
return this.$store.state.auth.name
|
||||
},
|
||||
nickname() {
|
||||
return this.$store.state.auth.nickname
|
||||
},
|
||||
telephone() {
|
||||
return this.$store.state.auth.telephone
|
||||
},
|
||||
roles() {
|
||||
return this.$store.state.auth.roles
|
||||
},
|
||||
createDatetime() {
|
||||
return this.$store.state.auth.createDatetime
|
||||
}
|
||||
},
|
||||
export default {
|
||||
computed: {
|
||||
name() {
|
||||
return this.$store.state.auth.name
|
||||
},
|
||||
nickname() {
|
||||
return this.$store.state.auth.nickname
|
||||
},
|
||||
telephone() {
|
||||
return this.$store.state.auth.telephone
|
||||
},
|
||||
roles() {
|
||||
return this.$store.state.auth.roles
|
||||
},
|
||||
createDatetime() {
|
||||
return this.$store.state.auth.createDatetime
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,104 +1,87 @@
|
||||
<template>
|
||||
<view class="pwd-retrieve-container">
|
||||
<view class="header">
|
||||
<u--text
|
||||
v-if="!isResetPassword"
|
||||
text="第一次进入系统,必须先重置密码。"
|
||||
:size="33"
|
||||
align="center"
|
||||
>
|
||||
</u--text>
|
||||
</view>
|
||||
<uni-forms ref="form" :value="form" labelWidth="80px">
|
||||
<uni-forms ref="form" :value="form" label-width="80px">
|
||||
<uni-forms-item name="newPassword" label="新密码">
|
||||
<uni-easyinput type="password" v-model="form.password" placeholder="请输入新密码" />
|
||||
<uni-easyinput v-model="form.password" type="password" placeholder="请输入新密码" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item name="confirmPassword" label="确认密码">
|
||||
<uni-easyinput type="password" v-model="form.password_two" placeholder="请确认新密码" />
|
||||
<uni-easyinput v-model="form.password_two" type="password" placeholder="请确认新密码" />
|
||||
</uni-forms-item>
|
||||
<u-button text="提交" @click="submit" type="primary"></u-button>
|
||||
<u-button text="提交" color="#e09bc7" @click="submit"></u-button>
|
||||
</uni-forms>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { postCurrentUserResetPassword } from '@/common/request/api/vadmin/auth/user.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
password: undefined,
|
||||
password_two: undefined
|
||||
import { postCurrentUserResetPassword } from '@/common/request/api/vadmin/auth/user.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
password: undefined,
|
||||
password_two: undefined
|
||||
},
|
||||
rules: {
|
||||
password: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
errorMessage: '新密码不能为空'
|
||||
},
|
||||
{
|
||||
minLength: 8,
|
||||
maxLength: 20,
|
||||
errorMessage: '长度在 8 到 20 个字符'
|
||||
}
|
||||
]
|
||||
},
|
||||
rules: {
|
||||
password: {
|
||||
rules: [{
|
||||
required: true,
|
||||
errorMessage: '新密码不能为空',
|
||||
},
|
||||
{
|
||||
minLength: 8,
|
||||
maxLength: 20,
|
||||
errorMessage: '长度在 8 到 20 个字符'
|
||||
}
|
||||
]
|
||||
},
|
||||
password_two: {
|
||||
rules: [{
|
||||
required: true,
|
||||
errorMessage: '确认密码不能为空'
|
||||
}, {
|
||||
validateFunction: (rule, value, data) => data.password === value,
|
||||
errorMessage: '两次输入的密码不一致'
|
||||
}
|
||||
]
|
||||
}
|
||||
password_two: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
errorMessage: '确认密码不能为空'
|
||||
},
|
||||
{
|
||||
validateFunction: (rule, value, data) => data.password === value,
|
||||
errorMessage: '两次输入的密码不一致'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isResetPassword() {
|
||||
return this.$store.state.auth.isResetPassword
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
this.$refs.form.setRules(this.rules)
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
this.$refs.form.validate().then(res => {
|
||||
this.$modal.loading("正在提交")
|
||||
postCurrentUserResetPassword(this.form).then(response => {
|
||||
this.form = {
|
||||
password: "",
|
||||
password_two: ""
|
||||
}
|
||||
this.$modal.msgSuccess("重置成功")
|
||||
if (!this.isResetPassword) {
|
||||
this.$store.commit('auth/SET_IS_RESET_PASSWORD', true)
|
||||
this.$tab.reLaunch('/pages/index')
|
||||
}
|
||||
}).finally(() => {
|
||||
this.$modal.closeLoading()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
this.$refs.form.setRules(this.rules)
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
this.$refs.form.validate().then((res) => {
|
||||
this.$modal.loading('正在提交')
|
||||
postCurrentUserResetPassword(this.form)
|
||||
.then((response) => {
|
||||
this.form = {
|
||||
password: '',
|
||||
password_two: ''
|
||||
}
|
||||
this.$modal.msgSuccess('修改成功')
|
||||
})
|
||||
.finally(() => {
|
||||
this.$modal.closeLoading()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
page {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.pwd-retrieve-container {
|
||||
padding-top: 36rpx;
|
||||
padding: 15px;
|
||||
|
||||
.header {
|
||||
padding-bottom: 36rpx;
|
||||
}
|
||||
}
|
||||
.pwd-retrieve-container {
|
||||
padding-top: 36rpx;
|
||||
padding: 15px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="setting-container" :style="{height: `${windowHeight}px`}">
|
||||
<view class="setting-container" :style="{ height: `${windowHeight}px` }">
|
||||
<view class="menu-list">
|
||||
<view class="list-cell list-cell-arrow" @click="handleToPwd">
|
||||
<view class="menu-item-box">
|
||||
@ -31,46 +31,46 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
windowHeight: uni.getSystemInfoSync().windowHeight
|
||||
}
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
windowHeight: uni.getSystemInfoSync().windowHeight
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleToPwd() {
|
||||
this.$tab.navigateTo('/pages/mine/pwd/index')
|
||||
},
|
||||
methods: {
|
||||
handleToPwd() {
|
||||
this.$tab.navigateTo('/pages/mine/pwd/index')
|
||||
},
|
||||
handleToUpgrade() {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
},
|
||||
handleCleanTmp() {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
},
|
||||
handleLogout() {
|
||||
this.$modal.confirm('确定注销并退出系统吗?').then(() => {
|
||||
this.$store.dispatch('auth/LogOut')
|
||||
})
|
||||
}
|
||||
handleToUpgrade() {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
},
|
||||
handleCleanTmp() {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
},
|
||||
handleLogout() {
|
||||
this.$modal.confirm('确定注销并退出系统吗?').then(() => {
|
||||
this.$store.dispatch('auth/LogOut')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
.page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.item-box {
|
||||
background-color: #FFFFFF;
|
||||
margin: 30rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10rpx;
|
||||
border-radius: 8rpx;
|
||||
color: #303133;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
.item-box {
|
||||
background-color: #ffffff;
|
||||
margin: 30rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 10rpx;
|
||||
border-radius: 8rpx;
|
||||
color: #303133;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
</style>
|
||||
|
@ -2,99 +2,92 @@
|
||||
<view class="work-container">
|
||||
<!-- 轮播图 -->
|
||||
<u-swiper
|
||||
:list="images"
|
||||
indicator
|
||||
indicatorMode="line"
|
||||
circular
|
||||
:height="`${windowWidth / 2.5}px`"
|
||||
></u-swiper>
|
||||
:list="images"
|
||||
indicator
|
||||
indicator-mode="line"
|
||||
circular
|
||||
:height="`${windowWidth / 2.5}px`"
|
||||
></u-swiper>
|
||||
|
||||
<!-- 宫格组件 -->
|
||||
<view class="grid-body">
|
||||
<u-grid
|
||||
:border="false"
|
||||
col="3"
|
||||
@click="changeGrid"
|
||||
>
|
||||
<u-grid-item
|
||||
v-for="(item, index) in baseList"
|
||||
:key="index"
|
||||
>
|
||||
<view class="grid-item">
|
||||
<view :class="'iconfont ' + item.icon + ' grid-icon'"></view>
|
||||
<u--text :text="item.title" align="center" lineHeight="32px"></u--text>
|
||||
</view>
|
||||
</u-grid-item>
|
||||
</u-grid>
|
||||
<u-grid :border="false" col="3" @click="changeGrid">
|
||||
<u-grid-item v-for="(item, index) in baseList" :key="index">
|
||||
<view class="grid-item">
|
||||
<view :class="'iconfont ' + item.icon + ' grid-icon'"></view>
|
||||
<u--text :text="item.title" align="center" line-height="32px"></u--text>
|
||||
</view>
|
||||
</u-grid-item>
|
||||
</u-grid>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
windowWidth: uni.getSystemInfoSync().windowWidth,
|
||||
images: [
|
||||
'https://ktianc.oss-cn-beijing.aliyuncs.com/kinit/system/banner/2022-11-14/1.jpg',
|
||||
'/static/images/banner/banner03.jpg',
|
||||
'/static/images/banner/banner03.jpg'
|
||||
],
|
||||
baseList: [
|
||||
{
|
||||
icon: 'icon-user1',
|
||||
title: '用户管理'
|
||||
},
|
||||
{
|
||||
icon: 'icon-users',
|
||||
title: '角色管理'
|
||||
},
|
||||
{
|
||||
icon: 'icon-caidan3',
|
||||
title: '菜单管理'
|
||||
},
|
||||
{
|
||||
icon: 'icon-shezhitianchong',
|
||||
title: '系统配置'
|
||||
},
|
||||
{
|
||||
icon: 'icon-changguizidian',
|
||||
title: '字典管理'
|
||||
},
|
||||
{
|
||||
icon: 'icon-rizhi',
|
||||
title: '日志管理'
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeGrid(e) {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
}
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
windowWidth: uni.getSystemInfoSync().windowWidth,
|
||||
images: [
|
||||
'https://ktianc.oss-cn-beijing.aliyuncs.com/kinit/system/banner/2022-11-14/1.jpg',
|
||||
'/static/images/banner/banner03.jpg',
|
||||
'/static/images/banner/banner03.jpg'
|
||||
],
|
||||
baseList: [
|
||||
{
|
||||
icon: 'icon-user1',
|
||||
title: '用户管理'
|
||||
},
|
||||
{
|
||||
icon: 'icon-users',
|
||||
title: '角色管理'
|
||||
},
|
||||
{
|
||||
icon: 'icon-caidan3',
|
||||
title: '菜单管理'
|
||||
},
|
||||
{
|
||||
icon: 'icon-shezhitianchong',
|
||||
title: '系统配置'
|
||||
},
|
||||
{
|
||||
icon: 'icon-changguizidian',
|
||||
title: '字典管理'
|
||||
},
|
||||
{
|
||||
icon: 'icon-rizhi',
|
||||
title: '日志管理'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeGrid(e) {
|
||||
this.$modal.showToast('模块建设中~')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #fff;
|
||||
min-height: 100%;
|
||||
height: auto;
|
||||
}
|
||||
page {
|
||||
background-color: #fff;
|
||||
min-height: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.grid-body {
|
||||
margin-top: 60rpx;
|
||||
|
||||
.grid-item {
|
||||
margin-bottom: 30rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.grid-icon {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
}
|
||||
.grid-body {
|
||||
margin-top: 60rpx;
|
||||
|
||||
.grid-item {
|
||||
margin-bottom: 30rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.grid-icon {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,54 +1,60 @@
|
||||
import { getToken } from '@/common/utils/auth'
|
||||
import store from '@/store'
|
||||
import { RouterMount, createRouter } from 'uni-simple-router';
|
||||
import { RouterMount, createRouter } from 'uni-simple-router'
|
||||
|
||||
// uni-simple-router 官方文档:https://www.hhyang.cn/v2/start/cross/codeRoute.html
|
||||
|
||||
// 登录页面
|
||||
const loginPage = "/pages/login/login"
|
||||
const loginPage = '/pages/login/login'
|
||||
// 首页
|
||||
const indexPage = '/pages/index'
|
||||
|
||||
const router = createRouter({
|
||||
platform: process.env.VUE_APP_PLATFORM,
|
||||
routes: [...ROUTES]
|
||||
});
|
||||
platform: process.env.VUE_APP_PLATFORM,
|
||||
detectBeforeLock: (router, to, navType) => {
|
||||
if (navType === 'replaceAll' && (to.path === loginPage || to.path === indexPage)) {
|
||||
router.$lockStatus = false // 取消跳转锁
|
||||
}
|
||||
},
|
||||
routes: [...ROUTES] // ROUTES是通过webpack的defaultPlugin编译成全局变量
|
||||
})
|
||||
|
||||
//全局路由前置守卫
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.meta.loginAuth) {
|
||||
// 如果跳转的路由需要登录权限,则验证该权限
|
||||
if (getToken()) {
|
||||
if (!store.state.auth.isUser) {
|
||||
store.dispatch('auth/GetInfo')
|
||||
}
|
||||
if (to.path === loginPage) {
|
||||
next({
|
||||
path: `/pages/index`,
|
||||
NAVTYPE: 'replaceAll'
|
||||
})
|
||||
}
|
||||
next();
|
||||
} else {
|
||||
next({
|
||||
path: loginPage,
|
||||
NAVTYPE: 'replaceAll'
|
||||
})
|
||||
}
|
||||
} else if (to.path === loginPage && getToken()) {
|
||||
// 如果跳转路由为登录页面并且存在token,则跳转到首页
|
||||
next({
|
||||
path: `/pages/index`,
|
||||
if (to.meta.loginAuth) {
|
||||
// 如果跳转的路由需要登录权限,则验证该权限
|
||||
if (getToken()) {
|
||||
if (!store.state.auth.isUser) {
|
||||
store.dispatch('auth/GetInfo')
|
||||
}
|
||||
if (to.path === loginPage) {
|
||||
next({
|
||||
path: indexPage,
|
||||
NAVTYPE: 'replaceAll'
|
||||
})
|
||||
}
|
||||
next()
|
||||
} else {
|
||||
next({
|
||||
path: loginPage,
|
||||
NAVTYPE: 'replaceAll'
|
||||
})
|
||||
}
|
||||
} else if (to.path === loginPage && getToken()) {
|
||||
// 如果跳转路由为登录页面并且存在token,则跳转到首页
|
||||
next({
|
||||
path: indexPage,
|
||||
NAVTYPE: 'replaceAll'
|
||||
})
|
||||
} else {
|
||||
// 不需要权限,且不是登录页面则不进行验证
|
||||
next();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 不需要权限,且不是登录页面则不进行验证
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
// 全局路由后置守卫
|
||||
router.afterEach((to, from) => {
|
||||
// console.log('跳转结束')
|
||||
// console.log('跳转结束')
|
||||
})
|
||||
|
||||
export {
|
||||
router,
|
||||
RouterMount
|
||||
}
|
||||
export { router, RouterMount }
|
||||
|
@ -1,10 +1,10 @@
|
||||
import store from '@/store'
|
||||
|
||||
function authPermission(permission) {
|
||||
const all_permission = "*:*:*"
|
||||
const all_permission = '*:*:*'
|
||||
const permissions = store.getters && store.getters.permissions
|
||||
if (permission && permission.length > 0) {
|
||||
return permissions.some(v => {
|
||||
return permissions.some((v) => {
|
||||
return all_permission === v || v === permission
|
||||
})
|
||||
} else {
|
||||
@ -13,10 +13,10 @@ function authPermission(permission) {
|
||||
}
|
||||
|
||||
function authRole(role) {
|
||||
const super_admin = "admin"
|
||||
const super_admin = 'admin'
|
||||
const roles = store.getters && store.getters.roles
|
||||
if (role && role.length > 0) {
|
||||
return roles.some(v => {
|
||||
return roles.some((v) => {
|
||||
return super_admin === v || v === role
|
||||
})
|
||||
} else {
|
||||
@ -31,13 +31,13 @@ export default {
|
||||
},
|
||||
// 验证用户是否含有指定权限,只需包含其中一个
|
||||
hasPermiOr(permissions) {
|
||||
return permissions.some(item => {
|
||||
return permissions.some((item) => {
|
||||
return authPermission(item)
|
||||
})
|
||||
},
|
||||
// 验证用户是否含有指定权限,必须全部拥有
|
||||
hasPermiAnd(permissions) {
|
||||
return permissions.every(item => {
|
||||
return permissions.every((item) => {
|
||||
return authPermission(item)
|
||||
})
|
||||
},
|
||||
@ -47,13 +47,13 @@ export default {
|
||||
},
|
||||
// 验证用户是否含有指定角色,只需包含其中一个
|
||||
hasRoleOr(roles) {
|
||||
return roles.some(item => {
|
||||
return roles.some((item) => {
|
||||
return authRole(item)
|
||||
})
|
||||
},
|
||||
// 验证用户是否含有指定角色,必须全部拥有
|
||||
hasRoleAnd(roles) {
|
||||
return roles.every(item => {
|
||||
return roles.every((item) => {
|
||||
return authRole(item)
|
||||
})
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ export default {
|
||||
content: content,
|
||||
cancelText: '取消',
|
||||
confirmText: '确定',
|
||||
success: function(res) {
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
resolve(res.confirm)
|
||||
}
|
||||
@ -50,12 +50,12 @@ export default {
|
||||
},
|
||||
// 提示信息
|
||||
showToast(option) {
|
||||
if (typeof option === "object") {
|
||||
if (typeof option === 'object') {
|
||||
uni.showToast(option)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: option,
|
||||
icon: "none",
|
||||
icon: 'none',
|
||||
duration: 2500
|
||||
})
|
||||
}
|
||||
|
19
kinit-uni/prettier.config.js
Normal file
19
kinit-uni/prettier.config.js
Normal file
@ -0,0 +1,19 @@
|
||||
module.exports = {
|
||||
printWidth: 100,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
semi: false,
|
||||
vueIndentScriptAndStyle: false,
|
||||
singleQuote: true,
|
||||
quoteProps: 'as-needed',
|
||||
bracketSpacing: true,
|
||||
trailingComma: 'none',
|
||||
jsxSingleQuote: false,
|
||||
arrowParens: 'always',
|
||||
insertPragma: false,
|
||||
requirePragma: false,
|
||||
proseWrap: 'never',
|
||||
htmlWhitespaceSensitivity: 'strict',
|
||||
endOfLine: 'auto',
|
||||
rangeStart: 0
|
||||
}
|
@ -1,26 +1,26 @@
|
||||
const getters = {
|
||||
isUser: state => state.auth.isUser,
|
||||
isUserOpenid: state => state.auth.isUserOpenid,
|
||||
isResetPassword: state => state.auth.isResetPassword,
|
||||
token: state => state.auth.token,
|
||||
avatar: state => state.auth.avatar,
|
||||
name: state => state.auth.name,
|
||||
roles: state => state.auth.roles,
|
||||
permissions: state => state.auth.permissions,
|
||||
telephone: state => state.auth.telephone,
|
||||
|
||||
version: state => state.app.version,
|
||||
title: state => state.app.title,
|
||||
logo: state => state.app.logo,
|
||||
logoImage: state => state.app.logoImage,
|
||||
footer: state => state.app.footer,
|
||||
footerContent: state => state.app.footerContent,
|
||||
icpNumber: state => state.app.icpNumber,
|
||||
privacy: state => state.app.privacy,
|
||||
agreement: state => state.app.agreement,
|
||||
siteUrl: state => state.app.siteUrl,
|
||||
WXEmail: state => state.app.WXEmail,
|
||||
WXPhone: state => state.app.WXPhone,
|
||||
dictObj: state => state.dict.dictObj,
|
||||
isUser: (state) => state.auth.isUser,
|
||||
isUserOpenid: (state) => state.auth.isUserOpenid,
|
||||
isResetPassword: (state) => state.auth.isResetPassword,
|
||||
token: (state) => state.auth.token,
|
||||
avatar: (state) => state.auth.avatar,
|
||||
name: (state) => state.auth.name,
|
||||
roles: (state) => state.auth.roles,
|
||||
permissions: (state) => state.auth.permissions,
|
||||
telephone: (state) => state.auth.telephone,
|
||||
|
||||
version: (state) => state.app.version,
|
||||
title: (state) => state.app.title,
|
||||
logo: (state) => state.app.logo,
|
||||
logoImage: (state) => state.app.logoImage,
|
||||
footer: (state) => state.app.footer,
|
||||
footerContent: (state) => state.app.footerContent,
|
||||
icpNumber: (state) => state.app.icpNumber,
|
||||
privacy: (state) => state.app.privacy,
|
||||
agreement: (state) => state.app.agreement,
|
||||
siteUrl: (state) => state.app.siteUrl,
|
||||
WXEmail: (state) => state.app.WXEmail,
|
||||
WXPhone: (state) => state.app.WXPhone,
|
||||
dictObj: (state) => state.dict.dictObj
|
||||
}
|
||||
export default getters
|
||||
|
@ -21,5 +21,5 @@ const store = new Vuex.Store({
|
||||
modules,
|
||||
getters
|
||||
})
|
||||
|
||||
export default store
|
||||
|
||||
export default store
|
||||
|
@ -2,76 +2,77 @@ import config from '@/config.js'
|
||||
import { getSystemBaseConfigApi } from '@/common/request/api/vadmin/system/settings.js'
|
||||
|
||||
const state = {
|
||||
title: "", // 标题
|
||||
logo: true, // 是否开启logo显示
|
||||
logoImage: '', // logo图片
|
||||
footer: true, // 显示页脚
|
||||
footerContent: '', // 页脚内容
|
||||
icpNumber: '', // 备案号
|
||||
version: config.appInfo.version, // 版本
|
||||
privacy: config.appInfo.privacy, // 隐私政策
|
||||
agreement: config.appInfo.agreement, // 用户协议
|
||||
siteUrl: "", // 源码地址
|
||||
WXEmail: "", // 官方邮箱
|
||||
WXPhone: "" // 服务热线
|
||||
title: '', // 标题
|
||||
logo: true, // 是否开启logo显示
|
||||
logoImage: '', // logo图片
|
||||
footer: true, // 显示页脚
|
||||
footerContent: '', // 页脚内容
|
||||
icpNumber: '', // 备案号
|
||||
version: config.appInfo.version, // 版本
|
||||
privacy: config.appInfo.privacy, // 隐私政策
|
||||
agreement: config.appInfo.agreement, // 用户协议
|
||||
siteUrl: '', // 源码地址
|
||||
WXEmail: '', // 官方邮箱
|
||||
WXPhone: '' // 服务热线
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
SET_TITLE: (state, title) => {
|
||||
state.title = title
|
||||
},
|
||||
SET_LOGO: (state, logo) => {
|
||||
state.logo = logo
|
||||
},
|
||||
SET_LOGO_IMAGE: (state, logoImage) => {
|
||||
state.logoImage = logoImage
|
||||
},
|
||||
SET_FOOTER: (state, footer) => {
|
||||
state.footer = footer
|
||||
},
|
||||
SET_FOOTER_CONTENT: (state, footerContent) => {
|
||||
state.footerContent = footerContent
|
||||
},
|
||||
SET_ICPNUMBER: (state, icpNumber) => {
|
||||
state.icpNumber = icpNumber
|
||||
},
|
||||
SET_VERSION: (state, version) => {
|
||||
state.version = version
|
||||
},
|
||||
SET_SITE_URL: (state, siteUrl) => {
|
||||
state.siteUrl = siteUrl
|
||||
},
|
||||
SET_WX_EMAIL: (state, WXEmail) => {
|
||||
state.WXEmail = WXEmail
|
||||
},
|
||||
SET_WX_PHONE: (state, WXPhone) => {
|
||||
state.WXPhone = WXPhone
|
||||
},
|
||||
SET_TITLE: (state, title) => {
|
||||
state.title = title
|
||||
},
|
||||
SET_LOGO: (state, logo) => {
|
||||
state.logo = logo
|
||||
},
|
||||
SET_LOGO_IMAGE: (state, logoImage) => {
|
||||
state.logoImage = logoImage
|
||||
},
|
||||
SET_FOOTER: (state, footer) => {
|
||||
state.footer = footer
|
||||
},
|
||||
SET_FOOTER_CONTENT: (state, footerContent) => {
|
||||
state.footerContent = footerContent
|
||||
},
|
||||
SET_ICPNUMBER: (state, icpNumber) => {
|
||||
state.icpNumber = icpNumber
|
||||
},
|
||||
SET_VERSION: (state, version) => {
|
||||
state.version = version
|
||||
},
|
||||
SET_SITE_URL: (state, siteUrl) => {
|
||||
state.siteUrl = siteUrl
|
||||
},
|
||||
SET_WX_EMAIL: (state, WXEmail) => {
|
||||
state.WXEmail = WXEmail
|
||||
},
|
||||
SET_WX_PHONE: (state, WXPhone) => {
|
||||
state.WXPhone = WXPhone
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
// 初始化系统配置
|
||||
InitConfig({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getSystemBaseConfigApi().then(res => {
|
||||
commit('SET_TITLE', res.data.web_title || 'Kinit')
|
||||
commit('SET_LOGO_IMAGE', config.baseUrl + (res.data.web_logo || '/media/system/logo.png'))
|
||||
commit('SET_FOOTER_CONTENT', res.data.web_copyright || 'Copyright ©2022-present K')
|
||||
commit('SET_ICPNUMBER', res.data.web_icp_number || '')
|
||||
commit('SET_SITE_URL', res.data.wx_server_site || '')
|
||||
commit('SET_WX_EMAIL', res.data.wx_server_email || '')
|
||||
commit('SET_WX_PHONE', res.data.wx_server_phone || '')
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
// 初始化系统配置
|
||||
InitConfig({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getSystemBaseConfigApi()
|
||||
.then((res) => {
|
||||
commit('SET_TITLE', res.data.web_title || 'Kinit')
|
||||
commit('SET_LOGO_IMAGE', config.baseUrl + (res.data.web_logo || '/media/system/logo.png'))
|
||||
commit('SET_FOOTER_CONTENT', res.data.web_copyright || 'Copyright ©2022-present K')
|
||||
commit('SET_ICPNUMBER', res.data.web_icp_number || '')
|
||||
commit('SET_SITE_URL', res.data.wx_server_site || '')
|
||||
commit('SET_WX_EMAIL', res.data.wx_server_email || '')
|
||||
commit('SET_WX_PHONE', res.data.wx_server_phone || '')
|
||||
resolve()
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
namespaced: true, // 使用命名空间去访问模块中属性,user/login
|
||||
namespaced: true, // 使用命名空间去访问模块中属性,user/login
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
|
@ -1,164 +1,192 @@
|
||||
import storage from '@/common/utils/storage'
|
||||
import { auth } from '@/common/utils/constant'
|
||||
import { getInfo, wxCodeLogin, login } from '@/common/request/api/login'
|
||||
import { getToken, setToken, removeToken } from '@/common/utils/auth'
|
||||
import {
|
||||
getToken,
|
||||
setToken,
|
||||
removeToken,
|
||||
getRefreshToken,
|
||||
setRefreshToken,
|
||||
removeRefreshToken
|
||||
} from '@/common/utils/auth'
|
||||
|
||||
const state = {
|
||||
token: getToken(),
|
||||
isUser: storage.get(auth.isUser) || false,
|
||||
isUserOpenid: storage.get(auth.isUserOpenid) || false,
|
||||
isResetPassword: storage.get(auth.isResetPassword) || false,
|
||||
name: storage.get(auth.name),
|
||||
nickname: storage.get(auth.nickname),
|
||||
gender: storage.get(auth.gender),
|
||||
telephone: storage.get(auth.telephone),
|
||||
avatar: storage.get(auth.avatar),
|
||||
createDatetime: storage.get(auth.createDatetime),
|
||||
roles: storage.get(auth.roles),
|
||||
permissions: storage.get(auth.permissions)
|
||||
token: getToken(),
|
||||
refreshToken: getRefreshToken(),
|
||||
isUser: storage.get(auth.isUser) || false,
|
||||
isUserOpenid: storage.get(auth.isUserOpenid) || false,
|
||||
isResetPassword: storage.get(auth.isResetPassword) || false,
|
||||
name: storage.get(auth.name),
|
||||
nickname: storage.get(auth.nickname),
|
||||
gender: storage.get(auth.gender),
|
||||
telephone: storage.get(auth.telephone),
|
||||
avatar: storage.get(auth.avatar),
|
||||
createDatetime: storage.get(auth.createDatetime),
|
||||
roles: storage.get(auth.roles),
|
||||
permissions: storage.get(auth.permissions)
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_IS_USER_OPENID: (state, isUserOpenid) => {
|
||||
state.isUserOpenid = isUserOpenid
|
||||
storage.set(auth.isUserOpenid, isUserOpenid)
|
||||
},
|
||||
SET_IS_RESET_PASSWORD: (state, isResetPassword) => {
|
||||
state.isResetPassword = isResetPassword
|
||||
storage.set(auth.isResetPassword, isResetPassword)
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name
|
||||
storage.set(auth.name, name)
|
||||
},
|
||||
SET_GENDER: (state, gender) => {
|
||||
state.gender = gender
|
||||
storage.set(auth.gender, gender)
|
||||
},
|
||||
SET_NICKNAME: (state, nickname) => {
|
||||
state.nickname = nickname
|
||||
storage.set(auth.nickname, nickname)
|
||||
},
|
||||
SET_CREATE_DATETIME: (state, createDatetime) => {
|
||||
state.createDatetime = createDatetime
|
||||
storage.set(auth.createDatetime, createDatetime)
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar
|
||||
storage.set(auth.avatar, avatar)
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles
|
||||
storage.set(auth.roles, roles)
|
||||
},
|
||||
SET_PERMISSIONS: (state, permissions) => {
|
||||
state.permissions = permissions
|
||||
storage.set(auth.permissions, permissions)
|
||||
},
|
||||
SET_TELEPHONE: (state, telephone) => {
|
||||
state.telephone = telephone
|
||||
storage.set(auth.telephone, telephone)
|
||||
},
|
||||
SET_ISUSER: (state, isUser) => {
|
||||
state.isUser = isUser
|
||||
storage.set(auth.isUser, isUser)
|
||||
},
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_REFRESH_TOKEN: (state, refreshToken) => {
|
||||
state.refreshToken = refreshToken
|
||||
setRefreshToken(refreshToken)
|
||||
},
|
||||
SET_IS_USER_OPENID: (state, isUserOpenid) => {
|
||||
state.isUserOpenid = isUserOpenid
|
||||
storage.set(auth.isUserOpenid, isUserOpenid)
|
||||
},
|
||||
SET_IS_RESET_PASSWORD: (state, isResetPassword) => {
|
||||
state.isResetPassword = isResetPassword
|
||||
storage.set(auth.isResetPassword, isResetPassword)
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name
|
||||
storage.set(auth.name, name)
|
||||
},
|
||||
SET_GENDER: (state, gender) => {
|
||||
state.gender = gender
|
||||
storage.set(auth.gender, gender)
|
||||
},
|
||||
SET_NICKNAME: (state, nickname) => {
|
||||
state.nickname = nickname
|
||||
storage.set(auth.nickname, nickname)
|
||||
},
|
||||
SET_CREATE_DATETIME: (state, createDatetime) => {
|
||||
state.createDatetime = createDatetime
|
||||
storage.set(auth.createDatetime, createDatetime)
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar
|
||||
storage.set(auth.avatar, avatar)
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles
|
||||
storage.set(auth.roles, roles)
|
||||
},
|
||||
SET_PERMISSIONS: (state, permissions) => {
|
||||
state.permissions = permissions
|
||||
storage.set(auth.permissions, permissions)
|
||||
},
|
||||
SET_TELEPHONE: (state, telephone) => {
|
||||
state.telephone = telephone
|
||||
storage.set(auth.telephone, telephone)
|
||||
},
|
||||
SET_ISUSER: (state, isUser) => {
|
||||
state.isUser = isUser
|
||||
storage.set(auth.isUser, isUser)
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
// 手机号密码登录
|
||||
Login({ commit }, userInfo) {
|
||||
const telephone = userInfo.telephone.trim()
|
||||
const password = userInfo.password
|
||||
return new Promise((resolve, reject) => {
|
||||
login(telephone, password).then(res => {
|
||||
setToken(`${res.data.token_type} ${res.data.access_token}`)
|
||||
commit('SET_TOKEN', `${res.data.token_type} ${res.data.access_token}`)
|
||||
commit('SET_IS_USER_OPENID', res.data.is_wx_server_openid)
|
||||
commit('SET_IS_RESET_PASSWORD', res.data.is_reset_password)
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 微信一键登录
|
||||
// 微信文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html
|
||||
wxLogin({ commit }, code) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wxCodeLogin(code).then(res => {
|
||||
setToken(`${res.data.token_type} ${res.data.access_token}`)
|
||||
commit('SET_TOKEN', `${res.data.token_type} ${res.data.access_token}`)
|
||||
commit('SET_IS_USER_OPENID', res.data.is_wx_server_openid)
|
||||
commit('SET_IS_RESET_PASSWORD', res.data.is_reset_password)
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 手机号密码登录
|
||||
Login({ commit }, userInfo) {
|
||||
const telephone = userInfo.telephone.trim()
|
||||
const password = userInfo.password
|
||||
return new Promise((resolve, reject) => {
|
||||
login(telephone, password)
|
||||
.then((res) => {
|
||||
setToken(`${res.data.token_type} ${res.data.access_token}`)
|
||||
commit('SET_TOKEN', `${res.data.token_type} ${res.data.access_token}`)
|
||||
commit('SET_REFRESH_TOKEN', res.data.refresh_token)
|
||||
commit('SET_IS_USER_OPENID', res.data.is_wx_server_openid)
|
||||
commit('SET_IS_RESET_PASSWORD', res.data.is_reset_password)
|
||||
resolve(res)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
GetInfo({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo().then(res => {
|
||||
const user = res.data
|
||||
const avatar = (user == null || user.avatar == "" || user.avatar == null) ? "https://vv-reserve.oss-cn-hangzhou.aliyuncs.com/avatar/2023-01-27/1674820804e81e7631.png" : user.avatar
|
||||
const name = (user == null || user.name == "" || user.name == null) ? "" : user.name
|
||||
commit('SET_ROLES', user.roles.map((item) => item.name) || ['ROLE_DEFAULT'])
|
||||
commit('SET_PERMISSIONS', user.permissions)
|
||||
commit('SET_NAME', name)
|
||||
commit('SET_NICKNAME', user.nickname)
|
||||
commit('SET_GENDER', user.gender)
|
||||
commit('SET_TELEPHONE', user.telephone)
|
||||
commit('SET_AVATAR', avatar)
|
||||
commit('SET_CREATE_DATETIME', user.create_datetime)
|
||||
commit('SET_ISUSER', true)
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 更新用户基本信息
|
||||
UpdateInfo({ commit }, user) {
|
||||
commit('SET_NAME', user.name)
|
||||
commit('SET_NICKNAME', user.nickname)
|
||||
commit('SET_GENDER', user.gender)
|
||||
commit('SET_TELEPHONE', user.telephone)
|
||||
},
|
||||
// 微信一键登录
|
||||
// 微信文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html
|
||||
wxLogin({ commit }, code) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wxCodeLogin(code)
|
||||
.then((res) => {
|
||||
setToken(`${res.data.token_type} ${res.data.access_token}`)
|
||||
commit('SET_TOKEN', `${res.data.token_type} ${res.data.access_token}`)
|
||||
commit('SET_REFRESH_TOKEN', res.data.refresh_token)
|
||||
commit('SET_IS_USER_OPENID', res.data.is_wx_server_openid)
|
||||
commit('SET_IS_RESET_PASSWORD', res.data.is_reset_password)
|
||||
resolve(res)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 退出系统
|
||||
LogOut({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_PERMISSIONS', [])
|
||||
commit('SET_NAME', "")
|
||||
commit('SET_NICKNAME', "")
|
||||
commit('SET_GENDER', "")
|
||||
commit('SET_TELEPHONE', "")
|
||||
commit('SET_AVATAR', "")
|
||||
commit('SET_CREATE_DATETIME', "")
|
||||
commit('SET_IS_USER_OPENID', false)
|
||||
commit('SET_IS_RESET_PASSWORD', false)
|
||||
commit('SET_ISUSER', false)
|
||||
removeToken()
|
||||
storage.clean()
|
||||
uni.reLaunch({ url: '/pages/login/login' })
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
// 获取用户信息
|
||||
GetInfo({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo()
|
||||
.then((res) => {
|
||||
const user = res.data
|
||||
const avatar =
|
||||
user == null || user.avatar == '' || user.avatar == null
|
||||
? 'https://vv-reserve.oss-cn-hangzhou.aliyuncs.com/avatar/2023-01-27/1674820804e81e7631.png'
|
||||
: user.avatar
|
||||
const name = user == null || user.name == '' || user.name == null ? '' : user.name
|
||||
commit('SET_ROLES', user.roles.map((item) => item.name) || ['ROLE_DEFAULT'])
|
||||
commit('SET_PERMISSIONS', user.permissions)
|
||||
commit('SET_NAME', name)
|
||||
commit('SET_NICKNAME', user.nickname)
|
||||
commit('SET_GENDER', user.gender)
|
||||
commit('SET_TELEPHONE', user.telephone)
|
||||
commit('SET_AVATAR', avatar)
|
||||
commit('SET_CREATE_DATETIME', user.create_datetime)
|
||||
commit('SET_ISUSER', true)
|
||||
resolve(res)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 更新用户基本信息
|
||||
UpdateInfo({ commit }, user) {
|
||||
commit('SET_NAME', user.name)
|
||||
commit('SET_NICKNAME', user.nickname)
|
||||
commit('SET_GENDER', user.gender)
|
||||
commit('SET_TELEPHONE', user.telephone)
|
||||
},
|
||||
|
||||
// 退出系统
|
||||
LogOut({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_REFRESH_TOKEN', '')
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_PERMISSIONS', [])
|
||||
commit('SET_NAME', '')
|
||||
commit('SET_NICKNAME', '')
|
||||
commit('SET_GENDER', '')
|
||||
commit('SET_TELEPHONE', '')
|
||||
commit('SET_AVATAR', '')
|
||||
commit('SET_CREATE_DATETIME', '')
|
||||
commit('SET_IS_USER_OPENID', false)
|
||||
commit('SET_IS_RESET_PASSWORD', false)
|
||||
commit('SET_ISUSER', false)
|
||||
removeToken()
|
||||
removeRefreshToken()
|
||||
storage.clean()
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/login',
|
||||
complete: () => {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
namespaced: true, // 使用命名空间去访问模块中属性,user/login
|
||||
namespaced: true, // 使用命名空间去访问模块中属性,user/login
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
|
@ -1,51 +1,52 @@
|
||||
import { getDictTypeDetailsApi } from '@/common/request/api/vadmin/system/dict.js'
|
||||
|
||||
const state = {
|
||||
dictObj: {}, // 字典元素
|
||||
dictObj: {} // 字典元素
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
SET_DICT_OBJ: (state, dictObj) => {
|
||||
state.dictObj = dictObj
|
||||
}
|
||||
SET_DICT_OBJ: (state, dictObj) => {
|
||||
state.dictObj = dictObj
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
// 获取字典选项
|
||||
getDicts({ commit, state }, dictTypes) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const result = {}
|
||||
const addList = []
|
||||
const dictObj = JSON.parse(JSON.stringify(state.dictObj))
|
||||
for (const item of dictTypes) {
|
||||
if (item in dictObj) {
|
||||
result[item] = dictObj[item]
|
||||
} else {
|
||||
result[item] = []
|
||||
addList.push(item)
|
||||
}
|
||||
}
|
||||
if (addList.length > 0) {
|
||||
getDictTypeDetailsApi(addList).then(res => {
|
||||
for (const item of addList) {
|
||||
result[item] = res.data[item]
|
||||
dictObj[item] = res.data[item]
|
||||
}
|
||||
commit('SET_DICT_OBJ', dictObj)
|
||||
resolve(result)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
} else {
|
||||
resolve(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 获取字典选项
|
||||
getDicts({ commit, state }, dictTypes) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const result = {}
|
||||
const addList = []
|
||||
const dictObj = JSON.parse(JSON.stringify(state.dictObj))
|
||||
for (const item of dictTypes) {
|
||||
if (item in dictObj) {
|
||||
result[item] = dictObj[item]
|
||||
} else {
|
||||
result[item] = []
|
||||
addList.push(item)
|
||||
}
|
||||
}
|
||||
if (addList.length > 0) {
|
||||
getDictTypeDetailsApi(addList)
|
||||
.then((res) => {
|
||||
for (const item of addList) {
|
||||
result[item] = res.data[item]
|
||||
dictObj[item] = res.data[item]
|
||||
}
|
||||
commit('SET_DICT_OBJ', dictObj)
|
||||
resolve(result)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
} else {
|
||||
resolve(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
namespaced: true, // 使用命名空间去访问模块中属性,user/login
|
||||
namespaced: true, // 使用命名空间去访问模块中属性,user/login
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
|
@ -1,26 +1,26 @@
|
||||
//vue.config.js
|
||||
const TransformPages = require('uni-read-pages')
|
||||
const {webpack} = new TransformPages()
|
||||
const { webpack } = new TransformPages()
|
||||
|
||||
module.exports = {
|
||||
configureWebpack: {
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
ROUTES: webpack.DefinePlugin.runtimeValue(() => {
|
||||
const tfPages = new TransformPages({
|
||||
// includes 中包含的是router会读取pages路由中的字段名
|
||||
// 后续如果有用到meta等路由信息,可以在 includes 里增加 'meta',
|
||||
// 在pages路由中写对应的数据,router中就可以获取得到
|
||||
includes: ['path', 'name', 'aliasPath', 'meta']
|
||||
});
|
||||
return JSON.stringify(tfPages.routes)
|
||||
}, true )
|
||||
})
|
||||
]
|
||||
},
|
||||
configureWebpack: {
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
ROUTES: webpack.DefinePlugin.runtimeValue(() => {
|
||||
const tfPages = new TransformPages({
|
||||
// includes 中包含的是router会读取pages路由中的字段名
|
||||
// 后续如果有用到meta等路由信息,可以在 includes 里增加 'meta',
|
||||
// 在pages路由中写对应的数据,router中就可以获取得到
|
||||
includes: ['path', 'name', 'aliasPath', 'meta']
|
||||
})
|
||||
return JSON.stringify(tfPages.routes)
|
||||
}, true)
|
||||
})
|
||||
]
|
||||
},
|
||||
devServer: {
|
||||
port: 8080,
|
||||
https: false,
|
||||
disableHostCheck: true // 禁止访问本地host文件
|
||||
port: 8080,
|
||||
https: false,
|
||||
disableHostCheck: true // 禁止访问本地host文件
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user