管理后台 实名认证页面添加

pull/10/head
youngS 4 years ago
parent 7a0c8bfce3
commit d133d0ec7b
  1. 18
      fir_admin/src/api/storage.js
  2. 15
      fir_admin/src/api/user.js
  3. 28
      fir_admin/src/router/index.js
  4. 6
      fir_admin/src/views/appinfos/AppReleaseList.vue
  5. 41
      fir_admin/src/views/appinfos/Dropdown/Comment.vue
  6. 46
      fir_admin/src/views/appinfos/Dropdown/Platform.vue
  7. 38
      fir_admin/src/views/appinfos/Dropdown/SourceUrl.vue
  8. 3
      fir_admin/src/views/appinfos/Dropdown/index.js
  9. 5
      fir_admin/src/views/appinfos/list.vue
  10. 140
      fir_admin/src/views/authentication/Detail.vue
  11. 199
      fir_admin/src/views/authentication/list.vue
  12. 140
      fir_admin/src/views/storage/Detail.vue
  13. 197
      fir_admin/src/views/storage/list.vue
  14. 5
      fir_admin/src/views/userinfos/UserDetail.vue
  15. 5
      fir_ser/admin/urls.py
  16. 73
      fir_ser/admin/views/storage.py
  17. 45
      fir_ser/admin/views/user.py
  18. 4
      fir_ser/api/models.py
  19. 45
      fir_ser/api/utils/serializer.py
  20. 8
      fir_ser/api/utils/utils.py

@ -0,0 +1,18 @@
import request from '@/utils/request'
export function getStorageInfo(query) {
return request({
url: '/storage/info',
method: 'get',
params: query
})
}
export function updateStorageInfo(data) {
return request({
url: '/storage/info',
method: 'put',
data
})
}

@ -38,3 +38,18 @@ export function updateUserInfo(data) {
data data
}) })
} }
export function getCertificationInfo(query) {
return request({
url: '/certification/info',
method: 'get',
params: query
})
}
export function updateCertificationInfo(data) {
return request({
url: '/certification/info',
method: 'put',
data
})
}

@ -124,10 +124,17 @@ export const constantRoutes = [
component: Layout, component: Layout,
children: [ children: [
{ {
path: 'index', path: 'list',
name: 'index', name: 'storage_info_list',
component: () => import('@/views/form/index'), component: () => import('@/views/storage/list'),
meta: { title: '存储管理', icon: 'form' } meta: { title: '存储管理', icon: 'form' }
},
{
path: 'edit/:id(\\d+)',
component: () => import('@/views/storage/Detail'),
name: 'storage_info_edit',
meta: { title: '编辑信息', noCache: true, activeMenu: '/storage/list' },
hidden: true
} }
] ]
}, },
@ -143,14 +150,21 @@ export const constantRoutes = [
} }
] ]
}, { }, {
path: '/certification', path: '/authentication',
component: Layout, component: Layout,
children: [ children: [
{ {
path: 'index', path: 'list',
name: 'index', name: 'user_authentication_info_list',
component: () => import('@/views/form/index'), component: () => import('@/views/authentication/list'),
meta: { title: '用户实名认证', icon: 'form' } meta: { title: '用户实名认证', icon: 'form' }
},
{
path: 'edit/:id(\\d+)',
component: () => import('@/views/authentication/Detail'),
name: 'user_authentication_info_edit',
meta: { title: '编辑信息', noCache: true, activeMenu: '/authentication/list' },
hidden: true
} }
] ]
}, { }, {

@ -89,7 +89,7 @@ import waves from '@/directive/waves' // waves directive
const sortOptions = [ const sortOptions = [
{ label: '上传时间 Ascending', key: 'created_time' }, { label: '上传时间 Ascending', key: 'created_time' },
{ label: '上传时间 Descending', key: '-created_time' }, { label: '上传时间 Descending', key: '-created_time' }
] ]
export default { export default {
@ -119,7 +119,7 @@ export default {
'0': 'info', '0': 'info',
'1': 'success', '1': 'success',
'2': 'gray', '2': 'gray',
'3': 'danger', '3': 'danger'
} }
return statusMap[status] return statusMap[status]
} }
@ -134,7 +134,7 @@ export default {
limit: 10, limit: 10,
app_id: undefined, app_id: undefined,
release_id: undefined, release_id: undefined,
sort: '-created_time', sort: '-created_time'
}, },
sortOptions, sortOptions,
type_choices: [], type_choices: [],

