版本升级:
1. 修复(kinit-api):utils/cache.py 日志模块导入问题修复 2. 修复(kinit-api):token解析失败会报错问题修复 3. 优化(kinit-api):用户登录认证失败返回值优化 4. 优化(kinit-api):获取redis方式统一改为redis_getter(request) 5. 优化(kini-api):文件IO修改为异步操作 6. 优化(kinit-api):关联创建人时将user_id改为create_user_id 7. 文档(kinit-api):kinit-api/README.md 加入查询数据文档 8. 修复(kinit-admin):用户无法导出问题修复 9. 优化(kinit-admin):角色新增与编辑框使用默认父子联动 10. 更新(kinit-admin):usePermissionStore 改为 useRouterStoreWithOut,因为此文件主要记录路由 11. 更新(kinit-admin):取消用户信息的持久化存储,改为仅保存在pinia store共享中,并添加roles,permissions信息 12. 修复(kinit-admin):菜单新增与编辑框,目录与菜单切换时会出现抖动问题修复 13. 优化(kinit-admin):src\hooks\web\useTable.ts 优化删除数据方法 14. 优化(kinit-admin):config/services.ts 新增返回403状态码时直接退出系统 15. 优化(kinit-admin):将store中的本文件使用store调用的,改为this 16. 更新(kinit-admin):路由拦截更新 17. 更新(kinit-api,kinit-admin,kinit-uni):取消接口地址最后面的 /
This commit is contained in:
parent
71dc166516
commit
c65ff06918
@ -7,17 +7,17 @@ import type {
|
||||
} from './types'
|
||||
|
||||
export const getBannersApi = (): Promise<IResponse<AnalysisBannersTypes[]>> => {
|
||||
return request.get({ url: '/vadmin/analysis/banners/' })
|
||||
return request.get({ url: '/vadmin/analysis/banners' })
|
||||
}
|
||||
|
||||
export const getUserAccessSourceApi = (): Promise<IResponse<UserAccessSource[]>> => {
|
||||
return request.get({ url: '/vadmin/analysis/user/access/source/' })
|
||||
return request.get({ url: '/vadmin/analysis/user/access/source' })
|
||||
}
|
||||
|
||||
export const getWeeklyUserActivityApi = (): Promise<IResponse<WeeklyUserActivity[]>> => {
|
||||
return request.get({ url: '/vadmin/analysis/weekly/user/activity/' })
|
||||
return request.get({ url: '/vadmin/analysis/weekly/user/activity' })
|
||||
}
|
||||
|
||||
export const getMonthlySalesApi = (): Promise<IResponse<MonthlySales[]>> => {
|
||||
return request.get({ url: '/vadmin/analysis/monthly/sales/' })
|
||||
return request.get({ url: '/vadmin/analysis/monthly/sales' })
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export const getUserLoginDistributeApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/record/analysis/user/login/distribute/' })
|
||||
return request.get({ url: '/vadmin/record/analysis/user/login/distribute' })
|
||||
}
|
||||
|
@ -2,25 +2,25 @@ import request from '@/config/axios'
|
||||
import type { WorkplaceTotal, Project, Dynamic, Team, RadarData, Shortcuts } from './types'
|
||||
|
||||
export const getCountApi = (): Promise<IResponse<WorkplaceTotal>> => {
|
||||
return request.get({ url: '/vadmin/workplace/total/' })
|
||||
return request.get({ url: '/vadmin/workplace/total' })
|
||||
}
|
||||
|
||||
export const getProjectApi = (): Promise<IResponse<Project>> => {
|
||||
return request.get({ url: '/vadmin/workplace/project/' })
|
||||
return request.get({ url: '/vadmin/workplace/project' })
|
||||
}
|
||||
|
||||
export const getDynamicApi = (): Promise<IResponse<Dynamic[]>> => {
|
||||
return request.get({ url: '/vadmin/workplace/dynamic/' })
|
||||
return request.get({ url: '/vadmin/workplace/dynamic' })
|
||||
}
|
||||
|
||||
export const getTeamApi = (): Promise<IResponse<Team[]>> => {
|
||||
return request.get({ url: '/vadmin/workplace/team/' })
|
||||
return request.get({ url: '/vadmin/workplace/team' })
|
||||
}
|
||||
|
||||
export const getRadarApi = (): Promise<IResponse<RadarData[]>> => {
|
||||
return request.get({ url: '/vadmin/workplace/radar/' })
|
||||
return request.get({ url: '/vadmin/workplace/radar' })
|
||||
}
|
||||
|
||||
export const getShortcutsApi = (): Promise<IResponse<Shortcuts[]>> => {
|
||||
return request.get({ url: '/vadmin/workplace/shortcuts/' })
|
||||
return request.get({ url: '/vadmin/workplace/shortcuts' })
|
||||
}
|
||||
|
@ -2,13 +2,13 @@ import request from '@/config/axios'
|
||||
import type { UserLoginType } from './types'
|
||||
|
||||
export const loginApi = (data: UserLoginType): Promise<IResponse> => {
|
||||
return request.post({ url: '/auth/login/', data })
|
||||
return request.post({ url: '/auth/login', data })
|
||||
}
|
||||
|
||||
export const getRoleMenusApi = (): Promise<IResponse<AppCustomRouteRecordRaw[]>> => {
|
||||
return request.get({ url: '/auth/getMenuList/' })
|
||||
return request.get({ url: '/auth/getMenuList' })
|
||||
}
|
||||
|
||||
export const postSMSCodeApi = (params: any): Promise<IResponse> => {
|
||||
return request.post({ url: '/vadmin/system/sms/send/', params })
|
||||
return request.post({ url: '/vadmin/system/sms/send', params })
|
||||
}
|
||||
|
@ -2,25 +2,25 @@ import request from '@/config/axios'
|
||||
import { List } from 'echarts'
|
||||
|
||||
export const getMenuListApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/auth/menus/', params })
|
||||
return request.get({ url: '/vadmin/auth/menus', params })
|
||||
}
|
||||
|
||||
export const delMenuListApi = (data: List): Promise<IResponse> => {
|
||||
return request.delete({ url: '/vadmin/auth/menus/', data })
|
||||
return request.delete({ url: '/vadmin/auth/menus', data })
|
||||
}
|
||||
|
||||
export const addMenuListApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: '/vadmin/auth/menus/', data })
|
||||
return request.post({ url: '/vadmin/auth/menus', data })
|
||||
}
|
||||
|
||||
export const putMenuListApi = (data: any): Promise<IResponse> => {
|
||||
return request.put({ url: `/vadmin/auth/menus/${data.id}/`, data })
|
||||
return request.put({ url: `/vadmin/auth/menus/${data.id}`, data })
|
||||
}
|
||||
|
||||
export const getMenuTreeOptionsApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/auth/menus/tree/options/' })
|
||||
return request.get({ url: '/vadmin/auth/menus/tree/options' })
|
||||
}
|
||||
|
||||
export const getMenuRoleTreeOptionsApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/auth/menus/role/tree/options/' })
|
||||
return request.get({ url: '/vadmin/auth/menus/role/tree/options' })
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export const getRoleListApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/auth/roles/', params })
|
||||
return request.get({ url: '/vadmin/auth/roles', params })
|
||||
}
|
||||
|
||||
export const addRoleListApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: '/vadmin/auth/roles/', data })
|
||||
return request.post({ url: '/vadmin/auth/roles', data })
|
||||
}
|
||||
|
||||
export const delRoleListApi = (data: any): Promise<IResponse> => {
|
||||
return request.delete({ url: '/vadmin/auth/roles/', data })
|
||||
return request.delete({ url: '/vadmin/auth/roles', data })
|
||||
}
|
||||
|
||||
export const putRoleListApi = (data: any): Promise<IResponse> => {
|
||||
return request.put({ url: `/vadmin/auth/roles/${data.id}/`, data })
|
||||
return request.put({ url: `/vadmin/auth/roles/${data.id}`, data })
|
||||
}
|
||||
|
||||
export const getRoleApi = (dataId: number): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/auth/roles/${dataId}/` })
|
||||
return request.get({ url: `/vadmin/auth/roles/${dataId}` })
|
||||
}
|
||||
|
||||
export const getRoleOptionsApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/auth/roles/options/` })
|
||||
return request.get({ url: `/vadmin/auth/roles/options` })
|
||||
}
|
||||
|
@ -1,57 +1,57 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export const getUserListApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/auth/users/', params })
|
||||
return request.get({ url: '/vadmin/auth/users', params })
|
||||
}
|
||||
|
||||
export const addUserListApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: '/vadmin/auth/users/', data })
|
||||
return request.post({ url: '/vadmin/auth/users', data })
|
||||
}
|
||||
|
||||
export const delUserListApi = (data: any): Promise<IResponse> => {
|
||||
return request.delete({ url: '/vadmin/auth/users/', data })
|
||||
return request.delete({ url: '/vadmin/auth/users', data })
|
||||
}
|
||||
|
||||
export const putUserListApi = (data: any): Promise<IResponse> => {
|
||||
return request.put({ url: `/vadmin/auth/users/${data.id}/`, data })
|
||||
return request.put({ url: `/vadmin/auth/users/${data.id}`, data })
|
||||
}
|
||||
|
||||
export const getUserApi = (dataId: number): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/auth/users/${dataId}/` })
|
||||
return request.get({ url: `/vadmin/auth/users/${dataId}` })
|
||||
}
|
||||
|
||||
export const postCurrentUserResetPassword = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: `/vadmin/auth/user/current/reset/password/`, data })
|
||||
return request.post({ url: `/vadmin/auth/user/current/reset/password`, data })
|
||||
}
|
||||
|
||||
export const postCurrentUserUpdateInfo = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: `/vadmin/auth/user/current/update/info/`, data })
|
||||
return request.post({ url: `/vadmin/auth/user/current/update/info`, data })
|
||||
}
|
||||
|
||||
export const getCurrentAdminUserInfo = (): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/auth/user/admin/current/info/` })
|
||||
return request.get({ url: `/vadmin/auth/user/admin/current/info` })
|
||||
}
|
||||
|
||||
export const postExportUserQueryListApi = (params: any, data: any): Promise<IResponse> => {
|
||||
return request.post({ url: `/vadmin/auth/user/export/query/list/to/excel/`, params, data })
|
||||
return request.post({ url: `/vadmin/auth/user/export/query/list/to/excel`, params, data })
|
||||
}
|
||||
|
||||
export const getImportTemplateApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/auth/user/download/import/template/` })
|
||||
return request.get({ url: `/vadmin/auth/user/download/import/template` })
|
||||
}
|
||||
|
||||
export const postImportUserApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({
|
||||
url: `/vadmin/auth/import/users/`,
|
||||
url: `/vadmin/auth/import/users`,
|
||||
headersType: 'multipart/form-data',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const postUsersInitPasswordSendSMSApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: `/vadmin/auth/users/init/password/send/sms/`, data })
|
||||
return request.post({ url: `/vadmin/auth/users/init/password/send/sms`, data })
|
||||
}
|
||||
|
||||
export const postUsersInitPasswordSendEmailApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: `/vadmin/auth/users/init/password/send/email/`, data })
|
||||
return request.post({ url: `/vadmin/auth/users/init/password/send/email`, data })
|
||||
}
|
||||
|
@ -2,46 +2,46 @@ import request from '@/config/axios'
|
||||
|
||||
// 常见问题类别
|
||||
export const getIssueCategoryListApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/help/issue/categorys/', params })
|
||||
return request.get({ url: '/vadmin/help/issue/categorys', params })
|
||||
}
|
||||
|
||||
export const addIssueCategoryApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: '/vadmin/help/issue/categorys/', data })
|
||||
return request.post({ url: '/vadmin/help/issue/categorys', data })
|
||||
}
|
||||
|
||||
export const delIssueCategoryListApi = (data: any): Promise<IResponse> => {
|
||||
return request.delete({ url: '/vadmin/help/issue/categorys/', data })
|
||||
return request.delete({ url: '/vadmin/help/issue/categorys', data })
|
||||
}
|
||||
|
||||
export const putIssueCategoryApi = (data: any): Promise<IResponse> => {
|
||||
return request.put({ url: `/vadmin/help/issue/categorys/${data.id}/`, data })
|
||||
return request.put({ url: `/vadmin/help/issue/categorys/${data.id}`, data })
|
||||
}
|
||||
|
||||
export const getIssueCategoryApi = (dataId: number): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/help/issue/categorys/${dataId}/` })
|
||||
return request.get({ url: `/vadmin/help/issue/categorys/${dataId}` })
|
||||
}
|
||||
|
||||
export const getIssueCategoryOptionsApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/help/issue/categorys/options/` })
|
||||
return request.get({ url: `/vadmin/help/issue/categorys/options` })
|
||||
}
|
||||
|
||||
// 常见问题
|
||||
export const getIssueListApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/help/issues/', params })
|
||||
return request.get({ url: '/vadmin/help/issues', params })
|
||||
}
|
||||
|
||||
export const addIssueApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: '/vadmin/help/issues/', data })
|
||||
return request.post({ url: '/vadmin/help/issues', data })
|
||||
}
|
||||
|
||||
export const delIssueListApi = (data: any): Promise<IResponse> => {
|
||||
return request.delete({ url: '/vadmin/help/issues/', data })
|
||||
return request.delete({ url: '/vadmin/help/issues', data })
|
||||
}
|
||||
|
||||
export const putIssueApi = (data: any): Promise<IResponse> => {
|
||||
return request.put({ url: `/vadmin/help/issues/${data.id}/`, data })
|
||||
return request.put({ url: `/vadmin/help/issues/${data.id}`, data })
|
||||
}
|
||||
|
||||
export const getIssueApi = (dataId: number): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/help/issues/${dataId}/` })
|
||||
return request.get({ url: `/vadmin/help/issues/${dataId}` })
|
||||
}
|
||||
|
@ -1,49 +1,49 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export const getDictTypeListApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/system/dict/types/', params })
|
||||
return request.get({ url: '/vadmin/system/dict/types', params })
|
||||
}
|
||||
|
||||
export const addDictTypeListApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: '/vadmin/system/dict/types/', data })
|
||||
return request.post({ url: '/vadmin/system/dict/types', data })
|
||||
}
|
||||
|
||||
export const delDictTypeListApi = (data: any): Promise<IResponse> => {
|
||||
return request.delete({ url: '/vadmin/system/dict/types/', data })
|
||||
return request.delete({ url: '/vadmin/system/dict/types', data })
|
||||
}
|
||||
|
||||
export const putDictTypeListApi = (data: any): Promise<IResponse> => {
|
||||
return request.put({ url: `/vadmin/system/dict/types/${data.id}/`, data })
|
||||
return request.put({ url: `/vadmin/system/dict/types/${data.id}`, data })
|
||||
}
|
||||
|
||||
export const getDictTypeApi = (dataId: number): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/system/dict/types/${dataId}/` })
|
||||
return request.get({ url: `/vadmin/system/dict/types/${dataId}` })
|
||||
}
|
||||
|
||||
export const getDictTypeOptionsApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/system/dict/types/options/` })
|
||||
return request.get({ url: `/vadmin/system/dict/types/options` })
|
||||
}
|
||||
|
||||
export const getDictTypeDetailsApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: `/vadmin/system/dict/types/details/`, data })
|
||||
return request.post({ url: `/vadmin/system/dict/types/details`, data })
|
||||
}
|
||||
|
||||
export const getDictDetailsListApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/system/dict/details/', params })
|
||||
return request.get({ url: '/vadmin/system/dict/details', params })
|
||||
}
|
||||
|
||||
export const addDictDetailsListApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({ url: '/vadmin/system/dict/details/', data })
|
||||
return request.post({ url: '/vadmin/system/dict/details', data })
|
||||
}
|
||||
|
||||
export const delDictDetailsListApi = (data: any): Promise<IResponse> => {
|
||||
return request.delete({ url: '/vadmin/system/dict/details/', data })
|
||||
return request.delete({ url: '/vadmin/system/dict/details', data })
|
||||
}
|
||||
|
||||
export const putDictDetailsListApi = (data: any): Promise<IResponse> => {
|
||||
return request.put({ url: `/vadmin/system/dict/details/${data.id}/`, data })
|
||||
return request.put({ url: `/vadmin/system/dict/details/${data.id}`, data })
|
||||
}
|
||||
|
||||
export const getDictDetailsApi = (dataId: number): Promise<IResponse> => {
|
||||
return request.get({ url: `/vadmin/system/dict/details/${dataId}/` })
|
||||
return request.get({ url: `/vadmin/system/dict/details/${dataId}` })
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import request from '@/config/axios'
|
||||
|
||||
export const addFilesListApi = (data: any): Promise<IResponse> => {
|
||||
return request.post({
|
||||
url: `/vadmin/system/files/`,
|
||||
url: `/vadmin/system/files`,
|
||||
headersType: 'multipart/form-data',
|
||||
data
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export const getRecordLoginListApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/record/logins/', params })
|
||||
return request.get({ url: '/vadmin/record/logins', params })
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export const getRecordOperationListApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/record/operations/', params })
|
||||
return request.get({ url: '/vadmin/record/operations', params })
|
||||
}
|
||||
|
@ -1,28 +1,28 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
export const getSystemSettingsTabsApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/system/settings/tabs/', params })
|
||||
return request.get({ url: '/vadmin/system/settings/tabs', params })
|
||||
}
|
||||
|
||||
export const getSystemSettingsApi = (params: any): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/system/settings/tabs/values/', params })
|
||||
return request.get({ url: '/vadmin/system/settings/tabs/values', params })
|
||||
}
|
||||
|
||||
export const putSystemSettingsApi = (data: any): Promise<IResponse> => {
|
||||
return request.put({ url: '/vadmin/system/settings/tabs/values/', data })
|
||||
return request.put({ url: '/vadmin/system/settings/tabs/values', data })
|
||||
}
|
||||
|
||||
// 获取系统基础配置,每次进入系统时使用
|
||||
export const getSystemBaseConfigApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/system/settings/base/config/' })
|
||||
return request.get({ url: '/vadmin/system/settings/base/config' })
|
||||
}
|
||||
|
||||
// 获取系统隐私协议
|
||||
export const getSystemPrivacyApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/system/settings/privacy/' })
|
||||
return request.get({ url: '/vadmin/system/settings/privacy' })
|
||||
}
|
||||
|
||||
// 获取系统用户协议
|
||||
export const getSystemAgreementApi = (): Promise<IResponse> => {
|
||||
return request.get({ url: '/vadmin/system/settings/agreement/' })
|
||||
return request.get({ url: '/vadmin/system/settings/agreement' })
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { ElBreadcrumb, ElBreadcrumbItem } from 'element-plus'
|
||||
import { ref, watch, computed, unref, defineComponent, TransitionGroup } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { useRouterStore } from '@/store/modules/router'
|
||||
import { filterBreadcrumb } from './helper'
|
||||
import { filter, treeToList } from '@/utils/tree'
|
||||
import type { RouteLocationNormalizedLoaded, RouteMeta } from 'vue-router'
|
||||
@ -29,10 +29,10 @@ export default defineComponent({
|
||||
|
||||
const levelList = ref<AppRouteRecordRaw[]>([])
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
const routerStore = useRouterStore()
|
||||
|
||||
const menuRouters = computed(() => {
|
||||
const routers = permissionStore.getRouters
|
||||
const routers = routerStore.getRouters
|
||||
return filterBreadcrumb(routers)
|
||||
})
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { computed, defineComponent, unref, PropType } from 'vue'
|
||||
import { ElMenu, ElScrollbar } from 'element-plus'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { useRouterStore } from '@/store/modules/router'
|
||||
import { useRenderMenuItem } from './components/useRenderMenuItem'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { isUrl } from '@/utils/is'
|
||||
@ -28,7 +28,7 @@ export default defineComponent({
|
||||
|
||||
const { push, currentRoute } = useRouter()
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
const routerStore = useRouterStore()
|
||||
|
||||
const menuMode = computed((): 'vertical' | 'horizontal' => {
|
||||
// 竖
|
||||
@ -42,7 +42,7 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
const routers = computed(() =>
|
||||
unref(layout) === 'cutMenu' ? permissionStore.getMenuTabRouters : permissionStore.getRouters
|
||||
unref(layout) === 'cutMenu' ? routerStore.getMenuTabRouters : routerStore.getRouters
|
||||
)
|
||||
|
||||
const collapse = computed(() => appStore.getCollapse)
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="tsx">
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { useRouterStore } from '@/store/modules/router'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { computed, unref, defineComponent, watch, ref, onMounted } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
@ -30,9 +30,9 @@ export default defineComponent({
|
||||
|
||||
const fixedMenu = computed(() => appStore.getFixedMenu)
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
const routerStore = useRouterStore()
|
||||
|
||||
const routers = computed(() => permissionStore.getRouters)
|
||||
const routers = computed(() => routerStore.getRouters)
|
||||
|
||||
const tabRouters = computed(() => unref(routers).filter((v) => !v?.meta?.hidden))
|
||||
|
||||
@ -51,7 +51,7 @@ export default defineComponent({
|
||||
|
||||
tabActive.value = path
|
||||
if (children) {
|
||||
permissionStore.setMenuTabRouters(
|
||||
routerStore.setMenuTabRouters(
|
||||
cloneDeep(children).map((v) => {
|
||||
v.path = pathResolve(unref(tabActive), v.path)
|
||||
return v
|
||||
@ -108,7 +108,7 @@ export default defineComponent({
|
||||
showMenu.value = unref(fixedMenu) ? true : !unref(showMenu)
|
||||
}
|
||||
if (unref(showMenu)) {
|
||||
permissionStore.setMenuTabRouters(
|
||||
routerStore.setMenuTabRouters(
|
||||
cloneDeep(item.children).map((v) => {
|
||||
v.path = pathResolve(unref(tabActive), v.path)
|
||||
return v
|
||||
@ -117,7 +117,7 @@ export default defineComponent({
|
||||
}
|
||||
} else {
|
||||
push(item.path)
|
||||
permissionStore.setMenuTabRouters([])
|
||||
routerStore.setMenuTabRouters([])
|
||||
showMenu.value = false
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { onMounted, watch, computed, unref, ref, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { RouteLocationNormalizedLoaded, RouterLinkProps } from 'vue-router'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { useRouterStore } from '@/store/modules/router'
|
||||
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
@ -21,9 +21,9 @@ const { t } = useI18n()
|
||||
|
||||
const { currentRoute, push, replace } = useRouter()
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
const routerStore = useRouterStore()
|
||||
|
||||
const routers = computed(() => permissionStore.getRouters)
|
||||
const routers = computed(() => routerStore.getRouters)
|
||||
|
||||
const tagsViewStore = useTagsViewStore()
|
||||
|
||||
@ -108,14 +108,14 @@ const toLastView = () => {
|
||||
push(latestView)
|
||||
} else {
|
||||
if (
|
||||
unref(currentRoute).path === permissionStore.getAddRouters[0].path ||
|
||||
unref(currentRoute).path === permissionStore.getAddRouters[0].redirect
|
||||
unref(currentRoute).path === routerStore.getAddRouters[0].path ||
|
||||
unref(currentRoute).path === routerStore.getAddRouters[0].redirect
|
||||
) {
|
||||
addTags()
|
||||
return
|
||||
}
|
||||
// You can set another route
|
||||
push(permissionStore.getAddRouters[0].path)
|
||||
push(routerStore.getAddRouters[0].path)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,7 @@ service.interceptors.response.use(
|
||||
},
|
||||
(error: AxiosError) => {
|
||||
let { message } = error
|
||||
const authStore = useAuthStore()
|
||||
const status = error.response?.status
|
||||
switch (status) {
|
||||
case 400:
|
||||
@ -112,12 +113,13 @@ service.interceptors.response.use(
|
||||
break
|
||||
case 401:
|
||||
// 强制要求重新登录,因账号已冻结,账号已过期,手机号码错误,刷新token无效等问题导致
|
||||
const authStore = useAuthStore()
|
||||
authStore.logout()
|
||||
message = '认证已过期,请重新登录'
|
||||
break
|
||||
case 403:
|
||||
message = '拒绝访问'
|
||||
// 强制要求重新登录,因无系统权限,而进入到系统访问等问题导致
|
||||
authStore.logout()
|
||||
message = '无权限访问,请联系管理员'
|
||||
break
|
||||
case 404:
|
||||
message = `请求地址出错: ${error.response?.config.url}`
|
||||
|
@ -1,18 +1,16 @@
|
||||
import type { App, Directive, DirectiveBinding } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { intersection } from 'lodash-es'
|
||||
import { isArray } from '@/utils/is'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { wsCache } = useCache()
|
||||
const appStore = useAppStoreWithOut()
|
||||
const authStore = useAuthStoreWithOut()
|
||||
|
||||
// 全部权限
|
||||
const all_permission = ['*.*.*']
|
||||
const hasPermission = (value: string | string[]): boolean => {
|
||||
const permissions = wsCache.get(appStore.getUserInfo).permissions as string[]
|
||||
const permissions = authStore.getPermissions
|
||||
if (!value) {
|
||||
throw new Error(t('permission.hasPermission'))
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { get } from 'lodash-es'
|
||||
import type { TableProps } from '@/components/Table/src/types'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { TableSetPropsType } from '@/types/table'
|
||||
import { isEmpty } from '@/utils/is'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@ -34,7 +35,7 @@ interface TableObject<T = any> {
|
||||
tableData: T[]
|
||||
params: any
|
||||
loading: boolean
|
||||
currentRow: Nullable<T>
|
||||
currentRow: Recordable | null
|
||||
}
|
||||
|
||||
type TableOrderChange = {
|
||||
@ -111,7 +112,7 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
|
||||
return table
|
||||
}
|
||||
|
||||
const delData = async (ids: string[] | number[]) => {
|
||||
const delData = async (ids: string[] | number[] | number) => {
|
||||
if (config?.delListApi) {
|
||||
const res = await config.delListApi(ids)
|
||||
if (res) {
|
||||
@ -166,29 +167,47 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
|
||||
methods.getList()
|
||||
},
|
||||
// 删除数据
|
||||
delListApi: async (ids: string[] | number[], multiple: boolean, message = true) => {
|
||||
// 如果存在 ids,则直接使用 ids 中的值进行删除
|
||||
// 如果不存在 ids,则判断 multiple 的值来进行删除
|
||||
// 如果 multiple 为 true,则说明是多选框,获取多选框中的数据删除
|
||||
// 如果为 false,则说明是点击按钮,则获取当前选择行数据进行删除
|
||||
delListApi: async (
|
||||
multiple: boolean,
|
||||
ids: string[] | number[] | number = [],
|
||||
message = true
|
||||
) => {
|
||||
const tableRef = await getTable()
|
||||
if (multiple) {
|
||||
if (!tableRef?.selections.length) {
|
||||
ElMessage.warning(t('common.delNoData'))
|
||||
return
|
||||
let value: string[] | number[] | number = []
|
||||
if (isEmpty(ids)) {
|
||||
if (multiple) {
|
||||
if (!tableRef?.selections.length) {
|
||||
ElMessage.warning(t('common.delNoData'))
|
||||
return
|
||||
} else {
|
||||
value = tableRef?.selections.map((item) => item.id)
|
||||
}
|
||||
} else {
|
||||
if (!tableObject.currentRow) {
|
||||
ElMessage.warning(t('common.delNoData'))
|
||||
return
|
||||
} else {
|
||||
value = tableObject.currentRow.id
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!tableObject.currentRow) {
|
||||
ElMessage.warning(t('common.delNoData'))
|
||||
return
|
||||
}
|
||||
value = ids
|
||||
}
|
||||
|
||||
if (message) {
|
||||
ElMessageBox.confirm(t('common.delMessage'), t('common.delWarning'), {
|
||||
confirmButtonText: t('common.delOk'),
|
||||
cancelButtonText: t('common.delCancel'),
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
await delData(ids)
|
||||
await delData(value)
|
||||
})
|
||||
} else {
|
||||
await delData(ids)
|
||||
await delData(value)
|
||||
}
|
||||
},
|
||||
// 导出筛选列表
|
||||
|
@ -4,12 +4,12 @@ import { useCache } from '@/hooks/web/useCache'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import { useTitle } from '@/hooks/web/useTitle'
|
||||
import { useNProgress } from '@/hooks/web/useNProgress'
|
||||
import { usePermissionStoreWithOut } from '@/store/modules/permission'
|
||||
import { useRouterStoreWithOut } from '@/store/modules/router'
|
||||
import { usePageLoading } from '@/hooks/web/usePageLoading'
|
||||
import { getRoleMenusApi } from '@/api/login'
|
||||
import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
|
||||
const permissionStore = usePermissionStoreWithOut()
|
||||
const Routertore = useRouterStoreWithOut()
|
||||
|
||||
const appStore = useAppStoreWithOut()
|
||||
const authStore = useAuthStoreWithOut()
|
||||
@ -25,16 +25,16 @@ const whiteList = ['/login', '/docs/privacy', '/docs/agreement'] // 不重定向
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
start()
|
||||
loadStart()
|
||||
if (wsCache.get(appStore.getUserInfo)) {
|
||||
if (wsCache.get(appStore.getToken)) {
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' })
|
||||
} else if (to.path === '/reset/password') {
|
||||
next()
|
||||
} else {
|
||||
if (!authStore.getIsUser) {
|
||||
await authStore.getUserInfo()
|
||||
await authStore.setUserInfo()
|
||||
}
|
||||
if (permissionStore.getIsAddRouters) {
|
||||
if (Routertore.getIsAddRouters) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
@ -44,14 +44,14 @@ router.beforeEach(async (to, from, next) => {
|
||||
const { wsCache } = useCache()
|
||||
const routers = res.data || []
|
||||
wsCache.set('roleRouters', routers)
|
||||
await permissionStore.generateRoutes(routers).catch(() => {})
|
||||
permissionStore.getAddRouters.forEach((route) => {
|
||||
await Routertore.generateRoutes(routers).catch(() => {})
|
||||
Routertore.getAddRouters.forEach((route) => {
|
||||
router.addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
||||
})
|
||||
const redirectPath = from.query.redirect || to.path
|
||||
const redirect = decodeURIComponent(redirectPath as string)
|
||||
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }
|
||||
permissionStore.setIsAddRouters(true)
|
||||
Routertore.setIsAddRouters(true)
|
||||
next(nextData)
|
||||
}
|
||||
} else {
|
||||
|
@ -27,7 +27,6 @@ interface AppState {
|
||||
pageLoading: boolean
|
||||
layout: LayoutType
|
||||
title: string
|
||||
userInfo: string
|
||||
isDark: boolean
|
||||
currentSize: ElementPlusSize
|
||||
sizeMap: ElementPlusSize[]
|
||||
@ -45,7 +44,6 @@ interface AppState {
|
||||
export const useAppStore = defineStore('app', {
|
||||
state: (): AppState => {
|
||||
return {
|
||||
userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
||||
token: 'Token', // 存储Token字段
|
||||
refreshToken: 'RefreshToken', // 存储刷新Token字段
|
||||
sizeMap: ['default', 'large', 'small'],
|
||||
@ -166,9 +164,6 @@ export const useAppStore = defineStore('app', {
|
||||
getTitle(): string {
|
||||
return this.title
|
||||
},
|
||||
getUserInfo(): string {
|
||||
return this.userInfo
|
||||
},
|
||||
getToken(): string {
|
||||
return this.token
|
||||
},
|
||||
|
@ -8,12 +8,14 @@ import { getCurrentAdminUserInfo } from '@/api/vadmin/auth/user'
|
||||
import { resetRouter } from '@/router'
|
||||
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||
import router from '@/router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
|
||||
export interface UserState {
|
||||
id?: number
|
||||
telephone?: string
|
||||
email?: string
|
||||
name?: string
|
||||
nickname?: string
|
||||
avatar?: string
|
||||
@ -23,14 +25,18 @@ export interface UserState {
|
||||
}
|
||||
|
||||
export interface AuthState {
|
||||
user: UserState
|
||||
isUser: boolean
|
||||
user: UserState // 当前用户基本信息
|
||||
isUser: boolean // 是否已经登录并获取到用户信息
|
||||
roles: string[] // 当前用户角色 role_key 列表
|
||||
permissions: string[] // 当前用户权限列表
|
||||
}
|
||||
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
state: (): AuthState => {
|
||||
return {
|
||||
user: {},
|
||||
roles: [],
|
||||
permissions: [],
|
||||
isUser: false
|
||||
}
|
||||
},
|
||||
@ -38,6 +44,12 @@ export const useAuthStore = defineStore('auth', {
|
||||
getUser(): UserState {
|
||||
return this.user
|
||||
},
|
||||
getRoles(): string[] {
|
||||
return this.roles
|
||||
},
|
||||
getPermissions(): string[] {
|
||||
return this.permissions
|
||||
},
|
||||
getIsUser(): boolean {
|
||||
return this.isUser
|
||||
}
|
||||
@ -50,35 +62,45 @@ export const useAuthStore = defineStore('auth', {
|
||||
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()
|
||||
// 获取当前登录用户的信息
|
||||
await this.setUserInfo()
|
||||
}
|
||||
return res
|
||||
},
|
||||
logout() {
|
||||
logout(message?: string) {
|
||||
wsCache.clear()
|
||||
this.user = {}
|
||||
this.roles = []
|
||||
this.permissions = []
|
||||
this.isUser = false
|
||||
const tagsViewStore = useTagsViewStore()
|
||||
tagsViewStore.delAllViews()
|
||||
resetRouter()
|
||||
router.push('/login')
|
||||
if (message) {
|
||||
ElMessage.error(message)
|
||||
}
|
||||
},
|
||||
// 这里更新用户是自己在个人中心更新自己的用户信息,不包括在用户列表中更新的,所以不包含权限角色等信息
|
||||
// 用户信息取消使用持久化存储,仅使用共享存储
|
||||
updateUser(data: UserState) {
|
||||
this.user.gender = data.gender
|
||||
this.user.name = data.name
|
||||
this.user.nickname = data.nickname
|
||||
this.user.telephone = data.telephone
|
||||
const appStore = useAppStore()
|
||||
wsCache.set(appStore.getUserInfo, this.user)
|
||||
},
|
||||
async getUserInfo() {
|
||||
// 获取用户详细信息,包括角色,权限
|
||||
// 用户信息取消使用持久化存储,仅使用共享存储
|
||||
async setUserInfo() {
|
||||
const res = await getCurrentAdminUserInfo()
|
||||
const appStore = useAppStore()
|
||||
wsCache.set(appStore.getUserInfo, res.data)
|
||||
this.isUser = true
|
||||
this.user = res.data
|
||||
this.roles = res.data.roles.map((item) => {
|
||||
if (!item.disabled) {
|
||||
return item.role_key
|
||||
}
|
||||
})
|
||||
this.permissions = res.data.permissions
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -4,15 +4,15 @@ import { generateRoutesFn2, flatMultiLevelRoutes } from '@/utils/routerHelper'
|
||||
import { store } from '../index'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
export interface PermissionState {
|
||||
export interface RouterState {
|
||||
routers: AppRouteRecordRaw[]
|
||||
addRouters: AppRouteRecordRaw[]
|
||||
isAddRouters: boolean
|
||||
menuTabRouters: AppRouteRecordRaw[]
|
||||
}
|
||||
|
||||
export const usePermissionStore = defineStore('permission', {
|
||||
state: (): PermissionState => ({
|
||||
export const useRouterStore = defineStore('router', {
|
||||
state: (): RouterState => ({
|
||||
routers: [],
|
||||
addRouters: [],
|
||||
isAddRouters: false,
|
||||
@ -63,6 +63,6 @@ export const usePermissionStore = defineStore('permission', {
|
||||
}
|
||||
})
|
||||
|
||||
export const usePermissionStoreWithOut = () => {
|
||||
return usePermissionStore(store)
|
||||
export const useRouterStoreWithOut = () => {
|
||||
return useRouterStore(store)
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
import { useTimeAgo } from '@/hooks/web/useTimeAgo'
|
||||
import { ElRow, ElCol, ElSkeleton, ElCard, ElDivider, ElLink } from 'element-plus'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { CountTo } from '@/components/CountTo'
|
||||
import { formatTime } from '@/utils'
|
||||
import { Highlight } from '@/components/Highlight'
|
||||
@ -20,11 +20,10 @@ import type {
|
||||
Team,
|
||||
Shortcuts
|
||||
} from '@/api/dashboard/workplace/types'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import avatar from '@/assets/imgs/avatar.jpg'
|
||||
import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const authStore = useAuthStoreWithOut()
|
||||
|
||||
const loading = ref(true)
|
||||
|
||||
@ -97,9 +96,7 @@ getAllApi()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const appStore = useAppStoreWithOut()
|
||||
|
||||
const user = wsCache.get(appStore.getUserInfo)
|
||||
const user = computed(() => authStore.getUser)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -6,7 +6,7 @@ import { ElButton, ElCheckbox, ElLink } from 'element-plus'
|
||||
import { useForm } from '@/hooks/web/useForm'
|
||||
import { getRoleMenusApi } from '@/api/login'
|
||||
import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { useRouterStore } from '@/store/modules/router'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
|
||||
import { UserLoginType } from '@/api/login/types'
|
||||
@ -18,7 +18,7 @@ const emit = defineEmits(['to-telephone-code'])
|
||||
|
||||
const { required } = useValidator()
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
const routerStore = useRouterStore()
|
||||
|
||||
const { currentRoute, addRoute, push } = useRouter()
|
||||
|
||||
@ -157,12 +157,12 @@ const getMenu = async () => {
|
||||
const { wsCache } = useCache()
|
||||
const routers = res.data || []
|
||||
wsCache.set('roleRouters', routers)
|
||||
await permissionStore.generateRoutes(routers).catch(() => {})
|
||||
permissionStore.getAddRouters.forEach((route) => {
|
||||
await routerStore.generateRoutes(routers).catch(() => {})
|
||||
routerStore.getAddRouters.forEach((route) => {
|
||||
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
||||
})
|
||||
permissionStore.setIsAddRouters(true)
|
||||
push({ path: redirect.value || permissionStore.addRouters[0].path })
|
||||
routerStore.setIsAddRouters(true)
|
||||
push({ path: redirect.value || routerStore.addRouters[0].path })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
import { RouteLocationNormalizedLoaded, useRouter, RouteRecordRaw } from 'vue-router'
|
||||
import { getRoleMenusApi } from '@/api/login'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { useRouterStore } from '@/store/modules/router'
|
||||
|
||||
const emit = defineEmits(['to-login'])
|
||||
|
||||
@ -20,7 +20,7 @@ const { register, elFormRef, methods } = useForm()
|
||||
const { t } = useI18n()
|
||||
const { required } = useValidator()
|
||||
const { currentRoute, addRoute, push } = useRouter()
|
||||
const permissionStore = usePermissionStore()
|
||||
const routerStore = useRouterStore()
|
||||
|
||||
const schema = reactive<FormSchema[]>([
|
||||
{
|
||||
@ -157,12 +157,12 @@ const getMenu = async () => {
|
||||
const { wsCache } = useCache()
|
||||
const routers = res.data || []
|
||||
wsCache.set('roleRouters', routers)
|
||||
await permissionStore.generateRoutes(routers).catch(() => {})
|
||||
permissionStore.getAddRouters.forEach((route) => {
|
||||
await routerStore.generateRoutes(routers).catch(() => {})
|
||||
routerStore.getAddRouters.forEach((route) => {
|
||||
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
||||
})
|
||||
permissionStore.setIsAddRouters(true)
|
||||
push({ path: redirect.value || permissionStore.addRouters[0].path })
|
||||
routerStore.setIsAddRouters(true)
|
||||
push({ path: redirect.value || routerStore.addRouters[0].path })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -4,7 +4,7 @@ import { Form } from '@/components/Form'
|
||||
import { ElButton } from 'element-plus'
|
||||
import { useForm } from '@/hooks/web/useForm'
|
||||
import { postCurrentUserResetPassword } from '@/api/vadmin/auth/user'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { useRouterStore } from '@/store/modules/router'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { RouteRecordRaw, RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import { getRoleMenusApi } from '@/api/login'
|
||||
@ -21,7 +21,7 @@ const { required } = useValidator()
|
||||
|
||||
const footer = computed(() => appStore.getFooter)
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
const routerStore = useRouterStore()
|
||||
|
||||
const { addRoute, push, currentRoute } = useRouter()
|
||||
|
||||
@ -124,12 +124,12 @@ const getMenu = async () => {
|
||||
const { wsCache } = useCache()
|
||||
const routers = res.data || []
|
||||
wsCache.set('roleRouters', routers)
|
||||
await permissionStore.generateRoutes(routers).catch(() => {})
|
||||
permissionStore.getAddRouters.forEach((route) => {
|
||||
await routerStore.generateRoutes(routers).catch(() => {})
|
||||
routerStore.getAddRouters.forEach((route) => {
|
||||
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
||||
})
|
||||
permissionStore.setIsAddRouters(true)
|
||||
push({ path: redirect.value || permissionStore.addRouters[0].path })
|
||||
routerStore.setIsAddRouters(true)
|
||||
push({ path: redirect.value || routerStore.addRouters[0].path })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -76,7 +76,7 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form :rules="rules" @register="register">
|
||||
<Form :rules="rules" @register="register" :labelWidth="100">
|
||||
<template #icon="form">
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<ElInput
|
||||
|
@ -49,7 +49,6 @@ const { register, elTableRef, tableObject, methods } = useTable({
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
const delLoading = ref(false)
|
||||
const actionType = ref('')
|
||||
const parentId = ref()
|
||||
|
||||
@ -74,12 +73,8 @@ const updateAction = (row: any) => {
|
||||
// 删除事件
|
||||
const delData = async (row: any) => {
|
||||
parentId.value = null
|
||||
tableObject.currentRow = row
|
||||
const { delListApi } = methods
|
||||
delLoading.value = true
|
||||
await delListApi([row.id], false).finally(() => {
|
||||
delLoading.value = false
|
||||
})
|
||||
await delListApi(true, [row.id])
|
||||
}
|
||||
|
||||
// 添加子菜单事件
|
||||
|
@ -75,7 +75,7 @@ defineExpose({
|
||||
|
||||
let selectAll = ref(false)
|
||||
let defaultExpandAll = ref(true)
|
||||
let checkStrictly = ref(false)
|
||||
let checkStrictly = ref(true) // 父子联动
|
||||
|
||||
// 获取所有节点的key
|
||||
const getTreeNodeKeys = (nodes: Recordable[]): number[] => {
|
||||
|
@ -65,12 +65,8 @@ const updateAction = async (row: any) => {
|
||||
|
||||
// 删除事件
|
||||
const delData = async (row: any) => {
|
||||
tableObject.currentRow = row
|
||||
const { delListApi } = methods
|
||||
loading.value = true
|
||||
await delListApi([row.id], false).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
await delListApi(true, [row.id])
|
||||
}
|
||||
|
||||
const writeRef = ref<ComponentRef<typeof Write>>()
|
||||
|
@ -1,98 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { ElButton, ElTable, ElTableColumn, ElPopconfirm, ElMessage, ElTag } from 'element-plus'
|
||||
import { postUsersInitPasswordSendSMSApi } from '@/api/vadmin/auth/user'
|
||||
import { ref, PropType } from 'vue'
|
||||
|
||||
const emit = defineEmits(['getList'])
|
||||
|
||||
const props = defineProps({
|
||||
selections: {
|
||||
type: Object as PropType<Recordable[]>
|
||||
}
|
||||
})
|
||||
|
||||
const tableData = ref(JSON.parse(JSON.stringify(props.selections)))
|
||||
const loading = ref(false)
|
||||
|
||||
const handleDelete = (index: number) => {
|
||||
tableData.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const initPassword = async () => {
|
||||
loading.value = true
|
||||
const ids = tableData.value
|
||||
.filter((item) => item.reset_password_status !== true)
|
||||
.map((item) => item.id)
|
||||
if (ids.length <= 0) {
|
||||
return ElMessage.warning('已全部重置完成,无需重复操作')
|
||||
}
|
||||
const res = await postUsersInitPasswordSendSMSApi(ids).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
if (res) {
|
||||
tableData.value = res.data
|
||||
ElMessage.success('重置成功')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex justify-between">
|
||||
<span>已选用户列表</span>
|
||||
<ElButton
|
||||
type="primary"
|
||||
:disabled="tableData?.length === 0"
|
||||
:loading="loading"
|
||||
@click="initPassword"
|
||||
>确认重置并发送短信通知</ElButton
|
||||
>
|
||||
</div>
|
||||
<ElTable
|
||||
:data="tableData"
|
||||
:stripe="true"
|
||||
:border="true"
|
||||
style="width: 100%"
|
||||
class="mt-10px"
|
||||
max-height="500px"
|
||||
>
|
||||
<ElTableColumn prop="id" label="用户编号" width="100" align="center" />
|
||||
<ElTableColumn prop="name" label="姓名" width="120" align="center" />
|
||||
<ElTableColumn prop="telephone" label="手机号" width="120" align="center" />
|
||||
<ElTableColumn prop="reset_password_status" label="重置状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.reset_password_status === true" type="success" effect="dark">
|
||||
重置成功
|
||||
</ElTag>
|
||||
<ElTag v-else-if="scope.row.reset_password_status === false" type="danger" effect="dark">
|
||||
重置失败
|
||||
</ElTag>
|
||||
<ElTag v-else type="warning" effect="dark"> 待重置 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="send_sms_status" label="发送状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElTag v-if="scope.row.send_sms_status === true" type="success" effect="dark">
|
||||
发送成功
|
||||
</ElTag>
|
||||
<ElTag v-else-if="scope.row.send_sms_status === false" type="danger" effect="dark">
|
||||
发送失败
|
||||
</ElTag>
|
||||
<ElTag v-else type="warning" effect="dark"> 待发送 </ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn prop="send_sms_msg" label="描述" align="center" />
|
||||
<ElTableColumn fixed="right" label="操作" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<ElPopconfirm title="确认移除吗?" @confirm="handleDelete(scope.$index)">
|
||||
<template #reference>
|
||||
<ElButton v-if="scope.row.send_sms_status !== true" link type="primary" size="small"
|
||||
>移除</ElButton
|
||||
>
|
||||
</template>
|
||||
</ElPopconfirm>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
</div>
|
||||
</template>
|
@ -71,6 +71,9 @@ const { register, elTableRef, tableObject, methods } = useTable({
|
||||
},
|
||||
defaultParams: {
|
||||
is_active: true
|
||||
},
|
||||
props: {
|
||||
columns
|
||||
}
|
||||
})
|
||||
|
||||
@ -100,20 +103,16 @@ const updateAction = async (row: any) => {
|
||||
}
|
||||
|
||||
// 删除事件
|
||||
const delDatas = async (row: any, multiple: boolean) => {
|
||||
const delDatas = async (row: any) => {
|
||||
const { delListApi, getSelections } = methods
|
||||
loading.value = true
|
||||
const selections = ref([] as any[])
|
||||
if (multiple) {
|
||||
if (row) {
|
||||
selections.value = [row.id]
|
||||
} else {
|
||||
selections.value = await getSelections()
|
||||
selections.value = selections.value.map((item) => item.id)
|
||||
} else {
|
||||
tableObject.currentRow = row
|
||||
selections.value = [row.id]
|
||||
}
|
||||
await delListApi(selections.value, multiple).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
await delListApi(true, selections.value)
|
||||
}
|
||||
|
||||
const writeRef = ref<ComponentRef<typeof Write>>()
|
||||
@ -224,7 +223,7 @@ const handleCommand = (command: string) => {
|
||||
} else if (command === 'd') {
|
||||
sendPasswordToEmail()
|
||||
} else if (command === 'e') {
|
||||
delDatas(null, true)
|
||||
delDatas(null)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -256,7 +255,7 @@ const handleCommand = (command: string) => {
|
||||
<ElButton @click="sendPasswordToEmail">重置密码通知邮件</ElButton>
|
||||
</ElCol>
|
||||
<ElCol :span="1.5" v-hasPermi="['auth.user.delete']" v-if="!mobile">
|
||||
<ElButton type="danger" @click="delDatas(null, true)">批量删除</ElButton>
|
||||
<ElButton type="danger" @click="delDatas(null)">批量删除</ElButton>
|
||||
</ElCol>
|
||||
<ElCol :span="1.5" v-if="mobile">
|
||||
<ElDropdown trigger="click" @command="handleCommand">
|
||||
@ -325,7 +324,7 @@ const handleCommand = (command: string) => {
|
||||
v-hasPermi="['auth.user.delete']"
|
||||
link
|
||||
size="small"
|
||||
@click="delDatas(row, false)"
|
||||
@click="delDatas(row)"
|
||||
v-if="authStore.getUser.id !== row.id && row.id !== 1"
|
||||
>
|
||||
{{ t('exampleDemo.del') }}
|
||||
|
@ -58,7 +58,6 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
const loading = ref(false)
|
||||
const searchSetSchemaList = ref([] as FormSetPropsType[])
|
||||
|
||||
const getOptions = async () => {
|
||||
@ -84,12 +83,8 @@ const updateAction = async (row: any) => {
|
||||
|
||||
// 删除事件
|
||||
const delData = async (row: any) => {
|
||||
tableObject.currentRow = row
|
||||
const { delListApi } = methods
|
||||
loading.value = true
|
||||
await delListApi([row.id], false).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
await delListApi(true, [row.id])
|
||||
}
|
||||
|
||||
getList()
|
||||
|
@ -103,12 +103,8 @@ const updateAction = async (row: any) => {
|
||||
|
||||
// 删除事件
|
||||
const delData = async (row: any) => {
|
||||
tableObject.currentRow = row
|
||||
const { delListApi } = methods
|
||||
loading.value = true
|
||||
await delListApi([row.id], false).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
await delListApi(true, [row.id])
|
||||
}
|
||||
|
||||
const writeRef = ref<ComponentRef<typeof Write>>()
|
||||
|
@ -89,12 +89,8 @@ const updateAction = async (row: any) => {
|
||||
|
||||
// 删除事件
|
||||
const delData = async (row: any) => {
|
||||
tableObject.currentRow = row
|
||||
const { delListApi } = methods
|
||||
loading.value = true
|
||||
await delListApi([row.id], false).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
await delListApi(true, [row.id])
|
||||
}
|
||||
|
||||
const writeRef = ref<ComponentRef<typeof Write>>()
|
||||
|
@ -64,12 +64,8 @@ const updateAction = async (row: any) => {
|
||||
|
||||
// 删除事件
|
||||
const delData = async (row: any) => {
|
||||
tableObject.currentRow = row
|
||||
const { delListApi } = methods
|
||||
loading.value = true
|
||||
await delListApi([row.id], false).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
await delListApi(true, [row.id])
|
||||
}
|
||||
|
||||
// 跳转到字典详情页面
|
||||
|
@ -83,7 +83,7 @@ python main.py init
|
||||
python main.py run
|
||||
```
|
||||
|
||||
## 其他
|
||||
## 其他操作
|
||||
|
||||
在线文档地址(在配置文件里面设置路径或者关闭)
|
||||
|
||||
@ -92,6 +92,7 @@ http://127.0.0.1:9000/docs
|
||||
```
|
||||
|
||||
Git更新ignore文件直接修改gitignore是不会生效的,需要先去掉已经托管的文件,修改完成之后再重新添加并提交。
|
||||
|
||||
```
|
||||
第一步:
|
||||
git rm -r --cached .
|
||||
@ -115,4 +116,173 @@ python main.py migrate
|
||||
python main.py migrate --env dev
|
||||
```
|
||||
|
||||
生成迁移文件后,会在alembic迁移目录中的version目录中多个迁移文件
|
||||
生成迁移文件后,会在alembic迁移目录中的version目录中多个迁移文件
|
||||
|
||||
## 查询数据
|
||||
|
||||
### 查询过滤
|
||||
|
||||
```python
|
||||
# 日期查询
|
||||
# 值的类型:str
|
||||
# 值得格式:%Y-%m-%d:2023-05-14
|
||||
字段名称=("date", 值)
|
||||
|
||||
# 模糊查询
|
||||
# 值的类型: str
|
||||
字段名称=("like", 值)
|
||||
|
||||
# in 查询
|
||||
# 值的类型:list
|
||||
字段名称=("in", 值)
|
||||
|
||||
# 时间区间查询
|
||||
# 值的类型:tuple 或者 list
|
||||
字段名称=("between", 值)
|
||||
|
||||
# 月份查询
|
||||
# 值的类型:str
|
||||
# 值的格式:%Y-%m:2023-05
|
||||
字段名称=("month", 值)
|
||||
|
||||
# 不等于查询
|
||||
字段名称=("!=", 值)
|
||||
|
||||
# 大于查询
|
||||
字段名称=(">", 值)
|
||||
|
||||
# 等于 None
|
||||
字段名称=("None")
|
||||
|
||||
# 不等于 None
|
||||
字段名称=("not None")
|
||||
```
|
||||
|
||||
代码部分:
|
||||
|
||||

|
||||
|
||||
示例:
|
||||
|
||||
查询所有用户id为1或2或 4或6,并且email不为空,并且名称包括李:
|
||||
|
||||
```python
|
||||
users = UserDal(db).get_datas(limit=0, id=("in", [1,2,4,6]), email=("not None"), name=("like", "李"))
|
||||
```
|
||||
|
||||
### v_join_query
|
||||
|
||||
外键字段查询,内连接
|
||||
|
||||
以常见问题类别表为例:
|
||||
|
||||
首先需要在 `crud.py/IssueCategoryDal` 的 `__init__` 方法中定义 `key_models`:
|
||||
|
||||
```python
|
||||
class IssueCategoryDal(DalBase):
|
||||
|
||||
def __init__(self, db: AsyncSession):
|
||||
key_models = {
|
||||
# 外键字段名,也可以自定义
|
||||
"create_user": {
|
||||
# 外键对应的orm模型
|
||||
"model": vadminAuthModels.VadminUser,
|
||||
# 如果对同一个模型只有一个外键关联时,下面这个 onclause 可以省略不写,一个以上时必须写,需要分清楚要查询的是哪个
|
||||
# 这里其实可以省略不写,但是为了演示这里写出来了
|
||||
"onclause": models.VadminIssueCategory.create_user_id == vadminAuthModels.VadminUser.id
|
||||
}
|
||||
}
|
||||
super(IssueCategoryDal, self).__init__(
|
||||
db,
|
||||
models.VadminIssueCategory,
|
||||
schemas.IssueCategorySimpleOut,
|
||||
key_models
|
||||
)
|
||||
```
|
||||
|
||||
使用案例:
|
||||
|
||||
```python
|
||||
async def test(self):
|
||||
"""
|
||||
v_join_query 示例方法
|
||||
获取用户名称包含李 创建出的常见问题类别
|
||||
"""
|
||||
v_join_query = {
|
||||
# 与 key_models 中定义的外键字段名定义的一样
|
||||
"create_user": {
|
||||
# 外键表字段名:查询值
|
||||
"name": ("like", "李")
|
||||
}
|
||||
}
|
||||
v_options = [joinedload(self.model.create_user)]
|
||||
datas = self.get_datas(limit=0, v_join_query=v_join_query, v_options=v_options)
|
||||
```
|
||||
|
||||
完整案例:
|
||||
|
||||
```python
|
||||
class IssueCategoryDal(DalBase):
|
||||
|
||||
def __init__(self, db: AsyncSession):
|
||||
key_models = {
|
||||
# 外键字段名,也可以自定义
|
||||
"create_user": {
|
||||
# 外键对应的orm模型
|
||||
"model": vadminAuthModels.VadminUser,
|
||||
# 如果对同一个模型只有一个外键关联时,下面这个 onclause 可以省略不写,一个以上时必须写,需要分清楚要查询的是哪个
|
||||
# 这里其实可以省略不写,但是为了演示这里写出来了
|
||||
"onclause": models.VadminIssueCategory.create_user_id == vadminAuthModels.VadminUser.id
|
||||
}
|
||||
}
|
||||
super(IssueCategoryDal, self).__init__(
|
||||
db,
|
||||
models.VadminIssueCategory,
|
||||
schemas.IssueCategorySimpleOut,
|
||||
key_models
|
||||
)
|
||||
|
||||
async def test(self):
|
||||
"""
|
||||
v_join_query 示例方法
|
||||
获取用户名称包含李 创建出的常见问题类别
|
||||
"""
|
||||
v_join_query = {
|
||||
# 与 key_models 中定义的外键字段名定义的一样
|
||||
"create_user": {
|
||||
# 外键表字段名:查询值
|
||||
"name": ("like", "李")
|
||||
}
|
||||
}
|
||||
v_options = [joinedload(self.model.create_user)]
|
||||
datas = self.get_datas(limit=0, v_join_query=v_join_query, v_options=v_options)
|
||||
```
|
||||
|
||||
### v_or
|
||||
|
||||
或逻辑运算查询
|
||||
|
||||
语法:
|
||||
|
||||
```python
|
||||
# 普通查询
|
||||
v_or = [(字段名称, 值), (字段名称, 值), ... ]
|
||||
|
||||
# 模糊查询
|
||||
v_or = [(字段名称, ("like", 值)), (字段名称, ("like", 值)), ... ]
|
||||
|
||||
# 组合查询
|
||||
v_or = [(字段名称, ("like", 值)), (字段名称, ("in", [值, 值, 值, ...])), ... ]
|
||||
|
||||
# 外键查询,需要先定义 key_models
|
||||
v_or = [("fk", key_models 中定义的外键字段名, 外键表字段名称, ("like", 值)), ("fk", key_models 中定义的外键字段名, 外键表字段名称, ("like", 值)), ... ]
|
||||
```
|
||||
|
||||
比如查询一个用户手机号为`13409090909`或者`15390909090`:
|
||||
|
||||
```python
|
||||
v_or = [("telephone", "13409090909"), ("telephone", "15390909090") ]
|
||||
user = UserDal(db).get_data(v_or=v_or)
|
||||
```
|
||||
|
||||
的version目录中多个迁移文件
|
@ -11,7 +11,7 @@ from fastapi.security import OAuth2PasswordBearer
|
||||
"""
|
||||
系统版本
|
||||
"""
|
||||
VERSION = "1.7.9"
|
||||
VERSION = "1.8.0"
|
||||
|
||||
"""安全警告: 不要在生产中打开调试运行!"""
|
||||
DEBUG = True
|
||||
@ -20,11 +20,11 @@ DEBUG = True
|
||||
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/"
|
||||
"/auth/login",
|
||||
"/auth/token/refresh",
|
||||
"/auth/wx/login",
|
||||
"/vadmin/system/dict/types/details",
|
||||
"/vadmin/auth/user/export/query/list/to/excel"
|
||||
]
|
||||
|
||||
"""
|
||||
|
@ -17,7 +17,7 @@ app = APIRouter()
|
||||
###########################################################
|
||||
# 图表数据
|
||||
###########################################################
|
||||
@app.get("/banners/", summary="轮播图")
|
||||
@app.get("/banners", summary="轮播图")
|
||||
async def get_banners(auth: Auth = Depends(AllUserAuth())):
|
||||
data = [
|
||||
{
|
||||
@ -33,7 +33,7 @@ async def get_banners(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/user/access/source/", summary="用户来源")
|
||||
@app.get("/user/access/source", summary="用户来源")
|
||||
async def get_user_access_source(auth: Auth = Depends(AllUserAuth())):
|
||||
data = [
|
||||
{"value": 1000, "name": 'analysis.directAccess'},
|
||||
@ -45,7 +45,7 @@ async def get_user_access_source(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/weekly/user/activity/", summary="每周用户活跃量")
|
||||
@app.get("/weekly/user/activity", summary="每周用户活跃量")
|
||||
async def get_weekly_user_activity(auth: Auth = Depends(AllUserAuth())):
|
||||
data = [
|
||||
{"value": 13253, "name": 'analysis.monday'},
|
||||
@ -59,7 +59,7 @@ async def get_weekly_user_activity(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/monthly/sales/", summary="每月销售额")
|
||||
@app.get("/monthly/sales", summary="每月销售额")
|
||||
async def get_monthly_sales(auth: Auth = Depends(AllUserAuth())):
|
||||
data = [
|
||||
{"estimate": 100, "actual": 120, "name": 'analysis.january'},
|
||||
|
@ -59,7 +59,7 @@ class VadminUser(BaseModel):
|
||||
self.last_login = datetime.datetime.now()
|
||||
await db.flush()
|
||||
|
||||
async def is_admin(self) -> bool:
|
||||
def is_admin(self) -> bool:
|
||||
"""
|
||||
获取该用户是否拥有最高权限
|
||||
|
||||
|
@ -39,7 +39,7 @@ import jwt
|
||||
app = APIRouter()
|
||||
|
||||
|
||||
@app.post("/login/", summary="手机号密码登录", description="员工登录通道,限制最多输错次数,达到最大值后将is_active=False")
|
||||
@app.post("/login", summary="手机号密码登录", description="员工登录通道,限制最多输错次数,达到最大值后将is_active=False")
|
||||
async def login_for_access_token(
|
||||
request: Request,
|
||||
data: LoginForm,
|
||||
@ -74,7 +74,7 @@ async def login_for_access_token(
|
||||
return ErrorResponse(msg=str(e))
|
||||
|
||||
|
||||
@app.post("/wx/login/", summary="微信服务端一键登录", description="员工登录通道")
|
||||
@app.post("/wx/login", summary="微信服务端一键登录", description="员工登录通道")
|
||||
async def wx_login_for_access_token(
|
||||
request: Request,
|
||||
data: WXLoginForm,
|
||||
@ -116,12 +116,12 @@ async def wx_login_for_access_token(
|
||||
return SuccessResponse(resp)
|
||||
|
||||
|
||||
@app.get("/getMenuList/", summary="获取当前用户菜单树")
|
||||
@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")
|
||||
@app.post("/token/refresh", summary="刷新Token")
|
||||
async def token_refresh(refresh: str = Body(..., title="刷新Token")):
|
||||
error_code = status.HTTP_401_UNAUTHORIZED
|
||||
try:
|
||||
|
@ -11,6 +11,7 @@ from fastapi import Request
|
||||
from application import settings
|
||||
import jwt
|
||||
from apps.vadmin.auth import models
|
||||
from core.database import redis_getter
|
||||
from .validation import LoginValidation, LoginForm, LoginResult
|
||||
from utils.aliyun_sms import AliyunSMS
|
||||
|
||||
@ -35,7 +36,7 @@ class LoginManage:
|
||||
"""
|
||||
验证用户短信验证码
|
||||
"""
|
||||
rd = request.app.state.redis
|
||||
rd = redis_getter(request)
|
||||
sms = AliyunSMS(rd, data.telephone)
|
||||
result = await sms.check_sms_code(data.password)
|
||||
if result:
|
||||
|
@ -25,12 +25,17 @@ class Auth(BaseModel):
|
||||
|
||||
|
||||
class AuthValidation:
|
||||
|
||||
"""
|
||||
用于用户每次调用接口时,验证用户提交的token是否正确,并从token中获取用户信息
|
||||
"""
|
||||
|
||||
# status_code = 401 时,表示强制要求重新登录,因账号已冻结,账号已过期,手机号码错误,刷新token无效等问题导致
|
||||
# 只有 code = 401 时,表示 token 过期,要求刷新 token
|
||||
# 只有 code = 错误值时,只是报错,不重新登陆
|
||||
error_code = status.HTTP_401_UNAUTHORIZED
|
||||
warning_code = status.HTTP_ERROR
|
||||
|
||||
# status_code = 403 时,表示强制要求重新登录,因无系统权限,而进入到系统访问等问题导致
|
||||
|
||||
@classmethod
|
||||
def validate_token(cls, request: Request, token: str | None) -> str:
|
||||
@ -38,14 +43,23 @@ class AuthValidation:
|
||||
验证用户 token
|
||||
"""
|
||||
if not token:
|
||||
raise CustomException(msg="请您先登录!", code=status.HTTP_ERROR)
|
||||
raise CustomException(
|
||||
msg="请您先登录!",
|
||||
code=status.HTTP_403_FORBIDDEN,
|
||||
status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
try:
|
||||
# TODO token解析失败问题解决
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||
telephone: str = payload.get("sub")
|
||||
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)
|
||||
raise CustomException(
|
||||
msg="未认证,请您重新登录",
|
||||
code=status.HTTP_403_FORBIDDEN,
|
||||
status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
# 计算当前时间 + 缓冲时间是否大于等于 JWT 过期时间
|
||||
buffer_time = (datetime.now() + timedelta(minutes=settings.ACCESS_TOKEN_CACHE_MINUTES)).timestamp()
|
||||
# print("过期时间", exp, datetime.fromtimestamp(exp))
|
||||
@ -55,10 +69,14 @@ class AuthValidation:
|
||||
request.scope["if-refresh"] = 1
|
||||
else:
|
||||
request.scope["if-refresh"] = 0
|
||||
except jwt.exceptions.InvalidSignatureError:
|
||||
raise CustomException(msg="无效认证,请您重新登录", code=cls.error_code)
|
||||
except (jwt.exceptions.InvalidSignatureError, jwt.exceptions.DecodeError):
|
||||
raise CustomException(
|
||||
msg="无效认证,请您重新登录",
|
||||
code=status.HTTP_403_FORBIDDEN,
|
||||
status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
except jwt.exceptions.ExpiredSignatureError:
|
||||
raise CustomException(msg="认证已过期,请您重新登录", code=cls.error_code)
|
||||
raise CustomException(msg="认证已过期,请您重新登录", code=cls.error_code, status_code=cls.error_code)
|
||||
return telephone
|
||||
|
||||
@classmethod
|
||||
@ -84,7 +102,7 @@ class AuthValidation:
|
||||
"""
|
||||
获取员工用户所有权限列表
|
||||
"""
|
||||
if any([role.is_admin for role in user.roles]):
|
||||
if user.is_admin():
|
||||
return {'*.*.*'}
|
||||
permissions = set()
|
||||
for role_obj in user.roles:
|
||||
|
@ -11,6 +11,7 @@ from pydantic import BaseModel, validator
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from application.settings import DEFAULT_AUTH_ERROR_MAX_NUMBER, DEMO
|
||||
from apps.vadmin.auth import crud, schemas
|
||||
from core.database import redis_getter
|
||||
from core.validator import vali_telephone
|
||||
from typing import Optional
|
||||
from utils.count import Count
|
||||
@ -64,7 +65,7 @@ class LoginValidation:
|
||||
result = await self.func(self, data=data, user=user, request=request)
|
||||
|
||||
count_key = f"{data.telephone}_password_auth" if data.method == '0' else f"{data.telephone}_sms_auth"
|
||||
count = Count(request.app.state.redis, count_key)
|
||||
count = Count(redis_getter(request), count_key)
|
||||
|
||||
if not result.status:
|
||||
self.result.msg = result.msg
|
||||
|
@ -23,7 +23,7 @@ app = APIRouter()
|
||||
###########################################################
|
||||
# 用户管理
|
||||
###########################################################
|
||||
@app.get("/users/", summary="获取用户列表")
|
||||
@app.get("/users", summary="获取用户列表")
|
||||
async def get_users(
|
||||
params: UserParams = Depends(),
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.list"]))
|
||||
@ -36,12 +36,12 @@ async def get_users(
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.post("/users/", summary="创建用户")
|
||||
@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))
|
||||
|
||||
|
||||
@app.delete("/users/", summary="批量删除用户", description="软删除,删除后清空所关联的角色")
|
||||
@app.delete("/users", summary="批量删除用户", description="软删除,删除后清空所关联的角色")
|
||||
async def delete_users(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.delete"]))):
|
||||
if auth.user.id in ids.ids:
|
||||
return ErrorResponse("不能删除当前登录用户")
|
||||
@ -51,7 +51,7 @@ async def delete_users(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAu
|
||||
return SuccessResponse("删除成功")
|
||||
|
||||
|
||||
@app.put("/users/{data_id}/", summary="更新用户信息")
|
||||
@app.put("/users/{data_id}", summary="更新用户信息")
|
||||
async def put_user(
|
||||
data_id: int,
|
||||
data: schemas.UserUpdate,
|
||||
@ -60,7 +60,7 @@ async def put_user(
|
||||
return SuccessResponse(await crud.UserDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/users/{data_id}/", summary="获取用户信息")
|
||||
@app.get("/users/{data_id}", summary="获取用户信息")
|
||||
async def get_user(
|
||||
data_id: int,
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.view", "auth.user.update"]))
|
||||
@ -71,29 +71,29 @@ async def get_user(
|
||||
return SuccessResponse(await crud.UserDal(auth.db).get_data(data_id, options, v_schema=schema))
|
||||
|
||||
|
||||
@app.post("/user/current/reset/password/", summary="重置当前用户密码")
|
||||
@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))
|
||||
|
||||
|
||||
@app.post("/user/current/update/info/", summary="更新当前用户基本信息")
|
||||
@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))
|
||||
|
||||
|
||||
@app.post("/user/current/update/avatar/", summary="更新当前用户头像")
|
||||
@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))
|
||||
|
||||
|
||||
@app.get("/user/admin/current/info/", summary="获取当前管理员信息")
|
||||
@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(FullAdminAuth.get_user_permissions(auth.user))
|
||||
return SuccessResponse(result)
|
||||
|
||||
|
||||
@app.post("/user/export/query/list/to/excel/", summary="导出用户查询列表为excel")
|
||||
@app.post("/user/export/query/list/to/excel", summary="导出用户查询列表为excel")
|
||||
async def post_user_export_query_list(
|
||||
header: list = Body(..., title="表头与对应字段"),
|
||||
params: UserParams = Depends(),
|
||||
@ -102,17 +102,17 @@ async def post_user_export_query_list(
|
||||
return SuccessResponse(await crud.UserDal(auth.db).export_query_list(header, params))
|
||||
|
||||
|
||||
@app.get("/user/download/import/template/", summary="下载最新批量导入用户模板")
|
||||
@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())
|
||||
|
||||
|
||||
@app.post("/import/users/", summary="批量导入用户")
|
||||
@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))
|
||||
|
||||
|
||||
@app.post("/users/init/password/send/sms/", summary="初始化所选用户密码并发送通知短信")
|
||||
@app.post("/users/init/password/send/sms", summary="初始化所选用户密码并发送通知短信")
|
||||
async def post_users_init_password(
|
||||
request: Request,
|
||||
ids: IdList = Depends(),
|
||||
@ -122,7 +122,7 @@ async def post_users_init_password(
|
||||
return SuccessResponse(await crud.UserDal(auth.db).init_password_send_sms(ids.ids, rd))
|
||||
|
||||
|
||||
@app.post("/users/init/password/send/email/", summary="初始化所选用户密码并发送通知邮件")
|
||||
@app.post("/users/init/password/send/email", summary="初始化所选用户密码并发送通知邮件")
|
||||
async def post_users_init_password_send_email(
|
||||
request: Request,
|
||||
ids: IdList = Depends(),
|
||||
@ -132,7 +132,7 @@ async def post_users_init_password_send_email(
|
||||
return SuccessResponse(await crud.UserDal(auth.db).init_password_send_email(ids.ids, rd))
|
||||
|
||||
|
||||
@app.put("/users/wx/server/openid/", summary="更新当前用户服务端微信平台openid")
|
||||
@app.put("/users/wx/server/openid", summary="更新当前用户服务端微信平台openid")
|
||||
async def put_user_wx_server_openid(code: str, auth: Auth = Depends(AllUserAuth()), rd: Redis = Depends(redis_getter)):
|
||||
result = await crud.UserDal(auth.db).update_wx_server_openid(code, auth.user, rd)
|
||||
return SuccessResponse(result)
|
||||
@ -141,7 +141,7 @@ async def put_user_wx_server_openid(code: str, auth: Auth = Depends(AllUserAuth(
|
||||
###########################################################
|
||||
# 角色管理
|
||||
###########################################################
|
||||
@app.get("/roles/", summary="获取角色列表")
|
||||
@app.get("/roles", summary="获取角色列表")
|
||||
async def get_roles(
|
||||
params: RoleParams = Depends(),
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.role.list"]))
|
||||
@ -151,12 +151,12 @@ async def get_roles(
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.post("/roles/", summary="创建角色信息")
|
||||
@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))
|
||||
|
||||
|
||||
@app.delete("/roles/", summary="批量删除角色", description="硬删除, 如果存在用户关联则无法删除")
|
||||
@app.delete("/roles", summary="批量删除角色", description="硬删除, 如果存在用户关联则无法删除")
|
||||
async def delete_roles(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAuth(permissions=["auth.role.delete"]))):
|
||||
if 1 in ids.ids:
|
||||
return ErrorResponse("不能删除管理员角色")
|
||||
@ -164,7 +164,7 @@ async def delete_roles(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAu
|
||||
return SuccessResponse("删除成功")
|
||||
|
||||
|
||||
@app.put("/roles/{data_id}/", summary="更新角色信息")
|
||||
@app.put("/roles/{data_id}", summary="更新角色信息")
|
||||
async def put_role(
|
||||
data_id: int,
|
||||
data: schemas.RoleIn,
|
||||
@ -175,12 +175,12 @@ async def put_role(
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/roles/options/", summary="获取角色选择项")
|
||||
@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())
|
||||
|
||||
|
||||
@app.get("/roles/{data_id}/", summary="获取角色信息")
|
||||
@app.get("/roles/{data_id}", summary="获取角色信息")
|
||||
async def get_role(
|
||||
data_id: int,
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.role.view", "auth.role.update"]))
|
||||
@ -194,39 +194,39 @@ async def get_role(
|
||||
###########################################################
|
||||
# 菜单管理
|
||||
###########################################################
|
||||
@app.get("/menus/", summary="获取菜单列表")
|
||||
@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)
|
||||
|
||||
|
||||
@app.get("/menus/tree/options/", summary="获取菜单树选择项,添加/修改菜单时使用")
|
||||
@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)
|
||||
|
||||
|
||||
@app.get("/menus/role/tree/options/", summary="获取菜单列表树信息,角色权限使用")
|
||||
@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))
|
||||
|
||||
|
||||
@app.post("/menus/", summary="创建菜单信息")
|
||||
@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))
|
||||
|
||||
|
||||
@app.delete("/menus/", summary="批量删除菜单", description="硬删除, 如果存在角色关联则无法删除")
|
||||
@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("删除成功")
|
||||
|
||||
|
||||
@app.put("/menus/{data_id}/", summary="更新菜单信息")
|
||||
@app.put("/menus/{data_id}", summary="更新菜单信息")
|
||||
async def put_menus(
|
||||
data_id: int,
|
||||
data: schemas.Menu, auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.update"]))
|
||||
@ -234,7 +234,7 @@ async def put_menus(
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/menus/{data_id}/", summary="获取菜单信息")
|
||||
@app.get("/menus/{data_id}", summary="获取菜单信息")
|
||||
async def put_menus(
|
||||
data_id: int,
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.view", "auth.menu.update"]))
|
||||
@ -243,7 +243,7 @@ async def put_menus(
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_data(data_id, None, v_schema=schema))
|
||||
|
||||
|
||||
@app.get("/role/menus/tree/{role_id}/", summary="获取菜单列表树信息以及角色菜单权限ID,角色权限使用")
|
||||
@app.get("/role/menus/tree/{role_id}", summary="获取菜单列表树信息以及角色菜单权限ID,角色权限使用")
|
||||
async def get_role_menu_tree(
|
||||
role_id: int,
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.role.create", "auth.role.update"]))
|
||||
|
@ -5,11 +5,13 @@
|
||||
# @File : crud.py
|
||||
# @IDE : PyCharm
|
||||
# @desc : 帮助中心 - 增删改查
|
||||
from typing import List
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from core.crud import DalBase
|
||||
from . import models, schemas
|
||||
from apps.vadmin.auth import models as vadminAuthModels
|
||||
|
||||
|
||||
class IssueDal(DalBase):
|
||||
@ -30,5 +32,34 @@ class IssueDal(DalBase):
|
||||
class IssueCategoryDal(DalBase):
|
||||
|
||||
def __init__(self, db: AsyncSession):
|
||||
super(IssueCategoryDal, self).__init__(db, models.VadminIssueCategory, schemas.IssueCategorySimpleOut)
|
||||
key_models = {
|
||||
# 外键字段名,也可以自定义
|
||||
"create_user": {
|
||||
# 外键对应的orm模型
|
||||
"model": vadminAuthModels.VadminUser,
|
||||
# 如果对同一个模型只有一个外键关联时,下面这个 onclause 可以省略不写,一个以上时必须写,需要分清楚要查询的是哪个
|
||||
# 这里其实可以省略不写,但是为了演示这里写出来了
|
||||
"onclause": models.VadminIssueCategory.create_user_id == vadminAuthModels.VadminUser.id
|
||||
}
|
||||
}
|
||||
super(IssueCategoryDal, self).__init__(
|
||||
db,
|
||||
models.VadminIssueCategory,
|
||||
schemas.IssueCategorySimpleOut,
|
||||
key_models
|
||||
)
|
||||
|
||||
async def test(self):
|
||||
"""
|
||||
v_join_query 示例方法
|
||||
获取用户名称包含李 创建出的常见问题类别
|
||||
"""
|
||||
v_join_query = {
|
||||
# 与 key_models 中定义的外键字段名定义的一样
|
||||
"create_user": {
|
||||
# 外键表字段名:查询值
|
||||
"name": ("like", "李")
|
||||
}
|
||||
}
|
||||
v_options = [joinedload(self.model.create_user)]
|
||||
datas = self.get_datas(limit=0, v_join_query=v_join_query, v_options=v_options)
|
||||
|
@ -21,8 +21,8 @@ class VadminIssueCategory(BaseModel):
|
||||
|
||||
issues = relationship("VadminIssue", back_populates='category')
|
||||
|
||||
user_id = Column(ForeignKey("vadmin_auth_user.id", ondelete='SET NULL'), comment="创建人")
|
||||
user = relationship("VadminUser", foreign_keys=user_id)
|
||||
create_user_id = Column(ForeignKey("vadmin_auth_user.id", ondelete='SET NULL'), comment="创建人")
|
||||
create_user = relationship("VadminUser", foreign_keys=create_user_id)
|
||||
|
||||
|
||||
class VadminIssue(BaseModel):
|
||||
@ -37,6 +37,6 @@ class VadminIssue(BaseModel):
|
||||
view_number = Column(Integer, default=0, comment="查看次数")
|
||||
is_active = Column(Boolean, default=True, comment="是否可见")
|
||||
|
||||
user_id = Column(ForeignKey("vadmin_auth_user.id", ondelete='SET NULL'), comment="创建人")
|
||||
user = relationship("VadminUser", foreign_keys=user_id)
|
||||
create_user_id = Column(ForeignKey("vadmin_auth_user.id", ondelete='SET NULL'), comment="创建人")
|
||||
create_user = relationship("VadminUser", foreign_keys=create_user_id)
|
||||
|
||||
|
@ -15,7 +15,7 @@ from .issue_category import IssueCategorySimpleOut
|
||||
|
||||
class Issue(BaseModel):
|
||||
category_id: Optional[int] = None
|
||||
user_id: Optional[int] = None
|
||||
create_user_id: Optional[int] = None
|
||||
|
||||
title: Optional[str] = None
|
||||
content: Optional[str] = None
|
||||
@ -33,7 +33,7 @@ class IssueSimpleOut(Issue):
|
||||
|
||||
|
||||
class IssueListOut(IssueSimpleOut):
|
||||
user: UserSimpleOut
|
||||
create_user: UserSimpleOut
|
||||
category: IssueCategorySimpleOut
|
||||
|
||||
class Config:
|
||||
|
@ -18,7 +18,7 @@ class IssueCategory(BaseModel):
|
||||
platform: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
user_id: Optional[int] = None
|
||||
create_user_id: Optional[int] = None
|
||||
|
||||
|
||||
class IssueCategorySimpleOut(IssueCategory):
|
||||
@ -31,7 +31,7 @@ class IssueCategorySimpleOut(IssueCategory):
|
||||
|
||||
|
||||
class IssueCategoryListOut(IssueCategorySimpleOut):
|
||||
user: UserSimpleOut
|
||||
create_user: UserSimpleOut
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
@ -16,7 +16,7 @@ class IssueCategoryPlatformOut(BaseModel):
|
||||
name: Optional[str] = None
|
||||
platform: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
user_id: Optional[int] = None
|
||||
create_user_id: Optional[int] = None
|
||||
|
||||
id: int
|
||||
update_datetime: DatetimeStr
|
||||
|
@ -22,91 +22,95 @@ app = APIRouter()
|
||||
###########################################################
|
||||
# 类别管理
|
||||
###########################################################
|
||||
@app.get("/issue/categorys/", summary="获取类别列表")
|
||||
@app.get("/issue/categorys", summary="获取类别列表")
|
||||
async def get_issue_categorys(p: params.IssueCategoryParams = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
model = models.VadminIssueCategory
|
||||
options = [joinedload(model.user)]
|
||||
options = [joinedload(model.create_user)]
|
||||
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)
|
||||
|
||||
|
||||
@app.get("/issue/categorys/options/", summary="获取类别选择项")
|
||||
@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))
|
||||
|
||||
|
||||
@app.post("/issue/categorys/", summary="创建类别")
|
||||
@app.post("/issue/categorys", summary="创建类别")
|
||||
async def create_issue_category(data: schemas.IssueCategory, auth: Auth = Depends(AllUserAuth())):
|
||||
data.user_id = auth.user.id
|
||||
data.create_user_id = auth.user.id
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).create_data(data=data))
|
||||
|
||||
|
||||
@app.delete("/issue/categorys/", summary="批量删除类别", description="硬删除")
|
||||
@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("删除成功")
|
||||
|
||||
|
||||
@app.put("/issue/categorys/{data_id}/", summary="更新类别信息")
|
||||
@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))
|
||||
|
||||
|
||||
@app.get("/issue/categorys/{data_id}/", summary="获取类别信息")
|
||||
@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))
|
||||
|
||||
|
||||
@app.get("/issue/categorys/platform/{platform}/", summary="获取平台中的常见问题类别列表")
|
||||
@app.get("/issue/categorys/platform/{platform}", summary="获取平台中的常见问题类别列表")
|
||||
async def get_issue_category_platform(platform: str, db: AsyncSession = Depends(db_getter)):
|
||||
model = models.VadminIssueCategory
|
||||
options = [joinedload(model.issues)]
|
||||
schema = schemas.IssueCategoryPlatformOut
|
||||
result = await crud.IssueCategoryDal(db).\
|
||||
get_datas(platform=platform, is_active=True, v_schema=schema, v_options=options)
|
||||
result = await crud.IssueCategoryDal(db).get_datas(
|
||||
platform=platform,
|
||||
is_active=True,
|
||||
v_schema=schema,
|
||||
v_options=options
|
||||
)
|
||||
return SuccessResponse(result)
|
||||
|
||||
|
||||
###########################################################
|
||||
# 问题管理
|
||||
###########################################################
|
||||
@app.get("/issues/", summary="获取问题列表")
|
||||
@app.get("/issues", summary="获取问题列表")
|
||||
async def get_issues(p: params.IssueParams = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
model = models.VadminIssue
|
||||
options = [joinedload(model.user), joinedload(model.category)]
|
||||
options = [joinedload(model.create_user), joinedload(model.category)]
|
||||
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)
|
||||
|
||||
|
||||
@app.post("/issues/", summary="创建问题")
|
||||
@app.post("/issues", summary="创建问题")
|
||||
async def create_issue(data: schemas.Issue, auth: Auth = Depends(AllUserAuth())):
|
||||
data.user_id = auth.user.id
|
||||
data.create_user_id = auth.user.id
|
||||
return SuccessResponse(await crud.IssueDal(auth.db).create_data(data=data))
|
||||
|
||||
|
||||
@app.delete("/issues/", summary="批量删除问题", description="硬删除")
|
||||
@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("删除成功")
|
||||
|
||||
|
||||
@app.put("/issues/{data_id}/", summary="更新问题信息")
|
||||
@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))
|
||||
|
||||
|
||||
@app.get("/issues/{data_id}/", summary="获取问题信息")
|
||||
@app.get("/issues/{data_id}", summary="获取问题信息")
|
||||
async def get_issue(data_id: int, db: AsyncSession = Depends(db_getter)):
|
||||
schema = schemas.IssueSimpleOut
|
||||
return SuccessResponse(await crud.IssueDal(db).get_data(data_id, v_schema=schema))
|
||||
|
||||
|
||||
@app.get("/issues/add/view/number/{data_id}/", summary="更新常见问题查看次数+1")
|
||||
@app.get("/issues/add/view/number/{data_id}", summary="更新常见问题查看次数+1")
|
||||
async def issue_add_view_number(data_id: int, db: AsyncSession = Depends(db_getter)):
|
||||
return SuccessResponse(await crud.IssueDal(db).add_view_number(data_id))
|
||||
|
@ -19,14 +19,14 @@ app = APIRouter()
|
||||
###########################################################
|
||||
# 日志管理
|
||||
###########################################################
|
||||
@app.get("/logins/", summary="获取登录日志列表")
|
||||
@app.get("/logins", summary="获取登录日志列表")
|
||||
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)
|
||||
|
||||
|
||||
@app.get("/operations/", summary="获取操作日志列表")
|
||||
@app.get("/operations", summary="获取操作日志列表")
|
||||
async def get_record_operation(
|
||||
p: OperationParams = Depends(),
|
||||
db: DatabaseManage = Depends(get_database),
|
||||
@ -37,7 +37,7 @@ async def get_record_operation(
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.get("/sms/send/list/", summary="获取短信发送列表")
|
||||
@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())
|
||||
@ -47,6 +47,6 @@ async def get_sms_send_list(p: SMSParams = Depends(), auth: Auth = Depends(AllUs
|
||||
###########################################################
|
||||
# 日志分析
|
||||
###########################################################
|
||||
@app.get("/analysis/user/login/distribute/", summary="获取用户登录分布情况列表")
|
||||
@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())
|
||||
|
@ -95,7 +95,7 @@ class SettingsDal(DalBase):
|
||||
if ico.config_value == web_ico:
|
||||
continue
|
||||
# 将上传的ico路径替换到static/system/favicon.ico文件
|
||||
FileManage.copy(value, os.path.join(STATIC_ROOT, "system/favicon.ico"))
|
||||
await FileManage.async_copy(value, os.path.join(STATIC_ROOT, "system/favicon.ico"))
|
||||
sql = update(self.model).where(self.model.config_key == "web_ico").values(config_value=web_ico)
|
||||
await self.db.execute(sql)
|
||||
else:
|
||||
|
@ -28,25 +28,25 @@ app = APIRouter()
|
||||
###########################################################
|
||||
# 字典类型管理
|
||||
###########################################################
|
||||
@app.get("/dict/types/", summary="获取字典类型列表")
|
||||
@app.get("/dict/types", summary="获取字典类型列表")
|
||||
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)
|
||||
|
||||
|
||||
@app.post("/dict/types/", summary="创建字典类型")
|
||||
@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))
|
||||
|
||||
|
||||
@app.delete("/dict/types/", summary="批量删除字典类型")
|
||||
@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("删除成功")
|
||||
|
||||
|
||||
@app.post("/dict/types/details/", summary="获取多个字典类型下的字典元素列表")
|
||||
@app.post("/dict/types/details", summary="获取多个字典类型下的字典元素列表")
|
||||
async def post_dicts_details(
|
||||
auth: Auth = Depends(AllUserAuth()),
|
||||
dict_types: List[str] = Body(None, title="字典元素列表", description="查询字典元素列表")
|
||||
@ -55,17 +55,17 @@ async def post_dicts_details(
|
||||
return SuccessResponse(datas)
|
||||
|
||||
|
||||
@app.get("/dict/types/options/", summary="获取字典类型选择项")
|
||||
@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())
|
||||
|
||||
|
||||
@app.put("/dict/types/{data_id}/", summary="更新字典类型")
|
||||
@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))
|
||||
|
||||
|
||||
@app.get("/dict/types/{data_id}/", summary="获取字典类型详细")
|
||||
@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))
|
||||
@ -74,12 +74,12 @@ async def get_dict_type(data_id: int, auth: Auth = Depends(AllUserAuth())):
|
||||
###########################################################
|
||||
# 字典元素管理
|
||||
###########################################################
|
||||
@app.post("/dict/details/", summary="创建字典元素")
|
||||
@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))
|
||||
|
||||
|
||||
@app.get("/dict/details/", summary="获取单个字典类型下的字典元素列表,分页")
|
||||
@app.get("/dict/details", summary="获取单个字典类型下的字典元素列表,分页")
|
||||
async def get_dict_details(params: DictDetailParams = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
if not params.dict_type_id:
|
||||
return ErrorResponse(msg="未获取到字典类型!")
|
||||
@ -88,18 +88,18 @@ async def get_dict_details(params: DictDetailParams = Depends(), auth: Auth = De
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.delete("/dict/details/", summary="批量删除字典元素", description="硬删除")
|
||||
@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("删除成功")
|
||||
|
||||
|
||||
@app.put("/dict/details/{data_id}/", summary="更新字典元素")
|
||||
@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))
|
||||
|
||||
|
||||
@app.get("/dict/details/{data_id}/", summary="获取字典元素详情")
|
||||
@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))
|
||||
@ -108,7 +108,7 @@ async def get_dict_detail(data_id: int, auth: Auth = Depends(AllUserAuth())):
|
||||
###########################################################
|
||||
# 文件上传管理
|
||||
###########################################################
|
||||
@app.post("/upload/image/to/oss/", summary="上传图片到阿里云OSS")
|
||||
@app.post("/upload/image/to/oss", summary="上传图片到阿里云OSS")
|
||||
async def upload_image_to_oss(file: UploadFile, path: str = Form(...)):
|
||||
result = await AliyunOSS(BucketConf(**ALIYUN_OSS)).upload_image(path, file)
|
||||
if not result:
|
||||
@ -116,7 +116,7 @@ async def upload_image_to_oss(file: UploadFile, path: str = Form(...)):
|
||||
return SuccessResponse(result)
|
||||
|
||||
|
||||
@app.post("/upload/image/to/local/", summary="上传图片到本地")
|
||||
@app.post("/upload/image/to/local", summary="上传图片到本地")
|
||||
async def upload_image_to_local(file: UploadFile, path: str = Form(...)):
|
||||
manage = FileManage(file, path)
|
||||
path = await manage.save_image_local()
|
||||
@ -126,7 +126,7 @@ async def upload_image_to_local(file: UploadFile, path: str = Form(...)):
|
||||
###########################################################
|
||||
# 短信服务管理
|
||||
###########################################################
|
||||
@app.post("/sms/send/", summary="发送短信验证码(阿里云服务)")
|
||||
@app.post("/sms/send", summary="发送短信验证码(阿里云服务)")
|
||||
async def sms_send(telephone: str, rd: Redis = Depends(redis_getter)):
|
||||
sms = AliyunSMS(rd, telephone)
|
||||
return SuccessResponse(await sms.main_async(AliyunSMS.Scene.login))
|
||||
@ -135,31 +135,31 @@ async def sms_send(telephone: str, rd: Redis = Depends(redis_getter)):
|
||||
###########################################################
|
||||
# 系统配置管理
|
||||
###########################################################
|
||||
@app.get("/settings/tabs/", summary="获取系统配置标签列表")
|
||||
@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))
|
||||
|
||||
|
||||
@app.get("/settings/tabs/values/", summary="获取系统配置标签下的信息")
|
||||
@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))
|
||||
|
||||
|
||||
@app.put("/settings/tabs/values/", summary="更新系统配置信息")
|
||||
@app.put("/settings/tabs/values", summary="更新系统配置信息")
|
||||
async def put_settings_tabs_values(datas: dict = Body(...), auth: Auth = Depends(FullAdminAuth()), rd: Redis = Depends(redis_getter)):
|
||||
return SuccessResponse(await crud.SettingsDal(auth.db).update_datas(datas, rd))
|
||||
|
||||
|
||||
@app.get("/settings/base/config/", summary="获取系统基础配置", description="每次进入系统中时使用")
|
||||
@app.get("/settings/base/config", summary="获取系统基础配置", description="每次进入系统中时使用")
|
||||
async def get_setting_base_config(db: AsyncSession = Depends(db_getter)):
|
||||
return SuccessResponse(await crud.SettingsDal(db).get_base_config())
|
||||
|
||||
|
||||
@app.get("/settings/privacy/", summary="获取隐私协议")
|
||||
@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)
|
||||
|
||||
|
||||
@app.get("/settings/agreement/", summary="获取用户协议")
|
||||
@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)
|
||||
|
@ -19,7 +19,7 @@ app = APIRouter()
|
||||
###########################################################
|
||||
# 工作区管理
|
||||
###########################################################
|
||||
@app.get("/total/", summary="获取统计")
|
||||
@app.get("/total", summary="获取统计")
|
||||
async def get_total(auth: Auth = Depends(AllUserAuth())):
|
||||
data = {
|
||||
"project": 40,
|
||||
@ -29,7 +29,7 @@ async def get_total(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/project/", summary="获取项目")
|
||||
@app.get("/project", summary="获取项目")
|
||||
async def get_project():
|
||||
data = [
|
||||
{
|
||||
@ -84,7 +84,7 @@ async def get_project():
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/dynamic/", summary="获取动态")
|
||||
@app.get("/dynamic", summary="获取动态")
|
||||
async def get_dynamic():
|
||||
data = [
|
||||
{
|
||||
@ -99,7 +99,7 @@ async def get_dynamic():
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/team/", summary="获取团队信息")
|
||||
@app.get("/team", summary="获取团队信息")
|
||||
async def get_team():
|
||||
data = [
|
||||
{
|
||||
@ -130,7 +130,7 @@ async def get_team():
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/shortcuts/", summary="获取快捷操作")
|
||||
@app.get("/shortcuts", summary="获取快捷操作")
|
||||
async def get_shortcuts():
|
||||
data = [
|
||||
{
|
||||
|
@ -31,7 +31,6 @@ def create_async_engine_session(database_url: str):
|
||||
pool_timeout=20, # 池中没有连接最多等待的时间,否则报错
|
||||
pool_recycle=-1 # 多久之后对线程池中的线程进行一次连接的回收(重置)
|
||||
|
||||
:param database_type: 数据库类型
|
||||
:param database_url: 数据库地址
|
||||
:return:
|
||||
"""
|
||||
|
@ -47,7 +47,7 @@ def register_exception(app: FastAPI):
|
||||
print(exc.desc)
|
||||
print(exc.msg)
|
||||
return JSONResponse(
|
||||
status_code=200,
|
||||
status_code=exc.status_code,
|
||||
content={"message": exc.msg, "code": exc.code},
|
||||
)
|
||||
|
||||
|
@ -39,7 +39,7 @@ idna==3.4
|
||||
importlib-metadata==5.0.0
|
||||
importlib-resources==5.10.0
|
||||
jmespath==0.10.0
|
||||
loguru==0.6.0
|
||||
loguru==0.7.0
|
||||
Mako==1.2.4
|
||||
MarkupSafe==2.1.1
|
||||
motor==3.1.1
|
||||
|
@ -7,7 +7,7 @@
|
||||
# @desc : 缓存
|
||||
|
||||
from typing import List
|
||||
from core import logger
|
||||
from core.logger import logger
|
||||
from core.database import db_getter
|
||||
from apps.vadmin.system.crud import SettingsTabDal
|
||||
import json
|
||||
@ -18,7 +18,7 @@ from utils import status
|
||||
|
||||
class Cache:
|
||||
|
||||
DEFAULT_TAB_NAMES = ["wx_server", "aliyun_sms", "aliyun_oss"]
|
||||
DEFAULT_TAB_NAMES = ["wx_server", "aliyun_sms", "aliyun_oss", "web_email"]
|
||||
|
||||
def __init__(self, rd: Redis):
|
||||
self.rd = rd
|
||||
|
@ -4,15 +4,17 @@
|
||||
# @File : file_manage.py
|
||||
# @IDE : PyCharm
|
||||
# @desc : 保存图片到本地
|
||||
|
||||
import asyncio
|
||||
import datetime
|
||||
import os
|
||||
import shutil
|
||||
from application.settings import TEMP_DIR, STATIC_ROOT, BASE_DIR, STATIC_URL, STATIC_DIR
|
||||
from fastapi import UploadFile
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from core.exception import CustomException
|
||||
from utils.file.file_base import FileBase
|
||||
from aiopathlib import AsyncPath as Path
|
||||
from aiopathlib import AsyncPath
|
||||
import aioshutil
|
||||
|
||||
|
||||
@ -41,8 +43,7 @@ class FileManage(FileBase):
|
||||
path = self.path
|
||||
if sys.platform == "win32":
|
||||
path = self.path.replace("/", "\\")
|
||||
# save_path = os.path.join(STATIC_ROOT, path)
|
||||
save_path = Path(STATIC_ROOT) / path
|
||||
save_path = AsyncPath(STATIC_ROOT) / path
|
||||
if not await save_path.parent.exists():
|
||||
await save_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
await save_path.write_bytes(await self.file.read())
|
||||
@ -52,21 +53,20 @@ class FileManage(FileBase):
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
async def save_tmp_file(file: UploadFile):
|
||||
async def save_tmp_file(file: UploadFile) -> str:
|
||||
"""
|
||||
保存临时文件
|
||||
"""
|
||||
date = datetime.datetime.strftime(datetime.datetime.now(), "%Y%m%d")
|
||||
# file_dir = os.path.join(TEMP_DIR, date)
|
||||
file_dir = Path(TEMP_DIR) / date
|
||||
file_dir = AsyncPath(TEMP_DIR) / date
|
||||
if not await file_dir.exists():
|
||||
await file_dir.mkdir(parents=True, exist_ok=True)
|
||||
filename = file_dir / str(int(datetime.datetime.now().timestamp())) + file.filename
|
||||
await filename.write_bytes(await self.file.read())
|
||||
await filename.write_bytes(await file.read())
|
||||
return str(filename)
|
||||
|
||||
@staticmethod
|
||||
def copy(src: str, dst: str):
|
||||
def copy(src: str, dst: str) -> None:
|
||||
"""
|
||||
复制文件
|
||||
根目录为项目根目录,传过来的文件路径均为相对路径
|
||||
@ -79,25 +79,39 @@ class FileManage(FileBase):
|
||||
if sys.platform == "win32":
|
||||
src = src.replace("/", "\\")
|
||||
dst = dst.replace("/", "\\")
|
||||
src = os.path.join(BASE_DIR, src)
|
||||
if not os.path.exists(os.path.dirname(dst)):
|
||||
os.mkdir(os.path.dirname(dst))
|
||||
src = Path(BASE_DIR) / src
|
||||
dst = Path(dst)
|
||||
if not src.exists():
|
||||
raise CustomException("源文件不存在!")
|
||||
if not dst.parent.exists():
|
||||
dst.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(src, dst)
|
||||
|
||||
async def async_copy(src: str, dst: str):
|
||||
@staticmethod
|
||||
async def async_copy(src: str, dst: str) -> None:
|
||||
"""
|
||||
异步复制文件
|
||||
根目录为项目根目录,传过来的文件路径均为相对路径
|
||||
|
||||
:param src: 原始文件
|
||||
:param dst: 目标路径。绝对路径
|
||||
"""
|
||||
if src[0] == "/":
|
||||
src = src.lstrip("/")
|
||||
if sys.platform == "win32":
|
||||
src = src.replace("/", "\\")
|
||||
dst = dst.replace("/", "\\")
|
||||
src = Path(BASE_DIR) / src
|
||||
dst = Path(dst)
|
||||
src = AsyncPath(BASE_DIR) / src
|
||||
if not await src.exists():
|
||||
raise CustomException("源文件不存在!")
|
||||
dst = AsyncPath(dst)
|
||||
if not await dst.parent.exists():
|
||||
await dst.parent.mkdir(parents=True, exist_ok=True)
|
||||
await aioshutil.copyfile(src, dst)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# src = r"D:\ktianc\private\vv-reserve\reserve-api\static\system\2022-12-07\16703958210ab33912.ico"
|
||||
# dst = r"D:\ktianc\private\vv-reserve\reserve-api\static\system\favicon.ico"
|
||||
# shutil.copyfile(src, dst)
|
||||
pass
|
||||
_src = r"D:\programming\ktianc\project\kinit-pro\kinit-api\static\system\favicon.ico"
|
||||
_dst = r"D:\programming\ktianc\project\kinit-pro\kinit-api\static\system\2022-12-07\16703958210ab33912.ico"
|
||||
asyncio.run(FileManage.async_copy(_src, _dst))
|
||||
# FileManage.copy(_src, _dst)
|
||||
|
@ -8,18 +8,18 @@ export function login(telephone, password) {
|
||||
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 })
|
||||
return request.put('/vadmin/auth/users/wx/server/openid', {}, { params: params })
|
||||
}
|
||||
|
||||
// 使用微信一键登录
|
||||
@ -29,5 +29,5 @@ export function wxCodeLogin(code) {
|
||||
method: '2',
|
||||
platform: '1'
|
||||
}
|
||||
return request.post('/auth/wx/login/', data)
|
||||
return request.post('/auth/wx/login', data)
|
||||
}
|
||||
|
@ -2,17 +2,17 @@ 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/', {
|
||||
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')
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user