瀏覽代碼

Merge branch 'develop' of http://52.130.252.100:10000/TEAMMODEL/TEAMModelOS into develop

jeff 2 年之前
父節點
當前提交
36fc2dea8d

+ 262 - 0
TEAMModelBI/ClientApp/src/until/excel/Export2MultipleSheetExcel.js

@@ -0,0 +1,262 @@
+// Export2MultipleSheetExcel
+// 导出多sheet表格专用
+/* eslint-disable */
+require("script-loader!file-saver")
+import XLSX from "xlsx"
+require('script-loader!xlsx/dist/xlsx.core.min');
+
+function generateArray(table) {
+    var out = []
+    var rows = table.querySelectorAll("tr")
+    var ranges = []
+    for (var R = 0; R < rows.length; ++R) {
+        var outRow = []
+        var row = rows[R]
+        var columns = row.querySelectorAll("td")
+        for (var C = 0; C < columns.length; ++C) {
+            var cell = columns[C]
+            var colspan = cell.getAttribute("colspan")
+            var rowspan = cell.getAttribute("rowspan")
+            var cellValue = cell.innerText
+            if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue
+
+            //Skip ranges
+            ranges.forEach(function(range) {
+                if (
+                    R >= range.s.r &&
+                    R <= range.e.r &&
+                    outRow.length >= range.s.c &&
+                    outRow.length <= range.e.c
+                ) {
+                    for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null)
+                }
+            })
+
+            //Handle Row Span
+            if (rowspan || colspan) {
+                rowspan = rowspan || 1
+                colspan = colspan || 1
+                ranges.push({
+                    s: {
+                        r: R,
+                        c: outRow.length
+                    },
+                    e: {
+                        r: R + rowspan - 1,
+                        c: outRow.length + colspan - 1
+                    }
+                })
+            }
+
+            //Handle Value
+            outRow.push(cellValue !== "" ? cellValue : null)
+
+            //Handle Colspan
+            if (colspan)
+                for (var k = 0; k < colspan - 1; ++k) outRow.push(null)
+        }
+        out.push(outRow)
+    }
+    return [out, ranges]
+}
+
+function datenum(v, date1904) {
+    if (date1904) v += 1462
+    var epoch = Date.parse(v)
+    return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
+}
+
+function sheet_from_array_of_arrays(data, opts) {
+    var ws = {}
+    var range = {
+        s: {
+            c: 10000000,
+            r: 10000000
+        },
+        e: {
+            c: 0,
+            r: 0
+        }
+    }
+    for (var R = 0; R != data.length; ++R) {
+        for (var C = 0; C != data[R].length; ++C) {
+            if (range.s.r > R) range.s.r = R
+            if (range.s.c > C) range.s.c = C
+            if (range.e.r < R) range.e.r = R
+            if (range.e.c < C) range.e.c = C
+            var cell = {
+                v: data[R][C]
+            }
+            if (cell.v == null) continue
+            var cell_ref = XLSX.utils.encode_cell({
+                c: C,
+                r: R
+            })
+
+            if (typeof cell.v === "number") cell.t = "n"
+            else if (typeof cell.v === "boolean") cell.t = "b"
+            else if (cell.v instanceof Date) {
+                cell.t = "n"
+                cell.z = XLSX.SSF._table[14]
+                cell.v = datenum(cell.v)
+            } else cell.t = "s"
+
+            ws[cell_ref] = cell
+        }
+    }
+    if (range.s.c < 10000000) ws["!ref"] = XLSX.utils.encode_range(range)
+    return ws
+}
+
+function Workbook() {
+    if (!(this instanceof Workbook)) return new Workbook()
+    this.SheetNames = []
+    this.Sheets = {}
+}
+
+function s2ab(s) {
+    var buf = new ArrayBuffer(s.length)
+    var view = new Uint8Array(buf)
+    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
+    return buf
+}
+
+export function export_table_to_excel(id) {
+    var theTable = document.getElementById(id)
+    var oo = generateArray(theTable)
+    var ranges = oo[1]
+
+    /* original data */
+    var data = oo[0]
+    var ws_name = "SheetJS"
+
+    var wb = new Workbook(),
+        ws = sheet_from_array_of_arrays(data)
+
+    /* add ranges to worksheet */
+    // ws['!cols'] = ['apple', 'banan'];
+    ws["!merges"] = ranges
+
+    /* add worksheet to workbook */
+    wb.SheetNames.push(ws_name)
+    wb.Sheets[ws_name] = ws
+
+    var wbout = XLSX.write(wb, {
+        bookType: "xlsx",
+        bookSST: false,
+        type: "binary"
+    })
+
+    saveAs(
+        new Blob([s2ab(wbout)], {
+            type: "application/octet-stream"
+        }),
+        "test.xlsx"
+    )
+}
+
+
+
+//主要修改此函数内的方法
+
+export function export_json_to_excel({
+    multiHeader = [],
+    header,
+    data,
+    sheetname,
+    filename,
+    merges = [],
+    autoWidth = true,
+    bookType = "xlsx"
+} = {}) {
+    /* original data */
+    filename = filename || "excel-list"
+    data = [...data]
+
+    for (var i = 0; i < header.length; i++) {
+        data[i].unshift(header[i])
+    }
+
+    // data.unshift(header)
+
+    for (let i = multiHeader.length - 1; i > -1; i--) {
+        data.unshift(multiHeader[i])
+    }
+
+    var ws_name = sheetname
+    var wb = new Workbook(),
+        ws = []
+    for (var j = 0; j < header.length; j++) {
+        ws.push(sheet_from_array_of_arrays(data[j]))
+    }
+
+    if (merges.length > 0) {
+        if (!ws["!merges"]) ws["!merges"] = []
+        merges.forEach(item => {
+            ws["!merges"].push(XLSX.utils.decode_range(item))
+        })
+    }
+    // console.log("width", autoWidth)
+    if (autoWidth) {
+        /*设置worksheet每列的最大宽度*/
+        var colWidth = []
+        for (var k = 0; k < header.length; k++) {
+            colWidth.push(
+                data[k].map(row =>
+                    row.map(val => {
+                        /*先判断是否为null/undefined*/
+                        if (val == null) {
+                            return {
+                                wch: 10
+                            }
+                        } else if (val.toString().charCodeAt(0) > 255) {
+                            /*再判断是否为中文*/
+                            return {
+                                wch: val.toString().length * 2
+                            }
+                        } else {
+                            return {
+                                wch: val.toString().length
+                            }
+                        }
+                    })
+                )
+            )
+        }
+
+        /*以第一行为初始值*/
+        let result = []
+        for (var k = 0; k < colWidth.length; k++) {
+            result[k] = colWidth[k][0]
+            for (let i = 1; i < colWidth[k].length; i++) {
+                for (let j = 0; j < colWidth[k][i].length; j++) {
+                    if (result[k][j]["wch"] < colWidth[k][i][j]["wch"]) {
+                        result[k][j]["wch"] = colWidth[k][i][j]["wch"]
+                    }
+                }
+            }
+        }
+        // 分别给sheet表设置宽度
+        for (var l = 0; l < result.length; l++) {
+            ws[l]["!cols"] = result[l]
+        }
+    }
+
+    /* add worksheet to workbook */
+    for (var k = 0; k < header.length; k++) {
+        wb.SheetNames.push(ws_name[k])
+        wb.Sheets[ws_name[k]] = ws[k]
+    }
+
+    var wbout = XLSX.write(wb, {
+        bookType: bookType,
+        bookSST: false,
+        type: "binary"
+    })
+    saveAs(
+        new Blob([s2ab(wbout)], {
+            type: "application/octet-stream"
+        }),
+        `${filename}.${bookType}`
+    )
+}

