一、背景

公司使用的是testlink去维护测试用例,但是因为一些客观原因导致testlink编写测试用例不方便、不易用。同时,testlink的导入只支持xml文件,平常都是大家在excel内编写,然后将excel转为xml,再将xml文件导入到testlink里面。本文只分享上传下载的功能,文件格式内容转换涉及到业务内容就不分享啦。

二、详细信息

仅支持上传xls/xlsx文件,如果不是则抛出错误提示

支持拖拽上传或点击上传,一次只能上传单个文件

上传excel后, 右侧展示其所有sheet的checkbox,选中下载

效果演示:

功能演示

三、上传文件部分

页面展示部分

select your Excel here

class="upload-demo"

ref="upload"

drag

:headers="headers"

:action="backUrl"

:before-upload="handleBefore"

:on-change="handleChange"

:on-success="uploadSuccess"

:show-file-list="true"

:on-remove="handleRemove"

:file-list="fileList"

:limit="1"

>

将文件拖到此处,或点击上传

只能上传xlsx/xls文件,且不超过5M

请求接口鉴权

因为上传接口需要鉴权,所以需要在发送网络请求的时候携带认证信息:

data() {

return {

headers: {

'Authorization': "Token " + this.$auth.token

}

}

},

 mounted() {

    let backURLl

    backURLl = window.VUE_APP_URL.backURL //上传接口

    this.backUrl=backURLl + "/api/v1/AvatarUpload/"

    },

文件上传校验

避免程序出错,需要限制上传的文件类型和大小,在此实现:

export default{

  methods: {

    // excel表上传

    handleBefore(file) {

    // 文件类型

    console.log(`上传前校验---`, file)

    const isType = file.type === 'application/vnd.ms-excel'

    const isTypeComputer = file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

    const fileType = isType || isTypeComputer

    if (!fileType) {

    this.$message.error('上传文件只能是xls/xlsx格式!')

    }

    // 文件大小限制为5M

    const fileLimit = file.size / 1024 / 1024 < 5

    if (!fileLimit) {

    this.$message.error('上传文件大小不超过5M!')

    }

    return fileType && fileLimit

    },

}

}

解析内存文件

常常在使用xlrd模块时,一般都是解析本地的某个实质性、物理的文件。而此处不一样,从前端传送过来,我并不想将其落到磁盘里面,于是直接在内存中直接进行解析文件(InMemoryUploadedFile)

使用方法:

files = request.FILES.get('file')

book = xlrd.open_workbook(filename=None, file_contents=files.read())

整体响应如下:

class AvatarUpload(APIView):

authentication_classes = (TokenAuthentication,) # token认证

permission_classes = (IsAuthenticated,) # IsAuthenticated 仅通过认证的用户

def post(self, request):

'''

:param request:

:return: a list of sheet name

'''

files = request.FILES.get('file')

book = xlrd.open_workbook(filename=None, file_contents=files.read())

sheetnames = book.sheet_names()

filename = files.name

ExcelToXml(book, filename, sheetnames).to_xml()

return Response(sheetnames)

四、下载文件部分

上传文件之后,能够获得其的sheet页,在页面上勾选,点击下载即可。

页面展示部分

 

There is sheets of Excel!

 

 

    {{city}}

 

  点击下载xml

当勾选或取消勾选选项的时候,需要实时处理数据,保证向后端提供的参数正确:

methods:{

handleCheckedCitiesChange(value) {

this.sheetnames=value

let checkedCount = value.length;

this.isIndeterminate = checkedCount > 0 && checkedCount < this.cities.length;

},

async getXML(){

this.sheetnames.forEach(item=>{

this.$http.getXML(item).then(res=>{

let url = this.backUrl + "?sheetname=" + item

window.open(url)

}).catch(err=>{

this.$message.error("something not found")

})

})

}

FileResponse下载文件

在后端下载功能则比较简单了,只需要从指定的目录找到对应的文件,同时在response中设置正确Content-Type、Content-Disposition即可

顺便简单描述一下:

Content-Type:发送端(客户端|服务器)发送的实体的数据类型,常见的text/html,application/json

Content-Disposition:把请求所得的内容存为一个文件的时候提供一个默认的文件名。

实际使用如下:

def get(self, request):

'''

:param request:根据参数确认是下载xml文件 还是 demo模板

:return: a file

'''

BASE_DIR = Path(__file__).resolve().parent.parent

xml_ROOT = os.path.join(BASE_DIR, 'testlink')

sheetname = request.query_params.get("sheetname")

demo = "demo.xlsx"

if sheetname:

sheetname = sheetname + ".xml"

filepath = os.path.join(xml_ROOT, sheetname)

else:

filepath = os.path.join(xml_ROOT, demo)

filename = sheetname if sheetname else demo

if os.path.exists(filepath):

response = FileResponse(open(filepath, 'rb')) # 生成文件对象application/msword application/octet-stream

response['Content-Type'] = 'application/octet-stream'

response['Content-Disposition'] = 'attachment;filename ="%s"' % (

filename.encode('utf-8').decode('ISO-8859-1'))

return response

else:

return Response({"notFound": sheetname}, status=400)

好文阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。