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