增加应用截图上传

pull/5/head
youngS 4 years ago
parent 68c7de7374
commit ecadd2a030
  1. 101
      fir_client/src/components/FirAppInfosbaseinfo.vue
  2. 2
      fir_client/src/components/FirUserProfileBase.vue
  3. 17
      fir_ser/api/migrations/0022_appreleaseinfo_distribution_name.py
  4. 31
      fir_ser/api/migrations/0023_auto_20210316_1602.py
  5. 16
      fir_ser/api/models.py
  6. 81
      fir_ser/api/utils/serializer.py
  7. 39
      fir_ser/api/views/apps.py
  8. 19
      fir_ser/api/views/uploads.py
  9. 2
      fir_ser/fir_ser/settings.py

@ -1,9 +1,9 @@
<template>
<div style="margin-top: 20px;width: 56%;margin-left: 8%">
<div style="margin-top: 20px;width: 100%;margin-left: 8%">
<el-form ref="form" label-width="80px">
<el-form-item label="应用ID">
<el-form-item label="应用ID" style="width: 55%">
<el-row>
<el-col :span="19">
@ -19,23 +19,23 @@
</el-form-item>
<el-form-item label="应用名称">
<el-form-item label="应用名称" style="width: 56%">
<el-input v-model="currentapp.name"></el-input>
</el-form-item>
<el-form-item label="短链接">
<el-form-item label="短链接" style="width: 56%">
<el-input v-model="currentapp.short" maxlength="16" show-word-limit type="text">
<template slot="prepend">{{ currentapp.preview_url }}/</template>
</el-input>
</el-form-item>
<el-form-item label="应用图标">
<el-form-item label="应用图标" style="width: 56%">
<el-upload
class="avatar-uploader"
action="#"
:show-file-list="false"
accept=".png , .jpg , .jpeg"
:before-upload="beforeAvatarUpload">
:before-upload="upload_app_icon">
<img v-if="currentapp.icon_url" :src="currentapp.icon_url"
class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
@ -43,12 +43,38 @@
</el-form-item>
<el-form-item label="应用描述">
<el-form-item label="应用描述" style="width: 66%">
<el-input type="textarea" v-model="currentapp.description"
:autosize="{ minRows: 6, maxRows: 18}"></el-input>
</el-form-item>
<el-divider></el-divider>
<el-form-item label="应用截图" style="width: 100%">
<div class="appdownload">
<el-image
style="width: 155px;height: 288px;margin-right: 20px;background-color: #d1eef9;float: left"
fit="scale-down"
@click="delscreen(screen.id)"
v-for="(screen) in currentapp.screenshots" :key="screen.id" :src="screen.url" alt=""/>
<div style="width: 155px;height: 288px;background-color: #d1eef9;float: left"
v-if="currentapp.screenshots && currentapp.screenshots.length < 5">
<el-upload
drag
action="#"
accept=".png , .jpg , .jpeg"
:before-upload="upload_app_screen">
<i class="el-icon-upload"></i>
</el-upload>
</div>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveappinfo">保存</el-button>
<el-button type="primary" @click="saveappinfo('save')">保存</el-button>
</el-form-item>
</el-form>
@ -58,7 +84,7 @@
</template>
<script>
import {apputils, getapppicurl, uploadimgs, getuploadurl} from "../restful"
import {apputils, getapppicurl, uploadimgs, getuploadurl, releaseapputils} from "../restful"
import {uploadaliyunoss, uploadlocalstorage, uploadqiniuoss} from "../utils";
export default {
@ -68,20 +94,47 @@
currentapp: {},
imageUrl: "",
uploadconf: {},
uploadprocess: 0
uploadprocess: 0,
dialogImageUrl: '',
dialogVisible: false
}
},
methods: {
// eslint-disable-next-line no-unused-vars
delscreen(screen_id) {
this.$confirm('确定要删除该应用截图?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
releaseapputils(data => {
if (data.code === 1000) {
this.$message.success('删除成功');
this.updateinfo();
} else if (data.code === 1003) {
this.$router.push({name: 'FirApps'});
}
}, {
"methods": "DELETE",
"app_id": this.$route.params.id,
"release_id": "screen",
"data": {'screen_id': screen_id}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消操作'
});
});
},
updateimgs(certinfo) {
uploadimgs(data => {
if (data.code === 1000) {
// eslint-disable-next-line no-console
// console.log(data.data);
this.$message.success('上传成功');
this.updateinfo();
} else {
this.$message.error('更新失败');
this.$message.error('更新失败: ' + data.msg);
}
}, {'methods': 'PUT', 'data': {'certinfo': certinfo}});
@ -189,7 +242,13 @@
}
});
},
beforeAvatarUpload(file) {
upload_app_icon(file) {
return this.beforeAvatarUpload(file, 'app')
},
upload_app_screen(file) {
return this.beforeAvatarUpload(file, 'screen')
},
beforeAvatarUpload(file, act) {
const isLt2M = file.size / 1024 / 1024 < 2;
if (file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg') {
if (isLt2M) {
@ -200,7 +259,7 @@
}
}, {
'methods': 'GET',
'data': {'app_id': this.currentapp.app_id, 'upload_key': file.name, 'ftype': 'app'}
'data': {'app_id': this.currentapp.app_id, 'upload_key': file.name, 'ftype': act}
});
} else {
this.$message.error('上传应用图片大小不能超过 2MB!');
@ -234,7 +293,15 @@
</script>
<style scoped>
.appdownload /deep/ .el-upload-dragger {
background: #d1eef9;
width: 155px;
height: 288px;
}
.appdownload /deep/ .el-icon-upload {
margin-top: 80%;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
@ -245,7 +312,7 @@
}
.avatar-uploader .el-upload:hover {
.avatar-uploader .el-image:hover {
border-color: #409EFF;
}

@ -85,7 +85,7 @@
this.updateUserInfo({"methods": 'GET'});
} else {
this.$message.error('更新失败');
this.$message.error('更新失败: ' + data.msg);
}
}, {'methods': 'PUT', 'data': {'certinfo': certinfo}});
},

