feat: upload done.

This commit is contained in:
chiayin
2023-12-29 16:05:27 +08:00
parent cd2ab42125
commit 9ef441ee83
8 changed files with 384 additions and 207 deletions

View File

@@ -1,86 +1,255 @@
<template>
<section class="h-screen-main w-full px-4 flex flex-col justify-between items-start">
<!-- Upload Content -->
<div class="w-full">
<div class="w-full h-[calc(100%_-_64px)]">
<!-- File name -->
<p class="font-bold text-base leading-[48px] border-b border-neutral-300">File Name(點擊可以改名字)</p>
<p id="uploadFileName" class="font-bold text-base leading-[48px] border-b border-neutral-300 cursor-pointer focus-visible:outline-primary/50 focus-visible:outline-0 " contentEditable="true">{{ uploadFileName }}<span class="material-symbols-outlined align-text-bottom text-lg" contentEditable="false">stylus</span></p>
<!-- Upload notification -->
<div class="flex justify-start items-center space-x-2 ml-2 py-2">
<span class="material-symbols-outlined text-neutral-700" v-tooltip.right="tooltipUpload">info</span>
<span class="material-symbols-outlined text-neutral-700 cursor-pointer" v-tooltip.right="tooltipUpload">info</span>
<span class="w-px h-7 bg-neutral-300"></span>
<div class="flex items-center">
<span class="material-symbols-outlined text-primary">notifications</span>
<span class="material-symbols-outlined material-fill text-danger">warning</span>
</div>
<!-- Upload text -->
<div class="flex justify-start items-center">
<p class="text-primary text-sm">
Please verify the label for each column before uploading.
</p>
<p class="text-danger text-sm">
Need to select [A], [B], [C].
</p>
<div class=" space-y-1">
<p class="text-danger text-sm">
[Case ID] has been assigned.
</p>
<p class="text-danger text-sm">
[Case ID], [Activity] have been assigned.
<div>
<div v-if="isInform" class="flex justify-start items-center space-x-2 duration-700">
<span class="material-symbols-outlined text-primary">notifications</span>
<p class="text-primary text-sm">
Please verify the label for each column before uploading.
</p>
</div>
<div v-else class="flex justify-start items-center space-x-2 duration-700">
<span class="material-symbols-outlined material-fill text-danger">warning</span>
<p class="text-danger text-sm">
Need to select
<span v-for="(item, index) in informData" :key="index">[ {{ item }} ]<span v-if="index !== informData.length - 1">, </span></span>.
</p>
<div v-if="repeatedData.length !== 0" class="duration-700">
<p v-if="repeatedData.length === 1" class="text-danger text-sm">
[ {{repeatedData[0]}} ] has been assigned.
</p>
<p v-else class="text-danger text-sm">
<span v-for="(item, index) in repeatedData" :key="index">[ {{ item }} ]<span v-if="index !== repeatedData.length - 1">, </span></span>
have been assigned.
</p>
</div>
</div>
</div>
</div>
</div>
<!-- Upload table -->
<div class="overflow-y-auto overflow-x-auto scrollbar max-h-[calc(100%_-_97px)]">
<table class="text-sm w-full table-fixed border-separate border-spacing-0">
<thead class="sticky top-0 bg-neutral-10">
<tr>
<td v-for="(item, index) in uploadDetail?.columns" :key="index" class="border border-neutral-500 p-2">{{ item }}</td>
</tr>
<tr>
<td v-for="(item, index) in uploadDetail?.columns" :key="index" class="px-2 py-1 bg-neutral-300 border border-neutral-500">
<Dropdown
v-model="selectedColumns[index]"
:options="columnType"
optionLabel="name"
placeholder="Not Assigned"
class="w-full !border-neutral-500"
:data-type="item"
:inputId="index.toString()"
:inputClass="selectedColumns[index]?.color"
inputClass="!text-sm">
<template #option="slotProps">
<div :class="slotProps.option.color" class="text-sm">
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</Dropdown>
</td>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in uploadDetail?.data" :key="index">
<td v-for="(itemDetail, key) in item" :key="key" class="border border-neutral-500 p-2 truncate break-keep">{{ itemDetail }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Upload button -->
<div class="w-full text-right space-x-4 px-8 py-4">
<button type="button" class="btn btn-sm btn-neutral" @click="reset">Cancel</button>
<button type="button" class="btn btn-sm" @click="submit" :disabled="isDisabled" :class="isDisabled ? 'btn-disable' : 'btn-neutral'">Upload</button>
<button type="button" class="btn btn-sm btn-neutral" @click="cancel">Cancel</button>
<button type="button" class="btn btn-sm btn-neutral" @click="reset">Reset</button>
<button type="button" class="btn btn-sm" @click="submit" :disabled="isDisabled" :class="isDisabled ? 'btn-disable' : 'btn-neutral'">Upload</button>
</div>
</section>
</template>
<script>
import { storeToRefs } from 'pinia';
import LoadingStore from '@/stores/loading.js';
import FilesStore from '@/stores/files.js';
import { uploadFailed, uploadSuccess, uploadConfirm } from '@/module/alertModal.js'
export default {
setup() {
const loadingStore = LoadingStore();
const filesStore = FilesStore();
const { isLoading } = storeToRefs(loadingStore);
const { uploadDetail, uploadId, uploadFileName } = storeToRefs(filesStore);
return { isLoading }
return { isLoading, filesStore, uploadDetail, uploadId, uploadFileName }
},
data() {
return {
isDisabled: true,
tooltipUpload: {
value: `1. Case ID: A unique identifier for each case.
2. Activity: A process step executed by either a system (automated) or humans (manual).
3. Activity Instance ID: A unique identifier for a single occurrence of an activity.
4. Timestamp: The time of occurrence of a particular event, such as the start or end of an activity.
5. Status: Activity status, such as Start or Complete.
6. Attribute: A property that can be associated with a case to provide additional information about that case.
7. Resource: A resource refers to any entity that is required to carry out a business process. This can include people, equipment, software, or any other type of asset.`,
6. Attribute: A property that can be associated with a case to provide additional information about that case.`,
// 7. Resource: A resource refers to any entity that is required to carry out a business process. This can include people, equipment, software, or any other type of asset.
class: '!max-w-[400px] !text-[10px]',
autoHide: false,
}
},
columnType: [
{ name: 'Case ID*', code: 'case_id', color: '!text-secondary', value: '' },
{ name: 'Timestamp*', code: 'timestamp', color: '!text-secondary', value: '' },
{ name: 'Status*', code: 'status', color: '!text-secondary', value: '' },
{ name: 'Activity*', code: 'name', color: '!text-secondary', value: '' },
{ name: 'Activity Instance ID*', code: 'instance', color: '!text-secondary', value: '' },
{ name: 'Case Attribute', code: 'case_attributes', color: '!text-primary', value: '' },
// { name: 'Resource', code: '', color: '', value: '' }, // 現階段沒有,未來可能有
{ name: 'Not Assigned', code: '', color: '!text-neutral-700', value: '' },
],
selectedColumns: [],
isInform: true, // true: 藍字提示; false: 紅字提示
informData: [], // 紅字提示,尚未選擇的 type
repeatedData: [], // 紅字提示,重複選擇的 type
baseTypeData: ['Case ID*', 'Timestamp*', 'Status*', 'Activity*', 'Activity Instance ID*'],
};
},
computed: {
isDisabled: function() {
// 1. 長度一樣,強制每一個都要選
// 2. 不為 null undefind
let hasValue = !this.selectedColumns.includes(undefined);
let result = !(this.selectedColumns.length === this.uploadDetail?.columns.length && this.informData.length === 0 && this.repeatedData.length === 0 && hasValue) ? true : false;
return result
},
},
watch: {
selectedColumns: {
deep: true, // 監聽陣列內部的變化
handler(newVal, oldVal) {
this.updateValidationData(newVal);
},
}
},
methods: {
uploadFailed,
uploadSuccess,
uploadConfirm,
/**
* 驗證,根據新的 selectedColumns 更新 isInform、informData 和 repeatedData
* @param {Array} data
*/
updateValidationData(data) {
const nameOccurrences = {};
let selectedData = [] // 已經選擇的 data
this.informData = []; // 尚未選擇的 data
this.repeatedData = []; // 重複選擇的 data
data.forEach(item => {
const { name, code } = item;
if(nameOccurrences[name]) {
// 'Not Assigned'、'Case Attribute' 不列入驗證
if(!code || code === 'case_attributes') return;
nameOccurrences[name]++;
this.repeatedData.push(name);
}else {
nameOccurrences[name] = 1;
selectedData.push(name);
this.informData = this.baseTypeData.filter(item => !selectedData.includes(item));
}
});
this.isInform = (this.informData.length === 0 && this.repeatedData.length === 0) ? true : false;
},
/**
* Reset Button
*/
reset() {
// 路徑不列入歷史紀錄
this.selectedColumns = [];
},
/**
* Cancel Button
*/
reset() {},
cancel() {
// 路徑不列入歷史紀錄
this.$router.push({name: 'Files', replace: true});
},
/**
* Upload Button
*/
submit() {},
async submit() {
// Post API Data
let fetchData = {
timestamp: '',
case_id: '',
name: '',
instance: '',
status: '',
case_attributes: []
};
// 給值
let haveValueData = this.selectedColumns.map((column, i) => {
if (column && this.uploadDetail.columns[i]) {
return {
name: column.name,
code: column.code,
color: column.color,
value: this.uploadDetail.columns[i]
}
}
});
// 取得欲更改的檔名
this.uploadFileName = document.querySelector('#uploadFileName').firstChild.textContent;
// 設定第二階段上傳的 data
haveValueData.forEach(column => {
switch (column.code) {
case 'timestamp':
fetchData.timestamp = column.value;
break;
case 'case_id':
fetchData.case_id = column.value;
break;
case 'name':
fetchData.name = column.value;
break;
case 'instance':
fetchData.instance = column.value;
break;
case 'status':
fetchData.status = column.value;
break;
case 'case_attributes':
fetchData.case_attributes.push(column.value);
break;
default:
break;
}
});
this.uploadConfirm(fetchData);
},
},
mounted() {
// 要有 uploadID 才能進來
this.isInform = true; // 初始為藍字提示
this.filesStore.getUploadDetail();
this.isLoading = false;
},
beforeUnmount() {
// 離開頁面要刪 uploadID
this.uploadId = null;
this.uploadFileName = null;
}
}
// beforeRouteUpdate(){}
</script>
<style scoped>
</style>