@ -1,41 +0,0 @@
<template>
<el-dropdown :show-timeout="100" trigger="click">
<el-button plain>
{{ !comment_disabled?'Comment: opened':'Comment: closed' }}
<i class="el-icon-caret-bottom el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown" class="no-padding">
<el-dropdown-item>
<el-radio-group v-model="comment_disabled" style="padding: 10px;">
<el-radio :label="true">
Close comment
</el-radio>
<el-radio :label="false">
Open comment
</el-radio>
</el-radio-group>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
props: {
value: {
type: Boolean,
default: false
}
},
computed: {
comment_disabled: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>

@ -1,46 +0,0 @@
<template>
<el-dropdown :hide-on-click="false" :show-timeout="100" trigger="click">
<el-button plain>
Platfroms({{ platforms.length }})
<i class="el-icon-caret-bottom el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown" class="no-border">
<el-checkbox-group v-model="platforms" style="padding: 5px 15px;">
<el-checkbox v-for="item in platformsOptions" :key="item.key" :label="item.key">
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
props: {
value: {
required: true,
default: () => [],
type: Array
}
},
data() {
return {
platformsOptions: [
{ key: 'a-platform', name: 'a-platform' },
{ key: 'b-platform', name: 'b-platform' },
{ key: 'c-platform', name: 'c-platform' }
]
}
},
computed: {
platforms: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>

@ -1,38 +0,0 @@
v<template>
<el-dropdown :show-timeout="100" trigger="click">
<el-button plain>
Link
<i class="el-icon-caret-bottom el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown" class="no-padding no-border" style="width:400px">
<el-form-item label-width="0px" style="margin-bottom: 0px" prop="source_uri">
<el-input v-model="source_uri" placeholder="Please enter the content">
<template slot="prepend">
URL
</template>
</el-input>
</el-form-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
props: {
value: {
type: String,
default: ''
}
},
computed: {
source_uri: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
}
}
}
</script>

@ -1,3 +0,0 @@
export { default as CommentDropdown } from './Comment'
export { default as PlatformDropdown } from './Platform'
export { default as SourceUrlDropdown } from './SourceUrl'

