diff --git a/src/utils/FilePicker.js b/src/utils/FilePicker.js new file mode 100644 index 0000000..08a6706 --- /dev/null +++ b/src/utils/FilePicker.js @@ -0,0 +1,55 @@ +/** + * 本地文件选择 + */ +export class FilePicker { + /** + * 接口是否可用 + * @returns { Boolean } + */ + static canUse() { + return !!(window.showDirectoryPicker && window.showOpenFilePicker) + } + + /** + * 选择一个目录 + * @returns { Promise } + */ + static chooseDirectory() { + if (!this.canUse()) { + throw new Error('Not Support showDirectoryPicker') + } + return window.showDirectoryPicker() + } + + /** + * 选择一个文件 + * @param { Boolean } multiple + * @param { { description?: string; accept?: { [key: string]: string[]; } } } types + * @returns { Promise } + */ + static chooseFile(multiple, types) { + if (!this.canUse()) { + throw new Error('Not Support showOpenFilePicker') + } + const pickerOpts = { + multiple, + types, + excludeAcceptAllOption: true + } + return window.showOpenFilePicker(pickerOpts) + } + + /** + * 判断一个文件是否在某个目录下 + * @param {FileSystemDirectoryHandle} directoryHandle + * @param {FileSystemFileHandle} fileHandle + */ + static async isFileInDirectory(directoryHandle, fileHandle) { + const relativePaths = await directoryHandle.resolve(fileHandle) + if (relativePaths === null || relativePaths.length > 1) { + return false + } else { + return true + } + } +} diff --git a/src/utils/file.js b/src/utils/file.js index 60c4ac9..88867ca 100644 --- a/src/utils/file.js +++ b/src/utils/file.js @@ -1,5 +1,6 @@ import { Modal } from 'ant-design-vue' import { saveAs } from 'file-saver' +import JSZip from 'jszip' /** * 弹窗填入文件名保存文件 @@ -31,3 +32,56 @@ export const showSaveFileModal = (data, ext) => { } }) } + +/** + * 读文件 + * @param {File} file + * @param { 'arrayBuffer' | 'text' | 'dataURL' | 'binaryString'} fileType + * @returns {Promise { + return new Promise((resolve, reject) => { + const fileReader = new FileReader() + const category = { + arrayBuffer: 'readAsArrayBuffer', + text: 'readAsText', + dataURL: 'readAsDataURL', + binaryString: 'readAsBinaryString' + } + fileReader[category[fileType]](file) + fileReader.onload = event => { + resolve(event.target.result) + } + fileReader.onerror = error => { + reject(error) + } + }) +} + +/** + * 压缩文件 + * @param {Array} fileList + * @param {string} zipName + * @returns + */ +export const zipFile = async (fileList, zipName) => { + const zip = new JSZip() + const promises = [] + + const readFileWithName = async file => { + const data = await readFile(file, 'arrayBuffer') + return { + fileName: file.name, + data + } + } + fileList.forEach(file => { + promises.push(readFileWithName(file)) + }) + const result = await Promise.all(promises) + result.forEach(res => { + zip.file(res.fileName, res.data) + }) + const content = await zip.generateAsync({ type: 'blob' }) + return new File([content], zipName, { type: content.type }) +} diff --git a/src/utils/phdHelper.js b/src/utils/phdHelper.js new file mode 100644 index 0000000..d44d9c9 --- /dev/null +++ b/src/utils/phdHelper.js @@ -0,0 +1,182 @@ +/** + * PHD 类型 + */ +export const PHD_DATA_TYPE = { + QCPHD: 'QCPHD', + DETBKPHD: 'DETBKPHD', + SAMPLEPHD: 'SAMPLEPHD', + GASBKPHD: 'GASBKPHD' +} + +/** + * 判断是不是sample + * @param {*} dataType + * @returns + */ +export const isSample = dataType => { + return ['SAMPLEPHD', 'SPHDP', 'SPHDF'].includes(dataType) +} + +export class PHDParser { + /** + * 根据Block解析出的结果集 + */ + blocks = { + baseInfo: [] + } + + /** + * 数据类型 + */ + dataType = '' + + /** + * 类型 B G 等 + */ + fileType = '' + + /** + * 质量 FULL 等 + */ + qualify = '' + + /** + * 生存时间 + */ + + liveTime = '' + + /** + * sample 谱的文件名 + */ + sampleFilePrefix = '' + + /** + * 其他文件名 + */ + otherFilePrefixes = [] + + /** + * 该文件是不是sample + */ + isSample = false + + /** + * 构造函数 + * @param {string} text + */ + constructor(text) { + this.splitByBlock(text) + this.dataType = this.getBaseInfoByTag('DATA_TYPE')[0] + this.isSample = isSample(this.dataType) + + const headerInfo = this.getBlockInfo('Header') + const headerInfoLine1 = this.splitLineText(headerInfo[0]) + this.fileType = headerInfoLine1[2] + this.qualify = headerInfoLine1[4] + + const liveTime = parseFloat(this.getBlockStr('Acquisition', 0, 3)).toFixed(1) + this.liveTime = liveTime.indexOf('.0') == -1 ? liveTime : liveTime.slice(0, -2) + + // 如果解析的是sample 文件,则解析相关联的文件 + if (this.isSample) { + const filePrefixes = this.getFilePrefixes(headerInfo[2]) + this.sampleFilePrefix = filePrefixes.splice(0, 1)[0] + this.otherFilePrefixes = filePrefixes + } + } + + /** + * 根据块类型分割 + * @param {string} text + */ + splitByBlock(text) { + const lines = (text = text.replace(/\r{0,1}\n/g, '\n').split('\n')) + let blockType = 'baseInfo' + for (const line of lines) { + // 如果以#开头 + if (line.startsWith('#')) { + blockType = line.slice(1) + if (blockType.startsWith('Header')) { + blockType = 'Header' + } + this.blocks[blockType] = [] + continue + } + this.blocks[blockType].push(line.trim()) + } + } + + /** + * 根据块名拿到块内容 + * @param {string} blockName + * @returns {Array} + */ + getBlockInfo(blockName) { + return this.blocks[blockName] + } + + /** + * 在baseInfo中根据tag查找值 + * @param {*} tag + * @returns {Array} + */ + getBaseInfoByTag(tag) { + const baseInfo = this.getBlockInfo('baseInfo') + const map = new Map() + baseInfo.forEach(line => { + if (line.startsWith(tag)) { + map.set(tag, this.getOnymousData(line)) + } + }) + + return map.get(tag) + } + + /** + * 根据行号和位置在block中查找字符 + * @param {string} blockName + * @param {number} lineNum + * @param {number} index + * @returns {string} + */ + getBlockStr(blockName, lineNum, index) { + const blockInfo = this.getBlockInfo(blockName) + const lineText = blockInfo[lineNum] + const splited = this.splitLineText(lineText) + return splited[index] + } + + /** + * 获取 具名 行的数据 + * @param {string} text + * @example DATA_TYPE SAMPLEPHD 返回['SAMPLEPHD'] + * @returns {string[]} + */ + getOnymousData(text) { + return text.split(' ').slice(1) + } + + /** + * 将一行中的文本按空格切割 + * @param {string} text + */ + splitLineText(text) { + return text.replace(/\s+/g, ',').split(',') + } + + /** + * 获取全部文件名 + * @param {string} text + */ + getFilePrefixes(text) { + const unHandledfilePrefixes = this.splitLineText(text) + const filePrefixes = unHandledfilePrefixes + .filter(filePrefix => filePrefix) + .map(filePrefix => { + filePrefix = filePrefix.replace(/(\d{4})\/(\d{2})\/(\d{2})-(\d{2}):(\d{2})(:\d{2}\.\d)?/, '$1$2$3_$4$5') + return filePrefix + '_' + }) + return filePrefixes + } +} diff --git a/src/views/spectrumAnalysis/components/Modals/LoadFromDBModal.vue b/src/views/spectrumAnalysis/components/Modals/LoadFromDBModal.vue index ed97764..8465ffd 100644 --- a/src/views/spectrumAnalysis/components/Modals/LoadFromDBModal.vue +++ b/src/views/spectrumAnalysis/components/Modals/LoadFromDBModal.vue @@ -197,7 +197,7 @@ export default { */ async handleLoad() { if (!this.selectedRowKeys.length) { - this.$message.warn('Please Select Databases To Load') + this.$message.warn('Please Select Sample To Load') return } this.selectedRowKeys = [] diff --git a/src/views/spectrumAnalysis/components/Modals/LoadFromFileModal.vue b/src/views/spectrumAnalysis/components/Modals/LoadFromFileModal.vue index 8221959..d4a4e3f 100644 --- a/src/views/spectrumAnalysis/components/Modals/LoadFromFileModal.vue +++ b/src/views/spectrumAnalysis/components/Modals/LoadFromFileModal.vue @@ -1,7 +1,68 @@ @@ -61,6 +122,7 @@ @@ -140,10 +202,12 @@