修复已知问题,增加设备消化统计

qrnn
youngS 3 years ago
parent fd43dcfea4
commit 55f5f65e15
  1. 130
      fir_client/src/components/user/FirSuperSignBase.vue
  2. 15
      fir_client/src/restful/index.js
  3. 3
      fir_ser/api/urls.py
  4. 8
      fir_ser/api/utils/apple/appleapiv3.py
  5. 48
      fir_ser/api/views/supersign.py

@ -722,6 +722,65 @@
</el-table> </el-table>
</el-tab-pane>
<el-tab-pane label="设备消耗统计" name="devicesrank">
<el-input
v-model="appnamesearch"
clearable
placeholder="输入应用名称或BundleID"
style="width: 30%;margin-right: 30px;margin-bottom: 10px"/>
<el-date-picker
v-model="timerangesearch"
:picker-options="pickerOptions"
align="right"
end-placeholder="结束日期"
range-separator="至"
start-placeholder="开始日期"
style="width: 30%;margin-right: 30px;margin-bottom: 10px"
type="daterange"
unlink-panels
value-format="timestamp">
</el-date-picker>
<el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(1)">
搜索
</el-button>
<el-table
v-loading="loading"
:data="app_rank_lists"
border
stripe
style="width: 100%">
<el-table-column
align="center"
fixed
label="应用名称"
prop="name"
>
<template slot-scope="scope">
<el-tooltip content="点击查看设备安装详细信息" effect="dark" placement="top">
<el-link :underline="false" @click="show_device_uinfo(scope.row.bundle_id)">
{{ scope.row.name }}
</el-link>
</el-tooltip>
</template>
</el-table-column>
<el-table-column
align="center"
label="应用ID"
prop="bundle_id">
</el-table-column>
<el-table-column
align="center"
label="消耗设备数"
prop="count"
width="100"
>
</el-table-column>
</el-table>
</el-tab-pane> </el-tab-pane>
<div v-if="activeName!== 'adddeveloper'" style="margin-top: 20px"> <div v-if="activeName!== 'adddeveloper'" style="margin-top: 20px">
<el-pagination <el-pagination
@ -741,7 +800,15 @@
<script> <script>
import {developercert, DeviceBillInfo, iosdeveloper, iosdevices, iosdevicesudid, iosudevices} from "@/restful"; import {
developercert,
DeviceBillInfo,
DeviceRankInfo,
iosdeveloper,
iosdevices,
iosdevicesudid,
iosudevices
} from "@/restful";
import {getUserInfoFun, removeAaary} from "@/utils"; import {getUserInfoFun, removeAaary} from "@/utils";
export default { export default {
@ -757,12 +824,15 @@ export default {
app_developer_lists: [], app_developer_lists: [],
app_devices_lists: [], app_devices_lists: [],
app_bill_lists: [], app_bill_lists: [],
app_rank_lists: [],
app_bill_info_lists: [], app_bill_info_lists: [],
app_udid_lists: [], app_udid_lists: [],
activeName: "iosdeveloper", activeName: "iosdeveloper",
udidsearch: "", udidsearch: "",
Bundleidsearch: "", Bundleidsearch: "",
appidseach: "", appidseach: "",
appnamesearch: "",
timerangesearch: [],
dialogaddDeveloperVisible: false, dialogaddDeveloperVisible: false,
importcertDeveloperVisible: false, importcertDeveloperVisible: false,
title: "", title: "",
@ -778,6 +848,40 @@ export default {
loadingfun: {}, loadingfun: {},
loading: false, loading: false,
cert_pwd: '', cert_pwd: '',
pickerOptions: {
shortcuts: [{
text: '今天',
onClick(picker) {
const end = new Date();
const start = new Date();
picker.$emit('pick', [start, end]);
}
}, {
text: '最近一周',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近一个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近三个月',
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit('pick', [start, end]);
}
}]
},
} }
}, watch: { }, watch: {
'dialogaddDeveloperVisible': function () { 'dialogaddDeveloperVisible': function () {
@ -1009,6 +1113,11 @@ export default {
}); });
}); });
}, },
show_device_uinfo(bundle_id) {
this.Bundleidsearch = bundle_id;
this.activeName = 'useddevices'
this.get_data_from_tabname(this.activeName);
},
get_data_from_tabname(tabname, data = {}) { get_data_from_tabname(tabname, data = {}) {
data.udid = this.udidsearch.replace(/^\s+|\s+$/g, ""); data.udid = this.udidsearch.replace(/^\s+|\s+$/g, "");
data.bundleid = this.Bundleidsearch.replace(/^\s+|\s+$/g, ""); data.bundleid = this.Bundleidsearch.replace(/^\s+|\s+$/g, "");
@ -1026,6 +1135,13 @@ export default {
this.iosdeveloperFun({"methods": "GET", "data": data}) this.iosdeveloperFun({"methods": "GET", "data": data})
} else if (tabname === "devicesbill") { } else if (tabname === "devicesbill") {
this.iosdevicebillFun({"methods": "GET", "data": data}) this.iosdevicebillFun({"methods": "GET", "data": data})
} else if (tabname === "devicesrank") {
if (this.timerangesearch && this.timerangesearch.length === 2) {
data.start_time = this.timerangesearch[0];
data.end_time = this.timerangesearch[1];
}
data.appnamesearch = this.appnamesearch.replace(/^\s+|\s+$/g, "");
this.iosdevicerankFun({"methods": "GET", "data": data})
} else if (tabname === "iosudevices") { } else if (tabname === "iosudevices") {
this.iosudevicesFun("GET", data, null) this.iosudevicesFun("GET", data, null)
} }
@ -1149,6 +1265,18 @@ export default {
this.loading = false this.loading = false
}, params) }, params)
}, },
iosdevicerankFun(params) {
this.loading = true;
DeviceRankInfo(data => {
if (data.code === 1000) {
this.app_rank_lists = data.data;
this.pagination.total = data.count;
} else {
this.$message.error("信息获取失败了 " + data.msg);
}
this.loading = false
}, params)
},
iosdevicesudidFun(action, data, scope) { iosdevicesudidFun(action, data, scope) {
if (action !== 'GET') { if (action !== 'GET') {
this.loadingfun = this.$loading({ this.loadingfun = this.$loading({

@ -724,6 +724,21 @@ export function DeviceBillInfo(callBack, params, load = true) {
); );
} }
/**签名下载排行 */
export function DeviceRankInfo(callBack, params, load = true) {
getData(
params.methods,
USERSEVER + '/supersign/rank',
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}
/**应用举报 */ /**应用举报 */
export function appReport(callBack, params, load = true) { export function appReport(callBack, params, load = true) {
getData( getData(

@ -27,7 +27,7 @@ from api.views.receiveudids import IosUDIDView, TaskView
from api.views.report import ReportView from api.views.report import ReportView
from api.views.storage import StorageView from api.views.storage import StorageView
from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView, SuperSignCertView, \ from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView, SuperSignCertView, \
DeviceUsedBillView, DeveloperDeviceView DeviceUsedBillView, DeveloperDeviceView, DeviceUsedRankInfoView
from api.views.thirdlogin import ValidWxChatToken, ThirdWxAccount from api.views.thirdlogin import ValidWxChatToken, ThirdWxAccount
from api.views.uploads import AppAnalyseView, UploadView from api.views.uploads import AppAnalyseView, UploadView
@ -61,6 +61,7 @@ urlpatterns = [
re_path("^supersign/udevices$", DeveloperDeviceView.as_view()), re_path("^supersign/udevices$", DeveloperDeviceView.as_view()),
re_path("^supersign/cert$", SuperSignCertView.as_view()), re_path("^supersign/cert$", SuperSignCertView.as_view()),
re_path("^supersign/bill$", DeviceUsedBillView.as_view()), re_path("^supersign/bill$", DeviceUsedBillView.as_view()),
re_path("^supersign/rank$", DeviceUsedRankInfoView.as_view()),
re_path("^package_prices$", PriceView.as_view()), re_path("^package_prices$", PriceView.as_view()),
re_path("^orders$", OrderView.as_view()), re_path("^orders$", OrderView.as_view()),
re_path("^certification$", CertificationView.as_view()), re_path("^certification$", CertificationView.as_view()),

@ -654,9 +654,9 @@ def call_function_try_attempts(try_attempts=3, sleep_time=1):
def decorator(func): def decorator(func):
@wraps(func) @wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
res = False, {}
start_time = time.time() start_time = time.time()
flag = False flag = False
res = ''
for i in range(try_attempts): for i in range(try_attempts):
try: try:
res = func(*args, **kwargs) res = func(*args, **kwargs)
@ -666,10 +666,14 @@ def call_function_try_attempts(try_attempts=3, sleep_time=1):
logger.warning( logger.warning(
f'exec {func} failed. Failed:{e} {try_attempts} times in total. now {sleep_time} later try ' f'exec {func} failed. Failed:{e} {try_attempts} times in total. now {sleep_time} later try '
f'again...{i}') f'again...{i}')
res = str(e)
if 'Authentication credentials are missing or invalid' in str(e):
res = '认证失败,请检查开发者信息填写是否正确'
time.sleep(sleep_time) time.sleep(sleep_time)
logger.info(f"exec {func} finished. time:{time.time() - start_time}")
if not flag: if not flag:
logger.error(f'exec {func} failed after the maximum number of attempts. Failed:{res}') logger.error(f'exec {func} failed after the maximum number of attempts. Failed:{res}')
logger.info(f"exec {func} finished. time:{time.time() - start_time}") raise Exception(res)
return res return res
return wrapper return wrapper

@ -3,6 +3,7 @@
# project: 3月 # project: 3月
# author: liuyu # author: liuyu
# date: 2020/3/4 # date: 2020/3/4
import datetime
import logging import logging
from django.db.models import Count, Q from django.db.models import Count, Q
@ -11,7 +12,8 @@ from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from api.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID, IosDeveloperPublicPoolBill, UDIDsyncDeveloper from api.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID, IosDeveloperPublicPoolBill, \
UDIDsyncDeveloper
from api.utils.app.supersignutils import IosUtils from api.utils.app.supersignutils import IosUtils
from api.utils.auth import ExpiringTokenAuthentication, SuperSignPermission from api.utils.auth import ExpiringTokenAuthentication, SuperSignPermission
from api.utils.modelutils import get_user_public_used_sign_num, get_user_public_sign_num from api.utils.modelutils import get_user_public_used_sign_num, get_user_public_sign_num
@ -211,8 +213,9 @@ class DeveloperView(APIView):
if developer_obj: if developer_obj:
logger.error(f"user {request.user} delete developer {developer_obj}") logger.error(f"user {request.user} delete developer {developer_obj}")
IosUtils.clean_developer(developer_obj, request.user) if developer_obj.certid:
IosUtils.revoke_developer_cert(developer_obj, request.user) IosUtils.clean_developer(developer_obj, request.user)
IosUtils.revoke_developer_cert(developer_obj, request.user)
developer_obj.delete() developer_obj.delete()
return self.get(request) return self.get(request)
@ -413,3 +416,42 @@ class DeviceUsedBillView(APIView):
'all_balance': get_user_public_sign_num(request.user) 'all_balance': get_user_public_sign_num(request.user)
} }
return Response(res.dict) return Response(res.dict)
class DeviceUsedRankInfoView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
permission_classes = [SuperSignPermission, ]
def get(self, request):
res = BaseResponse()
page_obj = PageNumber()
appnamesearch = request.query_params.get("appnamesearch")
start_time = request.query_params.get("start_time")
end_time = request.query_params.get("end_time")
app_used_sign_objs = APPSuperSignUsedInfo.objects.filter(user_id=request.user)
if appnamesearch:
app_used_sign_objs = app_used_sign_objs.filter(
Q(app_id__name=appnamesearch) | Q(app_id__bundle_id=appnamesearch))
if end_time and start_time:
try:
start_time = datetime.date.fromtimestamp(int(start_time) / 1000)
end_time = datetime.date.fromtimestamp(int(end_time) / 1000 + 24 * 60 * 60 - 1)
app_used_sign_objs = app_used_sign_objs.filter(created_time__range=[start_time, end_time])
except Exception as e:
logger.error(f"get time range failed {e}")
res.count = app_used_sign_objs.count()
app_used_sign_objs = app_used_sign_objs.values('app_id__app_id', 'app_id__name', 'app_id__bundle_id').annotate(
count=Count('app_id__app_id')).order_by('-count')
app_used_sign_infos = page_obj.paginate_queryset(queryset=app_used_sign_objs,
request=request, view=self)
new_app_used_sign_infos = []
for app_used_info in app_used_sign_infos:
new_app_used_info = {}
for key, value in app_used_info.items():
new_key = key.replace('app_id__', '')
new_app_used_info[new_key] = value
new_app_used_sign_infos.append(new_app_used_info)
res.data = new_app_used_sign_infos
return Response(res.dict)

Loading…
Cancel
Save