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

824 lines
24 KiB
Vue
Raw Normal View History

<template>
2023-08-25 18:38:35 +08:00
<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> -->
2023-08-25 18:38:35 +08:00
</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>
2023-08-25 18:38:35 +08:00
</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>
2023-08-25 18:38:35 +08:00
</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>
2023-08-25 18:38:35 +08:00
</template>
<template slot="status" slot-scope="text, record">
<span
:class="[
(record.detFileStatus && record.gasFileStatus && record.qcFileStatus) ||
(record.sampleFileName && !record.gasFileName && !record.detFileName && !record.qcFileName)
? 'status_true'
: 'status_false',
'status',
]"
></span>
2023-08-25 18:38:35 +08:00
</template>
</a-table>
2023-08-25 18:38:35 +08:00
<!-- 底部按钮 -->
<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>
2023-08-25 18:38:35 +08:00
<a-button type="primary" @click="handleReset">Reset</a-button>
<a-button :loading="isUploadingZip" type="primary" @click="handleLoad">Load</a-button>
2023-08-25 18:38:35 +08:00
<a-button type="primary" @click="handleCancel">Cancel</a-button>
</a-space>
</template>
2023-08-25 18:38:35 +08:00
<!-- 底部按钮结束 -->
</custom-modal>
<a-modal v-model="visible_file" :width="1200" title="File List" @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>
2023-08-25 18:38:35 +08:00
</div>
</template>
<script>
import { getAction, postAction } 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'
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',
},
},
]
2023-08-25 18:38:35 +08:00
const columns_file = [
{
title: 'Name',
dataIndex: 'name',
width: '45%',
2023-08-25 18:38:35 +08:00
align: 'left',
ellipsis: true,
},
{
2023-08-25 18:38:35 +08:00
title: 'UpdateDate',
dataIndex: 'updateDate',
align: 'left',
},
{
2023-08-25 18:38:35 +08:00
title: 'Size',
dataIndex: 'size',
align: 'left',
2023-08-25 18:38:35 +08:00
},
]
const canUseFilePicker = FilePicker.canUse()
export default {
mixins: [ModalMixin],
props: {
value: {
type: Boolean,
},
},
data() {
this.columns = columns
return {
2023-08-25 18:38:35 +08:00
visible_file: false,
list_file: [],
columns_file,
loading_file: false,
loading_list: false,
isUploadingZip: false,
list: [],
ipagination: {
2023-08-25 18:38:35 +08:00
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,
2023-08-25 18:38:35 +08:00
},
selectedRowKeys: [],
selectedFiles: [],
2023-08-25 18:38:35 +08:00
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 = []
2023-08-25 18:38:35 +08:00
this.visible_file = true
this.tableType = str === '_S_' ? 'multiple' : 'single'
this.getSpectrumFile({ pageNo: 1, pageSize: 10 })
2023-08-25 18:38:35 +08:00
},
// 用新的文件操作接口
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 {
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 })
},
2023-08-25 18:38:35 +08:00
getSpectrumFile(params) {
this.loading_file = true
let params_arg = { ...params, name: `${this.searchName ? this.searchName + ',' : ''}${this.currFileType}` }
getAction('/spectrumFile/get', params_arg).then((res) => {
2023-08-25 18:38:35 +08:00
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
2023-08-25 18:38:35 +08:00
this.list_file = res.result.records
} else {
this.$message.warning('This operation fails. Contact your system administrator')
2023-08-25 18:38:35 +08:00
}
})
},
handlePageChange(page, pageSize) {
this.selectedRowKeys = []
this.selectedFiles = []
2023-08-25 18:38:35 +08:00
this.ipagination.current = page
this.ipagination.pageSize = pageSize
this.getSpectrumFile({
pageNo: page,
pageSize: pageSize,
2023-08-25 18:38:35 +08:00
})
},
handleSizeChange(current, size) {
this.ipagination.current = current
this.ipagination.pageSize = size
this.getSpectrumFile({
pageNo: current,
pageSize: size,
2023-08-25 18:38:35 +08:00
})
},
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
}
}
2023-08-25 18:38:35 +08:00
},
cancelFileModale() {
this.visible_file = false
this.list_file = []
},
beforeUpload(file, fileList) {
2023-08-25 18:38:35 +08:00
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)
}
}
},
2023-08-25 18:38:35 +08:00
// 上传zip文件
async uploadZipFile(file) {
const formData = new FormData()
formData.append('file', file)
const res = await postAction('/spectrumFile/upload', formData)
return res
2023-08-25 18:38:35 +08:00
},
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)
}
}
if (!files.length) {
this.$message.warn('File is Empty ')
return
}
const zipedFiles = await zipFile(files, 'test.zip')
this.isUploadingZip = true
try {
const { success, message } = await this.uploadZipFile(zipedFiles)
if (success) {
let result = []
2023-10-19 19:32:40 +08:00
console.log('allFiles', allFiles)
allFiles.forEach((el) => {
let obj = {}
if (el.fileType == 'B') {
obj.sampleSystemType = el.fileType
el.files.forEach((item) => {
2023-10-19 19:32:40 +08:00
if (item.includes('_S_')) {
obj.sampleFileName = item
}
2023-10-19 19:32:40 +08:00
if (item.includes('_G_')) {
obj.gasFileName = item
obj.gasFileStatus = el.gasFileStatus
}
2023-10-19 19:32:40 +08:00
if (item.includes('_D_')) {
obj.detFileName = item
obj.detFileStatus = el.detFileStatus
}
2023-10-19 19:32:40 +08:00
if (item.includes('_Q_')) {
obj.qcFileName = item
obj.qcFileStatus = el.qcFileStatus
}
})
} else {
el.files.forEach((item) => {
2023-10-19 19:32:40 +08:00
if (item.includes('_S_')) {
obj.sampleSystemType = el.fileType
obj.sampleFileName = item
obj.gasFileName = ''
obj.detFileName = ''
obj.qcFileName = ''
}
})
}
result.push(obj)
})
2023-10-19 19:32:40 +08:00
console.log(result)
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', 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 {
2023-08-25 18:38:35 +08:00
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
2023-08-25 18:38:35 +08:00
}
.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 {
2023-08-25 18:38:35 +08:00
letter-spacing: 1px;
}
}
.item-label {
2023-08-25 18:38:35 +08:00
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>