@ -0,0 +1,17 @@
# Generated by Django 3.0.3 on 2021-03-16 14:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0021_auto_20210308_1951'),
]
operations = [
migrations.AddField(
model_name='appreleaseinfo',
name='distribution_name',
field=models.CharField(blank=True, default='', max_length=128, null=True, verbose_name='企业签名'),
),
]

@ -0,0 +1,31 @@
# Generated by Django 3.0.3 on 2021-03-16 16:02
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0022_appreleaseinfo_distribution_name'),
]
operations = [
migrations.CreateModel(
name='AppScreenShot',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('screenshot_url', models.CharField(blank=True, max_length=128, verbose_name='应用截图URL')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('app_id',
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
],
options={
'verbose_name': '应用截图',
'verbose_name_plural': '应用截图',
},
),
migrations.AddIndex(
model_name='appscreenshot',
index=models.Index(fields=['app_id'], name='api_appscre_app_id__b65655_idx'),
),
]

@ -133,6 +133,20 @@ class Apps(models.Model):
return "%s %s-%s %s" % (self.name, self.get_type_display(), self.short, self.issupersign)
class AppScreenShot(models.Model):
app_id = models.ForeignKey(to="Apps", on_delete=models.CASCADE, verbose_name="属于哪个APP")
screenshot_url = models.CharField(max_length=128, blank=True, verbose_name="应用截图URL")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
class Meta:
verbose_name = '应用截图'
verbose_name_plural = "应用截图"
indexes = [models.Index(fields=['app_id'])]
def __str__(self):
return "%s-%s" % (self.app_id, self.screenshot_url)
class AppReleaseInfo(models.Model):
is_master = models.BooleanField(verbose_name="是否master版本", default=True)
release_id = models.CharField(max_length=64, unique=True, verbose_name="release 版本id", db_index=True)
@ -155,7 +169,7 @@ class AppReleaseInfo(models.Model):
verbose_name_plural = "应用详情"
def __str__(self):
return "%s" % (self.release_id)
return "%s-%s" % (self.app_id, self.release_id)
class AppStorage(models.Model):

@ -12,6 +12,33 @@ logger = logging.getLogger(__file__)
token_obj = DownloadToken()
def get_download_url_from_context(self, key, url, force_new=False):
icon_url = ""
if self.context.get("key", None) and self.context.get("key") != "undefined":
key = self.context.get("key", '')
if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None)
icon_url = storage.get_download_url(os.path.basename(url), 600, key, force_new)
return icon_url
def get_app_master_obj_from_context(self, obj):
master_release_obj = models.AppReleaseInfo.objects.filter(app_id=obj, is_master=True).first()
if self.context.get("release_id", None) and self.context.get("release_id") != "undefined":
master_release_obj = models.AppReleaseInfo.objects.filter(app_id=obj,
release_id=self.context.get("release_id")).first()
return master_release_obj
def get_screenshots_from_self(self, obj, force_new=False):
screenshots_list = []
for screenshot_obj in models.AppScreenShot.objects.filter(app_id=obj).all():
key = ''
icon_url = get_download_url_from_context(self, key, screenshot_obj.screenshot_url, force_new)
screenshots_list.append({'id': screenshot_obj.pk, 'url': icon_url})
return screenshots_list
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
@ -58,22 +85,18 @@ class AppsSerializer(serializers.ModelSerializer):
def get_supersign_used_number(self, obj):
return models.APPSuperSignUsedInfo.objects.filter(app_id=obj).all().count()
screenshots = serializers.SerializerMethodField()
def get_screenshots(self, obj):
return get_screenshots_from_self(self, obj)
master_release = serializers.SerializerMethodField()
def get_master_release(self, obj):
master_release_obj = models.AppReleaseInfo.objects.filter(app_id=obj, is_master=True).first()
if self.context.get("release_id", None) and self.context.get("release_id") != "undefined":
master_release_obj = models.AppReleaseInfo.objects.filter(app_id=obj,
release_id=self.context.get("release_id")).first()
master_release_obj = get_app_master_obj_from_context(self, obj)
if master_release_obj:
icon_url = ""
key = ''
if self.context.get("key", None) and self.context.get("key") != "undefined":
key = self.context.get("key", '')
if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None)
icon_url = storage.get_download_url(os.path.basename(master_release_obj.icon_url), 600, key=key)
icon_url = get_download_url_from_context(self, key, master_release_obj.icon_url)
datainfo = {
"app_version": master_release_obj.app_version,
"icon_url": icon_url,
@ -107,7 +130,12 @@ class AppsShortSerializer(serializers.ModelSerializer):
class Meta:
model = models.Apps
fields = ["app_id", "name", "short", "has_combo", "isshow", "description", "need_password", 'master_release',
'type', 'issupersign', 'wxeasytype', 'wxredirect', 'domain_name']
'type', 'issupersign', 'wxeasytype', 'wxredirect', 'domain_name', 'screenshots']
screenshots = serializers.SerializerMethodField()
def get_screenshots(self, obj):
return get_screenshots_from_self(self, obj, True)
need_password = serializers.SerializerMethodField()
@ -127,20 +155,10 @@ class AppsShortSerializer(serializers.ModelSerializer):
master_release = serializers.SerializerMethodField()
def get_master_release(self, obj):
master_release_obj = models.AppReleaseInfo.objects.filter(app_id=obj, is_master=True).first()
if self.context.get("release_id", None) and self.context.get("release_id") != "undefined":
master_release_obj = models.AppReleaseInfo.objects.filter(app_id=obj,
release_id=self.context.get("release_id")).first()
master_release_obj = get_app_master_obj_from_context(self, obj)
if master_release_obj:
icon_url = ""
key = ''
if self.context.get("key", None) and self.context.get("key") != "undefined":
key = self.context.get("key", '')
if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None)
icon_url = storage.get_download_url(os.path.basename(master_release_obj.icon_url), 600, key=key,
force_new=True)
icon_url = get_download_url_from_context(self, key, os.path.basename(master_release_obj.icon_url), True)
datainfo = {
"app_version": master_release_obj.app_version,
"icon_url": icon_url,
@ -191,21 +209,10 @@ class AppReleaseSerializer(serializers.ModelSerializer):
return bytes2human(obj.binary_size)
def get_download_token(self, obj):
download_token = token_obj.make_token(obj.release_id, 600)
return download_token
return token_obj.make_token(obj.release_id, 600)
def get_icon_url(self, obj):
icon_url = ""
key = ''
if self.context.get("key", None) and self.context.get("key") != "undefined":
key = self.context.get("key", '')
if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None)
icon_url = storage.get_download_url(os.path.basename(obj.icon_url), 600, key=key)
return icon_url
return get_download_url_from_context(self, '', os.path.basename(obj.icon_url), force_new=False)
def get_master_color(self, obj):
if obj.is_master:

@ -12,7 +12,7 @@ from django.db.models import Sum
from api.utils.app.supersignutils import IosUtils, resign_by_app_obj
from api.utils.storage.storage import Storage
from api.utils.storage.caches import del_cache_response_by_short, get_app_today_download_times, del_cache_by_delete_app
from api.models import Apps, AppReleaseInfo, APPToDeveloper, AppIOSDeveloperInfo, UserInfo
from api.models import Apps, AppReleaseInfo, APPToDeveloper, AppIOSDeveloperInfo, UserInfo, AppScreenShot
from api.utils.serializer import AppsSerializer, AppReleaseSerializer, UserInfoSerializer
from rest_framework.pagination import PageNumberPagination
import logging
@ -22,6 +22,15 @@ from api.utils.utils import is_valid_domain, delete_local_files
logger = logging.getLogger(__name__)
def get_release_apps(res, app_serializer, apps_obj, storage):
res.data["currentapp"] = app_serializer.data
app_release_obj = AppReleaseInfo.objects.filter(app_id=apps_obj).all().order_by("-created_time")
app_release_serializer = AppReleaseSerializer(app_release_obj, many=True,
context={"storage": storage})
res.data["release_apps"] = app_release_serializer.data
return res
class AppsPageNumber(PageNumberPagination):
page_size = 20 # 每页显示多少条
page_size_query_param = 'size' # URL中每页显示条数的参数
@ -291,14 +300,9 @@ class AppReleaseinfoView(APIView):
if app_id:
apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
if apps_obj:
app_serializer = AppsSerializer(apps_obj, context={"storage": Storage(request.user)})
res.data["currentapp"] = app_serializer.data
app_release_obj = AppReleaseInfo.objects.filter(app_id=apps_obj).all().order_by("-created_time")
app_release_serializer = AppReleaseSerializer(app_release_obj, many=True,
context={"storage": Storage(request.user)})
res.data["release_apps"] = app_release_serializer.data
storage = Storage(request.user)
app_serializer = AppsSerializer(apps_obj, context={"storage": storage})
res = get_release_apps(res, app_serializer, apps_obj, storage)
else:
res.msg = "未找到该应用"
res.code = 1003
@ -310,6 +314,16 @@ class AppReleaseinfoView(APIView):
apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
if apps_obj:
storage = Storage(request.user)
if act == 'screen':
screen_id = request.query_params.get('screen_id', None)
if screen_id:
screen_obj = AppScreenShot.objects.filter(pk=screen_id, app_id=apps_obj).first()
if screen_obj:
storage.delete_file(screen_obj.screenshot_url)
screen_obj.delete()
del_cache_response_by_short(apps_obj.app_id)
return Response(res.dict)
apprelease_count = AppReleaseInfo.objects.filter(app_id=apps_obj).values("release_id").count()
appreleaseobj = AppReleaseInfo.objects.filter(app_id=apps_obj, release_id=act).first()
if not appreleaseobj.is_master:
@ -377,11 +391,6 @@ class AppReleaseinfoView(APIView):
del_cache_response_by_short(apps_obj.app_id)
app_serializer = AppsSerializer(apps_obj)
res.data["currentapp"] = app_serializer.data
app_release_obj = AppReleaseInfo.objects.filter(app_id=apps_obj).all().order_by("-created_time")
app_release_serializer = AppReleaseSerializer(app_release_obj, many=True,
context={"storage": Storage(request.user)})
res.data["release_apps"] = app_release_serializer.data
res = get_release_apps(res, app_serializer, apps_obj, Storage(request.user))
return Response(res.dict)

