1. 更新:kinit-api:core/crud.py keys 查询多外键时需添加onclause属性
2. 修复:kinit-admin: form属性设置了ifshow无法设置值问题修复 3. 修复:kinit-admin:表格字段设置缓存问题修复
This commit is contained in:
parent
1df58c937a
commit
afa9110771
@ -162,15 +162,7 @@ export default defineComponent({
|
||||
if (v.hidden !== undefined) {
|
||||
return !v.hidden
|
||||
} else if (v.ifshow !== undefined) {
|
||||
const show = v.ifshow(unref(formModel))
|
||||
if (!show) {
|
||||
if (v.value !== undefined) {
|
||||
formModel.value[v.field] = v.value
|
||||
} else {
|
||||
formModel.value[v.field] = undefined
|
||||
}
|
||||
}
|
||||
return show
|
||||
return v.ifshow(unref(formModel))
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
@ -15,7 +15,9 @@ import { ref, PropType } from 'vue'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import draggable from 'vuedraggable'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const emit = defineEmits(['getList', 'update:tableSize'])
|
||||
@ -25,7 +27,8 @@ const props = defineProps({
|
||||
columns: {
|
||||
type: Array as PropType<any[]>,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
cacheTableHeadersKey: propTypes.string.def('')
|
||||
})
|
||||
|
||||
const handleClickRefresh = () => {
|
||||
@ -43,6 +46,15 @@ const handleCommand = (command: string) => {
|
||||
const checkAll = ref(false)
|
||||
const columns = ref(props.columns)
|
||||
const isIndeterminate = ref(true) // 如果为True,则表示为半选状态
|
||||
|
||||
// 获取表头字段默认列表
|
||||
if (props.cacheTableHeadersKey) {
|
||||
const cacheTableHeaders = wsCache.get(props.cacheTableHeadersKey)
|
||||
if (cacheTableHeaders) {
|
||||
Object.assign(columns.value, JSON.parse(cacheTableHeaders))
|
||||
}
|
||||
}
|
||||
|
||||
const handleCheckAllChange = (val: boolean) => {
|
||||
columns.value.forEach((item) => {
|
||||
if (item.disabled !== true) {
|
||||
@ -51,6 +63,7 @@ const handleCheckAllChange = (val: boolean) => {
|
||||
})
|
||||
isIndeterminate.value = false
|
||||
}
|
||||
|
||||
const handleCheckChange = () => {
|
||||
checkAll.value = columns.value.every((item) => item.show)
|
||||
if (checkAll.value) {
|
||||
|
@ -17,7 +17,10 @@ import Write from './components/Write.vue'
|
||||
import { columns } from './components/menu.data'
|
||||
import { useDictStore } from '@/store/modules/dict'
|
||||
import { selectDictLabel, DictDetail } from '@/utils/dict'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const { t } = useI18n()
|
||||
|
||||
let menuTypeOptions = ref<DictDetail[]>([])
|
||||
@ -117,9 +120,13 @@ watch(tableSize, (val) => {
|
||||
tableSize.value = val
|
||||
})
|
||||
|
||||
const route = useRouter()
|
||||
const cacheTableHeadersKey = route.currentRoute.value.fullPath
|
||||
|
||||
watch(
|
||||
columns,
|
||||
async () => {
|
||||
async (val) => {
|
||||
wsCache.set(cacheTableHeadersKey, JSON.stringify(val))
|
||||
await nextTick()
|
||||
elTableRef.value?.doLayout()
|
||||
},
|
||||
@ -139,7 +146,12 @@ watch(
|
||||
>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<RightToolbar @get-list="getList" v-model:table-size="tableSize" v-model:columns="columns" />
|
||||
<RightToolbar
|
||||
@get-list="getList"
|
||||
v-model:table-size="tableSize"
|
||||
v-model:columns="columns"
|
||||
:cache-table-headers-key="cacheTableHeadersKey"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
|
@ -17,7 +17,10 @@ import { Dialog } from '@/components/Dialog'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { RightToolbar } from '@/components/RightToolbar'
|
||||
import { Search } from '@/components/Search'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const { t } = useI18n()
|
||||
|
||||
const { register, elTableRef, tableObject, methods } = useTable({
|
||||
@ -36,7 +39,7 @@ const loading = ref(false)
|
||||
const defaultCheckedKeys = ref([])
|
||||
|
||||
// 添加事件
|
||||
const AddAction = () => {
|
||||
const addAction = () => {
|
||||
dialogTitle.value = t('exampleDemo.add')
|
||||
tableObject.currentRow = null
|
||||
dialogVisible.value = true
|
||||
@ -50,7 +53,6 @@ const updateAction = async (row: any) => {
|
||||
dialogTitle.value = '编辑'
|
||||
tableObject.currentRow = res.data
|
||||
defaultCheckedKeys.value = res.data.menus.map((item: any) => item.id)
|
||||
console.log(defaultCheckedKeys.value)
|
||||
dialogVisible.value = true
|
||||
actionType.value = 'edit'
|
||||
}
|
||||
@ -103,9 +105,13 @@ watch(tableSize, (val) => {
|
||||
tableSize.value = val
|
||||
})
|
||||
|
||||
const route = useRouter()
|
||||
const cacheTableHeadersKey = route.currentRoute.value.fullPath
|
||||
|
||||
watch(
|
||||
columns,
|
||||
async () => {
|
||||
async (val) => {
|
||||
wsCache.set(cacheTableHeadersKey, JSON.stringify(val))
|
||||
await nextTick()
|
||||
elTableRef.value?.doLayout()
|
||||
},
|
||||
@ -122,10 +128,15 @@ watch(
|
||||
<div class="mb-8px flex justify-between">
|
||||
<ElRow :gutter="10">
|
||||
<ElCol :span="1.5" v-hasPermi="['auth.role.create']">
|
||||
<ElButton type="primary" @click="AddAction">新增角色</ElButton>
|
||||
<ElButton type="primary" @click="addAction">新增角色</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<RightToolbar @get-list="getList" v-model:table-size="tableSize" v-model:columns="columns" />
|
||||
<RightToolbar
|
||||
@get-list="getList"
|
||||
v-model:table-size="tableSize"
|
||||
v-model:columns="columns"
|
||||
:cache-table-headers-key="cacheTableHeadersKey"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
|
@ -34,7 +34,10 @@ import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
import { RightToolbar } from '@/components/RightToolbar'
|
||||
import { Search } from '@/components/Search'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const { t } = useI18n()
|
||||
@ -72,7 +75,7 @@ const loading = ref(false)
|
||||
const { getList, setSearchParams, exportQueryList } = methods
|
||||
|
||||
// 添加事件
|
||||
const AddAction = () => {
|
||||
const addAction = () => {
|
||||
dialogTitle.value = t('exampleDemo.add')
|
||||
tableObject.currentRow = null
|
||||
dialogVisible.value = true
|
||||
@ -147,9 +150,13 @@ watch(tableSize, (val) => {
|
||||
tableSize.value = val
|
||||
})
|
||||
|
||||
const route = useRouter()
|
||||
const cacheTableHeadersKey = route.currentRoute.value.fullPath
|
||||
|
||||
watch(
|
||||
columns,
|
||||
async () => {
|
||||
async (val) => {
|
||||
wsCache.set(cacheTableHeadersKey, JSON.stringify(val))
|
||||
await nextTick()
|
||||
elTableRef.value?.doLayout()
|
||||
},
|
||||
@ -209,7 +216,7 @@ const handleCommand = (command: string) => {
|
||||
<div class="mb-8px flex justify-between">
|
||||
<ElRow :gutter="10">
|
||||
<ElCol :span="1.5" v-hasPermi="['auth.user.create']">
|
||||
<ElButton type="primary" @click="AddAction">新增用户</ElButton>
|
||||
<ElButton type="primary" @click="addAction">新增用户</ElButton>
|
||||
</ElCol>
|
||||
<ElCol :span="1.5" v-hasPermi="['auth.user.import']" v-if="!mobile">
|
||||
<ElButton @click="importList">批量导入用户</ElButton>
|
||||
@ -250,7 +257,12 @@ const handleCommand = (command: string) => {
|
||||
</ElDropdown>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<RightToolbar @get-list="getList" v-model:table-size="tableSize" v-model:columns="columns" />
|
||||
<RightToolbar
|
||||
@get-list="getList"
|
||||
v-model:table-size="tableSize"
|
||||
v-model:columns="columns"
|
||||
:cache-table-headers-key="cacheTableHeadersKey"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
|
@ -20,9 +20,10 @@ import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Search } from '@/components/Search'
|
||||
import { FormSetPropsType } from '@/types/form'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const { currentRoute } = useRouter()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
let dictType = currentRoute.value.query.dictType
|
||||
@ -64,7 +65,7 @@ const actionType = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
// 添加事件
|
||||
const AddAction = () => {
|
||||
const addAction = () => {
|
||||
dialogTitle.value = t('exampleDemo.add')
|
||||
tableObject.currentRow = null
|
||||
dialogVisible.value = true
|
||||
@ -126,9 +127,13 @@ const tableSize = ref('default')
|
||||
watch(tableSize, (val) => {
|
||||
tableSize.value = val
|
||||
})
|
||||
|
||||
const cacheTableHeadersKey = currentRoute.value.fullPath
|
||||
|
||||
watch(
|
||||
columns,
|
||||
async () => {
|
||||
async (val) => {
|
||||
wsCache.set(cacheTableHeadersKey, JSON.stringify(val))
|
||||
await nextTick()
|
||||
elTableRef.value?.doLayout()
|
||||
},
|
||||
@ -150,10 +155,15 @@ watch(
|
||||
<div class="mb-8px flex justify-between">
|
||||
<ElRow :gutter="10">
|
||||
<ElCol :span="1.5">
|
||||
<ElButton type="primary" @click="AddAction">{{ t('exampleDemo.add') }}</ElButton>
|
||||
<ElButton type="primary" @click="addAction">{{ t('exampleDemo.add') }}</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<RightToolbar @get-list="getList" v-model:table-size="tableSize" v-model:columns="columns" />
|
||||
<RightToolbar
|
||||
@get-list="getList"
|
||||
v-model:table-size="tableSize"
|
||||
v-model:columns="columns"
|
||||
:cache-table-headers-key="cacheTableHeadersKey"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
|
@ -18,9 +18,10 @@ import { ElButton, ElMessage, ElRow, ElCol } from 'element-plus'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Search } from '@/components/Search'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const { push } = useRouter()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const { register, elTableRef, tableObject, methods } = useTable({
|
||||
@ -38,7 +39,7 @@ const actionType = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
// 添加事件
|
||||
const AddAction = () => {
|
||||
const addAction = () => {
|
||||
dialogTitle.value = t('exampleDemo.add')
|
||||
tableObject.currentRow = null
|
||||
dialogVisible.value = true
|
||||
@ -104,9 +105,14 @@ const tableSize = ref('default')
|
||||
watch(tableSize, (val) => {
|
||||
tableSize.value = val
|
||||
})
|
||||
|
||||
const route = useRouter()
|
||||
const cacheTableHeadersKey = route.currentRoute.value.fullPath
|
||||
|
||||
watch(
|
||||
columns,
|
||||
async () => {
|
||||
async (val) => {
|
||||
wsCache.set(cacheTableHeadersKey, JSON.stringify(val))
|
||||
await nextTick()
|
||||
elTableRef.value?.doLayout()
|
||||
},
|
||||
@ -123,10 +129,15 @@ watch(
|
||||
<div class="mb-8px flex justify-between">
|
||||
<ElRow :gutter="10">
|
||||
<ElCol :span="1.5">
|
||||
<ElButton type="primary" @click="AddAction">{{ t('exampleDemo.add') }}</ElButton>
|
||||
<ElButton type="primary" @click="addAction">{{ t('exampleDemo.add') }}</ElButton>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
<RightToolbar @get-list="getList" v-model:table-size="tableSize" v-model:columns="columns" />
|
||||
<RightToolbar
|
||||
@get-list="getList"
|
||||
v-model:table-size="tableSize"
|
||||
v-model:columns="columns"
|
||||
:cache-table-headers-key="cacheTableHeadersKey"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
|
@ -13,6 +13,10 @@ import { Search } from '@/components/Search'
|
||||
import { selectDictLabel, DictDetail } from '@/utils/dict'
|
||||
import { useDictStore } from '@/store/modules/dict'
|
||||
import { FormSetPropsType } from '@/types/form'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
|
||||
const { register, elTableRef, tableObject, methods } = useTable({
|
||||
getListApi: getRecordLoginListApi,
|
||||
@ -60,9 +64,13 @@ watch(tableSize, (val) => {
|
||||
tableSize.value = val
|
||||
})
|
||||
|
||||
const route = useRouter()
|
||||
const cacheTableHeadersKey = route.currentRoute.value.fullPath
|
||||
|
||||
watch(
|
||||
columns,
|
||||
async () => {
|
||||
async (val) => {
|
||||
wsCache.set(cacheTableHeadersKey, JSON.stringify(val))
|
||||
await nextTick()
|
||||
elTableRef.value?.doLayout()
|
||||
},
|
||||
@ -85,7 +93,12 @@ getList()
|
||||
|
||||
<div class="mb-8px flex justify-between">
|
||||
<ElRow />
|
||||
<RightToolbar @get-list="getList" v-model:table-size="tableSize" v-model:columns="columns" />
|
||||
<RightToolbar
|
||||
@get-list="getList"
|
||||
v-model:table-size="tableSize"
|
||||
v-model:columns="columns"
|
||||
:cache-table-headers-key="cacheTableHeadersKey"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
|
@ -10,6 +10,10 @@ import { RightToolbar } from '@/components/RightToolbar'
|
||||
import { Dialog } from '@/components/Dialog'
|
||||
import Detail from './components/Detail.vue'
|
||||
import { Search } from '@/components/Search'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
|
||||
const { register, elTableRef, tableObject, methods } = useTable({
|
||||
getListApi: getRecordOperationListApi,
|
||||
@ -38,9 +42,13 @@ watch(tableSize, (val) => {
|
||||
tableSize.value = val
|
||||
})
|
||||
|
||||
const route = useRouter()
|
||||
const cacheTableHeadersKey = route.currentRoute.value.fullPath
|
||||
|
||||
watch(
|
||||
columns,
|
||||
async () => {
|
||||
async (val) => {
|
||||
wsCache.set(cacheTableHeadersKey, JSON.stringify(val))
|
||||
await nextTick()
|
||||
elTableRef.value?.doLayout()
|
||||
},
|
||||
@ -56,7 +64,12 @@ watch(
|
||||
|
||||
<div class="mb-8px flex justify-between">
|
||||
<ElRow />
|
||||
<RightToolbar @get-list="getList" v-model:table-size="tableSize" v-model:columns="columns" />
|
||||
<RightToolbar
|
||||
@get-list="getList"
|
||||
v-model:table-size="tableSize"
|
||||
v-model:columns="columns"
|
||||
:cache-table-headers-key="cacheTableHeadersKey"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
|
@ -10,7 +10,6 @@ import type { UploadProps } from 'element-plus'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { config } from '@/config/axios/config'
|
||||
|
||||
const props = defineProps({
|
||||
tabId: propTypes.number
|
||||
@ -80,9 +79,8 @@ const getData = async () => {
|
||||
const appStore = useAppStore()
|
||||
const { wsCache } = useCache()
|
||||
const loading = ref(false)
|
||||
const { token } = config
|
||||
|
||||
const _token = wsCache.get(token)
|
||||
const token = wsCache.get(appStore.getToken)
|
||||
|
||||
const save = async () => {
|
||||
const formRef = unref(elFormRef)
|
||||
@ -122,7 +120,7 @@ getData()
|
||||
:on-success="handleLogoUploadSuccess"
|
||||
accept="image/jpeg,image/gif,image/png"
|
||||
name="file"
|
||||
:headers="{ Authorization: _token }"
|
||||
:headers="{ Authorization: token }"
|
||||
>
|
||||
<img v-if="form.web_logo" :src="form.web_logo" class="logo-image" />
|
||||
<ElIcon v-else class="logo-image-uploader-icon"
|
||||
@ -141,7 +139,7 @@ getData()
|
||||
:on-success="handleICOUploadSuccess"
|
||||
accept="image/x-icon"
|
||||
name="file"
|
||||
:headers="{ Authorization: _token }"
|
||||
:headers="{ Authorization: token }"
|
||||
>
|
||||
<img v-if="form.web_ico" :src="form.web_ico" class="ico-image" />
|
||||
<ElIcon v-else class="ico-image-uploader-icon"
|
||||
|
@ -6,7 +6,7 @@
|
||||
# @IDE : PyCharm
|
||||
# @desc : 增删改查
|
||||
|
||||
from typing import List
|
||||
from typing import List, Any
|
||||
from aioredis import Redis
|
||||
from fastapi import UploadFile
|
||||
from core.exception import CustomException
|
||||
@ -42,7 +42,13 @@ class UserDal(DalBase):
|
||||
def __init__(self, db: AsyncSession):
|
||||
super(UserDal, self).__init__(db, models.VadminUser, schemas.UserSimpleOut)
|
||||
|
||||
async def create_data(self, data: schemas.UserIn, return_obj: bool = False, options: list = None, schema=None):
|
||||
async def create_data(
|
||||
self,
|
||||
data: schemas.UserIn,
|
||||
v_options: list = None,
|
||||
v_return_obj: bool = False,
|
||||
v_schema: Any = None
|
||||
):
|
||||
"""
|
||||
创建用户
|
||||
"""
|
||||
@ -55,12 +61,12 @@ class UserDal(DalBase):
|
||||
for data_id in data.role_ids:
|
||||
obj.roles.append(await RoleDal(db=self.db).get_data(data_id=data_id))
|
||||
await self.flush(obj)
|
||||
if options:
|
||||
obj = await self.get_data(obj.id, options=options)
|
||||
if return_obj:
|
||||
if v_options:
|
||||
obj = await self.get_data(obj.id, v_options=v_options)
|
||||
if v_return_obj:
|
||||
return obj
|
||||
if schema:
|
||||
return schema.from_orm(obj).dict()
|
||||
if v_schema:
|
||||
return v_schema.from_orm(obj).dict()
|
||||
return self.out_dict(obj)
|
||||
|
||||
async def reset_current_password(self, user: models.VadminUser, data: schemas.ResetPwd):
|
||||
@ -225,24 +231,36 @@ class RoleDal(DalBase):
|
||||
def __init__(self, db: AsyncSession):
|
||||
super(RoleDal, self).__init__(db, models.VadminRole, schemas.RoleSimpleOut)
|
||||
|
||||
async def create_data(self, data: schemas.RoleIn, return_obj: bool = False, options: list = None, schema=None):
|
||||
async def create_data(
|
||||
self,
|
||||
data: schemas.RoleIn,
|
||||
v_options: list = None,
|
||||
v_return_obj: bool = False,
|
||||
v_schema: Any = None
|
||||
):
|
||||
"""创建数据"""
|
||||
obj = self.model(**data.dict(exclude={'menu_ids'}))
|
||||
for data_id in data.menu_ids:
|
||||
obj.menus.append(await MenuDal(db=self.db).get_data(data_id=data_id))
|
||||
obj.menus.append(await MenuDal(db=self.db).get_data(data_id))
|
||||
await self.flush(obj)
|
||||
if options:
|
||||
obj = await self.get_data(obj.id, options=options)
|
||||
if return_obj:
|
||||
if v_options:
|
||||
obj = await self.get_data(obj.id, v_options=v_options)
|
||||
if v_return_obj:
|
||||
return obj
|
||||
if schema:
|
||||
return schema.from_orm(obj).dict()
|
||||
if v_schema:
|
||||
return v_schema.from_orm(obj).dict()
|
||||
return self.out_dict(await self.get_data(obj.id))
|
||||
|
||||
async def put_data(self, data_id: int, data: schemas.RoleIn, return_obj: bool = False, options: list = None,
|
||||
schema=None):
|
||||
async def put_data(
|
||||
self,
|
||||
data_id: int,
|
||||
data: schemas.RoleIn,
|
||||
v_options: list = None,
|
||||
v_return_obj: bool = False,
|
||||
v_schema: Any = None
|
||||
):
|
||||
"""更新单个数据"""
|
||||
obj = await self.get_data(data_id, options=[self.model.menus])
|
||||
obj = await self.get_data(data_id, v_options=[self.model.menus])
|
||||
obj_dict = jsonable_encoder(data)
|
||||
for key, value in obj_dict.items():
|
||||
if key == "menu_ids":
|
||||
@ -254,14 +272,14 @@ class RoleDal(DalBase):
|
||||
setattr(obj, key, value)
|
||||
await self.db.flush()
|
||||
await self.db.refresh(obj)
|
||||
if return_obj:
|
||||
if v_return_obj:
|
||||
return obj
|
||||
if schema:
|
||||
return schema.from_orm(obj).dict()
|
||||
if v_schema:
|
||||
return v_schema.from_orm(obj).dict()
|
||||
return self.out_dict(obj)
|
||||
|
||||
async def get_role_menu_tree(self, role_id: int):
|
||||
role = await self.get_data(role_id, options=[self.model.menus])
|
||||
role = await self.get_data(role_id, v_options=[self.model.menus])
|
||||
return [i.id for i in role.menus]
|
||||
|
||||
async def get_select_datas(self):
|
||||
@ -283,9 +301,9 @@ class MenuDal(DalBase):
|
||||
3:获取菜单树列表,角色添加菜单权限时使用
|
||||
"""
|
||||
if mode == 3:
|
||||
sql = select(self.model).where(self.model.disabled == 0)
|
||||
sql = select(self.model).where(self.model.disabled == 0, self.model.delete_datetime.is_(None))
|
||||
else:
|
||||
sql = select(self.model)
|
||||
sql = select(self.model).where(self.model.delete_datetime.is_(None))
|
||||
queryset = await self.db.execute(sql)
|
||||
datas = queryset.scalars().all()
|
||||
roots = filter(lambda i: not i.parent_id, datas)
|
||||
@ -310,13 +328,14 @@ class MenuDal(DalBase):
|
||||
}
|
||||
"""
|
||||
if any([i.is_admin for i in user.roles]):
|
||||
sql = select(self.model).where(self.model.disabled == 0, self.model.menu_type != "2")
|
||||
sql = select(self.model)\
|
||||
.where(self.model.disabled == 0, self.model.menu_type != "2", self.model.delete_datetime.is_(None))
|
||||
queryset = await self.db.execute(sql)
|
||||
datas = queryset.scalars().all()
|
||||
else:
|
||||
datas = set()
|
||||
for role in user.roles:
|
||||
role_obj = await RoleDal(self.db).get_data(role.id, options=[models.VadminRole.menus])
|
||||
role_obj = await RoleDal(self.db).get_data(role.id, v_options=[models.VadminRole.menus])
|
||||
for menu in role_obj.menus:
|
||||
# 该路由没有被禁用,并且菜单不是按钮
|
||||
if not menu.disabled and menu.menu_type != "2":
|
||||
|
@ -18,8 +18,13 @@ class UserParams(QueryParams):
|
||||
列表分页
|
||||
"""
|
||||
|
||||
def __init__(self, name: str = None, telephone: str = None, is_active: bool | str = None,
|
||||
params: Paging = Depends()):
|
||||
def __init__(
|
||||
self,
|
||||
name: str = None,
|
||||
telephone: str = None,
|
||||
is_active: bool | str = None,
|
||||
params: Paging = Depends()
|
||||
):
|
||||
super().__init__(params)
|
||||
self.name = ("like", name)
|
||||
self.telephone = ("like", telephone)
|
||||
|
@ -46,5 +46,5 @@ async def full_admin(telephone: str, db: AsyncSession):
|
||||
如果令牌无效,立即返回一个 HTTP 错误。
|
||||
"""
|
||||
options = [models.VadminUser.roles, "roles.menus"]
|
||||
return await crud.UserDal(db).get_data(telephone=telephone, v_return_none=True, options=options)
|
||||
return await crud.UserDal(db).get_data(telephone=telephone, v_return_none=True, v_options=options)
|
||||
|
||||
|
@ -35,8 +35,12 @@ app = APIRouter()
|
||||
|
||||
|
||||
@app.post("/login/", summary="登录")
|
||||
async def login_for_access_token(request: Request, data: LoginForm, manage: LoginManage = Depends(),
|
||||
db: AsyncSession = Depends(db_getter)):
|
||||
async def login_for_access_token(
|
||||
request: Request,
|
||||
data: LoginForm,
|
||||
manage: LoginManage = Depends(),
|
||||
db: AsyncSession = Depends(db_getter)
|
||||
):
|
||||
if data.method == "0":
|
||||
result = await manage.password_login(data, db, request)
|
||||
elif data.method == "1":
|
||||
@ -45,8 +49,8 @@ async def login_for_access_token(request: Request, data: LoginForm, manage: Logi
|
||||
return ErrorResponse(msg="请使用正确的登录方式")
|
||||
if not result.status:
|
||||
resp = {"message": result.msg}
|
||||
await VadminLoginRecord.\
|
||||
create_login_record(db, data, result.status, request, resp)
|
||||
await VadminLoginRecord\
|
||||
.create_login_record(db, data, result.status, request, resp)
|
||||
return ErrorResponse(msg=result.msg)
|
||||
|
||||
user = result.user
|
||||
|
@ -33,8 +33,12 @@ class AuthValidation:
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
|
||||
async def __call__(self, request: Request, token: str = Depends(settings.oauth2_scheme),
|
||||
db: AsyncSession = Depends(db_getter)):
|
||||
async def __call__(
|
||||
self,
|
||||
request: Request,
|
||||
token: str = Depends(settings.oauth2_scheme),
|
||||
db: AsyncSession = Depends(db_getter)
|
||||
):
|
||||
if not settings.OAUTH_ENABLE:
|
||||
return Auth(db=db)
|
||||
if not token:
|
||||
|
@ -46,7 +46,7 @@ class LoginValidation:
|
||||
async def __call__(self, data: LoginForm, db: AsyncSession, request: Request) -> LoginResult:
|
||||
self.result = LoginResult()
|
||||
options = [models.VadminUser.roles, "roles.menus"]
|
||||
user = await crud.UserDal(db).get_data(telephone=data.telephone, v_return_none=True, options=options)
|
||||
user = await crud.UserDal(db).get_data(telephone=data.telephone, v_return_none=True, v_options=options)
|
||||
if not user:
|
||||
self.result.msg = "该手机号不存在!"
|
||||
return self.result
|
||||
|
@ -51,7 +51,7 @@ async def get_user(data_id: int, auth: Auth = Depends(login_auth)):
|
||||
model = models.VadminUser
|
||||
options = [model.roles]
|
||||
schema = schemas.UserOut
|
||||
return SuccessResponse(await crud.UserDal(auth.db).get_data(data_id, options, schema))
|
||||
return SuccessResponse(await crud.UserDal(auth.db).get_data(data_id, options, v_schema=schema))
|
||||
|
||||
|
||||
@app.post("/user/current/reset/password/", summary="重置当前用户密码")
|
||||
@ -77,8 +77,11 @@ async def get_user_current_info(auth: Auth = Depends(full_admin)):
|
||||
|
||||
|
||||
@app.post("/user/export/query/list/to/excel/", summary="导出用户查询列表为excel")
|
||||
async def post_user_export_query_list(header: list = Body(..., title="表头与对应字段"), params: UserParams = Depends(),
|
||||
auth: Auth = Depends(login_auth)):
|
||||
async def post_user_export_query_list(
|
||||
header: list = Body(..., title="表头与对应字段"),
|
||||
params: UserParams = Depends(),
|
||||
auth: Auth = Depends(login_auth)
|
||||
):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).export_query_list(header, params))
|
||||
|
||||
|
||||
@ -137,7 +140,7 @@ async def get_role(data_id: int, auth: Auth = Depends(login_auth)):
|
||||
model = models.VadminRole
|
||||
options = [model.menus]
|
||||
schema = schemas.RoleOut
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).get_data(data_id, options, schema))
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).get_data(data_id, options, v_schema=schema))
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -181,7 +184,7 @@ async def put_menus(data_id: int, data: schemas.Menu, auth: Auth = Depends(login
|
||||
@app.get("/menus/{data_id}/", summary="获取菜单信息")
|
||||
async def put_menus(data_id: int, auth: Auth = Depends(login_auth)):
|
||||
schema = schemas.MenuSimpleOut
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_data(data_id, None, schema))
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_data(data_id, None, v_schema=schema))
|
||||
|
||||
|
||||
@app.get("/role/menus/tree/{role_id}/", summary="获取菜单列表树信息以及角色菜单权限ID,角色权限使用")
|
||||
|
@ -69,5 +69,6 @@ class LoginRecordDal(DalBase):
|
||||
|
||||
|
||||
class SMSSendRecordDal(DalBase):
|
||||
|
||||
def __init__(self, db: AsyncSession):
|
||||
super(SMSSendRecordDal, self).__init__(db, models.VadminSMSSendRecord, schemas.SMSSendRecordSimpleOut)
|
||||
|
@ -57,8 +57,16 @@ class VadminLoginRecord(BaseModel):
|
||||
ip = IPManage(req.client.host)
|
||||
location = await ip.parse()
|
||||
params = json.dumps({"body": body, "headers": header})
|
||||
obj = VadminLoginRecord(**location.dict(), telephone=data.telephone, status=status, browser=browser,
|
||||
system=system, response=json.dumps(resp), request=params, platform=data.platform,
|
||||
login_method=data.method)
|
||||
obj = VadminLoginRecord(
|
||||
**location.dict(),
|
||||
telephone=data.telephone,
|
||||
status=status,
|
||||
browser=browser,
|
||||
system=system,
|
||||
response=json.dumps(resp),
|
||||
request=params,
|
||||
platform=data.platform,
|
||||
login_method=data.method
|
||||
)
|
||||
db.add(obj)
|
||||
await db.flush()
|
||||
|
@ -19,24 +19,24 @@ app = APIRouter()
|
||||
# 日志管理
|
||||
###########################################################
|
||||
@app.get("/logins/", summary="获取登录日志列表")
|
||||
async def get_record_login(params: LoginParams = Depends(), auth: Auth = Depends(login_auth)):
|
||||
datas = await crud.LoginRecordDal(auth.db).get_datas(**params.dict())
|
||||
count = await crud.LoginRecordDal(auth.db).get_count(**params.to_count())
|
||||
async def get_record_login(p: LoginParams = Depends(), auth: Auth = Depends(login_auth)):
|
||||
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="获取操作日志列表")
|
||||
async def get_record_operation(params: OperationParams = Depends(), db: DatabaseManage = Depends(get_database),
|
||||
async def get_record_operation(p: OperationParams = Depends(), db: DatabaseManage = Depends(get_database),
|
||||
auth: Auth = Depends(login_auth)):
|
||||
count = await db.get_count("operation_record", **params.to_count())
|
||||
datas = await db.get_datas("operation_record", schema=schemas.OpertionRecordSimpleOut, **params.dict())
|
||||
count = await db.get_count("operation_record", **p.to_count())
|
||||
datas = await db.get_datas("operation_record", v_schema=schemas.OpertionRecordSimpleOut, **p.dict())
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.get("/sms/send/list/", summary="获取短信发送列表")
|
||||
async def get_sms_send_list(params: SMSParams = Depends(), auth: Auth = Depends(login_auth)):
|
||||
datas = await crud.SMSSendRecordDal(auth.db).get_datas(**params.dict())
|
||||
count = await crud.SMSSendRecordDal(auth.db).get_count(**params.to_count())
|
||||
async def get_sms_send_list(p: SMSParams = Depends(), auth: Auth = Depends(login_auth)):
|
||||
datas = await crud.SMSSendRecordDal(auth.db).get_datas(**p.dict())
|
||||
count = await crud.SMSSendRecordDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
|
@ -30,8 +30,8 @@ class DictTypeDal(DalBase):
|
||||
"""
|
||||
data = {}
|
||||
for dict_type in dict_types:
|
||||
dict_data = await DictTypeDal(self.db).\
|
||||
get_data(dict_type=dict_type, v_return_none=True, options=[self.model.details])
|
||||
dict_data = await DictTypeDal(self.db)\
|
||||
.get_data(dict_type=dict_type, v_return_none=True, v_options=[self.model.details])
|
||||
if not dict_data:
|
||||
data[dict_type] = []
|
||||
continue
|
||||
@ -105,8 +105,14 @@ class SettingsTabDal(DalBase):
|
||||
"""
|
||||
model = models.VadminSystemSettingsTab
|
||||
options = [model.settings]
|
||||
datas = await self.get_datas(limit=0, options=options, classify=("in", classify), disabled=False,
|
||||
v_return_objs=True, hidden=hidden)
|
||||
datas = await self.get_datas(
|
||||
limit=0,
|
||||
v_options=options,
|
||||
classify=("in", classify),
|
||||
disabled=False,
|
||||
hidden=hidden,
|
||||
v_return_objs=True
|
||||
)
|
||||
result = {}
|
||||
for tab in datas:
|
||||
tabs = {}
|
||||
@ -115,4 +121,3 @@ class SettingsTabDal(DalBase):
|
||||
tabs[item.config_key] = item.config_value
|
||||
result[tab.tab_name] = tabs
|
||||
return result
|
||||
|
||||
|
@ -27,9 +27,9 @@ app = APIRouter()
|
||||
# 字典类型管理
|
||||
###########################################################
|
||||
@app.get("/dict/types/", summary="获取字典类型列表")
|
||||
async def get_dict_types(params: DictTypeParams = Depends(), auth: Auth = Depends(login_auth)):
|
||||
datas = await crud.DictTypeDal(auth.db).get_datas(**params.dict())
|
||||
count = await crud.DictTypeDal(auth.db).get_count(**params.to_count())
|
||||
async def get_dict_types(p: DictTypeParams = Depends(), auth: Auth = Depends(login_auth)):
|
||||
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)
|
||||
|
||||
|
||||
@ -45,16 +45,17 @@ async def delete_dict_types(ids: IdList = Depends(), auth: Auth = Depends(login_
|
||||
|
||||
|
||||
@app.post("/dict/types/details/", summary="获取多个字典类型下的字典元素列表")
|
||||
async def post_dicts_details(auth: Auth = Depends(login_auth),
|
||||
dict_types: List[str] = Body(None, title="字典元素列表", description="查询字典元素列表")):
|
||||
async def post_dicts_details(
|
||||
auth: Auth = Depends(login_auth),
|
||||
dict_types: List[str] = Body(None, title="字典元素列表", description="查询字典元素列表")
|
||||
):
|
||||
datas = await crud.DictTypeDal(auth.db).get_dicts_details(dict_types)
|
||||
return SuccessResponse(datas)
|
||||
|
||||
|
||||
@app.get("/dict/types/options/", summary="获取字典类型选择项")
|
||||
async def get_dicts_options(auth: Auth = Depends(login_auth)):
|
||||
datas = await crud.DictTypeDal(auth.db).get_select_datas()
|
||||
return SuccessResponse(datas)
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).get_select_datas())
|
||||
|
||||
|
||||
@app.put("/dict/types/{data_id}/", summary="更新字典类型")
|
||||
@ -65,7 +66,7 @@ async def put_dict_types(data_id: int, data: schemas.DictType, auth: Auth = Depe
|
||||
@app.get("/dict/types/{data_id}/", summary="获取字典类型详细")
|
||||
async def get_dict_type(data_id: int, auth: Auth = Depends(login_auth)):
|
||||
schema = schemas.DictTypeSimpleOut
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).get_data(data_id, None, schema))
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).get_data(data_id, None, v_schema=schema))
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -99,7 +100,7 @@ async def put_dict_details(data_id: int, data: schemas.DictDetails, auth: Auth =
|
||||
@app.get("/dict/details/{data_id}/", summary="获取字典元素详情")
|
||||
async def get_dict_detail(data_id: int, auth: Auth = Depends(login_auth)):
|
||||
schema = schemas.DictDetailsSimpleOut
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).get_data(data_id, None, schema))
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).get_data(data_id, None, v_schema=schema))
|
||||
|
||||
|
||||
###########################################################
|
||||
|
@ -13,6 +13,7 @@
|
||||
# SQLAlchemy join 内连接
|
||||
# selectinload 官方文档:
|
||||
# https://www.osgeo.cn/sqlalchemy/orm/loading_relationships.html?highlight=selectinload#sqlalchemy.orm.selectinload
|
||||
|
||||
import datetime
|
||||
from typing import List
|
||||
from fastapi import HTTPException
|
||||
@ -24,133 +25,156 @@ from sqlalchemy.orm import selectinload
|
||||
from starlette import status
|
||||
from core.logger import logger
|
||||
from sqlalchemy.sql.selectable import Select
|
||||
from typing import Any
|
||||
|
||||
|
||||
class DalBase:
|
||||
|
||||
def __init__(self, db: AsyncSession, model, schema, key_models: dict = None):
|
||||
def __init__(self, db: AsyncSession, model: Any, schema: Any, key_models: dict = None):
|
||||
self.db = db
|
||||
self.model = model
|
||||
self.schema = schema
|
||||
self.key_models = key_models
|
||||
|
||||
async def get_data(self, data_id: int = None, options: list = None, schema=None, keys: dict = None, **kwargs):
|
||||
async def get_data(
|
||||
self,
|
||||
data_id: int = None,
|
||||
v_options: list = None,
|
||||
v_join_query: dict = None,
|
||||
v_order: str = None,
|
||||
v_return_none: bool = False,
|
||||
v_schema: Any = None,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
获取单个数据,默认使用 ID 查询,否则使用关键词查询
|
||||
|
||||
@param data_id:
|
||||
@param keys: 外键字段查询,内连接
|
||||
@param options: 指示应使用select在预加载中加载给定的属性。
|
||||
@param schema: 指定使用的序列化对象
|
||||
@param kwargs: 关键词参数,
|
||||
@param kwargs: v_order,排序,默认正序,为 desc 是倒叙
|
||||
@param kwargs: v_return_none,是否返回空 None,否认 抛出异常,默认抛出异常
|
||||
@param data_id: 数据 ID
|
||||
@param v_join_query: 外键字段查询,内连接
|
||||
@param v_options: 指示应使用select在预加载中加载给定的属性。
|
||||
@param v_schema: 指定使用的序列化对象
|
||||
@param v_order: 排序,默认正序,为 desc 是倒叙
|
||||
@param v_return_none: 是否返回空 None,否认 抛出异常,默认抛出异常
|
||||
@param kwargs: 查询参数
|
||||
"""
|
||||
order = kwargs.pop("v_order", None)
|
||||
return_none = kwargs.pop("v_return_none", False)
|
||||
keys_exist = False
|
||||
if keys:
|
||||
for key, value in keys.items():
|
||||
if value and isinstance(value, dict):
|
||||
for k, v in value.items():
|
||||
if v:
|
||||
keys_exist = True
|
||||
break
|
||||
kwargs_exist = False
|
||||
if kwargs:
|
||||
for key, value in kwargs.items():
|
||||
if value and getattr(self.model, key, None):
|
||||
kwargs_exist = True
|
||||
break
|
||||
sql = select(self.model).where(self.model.delete_datetime.is_(None))
|
||||
if data_id or kwargs_exist or keys_exist:
|
||||
if data_id:
|
||||
sql = sql.where(self.model.id == data_id)
|
||||
sql = self.add_filter_condition(sql, keys, options, **kwargs)
|
||||
if order and (order == "desc" or order == "descending"):
|
||||
if data_id:
|
||||
sql = sql.where(self.model.id == data_id)
|
||||
sql = self.add_filter_condition(sql, v_join_query, v_options, **kwargs)
|
||||
if v_order and (v_order == "desc" or v_order == "descending"):
|
||||
sql = sql.order_by(self.model.create_datetime.desc())
|
||||
queryset = await self.db.execute(sql)
|
||||
data = queryset.scalars().first()
|
||||
if not data and return_none:
|
||||
if not data and v_return_none:
|
||||
return None
|
||||
if data and schema:
|
||||
return schema.from_orm(data).dict()
|
||||
if data and v_schema:
|
||||
return v_schema.from_orm(data).dict()
|
||||
if data:
|
||||
return data
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="未找到此数据")
|
||||
|
||||
async def get_datas(self, page: int = 1, limit: int = 10, keys: dict = None, options: list = None, schema=None,
|
||||
**kwargs):
|
||||
async def get_datas(
|
||||
self,
|
||||
page: int = 1,
|
||||
limit: int = 10,
|
||||
v_join_query: dict = None,
|
||||
v_options: list = None,
|
||||
v_order: str = None,
|
||||
v_order_field: str = None,
|
||||
v_return_objs: bool = False,
|
||||
v_start_sql: Any = None,
|
||||
v_schema: Any = None,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
获取数据列表
|
||||
|
||||
@param page: 页码
|
||||
@param limit: 当前页数据量
|
||||
@param keys: 外键字段查询
|
||||
@param options: 指示应使用select在预加载中加载给定的属性。
|
||||
@param schema: 指定使用的序列化对象
|
||||
@param kwargs: v_order,排序,默认正序,为 desc 是倒叙
|
||||
@param kwargs: v_order_field,排序字段
|
||||
@param kwargs: v_return_objs,是否返回对象
|
||||
@param kwargs: v_start_sql,初始 sql
|
||||
@param v_join_query: 外键字段查询
|
||||
@param v_options: 指示应使用select在预加载中加载给定的属性。
|
||||
@param v_schema: 指定使用的序列化对象
|
||||
@param v_order: 排序,默认正序,为 desc 是倒叙
|
||||
@param v_order_field: 排序字段
|
||||
@param v_return_objs: 是否返回对象
|
||||
@param v_start_sql: 初始 sql
|
||||
@param kwargs: 查询参数
|
||||
"""
|
||||
order = kwargs.pop("v_order", None)
|
||||
order_field = kwargs.pop("v_order_field", None)
|
||||
return_objs = kwargs.pop("v_return_objs", False)
|
||||
start_sql = kwargs.pop("v_start_sql", None)
|
||||
if not isinstance(start_sql, Select):
|
||||
start_sql = select(self.model).where(self.model.delete_datetime.is_(None))
|
||||
sql = self.add_filter_condition(start_sql, keys, options, **kwargs)
|
||||
if order_field and (order == "desc" or order == "descending"):
|
||||
sql = sql.order_by(getattr(self.model, order_field).desc(), self.model.id.desc())
|
||||
elif order_field:
|
||||
sql = sql.order_by(getattr(self.model, order_field), self.model.id)
|
||||
elif order == "desc" or order == "descending":
|
||||
if not isinstance(v_start_sql, Select):
|
||||
v_start_sql = select(self.model).where(self.model.delete_datetime.is_(None))
|
||||
sql = self.add_filter_condition(v_start_sql, v_join_query, v_options, **kwargs)
|
||||
if v_order_field and (v_order == "desc" or v_order == "descending"):
|
||||
sql = sql.order_by(getattr(self.model, v_order_field).desc(), self.model.id.desc())
|
||||
elif v_order_field:
|
||||
sql = sql.order_by(getattr(self.model, v_order_field), self.model.id)
|
||||
elif v_order == "desc" or v_order == "descending":
|
||||
sql = sql.order_by(self.model.id.desc())
|
||||
if limit != 0:
|
||||
sql = sql.offset((page - 1) * limit).limit(limit)
|
||||
queryset = await self.db.execute(sql)
|
||||
if return_objs:
|
||||
if v_return_objs:
|
||||
return queryset.scalars().all()
|
||||
if schema:
|
||||
return [schema.from_orm(i).dict() for i in queryset.scalars().all()]
|
||||
if v_schema:
|
||||
return [v_schema.from_orm(i).dict() for i in queryset.scalars().all()]
|
||||
return [self.out_dict(i) for i in queryset.scalars().all()]
|
||||
|
||||
async def get_count(self, keys: dict = None, **kwargs):
|
||||
"""获取数据总数"""
|
||||
async def get_count(self, v_join_query: dict = None, v_options: list = None, **kwargs):
|
||||
"""
|
||||
获取数据总数
|
||||
@param v_join_query: 外键字段查询
|
||||
@param v_options: 指示应使用select在预加载中加载给定的属性。
|
||||
@param kwargs: 查询参数
|
||||
"""
|
||||
sql = select(func.count(self.model.id).label('total')).where(self.model.delete_datetime.is_(None))
|
||||
sql = self.add_filter_condition(sql, keys, **kwargs)
|
||||
sql = self.add_filter_condition(sql, v_join_query, v_options, **kwargs)
|
||||
queryset = await self.db.execute(sql)
|
||||
return queryset.one()['total']
|
||||
|
||||
async def create_data(self, data, return_obj: bool = False, options: list = None, schema=None):
|
||||
"""创建数据"""
|
||||
async def create_data(self, data, v_options: list = None, v_return_obj: bool = False, v_schema: Any = None):
|
||||
"""
|
||||
创建数据
|
||||
@param data: 创建数据
|
||||
@param v_options: 指示应使用select在预加载中加载给定的属性。
|
||||
@param v_schema: ,指定使用的序列化对象
|
||||
@param v_return_obj: ,是否返回对象
|
||||
"""
|
||||
if isinstance(data, dict):
|
||||
obj = self.model(**data)
|
||||
else:
|
||||
obj = self.model(**data.dict())
|
||||
await self.flush(obj)
|
||||
if options:
|
||||
obj = await self.get_data(obj.id, options=options)
|
||||
if return_obj:
|
||||
if v_options:
|
||||
obj = await self.get_data(obj.id, v_options=v_options)
|
||||
if v_return_obj:
|
||||
return obj
|
||||
if schema:
|
||||
return schema.from_orm(obj).dict()
|
||||
if v_schema:
|
||||
return v_schema.from_orm(obj).dict()
|
||||
return self.out_dict(obj)
|
||||
|
||||
async def put_data(self, data_id: int, data, return_obj: bool = False, options: list = None, schema=None):
|
||||
async def put_data(
|
||||
self,
|
||||
data_id: int,
|
||||
data: Any,
|
||||
v_options: list = None,
|
||||
v_return_obj: bool = False,
|
||||
v_schema: Any = None
|
||||
):
|
||||
"""
|
||||
更新单个数据
|
||||
@param data_id: 修改行数据的 ID
|
||||
@param data: 数据内容
|
||||
@param v_options: 指示应使用select在预加载中加载给定的属性。
|
||||
@param v_return_obj: ,是否返回对象
|
||||
@param v_schema: ,指定使用的序列化对象
|
||||
"""
|
||||
obj = await self.get_data(data_id, options=options)
|
||||
obj = await self.get_data(data_id, v_options=v_options)
|
||||
obj_dict = jsonable_encoder(data)
|
||||
for key, value in obj_dict.items():
|
||||
setattr(obj, key, value)
|
||||
await self.flush(obj)
|
||||
if return_obj:
|
||||
if v_return_obj:
|
||||
return obj
|
||||
if schema:
|
||||
return schema.from_orm(obj).dict()
|
||||
if v_schema:
|
||||
return v_schema.from_orm(obj).dict()
|
||||
return self.out_dict(obj)
|
||||
|
||||
async def delete_datas(self, ids: List[int], soft: bool = False):
|
||||
@ -160,67 +184,72 @@ class DalBase:
|
||||
@param soft: 是否执行软删除
|
||||
"""
|
||||
if soft:
|
||||
await self.db.execute(update(self.model).where(self.model.id.in_(ids)).
|
||||
values(delete_datetime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
|
||||
await self.db.execute(
|
||||
update(self.model)
|
||||
.where(self.model.id.in_(ids))
|
||||
.values(delete_datetime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
||||
)
|
||||
else:
|
||||
await self.db.execute(delete(self.model).where(self.model.id.in_(ids)))
|
||||
|
||||
def add_filter_condition(self, sql: select, keys: dict = None, options: list = None, **kwargs) -> select:
|
||||
def add_filter_condition(self, sql: select, v_join_query: dict = None, v_options: list = None, **kwargs) -> select:
|
||||
"""
|
||||
添加过滤条件,以及内连接过滤条件
|
||||
@param sql:
|
||||
@param keys: 外键字段查询,内连接
|
||||
@param options: 指示应使用select在预加载中加载给定的属性。
|
||||
@param v_join_query: 外键字段查询,内连接
|
||||
@param v_options: 指示应使用select在预加载中加载给定的属性。
|
||||
@param kwargs: 关键词参数
|
||||
"""
|
||||
if keys and self.key_models:
|
||||
for key, value in keys.items():
|
||||
model = self.key_models.get(key)
|
||||
if model:
|
||||
sql = sql.join(model)
|
||||
if v_join_query and self.key_models:
|
||||
for key, value in v_join_query.items():
|
||||
foreign_key = self.key_models.get(key)
|
||||
if foreign_key and foreign_key.get("model"):
|
||||
# 当外键模型在查询模型中存在多个外键时,则需要添加onclause属性
|
||||
sql = sql.join(foreign_key.get("model"), onclause=foreign_key.get("onclause"))
|
||||
for v_key, v_value in value.items():
|
||||
if v_value is not None and v_value != "":
|
||||
v_attr = getattr(model, v_key, None)
|
||||
v_attr = getattr(foreign_key.get("model"), v_key, None)
|
||||
sql = self.filter_condition(sql, v_attr, v_value)
|
||||
else:
|
||||
logger.error(f"外键查询报错:{key}模型不存在,无法进行下一步查询。")
|
||||
elif keys and not self.key_models:
|
||||
elif v_join_query and not self.key_models:
|
||||
logger.error(f"外键查询报错:key_models 外键模型无配置项,无法进行下一步查询。")
|
||||
for field in kwargs:
|
||||
value = kwargs.get(field)
|
||||
if value is not None and value != "":
|
||||
attr = getattr(self.model, field, None)
|
||||
sql = self.filter_condition(sql, attr, value)
|
||||
if options:
|
||||
sql = sql.options(*[selectinload(i) for i in options])
|
||||
if v_options:
|
||||
sql = sql.options(*[selectinload(i) for i in v_options])
|
||||
return sql
|
||||
|
||||
@classmethod
|
||||
def filter_condition(cls, sql, attr, value):
|
||||
def filter_condition(cls, sql: Any, attr: Any, value: Any):
|
||||
"""
|
||||
过滤条件
|
||||
"""
|
||||
if not attr:
|
||||
return sql
|
||||
if isinstance(value, tuple):
|
||||
if value[0] == "date" and value[1]:
|
||||
# 根据日期查询, 关键函数是:func.time_format和func.date_format
|
||||
sql = sql.where(func.date_format(attr, "%Y-%m-%d") == value[1])
|
||||
elif value[0] == "like" and value[1]:
|
||||
sql = sql.where(attr.like(f"%{value[1]}%"))
|
||||
elif value[0] == "or" and value[1]:
|
||||
sql = sql.where(or_(i for i in value[1]))
|
||||
elif value[0] == "in" and value[1]:
|
||||
sql = sql.where(attr.in_(value[1]))
|
||||
elif value[0] == "between" and value[1]:
|
||||
sql = sql.where(attr.between(value[1][0], value[1][1]))
|
||||
elif value[0] == "month" and value[1]:
|
||||
sql = sql.where(func.date_format(attr, "%Y-%m") == value[1])
|
||||
if value[1]:
|
||||
if value[0] == "date":
|
||||
# 根据日期查询, 关键函数是:func.time_format和func.date_format
|
||||
sql = sql.where(func.date_format(attr, "%Y-%m-%d") == value[1])
|
||||
elif value[0] == "like":
|
||||
sql = sql.where(attr.like(f"%{value[1]}%"))
|
||||
elif value[0] == "or":
|
||||
sql = sql.where(or_(i for i in value[1]))
|
||||
elif value[0] == "in":
|
||||
sql = sql.where(attr.in_(value[1]))
|
||||
elif value[0] == "between":
|
||||
sql = sql.where(attr.between(value[1][0], value[1][1]))
|
||||
elif value[0] == "month":
|
||||
sql = sql.where(func.date_format(attr, "%Y-%m") == value[1])
|
||||
else:
|
||||
sql = sql.where(attr == value)
|
||||
return sql
|
||||
|
||||
async def flush(self, obj=None):
|
||||
async def flush(self, obj: Any = None):
|
||||
"""
|
||||
刷新到数据库
|
||||
"""
|
||||
@ -230,7 +259,7 @@ class DalBase:
|
||||
if obj:
|
||||
await self.db.refresh(obj)
|
||||
|
||||
def out_dict(self, data):
|
||||
def out_dict(self, data: Any):
|
||||
"""
|
||||
序列化
|
||||
@param data:
|
||||
|
@ -35,3 +35,16 @@ class Telephone(str):
|
||||
@classmethod
|
||||
def validate(cls, v):
|
||||
return vali_telephone(v)
|
||||
|
||||
|
||||
class DateStr(str):
|
||||
|
||||
@classmethod
|
||||
def __get_validators__(cls):
|
||||
yield cls.validate
|
||||
|
||||
@classmethod
|
||||
def validate(cls, v):
|
||||
if isinstance(v, str):
|
||||
return v
|
||||
return v.strftime("%Y-%m-%d")
|
||||
|
@ -108,8 +108,8 @@ def register_exception(app: FastAPI):
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
content=jsonable_encoder(
|
||||
{
|
||||
"message": "接口异常!"
|
||||
, "code": status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
"message": "接口异常!",
|
||||
"code": status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
}
|
||||
),
|
||||
)
|
||||
|
@ -1,4 +1,5 @@
|
||||
from abc import abstractmethod
|
||||
from typing import Any
|
||||
|
||||
|
||||
class DatabaseManage:
|
||||
@ -29,7 +30,16 @@ class DatabaseManage:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_datas(self, collection: str, page: int = 1, limit: int = 10, schema=None, **kwargs):
|
||||
async def get_datas(
|
||||
self,
|
||||
collection: str,
|
||||
page: int = 1,
|
||||
limit: int = 10,
|
||||
v_schema: Any = None,
|
||||
v_order: str = None,
|
||||
v_order_field: str = None,
|
||||
**kwargs
|
||||
):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
|
@ -1,4 +1,6 @@
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from bson.json_util import dumps
|
||||
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
|
||||
from core.mongo import DatabaseManage
|
||||
@ -30,15 +32,20 @@ class MongoManage(DatabaseManage):
|
||||
async def create_data(self, collection: str, data: dict) -> InsertOneResult:
|
||||
return await self.db[collection].insert_one(data)
|
||||
|
||||
async def get_datas(self, collection: str, schema: BaseModel = None, **kwargs):
|
||||
async def get_datas(
|
||||
self,
|
||||
collection: str,
|
||||
page: int = 1,
|
||||
limit: int = 10,
|
||||
v_schema: Any = None,
|
||||
v_order: str = None,
|
||||
v_order_field: str = None,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
使用 find() 要查询的一组文档。 find() 没有I / O,也不需要 await 表达式。它只是创建一个 AsyncIOMotorCursor 实例
|
||||
当您调用 to_list() 或为循环执行异步时 (async for) ,查询实际上是在服务器上执行的。
|
||||
"""
|
||||
page = kwargs.pop("page", 1)
|
||||
limit = kwargs.pop("limit", 10)
|
||||
order = kwargs.pop("v_order", None)
|
||||
order_field = kwargs.pop("v_order_field", None)
|
||||
|
||||
params = self.filter_condition(**kwargs)
|
||||
cursor = self.db[collection].find(params)
|
||||
@ -50,8 +57,8 @@ class MongoManage(DatabaseManage):
|
||||
async for row in cursor:
|
||||
del row['_id']
|
||||
data = json.loads(dumps(row))
|
||||
if schema:
|
||||
data = schema.parse_obj(data).dict()
|
||||
if v_schema:
|
||||
data = v_schema.parse_obj(data).dict()
|
||||
datas.append(data)
|
||||
return datas
|
||||
|
||||
|
@ -156,7 +156,8 @@ class ExcelManage:
|
||||
@param max_column: 最大列
|
||||
"""
|
||||
for index in range(0, max_column):
|
||||
# 设置单元格对齐方式 Alignment(horizontal=水平对齐模式,vertical=垂直对齐模式,text_rotation=旋转角度,wrap_text=是否自动换行)
|
||||
# 设置单元格对齐方式
|
||||
# Alignment(horizontal=水平对齐模式,vertical=垂直对齐模式,text_rotation=旋转角度,wrap_text=是否自动换行)
|
||||
alignment = Alignment(horizontal='center', vertical='center', text_rotation=0, wrap_text=False)
|
||||
self.sheet.cell(row=row, column=index+1).alignment = alignment
|
||||
|
||||
|
@ -39,7 +39,7 @@ class IPManage:
|
||||
|
||||
def __init__(self, ip: str):
|
||||
self.ip = ip
|
||||
self.url = f"https://api.ip138.com/ip/?ip={ip}&datatype=jsonp&token={IP_PARSE_TOKEN}"
|
||||
self.url = f"http://api.ip138.com/ip/?ip={ip}&datatype=jsonp&token={IP_PARSE_TOKEN}"
|
||||
|
||||
async def parse(self):
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user