290 lines
8.4 KiB
Vue
290 lines
8.4 KiB
Vue
<template>
|
||
<h3>
|
||
数据管理
|
||
</h3>
|
||
<hr>
|
||
<div class="fade-in">
|
||
<div class="my-2">
|
||
<button @click="reload" class="btn btn-secondary">
|
||
<font-awesome-icon icon="refresh" class="me-1"/>刷新
|
||
</button>
|
||
<button class="btn btn-success ms-2" @click="$router.push('/estor/import')">从USB导入</button>
|
||
<button class="btn btn-info ms-2" @click="$router.push('/estor/config')">配置</button>
|
||
</div>
|
||
<div class="input-group my-4">
|
||
<input class="form-control" type="text" v-model="search_query" />
|
||
<button class="btn btn-secondary" @click="search">搜索</button>
|
||
</div>
|
||
<div v-if="loading" class="alert alert-info">
|
||
正在加载...
|
||
<CSpinner class="d-block my-3"/>
|
||
</div>
|
||
<div v-else-if="!entries.length" class="alert alert-info">
|
||
没有数据
|
||
</div>
|
||
<table v-else class="table">
|
||
<thead>
|
||
<tr>
|
||
<th>
|
||
批次名称
|
||
</th>
|
||
<th>导入时间</th>
|
||
<th>状态</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-for="e, i in entries" :key="i">
|
||
<td>
|
||
<a href="/estor/files?">{{ e.name }}</a>
|
||
</td>
|
||
<td>{{ show_time(e) }}</td>
|
||
<td>{{ show_status(e) }}</td>
|
||
<td>
|
||
<CDropdown>
|
||
<CDropdownToggle size="sm" color="secondary">操作</CDropdownToggle>
|
||
<CDropdownMenu>
|
||
<CDropdownItem href="javascript:void(0)" @click="qr_std_upload(e)">
|
||
备案到云
|
||
</CDropdownItem>
|
||
<CDropdownItem href="javascript:void(0)" @click="show_image_convert(e)">
|
||
图像格式转换
|
||
</CDropdownItem>
|
||
<CDropdownItem class="text-danger" href="javascript:void(0)" @click="delete_batch(e)">
|
||
删除
|
||
</CDropdownItem>
|
||
</CDropdownMenu>
|
||
</CDropdown>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<Modal title="图片转换" ref="image_convert_modal" @close="image_convert">
|
||
<div class="mb-3">
|
||
数据批次:
|
||
<strong>
|
||
{{ image_convert_target.name }}
|
||
</strong>
|
||
</div>
|
||
<div>
|
||
任务配置:
|
||
</div>
|
||
<div class="convert-config-section">
|
||
转换文件格式
|
||
<div>
|
||
<select v-model="image_convert_format" class="form-control">
|
||
<option value="jpeg">JPEG</option>
|
||
<option value="png">PNG</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="convert-config-section">
|
||
分辨率
|
||
<div>
|
||
长边限制(像素)
|
||
<input class="d-block form-control" type="text" v-model="image_convert_size"/>
|
||
</div>
|
||
</div>
|
||
<div class="convert-config-section">
|
||
输出图像质量
|
||
<select v-model="image_convert_quality" class="d-block form-control">
|
||
<option value="high">高</option>
|
||
<option value="middle">中</option>
|
||
<option value="low">低</option>
|
||
</select>
|
||
<div>
|
||
<input type="checkbox" id="icg" v-model="image_convert_grayscale" />
|
||
<label for="icg">灰度化</label>
|
||
</div>
|
||
</div>
|
||
</Modal>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: 'EstorBatches',
|
||
props: [],
|
||
components: {
|
||
},
|
||
data: function () {
|
||
return {
|
||
loading: true,
|
||
search_query: '',
|
||
entries: [],
|
||
image_convert_target: null,
|
||
image_convert_format: "jpeg",
|
||
image_convert_size_enabled: false,
|
||
image_convert_size: 1920,
|
||
image_convert_quality: 'high',
|
||
image_convert_grayscale: false,
|
||
};
|
||
},
|
||
computed: {
|
||
},
|
||
methods: {
|
||
search() {
|
||
this.$router.push("/estor/search?q=" + this.search_query);
|
||
},
|
||
get_batch_dir(e, n) {
|
||
return this.batch_dir(e.name, n);
|
||
},
|
||
delete_batch(e) {
|
||
this.sms_verified_action(
|
||
'删除批次',
|
||
'确定删除批次吗?名称: ' + e.name,
|
||
() => this.do_delete_batch(e))
|
||
},
|
||
async do_delete_batch(e) {
|
||
await this.$root.estor_delete(this.get_batch_dir(e));
|
||
this.reload();
|
||
},
|
||
show_image_convert(e) {
|
||
this.image_convert_target = e;
|
||
this.$refs.image_convert_modal.show();
|
||
},
|
||
async image_convert(ok) {
|
||
if (!ok) return;
|
||
this.$root.notify("格式转换", "正在创建格式转换任务");
|
||
var e = this.image_convert_target;
|
||
var ib = this.get_batch_dir(e, "import");
|
||
var params = {
|
||
'Estor-Addr': this.estor_url,
|
||
'Estor-Token': this.estor_token,
|
||
'Input-Basedir': ib,
|
||
'Output-Basedir': this.get_batch_dir(e, "convert/"),
|
||
'Output-Format': this.image_convert_format,
|
||
'Resize': this.image_convert_size.toString(),
|
||
'Quality': this.image_convert_quality,
|
||
};
|
||
if (this.image_convert_grayscale) {
|
||
params['Grayscale'] = 'yes';
|
||
}
|
||
var r = await this.$root.estor_call("CreateJob", {
|
||
name: "[格式转换]" + e.name,
|
||
spec: {
|
||
type: "HttpPost",
|
||
args: {
|
||
space: this.$root.estor_space,
|
||
files: [this.get_batch_dir(e, "import")],
|
||
url: this.emblem_processor_url + '/image-convert',
|
||
params,
|
||
recursive: true,
|
||
},
|
||
},
|
||
});
|
||
console.log(r);
|
||
this.$router.push("/estor/jobs");
|
||
},
|
||
async qr_std_upload(e) {
|
||
this.$root.notify("备案到云", "正在创建备案任务");
|
||
var base_url = this.base_url();
|
||
var url = base_url + '/api/v1/qr-std-upload/';
|
||
var r = await this.$root.estor_call("CreateJob", {
|
||
name: "[备案到云]" + e.name,
|
||
spec: {
|
||
type: "HttpPost",
|
||
args: {
|
||
space: this.$root.estor_space,
|
||
files: [this.get_batch_dir(e, 'import')],
|
||
url,
|
||
concurrency: 256,
|
||
recursive: true,
|
||
headers: {
|
||
'Authorization': 'token ' + this.$root.token,
|
||
},
|
||
},
|
||
},
|
||
});
|
||
await this.set_batch_state(e.name, {
|
||
status: 'qr_std_uploading',
|
||
job: r.data.data,
|
||
});
|
||
this.$router.push("/estor/jobs");
|
||
},
|
||
show_time(e) {
|
||
var ctime = e.ts.ctime;
|
||
return this.format_timestamp(ctime, false);
|
||
},
|
||
show_status(e) {
|
||
var m = {
|
||
loading: '正在获取...',
|
||
importing: '正在导入',
|
||
imported: '已导入',
|
||
qr_std_uploading: '备案中',
|
||
qr_std_uploaded: '备案完成',
|
||
feature_extracting: '特征提取中',
|
||
feature_extracted: '特征提取完成',
|
||
error: '获取失败',
|
||
};
|
||
return m[e.status] || e.status;
|
||
},
|
||
async reload() {
|
||
this.loading = true;
|
||
var r = await this.$root.estor_list(this.$root.batches_dir);
|
||
var entries = this.sort_entries(r);
|
||
for (var i in entries) {
|
||
entries[i].status ='loading';
|
||
}
|
||
this.entries = entries;
|
||
this.loading = false;
|
||
this.reload_status();
|
||
},
|
||
async reload_status() {
|
||
for (var i in this.entries) {
|
||
var e = this.entries[i];
|
||
try {
|
||
var r = await this.get_batch_state(e.name);
|
||
console.log(r);
|
||
var st = r['status'];
|
||
if (!r.job) {
|
||
this.entries[i].status = st;
|
||
continue;
|
||
}
|
||
if (st == 'importing') {
|
||
st = await this.patch_status_if_completed(e.name, r.job, st, 'imported');
|
||
} else if (st == 'qr_std_uploading') {
|
||
st = await this.patch_status_if_completed(e.name, r.job, st, 'qr_std_uploaded');
|
||
}
|
||
this.entries[i].status = st;
|
||
} catch {
|
||
this.entries[i].status = 'error';
|
||
}
|
||
}
|
||
},
|
||
async patch_status_if_completed(batch_name, job_id, old_st, new_st) {
|
||
var r = await this.$root.estor_call("GetJob", {
|
||
uuid: job_id,
|
||
});
|
||
if (r.data.data.status == 'Completed') {
|
||
this.set_batch_state(batch_name, {
|
||
status: new_st,
|
||
});
|
||
return new_st;
|
||
}
|
||
return old_st;
|
||
},
|
||
sort_entries(r) {
|
||
var sorted = r.sort((a, b) => { return b.ts.ctime - a.ts.ctime });
|
||
return sorted;
|
||
},
|
||
},
|
||
mounted() {
|
||
this.reload();
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
div.convert-config-section {
|
||
border: 1px solid #ccc;
|
||
border-radius: 5px;
|
||
padding: 0.5rem;
|
||
margin: 0.5rem 0;
|
||
}
|
||
input[type=checkbox] {
|
||
margin-right: 0.2rem;
|
||
}
|
||
|
||
</style>
|