changes
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<div class="field is-grouped">
|
||||
<div
|
||||
class="control"
|
||||
id="ignore"
|
||||
>
|
||||
<div class="file is-primary m-0">
|
||||
<label class="file-label">
|
||||
<input
|
||||
class="file-input"
|
||||
@@ -12,86 +9,112 @@
|
||||
name="resume"
|
||||
@change="inputFile"
|
||||
/>
|
||||
<span class="file-cta px-2 has-background-primary">
|
||||
<span class="icon-text is-clickable">
|
||||
<SvgIcon v-bind="{ name: 'attach-file.svg', type: 'white', size: 22 }"></SvgIcon>
|
||||
<span class="has-text-white">Chọn file</span>
|
||||
<span
|
||||
class="file-cta"
|
||||
style="padding-left: 0.5rem"
|
||||
>
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<Icon
|
||||
name="material-symbols:attach-file"
|
||||
:size="18"
|
||||
/>
|
||||
</span>
|
||||
<span class="font-medium">Chọn file</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a
|
||||
class="button is-primary"
|
||||
@click="download()"
|
||||
>
|
||||
Tải template
|
||||
</a>
|
||||
<a
|
||||
class="button is-light ml-6"
|
||||
v-if="datafile"
|
||||
@click="exportExcel()"
|
||||
>Xuất Excel</a
|
||||
>
|
||||
</div>
|
||||
<button
|
||||
class="button is-primary is-light"
|
||||
@click="download"
|
||||
>
|
||||
<span class="icon">
|
||||
<Icon
|
||||
name="material-symbols:download"
|
||||
:size="20"
|
||||
/>
|
||||
</span>
|
||||
<span>Tải template</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="datafile"
|
||||
class="button is-success is-light"
|
||||
@click="exportExcel"
|
||||
>
|
||||
<span class="icon">
|
||||
<Icon
|
||||
name="mdi:microsoft-excel"
|
||||
:size="20"
|
||||
/>
|
||||
</span>
|
||||
<span>Xuất Excel</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="columns mb-0"
|
||||
class="fixed-grid has-12-cols"
|
||||
v-if="msgInfo.length > 0"
|
||||
>
|
||||
<div class="column is-7 mb-0">
|
||||
<div class="notification is-white py-2 mb-2">
|
||||
<button
|
||||
class="delete"
|
||||
@click="msgInfo = []"
|
||||
></button>
|
||||
<div style="max-height: 250px; overflow-y: auto">
|
||||
<article
|
||||
class="media py-0 my-0"
|
||||
v-for="(ele, key) in msgInfo"
|
||||
:key="key"
|
||||
<div class="grid">
|
||||
<div class="cell is-col-span-9">
|
||||
<div class="notification fs-14">
|
||||
<button
|
||||
class="delete"
|
||||
@click="msgInfo = []"
|
||||
></button>
|
||||
<div
|
||||
class="content"
|
||||
style="max-height: 250px; overflow-y: auto"
|
||||
>
|
||||
<figure class="media-left">
|
||||
<i :class="classinfo.find((v) => v.type === ele.type).icon_class"> </i>
|
||||
</figure>
|
||||
<div class="media-content">
|
||||
<div class="content">
|
||||
<p :class="classinfo.find((v) => v.type == ele.type).text_class">
|
||||
{{ ele.message }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<p
|
||||
v-for="(ele, i) in msgInfo"
|
||||
:key="i"
|
||||
class="mb-2"
|
||||
>
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<Icon
|
||||
:name="classinfo.find((v) => v.type === ele.type).icon"
|
||||
:size="18"
|
||||
:class="classinfo.find((v) => v.type === ele.type).color"
|
||||
/>
|
||||
</span>
|
||||
<span v-html="ele.message"></span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="result">
|
||||
<span class="has-text-primary fsb-18">Thành công: {{ result.success_count || 0 }} / {{ total || "" }}</span>
|
||||
<span class="has-text-danger fsb-18 ml-5">{{ `Lỗi: ${result.error_count || 0}` }} / {{ total || "" }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
v-if="ready"
|
||||
class="cell is-col-span-3"
|
||||
>
|
||||
<div class="buttons">
|
||||
<button
|
||||
v-if="countNew > 0"
|
||||
:class="['button is-success', isloading && 'is-loading']"
|
||||
@click="insert"
|
||||
>
|
||||
Thêm mới ({{ countNew }}/{{ total }})
|
||||
</button>
|
||||
<button
|
||||
v-if="countUdt > 0"
|
||||
:class="['button is-primary is-light', isloading && 'is-loading']"
|
||||
@click="update"
|
||||
>
|
||||
Cập nhật ({{ countUdt }}/{{ total }})
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="result">
|
||||
<span class="has-text-primary fsb-18"
|
||||
>{{ `Thành công: ${result.success_count || 0}` }} / {{ total || "" }}</span
|
||||
>
|
||||
<span class="has-text-danger fsb-18 ml-5">{{ `Lỗi: ${result.error_count || 0}` }} / {{ total || "" }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="column has-text-centered mb-0"
|
||||
v-if="ready"
|
||||
>
|
||||
<a
|
||||
:class="`button is-primary ${isloading ? 'is-loading' : ''}`"
|
||||
@click="insert()"
|
||||
v-if="countNew > 0"
|
||||
>Thêm mới ({{ countNew }}/{{ total }})</a
|
||||
>
|
||||
<a
|
||||
:class="`button is-dark ${isloading ? 'is-loading' : ''} ml-2`"
|
||||
@click="update()"
|
||||
v-if="countUdt > 0"
|
||||
>Cập nhật ({{ countUdt }}/{{ total }})</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<DataTable
|
||||
v-bind="{ pagename: pagename }"
|
||||
v-if="pagedata"
|
||||
:pagename="pagename"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -103,23 +126,23 @@ export default {
|
||||
classinfo: [
|
||||
{
|
||||
type: "success",
|
||||
icon_class: "mdi mdi-check",
|
||||
text_class: "has-text-primary",
|
||||
icon: "material-symbols:check-rounded",
|
||||
color: "has-text-success",
|
||||
},
|
||||
{
|
||||
type: "error",
|
||||
icon_class: "mdi mdi-close has-text-danger",
|
||||
text_class: "has-text-danger",
|
||||
icon: "material-symbols:cancel-rounded",
|
||||
color: "has-text-danger",
|
||||
},
|
||||
{
|
||||
type: "warning",
|
||||
icon_class: "mdi mdi-alert has-text-warning",
|
||||
text_class: "has-text-warning",
|
||||
icon: "material-symbols:warning-rounded",
|
||||
color: "has-text-warning",
|
||||
},
|
||||
{
|
||||
type: "waiting",
|
||||
icon_class: "mdi mdi-timer-sand has-text-primary",
|
||||
text_class: "has-text-primary",
|
||||
icon: "material-symbols:hourglass-top-rounded",
|
||||
color: "has-text-primary",
|
||||
},
|
||||
],
|
||||
msgInfo: [],
|
||||
@@ -160,34 +183,36 @@ export default {
|
||||
download() {
|
||||
window.open(`${this.$getpath()}static/excelform/${this.setting.template}`, "_blank");
|
||||
},
|
||||
async inputFile(v) {
|
||||
async inputFile() {
|
||||
this.isloading = true;
|
||||
this.msgInfo = [];
|
||||
let fileList = document.getElementById("divfile").files;
|
||||
let files = Array.from(fileList);
|
||||
const files = document.getElementById("divfile").files;
|
||||
if (files.length === 0) return;
|
||||
var thefile = this.$upload(files[0], "file", 1);
|
||||
|
||||
const file = files.item(0);
|
||||
let thefile = this.$upload(file, "file", 1);
|
||||
|
||||
if (thefile.error) {
|
||||
this.$buefy.toast.open({ message: thefile.text, type: "is-danger" });
|
||||
this.$snackbar(thefile.text, undefined, "Error");
|
||||
return (this.isloading = false);
|
||||
}
|
||||
if (!(thefile.name.search(".xls") > 0 || thefile.name.search(".xlsx") > 0)) {
|
||||
let text = this.$find(
|
||||
const message = this.$find(
|
||||
this.$store.syspara,
|
||||
{ category: "inform", classify: "import", code: "file-type-invalid" },
|
||||
"value",
|
||||
);
|
||||
this.msgInfo.push({ message: text, type: "error" });
|
||||
this.msgInfo.push({ message, type: "error" });
|
||||
return (this.isloading = false);
|
||||
}
|
||||
let result = await this.$insertapi("upload", thefile.form, undefined, false);
|
||||
if (result === "error") {
|
||||
let text = this.$find(
|
||||
const message = this.$find(
|
||||
this.$store.syspara,
|
||||
{ category: "inform", classify: "import", code: "file-upload-fail" },
|
||||
"value",
|
||||
);
|
||||
this.msgInfo.push({ message: text, type: "error" });
|
||||
this.msgInfo.push({ message, type: "error" });
|
||||
} else {
|
||||
this.fileLog = result;
|
||||
this.fileInfo = thefile;
|
||||
@@ -199,19 +224,22 @@ export default {
|
||||
document.getElementById("divfile").value = "";
|
||||
},
|
||||
async fillData() {
|
||||
let found = this.$findapi("readexcel");
|
||||
found.params = { name: this.fileInfo.filename };
|
||||
let result = await this.$getapi([found]);
|
||||
const readExcelApi = this.$findapi("readexcel");
|
||||
readExcelApi.params = { name: this.fileInfo.filename };
|
||||
const result = await this.$getapi([readExcelApi]);
|
||||
this.datafile = JSON.parse(result[0].data);
|
||||
let fields = [];
|
||||
const fields = [];
|
||||
|
||||
this.datafile.schema.fields.forEach((ele) => {
|
||||
let field = this.$createField(ele.name, ele.name, "string", true);
|
||||
if (field.name !== "index") fields.push(field);
|
||||
});
|
||||
let copy = this.pagedata ? this.$copy(this.pagedata) : this.$getpage();
|
||||
let data = this.datafile.data;
|
||||
data.map((v) => (v.updater = this.$store.login.id));
|
||||
copy.update = { fields: fields, data: data };
|
||||
|
||||
const copy = this.pagedata ? this.$copy(this.pagedata) : this.$getpage();
|
||||
const data = this.datafile.data;
|
||||
// data.map((v) => (v.updater = this.$store.login.id));
|
||||
data.map((v) => (v.updater = 1));
|
||||
copy.update = { fields, data };
|
||||
copy.data = data;
|
||||
copy.fields = fields;
|
||||
this.pagedata = copy;
|
||||
@@ -223,17 +251,18 @@ export default {
|
||||
let found = fields.find((x) => x.name === v);
|
||||
if (!found) misslist.push(v);
|
||||
});
|
||||
|
||||
if (misslist.length > 0) {
|
||||
let text = `Thiếu các cột bắt buộc: ${misslist.join(", ")}`;
|
||||
this.msgInfo.push({ message: text, type: "error" });
|
||||
const message = `Thiếu các cột bắt buộc: ${misslist.join(", ")}`;
|
||||
this.msgInfo.push({ message, type: "error" });
|
||||
} else {
|
||||
this.validateFontend();
|
||||
this.validateFrontend();
|
||||
}
|
||||
},
|
||||
validateFontend() {
|
||||
validateFrontend() {
|
||||
let self = this;
|
||||
var checkValid = function (name, obj, data) {
|
||||
var error = false;
|
||||
const checkValid = function (name, obj, data) {
|
||||
let error = false;
|
||||
if (obj.empty === "no" || !self.$empty(obj.api)) {
|
||||
data.map((x) => {
|
||||
if (self.$empty(x[name])) {
|
||||
@@ -305,14 +334,14 @@ export default {
|
||||
message: "Dữ liệu có lỗi. Hãy kiểm tra lại",
|
||||
type: "error",
|
||||
});
|
||||
let field = this.$createField("error", "error", "string", true, true);
|
||||
const field = this.$createField("error", "error", "string", true, true);
|
||||
field.color = "red";
|
||||
let fields = this.$copy(this.pagedata.fields);
|
||||
fields = [field].concat(fields);
|
||||
let copy = this.$clone(this.pagedata);
|
||||
const copy = this.$clone(this.pagedata);
|
||||
copy.data = data;
|
||||
copy.fields = fields;
|
||||
copy.update = { data: data, fields: fields };
|
||||
copy.update = { data, fields };
|
||||
this.pagedata = copy;
|
||||
},
|
||||
|
||||
@@ -323,12 +352,12 @@ export default {
|
||||
type: "waiting",
|
||||
});
|
||||
|
||||
let keys = [];
|
||||
let related = [];
|
||||
const keys = [];
|
||||
const related = [];
|
||||
|
||||
// 1. Tạo dữ liệu gửi lên: Dùng chính tên cột Excel để chứa giá trị
|
||||
let mappedRows = rows.map((row) => {
|
||||
let newRow = { ...row };
|
||||
const mappedRows = rows.map((row) => {
|
||||
const newRow = { ...row };
|
||||
for (const [excelColName, config] of Object.entries(this.requireFields)) {
|
||||
if (excelColName in row) {
|
||||
newRow[excelColName] = row[excelColName];
|
||||
@@ -354,17 +383,19 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
let conn = this.$findapi(this.setting.api);
|
||||
let payload = {
|
||||
// this.setting.api is 'Product_Variant'
|
||||
const conn = this.$findapi(this.setting.api);
|
||||
const payload = {
|
||||
name: conn.url.replace("data/", "").replace(/\//g, ""),
|
||||
data: mappedRows,
|
||||
keys: keys,
|
||||
related: related,
|
||||
keys,
|
||||
related,
|
||||
};
|
||||
|
||||
try {
|
||||
let rs = await this.$insertapi("findkey", payload);
|
||||
if (rs && rs.data) {
|
||||
const rs = await this.$insertapi("findkey", payload, undefined, false);
|
||||
if (rs === "error") throw new Error();
|
||||
else {
|
||||
this.data = rs.data;
|
||||
this.total = this.data.length;
|
||||
|
||||
@@ -372,7 +403,7 @@ export default {
|
||||
this.checkUpdatePermission();
|
||||
|
||||
// 1. Lọc ra danh sách các lỗi
|
||||
let errors = this.data
|
||||
const errors = this.data
|
||||
.map((v, i) => (v.error ? { line: i + 1, msg: v.error } : null))
|
||||
.filter((v) => v !== null);
|
||||
|
||||
@@ -403,9 +434,10 @@ export default {
|
||||
this.showStatus();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
this.isloading = false;
|
||||
this.msgInfo.push({
|
||||
message: "Lỗi hệ thống khi kiểm tra",
|
||||
message: `Lỗi hệ thống khi kiểm tra: ${e.message}`,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
@@ -454,23 +486,23 @@ export default {
|
||||
},
|
||||
|
||||
showStatus() {
|
||||
let field = this.$createField("record_status", "Status", "string", true, true);
|
||||
const field = this.$createField("record_status", "Status", "string", true, true);
|
||||
field.color = "blue";
|
||||
let fields = this.$copy(this.pagedata.fields);
|
||||
const fields = this.$copy(this.pagedata.fields);
|
||||
fields.push(field);
|
||||
this.$store.commit("updateState", {
|
||||
name: this.pagename,
|
||||
key: "fields",
|
||||
data: fields,
|
||||
});
|
||||
let data = this.$copy(this.pagedata.data);
|
||||
data.map((v, i) => (v.record_status = this.data[i].id ? "Tồn tại" : "Mới"));
|
||||
const data = this.$copy(this.pagedata.data);
|
||||
data.forEach((v, i) => (v.record_status = this.data[i].id ? "Tồn tại" : "Mới"));
|
||||
this.$store.commit("updateState", {
|
||||
name: this.pagename,
|
||||
key: "data",
|
||||
data: data,
|
||||
data,
|
||||
});
|
||||
let copy = this.$clone(this.pagedata);
|
||||
const copy = this.$clone(this.pagedata);
|
||||
this.pagedata = undefined;
|
||||
setTimeout(() => (this.pagedata = copy), 10);
|
||||
},
|
||||
@@ -500,39 +532,40 @@ export default {
|
||||
async insert() {
|
||||
this.isloading = true;
|
||||
this.result = undefined;
|
||||
let conn = this.$findapi(this.setting.api);
|
||||
let obj = {
|
||||
const conn = this.$findapi(this.setting.api);
|
||||
const importLogPayload = {
|
||||
code: this.$id(),
|
||||
model: conn.url.replace("data/", "").replace("/", ""),
|
||||
file: this.fileInfo.name,
|
||||
fields: this.setting.detail,
|
||||
};
|
||||
await this.$insertapi("importlog", obj);
|
||||
var interval = setInterval(() => this.getResult(obj.code), 2000);
|
||||
await this.$insertapi("importlog", importLogPayload);
|
||||
const interval = setInterval(() => this.getResult(importLogPayload.code), 2000);
|
||||
|
||||
//Lọc bản ghi KHÔNG có id (bản ghi mới)
|
||||
// Lọc bản ghi KHÔNG có id (bản ghi mới)
|
||||
let filter = this.data.filter((v) => !v.id && !v.error);
|
||||
|
||||
//Xóa trường lookup trước khi gửi
|
||||
// Xóa trường lookup trước khi gửi
|
||||
filter = this.cleanupLookupFields(filter);
|
||||
filter = filter.map((v) => this.$resetNull(v));
|
||||
this.total = filter.length;
|
||||
|
||||
//Gửi lên API - Backend sẽ INSERT
|
||||
// Gửi lên API - Backend sẽ INSERT
|
||||
let result;
|
||||
if (this.setting.call_api) {
|
||||
result = await this.$insertapi(
|
||||
this.setting.call_api,
|
||||
{ data: filter, user: this.$store.login.id },
|
||||
undefined,
|
||||
obj.code,
|
||||
importLogPayload.code,
|
||||
);
|
||||
} else {
|
||||
result = await this.$insertapi(this.setting.api, filter, undefined, obj.code);
|
||||
result = await this.$insertapi(this.setting.api, filter, undefined, importLogPayload.code);
|
||||
}
|
||||
|
||||
this.isloading = false;
|
||||
clearInterval(interval);
|
||||
this.getResult(obj.code);
|
||||
this.getResult(importLogPayload.code);
|
||||
|
||||
// Xử lý result/response mới
|
||||
if (result === "error") {
|
||||
@@ -544,7 +577,7 @@ export default {
|
||||
}
|
||||
|
||||
let hasError = false;
|
||||
let errorMessages = [];
|
||||
const errorMessages = [];
|
||||
|
||||
// Kiểm tra entries có lỗi không
|
||||
if (result.entries && Array.isArray(result.entries)) {
|
||||
@@ -600,36 +633,41 @@ export default {
|
||||
async update() {
|
||||
this.isloading = true;
|
||||
this.result = undefined;
|
||||
let conn = this.$findapi(this.setting.api);
|
||||
let obj = {
|
||||
const conn = this.$findapi(this.setting.api);
|
||||
const importlogPayload = {
|
||||
code: this.$id(),
|
||||
model: conn.url.replace("data/", "").replace("/", ""),
|
||||
file: this.fileInfo.name,
|
||||
fields: this.setting.detail,
|
||||
};
|
||||
await this.$insertapi("importlog", obj);
|
||||
var interval = setInterval(() => this.getResult(obj.code), 2000);
|
||||
await this.$insertapi("importlog", importlogPayload);
|
||||
const interval = setInterval(() => this.getResult(importlogPayload.code), 2000);
|
||||
|
||||
//Lọc bản ghi CÓ id (bản ghi tồn tại) VÀ KHÔNG CÓ LỖI
|
||||
// Lọc bản ghi CÓ id (bản ghi tồn tại) VÀ KHÔNG CÓ LỖI
|
||||
let filter = this.data.filter((v) => v.id && !v.error);
|
||||
|
||||
//Xóa trường lookup trước khi gửi
|
||||
// Xóa trường lookup trước khi gửi
|
||||
filter = this.cleanupLookupFields(filter);
|
||||
filter = filter.map((v) => this.$resetNull(v));
|
||||
this.total = filter.length;
|
||||
|
||||
//Gửi lên API - Backend sẽ UPDATE
|
||||
let result = await this.$insertapi(this.setting.call_api || this.setting.api, filter, undefined, obj.code);
|
||||
// Gửi lên API - Backend sẽ UPDATE
|
||||
const result = await this.$insertapi(
|
||||
this.setting.call_api || this.setting.api,
|
||||
filter,
|
||||
undefined,
|
||||
importlogPayload.code,
|
||||
);
|
||||
this.isloading = false;
|
||||
clearInterval(interval);
|
||||
this.getResult(obj.code);
|
||||
this.getResult(importlogPayload.code);
|
||||
|
||||
if (result === "error") {
|
||||
return this.msgInfo.push({ message: "Có lỗi xảy ra", type: "error" });
|
||||
}
|
||||
|
||||
let hasError = false;
|
||||
let errorMessages = [];
|
||||
const errorMessages = [];
|
||||
|
||||
// Kiểm tra có lỗi trong result không
|
||||
if (Array.isArray(result)) {
|
||||
@@ -656,16 +694,16 @@ export default {
|
||||
},
|
||||
|
||||
async getResult(logcode) {
|
||||
let found = this.$findapi("importlog");
|
||||
const found = this.$findapi("importlog");
|
||||
found.params.filter = { code: logcode };
|
||||
let rs = await this.$getapi([found]);
|
||||
const rs = await this.$getapi([found]);
|
||||
this.result = rs[0].data.rows[0];
|
||||
},
|
||||
|
||||
exportExcel() {
|
||||
let dataType = {};
|
||||
const dataType = {};
|
||||
this.pagedata.fields.map((v) => (dataType[v.label.indexOf(">") >= 0 ? v.name : v.label] = "String"));
|
||||
let data = this.pagedata.dataFilter || this.pagedata.data;
|
||||
const data = this.pagedata.dataFilter || this.pagedata.data;
|
||||
this.$exportExcel(
|
||||
data,
|
||||
"data-export",
|
||||
|
||||
Reference in New Issue
Block a user