diff --git a/fir_admin/src/api/app.js b/fir_admin/src/api/app.js index 7606992..91d9ddb 100644 --- a/fir_admin/src/api/app.js +++ b/fir_admin/src/api/app.js @@ -2,7 +2,7 @@ import request from '@/utils/request' export function getAppInfos(query) { return request({ - url: '/appinfo', + url: '/app/info', method: 'get', params: query }) @@ -10,7 +10,23 @@ export function getAppInfos(query) { export function updateAppInfo(data) { return request({ - url: '/appinfo', + url: '/app/info', + method: 'put', + data + }) +} + +export function getAppReleaseInfos(query) { + return request({ + url: '/app/release/info', + method: 'get', + params: query + }) +} + +export function updateReleaseAppInfo(data) { + return request({ + url: '/app/release/info', method: 'put', data }) diff --git a/fir_admin/src/router/index.js b/fir_admin/src/router/index.js index 6b019b7..8a30e93 100644 --- a/fir_admin/src/router/index.js +++ b/fir_admin/src/router/index.js @@ -102,6 +102,20 @@ export const constantRoutes = [ name: 'app_info_edit', meta: { title: '编辑信息', noCache: true, activeMenu: '/apps/list' }, hidden: true + }, + { + path: 'release/:app_id(\\d+)/list', + name: 'app_release_info_list', + component: () => import('@/views/appinfos/AppReleaseList'), + meta: { title: '版本记录', noCache: true, activeMenu: '/apps/list' }, + hidden: true + }, + { + path: 'release/:app_id(\\d+)/edit/:id(\\d+)', + name: 'app_release_info_edit', + component: () => import('@/views/appinfos/AppReleaseDetail'), + meta: { title: '版本记录', noCache: true, activeMenu: '/apps/list' }, + hidden: true } ] }, diff --git a/fir_admin/src/views/appinfos/AppDetail.vue b/fir_admin/src/views/appinfos/AppDetail.vue index 51de4c6..16c3942 100644 --- a/fir_admin/src/views/appinfos/AppDetail.vue +++ b/fir_admin/src/views/appinfos/AppDetail.vue @@ -297,9 +297,3 @@ export default { } - - diff --git a/fir_admin/src/views/appinfos/AppReleaseDetail.vue b/fir_admin/src/views/appinfos/AppReleaseDetail.vue new file mode 100644 index 0000000..e829c2d --- /dev/null +++ b/fir_admin/src/views/appinfos/AppReleaseDetail.vue @@ -0,0 +1,195 @@ + + + + diff --git a/fir_admin/src/views/appinfos/AppReleaseList.vue b/fir_admin/src/views/appinfos/AppReleaseList.vue new file mode 100644 index 0000000..cbcf6b5 --- /dev/null +++ b/fir_admin/src/views/appinfos/AppReleaseList.vue @@ -0,0 +1,167 @@ + + + diff --git a/fir_admin/src/views/appinfos/list.vue b/fir_admin/src/views/appinfos/list.vue index e775a38..5f1e41d 100644 --- a/fir_admin/src/views/appinfos/list.vue +++ b/fir_admin/src/views/appinfos/list.vue @@ -33,7 +33,7 @@ {{ scope.row.id }} - + @@ -76,6 +76,18 @@ {{ scope.row.count_hits }} + + + + + + - + diff --git a/fir_admin/src/views/userinfos/UserDetail.vue b/fir_admin/src/views/userinfos/UserDetail.vue index 3099a6c..3200bab 100644 --- a/fir_admin/src/views/userinfos/UserDetail.vue +++ b/fir_admin/src/views/userinfos/UserDetail.vue @@ -50,6 +50,18 @@ + + + + + + + + + 用户需要先提交认证信息,才可以进行认证修改 + + + @@ -305,6 +317,7 @@ export default { source_uri: [{ validator: validateSourceUri, trigger: 'blur' }] }, is_edit: false, + certification_status_choices: [] } }, computed: { @@ -320,6 +333,7 @@ export default { getUserInfos({ id: id }).then(response => { if (response.data.length === 1) { this.postForm = response.data[0] + this.certification_status_choices = this.postForm.certification_status_choices } }).catch(err => { console.log(err) diff --git a/fir_admin/src/views/userinfos/list.vue b/fir_admin/src/views/userinfos/list.vue index 2b36146..ad9a9dc 100644 --- a/fir_admin/src/views/userinfos/list.vue +++ b/fir_admin/src/views/userinfos/list.vue @@ -6,7 +6,7 @@ - + @@ -79,7 +79,7 @@ @@ -94,8 +94,8 @@ @@ -111,13 +111,6 @@ import { getUserInfos } from '@/api/user' import Pagination from '@/components/Pagination' // secondary package based on el-pagination import waves from '@/directive/waves' // waves directive -const searchCertficationOptions = [ - { key: '-1', display_name: '未认证' }, - { key: '0', display_name: '认证中' }, - { key: '1', display_name: '认证成功' }, - { key: '2', display_name: '认证失败' } -] - const sortOptions = [ { label: '注册时间 Ascending', key: 'date_joined' }, { label: '注册时间 Descending', key: '-date_joined' }, @@ -149,10 +142,10 @@ export default { } return statusMap[status] }, - certLableFilter(status) { - for (const v of searchCertficationOptions) { - if (v.key === status.toString()) { - return v.display_name + certLableFilter(row) { + for (const v of row.certification_status_choices) { + if (v.id === row.certification) { + return v.name } } } @@ -172,7 +165,7 @@ export default { mobile: undefined }, sortOptions, - searchCertficationOptions + certification_status_choices: [] } }, created() { @@ -188,6 +181,9 @@ export default { getUserInfos(this.listQuery).then(response => { this.list = response.data this.total = response.total + if (this.list && this.list.length > 0) { + this.certification_status_choices = this.list[0].certification_status_choices + } this.listLoading = false }) } diff --git a/fir_client/src/components/user/FirUserProfileCertification.vue b/fir_client/src/components/user/FirUserProfileCertification.vue index 3e4a1e4..405c6f5 100644 --- a/fir_client/src/components/user/FirUserProfileCertification.vue +++ b/fir_client/src/components/user/FirUserProfileCertification.vue @@ -76,7 +76,7 @@ - diff --git a/fir_ser/admin/urls.py b/fir_ser/admin/urls.py index 5374988..6cfab6e 100644 --- a/fir_ser/admin/urls.py +++ b/fir_ser/admin/urls.py @@ -16,7 +16,7 @@ Including another URLconf from django.urls import re_path from admin.views.login import LoginView, LoginUserView from admin.views.user import UserInfoView -from admin.views.app import AppInfoView +from admin.views.app import AppInfoView, AppReleaseInfoView urlpatterns = [ # path("",include(router.urls)), @@ -25,6 +25,7 @@ urlpatterns = [ re_path("^login", LoginView.as_view()), re_path("^user/info", LoginUserView.as_view()), re_path("^userinfo", UserInfoView.as_view()), - re_path("^appinfo", AppInfoView.as_view()), + re_path("^app/info", AppInfoView.as_view()), + re_path("^app/release/info", AppReleaseInfoView.as_view()), ] diff --git a/fir_ser/admin/views/app.py b/fir_ser/admin/views/app.py index 87aef05..d7ee93e 100644 --- a/fir_ser/admin/views/app.py +++ b/fir_ser/admin/views/app.py @@ -55,14 +55,14 @@ class AppInfoView(APIView): def put(self, request): res = BaseResponse() data = request.data - id = data.get("id", None) - if not id: + pk = data.get("id", None) + if not pk: res.code = 1003 res.msg = "参数错误" return Response(res.dict) - app_obj = Apps.objects.filter(id=id).first() + app_obj = Apps.objects.filter(pk=pk).first() if app_obj: - data['pk'] = id + data['pk'] = pk serializer_obj = AdminAppsSerializer(app_obj, data=data, partial=True) if serializer_obj.is_valid(): serializer_obj.save() @@ -73,6 +73,16 @@ class AppInfoView(APIView): res.msg = "数据校验失败" return Response(res.dict) + def delete(self, request): + res = BaseResponse() + data = request.data + pk = data.get("id", None) + if not pk: + res.code = 1003 + res.msg = "参数错误" + Apps.delete() + return Response(res.dict) + class AppReleaseInfoView(APIView): authentication_classes = [AdminTokenAuthentication, ] @@ -80,12 +90,16 @@ class AppReleaseInfoView(APIView): def get(self, request): res = BaseResponse() filter_data = {} - filter_fields = ["id", "release_id"] + filter_fields = ["id", "release_id", "app_id"] for filed in filter_fields: f_value = request.query_params.get(filed, None) if f_value: filter_data[filed] = f_value sort = request.query_params.get("sort", "-created_time") + if not filter_data.get('app_id', None): + res.code = 1003 + res.msg = "参数错误" + return Response(res.dict) page_obj = AppsPageNumber() obj_list = AppReleaseInfo.objects.filter(**filter_data).order_by(sort) page_serializer = page_obj.paginate_queryset(queryset=obj_list, request=request, @@ -98,19 +112,20 @@ class AppReleaseInfoView(APIView): def put(self, request): res = BaseResponse() data = request.data - id = data.get("id", None) - if not id: + pk = data.get("id", None) + app_id = data.get("app_id", None) + if not pk or not app_id: res.code = 1003 res.msg = "参数错误" return Response(res.dict) - app_obj = Apps.objects.filter(id=id).first() + app_obj = AppReleaseInfo.objects.filter(pk=pk, app_id=app_id).first() if app_obj: - data['pk'] = id + data['pk'] = pk serializer_obj = AdminAppReleaseSerializer(app_obj, data=data, partial=True) if serializer_obj.is_valid(): serializer_obj.save() res.data = serializer_obj.data - del_cache_response_by_short(app_obj.app_id) + del_cache_response_by_short(app_obj.app_id.app_id) return Response(res.dict) res.code = 1004 res.msg = "数据校验失败" diff --git a/fir_ser/admin/views/user.py b/fir_ser/admin/views/user.py index 42dcdcc..0d53a51 100644 --- a/fir_ser/admin/views/user.py +++ b/fir_ser/admin/views/user.py @@ -5,7 +5,7 @@ # date: 2021/4/11 from django.contrib import auth -from api.models import Token, UserInfo +from api.models import Token, UserInfo, UserCertificationInfo from rest_framework.response import Response from api.utils.auth import AdminTokenAuthentication from api.utils.serializer import AdminUserInfoSerializer @@ -37,7 +37,7 @@ class UserInfoView(APIView): def get(self, request): res = BaseResponse() filter_data = {} - filter_fileds = ["id", "mobile", "username", "email", "first_name", "certification", ] + filter_fileds = ["id", "mobile", "username", "email", "first_name"] for filed in filter_fileds: f_value = request.query_params.get(filed, None) if f_value: @@ -72,6 +72,9 @@ class UserInfoView(APIView): users_serializer = AdminUserInfoSerializer(user_obj, data=data, partial=True) if users_serializer.is_valid(): users_serializer.save() + certification = data.get("certification", None) + if certification and certification != -1: + UserCertificationInfo.objects.filter(user_id=user_obj).update(status=data["certification"]) res.data = users_serializer.data return Response(res.dict) res.code = 1004 diff --git a/fir_ser/api/models.py b/fir_ser/api/models.py index 8ce3f54..8d53fa1 100644 --- a/fir_ser/api/models.py +++ b/fir_ser/api/models.py @@ -405,7 +405,7 @@ class UserCertificationInfo(models.Model): card = 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) - status_choices = ((0, '审核中'), (1, '审核成功'), (2, '审核失败')) + status_choices = ((-1, '待认证'),(0, '认证中'), (1, '认证成功'), (2, '认证失败')) status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="审核状态") msg = models.CharField(max_length=512, null=True, blank=True, verbose_name="备注") created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") diff --git a/fir_ser/api/utils/serializer.py b/fir_ser/api/utils/serializer.py index e70334f..5ceb38e 100644 --- a/fir_ser/api/utils/serializer.py +++ b/fir_ser/api/utils/serializer.py @@ -20,7 +20,12 @@ 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": storage = self.context.get("storage", None) else: - storage = Storage(obj.user_id) + if isinstance(obj, models.Apps): + storage = Storage(obj.user_id) + elif isinstance(obj, models.AppReleaseInfo): + storage = Storage(obj.app_id.user_id) + else: + storage = None if storage: icon_url = storage.get_download_url(os.path.basename(url), 600, key, force_new) return icon_url @@ -75,7 +80,7 @@ class AdminUserInfoSerializer(UserInfoSerializer): class Meta: model = models.UserInfo exclude = ["password", "api_token"] - read_only_fields = ["id", "head_img", "free_download_times", "certification", "last_login", + read_only_fields = ["id", "head_img", "free_download_times", "last_login", "is_superuser", "last_name", "is_staff", "uid", "storage_active", "supersign_active", "date_joined", "download_times", "all_download_times", "storage", "groups", "user_permissions"] @@ -95,6 +100,11 @@ class AdminUserInfoSerializer(UserInfoSerializer): def get_storage_choices(self, obj): return get_choices_dict(models.AppStorage.storage_choices[1:]) + certification_status_choices = serializers.SerializerMethodField() + + def get_certification_status_choices(self, obj): + return get_choices_dict(models.UserCertificationInfo.status_choices) + def update(self, instance, validated_data): return super(AdminUserInfoSerializer, self).update(instance, validated_data) @@ -171,7 +181,7 @@ class AdminAppsSerializer(AppsSerializer): class Meta: model = models.Apps fields = "__all__" - read_only_fields = ["id", "app_id", "user_id", "bundle_id", "count_hits","updated_time","created_time"] + read_only_fields = ["id", "app_id", "user_id", "bundle_id", "count_hits", "updated_time", "created_time"] status_choices = serializers.SerializerMethodField() @@ -188,10 +198,15 @@ class AdminAppsSerializer(AppsSerializer): def get_supersign_type_choices(self, obj): return get_choices_dict(obj.supersign_type_choices) + release_count = serializers.SerializerMethodField() + + def get_release_count(self, obj): + return models.AppReleaseInfo.objects.filter(app_id=obj).count() + def update(self, instance, validated_data): - print(validated_data) return super(AdminAppsSerializer, self).update(instance, validated_data) + class AppsShortSerializer(serializers.ModelSerializer): class Meta: model = models.Apps @@ -224,7 +239,8 @@ class AppsShortSerializer(serializers.ModelSerializer): master_release_obj = get_app_master_obj_from_context(self, obj) if master_release_obj: key = '' - icon_url = get_download_url_from_context(self, obj, key, os.path.basename(master_release_obj.icon_url), True) + icon_url = get_download_url_from_context(self, obj, key, os.path.basename(master_release_obj.icon_url), + True) datainfo = { "app_version": master_release_obj.app_version, "icon_url": icon_url, @@ -296,9 +312,9 @@ class AppReleaseSerializer(serializers.ModelSerializer): class AdminAppReleaseSerializer(AppReleaseSerializer): class Meta: - model = models.Apps + model = models.AppReleaseInfo fields = "__all__" - read_only_fields = ["id", "app_id", "release_id", "is_master"] + read_only_fields = ["id", "app_id", "release_id", "binary_size"] release_choices = serializers.SerializerMethodField() @@ -306,8 +322,15 @@ class AdminAppReleaseSerializer(AppReleaseSerializer): return get_choices_dict(obj.release_choices) def update(self, instance, validated_data): + print(validated_data) + if validated_data.get("is_master", False): + models.AppReleaseInfo.objects.filter(app_id=instance.app_id).update(**{"is_master": False}) + else: + if "is_master" in validated_data and validated_data.get("is_master") != True: + del validated_data["is_master"] return super(AdminAppReleaseSerializer, self).update(instance, validated_data) + class StorageSerializer(serializers.ModelSerializer): class Meta: model = models.AppStorage