+ 36 - 0
TEAMModelBI/ClientApp/src/until/multipleSheetExport.js

@@ -0,0 +1,36 @@
+/**
+ * multipleSheetExport
+ * tableJson 导出数据
+ * filenames 导出表的名字
+ * autowidth 表格宽度自动
+ * bookTypes Xlsx & csv & txt
+ * 
+ * @param {(Object)} tableJson
+ * @param {string} filenames
+ * @param {boolean} autowidth
+ * @param {string} bookTypes
+ */
+export function multipleSheetExport(tableJson, filenames, autowidth, bookTypes) {
+    import ('@/until/excel/Export2MultipleSheetExcel').then(excel => {
+        var tHeader = []
+        var dataArr = []
+        var sheetnames = []
+        for (var i in tableJson) {
+            tHeader.push(tableJson[i].tHeader)
+            dataArr.push(formatJson(tableJson[i].filterVal, tableJson[i].tableDatas))
+            sheetnames.push(tableJson[i].sheetName)
+        }
+        excel.export_json_to_excel({
+            header: tHeader,
+            data: dataArr,
+            sheetname: sheetnames,
+            filename: filenames,
+            autoWidth: autowidth,
+            bookType: bookTypes
+        })
+    })
+}
+
+function formatJson(filterVal, jsonData) {
+    return jsonData.map(v => filterVal.map(j => v[j]))
+}

+ 63 - 14
TEAMModelBI/ClientApp/src/view/product/index.vue

@@ -269,6 +269,7 @@
 import option_cn from '@/static/regions/region_cn.json'
 import { ref, getCurrentInstance, watch, h, nextTick } from 'vue'
 import { ElMessage, TableV2SortOrder, ElLoading, ElCheckbox } from 'element-plus'
+import { multipleSheetExport } from '@/until/multipleSheetExport'
 import { Search, CirclePlus } from '@element-plus/icons-vue'
 import Details from './details.vue'
 let { proxy } = getCurrentInstance()
@@ -894,8 +895,13 @@ function selectChange (value) {
 }
 //确认数据导出
 function exportExcel () {
-  let headerArr = []
-  let keyArr = []
+  //普通
+  let headerArr = []; let keyArr = []
+  //装置数据
+  let deviceArr = ['学校名称', '学校简码', '硬体装置', '无机器授权', '安装机器授权']; let deviceKey = ['name', 'schoolId', 'disposeDevice', 'deviceNoAuth', 'deviceAuth'];
+  //ID数据
+  let IDArr = ['学校名称', '学校简码', '教师ID']; let IDKey = ['name', 'schoolId', 'disposeId']
+  //处理普通
   let superaddition = [
     { label: '任务数', key: 'mission' },
     { label: '作品数', key: 'missionFin' },
@@ -928,19 +934,62 @@ function exportExcel () {
     })
   })
   superaddition.forEach((item) => { headerArr.push(item.label), keyArr.push(item.key) })
