|
|
|
@ -100,6 +100,13 @@
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="data-preview" v-if="fileData.previewData">
|
|
|
|
|
<div class="table-operations" style="margin-bottom: 15px; display: flex; justify-content: flex-end;">
|
|
|
|
|
<el-button
|
|
|
|
|
type="primary"
|
|
|
|
|
size="small"
|
|
|
|
|
@click="handleAddNew"
|
|
|
|
|
>新增数据</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<h4>数据预览</h4>
|
|
|
|
|
<el-table :data="fileData.previewData.rows" border style="width: 100%">
|
|
|
|
|
<el-table-column
|
|
|
|
@ -109,8 +116,53 @@
|
|
|
|
|
:label="col.label"
|
|
|
|
|
width="180"
|
|
|
|
|
></el-table-column>
|
|
|
|
|
<el-table-column
|
|
|
|
|
label="操作"
|
|
|
|
|
width="180"
|
|
|
|
|
fixed="right"
|
|
|
|
|
>
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<el-button
|
|
|
|
|
size="mini"
|
|
|
|
|
@click="handleEdit(scope.$index, scope.row)"
|
|
|
|
|
>编辑</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
size="mini"
|
|
|
|
|
type="danger"
|
|
|
|
|
@click="handleDelete(scope.$index)"
|
|
|
|
|
>删除</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
</el-table>
|
|
|
|
|
</div>
|
|
|
|
|
<el-dialog
|
|
|
|
|
:title="isEditing ? '编辑数据' : '新增数据'"
|
|
|
|
|
:visible.sync="dataDialogVisible"
|
|
|
|
|
width="50%"
|
|
|
|
|
>
|
|
|
|
|
<el-form
|
|
|
|
|
:model="currentRowData"
|
|
|
|
|
label-width="100px"
|
|
|
|
|
ref="dataForm"
|
|
|
|
|
:rules="formRules"
|
|
|
|
|
>
|
|
|
|
|
<el-form-item
|
|
|
|
|
v-for="col in fileData.previewData.columns"
|
|
|
|
|
:key="col.prop"
|
|
|
|
|
:label="col.label"
|
|
|
|
|
:prop="col.prop"
|
|
|
|
|
>
|
|
|
|
|
<el-input v-model="currentRowData[col.prop]"></el-input>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form>
|
|
|
|
|
<span slot="footer">
|
|
|
|
|
<el-button @click="dataDialogVisible = false">取消</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
type="primary"
|
|
|
|
|
@click="submitDataForm"
|
|
|
|
|
>确 定</el-button>
|
|
|
|
|
</span>
|
|
|
|
|
</el-dialog>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</process-step>
|
|
|
|
@ -123,11 +175,11 @@ import { mapState, mapActions } from 'vuex'
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
name: 'FileUploadComponent',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
components: {
|
|
|
|
|
ProcessStep
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
fileList: [],
|
|
|
|
@ -135,17 +187,24 @@ export default {
|
|
|
|
|
loading: false,
|
|
|
|
|
uploadProgress: 0,
|
|
|
|
|
uploadStatus: 'waiting',
|
|
|
|
|
uploadTimer: null
|
|
|
|
|
uploadTimer: null,
|
|
|
|
|
dataDialogVisible: false,
|
|
|
|
|
currentRowData: {},
|
|
|
|
|
currentEditIndex: -1,
|
|
|
|
|
isEditing: false,
|
|
|
|
|
formRules: {
|
|
|
|
|
'col0': [{ required: true, message: '字段不能为空', trigger: 'blur' }]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
computed: {
|
|
|
|
|
...mapState({
|
|
|
|
|
fileData: state => state.process.fileData,
|
|
|
|
|
fileUploaded: state => state.process.fileUploaded
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
|
fileUploaded(newVal) {
|
|
|
|
|
if (newVal) {
|
|
|
|
@ -160,48 +219,48 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
|
...mapActions('process', [
|
|
|
|
|
'uploadFile',
|
|
|
|
|
'setFileData'
|
|
|
|
|
]),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleNextStep() {
|
|
|
|
|
console.log('手动点击继续处理按钮');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 确保文件已经上传完成
|
|
|
|
|
if (this.uploadStatus !== 'completed') {
|
|
|
|
|
this.$message.warning('请等待文件上传完成');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 向父组件发出next事件,同时确保fileData已设置
|
|
|
|
|
this.$emit('next');
|
|
|
|
|
this.$emit('file-uploaded', this.fileData);
|
|
|
|
|
console.log('已发出next事件和file-uploaded事件', this.fileData);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleFileChange(file) {
|
|
|
|
|
this.file = file.raw
|
|
|
|
|
this.fileList = [file]
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleFileRemove() {
|
|
|
|
|
this.file = null
|
|
|
|
|
this.fileList = []
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleUpload() {
|
|
|
|
|
if (!this.file) {
|
|
|
|
|
this.$message.warning('请先选择要上传的文件')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.loading = true
|
|
|
|
|
this.uploadStatus = 'running'
|
|
|
|
|
this.uploadProgress = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟上传进度
|
|
|
|
|
this.uploadTimer = setInterval(() => {
|
|
|
|
|
this.uploadProgress += 10
|
|
|
|
@ -210,11 +269,11 @@ export default {
|
|
|
|
|
this.simulateUploadComplete()
|
|
|
|
|
}
|
|
|
|
|
}, 300)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 调用API上传文件
|
|
|
|
|
const formData = new FormData()
|
|
|
|
|
formData.append('file', this.file)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.uploadFile(formData)
|
|
|
|
|
.then(() => {
|
|
|
|
|
// 上传成功后的处理会在simulateUploadComplete中完成
|
|
|
|
@ -226,7 +285,7 @@ export default {
|
|
|
|
|
this.$message.error('文件上传失败:' + (error.message || '未知错误'))
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
simulateUploadComplete() {
|
|
|
|
|
// 模拟上传完成后获取文件分析结果
|
|
|
|
|
setTimeout(() => {
|
|
|
|
@ -241,19 +300,19 @@ export default {
|
|
|
|
|
fileType: this.getFileType(this.file.name),
|
|
|
|
|
previewData: this.generatePreviewData()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 设置文件数据到Vuex
|
|
|
|
|
this.setFileData(mockFileData)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将上传步骤状态更新为已完成
|
|
|
|
|
this.$store.commit('process/UPDATE_STEP_STATUS', { step: 'upload', status: 'completed' })
|
|
|
|
|
this.$store.commit('process/SET_FILE_UPLOADED', true)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 重要:立即更新组件状态为已完成
|
|
|
|
|
this.loading = false
|
|
|
|
|
this.uploadStatus = 'completed'
|
|
|
|
|
console.log('文件上传完成,状态已设置为:', this.uploadStatus)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 显示成功消息
|
|
|
|
|
this.$message({
|
|
|
|
|
message: '文件上传成功',
|
|
|
|
@ -261,11 +320,11 @@ export default {
|
|
|
|
|
duration: 3000,
|
|
|
|
|
showClose: true
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 通知父组件文件上传完成
|
|
|
|
|
this.$emit('file-uploaded', mockFileData)
|
|
|
|
|
console.log('触发file-uploaded事件,文件数据:', mockFileData)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 确保DOM更新完成
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
console.log('DOM已更新,文件上传状态:', this.uploadStatus)
|
|
|
|
@ -278,12 +337,12 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
}, 500)
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleRetry() {
|
|
|
|
|
this.uploadStatus = 'waiting'
|
|
|
|
|
this.uploadProgress = 0
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
formatFileSize(size) {
|
|
|
|
|
if (size < 1024) {
|
|
|
|
|
return size + ' B'
|
|
|
|
@ -293,12 +352,12 @@ export default {
|
|
|
|
|
return (size / (1024 * 1024)).toFixed(2) + ' MB'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
formatDate(timestamp) {
|
|
|
|
|
const date = new Date(timestamp)
|
|
|
|
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getFileType(filename) {
|
|
|
|
|
const ext = filename.split('.').pop().toLowerCase()
|
|
|
|
|
if (ext === 'csv') {
|
|
|
|
@ -309,12 +368,12 @@ export default {
|
|
|
|
|
return '未知类型'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
generatePreviewData() {
|
|
|
|
|
// 生成模拟的预览数据
|
|
|
|
|
const columns = []
|
|
|
|
|
const rows = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 生成列
|
|
|
|
|
const colCount = Math.floor(Math.random() * 5) + 3
|
|
|
|
|
for (let i = 0; i < colCount; i++) {
|
|
|
|
@ -323,7 +382,7 @@ export default {
|
|
|
|
|
label: '列 ' + (i + 1)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 生成行数据
|
|
|
|
|
const rowCount = Math.min(5, Math.floor(Math.random() * 10) + 3)
|
|
|
|
|
for (let i = 0; i < rowCount; i++) {
|
|
|
|
@ -333,11 +392,55 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
rows.push(row)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { columns, rows }
|
|
|
|
|
},
|
|
|
|
|
handleEdit(index, row) {
|
|
|
|
|
this.currentRowData = { ...row }
|
|
|
|
|
this.currentEditIndex = index
|
|
|
|
|
this.isEditing = true
|
|
|
|
|
this.dataDialogVisible = true
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
handleDelete(index) {
|
|
|
|
|
this.$confirm('确认删除该行数据吗?', '提示', {
|
|
|
|
|
type: 'warning'
|
|
|
|
|
}).then(() => {
|
|
|
|
|
const newRows = this.fileData.previewData.rows.filter((_, i) => i !== index)
|
|
|
|
|
this.$store.commit('process/UPDATE_PREVIEW_DATA', { rows: newRows })
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
handleAddNew() {
|
|
|
|
|
this.currentRowData = this.fileData.previewData.columns.reduce((acc, col) => {
|
|
|
|
|
acc[col.prop] = ''
|
|
|
|
|
return acc
|
|
|
|
|
}, {})
|
|
|
|
|
this.currentRowData._id = this._generateUniqueId()
|
|
|
|
|
this.isEditing = false
|
|
|
|
|
this.dataDialogVisible = true
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
submitDataForm() {
|
|
|
|
|
this.$refs.dataForm.validate(valid => {
|
|
|
|
|
if (valid) {
|
|
|
|
|
const newRows = [...this.fileData.previewData.rows]
|
|
|
|
|
if (this.isEditing) {
|
|
|
|
|
newRows[this.currentEditIndex] = this.currentRowData
|
|
|
|
|
} else {
|
|
|
|
|
newRows.push(this.currentRowData)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.$store.commit('process/UPDATE_PREVIEW_DATA', { rows: newRows })
|
|
|
|
|
this.dataDialogVisible = false
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
_generateUniqueId() {
|
|
|
|
|
return `row-${Date.now()}-${Math.floor(Math.random() * 1000)}`
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
if (this.uploadTimer) {
|
|
|
|
|
clearInterval(this.uploadTimer)
|
|
|
|
@ -347,6 +450,12 @@ export default {
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.table-operations {
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.file-upload {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|