Skip to content

Commit

Permalink
修复csv导出功能
Browse files Browse the repository at this point in the history
  • Loading branch information
putianyi889 committed Nov 23, 2024
1 parent 8e290ab commit 46ec58d
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 78 deletions.
1 change: 0 additions & 1 deletion back_end/saolei/userprofile/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ def user_register(request):
def check_collision(request):
user = None
if request.GET.get('username'):
print(request.GET.get('username'))
user = UserProfile.objects.filter(username=request.GET.get('username')).first()
elif request.GET.get('email'):
user = UserProfile.objects.filter(email=request.GET.get('email')).first()
Expand Down
136 changes: 136 additions & 0 deletions front_end/src/components/widgets/UserArbiterCSV.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<template>
<el-button :disabled="id==0" @click="clickExportJSON">
{{ $t('profile.exportJSON') }}&nbsp;
<el-tooltip :content="$t('profile.exportJSONTooltip')" raw-content>
<el-icon v-if="local.tooltip_show">
<QuestionFilled />
</el-icon>
</el-tooltip>
</el-button>
<el-button @click="clickExportCSV" :disabled="id==0">
{{ $t('profile.exportArbiterCSV') }}&nbsp;
<el-tooltip :content="$t('profile.exportArbiterCSVTooltip')" raw-content>
<el-icon v-if="local.tooltip_show">
<QuestionFilled />
</el-icon>
</el-tooltip>
</el-button>
</template>

