AnalysisSystemForRadionucli.../src/views/spectrumAnalysis/components/Modals/LoadFromFileModal.vue

897 lines
27 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<custom-modal v-model="visible" :width="1200" title="Load Data From File">
<!-- 支持 File System Access 的情况 -->
<a-table
v-if="canUseFilePicker"
:dataSource="list"
:columns="columns"
:pagination="false"
bordered
:scroll="{ y: 450 }"
>
<template slot="sampleData" slot-scope="text, record, index">
<div
class="file-name file-ellipsis"
:title="text && text.fileName"
@dblclick="useFilePicker('sampleFileName', record, index)"
>
{{ text && text.fileName }}
</div>
</template>
<template slot="gasBkData" slot-scope="text, record, index">
<div
:class="['file-ellipsis', text && text.file ? '' : 'file-name-color']"
:title="text && text.fileName"
@dblclick="useFilePicker('gasFileName', record, index)"
>
{{ text && text.fileName }}
</div>
</template>
<template slot="detBkData" slot-scope="text, record, index">
<div
:class="['file-ellipsis', text && text.file ? '' : 'file-name-color']"
:title="text && text.fileName"
@dblclick="useFilePicker('detFileName', record, index)"
>
{{ text && text.fileName }}
</div>
</template>
<template slot="qcData" slot-scope="text, record, index">
<div
:class="['file-ellipsis', text && text.file ? '' : 'file-name-color']"
:title="text && text.fileName"
@dblclick="useFilePicker('qcFileName', record, index)"
>
{{ text && text.fileName }}
</div>
</template>
<template slot="status" slot-scope="text, record">
<template v-if="record.sampleFileName">
<span
class="status"
:class="
record.fileType == 'B' &&
!(record.gasFileName && record.gasFileName.file && record.detFileName && record.detFileName.file)
? 'status_false'
: 'status_true'
"
></span>
</template>
</template>
</a-table>
<!-- 不支持 File System Access 的情况 -->
<a-table
v-else
:data-source="list"
:columns="columns"
:loading="loading_list"
:pagination="false"
bordered
:scroll="{ y: 450 }"
>
<template slot="sampleData" slot-scope="text, record">
<div class="file-name file-ellipsis" :title="text" @dblclick="handleFileSelect('_S_', record)">
{{ text }}
</div>
<!-- <phd-select type="file" @change="handleFileChange(record, 'sampleData', $event)" @select="handleFileSelect" :title="text && text.fileName">
{{ text }}
</phd-select> -->
</template>
<template slot="gasBkData" slot-scope="text, record">
<div
:class="['file-ellipsis', !record.gasFileStatus ? 'file-name-color' : '']"
:title="text"
@dblclick="handleFileSelect('_G_', record)"
>
{{ text }}
</div>
</template>
<template slot="detBkData" slot-scope="text, record">
<div
:class="['file-ellipsis', !record.detFileStatus ? 'file-name-color' : '']"
:title="text"
@dblclick="handleFileSelect('_D_', record)"
>
{{ text }}
</div>
</template>
<template slot="qcData" slot-scope="text, record">
<div
:class="['file-ellipsis', !record.qcFileStatus ? 'file-name-color' : '']"
:title="text"
@dblclick="handleFileSelect('_Q_', record)"
>
{{ text }}
</div>
</template>
<template slot="status" slot-scope="text, record">
<span
:class="[
(record.detFileStatus && record.gasFileStatus && record.qcFileStatus) ||
(record.sampleFileName && !record.gasFileName && !record.detFileName && !record.qcFileName) ||
(record.sampleSystemType == 'C' && record.sampleFileName)
? 'status_true'
: 'status_false',
'status',
]"
></span>
</template>
</a-table>
<!-- 底部按钮 -->
<template slot="custom-footer">
<a-space>
<a-upload
v-if="!canUseFilePicker"
accept=".PHD,.phd"
:custom-request="handleUpload"
:multiple="true"
:show-upload-list="false"
:before-upload="beforeUpload"
>
<a-button type="primary" :loading="uploading"> Upload </a-button>
</a-upload>
<a-button type="primary" @click="handleReset">Reset</a-button>
<a-button :loading="isUploadingZip" type="primary" @click="handleLoad">Load</a-button>
<a-button type="warn" @click="handleCancel">Cancel</a-button>
</a-space>
</template>
<!-- 底部按钮结束 -->
</custom-modal>
<a-modal v-model="visible_file" :width="1200" title="File List" :maskClosable="false" @cancel="cancelFileModale">
<a-spin :spinning="loading_file">
<div style="position: relative; padding-bottom: 40px; height: 460px; overflow: hidden">
<a-row type="flex" style="margin-bottom: 15px">
<a-col flex="400px">
<a-input placeholder="search..." v-model="searchName" />
</a-col>
<a-col flex="108px">
<a-button class="search-btn" type="primary" @click="onSearchFileName">
<img src="@/assets/images/global/search.png" alt="" />
Search
</a-button>
</a-col>
</a-row>
<a-table
v-if="tableType == 'multiple'"
:data-source="list_file"
:columns="columns_file"
:pagination="false"
:customRow="customRow"
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:scroll="{ y: 330 }"
>
</a-table>
<custom-table
v-if="tableType == 'single'"
rowKey="id"
size="middle"
:columns="columns_file"
:list="list_file"
:pagination="false"
:selectedRowKeys.sync="selectedRowKeys_edit"
:selectionRows.sync="selectionRows_edit"
>
</custom-table>
<a-pagination
size="small"
v-model="ipagination.current"
:pageSize="ipagination.pageSize"
:page-size-options="ipagination.pageSizeOptions"
show-size-changer
show-quick-jumper
:total="ipagination.total"
:show-total="
(total, range) =>
`Total ${total} items Page ${ipagination.current} / ${Math.ceil(total / ipagination.pageSize)}`
"
show-less-items
@change="handlePageChange"
@showSizeChange="handleSizeChange"
/>
</div>
</a-spin>
<template slot="footer">
<a-space class="operators" :size="20">
<a-button type="success" @click="saveFileName">Save</a-button>
<a-button type="warn" @click="cancelFileModale">Cancel</a-button>
</a-space>
</template>
</a-modal>
</div>
</template>
<script>
import { getAction, postActionWithTimeOut } from '../../../../api/manage'
import { FilePicker } from '@/utils/FilePicker'
import { readFile, zipFile } from '@/utils/file'
import { isSample, PHDParser, PHD_DATA_TYPE } from '@/utils/phdHelper'
import ModalMixin from '@/mixins/ModalMixin'
import { cloneDeep } from 'lodash'
const columns = [
{
title: 'SampleData',
dataIndex: 'sampleFileName',
width: '23%',
ellipsis: true,
scopedSlots: {
customRender: 'sampleData',
},
},
{
title: 'GasBkData',
dataIndex: 'gasFileName',
width: '23%',
ellipsis: true,
scopedSlots: {
customRender: 'gasBkData',
},
},
{
title: 'DetBkData',
dataIndex: 'detFileName',
width: '23%',
ellipsis: true,
scopedSlots: {
customRender: 'detBkData',
},
},
{
title: 'QCData',
dataIndex: 'qcFileName',
width: '23%',
ellipsis: true,
scopedSlots: {
customRender: 'qcData',
},
},
{
title: 'Status',
align: 'center',
scopedSlots: {
customRender: 'status',
},
},
]
const columns_file = [
{
title: 'Name',
dataIndex: 'name',
width: '45%',
align: 'left',
ellipsis: true,
},
{
title: 'UpdateDate',
dataIndex: 'updateDate',
align: 'left',
},
{
title: 'Size',
dataIndex: 'size',
align: 'left',
},
]
const canUseFilePicker = FilePicker.canUse()
export default {
mixins: [ModalMixin],
props: {
value: {
type: Boolean,
},
},
data() {
this.columns = columns
return {
visible_file: false,
list_file: [],
columns_file,
loading_file: false,
loading_list: false,
isUploadingZip: false,
list: [],
ipagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '20', '30'],
showTotal: (total, range) => {
const { current, pageSize } = this.ipagination
return `Total ${total} items Page ${current} / ${Math.ceil(total / pageSize)}`
},
showQuickJumper: true,
showSizeChanger: true,
total: 0,
},
selectedRowKeys: [],
selectedFiles: [],
fileList: [],
fileNum: 0,
uploading: false,
currRowData: {},
currFileType: '_S_',
selectedRowKeys_edit: [],
selectionRows_edit: [],
tableType: 'multiple',
searchName: '',
canUseFilePicker,
}
},
created() {
this.handleReset()
},
methods: {
// 初始化为10*4的表格
getInitialList() {
return new Array(10).fill(0).map(() => ({
sampleFileName: undefined,
gasFileName: undefined,
detFileName: undefined,
qcFileName: undefined,
}))
},
customRow(record, index) {
const that = this
return {
on: {
click: () => {
if (that.selectedRowKeys.includes(record.id)) {
const findIndex = that.selectedRowKeys.findIndex((k) => k == record.id)
const idx = that.selectedFiles.findIndex((k) => k == record.name)
that.selectedRowKeys.splice(findIndex, 1)
that.selectedFiles.splice(idx, 1)
} else {
that.selectedRowKeys.push(record.id)
that.selectedFiles.push(record.name)
}
},
},
}
},
handleFileChange(record, key, fileInfo) {
record[key] = fileInfo
},
handleFileSelect(str, record) {
this.currRowData = record
this.currFileType = str
this.selectedRowKeys = []
this.selectedFiles = []
this.visible_file = true
this.tableType = str === '_S_' ? 'multiple' : 'single'
this.getSpectrumFile({ pageNo: 1, pageSize: 10 })
},
// 用新的文件操作接口
async useFilePicker(column, record, rowIndex) {
// 如果没有选择sampleFile则不允许选其他的
if (column !== 'sampleFileName' && (!record.sampleFileName || record.fileType !== 'B')) {
return
}
if (this.directoryHanlder) {
this.chooseFile(column, record, rowIndex)
} else {
try {
this.directoryHanlder = await FilePicker.chooseDirectory()
this.chooseFile(column, record, rowIndex)
} catch {}
}
},
async chooseFile(column, record, rowIndex) {
try {
const [fileHandle] = await FilePicker.chooseFile(false, [{ accept: { 'text/phd': ['.phd'] } }])
try {
const isFileInDirectory = await FilePicker.isFileInDirectory(this.directoryHanlder, fileHandle)
if (!isFileInDirectory) {
this.$message.warn('File and Directory Not in Same')
this.directoryHanlder = undefined
this.useFilePicker(column, record, rowIndex)
return
}
const file = await fileHandle.getFile()
const text = await readFile(file)
const phdParser = new PHDParser(text)
console.log('%c [ phdParser ]-313', 'font-size:13px; background:pink; color:#bf2c9f;', phdParser)
const match = this.fileNameAndColumnMatch(column, phdParser.dataType)
if (!match) {
this.$message.warn('File Type Error')
return
}
record.fileType = phdParser.fileType
// 如果是sample
if (column == 'sampleFileName') {
// 看看之前有没有选中过该文件,非同一行,则只能选择文件名不同的
const findIndex = this.list.findIndex(
(item) => item.sampleFileName && item.sampleFileName.file && item.sampleFileName.file.name == file.name
)
if (-1 !== findIndex && findIndex !== rowIndex) {
return
}
const { sampleFilePrefix, otherFilePrefixes, qualify, liveTime } = phdParser
record.sampleFileName = {
file,
fileName: `${sampleFilePrefix}S_${qualify}_${liveTime}.PHD`,
}
// 如果是Beta Gamma则查找其他的文件
if (phdParser.fileType == 'B') {
const iter = await this.directoryHanlder.values()
const fileList = []
let result = await iter.next()
while (!result.done) {
const fileHandle = result.value
const file = await fileHandle.getFile()
fileList.push(file)
result = await iter.next()
}
const nameKeys = ['detFileName', 'gasFileName']
const fileTypes = ['D', 'G']
otherFilePrefixes.forEach((otherFilePrefix, index) => {
const fileType = fileTypes[index]
// 在所有文件中查找 名字含有 从sample文件解析出的文件名 的文件
const findFile = fileList.find((file) => {
return file.name.includes(`${otherFilePrefix}${fileType}_${qualify}`)
})
if (findFile) {
const regExp = new RegExp(
`(${otherFilePrefix}${fileType}_${qualify}_\\d{1,}\\.{0,}\\d{0,}).*?(\\.PHD)`
)
record[nameKeys[index]] = {
file: findFile,
fileName: findFile.name.replace(regExp, '$1$2'),
}
} else {
record[nameKeys[index]] = {
file: undefined,
fileName: `${otherFilePrefix}${fileType}.PHD`,
}
}
})
// 查找 QC 文件
let qcFileInfo = {
file: undefined,
fileName: `${sampleFilePrefix}Q.PHD`,
}
const qcFileList = fileList.filter((file) => file.name.includes('_Q_'))
for (const qcFile of qcFileList) {
if (qcFile.name.slice(0, 23) <= sampleFilePrefix) {
qcFileInfo = {
file: qcFile,
fileName: qcFile.name,
}
} else {
break
}
}
record.qcFileName = qcFileInfo
} else if (phdParser.fileType == 'C') {
const iter = await this.directoryHanlder.values()
const fileList = []
let result = await iter.next()
while (!result.done) {
const fileHandle = result.value
const file = await fileHandle.getFile()
fileList.push(file)
result = await iter.next()
}
const nameKeys = ['detFileName']
const fileTypes = ['D']
otherFilePrefixes.forEach((otherFilePrefix, index) => {
const fileType = fileTypes[index]
// 在所有文件中查找 名字含有 从sample文件解析出的文件名 的文件
const findFile = fileList.find((file) => {
return file.name.includes(`${otherFilePrefix}${fileType}_${qualify}`)
})
if (findFile) {
const regExp = new RegExp(
`(${otherFilePrefix}${fileType}_${qualify}_\\d{1,}\\.{0,}\\d{0,}).*?(\\.PHD)`
)
record[nameKeys[index]] = {
file: findFile,
fileName: findFile.name.replace(regExp, '$1$2'),
}
} else {
record[nameKeys[index]] = {
file: undefined,
fileName: `${otherFilePrefix}${fileType}.PHD`,
}
}
})
// 查找 QC 文件
let qcFileInfo = {
file: undefined,
fileName: `${sampleFilePrefix}Q.PHD`,
}
const qcFileList = fileList.filter((file) => file.name.includes('_Q_'))
for (const qcFile of qcFileList) {
if (qcFile.name.slice(0, 23) <= sampleFilePrefix) {
qcFileInfo = {
file: qcFile,
fileName: qcFile.name,
}
} else {
break
}
}
record.qcFileName = qcFileInfo
} else {
Object.assign(record, {
gasFileName: undefined,
detFileName: undefined,
qcFileName: undefined,
})
}
}
// 非sample
else {
record[column] = {
file,
fileName: file.name,
}
}
} catch (error) {
console.log(error)
}
} catch {}
},
/**
* 判断文件和列是否匹配
* @param {*} column
* @param {*} dataType
*/
fileNameAndColumnMatch(column, dataType) {
let currDataType = ''
switch (column) {
case 'sampleFileName':
return isSample(dataType)
case 'gasFileName':
currDataType = PHD_DATA_TYPE.GASBKPHD
break
case 'detFileName':
currDataType = PHD_DATA_TYPE.DETBKPHD
break
case 'qcFileName':
currDataType = PHD_DATA_TYPE.QCPHD
break
}
return currDataType == dataType
},
onSearchFileName() {
this.getSpectrumFile({ pageNo: 1, pageSize: 10 })
},
getSpectrumFile(params) {
this.loading_file = true
let params_arg = { ...params, name: `${this.searchName ? this.searchName + ',' : ''}${this.currFileType}` }
getAction('/spectrumFile/get', params_arg).then((res) => {
this.loading_file = false
if (res.success) {
res.result.records.forEach((item, index) => {
item.id = index
})
this.ipagination.total = res.result.total
this.ipagination.current = res.result.current
this.ipagination.pageSize = res.result.size
this.list_file = res.result.records
} else {
this.$message.warning('This operation fails. Contact your system administrator')
}
})
},
handlePageChange(page, pageSize) {
this.selectedRowKeys = []
this.selectedFiles = []
this.ipagination.current = page
this.ipagination.pageSize = pageSize
this.getSpectrumFile({
pageNo: page,
pageSize: pageSize,
})
},
handleSizeChange(current, size) {
this.ipagination.current = current
this.ipagination.pageSize = size
this.getSpectrumFile({
pageNo: current,
pageSize: size,
})
},
onSelectChange(selectedRowKeys, selectedRows) {
this.selectedRowKeys = selectedRowKeys
this.selectedFiles = selectedRows.map((item) => {
return item.name
})
},
saveFileName() {
this.visible_file = false
if (this.tableType === 'multiple') {
this.loading_list = true
let params = {
fileName: this.selectedFiles.join(','),
}
getAction('/spectrumAnalysis/getFilesBySampleFile', params).then((res) => {
this.loading_list = false
if (res.success) {
let idx = res.result.length
let staIdx = this.list.filter((item) => Object.keys(item).length > 4).length
if (staIdx < 10) {
this.list.splice(staIdx, idx, ...res.result)
} else {
this.list.push(...res.result)
}
} else {
this.$message.warning('This operation fails. Contact your system administrator')
}
})
} else {
let currFileName = this.selectionRows_edit[0].name
if (currFileName.includes(this.currFileType)) {
this.currRowData.gasFileName = currFileName
}
}
},
cancelFileModale() {
this.visible_file = false
this.list_file = []
},
beforeUpload(file, fileList) {
this.fileList = fileList
},
async handleUpload() {
this.uploading = true
this.fileNum += 1
if (this.fileNum == this.fileList.length) {
const file = await zipFile(this.fileList, 'test.zip')
const res = await this.uploadZipFile(file)
this.uploading = false
this.fileNum = 0
if (res.success) {
this.$message.success(res.message)
} else {
this.$message.warning(res.message)
}
}
},
// 上传zip文件
async uploadZipFile(file) {
const formData = new FormData()
formData.append('file', file)
const res = await postActionWithTimeOut('/spectrumFile/upload', formData, 0)
return res
},
handleReset() {
this.list = this.getInitialList()
},
async handleLoad() {
// 如果文件系统可用
if (this.canUseFilePicker) {
const propNames = ['sampleFileName', 'gasFileName', 'detFileName', 'qcFileName']
const propStatus = ['sampleFileStatus', 'gasFileStatus', 'detFileStatus', 'qcFileStatus']
const files = []
const allFiles = []
for (const item of this.list) {
if (item.fileType) {
let fileObj = {
files: [],
fileType: item.fileType,
}
propNames.forEach((propName, index) => {
const value = item[propName]
if (value && value.file) {
fileObj[propStatus[index]] = true
files.push(value.file)
fileObj.files.push(value.fileName)
} else {
fileObj[propStatus[index]] = false
}
})
allFiles.push(fileObj)
}
}
console.log('filesfiles', files)
if (!files.length) {
this.$message.warn('File is Empty ')
return
}
const zipedFiles = await zipFile(files, 'test.zip')
console.log('zipedFileszipedFiles', zipedFiles)
this.isUploadingZip = true
try {
const { success, message } = await this.uploadZipFile(zipedFiles)
if (success) {
let result = []
allFiles.forEach((el) => {
let obj = {}
if (el.fileType == 'B') {
obj.sampleSystemType = el.fileType
el.files.forEach((item) => {
if (item.includes('_S_')) {
obj.sampleFileName = item
}
if (item.includes('_G_')) {
obj.gasFileName = item
obj.gasFileStatus = el.gasFileStatus
}
if (item.includes('_D_')) {
obj.detFileName = item
obj.detFileStatus = el.detFileStatus
}
if (item.includes('_Q_')) {
obj.qcFileName = item
obj.qcFileStatus = el.qcFileStatus
}
})
} else if (el.fileType == 'C') {
obj.sampleSystemType = el.fileType
obj.gasFileName = ''
obj.qcFileName = ''
el.files.forEach((item) => {
if (item.includes('_S_')) {
obj.sampleFileName = item
}
if (item.includes('_D_')) {
obj.detFileName = item
obj.detFileStatus = el.detFileStatus
}
if (item.includes('_Q_')) {
obj.qcFileName = item
obj.qcFileStatus = el.qcFileStatus
}
})
} else {
el.files.forEach((item) => {
if (item.includes('_S_')) {
obj.sampleSystemType = el.fileType
obj.sampleFileName = item
obj.gasFileName = ''
obj.detFileName = ''
obj.qcFileName = ''
}
})
}
result.push(obj)
})
this.$emit('loadFormFile', result)
this.visible = false
this.isUploadingZip = false
// }
} else {
this.isUploadingZip = false
this.$message.error(message)
}
} catch (error) {
console.error(error)
this.isUploadingZip = false
}
} else {
this.visible = false
this.$emit('loadFormFile', cloneDeep(this.list))
}
},
handleCancel() {
this.visible = false
},
},
}
</script>
<style lang="less" scoped>
.status {
display: inline-block;
width: 25px;
height: 25px;
border-radius: 50%;
margin-top: 8px;
background-color: transparent;
}
.status_true {
background-color: #00e170;
}
.status_false {
background-color: red;
}
::v-deep {
@tableBorderColor: #000;
.ant-table-bordered .ant-table-thead > tr > th,
.ant-table-bordered .ant-table-tbody > tr > td {
border-right-color: @tableBorderColor;
}
.ant-table-thead > tr th {
border-bottom: 1px solid @tableBorderColor;
}
.ant-table-bordered .ant-table-body > table {
border-color: @tableBorderColor;
}
.ant-table-tbody tr td {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
.ant-pagination {
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
}
.ant-select {
.ant-select-arrow-icon {
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
&-open {
.ant-select-arrow-icon {
transform: rotate(180deg);
}
}
}
.ant-modal-title {
letter-spacing: 1px;
}
}
.item-label {
display: inline-block;
font-size: 16px;
font-family: ArialMT;
color: #ade6ee;
line-height: 32px;
height: 32px;
margin-right: 10px;
}
.operators {
width: 100%;
justify-content: center;
.ant-btn {
width: 92px;
}
}
.file-name {
height: 42px;
line-height: 42px;
}
.file-name-color {
color: red;
}
.file-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
height: 40px;
line-height: 40px;
}
/deep/.ant-table-tbody .ant-table-row td {
cursor: pointer;
}
.ant-input {
width: 380px;
}
/deep/.ant-table-bordered.ant-table-fixed-header .ant-table-header > table {
border: none;
}
</style>