-  require.ensure([], () => {
-    console.log(headerArr, keyArr)
-    const { export_json_to_excel } = require('../../until/excel/Export2Excel')
-    const tHeader = headerArr // excel文档第一行显示的标题
-    const filterVal = keyArr // id,version等都是上面标题所对应的数据
-    const list = filterdata.value
-    const data = formatJson(filterVal, list)
-    console.log(data, '处理后的数据')
-    export_json_to_excel(tHeader, data, '产品使用分析表', true) //标题,数据,文件名
+
+  let totalHeader = {
+    common: headerArr.length > 0 ? headerArr : [],
+    deviceH: deviceArr,
+    IDheader: IDArr
+  }
+  let totalKey = {
+    common: keyArr.length > 0 ? keyArr : [],
+    deviceK: deviceKey,
+    IDkey: IDKey
+  }
+  multipleExports(totalHeader, totalKey)
+  // require.ensure([], () => {
+  //   console.log(headerArr, keyArr)
+  //   const { export_json_to_excel } = require('../../until/excel/Export2Excel')
+  //   const tHeader = headerArr // excel文档第一行显示的标题
+  //   const filterVal = keyArr // id,version等都是上面标题所对应的数据
+  //   const list = filterdata.value
+  //   const data = formatJson(filterVal, list)
+  //   console.log(data, '处理后的数据')
+  //   export_json_to_excel(tHeader, data, '产品使用分析表', true) //标题,数据,文件名
+  // })
+}
+function multipleExports (header, key) {
+  let disposeArr = filterdata.value
+  disposeArr.forEach((item) => {
+    let disarray = (item.deviceList).toString()
+    let idarray = (item.tmidList).toString()
+    item.disposeDevice = disarray.replace(/,/g, ',' + "\n")
+    item.disposeId = idarray.replace(/,/g, ',' + "\n")
   })
-}
-function formatJson (filterVal, jsonData) {
-  return jsonData.map((v) => filterVal.map((j) => v[j]))
+  const excelDatas = [
+    {
+      // sheet表一头部
+      tHeader: header.common,
+      // 表一的数据字段
+      filterVal: key.common,
+      // 表一的整体json数据
+      tableDatas: disposeArr,
+      // 表一的sheet名字
+      sheetName: '产品使用分析全览'
+    },
+    {
+      tHeader: header.deviceH,
+      filterVal: key.deviceK,
+      tableDatas: disposeArr,
+      sheetName: '装置数据'
+    },
+    {
+      tHeader: header.IDheader,
+      filterVal: key.IDkey,
+      tableDatas: disposeArr,
+      sheetName: 'ID列表'
+    }
+  ]
+  multipleSheetExport(excelDatas, '产品使用分析表', true, 'xlsx')
 }
 // init()
 dataInit()

+ 6 - 0
TEAMModelOS/ClientApp/public/lang/en-US.js

@@ -7289,6 +7289,12 @@ const LANG_EN_US = {
             basicsV: 'Basic Version',
             standardV: 'Standard Version',
             marjorV: 'Advanced Version',
+            activityP: 'Activity percentage',
+            versionsP: 'Versions percentage',
+            schoolP: 'School data percentage',
+            sizeP: 'Size percentage',
+            scheduleP: 'Progress stage',
+            subjectP: 'Subject percentage'
         },
         class: {
             total: 'Year Total Data',

+ 6 - 0
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -7277,6 +7277,12 @@ const LANG_ZH_CN = {
             basicsV: '基础版',
             standardV: '标准版',
             marjorV: '专业版',
+            activityP: '活动占比',
+            versionsP: '版本占比',
+            schoolP: '学校数据占比',
+            sizeP: '空间占比',
+            scheduleP:'进度阶段',
+            subjectP:'科目占比'
         },
         class: {
             total: '今年总数据',

+ 6 - 0
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -7276,6 +7276,12 @@ const LANG_ZH_TW = {
             basicsV: '基礎版',
             standardV: '標準版',
             marjorV: '專業版',
+            activityP: '活動百分比',
+            versionsP: '版本百分比',
+            schoolP: '學校數據百分比',
+            sizeP: '空間百分比',
+            scheduleP: '進度階段',
+            subjectP: '科目百分比'
         },
         class: {
             total: '今年總數據',

+ 1 - 2
TEAMModelOS/ClientApp/src/components/dashboard/art/BaseGradeLineBar.vue

@@ -242,10 +242,9 @@ export default {
         if (n) {
           this.$nextTick(() => {
             let analysisJson = n
-            let curPeriod = JSON.parse(localStorage.getItem('curPeriod'))
             let gradeDatas = analysisJson.gscore.map(grade => {
               return {
-                gradeName: curPeriod.grades[+grade.id],
+                gradeName: grade.name,
                 average: grade.score,
                 hScore: grade.max,
                 goodRate: parseInt(grade.excellent * 100),

+ 1 - 3
TEAMModelOS/ClientApp/src/components/dashboard/art/RightTop.vue

@@ -307,8 +307,6 @@ export default {
         if (n) {
           this.$nextTick(() => {
             let analysisJson = n
-            let curPeriod = JSON.parse(localStorage.getItem('curPeriod'))
-
             // 全校
             let cascaderConfig = [
               {
@@ -321,7 +319,7 @@ export default {
             analysisJson.gscore.forEach(grade => {
               cascaderConfig[0].children.push({
                 value: grade.id,
-                label: curPeriod.grades[+grade.id],
+                label: grade.name,
                 children: []
               })
             })

+ 1 - 0
TEAMModelOS/ClientApp/src/utils/excel.js

@@ -2,6 +2,7 @@
 import { Array } from 'core-js';
 import XLSX from 'xlsx';
 
+
 function auto_width(ws, data) {
     /*set worksheet max width per col*/
     const colWidth = data.map(row => row.map(val => {

+ 4 - 14
TEAMModelOS/ClientApp/src/view/areaArtExam/AcQuos.vue

@@ -254,20 +254,7 @@ export default {
                                     ? _this.$t('ae.ae1')
                                     : ""
                         ),
-                        node.data.type === 2 ? h("Tag",
-                            {
-                                class: "type-setting",
-                                props: {
-                                    color: "primary",
-                                },
-                                nativeOn: {
-                                    click: (evt) => {
-                                        _this.uploadStatus = true
-                                        _this.uploadNode = node.data
-                                    }
-                                }
-                            },
-                            '批量导入') : undefined,
+                        
                         _this.activeNode?.id == node.data.id &&
                             node.data.type === 1
                             ? h(
@@ -275,6 +262,7 @@ export default {
                                 {
                                     class: ["data-wrap"],
                                     props: {
+                                        schoolCode: _this.artInfo.school,
                                         taskInfo: _this.getNodeSetting(node.data.id),
                                         curClass: _this.curClass,
                                         subjectId: _this.subjectId
@@ -290,6 +278,7 @@ export default {
                                     class: ["data-wrap"],
                                     ref: node.data.id + '_data',
                                     props: {
+                                        artExamId: _this.artInfo.id,
                                         taskInfo: _this.getNodeSetting(node.data.id),
                                         curClass: _this.curClass,
                                         subjectId: _this.subjectId,
@@ -304,6 +293,7 @@ export default {
     },
     mounted() {
         console.log('*****', this.treeData)
+        console.log('*****', this.artInfo)
         if (this.treeData && this.treeData.length) {
             this.activeNode = this.getDefaultOpenNode(this.treeData)
 			console.log(this.activeNode)

+ 5 - 1
TEAMModelOS/ClientApp/src/view/areaArtExam/ExamData.vue

@@ -49,6 +49,10 @@ export default {
         subjectId: {
             type: String,
             default: ''
+        },
+        schoolCode: {
+            type: String,
+            default: ''
         }
     },
     data() {
@@ -126,7 +130,7 @@ export default {
             this.tableLoading = true
             let requestData = {
                 id: examId,
-                code: this.$store.state.userInfo.schoolCode,
+                code: this.schoolCode,
                 subjectId: this.subjectId,
                 classId: this.curClass.id,
             };

+ 27 - 12
TEAMModelOS/ClientApp/src/view/areaArtExam/WorkData.vue

@@ -21,9 +21,15 @@
             <img v-else-if="item.type == 'res'" src="../../assets/icon/htex.png" />
             <img v-else src="../../assets/source/unknow.png" />
           </div>
-          <p class="work-file-name" @click="handlePreviewHw(item)">
+          <!-- <p class="work-file-name" @click="handlePreviewHw(item)">
             {{item.name}}
-          </p>
+          </p> -->
+          <p v-if="item.type != 'zy'" class="work-file-name" @click="handlePreviewHw(item)">
+              {{ item.name }}
+            </p>
+            <a v-else :href="item.url" target="_blank">
+              {{ item.name }}
+            </a>
         </div>
       </template>
       <template slot-scope="{ row }" slot="createTime">
@@ -47,7 +53,7 @@
           <source :src="hwPreviewFile.url+schoolSas.sas">
           {{$t('teachContent.notAudio')}}
         </audio>
-        <img v-else-if="hwPreviewFile.type == 'image'" :src="hwPreviewFile.url+schoolSas.sas" style="border-radius: 5px;max-height: 800px;max-width:870px;" />
+        <img v-else-if="hwPreviewFile.type == 'image'" :src="hwPreviewFile.url" style="border-radius: 5px;max-height: 800px;max-width:870px;" />
       </div>
     </Modal>
   </div>
@@ -71,7 +77,11 @@ export default {
     subjectId: {
       type: String,
       default: ''
-    }
+    },
+    artExamId: {
+      type: String,
+      default: ''
+    },
   },
   data() {
     let _this = this
@@ -120,8 +130,10 @@ export default {
      * 预览/下载作业文件
      * @param {string} type video 删除研修视频 file 删除资料
      */
-    handlePreviewHw(info) {
+    async handlePreviewHw(info) {
       if (info.type === 'image' || info.type === 'video' || info.type === 'audio') {
+        let fullUrl = await this.$tools.getFileSas(info.url)
+        info.url = fullUrl.url
         this.hwPreviewFile = info
         this.hwViewStatus = true
       } else if (info.type === 'doc') {
@@ -171,8 +183,8 @@ export default {
       console.log(`output->this.taskInfo`, this.taskInfo)
       if (!workId || !this.subjectId || !this.curClass.id) return
       let req = {
-        id: workId,
-        // taskId:workId,
+        id: this.artExamId,
+        taskId: workId,
         subject: this.subjectId,
         classId: this.curClass.id
       }
@@ -194,17 +206,19 @@ export default {
         students.forEach(s => {
           let work = data.find(w => w.stuId === s.id)
           let hasWork = work && work.attachments?.length
+          let hasZY = work && work.url
           let info = {
             id: s.id,
             name: s.name,
           }
-          info.status = hasWork ? 1 : 0
-          info.createTime = hasWork ? work.attachments[0].createTime : 0
-          info.count = hasWork ? work.attachments.length : 0
-          info.files = hasWork ? work.attachments : []
+          info.status = hasWork || hasZY ? 1 : 0
+          info.createTime = hasWork ? work.attachments[0].createTime : hasZY ? work.createTime : 0
+          info.count = hasWork ? work.attachments.length : hasZY ? 1 : 0
+          info.files = hasWork ? work.attachments : hasZY ? [{ type: 'zy', name: '评唱结果', url: work.url }] : []
           this.workData.push(info)
         })
       }
+      console.log(this.workData);
       this.pageChange(1)
     },
     // 分页页面变化
@@ -213,7 +227,8 @@ export default {
       let end = this.pageSize * page
       this.currentPage = page
       this.tableData = this.workData.slice(start, end)
-    },
+      console.log(this.tableData);
+    }
   },
   watch: {
     subjectId: {

+ 8 - 8
TEAMModelOS/ClientApp/src/view/areaMgmt/AreaIndex.vue

@@ -320,7 +320,7 @@ export default {
           },
           series: [
             {
-              name: '活动占比',
+              name: this.$t('areaStatistics.basics.activityP'),
               type: 'pie',
               radius: '70%',
               center: ['45%', '50%'],
@@ -357,7 +357,7 @@ export default {
           },
           series: [
             {
-              name: '版本占比',
+              name: this.$t('areaStatistics.basics.versionsP'),
               type: 'pie',
               radius: '70%',
               center: ['45%', '50%'],
@@ -403,7 +403,7 @@ export default {
           },
           series: [
             {
-              name: '学校数据占比',
+              name: this.$t('areaStatistics.basics.schoolP'),
               type: 'pie',
               radius: '65%',
               center: ['40%', '40%'],
@@ -450,7 +450,7 @@ export default {
           },
           series: [
             {
-              name: '学校数据占比',
+              name: this.$t('areaStatistics.basics.schoolP'),
               type: 'pie',
               radius: '75%',
               center: ['30%', '50%'],
@@ -497,7 +497,7 @@ export default {
           },
           series: [
             {
-              name: '学校数据占比',
+              name: this.$t('areaStatistics.basics.schoolP'),
               type: 'pie',
               radius: '75%',
               center: ['30%', '50%'],
@@ -598,7 +598,7 @@ export default {
             end: 35
           }],
           series: [{
-            name: this.$t('areaStatistics.class.vitality'),
+            name: this.$t('areaStatistics.basics.vitality'),
             type: "line",
             symbolSize: 10,
             symbol: 'circle',
@@ -679,7 +679,7 @@ export default {
               ],
             },
             {
-              name: '进度阶段',
+              name: this.$t('areaStatistics.basics.scheduleP'),
               type: 'pie',
               radius: ['65%', '90%'],
               data: [
@@ -715,7 +715,7 @@ export default {
           },
           series: [
             {
-              name: '空间占比',
+              name: this.$t('areaStatistics.basics.sizeP'),
               type: 'pie',
               radius: '90%',
               center: ['50%', '50%'],

+ 142 - 2
TEAMModelOS/ClientApp/src/view/art/AreaArt.vue

@@ -3,6 +3,10 @@
     <vuescroll ref="art-dasboard">
       <Loading v-show="isLoading"></Loading>
       <back-to-top @on-to-top="backToTop"></back-to-top>
+      <div class="export-box"  @click="exportArtTable">
+        <span class="icon iconfont icon-download" style="margin-right:5px;margin-top: 5px;" :title="`下载艺术评测数据表`"></span>
+        <span>下载数据总表</span>
+      </div>
       <div class="tab-box" style="padding:0px 20px 5px 20px;">
         <span class="pane" v-for="item in periodList" style="line-height:30px;padding:2px;" @click="tabClick(item.value)" :class="{ active: periodId === item.value }">
           {{item.label}}
@@ -126,6 +130,7 @@
   </div>
 </template>
 <script>
+import excel from '@/utils/excel.js'
 import Overall from './echart/Overall.vue'
 import KngLevel from './echart/KngLevel.vue'
 import KngPoint from './echart/KngPoint.vue'
@@ -159,6 +164,7 @@ export default {
     curPeriodData() {
       let data = {}
       data.areaSchool = this.allData.areaSchool || {}
+      data.periodAll = this.allData.periodAll || {}
       data.overall = this.allData.periodAll?.subject || []
       data.knData = this.allData.allBlock?.sub || []
       data.examData = this.allData.periodAll?.schoolScore || []
@@ -168,12 +174,20 @@ export default {
     // 头部统计数据
     topData() {
       let { scCount, classCount, stuCount, subjectCount } = this.curPeriodData.areaSchool
+      let joinCount = this.curPeriodData.periodAll ? this.curPeriodData.periodAll.schoolScore?.length : 0
       let topData = [
         {
           icon: 'md-cube',
           color: '#2d8cf0',
           number: scCount || 0,
-          text: '学校数量',
+          text: '区域学校数',
+          type: 'num'
+        },
+        {
+          icon: 'md-cube',
+          color: '#6acd7f',
+          number: joinCount || 0,
+          text: '参与学校数',
           type: 'num'
         },
         {
@@ -285,6 +299,124 @@ export default {
     this.getAreaArtList()
   },
   methods: {
+    exportArtTable(){
+      let sheets = []
+      // 区级概况
+      let areaHeaders = ['学校总数量', '参与学校数量', '班级数量','学科数量','学生人数','音乐最高分','音乐最低分','音乐平均分','音乐优秀率','音乐合格率', '美术最高分', '美术最低分', '美术平均分', '美术优秀率', '美术合格率']
+      let areaKeys = ['scCount', 'scJoinCount', 'classCount','subjectCount','stuCount','m_max','m_min','m_average','m_excellent','m_pass','p_max','p_min','p_average','p_excellent','p_pass']
+      let mScore = this.allData.periodAll.subject.find(i => i.name === 'subject_music')
+      let pScore = this.allData.periodAll.subject.find(i => i.name === 'subject_painting')
+      let areaDatas = [
+        {
+          scCount: this.allData.areaSchool.scCount,
+          scJoinCount: this.allData.periodAll.schoolScore.length,
+          classCount: this.allData.areaSchool.classCount,
+          subjectCount: this.allData.areaSchool.subjectCount,
+          stuCount: this.allData.areaSchool.stuCount,
+          m_max: mScore.max,
+          m_min: mScore.min,
+          m_average: mScore.average,
+          m_excellent: parseInt(mScore.excellent * 100) + '%',
+          m_pass:  parseInt(mScore.pass * 100) + '%',
+          p_max: pScore.max,
+          p_min: pScore.min,
+          p_average: pScore.average,
+          p_excellent: parseInt(pScore.excellent * 100) + '%',
+          p_pass: parseInt(pScore.pass * 100) + '%'
+        }
+      ]
+      const areaSheet = {
+        title: areaHeaders,
+        key: areaKeys,
+        data: areaDatas,
+        filename: '区级概况',
+        autoWidth: true
+      }
+      sheets.push(areaSheet)
+      // 各学校数据
+      let schoolHeaders = ['学校名称', '音乐最高分', '音乐平均分', '音乐优秀率', '音乐合格率', '美术最高分', '美术平均分', '美术优秀率', '美术合格率']
+      let schoolKeys = ['name', 'm_max','m_average','m_excellent','m_pass', 'p_max',  'p_average', 'p_excellent', 'p_pass']
+      let schoolDatas = []
+      this.allData.periodAll.schoolScore.forEach(school => {
+        let sch_music_score = school.scores.find(i => i.subjectId === 'subject_music')
+        let sch_paint_score = school.scores.find(i => i.subjectId === 'subject_painting')
+        schoolDatas.push({
+          name: school.name,
+          m_max: sch_music_score.max,
+          m_average: sch_music_score.average,
+          m_excellent: parseInt(sch_music_score.excellent * 100) + '%',
+          m_pass: parseInt(sch_music_score.pass * 100) + '%',
+          p_max: sch_paint_score.max,
+          p_average: sch_paint_score.average,
+          p_excellent: parseInt(sch_paint_score.excellent * 100) + '%',
+          p_pass: parseInt(sch_paint_score.pass * 100) + '%'
+        })
+      })
+      const schSheet = {
+        title: schoolHeaders,
+        key: schoolKeys,
+        data: schoolDatas,
+        filename: '各学校测评详情',
+        autoWidth: true
+      }
+      sheets.push(schSheet)
+      // 音乐数据sheet
+      let m_knoHeaders = ['知识点名称', '知识块名称', '知识块配分', '知识块维度', '知识点得分率']
+      let m_knoKeys = ['pointName', 'blockName', 'blockScore', 'dim', 'pointScoreRate']
+      let m_knoDatas = []
+      let musicKnoItem = this.allData.allBlock.sub.find(i => i.key === 'subject_music')
+      musicKnoItem.sl.forEach(point => {
+        point.kno.forEach(block => {
+          m_knoDatas.push(
+            {
+              pointName: point.key,
+              blockName: block,
+              blockScore: musicKnoItem.blk.find(i => i.name === block).score,
+              dim: musicKnoItem.blk.find(i => i.name === block).dim[0],
+              pointScoreRate: parseInt(point.scores * 100) + '%'
+            }
+          )
+        })
+      })
+      const m_knoSheet = {
+        title: m_knoHeaders,
+        key: m_knoKeys,
+        data: m_knoDatas,
+        filename: '音乐知识点得分率',
+        autoWidth: true
+      }
+      sheets.push(m_knoSheet)
+      // 美术得分率sheet
+      let p_knoHeaders = ['知识点名称', '知识块名称', '知识块配分', '知识块维度', '知识点得分率']
+      let p_knoKeys = ['pointName', 'blockName', 'blockScore', 'dim', 'pointScoreRate']
+      let p_knoDatas = []
+      let paintKnoItem = this.allData.allBlock.sub.find(i => i.key === 'subject_painting')
+      paintKnoItem.sl.forEach(point => {
+        point.kno.forEach(block => {
+          p_knoDatas.push(
+            {
+              pointName: point.key,
+              blockName: block,
+              blockScore: paintKnoItem.blk.find(i => i.name === block).score,
+              dim: paintKnoItem.blk.find(i => i.name === block).dim[0],
+              pointScoreRate: parseInt(point.scores * 100) + '%'
+            }
+          )
+        })
+      })
+      const p_knoSheet = {
+        title: p_knoHeaders,
+        key: p_knoKeys,
+        data: p_knoDatas,
+        filename: '美术知识点得分率',
+        autoWidth: true
+      }
+      sheets.push(p_knoSheet)
+      console.log(this.periodList);
+      console.log(this.periodId);
+      let curPeriodName = this.periodList.find(i => i.value === this.periodId).label
+      excel.export_array_to_sheet(sheets, `${sessionStorage.getItem('areaName')} - 艺术评测报告(${ curPeriodName })`)
+    },
     getAreaArtList() {
       this.$api.areaArt.findAreaArtList({
         id: sessionStorage.getItem('areaId'),
@@ -548,7 +680,7 @@ export default {
   border-radius: 4px;
 }
 .content-con-item {
-  width: 23%;
+  width: 18%;
   height: 110px;
   position: relative;
   border-radius: 2px;
@@ -582,9 +714,17 @@ export default {
   padding: 0px 20px 0px 20px;
 }
 .area-data-container {
+  position: relative;
   width: 100%;
   height: 100%;
   background: #ededed;
+
+  .export-box{
+    position: absolute;
+    right: 20px;
+    top: 20px;
+    cursor: pointer;
+  }
 }
 </style>
 <style lang="less">

+ 18 - 3
TEAMModelOS/ClientApp/src/view/art/SchoolArt.less

@@ -1,6 +1,6 @@
 @mainColor: #284c8e;
 
-#artIndex {
+#areaArtIndex {
   color: #d3d6dd;
   width: 100%;
   height: 100%;
@@ -12,6 +12,20 @@
     "Microsoft JhengHei UI",
     "Microsoft JhengHei";
 
+  .no-data-wrap {
+    height: 90vh;
+    margin-top: 20px;
+
+    .border-box-content {
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+      font-size: 38px;
+      letter-spacing: 1px;
+    }
+  }
+
 
   .tools {
     position: absolute;
@@ -61,8 +75,9 @@
 
   .ivu-input {
     width: 200px;
+    font-size: 12px !important;
     color: #fff !important;
-    font-weight: bold;
+    // font-weight: bold;
   }
 
   .ivu-cascader .ivu-cascader-menu-item {
@@ -185,7 +200,7 @@
 
       .title-text {
         font-size: 24px;
-        font-weight: bold;
+        // font-weight: bold;
         position: absolute;
         bottom: 20px;
         left: 50%;

+ 106 - 1
TEAMModelOS/ClientApp/src/view/art/SchoolArt.vue

@@ -6,6 +6,7 @@
         <!-- 实时北京时间 -->
         <div class="tools">
           <span class="time-text">{{ dateYear }} <span style="display: inline-block; margin: 0 5px;color: #0fa2fe;">{{ dateDay }}</span> </span>
+          <span class="icon iconfont icon-download" v-if="!isNoData" style="font-size: 22px;margin-right:10px" :title="`下载艺术评测数据表`" @click="exportArtTable"></span>
           <span class="icon iconfont icon-tuichuquanping" style="font-size: 22px;" :title="$t('researchCenter.dashboard.quit')" @click="goBack"></span>
         </div>
         <!-- 学校基础信息 及 活动、科目选择 -->
@@ -79,6 +80,7 @@
 </template>
 
 <script>
+import excel from '@/utils/excel.js'
 import RightBotR from '@/components/dashboard/art/RightBotR'
 import RightBotL from '@/components/dashboard/art/RightBotL'
 import LeftTop from '@/components/dashboard/art/LeftTop'
@@ -88,6 +90,7 @@ import RightTop from '@/components/dashboard/art/RightTop'
 export default {
   data() {
     return {
+      isNoData: false,
       schCodeFromArea: null,
       activeAcIndex: 0,
       acList: [],
@@ -250,6 +253,105 @@ export default {
       // }
       this.$router.go(-1)
     },
+    exportArtTable() {
+      let sheets = []
+      let analysisJson = this.$store.state.artDashboard.artAnalysisJson
+      // 校级概况sheet
+      let schoolHeader = ['应考人数', '实考人数', '最高分(总)', '最低分(总)', '平均分(总)', '优秀率', '及格率', '标准差', '年级测评平均分', '年级测评最高分', '年级测评优秀率', '年级测评及格率']
+      let schoolKeys = ['count', 'scount', 'max', 'min', 'average', 'excellent', 'pass', 'pow', 'gradeAverage', 'gradeMax', 'gradeExcellent', 'gradePass']
+      let schoolDatas = [{
+        count: analysisJson.count,
+        scount: analysisJson.scount,
+        max: analysisJson.max,
+        min: analysisJson.min,
+        average: analysisJson.average,
+        excellent: parseInt(analysisJson.excellent * 100) + '%',
+        pass: parseInt(analysisJson.pass * 100) + '%',
+        pow: analysisJson.pow,
+        gradeAverage: analysisJson.gscore[0].score,
+        gradeMax: analysisJson.gscore[0].max,
+        gradeExcellent: analysisJson.gscore[0].excellent,
+        gradePass: analysisJson.gscore[0].pass
+      }]
+      const schoolSheet = {
+        title: schoolHeader,
+        key: schoolKeys,
+        data: schoolDatas,
+        filename: '校级概况',
+        autoWidth: true
+      }
+      sheets.push(schoolSheet)
+      // 班级概况sheet
+      let classHeaders = ['班级名称', '平均分', '最高分', '最低分', '优秀率', '及格率']
+      let classKeys = ['name', 'average', 'max', 'min', 'excellent', 'pass']
+      let classDatas = analysisJson.cInfo.map(classItem => {
+        return {
+          name: classItem.name,
+          average: classItem.score,
+          max: classItem.max,
+          min: classItem.min,
+          excellent: parseInt(classItem.excellent * 100) + '%',
+          pass: parseInt(classItem.pass * 100) + '%'
+        }
+      })
+      const classSheet = {
+        title: classHeaders,
+        key: classKeys,
+        data: classDatas,
+        filename: '测评情况统计(班级)',
+        autoWidth: true
+      }
+      sheets.push(classSheet)
+      // 学生测评sheet
+      let stuHeaders = ['班级名称', '年级', '学生姓名', '学生学号', '测评得分', '测评得分率', '稳定度系数', '稳定度区级']
+      let stuKeys = ['className', 'gradeName', 'name', 'id', 'score', 'pass', 'sta', 'stu']
+      let stuDatas = analysisJson.students.map(stu => {
+        return {
+          className: stu.className,
+          gradeName: stu.gradeId,
+          name: stu.name,
+          id: stu.id,
+          score: stu.score,
+          pass: parseInt(stu.score) + '%',
+          sta: stu.sta,
+          stu: stu.stu
+        }
+      })
+      const stuSheet = {
+        title: stuHeaders,
+        key: stuKeys,
+        data: stuDatas,
+        filename: '测评详细统计(学生)',
+        autoWidth: true
+      }
+      sheets.push(stuSheet)
+      // 学生测评sheet
+      let knoHeaders = ['知识点名称', '知识块名称', '知识块配分', '知识块维度', '知识点得分率']
+      let knoKeys = ['pointName', 'blockName', 'blockScore', 'dim', 'pointScoreRate']
+      let knoDatas = []
+      analysisJson.kno.forEach(point => {
+        point.block.forEach(block => {
+          knoDatas.push(
+            {
+              pointName: point.name,
+              blockName: block,
+              blockScore: analysisJson.blk.find(i => i.name === block).score,
+              dim: analysisJson.blk.find(i => i.name === block).dimension[0],
+              pointScoreRate: parseInt(point.score * 100) + '%'
+            }
+          )
+        })
+      })
+      const knoSheet = {
+        title: knoHeaders,
+        key: knoKeys,
+        data: knoDatas,
+        filename: '知识点得分率',
+        autoWidth: true
+      }
+      sheets.push(knoSheet)
+      excel.export_array_to_sheet(sheets, `${this.artName}(${this.subjectList[this.curSubjectIndex].name})- 校级艺术评测报告`)
+    },
     /* 格式化最新时间 */
     timeFn() {
       this.timing = setInterval(() => {
@@ -267,11 +369,13 @@ export default {
   computed: {
     schoolInfo() {
       let artInfo = this.$route.params.artInfo
+      console.log(artInfo)
+      this.artName = artInfo.name
       if (artInfo) {
         return {
           schoolName: artInfo.name,
           schoolLogo: '',
-          periodName: artInfo.perName,
+          periodName: artInfo.perCname,
           periodId: artInfo.perId,
           curSemester: ''
         }
@@ -294,5 +398,6 @@ export default {
 
 <style lang="less">
 @import "../dashboard/Art.less";
+@import "../dashboard/style.less";
 </style>
 

+ 77 - 5
TEAMModelOS/ClientApp/src/view/dashboard/Art.vue

@@ -136,6 +136,7 @@ export default {
     console.log(params)
     if (params.artInfo) {
       this.findAreaSchoolAnalysis(params.artInfo)
+      this.$tools.fullScreen(document.getElementById('artIndex'))
     } else {
       this.findArtList()
     }
@@ -280,7 +281,8 @@ export default {
     exportArtTable() {
       let sheets = []
       let analysisJson = this.$store.state.artDashboard.artAnalysisJson
-      let schoolHeader = ['应考人数', '实考人数', '最高分(总)', '最低分(总)','平均分(总)','优秀率','及格率','标准差','年级测评平均分','年级测评优秀率','年级测评及格率']
+      // 校级概况sheet
+      let schoolHeader = ['应考人数', '实考人数', '最高分(总)', '最低分(总)','平均分(总)','优秀率','及格率','标准差','年级测评平均分', '年级测评最高分', '年级测评优秀率','年级测评及格率']
       let schoolKeys = ['count','scount','max','min','average','excellent','pass','pow','gradeAverage','gradeMax','gradeExcellent','gradePass']
       let schoolDatas = [{
         count:analysisJson.count,
@@ -288,8 +290,8 @@ export default {
         max:analysisJson.max,
         min:analysisJson.min,
         average:analysisJson.average,
-        excellent:analysisJson.excellent,
-        pass:analysisJson.pass,
+        excellent: parseInt(analysisJson.excellent * 100) + '%',
+        pass:parseInt(analysisJson.pass * 100) + '%',
         pow:analysisJson.pow,
         gradeAverage:analysisJson.gscore[0].score,
         gradeMax:analysisJson.gscore[0].max,
@@ -300,9 +302,79 @@ export default {
         title: schoolHeader,
         key: schoolKeys,
         data: schoolDatas,
-        filename: '校级概况'
+        filename: '校级概况',
+        autoWidth: true
       }
       sheets.push(schoolSheet)
+      // 班级概况sheet
+      let classHeaders = ['班级名称','平均分','最高分','最低分','优秀率','及格率']
+      let classKeys = ['name', 'average', 'max', 'min', 'excellent', 'pass']
+      let classDatas = analysisJson.cInfo.map(classItem => {
+        return {
+          name: classItem.name,
+          average: classItem.score,
+          max: classItem.max,
+          min: classItem.min,
+          excellent: parseInt(classItem.excellent * 100) + '%',
+          pass: parseInt(classItem.pass * 100) + '%'
+        }
+      })
+      const classSheet = {
+        title: classHeaders,
+        key: classKeys,
+        data: classDatas,
+        filename: '测评情况统计(班级)',
+        autoWidth: true
+      }
+      sheets.push(classSheet)
+      // 学生测评sheet
+      let stuHeaders = ['班级名称', '年级', '学生姓名', '学生学号', '测评得分', '测评得分率','稳定度系数','稳定度区级']
+      let stuKeys = ['className', 'gradeName', 'name', 'id', 'score', 'pass','sta','stu']
+      let stuDatas = analysisJson.students.map(stu => {
+        return {
+          className: stu.className,
+          gradeName: stu.gradeId,
+          name: stu.name,
+          id: stu.id,
+          score: stu.score,
+          pass: parseInt(stu.score) + '%',
+          sta: stu.sta,
+          stu: stu.stu
+        }
+      })
+      const stuSheet = {
+        title: stuHeaders,
+        key: stuKeys,
+        data: stuDatas,
+        filename: '测评详细统计(学生)',
+        autoWidth: true
+      }
+      sheets.push(stuSheet)
+      // 学生测评sheet
+      let knoHeaders = ['知识点名称','知识块名称','知识块配分','知识块维度','知识点得分率']
+      let knoKeys = ['pointName', 'blockName', 'blockScore', 'dim', 'pointScoreRate']
+      let knoDatas = []
+      analysisJson.kno.forEach(point => {
+        point.block.forEach(block => {
+          knoDatas.push(
+            {
+              pointName: point.name,
+              blockName: block,
+              blockScore: analysisJson.blk.find(i => i.name === block).score,
+              dim: analysisJson.blk.find(i => i.name === block).dimension[0],
+              pointScoreRate: parseInt(point.score * 100) + '%'
+            }
+          )
+        })
+      })
+      const knoSheet = {
+        title: knoHeaders,
+        key: knoKeys,
+        data: knoDatas,
+        filename: '知识点得分率',
+        autoWidth:true
+      }
+      sheets.push(knoSheet)
       excel.export_array_to_sheet(sheets, `${ this.artName }(${ this.subjectList[this.curSubjectIndex].name })- 校级艺术评测报告`)
     },
     /* 格式化最新时间 */
@@ -326,7 +398,7 @@ export default {
         return {
           schoolName: artInfo.name,
           schoolLogo: '',
-          periodName: artInfo.perName,
+          periodName: artInfo.perCname,
           periodId: artInfo.perId,
           curSemester: ''
         }

+ 1 - 1
TEAMModelOS/Controllers/Common/AreaController.cs

@@ -852,7 +852,7 @@ namespace TEAMModelOS.Controllers
                     var pschoolScore = psc.GroupBy(g => (g.code, g.artId, g.examId, g.classes)).Select(x => new
                     {
                         perName = ptype,
-                        perCname = perInfos.Where(c => c.ptype.Equals(ptype) && c.pId.Equals(x.Key.code)).FirstOrDefault().name,
+                        perCname = baseInfo.Where(c => c.id.Equals(x.Key.code)).FirstOrDefault().periods.Where(z => null != z.periodType && z.periodType.Equals(ptype)).FirstOrDefault()?.name,
                         baseInfo.Where(c => c.id.Equals(x.Key.code)).FirstOrDefault().name,
                         x.Key.artId,
                         x.Key.examId,

+ 5 - 5
TEAMModelOS/Controllers/XTest/FixDataController.cs

@@ -229,12 +229,12 @@ namespace TEAMModelOS.Controllers
                 x.name,
                 className = classes.Where(c => c.classId.Equals(x.name))?.FirstOrDefault().name,
                 x.values,
-                x.scores,
-                results =  x.results.Select(c => new { 
-                    c.subjectId,
-                    c.quotaName,
-                    c.score
+                x.scores.Where(c => c.subjectId.Equals("subject_music")).FirstOrDefault()?.score,
+                quotaName = x.results.Where(c => c.subjectId.Equals("subject_music")).Select(z => new {
+                    z.quotaName,
+                    z.score
                 })
+                
             });
             return Ok(stus);
         }