331 lines
8.8 KiB
JavaScript
331 lines
8.8 KiB
JavaScript
import { always, cond, equals, is, T, mergeLeft } from "ramda";
|
|
import Handlebars from "handlebars/dist/cjs/handlebars";
|
|
import moment from "moment";
|
|
import presetConfig from './presetConfig'
|
|
|
|
const tablefy = (list = []) => {
|
|
const defaultData = (title) => ({
|
|
headerFilter: "input",
|
|
minWidth: 80,
|
|
headerFilterPlaceholder: title,
|
|
download: false,
|
|
print: false,
|
|
vertAlign: "middle",
|
|
sorter: "string",
|
|
responsive: 0
|
|
})
|
|
|
|
if (!is(Array, list)) return []
|
|
return list.map((el) => mergeLeft(el, defaultData(el?.title || "")))
|
|
}
|
|
|
|
const math = (value, operator, operand) => {
|
|
var left = parseFloat(value);
|
|
var right = parseFloat(operand);
|
|
|
|
switch(operator) {
|
|
case "+":
|
|
return left + right;
|
|
case "-":
|
|
return left - right;
|
|
case "*":
|
|
return left * right;
|
|
case "/":
|
|
return left / right;
|
|
case "%":
|
|
return left % right;
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
const link = (col) => ({
|
|
...col,
|
|
formatter: (cell, { prefix = "", text, key = "id" }, onRendered) => {
|
|
onRendered(function () {
|
|
let row = cell.getRow().getData();
|
|
if (!text && !cell.getValue()) {
|
|
return null;
|
|
}
|
|
if (!row[key]) return null;
|
|
|
|
cell.getElement().innerHTML = `<a target="_blank" href="${prefix}/${
|
|
row[key]
|
|
}">${text || cell.getValue()}</a>`;
|
|
});
|
|
},
|
|
});
|
|
|
|
[
|
|
['math', math],
|
|
['presetConfig', (record, pack) => presetConfig(pack, record)],
|
|
[
|
|
"dt_shift",
|
|
(date, shift, param) => {
|
|
return date ? moment(date).add(shift, param) : "нд";
|
|
},
|
|
],
|
|
[
|
|
"dt_format",
|
|
(date) => {
|
|
return date ? moment(date).format("DD.MM.YYYY HH:mm") : "нд";
|
|
},
|
|
],
|
|
[
|
|
"dt_db_format",
|
|
(date) => {
|
|
return date ? moment(date).format("YYYY-MM-DDTHH:mm:ss") : "нд";
|
|
},
|
|
],
|
|
[
|
|
"from_now",
|
|
(date) => {
|
|
return moment(date).fromNow()
|
|
},
|
|
],
|
|
[
|
|
"json_parse",
|
|
(item) => {
|
|
return `
|
|
<div>
|
|
${item}
|
|
</div>
|
|
`
|
|
},
|
|
],
|
|
[
|
|
"time_from_sec",
|
|
(ms) => {
|
|
if (!ms) return "н/д"
|
|
return `${moment(moment().subtract(Math.round(ms), 'milliseconds')).fromNow()}`.replace("назад", '')
|
|
},
|
|
],
|
|
[
|
|
"lenght",
|
|
(list) => {
|
|
return is(Array, list) ? list.length : 0;
|
|
},
|
|
],
|
|
[
|
|
"more",
|
|
(one, two) => {
|
|
return one > two;
|
|
},
|
|
],
|
|
[
|
|
"less",
|
|
(one, two) => {
|
|
return one < two;
|
|
},
|
|
],
|
|
[
|
|
"or",
|
|
(one, two) => {
|
|
return one || two;
|
|
},
|
|
],
|
|
[
|
|
"eq",
|
|
(one, two) => {
|
|
return one === two;
|
|
},
|
|
],
|
|
[
|
|
"endOf",
|
|
(date, param) => moment(date).endOf(param)
|
|
],
|
|
[
|
|
"startOf",
|
|
(date, param) => moment(date).startOf(param)
|
|
],
|
|
[
|
|
"render",
|
|
(list, key) => {
|
|
return list.map(el => el[key]).join(", ")
|
|
}
|
|
],
|
|
[
|
|
"get",
|
|
(map, key) => {
|
|
return map[key] ? `${map[key]}` : ""
|
|
}
|
|
],
|
|
[
|
|
"get_from",
|
|
(map, key) => {
|
|
return map[key] ? `${map[key]}` : ""
|
|
}
|
|
],
|
|
[
|
|
"uint8parse",
|
|
(list) => pipe(
|
|
(x) => Uint8Array.from(x, e => e.charCodeAt(0)),
|
|
Array.from
|
|
)(list)
|
|
],
|
|
[
|
|
"filter_aoo",
|
|
(list = [], key, _availible_list) => {
|
|
const availible_list = pipe(
|
|
(x) => Uint8Array.from(x, e => e.charCodeAt(0)),
|
|
Array.from
|
|
)(_availible_list)
|
|
return list.filter((el) =>
|
|
availible_list.includes(el[key]))
|
|
}
|
|
]
|
|
].forEach(([name, func]) => {
|
|
Handlebars.registerHelper(name, func);
|
|
});
|
|
|
|
const render = (col) => ({
|
|
...col,
|
|
formatter: (cell, _, onRendered) => {
|
|
onRendered(function () {
|
|
if (`${col.render}`.includes("{{") && `${col.render}`.includes("}}")) {
|
|
let record = cell.getRow().getData();
|
|
cell.getElement().innerHTML = Handlebars.compile(col.render)(
|
|
{...record, __record__: record}
|
|
);
|
|
} else if (typeof col.render === "function") {
|
|
cell.getElement().innerHTML = col.render(cell.getRow().getData(), cell.getRow());
|
|
}
|
|
});
|
|
},
|
|
});
|
|
|
|
let sorter = (a, b) => {
|
|
let [a_field, b_field] = [a["field"], b["field"]];
|
|
if (a_field.includes("id") && b_field.includes("id"))
|
|
return a_field.localeCompare(b_field);
|
|
if (a_field.includes("id")) return -1;
|
|
if (b_field.includes("id")) return 1;
|
|
if (a_field.includes("dt") && b_field.includes("dt"))
|
|
return b_field.localeCompare(a_field);
|
|
if (a_field.includes("dt")) return -1;
|
|
if (b_field.includes("dt")) return 1;
|
|
if (a_field.includes("imei") && b_field.includes("imei"))
|
|
return b_field.localeCompare(a_field);
|
|
if (a_field.includes("imei")) return -1;
|
|
if (b_field.includes("imei")) return 1;
|
|
return a_field.localeCompare(b_field);
|
|
};
|
|
|
|
const prepCol = (col) =>
|
|
cond([
|
|
[() => is(String, col.render), () => render(col)],
|
|
[() => is(Function, col.render), () => render(col)],
|
|
[equals("link"), () => link(col)],
|
|
[T, always(col)],
|
|
])(col.mode);
|
|
|
|
const prepColumns = (cols) =>
|
|
is(Array, cols) ? cols.map((col) => prepCol(col)) : [];
|
|
|
|
const renderGroupHeader = ({ groupHeader, value, count, group, extra }) => {
|
|
const groupData = group._group;
|
|
|
|
if (groupData.level == 0) {
|
|
const {company_id, param, train_info: train, date: _date} = groupData.groupList[0].rows[0].data
|
|
|
|
const date = `${_date}`.replace(/\s(.*)/gm, "")
|
|
|
|
const icident_group = extra.find((el) =>
|
|
el.date === date &&
|
|
el.company_id == company_id &&
|
|
el.train == train &&
|
|
el.param == param
|
|
) || {}
|
|
|
|
return Handlebars.compile(groupHeader)({
|
|
_value: value,
|
|
_count: count,
|
|
extra: extra,
|
|
icident_group: icident_group
|
|
});
|
|
}
|
|
|
|
return `${value} (${count} записей)`;
|
|
};
|
|
|
|
const groupByFunction = (groupBy) => (data) =>
|
|
Handlebars.compile(groupBy)(data);
|
|
|
|
const makedFiltering = (id, filterParams, selectedFilter, clearFilters) => {
|
|
|
|
const table = document.querySelector(`#${id}`)
|
|
const isFiltering = document.querySelector(`${id}-filters`)
|
|
|
|
if(id && filterParams) {
|
|
filterParams.unshift([])
|
|
const filtersContainer = document.createElement('div')
|
|
filtersContainer.setAttribute("id", `${id}-filters`)
|
|
filtersContainer.classList.add("col-span-12")
|
|
filtersContainer.innerHTML = `
|
|
<div id="${id}-filtersContainer" class="filters flex flex-row items-center justify-start gap-3 mb-0 pt-2.5 bg-slate-100 rounded-t-md flex-row 2xl:flex-row">
|
|
<div id="${id}-selectFilters" class="flex items-center justify-start gap-3 p-1 ml-2 text-base text-slate-700 font-bold">
|
|
Фильтр по статусу
|
|
<select name="selectFilter" id="${id}-selectFilter" class="flex text-gray-700 pl-3 pr-9 py-0.5 rounded cursor-pointer border-none" style="--tw-ring-color:focus: none" >
|
|
${filterParams.map((el) => {
|
|
return (`<option value='${el}'>
|
|
${el}
|
|
</option>`)
|
|
})}
|
|
</select>
|
|
</div>
|
|
<button id="${id}-filtersClear"class="w-fit h-fit flex items-center text-white text-sm font-bold bg-slate-600 hover:bg-slate-700 py-1 px-3 gap-1 rounded">Очистить фильтр</button>
|
|
</div>`
|
|
if(!isFiltering) {
|
|
table.before(filtersContainer)
|
|
}
|
|
else {
|
|
isFiltering.remove()
|
|
table.before(filtersContainer)
|
|
}
|
|
|
|
const selectFilters = document.querySelectorAll(`#${id}-selectFilter`)
|
|
const selectOptions = document.querySelectorAll(`#${id}-selectFilter option`)
|
|
const buttonClearFilters = document.querySelector(`#${id}-filtersClear`)
|
|
|
|
selectFilters.forEach((el) => {
|
|
el.onchange = (e) => {
|
|
if(e.target.value) {
|
|
selectOptions[0].removeAttribute('selected')
|
|
selectedFilter(e.target.value)
|
|
} else {
|
|
clearFilters()
|
|
e.target.setAttribute('selected', 'selected')
|
|
}
|
|
}
|
|
})
|
|
|
|
buttonClearFilters.onclick = () => {
|
|
clearFilters()
|
|
selectOptions[0].setAttribute('selected', 'selected')
|
|
}
|
|
}
|
|
}
|
|
|
|
const validation = (value, pagination) => {
|
|
const pipe = (...fns) => (...x) => fns.reduce((error, validator) => error || validator(...x), undefined)
|
|
|
|
const minPage = length => value => {
|
|
value = value.replace(/\s+/g, '')
|
|
return value >= length ? undefined : `Номер страницы должен быть больше или равен ${length}`
|
|
}
|
|
const maxPage = length => value => {
|
|
value = value.replace(/\s+/g, '')
|
|
return length >= value ? undefined : `Номер страницы должен быть меньше или равен ${length}`
|
|
}
|
|
const onlyDigits = value => {
|
|
const pattern = /^([\d])*$/g
|
|
return pattern.test(value) ? undefined : `Номер страницы должен содержать только цифры`
|
|
}
|
|
const composedValidators = pipe(onlyDigits, minPage(1), maxPage(pagination.total_pages))
|
|
return composedValidators(value)
|
|
}
|
|
|
|
const pipe = (x) => (...fns) => fns.reduce((r, fn) => fn(r), x)
|
|
|
|
export {prepColumns, sorter, renderGroupHeader, groupByFunction, makedFiltering, tablefy, validation, pipe};
|