<script setup lang="ts">
import { local } from '@/store';
import useCurrentInstance from '@/utils/common/useCurrentInstance';
import { ref, watch } from 'vue';
import { httpErrorNotification } from '../Notifications';
const { proxy } = useCurrentInstance();
const data = ref([] as any[]);
const progress = ref(0);
const status = ref("");
const text = ref("")
const prop = defineProps({
id: {
type: Number,
default: 0,
},
})
watch(prop, ()=>{data.value=[]});
async function fetchData(id: number) {
await proxy.$axios.get('video/query_by_id',
{
params: {
id: id,
}
}
).then(function(response){
data.value = response.data
}).catch(httpErrorNotification)
}
function generateArbiterCSV(data: any) {
if (!data) return "";
let csvdata = ['Day,Month,Year,Hour,Min,Sec,mode,Time,BBBV,BBBVs,style,cell0,cell1,cell2,cell3,cell4,cell5,cell6,cell7,cell8,Lcl,Rcl,Dcl,Leff,Reff,Deff,Openings,Islands,Path,GZiNi,HZiNi']
for (let v of data) {
if (v.mode != 'std' && v.mode != 'nf') continue;
let date = new Date(v.upload_time);
let row: any[] = [date.getUTCDate(), date.getUTCMonth() + 1, date.getUTCFullYear(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()];
switch (v.level) {
case 'e': row.push(3); break;
case 'i': row.push(2); break;
case 'b': row.push(1); break;
default: console.error('未知级别');
}
row.push((v.timems / 1000).toFixed(2));
row.push(v.bv);
row.push(v.bvs.toFixed(2));
if (v.video__flag == 0) row.push('NF');
else row.push('Flag');
row.push(v.video__cell0, v.video__cell1, v.video__cell2, v.video__cell3, v.video__cell4, v.video__cell5, v.video__cell6, v.video__cell7, v.video__cell8)
row.push(v.video__left, v.video__right, v.video__double, 0, 0, 0)
row.push(v.video__op, v.video__isl)
row.push(Math.round(v.video__path))
row.push(0, 0)
csvdata.push(row.join())
}
return csvdata.join('\n');
}
// Credit: ChatGPT
function downloadCSV(csv: string) {
if (csv==="") return;
// Create a Blob from the CSV data
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
// Create a temporary anchor element
const a = document.createElement('a');
a.href = url;
a.download = 'stats_csv.csv'; // Set the file name
// Append the anchor to the body
document.body.appendChild(a);
a.click(); // Trigger the download
document.body.removeChild(a); // Remove the anchor after download
// Release the object URL
URL.revokeObjectURL(url);
}
function downloadJSON(json: string) {
if (json==="") return;
// Create a Blob from the CSV data
const blob = new Blob([json], { type: 'text/json' });
const url = URL.createObjectURL(blob);
// Create a temporary anchor element
const a = document.createElement('a');
a.href = url;
a.download = 'stats_json.json'; // Set the file name
// Append the anchor to the body
document.body.appendChild(a);
a.click(); // Trigger the download
document.body.removeChild(a); // Remove the anchor after download
// Release the object URL
URL.revokeObjectURL(url);
}
async function clickExportCSV() {
if (data.value.length===0) await fetchData(prop.id);
if (data.value.length===0) return;
downloadCSV(generateArbiterCSV(data.value));
}
async function clickExportJSON() {
if (data.value.length===0) await fetchData(prop.id);
if (data.value.length===0) return;
downloadJSON(JSON.stringify(data.value))
}
</script>
6 changes: 4 additions & 2 deletions front_end/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,10 @@ export default {
modeRecord: ' mode record: '
},
videos: 'All videos',
exportArbiterCSV: 'Export as stats_csv.csv',
exportArbiterCSVTooltip: 'Compatible with the datasheet generated by Minesweeper Arbiter.<br/> Not supporting Leff, Reff, Deff, GZiNi and HZiNi at present.',
exportJSON: 'Export as JSON',
exportJSONTooltip: 'Raw data fetched from the server.',
exportArbiterCSV: 'Export as CSV',
exportArbiterCSVTooltip: 'Compatible with <span style="font-family: \'Courier New\', Courier, monospace;">stats_csv.csv</span> generated by Minesweeper Arbiter.<br/> Not supporting Leff, Reff, Deff, GZiNi and HZiNi at present.',
upload: {
title: 'Video Upload',
dragOrClick: `Drag files here or <em>click here to select</em>`,
Expand Down
6 changes: 4 additions & 2 deletions front_end/src/i18n/locales/zh-cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,10 @@ export default {
modeRecord: '模式纪录:'
},
videos: '全部录像',
exportArbiterCSV: '导出stats_csv.csv',
exportArbiterCSVTooltip: '兼容 Minesweeper Arbiter 生成的数据表。<br/> 目前不支持 Leff, Reff, Deff, GZiNi, HZiNi。',
exportJSON: '导出JSON',
exportJSONTooltip: '从服务器获取的源数据',
exportArbiterCSV: '导出CSV',
exportArbiterCSVTooltip: '兼容 Minesweeper Arbiter 生成的 <span style="font-family: \'Courier New\', Courier, monospace;">stats_csv.csv</span>。<br/> 目前不支持 Leff, Reff, Deff, GZiNi, HZiNi。',
upload: {
title: '上传录像',
dragOrClick: `将录像拉到此处或 <em>点击此处选择</em>`,
Expand Down
76 changes: 3 additions & 73 deletions front_end/src/views/PlayerVideosView.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
<template>
<el-button @click="downloadCSV(generateArbiterCSV(store.player.id))" v-if="false && !store.player.loading">
{{ $t('profile.exportArbiterCSV') }}&nbsp;
<el-tooltip :content="$t('profile.exportArbiterCSVTooltip')" raw-content>
<el-icon v-if="local.tooltip_show">
<QuestionFilled />
</el-icon>
</el-tooltip>
</el-button>
<UserArbiterCSV :id="store.player.id" />
<el-card class="box-card" body-style="" style="max-height: 800px; overflow: auto; margin-top:5px">
<el-skeleton animated v-show="store.player.loading" :rows="8" />
<VideoList :videos="store.player.videos" :need_player_name="false" reverse></VideoList>
Expand All @@ -15,71 +8,8 @@

<script lang="ts" setup>
// 个人主页的个人所有录像部分
import { onMounted, ref, Ref } from 'vue'
import useCurrentInstance from "@/utils/common/useCurrentInstance";
const { proxy } = useCurrentInstance();
// import { genFileId, ElMessage } from 'element-plus'
import VideoList from '@/components/VideoList.vue';
// import { fa } from 'element-plus/es/locale';
import { local, store } from '../store'
function generateArbiterCSV(data: any) {
let csvdata = ['Day,Month,Year,Hour,Min,Sec,mode,Time,BBBV,BBBVs,style,cell0,cell1,cell2,cell3,cell4,cell5,cell6,cell7,cell8,Lcl,Rcl,Dcl,Leff,Reff,Deff,Openings,Islands,Path,GZiNi,HZiNi']
for (let v of data) {
if (v.mode != 'std' && v.mode != 'nf') continue;
let date = new Date(v.upload_time);
let row: any[] = [date.getUTCDate(), date.getUTCMonth() + 1, date.getUTCFullYear(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()];
switch (v.level) {
case 'e': row.push(3); break;
case 'i': row.push(2); break;
case 'b': row.push(1); break;
default: console.error('未知级别');
}
row.push((v.timems / 1000).toFixed(2));
row.push(v.bv);
row.push(v.bvs.toFixed(2));
if (v.video__flag == 0) row.push('NF');
else row.push('Flag');
row.push(v.video__cell0, v.video__cell1, v.video__cell2, v.video__cell3, v.video__cell4, v.video__cell5, v.video__cell6, v.video__cell7, v.video__cell8)
row.push(v.video__left, v.video__right, v.video__double, 0, 0, 0)
row.push(v.video__op, v.video__isl)
row.push(Math.round(v.video__path))
row.push(0, 0)
csvdata.push(row.join())
}
return csvdata.join('\n');
}
// Credit: ChatGPT
function downloadCSV(csv: string) {
// Create a Blob from the CSV data
const blob = new Blob([csv], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
// Create a temporary anchor element
const a = document.createElement('a');
a.href = url;
a.download = 'stats_csv.csv'; // Set the file name
// Append the anchor to the body
document.body.appendChild(a);
a.click(); // Trigger the download
document.body.removeChild(a); // Remove the anchor after download
// Release the object URL
URL.revokeObjectURL(url);
}
import { store } from '../store'
import UserArbiterCSV from '@/components/widgets/UserArbiterCSV.vue';
</script>


<style>
.avatar-uploader {
margin: auto;
text-align: center;
margin-top: 30px;
}
</style>

0 comments on commit 46ec58d

Please sign in to comment.