导入数据平台的表

openf12 V2.1.3
yujialong 2 years ago
parent 520feb1396
commit a502f4bfcc
  1. 21
      package-lock.json
  2. 1
      package.json
  3. 6
      src/api/index.js
  4. 14
      src/components/TestPanel.vue
  5. 2
      src/config/index.js
  6. 7
      src/styles/common.scss
  7. 400
      src/views/Data.vue
  8. 19
      src/views/Home.vue

21
package-lock.json generated

@ -1470,6 +1470,11 @@
}
}
},
"@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="
},
"@types/webpack": {
"version": "4.41.32",
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.32.tgz",
@ -11773,6 +11778,22 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true
},
"vue-uuid": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/vue-uuid/-/vue-uuid-3.0.0.tgz",
"integrity": "sha512-+5DP857xVmTHYd00dMC1c1gVg/nxG6+K4Lepojv9ckHt8w0fDpGc5gQCCttS9D+AkSkTJgb0cekidKjTWu5OQQ==",
"requires": {
"@types/uuid": "^8.3.4",
"uuid": "^8.3.2"
},
"dependencies": {
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
}
}
},
"vuescroll": {
"version": "4.17.3",
"resolved": "https://registry.npmjs.org/vuescroll/-/vuescroll-4.17.3.tgz",

@ -24,6 +24,7 @@
"vue-draggable-resizable": "^2.3.0",
"vue-draggable-resizable-gorkys": "^2.4.8",
"vue-router": "^3.5.3",
"vue-uuid": "^3.0.0",
"vuescroll": "^4.17.3",
"vuex": "^3.6.2"
},

