| | |
| | | <template> |
| | | <div>DailyReport</div> |
| | | <!-- 主内容 --> |
| | | <FYSearchBar ref="searchRef" @search="search" :loading="loading"> |
| | | <template #options> |
| | | <!-- 区县 --> |
| | | <FYOptionLocation |
| | | :allOption="false" |
| | | :level="3" |
| | | :checkStrictly="false" |
| | | v-model:value="formSearch.locations" |
| | | style="width: 300px" |
| | | ></FYOptionLocation> |
| | | <!-- 场景类型 --> |
| | | <!-- <FYOptionScene |
| | | :allOption="true" |
| | | :type="2" |
| | | v-model:value="formSearch.scenetype" |
| | | ></FYOptionScene> --> |
| | | <!-- 时间 --> |
| | | <FYOptionTime |
| | | :initValue="false" |
| | | type="datetimerange" |
| | | v-model:value="formSearch.timeArray" |
| | | style="width: 250px" |
| | | ></FYOptionTime> |
| | | </template> |
| | | <template #buttons> |
| | | <el-button |
| | | icon="Download" |
| | | type="primary" |
| | | class="" |
| | | :loading="docLoading" |
| | | :disabled="!docParam" |
| | | @click="genWord()" |
| | | > |
| | | 生成报告 |
| | | </el-button> |
| | | <el-button |
| | | icon="Download" |
| | | type="success" |
| | | class="" |
| | | :disabled="!docParam" |
| | | @click="exportToExcel()" |
| | | > |
| | | 下载表格 |
| | | </el-button> |
| | | </template> |
| | | </FYSearchBar> |
| | | |
| | | <div class="m-task container"> |
| | | <!--头部信息--> |
| | | <div class="h-top col-md-12"> |
| | | <div class="m-top"> |
| | | <span class="title-input"> {{ reportName }} </span> |
| | | <!-- <input |
| | | type="text" |
| | | class="title-input" |
| | | value="秋冬污染季期间徐汇区扬尘污染辅助监管工作日报" |
| | | /> --> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="m-msg col-md-12"> |
| | | <span>{{ descMsg }}</span> |
| | | <div class="report-table row"> |
| | | <table id="table_subtask" class="" border="1"></table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import taskApi from '@/api/fysp/taskApi'; |
| | | import dayjs from 'dayjs'; |
| | | import * as XLSX from 'xlsx'; |
| | | import FileSaver from 'file-saver'; |
| | | import analysisApi from '@/api/fysp/analysisApi.js'; |
| | | import { exportDocx } from '@/utils/doc'; |
| | | |
| | | export default { |
| | | name: 'DailyReport', |
| | | computed: { |
| | | reportName() { |
| | | return `${this.formSearch.locations.dName}扬尘污染辅助监管工作日报`; |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | CompTable: { |
| | | title: [], |
| | | content: [], |
| | | tableStyleClass: 'comp-table', |
| | | rowStyleClss: 'oddrowcolor', |
| | | |
| | | init: function (title, content) { |
| | | this.title = title; |
| | | this.content = content; |
| | | }, |
| | | |
| | | /** |
| | | * 展示表格 |
| | | * @param {*} elementId table的id |
| | | */ |
| | | show: function (elementId) { |
| | | const table = document.getElementById(elementId); |
| | | if (table) { |
| | | table.innerHTML = ''; |
| | | table.classList.add(this.tableStyleClass); |
| | | this.createHead(elementId); |
| | | this.createContents(elementId); |
| | | } |
| | | }, |
| | | |
| | | /** |
| | | * 生成表头 |
| | | * @param {*} elementId |
| | | */ |
| | | createHead: function (elementId) { |
| | | const element = document.getElementById(elementId); |
| | | if (element) { |
| | | const row = document.createElement('tr'); |
| | | for (let index = 0; index < this.title.length; index++) { |
| | | const th = document.createElement('th'); |
| | | th.setAttribute('align', 'center'); |
| | | th.textContent = |
| | | this.title[index] === undefined ? '' : this.title[index]; |
| | | row.appendChild(th); |
| | | } |
| | | element.appendChild(row); |
| | | } |
| | | }, |
| | | |
| | | /** |
| | | * 生成表内容 |
| | | * @param {*} elementId |
| | | */ |
| | | createContents: function (elementId) { |
| | | const element = document.getElementById(elementId); |
| | | if (element) { |
| | | for (let index = 0; index < this.content.length; index++) { |
| | | if (index % 2 === 0) { |
| | | this.rowStyleClss = 'evenrowcolor'; |
| | | } else { |
| | | this.rowStyleClss = 'oddrowcolor'; |
| | | } |
| | | const rowArray = this.content[index]; |
| | | this.createRow(rowArray, elementId); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | /** |
| | | * 生成一行(包括合并单元格) |
| | | * @param {*} rowArray |
| | | */ |
| | | createRow: function (rowArray, elementId) { |
| | | const maxRows = this.getMaxRow(rowArray); |
| | | const leftArray = []; |
| | | |
| | | const tr = document.createElement('tr'); |
| | | for (let i = 0; i < rowArray.length; i++) { |
| | | let cell = rowArray[i]; |
| | | if (Array.isArray(cell)) { |
| | | const rowspan = maxRows / cell.length; |
| | | const td = document.createElement('td'); |
| | | td.setAttribute('rowspan', rowspan); |
| | | td.classList.add(this.rowStyleClss); |
| | | td.textContent = cell[0] === undefined ? '' : cell[0]; |
| | | tr.appendChild(td); |
| | | leftArray.push(cell.slice(1)); // Save the rest of the cell contents |
| | | } else { |
| | | const td = document.createElement('td'); |
| | | td.setAttribute('rowspan', maxRows); |
| | | td.classList.add(this.rowStyleClss); |
| | | td.textContent = cell === undefined ? '' : cell; |
| | | tr.appendChild(td); |
| | | } |
| | | } |
| | | document.getElementById(elementId).appendChild(tr); |
| | | |
| | | for (let i = 1; i < maxRows; i++) { |
| | | const tr = document.createElement('tr'); |
| | | leftArray.forEach((cell, y) => { |
| | | if (i < cell.length) { |
| | | const td = document.createElement('td'); |
| | | td.setAttribute('rowspan', maxRows / (cell.length - i)); |
| | | td.classList.add(this.rowStyleClss); |
| | | td.textContent = cell[i] === undefined ? '' : cell[i]; |
| | | tr.appendChild(td); |
| | | } |
| | | }); |
| | | document.getElementById(elementId).appendChild(tr); |
| | | } |
| | | }, |
| | | |
| | | /** |
| | | * 获取这一行中需要合并的行数 |
| | | * @param {*} rowArray |
| | | */ |
| | | getMaxRow: function (rowArray) { |
| | | let maxRows = 1; |
| | | rowArray.forEach((element) => { |
| | | if (Array.isArray(element) && element.length > maxRows) { |
| | | maxRows = element.length; |
| | | } |
| | | }); |
| | | return maxRows; |
| | | } |
| | | }, |
| | | |
| | | canClickDay: [], |
| | | excelConfig: { |
| | | title: '', |
| | | data: [], |
| | | fields: [] |
| | | }, |
| | | table: { |
| | | headers: [], |
| | | data: [] |
| | | }, |
| | | loading: false, |
| | | formSearch: { |
| | | locations: {}, |
| | | scenetype: {}, |
| | | time: [], |
| | | timeArray: [new Date(), new Date()], |
| | | districtCode: '310116' |
| | | }, |
| | | descMsg: '', |
| | | // 导出报告参数 |
| | | docParam: undefined, |
| | | docLoading: false |
| | | }; |
| | | }, |
| | | watch: { |
| | | formSearch: { |
| | | handler(nV, oV) { |
| | | // this.getCanClickDay(); |
| | | }, |
| | | deep: true |
| | | // immediate: true |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.formSearch.time = new Date(); |
| | | }, |
| | | methods: { |
| | | disabledDate(time) { |
| | | this.getCanClickDay(); |
| | | let disabled = |
| | | this.canClickDay.filter((item) => { |
| | | let date = dayjs(time); |
| | | let itemDay = new Date(item); |
| | | console.log( |
| | | 'curr preview time canClickDay', |
| | | itemDay.getFullYear(), |
| | | itemDay.getMonth(), |
| | | itemDay.getDate() |
| | | ); |
| | | console.log( |
| | | 'curr preview time date', |
| | | date.year(), |
| | | date.month(), |
| | | date.date() |
| | | ); |
| | | return ( |
| | | date.year() == itemDay.getFullYear() && |
| | | date.month() == itemDay.getMonth() && |
| | | date.date() == itemDay.getDate() |
| | | ); |
| | | }).length == 0; |
| | | return !disabled; |
| | | }, |
| | | getSelectedCityname() { |
| | | let city = ''; |
| | | |
| | | switch (this.formSearch.districtCode) { |
| | | case '310116': |
| | | city = '金山区'; |
| | | break; |
| | | case '310106': |
| | | city = '静安区'; |
| | | break; |
| | | case '310104': |
| | | city = '徐汇区'; |
| | | break; |
| | | case '310105': |
| | | city = '长宁区'; |
| | | break; |
| | | } |
| | | return city; |
| | | }, |
| | | getCanClickDay() { |
| | | taskApi.getTopTask().then((res) => { |
| | | this.canClickDay = []; |
| | | let city = this.getSelectedCityname(); |
| | | res |
| | | .filter((r) => { |
| | | return ( |
| | | r.districtname == city && |
| | | dayjs(this.formSearch.time).year() == dayjs(r.starttime).year() && |
| | | dayjs(this.formSearch.time).month() == dayjs(r.starttime).month() |
| | | ); |
| | | }) |
| | | .map((topTask) => { |
| | | taskApi.fetchDayTasks(topTask.tguid).then((res) => { |
| | | res.forEach((r) => { |
| | | let formSearchDate = dayjs(this.formSearch.time); |
| | | let date = new Date(); |
| | | dayjs(date) |
| | | .year(formSearchDate.year()) |
| | | .month(formSearchDate.month()) |
| | | .date(Number(r.date.slice(8, 10))); |
| | | this.canClickDay.push(date); |
| | | }); |
| | | console.log('this.canClickDay', this.canClickDay); |
| | | }); |
| | | }); |
| | | }); |
| | | }, |
| | | exportToExcel() { |
| | | // 创建工作簿 |
| | | const wb = XLSX.utils.book_new(); |
| | | |
| | | var wsData = []; |
| | | for (let index = 0; index < this.table.data.length; index++) { |
| | | const dataItem = this.table.data[index]; |
| | | var row = {}; |
| | | wsData.push(row); |
| | | for (let index = 0; index < dataItem.length; index++) { |
| | | row[this.table.headers[index]] = dataItem[index]; |
| | | } |
| | | } |
| | | console.log('data', wsData); |
| | | |
| | | // 创建工作表 |
| | | const ws = XLSX.utils.json_to_sheet(wsData); |
| | | |
| | | // 将工作表添加到工作簿 |
| | | XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); |
| | | |
| | | // 生成Excel文件 |
| | | const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' }); |
| | | |
| | | // 字符串转ArrayBuffer |
| | | function s2ab(s) { |
| | | const buf = new ArrayBuffer(s.length); |
| | | const view = new Uint8Array(buf); |
| | | for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff; |
| | | return buf; |
| | | } |
| | | |
| | | // 保存文件 |
| | | FileSaver.saveAs( |
| | | new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), |
| | | `${this.reportName}.xlsx` |
| | | ); |
| | | }, |
| | | search() { |
| | | let sTime = dayjs(this.formSearch.timeArray[0]) |
| | | .hour(0) |
| | | .minute(0) |
| | | .second(0) |
| | | .millisecond(0); |
| | | let eTime = dayjs(this.formSearch.timeArray[1]) |
| | | .hour(23) |
| | | .minute(59) |
| | | .second(59) |
| | | .millisecond(0); |
| | | // eTime = eTime.toISOString(); |
| | | // sTime = sTime.toISOString(); |
| | | |
| | | let config = { |
| | | startTime: sTime.toDate(), |
| | | endTime: eTime.toDate(), |
| | | districtCode: this.formSearch.locations.dCode |
| | | }; |
| | | this.loading = true; |
| | | analysisApi |
| | | .dailyreport(config) |
| | | .then((res) => { |
| | | this.table.headers = res.tableTitle[0]; |
| | | this.table.data = res.tableContent; |
| | | |
| | | this.CompTable.init(res.tableTitle[0], res.tableContent); |
| | | this.CompTable.show('table_subtask'); |
| | | |
| | | const countMap = new Map(); //各场景数量 |
| | | let proCount = 0; //总计问题数量 |
| | | let changeCount = 0; //总计整改数量 |
| | | const tableRows = []; |
| | | |
| | | res.tableContent.forEach((cList) => { |
| | | const sceneType = cList[2]; |
| | | if (!(sceneType in countMap)) { |
| | | countMap[sceneType] = 0; |
| | | } |
| | | countMap[sceneType] += 1; |
| | | proCount += Number(cList[10]); |
| | | changeCount += Number(cList[13]); |
| | | |
| | | tableRows.push({ |
| | | sIndex: cList[0], |
| | | sType: sceneType, |
| | | sName: cList[3], |
| | | sLocation: cList[4], |
| | | sProblemList: cList[8].split('\n'), |
| | | time: cList[6], |
| | | sTown: cList[5], |
| | | sChangeList: cList[11].split('\n') |
| | | }); |
| | | }); |
| | | |
| | | let countStr = ''; |
| | | for (const key in countMap) { |
| | | const e = countMap[key]; |
| | | if (countStr != '') { |
| | | countStr += '、'; |
| | | } |
| | | countStr += `${key}${e}个`; |
| | | } |
| | | this.descMsg = `共巡查${res.tableContent.length}个扬尘场景(${countStr}),共发现问题${proCount}项,督促整改了${changeCount}项。`; |
| | | |
| | | this.docParam = { |
| | | month: sTime.month() + 1, |
| | | day: sTime.date(), |
| | | index: 1, |
| | | hasMoreDays: !sTime.isSame(eTime, 'day'), |
| | | endMonth: eTime.month() + 1, |
| | | endDay: eTime.date(), |
| | | totalScene: res.tableContent.length, |
| | | sceneNumTxt: countStr, |
| | | proNum: proCount, |
| | | changeNum: changeCount, |
| | | unChangeNum: proCount - changeCount, |
| | | table1: tableRows |
| | | }; |
| | | }) |
| | | .finally(() => (this.loading = false)); |
| | | }, |
| | | // 生成word报告 |
| | | genWord() { |
| | | if (this.docParam) { |
| | | const param = this.docParam; |
| | | exportDocx( |
| | | '/秋冬季空气质量攻坚工作提示模板.docx', |
| | | param, |
| | | `秋冬季空气质量攻坚工作提示(${param.month}月${param.day}日).docx` |
| | | ); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | <style> |
| | | .options { |
| | | display: flex; |
| | | } |
| | | .c-time { |
| | | width: 12rem; |
| | | height: 3rem; |
| | | border-radius: 3px; |
| | | |
| | | font-size: 1rem; |
| | | } |
| | | .download-div { |
| | | } |
| | | .download-btn { |
| | | background-color: #5599cc; |
| | | width: 10rem; |
| | | height: 2.6rem; |
| | | color: #ffffff; |
| | | border-radius: 3px; |
| | | margin-right: 2rem; |
| | | } |
| | | .h-top .m-top { |
| | | /* width: 100%; */ |
| | | padding-right: 8rem; |
| | | /* padding: 0 7% 0 0%; */ |
| | | /* min-height: 8rem; */ |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | .title-input { |
| | | margin-top: -20px; |
| | | border-radius: 6px; |
| | | color: #000; |
| | | width: 80%; |
| | | font-size: 1.5rem; |
| | | line-height: 5rem; |
| | | text-align: center; |
| | | border: none; |
| | | } |
| | | .report-desc { |
| | | width: 80%; |
| | | margin-top: 5rem; |
| | | } |
| | | .desc-textarea { |
| | | width: 100%; |
| | | text-indent: 6rem; |
| | | font-size: 1rem; |
| | | margin-left: 5px; |
| | | } |
| | | .report-table { |
| | | width: 100%; |
| | | margin-top: 2rem; |
| | | table-layout: fixed; |
| | | } |
| | | .r-table { |
| | | width: 100%; |
| | | font-size: 2rem; |
| | | } |
| | | .r-table tr { |
| | | height: auto; |
| | | } |
| | | .r-table th { |
| | | height: 100%; |
| | | text-align: center; |
| | | } |
| | | .r-table td { |
| | | border-width: 1px; |
| | | min-width: 6rem; |
| | | } |
| | | .render-html { |
| | | cursor: pointer; |
| | | } |
| | | .h-top .m-top .task-div { |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | height: 2.6rem; |
| | | margin-bottom: 1rem; |
| | | } |
| | | |
| | | /******************************表格样式*******************************/ |
| | | table.comp-table { |
| | | font-family: verdana, arial, sans-serif; |
| | | font-size: 11px; |
| | | color: #333333; |
| | | border-width: 1px; |
| | | border-color: #666666; |
| | | border-collapse: collapse; |
| | | margin: 4px; |
| | | width: 87vw; |
| | | } |
| | | table.comp-table th { |
| | | border-width: 1px; |
| | | padding: 8px; |
| | | border-style: solid; |
| | | border-color: #666666; |
| | | background-color: #dedede; |
| | | text-align: center; /** 设置水平方向居中 */ |
| | | vertical-align: middle; /** 设置垂直方向居中 */ |
| | | } |
| | | table.comp-table td { |
| | | border-width: 1px; |
| | | padding: 8px; |
| | | border-style: solid; |
| | | border-color: #666666; |
| | | /* background-color: #ffffff; */ |
| | | } |
| | | .oddrowcolor { |
| | | background-color: #d9f2f5; |
| | | } |
| | | .evenrowcolor { |
| | | background-color: #eff6f8; |
| | | } |
| | | /**********************************************************************/ |
| | | </style> |