@ -7,7 +7,7 @@
from api.utils.app.apputils import get_random_short, SaveAppInfos
from api.utils.storage.storage import Storage
from api.utils.storage.caches import upload_file_tmp_name, del_cache_response_by_short
from api.models import Apps, AppReleaseInfo, UserInfo
from api.models import Apps, AppReleaseInfo, UserInfo, AppScreenShot
from api.utils.app.randomstrings import make_app_uuid
from rest_framework.views import APIView
from api.utils.response import BaseResponse
@ -157,7 +157,7 @@ class UploadView(APIView):
app_id = request.query_params.get("app_id", None)
ftype = request.query_params.get("ftype", None)
if ftype and app_id and request_upload_key:
if ftype == 'app':
if ftype == 'app' or ftype == 'screen':
app_obj = Apps.objects.filter(app_id=app_id, user_id=request.user).first()
elif ftype and ftype == 'head':
@ -224,7 +224,7 @@ class UploadView(APIView):
app_id = certinfo.get("app_id", None)
ftype = certinfo.get("ftype", None)
if ftype and ftype == 'app':
if ftype and ftype in ['app', 'screen']:
pass
# app_obj = Apps.objects.filter(app_id=app_id, user_id=request.user).first()
# if not app_obj:
@ -308,6 +308,19 @@ class UploadView(APIView):
del_cache_response_by_short(app_id)
storage.delete_file(old_file_key)
return Response(res.dict)
elif ftype and app_id and ftype == 'screen':
app_obj = Apps.objects.filter(app_id=app_id, user_id=request.user).first()
if app_obj:
scount = AppScreenShot.objects.filter(app_id=app_obj).count()
if scount >= 5:
storage.delete_file(certinfo.get("upload_key"))
res.msg = '最多支持五张截图'
res.code = 1009
return Response(res.dict)
AppScreenShot.objects.create(app_id=app_obj, screenshot_url=certinfo.get("upload_key"))
del_cache_response_by_short(app_id)
return Response(res.dict)
elif ftype and app_id and ftype == 'head':
if request.user.uid != app_id:
res.code = 1007

@ -170,7 +170,7 @@ REST_FRAMEWORK_EXTENSIONS = {
# 注册方式,如果启用sms或者email 需要配置 THIRD_PART_CONFIG.sender 信息
REGISTER = {
"enable": False,
"enable": True,
"captcha": True, # 是否开启注册字母验证码
"register_type": {
'sms': False, # 短信注册

Loading…
Cancel
Save