@ -11,6 +11,12 @@ export default {
getLastCache: 'python/python/getLastCache',
delCache: 'python/python/delCache',
getTheMostRecentlyRunProject: 'python/python/getTheMostRecentlyRunProject',
getDataProductBoughtByOurSchool: 'data/data/myDate/getDataProductBoughtByOurSchool',
getPurchasedTableByCategory: `data/data/myDate/getPurchasedTableByCategory`,
previewData: `data/data/preview`,
lookupTableFile: `occupationlab/python/table/data/lookupTableFile`,
downloadData:`${config.host}data/data/download`,
fileupload: `${config.host}occupationlab/oss/manage/fileupload`,
getDetailById: 'occupationlab/occupationlab/assessment/getDetailById',
pageStuAssessment: 'occupationlab/occupationlab/assessment/pageStuAssessment',
modelClassList: `nakadai/nakadai/model/reference/modelClassList`,

@ -4,7 +4,12 @@
<el-header>
<div class="panel-header">
<div class="project">
<div class="inline-center">
<p>实训项目</p>
<el-tooltip effect="dark" content="点击右侧“下三角”按钮可切换实验项目" placement="bottom">
<i class="info el-icon-warning" style="margin-left: 10px"></i>
</el-tooltip>
</div>
<el-select
v-model="projectId"
placeholder="请选择"
@ -61,7 +66,7 @@
<div>
<el-row>
<el-col :span="24">
<el-card shadow="hover">
<el-card shadow="never" :border="false">
<el-table :data="taskList" :stripe="true">
<el-table-column type="index"></el-table-column>
<el-table-column prop="name" label="判分点" align="center"></el-table-column>
@ -846,4 +851,11 @@ export default {
color: #f00;
font-size: 20px;
}
.info {
color: #bfbfbf;
cursor: pointer;
&:hover {
opacity: .9;
}
}
</style>

@ -10,7 +10,7 @@ let bankPath = `${location.origin}/banksystem` // 银行系统
// 121.37.12.51 | 192.168.31.151
if (isDev) {
host = 'http://192.168.31.151:9000/'
host = 'http://121.37.12.51:9000/'
// host = 'http://121.37.12.51:9000/'
bankPath = `http://${location.hostname}:8093`
} else if (isPro) {
host = 'https://occupationlab.com/'

@ -26,6 +26,13 @@ input::-moz-input-placeholder {
input::-ms-input-placeholder {
color: #333;
}
.inline-center {
display: inline-flex;
align-items: center;
}
.el-card {
border: 0 !important;
}
body .cus-table.el-table {
border-radius: 4px;
th{

@ -10,7 +10,7 @@
</div>
</div>
<el-table :data="list" class="cus-table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange">
<el-table :data="list" class="cus-table" ref="table" stripe header-align="center" empty-text="暂无数据支持导入xlsx csv txt等格式的文件" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="80" align="center"></el-table-column>
<el-table-column type="index" label="序号" width="55" align="center"></el-table-column>
<el-table-column prop="fileName" label="文件名称" align="center" show-overflow-tooltip></el-table-column>
@ -51,9 +51,9 @@
</el-dialog>
<!-- 导入数据 -->
<el-dialog title="导入" :visible.sync="importVisible" width="80%" center @close="closeImport" class="dialog" :close-on-click-modal="false">
<el-dialog title="导入" :visible.sync="importVisible" width="80%" center class="dialog" :close-on-click-modal="false">
<el-container style="padding: 20px 0 20px 20px;background-color: #f0f0f0;">
<div style="overflow:auto;height: 558px;width:330px;padding:15px;background:#fff" ref="typeTreeWrap" @scroll="loadType">
<div style="overflow:auto;height: 558px;width:330px;padding:15px;background:#fff" ref="typeTreeWrap">
<el-tree v-loading="importLoading"
ref="typeTree"
:data="importTypeList"
@ -62,23 +62,47 @@
:default-expanded-keys="defaultTypeActive"
:default-checked-keys="defaultTypeChecked"
:current-node-key="curId"
show-checkbox
highlight-current
@node-click="importTypeClick"
@node-expand="importTypeExpand"
:props="{
label: 'categoryName'
}"
@node-click="getTable"
>
</el-tree>
</div>
<el-main style="padding-top: 0;padding-bottom: 0;">
<el-card shadow="hover">
<div class="flex-center mgb20">
<p class="hr_tag"></p>
<span>预览</span>
</div>
<el-table :data="fieldData" stripe header-align="center" v-if="fieldHead.length">
<el-table-column type="index" width="100" label="序号" align="center"></el-table-column>
<el-table-column v-for="(item,index) in fieldHead" :prop="item.field" :key="index" :label="item.comment" align="center"></el-table-column>
<el-input style="width: 250px;margin-bottom: 15px;" placeholder="请输入表名称" v-model="keyword" suffix-icon="el-icon-search" clearable size="small"></el-input>
<el-table :data="tables" class="cus-table" ref="table" stripe header-align="center" @selection-change="handleSelectionChange">
<el-table-column width="40" align="center">
<template slot-scope="scope">
<el-radio class="check-table" v-model="curTable" :label="scope.row.id"></el-radio>
</template>
</el-table-column>
<el-table-column type="index" width="50" label="序号" align="center"></el-table-column>
<el-table-column prop="tableComment" label="数据表名称" align="center">
<template slot-scope="scope">
{{scope.row.tableComment ? scope.row.tableComment : scope.row.showName}}
</template>
</el-table-column>
<el-table-column prop="dataTotal" label="数据总量" width="80" align="center"></el-table-column>
<el-table-column prop="timeRange" label="起止日期" width="200" align="center"></el-table-column>
<el-table-column prop="dataSize" label="数据大小" width="80" align="center">
<template slot-scope="scope">
{{scope.row.dataSize}}M
</template>
</el-table-column>
<el-table-column prop="updateTime" label="更新时间" width="160" align="center"></el-table-column>
<el-table-column label="操作" width="80" align="center">
<template slot-scope="scope">
<el-button type="text" @click="preview(scope.row)">预览</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination background layout="total, prev, pager, next" :current-page="pageTable" @current-change="handleCurrentChangeTable" :total="totalTable">
</el-pagination>
</div>
</el-card>
</el-main>
</el-container>
@ -87,6 +111,12 @@
<el-button type="primary" :loading="submited" @click="confirmImport"> </el-button>
</span>
</el-dialog>
<el-dialog title="预览" :visible.sync="previewVisible" width="60%" center :close-on-click-modal="false">
<el-table :data="previewData" class="table" stripe header-align="center" row-key="id">
<el-table-column type="index" width="100" label="序号" align="center"></el-table-column>
<el-table-column v-for="(item,index) in previewHead" :prop="item.field" :key="index" :label="item.comment" align="center"></el-table-column>
</el-table>
</el-dialog>
</div>
</div>
</template>
@ -95,6 +125,7 @@ import Cookie from 'js-cookie'
import util from '@/util'
import clipboard from '@/util/clipboard'
import breadcrumb from '@/components/breadcrumb'
import axios from 'axios'
export default {
data() {
return {
@ -120,6 +151,15 @@ export default {
curId: '',
curExpand: '',
submited: false,
tables: [],
keywordTable: '',
pageTable: 1,
pageSizeTable: 10,
totalTable: 0,
curTable: '',
previewVisible: false,
previewHead: [],
previewData: [],
};
},
components: {
@ -210,13 +250,8 @@ export default {
},
//
show(row) {
// word,pdf,excel
const format = row.fileFormat
// if ('xls,xlsx'.includes(format)) {
// this.$router.push(`/preview?path=${row.filePath}`)
// } else {
window.open((util.isDoc(format) ? 'https://view.officeapps.live.com/op/view.aspx?src=' : '') + row.filePath)
// }
},
//
download(row) {
@ -242,286 +277,146 @@ export default {
},
//
getMoreTable(list,id){
list.map(n => {
if(n.id == id){
this.getTable(n,1)
}else if(n.children && n.children.length){
this.getMoreTable(n.children,id)
}
})
},
// ,,id
renderChecked(){
let result = []
let list = this.$refs.typeTree.getCheckedNodes()
list.map((n,i) => {
if(n.tableLen && n.tableLen > n.children.length){
result = [...result,...n.children.map(n => n.id)]
}else{
result.push(n.id)
}
})
this.$refs.typeTree.setCheckedKeys(result)
},
// ,dom,
loadType(e){
clearTimeout(this.typeTimer)
let typeTree = this.$refs.typeTreeWrap
//
this.typeTimer = setTimeout(() => {
this.typeTreeScrollTop = typeTree.scrollTop - this.typeTreeScrollTop
// ,
if(this.typeTreeScrollTop > 0 && typeTree.scrollHeight - (typeTree.clientHeight + parseInt(typeTree.scrollTop)) < 10){
this.getMoreTable(this.importTypeList,this.curExpand)
Promise.all(this.tablePromises).then(_ => {
this.renderChecked()
})
}
},50)
},
//
getTable(n,isConcat){
this.tablePromises.push(new Promise((resolve,reject) => {
this.$post(`${this.api.originalListById}?categoryId=${n.realId}&pageNum=${n.typeTreePage ? n.typeTreePage : 1}&pageSize=${this.typeTreeUnit}`).then(res => {
let list = res.list.records
list.map(n => {
n.label = n.showName
n.id = String(n.id)
// ,
if(this.defaultTypeChecked.includes(n.id)){
n.disabled = true
}
})
// ,
if(isConcat){
n.children = n.children.concat(list)
}else{
n.children = list
n.tableLen = res.list.total
}
// ,+1
n.typeTreePage++
resolve()
}).catch(res => {
reject()
})
}))
},
//
showData(){
this.curTable = ''
this.tables = []
this.importLoading = true
this.importVisible = true
//
this.$post(this.api.originalList).then(res => {
// idlabelnamekeylabelnamekey
function handleId(data){
data.map(n => {
n.realId = n.id
// ididuuid
n.id = uuid.v4()
n.label = n.categoryName
if(n.children.length){
handleId(n.children)
}
})
}
handleId(res)
// pageSize300020
this.$post(`${this.api.getIdQueryTable}?categoryId=${this.categoryId}&showName=${this.keyword}&pageNum=1&pageSize=3000&updateTime=${this.updateTime ? this.updateTime : ''}`).then(res1 => {
let list = res1.pageList.records
this.defaultTypeChecked = list.map(n => n.copyId) // copyIdidid
//
const handleId = data => {
data.map(n => {
if(n.children.length){
handleId(n.children)
}else{
// 1
n.typeTreePage = 1
this.getTable(n)
}
})
}
handleId(res)
//
function handleDisabled (list) {
list.map(e => {
if (e.children && e.children.length) {
if (e.children.every(e => e.disabled)) e.disabled = true
handleDisabled(e.children)
}
})
}
Promise.all(this.tablePromises).then(_ => {
handleDisabled(res)
this.importTypeList = res
this.$post(this.api.getDataProductBoughtByOurSchool).then(({ data }) => {
this.importTypeList = data
this.importLoading = false
})
}).catch(res => {
this.importLoading = false
})
}).catch(res => {
this.importLoading = false
},
//
getTable(){
this.$post(`${this.api.getPurchasedTableByCategory}?categoryId=${this.$refs.typeTree.getCurrentKey()}&pageNum=${this.pageTable}&pageSize=${this.pageSizeTable}`).then(({ data }) => {
const list = data.records
list.map(e => {
//
const startTime = e.startTime ? e.startTime.slice(0, 10) : ''
const endTime = e.endTime ? e.endTime.slice(0, 10) : ''
if (startTime && endTime) {
e.timeRange = startTime + ' ~ ' + endTime
} else if (startTime) {
e.timeRange = startTime
} else if (endTime) {
e.timeRange = e.endTime
}
})
this.tables = list
this.totalTable = data.total
}).catch(res => {})
},
//
getFields(){
this.$get(`${this.api.staticPreview}?tableName=${this.tableName}`).then(res => {
handleCurrentChangeTable(val) {
this.pageTable = val
this.getTable()
},
//
preview(row){
this.$get(`${this.api.previewData}?tableName=${row.name}&tableId=${row.id}`).then(res => {
let comment = res.comment
let fieldHead = []
// id
let previewHead = []
this.curComment = comment //
comment.map(n => {
n.field != 'id' && n.field != 'operation_time' && fieldHead.push(n)
// id
n.field != 'id' && n.field != 'operation_time' && previewHead.push(n)
})
this.fieldHead = fieldHead
this.previewHead = previewHead
let data = res.data
// custom
isEdit && data.unshift({
custom: true
})
data.map(n => {
for(let i in n){
// +0000,,
if(typeof n[i] == 'string' && n[i].endsWith('+0000')) n[i] = this.formatDate('yyyy-MM-dd hh:mm:ss',new Date(n[i]))
}
})
this.fieldData = data
}).catch(res => {})
this.importVisible = true
},
//
importTypeClick(data){
// ,,
if(data.name){
this.tableName = data.name
this.curId = data.id
this.getFields()
}
},
//
importTypeExpand(obj,node,com){
this.curExpand = obj.id
this.renderChecked()
},
//
closeImport(){
this.$refs.typeTree.setCheckedKeys([])
this.categorys = []
},
// id
getNames(list){
const categoryId = Number(this.categoryId)
return new Promise((resolve,reject) => {
this.$get(`${this.api.getAllTableInfoByCategoryId}?categoryId=${list.join()}`).then(res => {
const list = res.tableInfo
list.map(e => {
delete e.id // id
e.categoryId = categoryId
})
this.categorys = list
resolve()
this.previewData = data
this.previewVisible = true //
}).catch(res => {})
})
},
//
saveSuccess() {
// python
importData(file) {
this.$post(this.api.importData, {
fileFormat: file.fileType || file.fileFormat,
fileName: file.originalFileName || file.fileName,
filePath: file.fileUrl || file.filePath,
fileSize: file.fileSize,
ossFileName: file.ossFileName
}).then(res => {
this.$message.success('导入成功')
this.getData()
this.importVisible = false
setTimeout(() => {
this.submited = false
},1000)
}, 1000)
this.sourceVisible = false
}).catch(res => {
this.submited = false
})
},
//
confirmImport(){
if(this.submited) return false //
const checked = this.$refs.typeTree.getCheckedNodes().filter(e => !e.disabled) //
const id = this.curTable //
//
if(!checked.length) return this.$message.warning('请选择数据')
if(!id) return this.$message.warning('请选择数据')
const row = this.tables.find(e => e.id === id)
const { name } = row
this.submited = true
// ididid
const typeIds = checked.filter(e => !e.name).map(e => e.realId) // idnamenameididididrealIdid
const tableIds = checked.filter(e => e.name) //
const categoryId = Number(this.categoryId) //
// categoryId
tableIds.map(e => {
delete e.id
e.categoryId = categoryId
})
/**
* 根据某个值给数组对象去重
* @param arr 要处理的数组
* @param val 去重依据的值
*/
function uniq (arr, val) {
const res = new Map()
return arr.filter(e => !res.has(e[val]) && res.set(e[val], 1))
}
// ididid
if (typeIds.length) {
this.getNames(typeIds).then(() => {
const allIds = [...this.categorys, ...tableIds] // idid
const data = uniq(allIds, 'name')
const dataList = []
// 2000
for (let i = 0, len = data.length; i < len; i += 2000) {
dataList.push(data.slice(i, i + 2000))
}
const promiseList = []
// 2000item6item6item2000item6item6item2000666
if (dataList.length > 6) {
dataList.slice(0, 6).map(e => {
promiseList.push(new Promise((resolve,reject) => {
this.$post(this.api.saveTable, e).then(res => {
resolve()
}).catch(res => {
reject()
})
}))
})
Promise.all(promiseList).then(res => {
dataList.slice(6).map(e => {
promiseList.push(new Promise((resolve,reject) => {
this.$post(this.api.saveTable, e).then(res => {
resolve()
// Excel
this.$post(`${this.api.lookupTableFile}?tableName=${name}`).then(({ data }) => {
//
if (!data) {
//
this.$get(`${this.api.previewData}?tableName=${name}&tableId=${id}`).then(({ comment }) => {
//
axios.get(`${this.api.downloadData}?tableName=${name}&table_id=${id}&fields=${comment.map(e => e.field).join()}&startTime=${row.startTime}&endTime=${row.endTime}&frequency=1`, {
headers: {
token: this.token
},
responseType: 'blob'
}).then((res) => {
// if (res.data.type != 'multipart/form-data') return util.warningMsg('')
//
const form = new FormData()
form.append('file', new Blob([res.data], {type: 'application/vnd.ms-excel'}))
form.append('tableName', name)
form.append('token', this.token)
axios({
method: 'post',
url: `${this.api.fileupload}`,
data: form,
headers: {
token: this.token,
'Content-Type': 'multipart/form-data'
},
}).then(({ data }) => {
this.importData(data.filesResult)
}).catch(res => {
reject()
})
}))
})
Promise.all(promiseList).then(res => {
this.saveSuccess()
}).catch(err => {
this.submited = false
})
}).catch(err => {
}).catch(res => {
this.submited = false
})
} else {
dataList.map(e => {
promiseList.push(new Promise((resolve,reject) => {
this.$post(this.api.saveTable, e).then(res => {
resolve()
}).catch(res => {
reject()
})
}))
})
Promise.all(promiseList).then(res => {
this.saveSuccess()
}).catch(err => {
this.submited = false
})
} else {
//
this.importData(data)
}
})
} else { //
this.$post(this.api.saveTable, tableIds).then(res => {
this.saveSuccess()
}).catch(res => {
this.submited = false
})
}
}
}
};
</script>
<style lang="scss" scoped>
@ -582,4 +477,9 @@ export default {
}
}
}
/deep/.check-table {
.el-radio__label {
display: none;
}
}
</style>

@ -12,8 +12,13 @@
<p>编程语言</p>
<el-input placeholder="请输入内容" v-model="language" :disabled="true"></el-input>
</div>
<div class="inline-center">
<el-tooltip class="item" effect="dark" content="支持导入其它数据用于实验,总上传的文件大小不可以超过10M" placement="bottom">
<i class="info el-icon-warning" style="margin-right: 10px"></i>
</el-tooltip>
<el-button type="primary" size="small" icon="el-icon-document" @click="toData">我的数据</el-button>
</div>
</div>
<div class="tab">
<el-tabs v-model="curTab" type="card" @tab-click="judChange">
@ -61,6 +66,7 @@ export default {
return {
loaded: false, //
loadIns: null, // loading
fromManager: Cookie.get('admin-fromManager'), //
courseId: Cookie.get('admin-courseId'), // id
curriculumName: Cookie.get('admin-curriculumName') ? unescape(Cookie.get('admin-curriculumName')) : 'python', //
assessmentId: Cookie.get('admin-assessmentId'), // id
@ -165,7 +171,11 @@ export default {
back() {
let href = this.$config.isDev ?
`http://${location.hostname}:8082/#/` :
`${location.origin}${this.$config.isPro ? '' : '/student'}/#/`
`${location.origin}${this.fromManager ?
'/admin' :
this.$config.isPro ?
'' :
'/student'}/#/`
//
if (this.assessmentId) {
href += `ass/list`
@ -269,4 +279,11 @@ export default {
border-bottom: none;
}
}
.info {
color: #bfbfbf;
cursor: pointer;
&:hover {
opacity: .9;
}
}
</style>
Loading…
Cancel
Save