@ -196,7 +196,6 @@ export default {
}, },
methods: { methods: {
deleteApp(app_id) { deleteApp(app_id) {
this.$confirm('此操作将永久删除该应用, 是否继续?', '提示', { this.$confirm('此操作将永久删除该应用, 是否继续?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
@ -212,8 +211,8 @@ export default {
this.$message({ this.$message({
type: 'info', type: 'info',
message: '已取消删除' message: '已取消删除'
}); })
}); })
}, },
handleFilter() { handleFilter() {
this.listQuery.page = 1 this.listQuery.page = 1

@ -0,0 +1,140 @@
<template>
<div class="app-container">
<el-form ref="postForm" :model="postForm" label-width="100px" :disabled="!is_edit">
<el-row>
<el-col :span="12">
<el-form-item label="用户ID">
<el-row :gutter="12">
<el-col :span="16">
<el-input :value="postForm.user_id" disabled />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="真实姓名">
<el-row :gutter="12">
<el-col :span="16">
<el-input v-model="postForm.name" />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="身份证号码">
<el-row :gutter="12">
<el-col :span="16">
<el-input v-model="postForm.card" />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="居住地址">
<el-row :gutter="12">
<el-col :span="16">
<el-input v-model="postForm.addr" />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="实名认证">
<el-row :gutter="12">
<el-col :span="16">
<el-select v-model="postForm.status" class="filter-item" placeholder="Please select">
<el-option v-for="item in postForm.certification_status_choices" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="提交时间" prop="timestamp">
<el-row :gutter="20">
<el-col :span="8">
<el-date-picker :value="postForm.created_time" type="datetime" disabled />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="审核时间" prop="timestamp">
<el-row :gutter="20">
<el-col :span="8">
<el-date-picker :value="postForm.reviewed_time" type="datetime" disabled />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="审核备注">
<el-row :gutter="12">
<el-col :span="16">
<el-input v-model="postForm.msg" :autosize="{ minRows: 4, maxRows: 6}" type="textarea" placeholder="Please input" />
</el-col>
</el-row>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实名认证照片">
<div v-for="info in postForm.certification_infos" :key="info.name" style="width: 320px; height: 340px;float: left;border: #409EFF 1px solid;text-align: center;margin-left: 20px;margin-bottom: 20px">
<el-image :src="info.certification_url" :preview-src-list="[info.certification_url]" fit="contain" style="width: 260px; height: 260px" />
<el-link :underline="false"> {{ info.name }}</el-link>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-col :span="9" style="float: right">
<el-button v-if="!is_edit" type="primary" @click="is_edit=true">修改</el-button>
<div v-else>
<el-button type="primary" @click="is_edit=false">取消</el-button>
<el-button type="primary" @click="updateData">保存修改</el-button>
</div>
</el-col>
</div>
</template>
<script>
import { getCertificationInfo, updateCertificationInfo } from '@/api/user'
const defaultForm = {
user_id: undefined,
name: undefined,
card: undefined,
addr: undefined,
mobile: undefined,
status: undefined,
msg: undefined,
created_time: undefined,
reviewed_time: undefined
}
export default {
name: 'AppReleaseDetail',
components: { }, filters: {
},
data() {
return {
postForm: Object.assign({}, defaultForm),
loading: false,
is_edit: false
}
},
computed: {
},
created() {
const id = this.$route.params && this.$route.params.id
this.fetchData(id)
},
methods: {
fetchData(id) {
getCertificationInfo({ id: id }).then(response => {
if (response.data.length === 1) {
this.postForm = response.data[0]
}
}).catch(err => {
console.log(err)
})
},
updateData() {
updateCertificationInfo(this.postForm).then(response => {
this.$message.success('更新成功')
this.postForm = response.data
}).catch(err => {
console.log(err)
})
}
}
}
</script>

@ -0,0 +1,199 @@
<template>
<div class="app-container">
<div class="filter-container">
<el-input v-model="listQuery.user_id" placeholder="用户ID" style="width: 140px;" class="filter-item" clearable @keyup.enter.native="handleFilter" />
<el-input v-model="listQuery.card" placeholder="身份证" style="width: 300px;" class="filter-item" clearable @keyup.enter.native="handleFilter" />
<el-input v-model="listQuery.name" placeholder="姓名" style="width: 200px;" class="filter-item" clearable @keyup.enter.native="handleFilter" />
<el-input v-model="listQuery.mobile" placeholder="手机号码" style="width: 200px;" class="filter-item" clearable @keyup.enter.native="handleFilter" />
<el-select v-model="listQuery.status" placeholder="实名认证状态" clearable class="filter-item" style="width: 140px" @change="handleFilter">
<el-option v-for="item in certification_status_choices" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter">
<el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key" />
</el-select>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
Search
</el-button>
</div>
<el-table
v-loading="listLoading"
:data="list"
element-loading-text="Loading"
border
fit
highlight-current-row
stripe
>
<el-table-column align="center" label="ID" width="90">
<template slot-scope="scope">
{{ scope.row.id }}
</template>
</el-table-column>
<el-table-column label="用户ID" width="100" align="center">
<template slot-scope="scope">
<router-link :to="{name: 'user_info_edit',params:{id:scope.row.user_id}}">
<el-link type="primary"> {{ scope.row.user_id }}</el-link>
</router-link>
</template>
</el-table-column>
<el-table-column label="真实姓名">
<template slot-scope="scope">
{{ scope.row.name }}
</template>
</el-table-column>
<el-table-column label="身份证号码" align="center">
<template slot-scope="scope">
<span>{{ scope.row.card }}</span>
</template>
</el-table-column>
<el-table-column label="居住地" align="center">
<template slot-scope="scope">
{{ scope.row.addr }}
</template>
</el-table-column>
<el-table-column label="手机号码" align="center">
<template slot-scope="scope">
{{ scope.row.mobile }}
</template>
</el-table-column>
<el-table-column class-name="status-col" label="实名认证" width="95" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.status | certStatusFilter">{{ scope.row| certLableFilter }}</el-tag>
</template>
</el-table-column>
<el-table-column align="center" prop="created_time" label="提交时间" width="120">
<template slot-scope="scope">
<i class="el-icon-time" />
<el-tooltip :content="scope.row.created_time">
<span>{{ scope.row.created_time|formatTime }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column align="center" prop="created_time" label="审核时间" width="120">
<template slot-scope="scope">
<i class="el-icon-time" />
<el-tooltip :content="scope.row.reviewed_time">
<span>{{ scope.row.reviewed_time|formatTime }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope">
<router-link :to="{name: 'user_authentication_info_edit',params:{id:scope.row.id}}">
<el-button type="primary" size="mini">
查看编辑
</el-button>
</router-link>
<el-button type="danger" size="mini" @click="deleteApp(scope.row.id)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="fetchData" />
</div>
</template>
<script>
import { getCertificationInfo } from '@/api/user'
import Pagination from '@/components/Pagination' // secondary package based on el-pagination
import waves from '@/directive/waves' // waves directive
const sortOptions = [
{ label: '审核时间 Ascending', key: 'reviewed_time' },
{ label: '审核时间 Descending', key: '-reviewed_time' },
{ label: '提交时间 Ascending', key: 'created_time' },
{ label: '提交时间 Descending', key: '-created_time' }
]
export default {
name: 'AppInfo',
components: { Pagination },
directives: { waves },
filters: {
formatTime(time) {
return time.split('T')[0]
},
certStatusFilter(status) {
const statusMap = {
'-1': 'info',
'1': 'success',
'0': 'gray',
'2': 'danger'
}
return statusMap[status]
},
certLableFilter(row) {
for (const v of row.certification_status_choices) {
if (v.id === row.status) {
return v.name
}
}
},
statusFilter(status) {
const statusMap = {
true: 'success',
false: 'danger'
}
return statusMap[status]
},
appStatusNameFilter(row) {
for (const r of row.status_choices) {
if (r.id === row.status) {
return r.name
}
}
},
appStatusFilter(status) {
const statusMap = {
'0': 'danger',
'1': 'success',
'2': 'gray'
}
return statusMap[status]
}
},
data() {
return {
list: null,
listLoading: true,
total: 0,
listQuery: {
page: 1,
limit: 10,
name: undefined,
sort: '-created_time',
card: undefined,
mobile: undefined,
status: undefined,
user_id: undefined
},
sortOptions,
certification_status_choices: []
}
},
created() {
this.fetchData()
},
methods: {
handleFilter() {
this.listQuery.page = 1
this.fetchData()
},
fetchData() {
this.listLoading = true
getCertificationInfo(this.listQuery).then(response => {
this.list = response.data
if (this.list && this.list.length > 0) {
this.certification_status_choices = this.list[0].certification_status_choices
}
this.total = response.total
this.listLoading = false
})
}
}
}
</script>

@ -0,0 +1,140 @@
<template>
<div class="app-container">
<el-form ref="postForm" :model="postForm" label-width="100px" :disabled="!is_edit">
<el-row>
<el-col :span="12">
<el-form-item label="用户ID">
<el-row :gutter="12">
<el-col :span="16">
<el-input :value="postForm.user_id" disabled />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="真实姓名">
<el-row :gutter="12">
<el-col :span="16">
<el-input v-model="postForm.name" />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="身份证号码">
<el-row :gutter="12">
<el-col :span="16">
<el-input v-model="postForm.card" />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="居住地址">
<el-row :gutter="12">
<el-col :span="16">
<el-input v-model="postForm.addr" />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="实名认证">
<el-row :gutter="12">
<el-col :span="16">
<el-select v-model="postForm.status" class="filter-item" placeholder="Please select">
<el-option v-for="item in postForm.certification_status_choices" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="提交时间" prop="timestamp">
<el-row :gutter="20">
<el-col :span="8">
<el-date-picker :value="postForm.created_time" type="datetime" disabled />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="审核时间" prop="timestamp">
<el-row :gutter="20">
<el-col :span="8">
<el-date-picker :value="postForm.reviewed_time" type="datetime" disabled />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="审核备注">
<el-row :gutter="12">
<el-col :span="16">
<el-input v-model="postForm.msg" :autosize="{ minRows: 4, maxRows: 6}" type="textarea" placeholder="Please input" />
</el-col>
</el-row>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实名认证照片">
<div v-for="info in postForm.certification_infos" :key="info.name" style="width: 320px; height: 340px;float: left;border: #409EFF 1px solid;text-align: center;margin-left: 20px;margin-bottom: 20px">
<el-image :src="info.certification_url" :preview-src-list="[info.certification_url]" fit="contain" style="width: 260px; height: 260px" />
<el-link :underline="false"> {{ info.name }}</el-link>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-col :span="9" style="float: right">
<el-button v-if="!is_edit" type="primary" @click="is_edit=true">修改</el-button>
<div v-else>
<el-button type="primary" @click="is_edit=false">取消</el-button>
<el-button type="primary" @click="updateData">保存修改</el-button>
</div>
</el-col>
</div>
</template>
<script>
import { getCertificationInfo, updateCertificationInfo } from '@/api/user'
const defaultForm = {
user_id: undefined,
name: undefined,
card: undefined,
addr: undefined,
mobile: undefined,
status: undefined,
msg: undefined,
created_time: undefined,
reviewed_time: undefined
}
export default {
name: 'AppReleaseDetail',
components: { }, filters: {
},
data() {
return {
postForm: Object.assign({}, defaultForm),
loading: false,
is_edit: false
}
},
computed: {
},
created() {
const id = this.$route.params && this.$route.params.id
this.fetchData(id)
},
methods: {
fetchData(id) {
getCertificationInfo({ id: id }).then(response => {
if (response.data.length === 1) {
this.postForm = response.data[0]
}
}).catch(err => {
console.log(err)
})
},
updateData() {
updateCertificationInfo(this.postForm).then(response => {
this.$message.success('更新成功')
this.postForm = response.data
}).catch(err => {
console.log(err)
})
}
}
}
</script>

@ -0,0 +1,197 @@
<template>
<div class="app-container">
<div class="filter-container">
<el-input v-model="listQuery.user_id" placeholder="用户ID" style="width: 140px;" class="filter-item" clearable @keyup.enter.native="handleFilter" />
<el-input v-model="listQuery.card" placeholder="身份证" style="width: 300px;" class="filter-item" clearable @keyup.enter.native="handleFilter" />
<el-input v-model="listQuery.name" placeholder="姓名" style="width: 200px;" class="filter-item" clearable @keyup.enter.native="handleFilter" />
<el-input v-model="listQuery.mobile" placeholder="手机号码" style="width: 200px;" class="filter-item" clearable @keyup.enter.native="handleFilter" />
<el-select v-model="listQuery.status" placeholder="实名认证状态" clearable class="filter-item" style="width: 140px" @change="handleFilter">
<el-option v-for="item in certification_status_choices" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter">
<el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key" />
</el-select>
<el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
Search
</el-button>
</div>
<el-table
v-loading="listLoading"
:data="list"
element-loading-text="Loading"
border
fit
highlight-current-row
stripe
>
<el-table-column align="center" label="ID" width="90">
<template slot-scope="scope">
{{ scope.row.id }}
</template>
</el-table-column>
<el-table-column label="用户ID" width="100" align="center">
<template slot-scope="scope">
<router-link :to="{name: 'user_info_edit',params:{id:scope.row.user_id}}">
<el-link type="primary"> {{ scope.row.user_id }}</el-link>
</router-link>
</template>
</el-table-column>
<el-table-column label="真实姓名">
<template slot-scope="scope">
{{ scope.row.name }}
</template>
</el-table-column>
<el-table-column label="身份证号码" align="center">
<template slot-scope="scope">
<span>{{ scope.row.card }}</span>
</template>
</el-table-column>
<el-table-column label="居住地" align="center">
<template slot-scope="scope">
{{ scope.row.addr }}
</template>
</el-table-column>
<el-table-column label="手机号码" align="center">
<template slot-scope="scope">
{{ scope.row.mobile }}
</template>
</el-table-column>
<el-table-column class-name="status-col" label="实名认证" width="95" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.status | certStatusFilter">{{ scope.row| certLableFilter }}</el-tag>
</template>
</el-table-column>
<el-table-column align="center" prop="created_time" label="提交时间" width="120">
<template slot-scope="scope">
<i class="el-icon-time" />
<el-tooltip :content="scope.row.created_time">
<span>{{ scope.row.created_time|formatTime }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column align="center" prop="created_time" label="审核时间" width="120">
<template slot-scope="scope">
<i class="el-icon-time" />
<el-tooltip :content="scope.row.reviewed_time">
<span>{{ scope.row.reviewed_time|formatTime }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope">
<router-link :to="{name: 'user_authentication_info_edit',params:{id:scope.row.id}}">
<el-button type="primary" size="mini">
查看编辑
</el-button>
</router-link>
<el-button type="danger" size="mini" @click="deleteApp(scope.row.id)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="fetchData" />
</div>
</template>
<script>
import { getStorageInfo } from '@/api/storage'
import Pagination from '@/components/Pagination' // secondary package based on el-pagination
import waves from '@/directive/waves' // waves directive
const sortOptions = [
{ label: '审核时间 Ascending', key: 'reviewed_time' },
{ label: '审核时间 Descending', key: '-reviewed_time' },
{ label: '提交时间 Ascending', key: 'created_time' },
{ label: '提交时间 Descending', key: '-created_time' }
]
export default {
name: 'AppInfo',
components: { Pagination },
directives: { waves },
filters: {
formatTime(time) {
return time.split('T')[0]
},
certStatusFilter(status) {
const statusMap = {
'-1': 'info',
'1': 'success',
'0': 'gray',
'2': 'danger'
}
return statusMap[status]
},
certLableFilter(row) {
for (const v of row.certification_status_choices) {
if (v.id === row.status) {
return v.name
}
}
},
statusFilter(status) {
const statusMap = {
true: 'success',
false: 'danger'
}
return statusMap[status]
},
appStatusNameFilter(row) {
for (const r of row.status_choices) {
if (r.id === row.status) {
return r.name
}
}
},
appStatusFilter(status) {
const statusMap = {
'0': 'danger',
'1': 'success',
'2': 'gray'
}
return statusMap[status]
}
},
data() {
return {
list: null,
listLoading: true,
total: 0,
listQuery: {
page: 1,
limit: 10,
name: undefined,
sort: '-created_time',
card: undefined,
mobile: undefined,
status: undefined,
user_id: undefined
},
sortOptions,
certification_status_choices: []
}
},
created() {
this.fetchData()
},
methods: {
handleFilter() {
this.listQuery.page = 1
this.fetchData()
},
fetchData() {
this.listLoading = true
getStorageInfo(this.listQuery).then(response => {
this.list = response.data
if (this.list && this.list.length > 0) {
this.certification_status_choices = this.list[0].certification_status_choices
}
this.total = response.total
this.listLoading = false
})
}
}
}
</script>

@ -56,6 +56,11 @@
<el-select v-model="postForm.certification" class="filter-item" placeholder="Please select" :disabled="postForm.certification === -1"> <el-select v-model="postForm.certification" class="filter-item" placeholder="Please select" :disabled="postForm.certification === -1">
<el-option v-for="item in postForm.certification_status_choices" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in postForm.certification_status_choices" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
<router-link v-if="postForm.certification_id" :to="{name: 'user_authentication_info_edit',params:{id:postForm.certification_id.id}}">
<el-button type="primary">
审核认证信息
</el-button>
</router-link>
</el-col> </el-col>
<el-col v-if="postForm.certification === -1" span="16"> <el-col v-if="postForm.certification === -1" span="16">
<el-link :underline="false"> 用户需要先提交认证信息才可以进行认证修改</el-link> <el-link :underline="false"> 用户需要先提交认证信息才可以进行认证修改</el-link>

@ -15,8 +15,9 @@ Including another URLconf
""" """
from django.urls import re_path from django.urls import re_path
from admin.views.login import LoginView, LoginUserView from admin.views.login import LoginView, LoginUserView
from admin.views.user import UserInfoView from admin.views.user import UserInfoView, UserCertificationInfoView
from admin.views.app import AppInfoView, AppReleaseInfoView from admin.views.app import AppInfoView, AppReleaseInfoView
from admin.views.storage import StorageInfoView
urlpatterns = [ urlpatterns = [
# path("",include(router.urls)), # path("",include(router.urls)),
@ -27,5 +28,7 @@ urlpatterns = [
re_path("^userinfo", UserInfoView.as_view()), re_path("^userinfo", UserInfoView.as_view()),
re_path("^app/info", AppInfoView.as_view()), re_path("^app/info", AppInfoView.as_view()),
re_path("^app/release/info", AppReleaseInfoView.as_view()), re_path("^app/release/info", AppReleaseInfoView.as_view()),
re_path("^certification/info", UserCertificationInfoView.as_view()),
re_path("^storage/info", StorageInfoView.as_view()),
] ]

@ -0,0 +1,73 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 4月
# author: liuyu
# date: 2021/4/11
from django.contrib import auth
from api.models import Token, UserInfo, AppStorage
from rest_framework.response import Response
from api.utils.auth import AdminTokenAuthentication
from api.utils.serializer import AdminStorageSerializer, AdminUserCertificationSerializer
from django.core.cache import cache
from rest_framework.views import APIView
import binascii
import os, datetime
from api.utils.utils import get_captcha, valid_captcha, get_choices_dict
from api.utils.response import BaseResponse
from fir_ser.settings import CACHE_KEY_TEMPLATE, LOGIN
from api.utils.storage.caches import login_auth_failed
import logging
from api.utils.throttle import VisitRegister1Throttle, VisitRegister2Throttle
from rest_framework.pagination import PageNumberPagination
logger = logging.getLogger(__name__)
class AppsPageNumber(PageNumberPagination):
page_size = 20 # 每页显示多少条
page_size_query_param = 'limit' # URL中每页显示条数的参数
page_query_param = 'page' # URL中页码的参数
max_page_size = None # 最大页码数限制
class StorageInfoView(APIView):
authentication_classes = [AdminTokenAuthentication, ]
def get(self, request):
res = BaseResponse()
filter_data = {}
filter_fileds = ["id", "user_id", "name", "storage_type", "access_key", "bucket_name"]
for filed in filter_fileds:
f_value = request.query_params.get(filed, None)
if f_value:
filter_data[filed] = f_value
sort = request.query_params.get("sort", "-created_time")
page_obj = AppsPageNumber()
obj_list = AppStorage.objects.filter(**filter_data).order_by(sort)
page_serializer = page_obj.paginate_queryset(queryset=obj_list, request=request,
view=self)
serializer = AdminStorageSerializer(page_serializer, many=True)
res.data = serializer.data
res.total = obj_list.count()
return Response(res.dict)
def put(self, request):
res = BaseResponse()
data = request.data
pk = data.get("id", None)
if not pk:
res.code = 1003
res.msg = "参数错误"
return Response(res.dict)
user_obj = UserInfo.objects.filter(pk=pk).first()
if user_obj:
data['pk'] = pk
users_serializer = AdminStorageSerializer(user_obj, data=data, partial=True)
if users_serializer.is_valid():
users_serializer.save()
res.data = users_serializer.data
return Response(res.dict)
res.code = 1004
res.msg = "数据校验失败"
return Response(res.dict)

@ -8,7 +8,7 @@ from django.contrib import auth
from api.models import Token, UserInfo, UserCertificationInfo from api.models import Token, UserInfo, UserCertificationInfo
from rest_framework.response import Response from rest_framework.response import Response
from api.utils.auth import AdminTokenAuthentication from api.utils.auth import AdminTokenAuthentication
from api.utils.serializer import AdminUserInfoSerializer from api.utils.serializer import AdminUserInfoSerializer, AdminUserCertificationSerializer
from django.core.cache import cache from django.core.cache import cache
from rest_framework.views import APIView from rest_framework.views import APIView
import binascii import binascii
@ -80,3 +80,46 @@ class UserInfoView(APIView):
res.code = 1004 res.code = 1004
res.msg = "数据校验失败" res.msg = "数据校验失败"
return Response(res.dict) return Response(res.dict)
class UserCertificationInfoView(APIView):
authentication_classes = [AdminTokenAuthentication, ]
def get(self, request):
res = BaseResponse()
filter_data = {}
filter_fileds = ["id", "card", "name", "status"]
for filed in filter_fileds:
f_value = request.query_params.get(filed, None)
if f_value:
filter_data[filed] = f_value
sort = request.query_params.get("sort", "-created_time")
page_obj = AppsPageNumber()
obj_list = UserCertificationInfo.objects.filter(**filter_data).order_by(sort)
page_serializer = page_obj.paginate_queryset(queryset=obj_list, request=request,
view=self)
users_serializer = AdminUserCertificationSerializer(page_serializer, many=True)
res.data = users_serializer.data
res.total = obj_list.count()
return Response(res.dict)
def put(self, request):
res = BaseResponse()
data = request.data
pk = data.get("id", None)
if not pk:
res.code = 1003
res.msg = "参数错误"
return Response(res.dict)
obj = UserCertificationInfo.objects.filter(id=pk).first()
if obj:
data['pk'] = pk
users_serializer = AdminUserCertificationSerializer(obj, data=data, partial=True)
if users_serializer.is_valid():
users_serializer.save()
res.data = users_serializer.data
return Response(res.dict)
print(users_serializer.errors)
res.code = 1004
res.msg = "数据校验失败"
return Response(res.dict)

@ -404,10 +404,10 @@ class UserCertificationInfo(models.Model):
related_name='certification') related_name='certification')
name = models.CharField(max_length=128, null=False, verbose_name="真实姓名") name = models.CharField(max_length=128, null=False, verbose_name="真实姓名")
card = models.CharField(max_length=128, null=False, verbose_name="身份证号码") card = models.CharField(max_length=128, null=False, verbose_name="身份证号码")
addr = models.CharField(max_length=128, null=False, verbose_name="居住地") addr = models.CharField(max_length=128, null=False, verbose_name="居住地")
mobile = models.BigIntegerField(verbose_name="手机号码", unique=True, null=False) mobile = models.BigIntegerField(verbose_name="手机号码", unique=True, null=False)
status_choices = ((-1, '待认证'), (0, '认证中'), (1, '认证成功'), (2, '认证失败')) status_choices = ((-1, '待认证'), (0, '认证中'), (1, '认证成功'), (2, '认证失败'))
status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="审核状态") status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="认证状态")
msg = models.CharField(max_length=512, null=True, blank=True, verbose_name="备注") msg = models.CharField(max_length=512, null=True, blank=True, verbose_name="备注")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
reviewed_time = models.DateTimeField(auto_now_add=False, verbose_name="审核时间") reviewed_time = models.DateTimeField(auto_now_add=False, verbose_name="审核时间")

@ -4,7 +4,7 @@ from api.utils.app.apputils import bytes2human
from api.utils.TokenManager import DownloadToken from api.utils.TokenManager import DownloadToken
from api.utils.app.supersignutils import get_redirect_server_domain from api.utils.app.supersignutils import get_redirect_server_domain
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.utils import get_developer_udided, get_choices_dict from api.utils.utils import get_developer_udided, get_choices_dict, get_choices_name_from_key
from api.utils.storage.caches import get_user_free_download_times, get_user_cert_auth_status from api.utils.storage.caches import get_user_free_download_times, get_user_cert_auth_status
import os, json, logging import os, json, logging
@ -20,7 +20,7 @@ def get_download_url_from_context(self, obj, key, url, force_new=False):
if self.context.get("storage", None) and self.context.get("storage") != "undefined": if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None) storage = self.context.get("storage", None)
else: else:
if isinstance(obj, models.Apps): if isinstance(obj, models.Apps) or isinstance(obj, models.UserCertificationInfo):
storage = Storage(obj.user_id) storage = Storage(obj.user_id)
elif isinstance(obj, models.AppReleaseInfo): elif isinstance(obj, models.AppReleaseInfo):
storage = Storage(obj.app_id.user_id) storage = Storage(obj.app_id.user_id)
@ -83,7 +83,7 @@ class AdminUserInfoSerializer(UserInfoSerializer):
read_only_fields = ["id", "head_img", "free_download_times", "last_login", read_only_fields = ["id", "head_img", "free_download_times", "last_login",
"is_superuser", "last_name", "is_staff", "uid", "storage_active", "supersign_active", "is_superuser", "last_name", "is_staff", "uid", "storage_active", "supersign_active",
"date_joined", "download_times", "all_download_times", "storage", "groups", "date_joined", "download_times", "all_download_times", "storage", "groups",
"user_permissions"] "user_permissions", "certification_id"]
gender_choices = serializers.SerializerMethodField() gender_choices = serializers.SerializerMethodField()
@ -105,6 +105,11 @@ class AdminUserInfoSerializer(UserInfoSerializer):
def get_certification_status_choices(self, obj): def get_certification_status_choices(self, obj):
return get_choices_dict(models.UserCertificationInfo.status_choices) return get_choices_dict(models.UserCertificationInfo.status_choices)
certification_id = serializers.SerializerMethodField()
def get_certification_id(self, obj):
return models.UserCertificationInfo.objects.filter(user_id=obj).values('id').first()
def update(self, instance, validated_data): def update(self, instance, validated_data):
return super(AdminUserInfoSerializer, self).update(instance, validated_data) return super(AdminUserInfoSerializer, self).update(instance, validated_data)
@ -322,7 +327,6 @@ class AdminAppReleaseSerializer(AppReleaseSerializer):
return get_choices_dict(obj.release_choices) return get_choices_dict(obj.release_choices)
def update(self, instance, validated_data): def update(self, instance, validated_data):
print(validated_data)
if validated_data.get("is_master", False): if validated_data.get("is_master", False):
models.AppReleaseInfo.objects.filter(app_id=instance.app_id).update(**{"is_master": False}) models.AppReleaseInfo.objects.filter(app_id=instance.app_id).update(**{"is_master": False})
else: else:
@ -357,6 +361,13 @@ class StorageSerializer(serializers.ModelSerializer):
return None return None
class AdminStorageSerializer(StorageSerializer):
class Meta:
model = models.AppStorage
fields = "__all__"
read_only_fields = ["id", "user_id", "updated_time", "created_time"]
class DeveloperSerializer(serializers.ModelSerializer): class DeveloperSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.AppIOSDeveloperInfo model = models.AppIOSDeveloperInfo
@ -447,3 +458,29 @@ class UserCertificationSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = models.UserCertificationInfo model = models.UserCertificationInfo
exclude = ["id", "user_id", "created_time"] exclude = ["id", "user_id", "created_time"]
class AdminUserCertificationSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserCertificationInfo
fields = "__all__"
read_only_fields = ["id", "user_id", "reviewed_time", "created_time"]
certification_status_choices = serializers.SerializerMethodField()
def get_certification_status_choices(self, obj):
return get_choices_dict(obj.status_choices)
certification_infos = serializers.SerializerMethodField()
def get_certification_infos(self, obj):
result = []
for c_info in models.CertificationInfo.objects.filter(user_id=obj.user_id).all():
result.append({
'name': get_choices_name_from_key(models.CertificationInfo.type_choices, c_info.type),
'certification_url': get_download_url_from_context(self, obj, '', c_info.certification_url)
})
return result
def update(self, instance, validated_data):
return super(AdminUserCertificationSerializer, self).update(instance, validated_data)

@ -304,3 +304,11 @@ def get_choices_dict(choices):
for choice in choices_org_list: for choice in choices_org_list:
result.append({'id': choice[0], 'name': choice[1]}) result.append({'id': choice[0], 'name': choice[1]})
return result return result
def get_choices_name_from_key(choices, key):
choices_org_list = list(choices)
for choice in choices_org_list:
if choice[0] == key:
return choice[1]
return ''

Loading…
Cancel
Save