From 8c9f89329256299c1cc68ed461e4f8621275aa7d Mon Sep 17 00:00:00 2001 From: guoshipeng <3194674006@qq.com> Date: Thu, 27 Oct 2022 09:08:57 +0800 Subject: [PATCH] 郭世朋20221027提交空气质量报告页面 --- src/views/air/index.vue | 590 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 462 insertions(+), 128 deletions(-) diff --git a/src/views/air/index.vue b/src/views/air/index.vue index 9c2479b..983023b 100644 --- a/src/views/air/index.vue +++ b/src/views/air/index.vue @@ -13,7 +13,6 @@ </el-select> </div> <el-date-picker - v-if="value==='gx'" v-model="value3" style="margin-right: 5%" align="right" @@ -34,7 +33,8 @@ multiple :auto-upload="false"> <el-button slot="trigger" type="primary" size="small">������������</el-button> - <div slot="tip" class="el-upload__tip">������������������������������</div> + <div slot="tip" class="el-upload__tip" v-if="value==='gx'">������������������������������</div> + <div slot="tip" class="el-upload__tip" v-else></div> </el-upload> <el-upload v-if="value==='gx'" @@ -50,7 +50,8 @@ multiple :auto-upload="false"> <el-button slot="trigger" type="primary" size="small">������������</el-button> - <div slot="tip" class="el-upload__tip">���������������������������</div> + <div slot="tip" class="el-upload__tip" v-if="value==='gx'">���������������������������</div> + <div slot="tip" class="el-upload__tip" v-else></div> </el-upload> <el-upload v-if="value==='gx'" @@ -66,7 +67,8 @@ multiple :auto-upload="false"> <el-button slot="trigger" type="primary" size="small">������������</el-button> - <div slot="tip" class="el-upload__tip">���������������������������</div> + <div slot="tip" class="el-upload__tip" v-if="value==='gx'">���������������������������</div> + <div slot="tip" class="el-upload__tip" v-else></div> </el-upload> <el-upload v-if="value==='gx'" @@ -82,7 +84,8 @@ multiple :auto-upload="false"> <el-button slot="trigger" type="primary" size="small">������������</el-button> - <div slot="tip" class="el-upload__tip">������������������������������</div> + <div slot="tip" class="el-upload__tip" v-if="value==='gx'">������������������������������</div> + <div slot="tip" class="el-upload__tip" v-else></div> </el-upload> <el-upload v-if="value==='gx'" @@ -98,7 +101,8 @@ multiple :auto-upload="false"> <el-button slot="trigger" type="primary" size="small">������������</el-button> - <div slot="tip" class="el-upload__tip">������������������������</div> + <div slot="tip" class="el-upload__tip" v-if="value==='gx'">������������������������</div> + <div slot="tip" class="el-upload__tip" v-else></div> </el-upload> <el-upload v-if="value==='gx'" @@ -116,23 +120,25 @@ <el-button slot="trigger" type="primary" size="small">������������</el-button> <div slot="tip" class="el-upload__tip">������������������������������</div> </el-upload> + <div v-if="value==='hn'" style="position: relative"> + <el-upload + class="upload-demo" + ref="upload7" + action="" + accept="xlsx" + :on-change="handleChange7" + :on-remove="handleRemove7" + :file-list="fileList7" + :limit="1" + :on-exceed="handleExceed" + multiple + :auto-upload="false"> + <el-button slot="trigger" type="primary" size="small">������������</el-button> + <div slot="tip" class="el-upload__tip">������������������������������������������AQI������</div> + </el-upload> + <el-button type="success" @click="submitUpload" :disabled="idDisabled" size="small" style="position: absolute;right: 20%;bottom: -100%">������������</el-button> + </div> <!-- <el-upload - v-if="value==='gx'" - class="upload-demo" - ref="upload7" - action="" - accept="xlsx" - :on-change="handleChange7" - :on-remove="handleRemove7" - :file-list="fileList7" - :limit="1" - :on-exceed="handleExceed" - multiple - :auto-upload="false"> - <el-button slot="trigger" type="primary" size="small">������������</el-button> - <div slot="tip" class="el-upload__tip">������������</div> - </el-upload> - <el-upload v-if="value==='gx'" class="upload-demo" ref="upload8" @@ -148,12 +154,13 @@ <el-button slot="trigger" type="primary" size="small">������������</el-button> <div slot="tip" class="el-upload__tip">������������</div> </el-upload>--> - <div style="position: absolute; bottom: 2%; right: 20%" v-if="value==='gx'"> - <el-button type="success" @click="submitUpload" size="small">������������</el-button> +<!-- <div style="position: absolute; bottom: 2%; right: 20%">--> + <div style="position: absolute; right: 20%"> + <el-button v-if="value==='gx'" type="success" @click="submitUpload" size="small">������������</el-button> <!-- <el-button type="primary" @click="exportReport" size="small">������������</el-button>--> </div> </div> - <div class="exDown" v-if="value==='gx'"> + <div class="exDown"> <el-card class="box-card" style="position: relative"> <div class="block" style="margin-bottom: 30px;"> <el-date-picker @@ -174,60 +181,72 @@ :value="item.valueSelect"> </el-option> </el-select> - <el-button type="primary" @click="selectReport" size="small" class="selectBtn">������</el-button> + <el-button type="primary" @click="selectReport(1)" size="small" class="selectBtn">������</el-button> <!-- <el-button type="primary" @click="selectReport" size="small" class="selectBtn">������������</el-button>--> </div> - <el-table - :data="tableData" - style="width: 100%"> -<!-- <el-table-column - width="100" - align="center"> - <template slot="header"> - <el-checkbox - :indeterminate="isIndeterminate" - v-model="checkAll" - @change="handleCheckAllChange">������</el-checkbox> - </template> - <template slot-scope="scope"> - <el-checkbox - v-model="scope.row.checked" - @change="handleCheckOneChange(scope.row)"></el-checkbox> - </template> - </el-table-column>--> - <el-table-column - prop="name" - label="������������" - > - </el-table-column> - <el-table-column - prop="time" - label="������������" - > - </el-table-column> - <el-table-column - prop="date" - label="������������" - > - </el-table-column> - <el-table-column label="������"> - <template slot-scope="scope"> - <el-button type="text" size="medium" @click="expReport(scope.row)">������</el-button> - </template> - </el-table-column> - </el-table> -<!-- <el-pagination - class="paginationDemo" - background - layout="prev, pager, next" - :total="100"> - </el-pagination>--> + <div style="overflow-y: auto; height: 82%;margin-bottom: 2%;"> + <el-table + :data="tableData" + style="width: 100%"> + <!-- <el-table-column + width="100" + align="center"> + <template slot="header"> + <el-checkbox + :indeterminate="isIndeterminate" + v-model="checkAll" + @change="handleCheckAllChange">������</el-checkbox> + </template> + <template slot-scope="scope"> + <el-checkbox + v-model="scope.row.checked" + @change="handleCheckOneChange(scope.row)"></el-checkbox> + </template> + </el-table-column>--> + <el-table-column + prop="name" + label="������������" + > + </el-table-column> + <el-table-column + prop="time" + label="������������" + > + </el-table-column> + <el-table-column + prop="date" + label="������������" + > + </el-table-column> + <el-table-column label="������"> + <template slot-scope="scope"> + <el-button type="text" size="medium" v-if="valueSelect==='gx'" @click="expReport(scope.row)">������</el-button> + <!--������excel--> + <img src="../../assets/icon/hn_excel.png" alt="������������excel" v-if="valueSelect==='hn'" @click="hnExcel(scope.row)" style="margin-left:0; cursor:pointer;"> + <!--������word --> + <img src="../../assets/icon/hn_word.png" alt="���������������������������������" v-if="valueSelect==='hn'" @click="hnExpReport(scope.row)" style="cursor:pointer;"> + </template> + </el-table-column> + </el-table> + </div> + <div class="block" v-if="isDisplay"> + <el-pagination + background + @size-change="handleSizeChange" + @current-change="handleCurrentChange" + :current-page.sync="currentPage3" + :page-size="onePageCount" + layout="total, prev, pager, next, jumper" + :total="totalNumber"> + </el-pagination> + </div> </el-card> </div> </div> </template> <script> import { ExportBriefDataDocx } from '@/utils/exportBriefDataDocx' +import { ExportHunnanExcel } from '@/utils/ExportHunnanExcel' export default { data() { return { @@ -278,8 +297,8 @@ value3: new Date(), // ��������������������������� options: [ { - value: 'sy', - label: '������' + value: 'hn', + label: '���������' }, { value: 'gx', label: '���������' @@ -287,10 +306,11 @@ ], value: 'gx', // ������ valueSelect: 'gx', + valueSelect2: 'hn', optionsSelect: [ { - valueSelect: 'sy', - label: '������' + valueSelect: 'hn', + label: '���������' }, { valueSelect: 'gx', label: '���������' @@ -305,10 +325,36 @@ isIndeterminate: true, dateArr: [], // ��������������������� airData: {}, - reportInfo: {} + reportInfo: {}, + hunNanAirData: [], // ���������word������������ + hnexcelID: '', + idDisabled: false, + currentPage3: 1, // ��������������� + totalNumber: 0, // ��������� + onePageCount: 8, // ��������������� + isDisplay: false // ������������������ + } + }, + watch: { + value(newName, oldName) { + this.valueSelect = newName + this.tableData = [] + this.value2 = [new Date(), new Date()] + }, + valueSelect(newName, oldName) { + this.tableData = [] } }, methods: { + // ������ + handleSizeChange(val) { + console.log(`������ ${val} ���`) + }, + handleCurrentChange(val) { + console.log(`���������: ${val}`) + this.selectReport(val) + }, + // ������ handleChange(file, fileList) { if (file.raw.type !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') { this.$refs.upload.handleRemove(file) @@ -387,8 +433,8 @@ this.fileList6 = fileList this.file6 = fileList[0] }, - /* handleChange7(file, fileList) { - if (file.raw.type !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') { + handleChange7(file, fileList) { + if (file.raw.type !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' && file.raw.type !== 'application/vnd.ms-excel') { this.$refs.upload7.handleRemove(file) this.$message.warning(`���������������������������`) return @@ -400,25 +446,11 @@ this.fileList7 = fileList this.file7 = fileList[0] }, - handleChange8(file, fileList) { - if (file.raw.type !== 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') { - this.$refs.upload8.handleRemove(file) - this.$message.warning(`���������������������������`) - return - } - this.fileList8 = fileList - this.file8 = fileList[0] - }, - handleRemove8(file, fileList) { - this.fileList8 = fileList - this.file8 = fileList[0] - },*/ handleExceed(files, fileList) { this.$message.warning(`������������������ 1 ��������������������������� ${files.length} ������������������������ ${files.length + fileList.length} ���������`) }, submitUpload() { this.formData2 = [] - if (!this.value3) { this.$message({ message: '���������������', @@ -426,6 +458,14 @@ }) return } + if (this.value === 'gx') { // ��������������������� + this.gxSubmit() + } else { // ��������������������� + this.hnSubmit() + } + }, + // ��������������������������� + gxSubmit() { if (this.file1 && this.file2 && this.file3 && this.file4 && this.file5 && this.file6) { const formData = new FormData() formData.append(`code`, this.value) @@ -460,16 +500,62 @@ }) } }, - // ������������������ - MultipartFile(data) { - return this.$request({ - url: '/excel/excelImport', - method: 'post', - headers: { 'Content-Type': 'multipart/form-data' }, // ��������������������������������� - data - }) + // ��������������������������� + hnSubmit() { + if (this.file7) { + const formData = new FormData() + formData.append(`code`, this.value) + this.sensorTime = this.newTime(this.value3, 'submit') + var date = new Date() + date = this.newTime(date, 'submit') + formData.append(`time`, this.sensorTime) + formData.append(`date`, date) + formData.append(`files`, this.file7.raw) + // ������������������ + this.MultipartFile(formData).then(res => { + this.idDisabled = false + if (res.code === 0) { + this.$message({ + message: '���������������', + type: 'success' + }) + var reportInfo = res.data + this.value2 = [this.value3, this.value3] + reportInfo.name = '���������������' + reportInfo.time.split('-').join('') + this.tableData = [reportInfo] + } else { + this.$message.error('���������������') + } + }).catch(err => { + console.log(err) + }) + } else { + this.$message({ + message: '���������������������������', + type: 'warning' + }) + } }, - // ������������������ + // ������������������ + MultipartFile(data) { + this.idDisabled = true + if (this.value === 'gx') { + return this.$request({ + url: '/excel/excelImport', + method: 'post', + headers: { 'Content-Type': 'multipart/form-data' }, // ��������������������������������� + data + }) + } else { + return this.$request({ + url: '/excel/syExcelImport', + method: 'post', + headers: { 'Content-Type': 'multipart/form-data' }, // ��������������������������������� + data + }) + } + }, + // ������������������������������0��� newTime(timeArr, name) { if (name === 'submit') { var date = new Date(timeArr) @@ -499,6 +585,14 @@ }) return arr } + }, + // ������������������������������������0��� + newTimeNotZero(time) { + var date = new Date(time) + var y = date.getFullYear() + var m = date.getMonth() + 1 + var d = date.getDate() + return y + '-' + m + '-' + d }, // ������ handleCheckAllChange(val) { @@ -536,7 +630,7 @@ this.checkAll = totalCount === someStatusCount ? obj.checked : !obj.checked this.isIndeterminate = someStatusCount > 0 && someStatusCount < totalCount }, - // ������ + // ��������������������� expReport(obj) { this.$request({ url: '/excel/excelExport', @@ -555,10 +649,41 @@ getData.list3 = this.cityFirst(getData.list3) getData.list4 = this.cityFirst(getData.list4) this.airData = getData - this.airData.month = res.data.time.split('���')[0] - this.airData.day = res.data.time.split('���')[1].split('���')[0] + var monthZero = res.data.time.split('���')[0] + if (monthZero.substr(0, 1) === '0') { + this.airData.month = monthZero.substr(1) + } else { + this.airData.month = res.data.time.split('���')[0] + } + var dayZero = res.data.time.split('���')[1].split('���')[0] + if (dayZero.substr(0, 1) === '0') { + this.airData.day = dayZero.substr(1) + } else { + this.airData.day = dayZero + } var arr = obj.time.split('-') + if (arr[2].substr(0, 1) === '0') { + arr[2] = arr[2].substr(1) + } + if (arr[1].substr(0, 1) === '0') { + arr[1] = arr[1].substr(1) + } this.airData.currentTime = arr[0] + '���' + arr[1] + '���' + arr[2] + '���' + this.airData.currentYear = arr[0] + var time1DayZero = '' + var time1MonthZero = '' + if (res.data.time1.split('���')[1].split('���')[0].substr(0, 1) === '0') { + time1MonthZero = res.data.time1.split('���')[1].split('���')[0].substr(1) + } else { + time1MonthZero = res.data.time1.split('���')[1].split('���')[0] + } + + if (res.data.time1.split('���')[1].split('���')[0].substr(0, 1) === '0') { + time1DayZero = res.data.time1.split('���')[1].split('���')[0].substr(1) + } else { + time1DayZero = res.data.time1.split('���')[1].split('���')[0] + } + this.airData.time1 = res.data.time1.split('���')[0] + '���' + time1MonthZero + '���' + time1DayZero + '���' ExportBriefDataDocx('/airQuality.docx', this.airData, `${obj.name}.docx`) }).catch(err => { console.log(err) @@ -588,50 +713,257 @@ list.unshift(obj) return list }, - // ������������ - exportReport() { - // ExportBriefDataDocx('/airQuality.docx', this.airData, `������������������.docx`) + // ��������������������� + hnExpReport(obj) { this.$request({ - url: '/excel/excelExport', + url: '/excel/hnExcelExport', method: 'get', params: { - id: 23 + id: obj.id + // id: 68 } }).then(res => { - console.log(res) - this.airData = res.data - this.airData.month = res.data.time.split('���')[0] - this.airData.day = res.data.time.split('���')[1].split('���')[0] - ExportBriefDataDocx('/airQuality.docx', this.airData, `������������������.docx`) + // console.log(res) + this.hunNanAirData = res.data + // currentTime������ + var arr = res.data.time2.split('-') + var currentTime = arr[0] + '���' + arr[1] + '���' + arr[2] + '���' + var currentYear = arr[0] + this.hunNanAirData.currentTime = currentTime + this.hunNanAirData.currentYear = currentYear + // ������������������09���26���,yearDate������������ + var month = res.data.time.split('-')[0] + if (month.substr(0, 1) === '0') { + month = month.substr(1) + } + this.hunNanAirData.month = month + var day = res.data.time.split('-')[1] + if (day.substr(0, 1) === '0') { + day = day.substr(1) + } + this.hunNanAirData.day = day + ExportBriefDataDocx('/hunnan.docx', this.hunNanAirData, `���������${arr[1]}���${arr[2]}���������������������������.docx`) }).catch(err => { console.log(err) }) + }, + // ���������excel������ + hnExcel(obj) { + this.$request({ + url: '/excel/syExcelExport', + method: 'get', + params: { + id: obj.id + } + }).then(res => { + var code2 = res.data.code2.substr(0, 2) + '\n' + res.data.code2.substr(2) + var code4 = res.data.code4.substr(0, 2) + '\n' + res.data.code4.substr(2) + var table1Data = [['', '���������', '������', '������', '������'], ['', '', '', '', ''], ['���������', '300', res.data.code1, '', code2], ['', '', '', '', ''], ['PM2.5', '41', res.data.code3, '', code4], ['', '', '', '', '']] + var table3Data = [['', '���������', '���������', '������', '������'], ['', '���������', '���������', '������', '������'], ['���������', '80', '80', res.data.code5, ''], ['', '', '', '', ''], ['PM2.5', '23', '23', res.data.code6, ''], ['', '', '', '', '']] + var table2Data = [ + res.data.list.sy1, + res.data.list.sy2, + res.data.list.hnd1, + res.data.list.hnd2, + res.data.list.xxj1, + res.data.list.xxj2, + res.data.list.hnq1, + res.data.list.hnq2 + ] + var data = new Date() + var currentYearData = data.getFullYear() + var jd = res.data.season + ExportHunnanExcel(`������������������������${obj.time.split('-').join('')}`, table1Data, table3Data, table2Data, currentYearData, jd) + }).catch(err => { + console.log(err) + }) + }, + // ������������ + exportReport() { + // ������excel������ + // table1������������ + /* var table1Data = [['', '���������', '������', '������', '������'], ['', '', '', '', ''], ['���������', '300', '215', '', '������\n11���'], ['', '', '', '', ''], ['PM2.5', '41', '33', '33', '������\n20.7%'], ['', '', '', '', '']] + var table3Data = [['', '���������', '���������', '������', '������'], ['', '���������', '���������', '������', '������'], ['���������', '80', '80', '61', '61'], ['', '', '', '', ''], ['PM2.5', '23', '23', '18', '18'], ['', '', '', '', '']] + var table2Data = [ + ['������������', '21', '25', '29', '27', '24', '26', '28', '18', '5', '', '', '', '215', '������9���'], + ['PM2.5������������/������', '11', '30', '29', '27', '24', '26', '28', '18', '5', '', '', '', '215', '������17.9%'], + ['������������', '21', '25', '29', '27', '24', '26', '28', '18', '5', '', '', '', '215', '������9���'], + ['PM2.5������������/������', '22', '25', '23', '37', '34', '36', '38', '18', '5', '', '', '', '215', '������17.9%'], + ['������������', '21', '25', '29', '27', '24', '26', '28', '18', '5', '', '', '', '215', '������9���'], + ['PM2.5������������/������', '28', '69', '39', '27', '24', '26', '28', '18', '5', '', '', '', '215', '������17.9%'], + ['������������', '21', '25', '29', '27', '24', '26', '28', '18', '5', '', '', '', '215', '������9���'], + ['PM2.5������������/������', '32', '20', '29', '27', '24', '26', '28', '18', '5', '', '', '', '215', '������17.9%'] + ] + var data = new Date() + var currentYearData = data.getFullYear() + var jd = '���' + ExportHunnanExcel('������������������������', table1Data, table3Data, table2Data, currentYearData, jd)*/ - // if (this.isInfo) { - // // ExportBriefDataDocx('/airQ.docx', this.airData, `������������������.docx`) - // } else { - // this.$message({ - // message: '������������������', - // type: 'warning' - // }) - // } + // ������word������ + // ������ + /* var arr = this.newTimeNotZero(this.value3).split('-') + var currentTime = arr[0] + ' ���' + arr[1] + ' ���' + arr[2] + ' ���' + var currentYear = arr[0] + this.hunNanAirData.currentTime = currentTime + this.hunNanAirData.currentYear = currentYear + // ��������������������������� + var yearDate = '09���26���' + var list1 = { + sy: { + AQI: 127, + PM25: 38, + PM10: 75, + CO: 1.1, + O38H: 21, + SO2: 189, + NO2: 20, + ZH: 32, + PaiM: '-' + }, + hnd: { + AQI: 71, + PM25: 38, + PM10: 75, + CO: 1.1, + O38H: 21, + SO2: 189, + NO2: 20, + ZH: 32, + PaiM: '-' + }, + xxj: { + AQI: 72, + PM25: 38, + PM10: 75, + CO: 1.1, + O38H: 21, + SO2: 189, + NO2: 20, + ZH: 32, + PaiM: '-' + } + } + var hnd = { + hnd1: { + nd: '2022', + yl: '226', + excellent: '92', + good: '134', + slightPol: '36', + moderatePol: '6', + heavyPol: '1', + seriousPol: '0' + }, + hnd2: { + nd: '2021', + yl: '222', + excellent: '92', + good: '134', + slightPol: '36', + moderatePol: '6', + heavyPol: '1', + seriousPol: '0' + }, + hnd3: { + nd: '������������', + yl: '4', + excellent: '92', + good: '134', + slightPol: '36', + moderatePol: '6', + heavyPol: '1', + seriousPol: '0' + } + } + var xxj = { + xxj1: { + nd: '2022', + yl: '226', + excellent: '92', + good: '134', + slightPol: '36', + moderatePol: '6', + heavyPol: '1', + seriousPol: '0' + }, + xxj2: { + nd: '2021', + yl: '222', + excellent: '92', + good: '134', + slightPol: '36', + moderatePol: '6', + heavyPol: '1', + seriousPol: '0' + }, + xxj3: { + nd: '������������', + yl: '4', + excellent: '92', + good: '134', + slightPol: '36', + moderatePol: '6', + heavyPol: '1', + seriousPol: '0' + } + } + var datafor = { + so2: '23%', + no2: '25%', + co: '-23' + } + // var airQua = '���������' + var airQua = '���������' + this.hunNanAirData.list1 = list1 + this.hunNanAirData.hnd = hnd + this.hunNanAirData.xxj = xxj + this.hunNanAirData.airQua = airQua + // ������������������9���26��������������� + var month = yearDate.split('���')[0] + if (month.substr(0, 1) === '0') { + month = month.substr(1) + } + this.hunNanAirData.month = month + var day = yearDate.split('���')[1].split('���')[0] + if (day.substr(0, 1) === '0') { + day = day.substr(1) + } + this.hunNanAirData.day = day + this.hunNanAirData.datafor = datafor + ExportBriefDataDocx('/HunnanReport.docx', this.hunNanAirData, `���������${month}���${day}���������������������������.docx`)*/ }, // ������������ - selectReport() { + selectReport(val) { + var page = val + if (this.isDisplay === false) { + page = 0 + } this.sensorTime2 = this.newTime(this.value2, 'select') this.$request({ - url: '/excel/selectExcel', + // url: '/excel/selectExcel', + url: 'excel/selectExcel', method: 'get', params: { startTime: this.sensorTime2[0], endTime: this.sensorTime2[1], - code: this.valueSelect + code: this.valueSelect, + pageCount: page } }).then(res => { if (res.code === 0) { - var info = res.data + var info = [] + if (this.isDisplay) { + this.totalNumber = res.data.total + info = res.data.item + } else { + info = res.data + } info.map(v => { - v.name = '���������������������������������' + v.time.split('-').join('') + if (this.valueSelect === 'gx') { + v.name = '���������������������������������' + v.time.split('-').join('') + } else { + v.name = '���������������' + v.time.split('-').join('') + } }) info.sort((a, b) => { return b.time.split('-').join('') - a.time.split('-').join('') }) this.tableData = info @@ -653,8 +985,10 @@ } .exTop{ width: 30%; - height: 95%; + /*height: 95%;*/ position: relative; + overflow: auto; + margin-bottom: 2%; } .cascader-demo{ float: left; -- Gitblit v1.8.0