mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
500da8099b
- Also some refactoring of how forms are handled and saved
793 lines
26 KiB
JavaScript
793 lines
26 KiB
JavaScript
{% load i18n %}
|
|
{% load inventree_extras %}
|
|
|
|
function newBuildOrder(options={}) {
|
|
/* Launch modal form to create a new BuildOrder.
|
|
*/
|
|
|
|
launchModalForm(
|
|
"{% url 'build-create' %}",
|
|
{
|
|
follow: true,
|
|
data: options.data || {},
|
|
callback: [
|
|
{
|
|
field: 'part',
|
|
action: function(value) {
|
|
inventreeGet(
|
|
`/api/part/${value}/`, {},
|
|
{
|
|
success: function(response) {
|
|
|
|
//enableField('serial_numbers', response.trackable);
|
|
//clearField('serial_numbers');
|
|
}
|
|
}
|
|
);
|
|
},
|
|
}
|
|
],
|
|
}
|
|
)
|
|
}
|
|
|
|
|
|
function makeBuildOutputActionButtons(output, buildInfo) {
|
|
/* Generate action buttons for a build output.
|
|
*/
|
|
|
|
var buildId = buildInfo.pk;
|
|
var outputId = output.pk;
|
|
|
|
var panel = `#allocation-panel-${outputId}`;
|
|
|
|
function reloadTable() {
|
|
$(panel).find(`#allocation-table-${outputId}`).bootstrapTable('refresh');
|
|
}
|
|
|
|
// Find the div where the buttons will be displayed
|
|
var buildActions = $(panel).find(`#output-actions-${outputId}`);
|
|
|
|
var html = `<div class='btn-group float-right' role='group'>`;
|
|
|
|
// Add a button to "auto allocate" against the build
|
|
html += makeIconButton(
|
|
'fa-magic icon-blue', 'button-output-auto', outputId,
|
|
'{% trans "Auto-allocate stock items to this output" %}',
|
|
);
|
|
|
|
// Add a button to "complete" the particular build output
|
|
html += makeIconButton(
|
|
'fa-check icon-green', 'button-output-complete', outputId,
|
|
'{% trans "Complete build output" %}',
|
|
{
|
|
//disabled: true
|
|
}
|
|
);
|
|
|
|
// Add a button to "cancel" the particular build output (unallocate)
|
|
html += makeIconButton(
|
|
'fa-minus-circle icon-red', 'button-output-unallocate', outputId,
|
|
'{% trans "Unallocate stock from build output" %}',
|
|
);
|
|
|
|
// Add a button to "delete" the particular build output
|
|
html += makeIconButton(
|
|
'fa-trash-alt icon-red', 'button-output-delete', outputId,
|
|
'{% trans "Delete build output" %}',
|
|
);
|
|
|
|
// Add a button to "destroy" the particular build output (mark as damaged, scrap)
|
|
// TODO
|
|
|
|
html += '</div>';
|
|
|
|
buildActions.html(html);
|
|
|
|
// Add callbacks for the buttons
|
|
$(panel).find(`#button-output-auto-${outputId}`).click(function() {
|
|
// Launch modal dialog to perform auto-allocation
|
|
launchModalForm(`/build/${buildId}/auto-allocate/`,
|
|
{
|
|
data: {
|
|
output: outputId,
|
|
},
|
|
reload: true,
|
|
}
|
|
);
|
|
});
|
|
|
|
$(panel).find(`#button-output-complete-${outputId}`).click(function() {
|
|
launchModalForm(
|
|
`/build/${buildId}/complete-output/`,
|
|
{
|
|
success: reloadTable,
|
|
data: {
|
|
output: outputId,
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
$(panel).find(`#button-output-unallocate-${outputId}`).click(function() {
|
|
launchModalForm(
|
|
`/build/${buildId}/unallocate/`,
|
|
{
|
|
success: reloadTable,
|
|
data: {
|
|
output: outputId,
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
$(panel).find(`#button-output-delete-${outputId}`).click(function() {
|
|
launchModalForm(
|
|
`/build/${buildId}/delete-output/`,
|
|
{
|
|
reload: true,
|
|
data: {
|
|
output: outputId
|
|
}
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
|
|
function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|
/*
|
|
* Load the "allocation table" for a particular build output.
|
|
*
|
|
* Args:
|
|
* - buildId: The PK of the Build object
|
|
* - partId: The PK of the Part object
|
|
* - output: The StockItem object which is the "output" of the build
|
|
* - options:
|
|
* -- table: The #id of the table (will be auto-calculated if not provided)
|
|
*/
|
|
|
|
var buildId = buildInfo.pk;
|
|
var partId = buildInfo.part;
|
|
|
|
var outputId = null;
|
|
|
|
outputId = output.pk;
|
|
|
|
var table = options.table;
|
|
|
|
if (options.table == null) {
|
|
table = `#allocation-table-${outputId}`;
|
|
}
|
|
|
|
function reloadTable() {
|
|
// Reload the entire build allocation table
|
|
$(table).bootstrapTable('refresh');
|
|
}
|
|
|
|
function requiredQuantity(row) {
|
|
// Return the requied quantity for a given row
|
|
|
|
return row.quantity * output.quantity;
|
|
}
|
|
|
|
function sumAllocations(row) {
|
|
// Calculat total allocations for a given row
|
|
if (!row.allocations) {
|
|
return 0;
|
|
}
|
|
|
|
var quantity = 0;
|
|
|
|
row.allocations.forEach(function(item) {
|
|
quantity += item.quantity;
|
|
});
|
|
|
|
return quantity;
|
|
}
|
|
|
|
function setupCallbacks() {
|
|
// Register button callbacks once table data are loaded
|
|
|
|
// Callback for 'allocate' button
|
|
$(table).find(".button-add").click(function() {
|
|
|
|
// Primary key of the 'sub_part'
|
|
var pk = $(this).attr('pk');
|
|
|
|
// Launch form to allocate new stock against this output
|
|
launchModalForm("{% url 'build-item-create' %}", {
|
|
success: reloadTable,
|
|
data: {
|
|
part: pk,
|
|
build: buildId,
|
|
install_into: outputId,
|
|
},
|
|
secondary: [
|
|
{
|
|
field: 'stock_item',
|
|
label: '{% trans "New Stock Item" %}',
|
|
title: '{% trans "Create new Stock Item" %}',
|
|
url: '{% url "stock-item-create" %}',
|
|
data: {
|
|
part: pk,
|
|
},
|
|
},
|
|
],
|
|
callback: [
|
|
{
|
|
field: 'stock_item',
|
|
action: function(value) {
|
|
inventreeGet(
|
|
`/api/stock/${value}/`, {},
|
|
{
|
|
success: function(response) {
|
|
|
|
// How many items are actually available for the given stock item?
|
|
var available = response.quantity - response.allocated;
|
|
|
|
var field = getFieldByName('#modal-form', 'quantity');
|
|
|
|
// Allocation quantity initial value
|
|
var initial = field.attr('value');
|
|
|
|
if (available < initial) {
|
|
field.val(available);
|
|
}
|
|
}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
]
|
|
});
|
|
});
|
|
|
|
// Callback for 'build' button
|
|
$(table).find('.button-build').click(function() {
|
|
var pk = $(this).attr('pk');
|
|
|
|
// Extract row data from the table
|
|
var idx = $(this).closest('tr').attr('data-index');
|
|
var row = $(table).bootstrapTable('getData')[idx];
|
|
|
|
// Launch form to create a new build order
|
|
launchModalForm('{% url "build-create" %}', {
|
|
follow: true,
|
|
data: {
|
|
part: pk,
|
|
parent: buildId,
|
|
quantity: requiredQuantity(row) - sumAllocations(row),
|
|
}
|
|
});
|
|
});
|
|
|
|
// Callback for 'unallocate' button
|
|
$(table).find('.button-unallocate').click(function() {
|
|
var pk = $(this).attr('pk');
|
|
|
|
launchModalForm(`/build/${buildId}/unallocate/`,
|
|
{
|
|
success: reloadTable,
|
|
data: {
|
|
output: outputId,
|
|
part: pk,
|
|
}
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
// Load table of BOM items
|
|
$(table).inventreeTable({
|
|
url: "{% url 'api-bom-list' %}",
|
|
queryParams: {
|
|
part: partId,
|
|
sub_part_detail: true,
|
|
},
|
|
formatNoMatches: function() {
|
|
return '{% trans "No BOM items found" %}';
|
|
},
|
|
name: 'build-allocation',
|
|
uniqueId: 'sub_part',
|
|
onPostBody: setupCallbacks,
|
|
onLoadSuccess: function(tableData) {
|
|
// Once the BOM data are loaded, request allocation data for this build output
|
|
|
|
inventreeGet('/api/build/item/',
|
|
{
|
|
build: buildId,
|
|
output: outputId,
|
|
},
|
|
{
|
|
success: function(data) {
|
|
// Iterate through the returned data, and group by the part they point to
|
|
var allocations = {};
|
|
|
|
// Total number of line items
|
|
var totalLines = tableData.length;
|
|
|
|
// Total number of "completely allocated" lines
|
|
var allocatedLines = 0;
|
|
|
|
data.forEach(function(item) {
|
|
|
|
// Group BuildItem objects by part
|
|
var part = item.part;
|
|
var key = parseInt(part);
|
|
|
|
if (!(key in allocations)) {
|
|
allocations[key] = new Array();
|
|
}
|
|
|
|
allocations[key].push(item);
|
|
});
|
|
|
|
// Now update the allocations for each row in the table
|
|
for (var key in allocations) {
|
|
|
|
// Select the associated row in the table
|
|
var tableRow = $(table).bootstrapTable('getRowByUniqueId', key);
|
|
|
|
if (!tableRow) {
|
|
continue;
|
|
}
|
|
|
|
// Set the allocation list for that row
|
|
tableRow.allocations = allocations[key];
|
|
|
|
// Calculate the total allocated quantity
|
|
var allocatedQuantity = sumAllocations(tableRow);
|
|
|
|
// Is this line item fully allocated?
|
|
if (allocatedQuantity >= (tableRow.quantity * output.quantity)) {
|
|
allocatedLines += 1;
|
|
}
|
|
|
|
// Push the updated row back into the main table
|
|
$(table).bootstrapTable('updateByUniqueId', key, tableRow, true);
|
|
}
|
|
|
|
// Update the total progress for this build output
|
|
var buildProgress = $(`#allocation-panel-${outputId}`).find($(`#output-progress-${outputId}`));
|
|
|
|
var progress = makeProgressBar(
|
|
allocatedLines,
|
|
totalLines
|
|
);
|
|
|
|
buildProgress.html(progress);
|
|
|
|
// Update the available actions for this build output
|
|
|
|
makeBuildOutputActionButtons(output, buildInfo);
|
|
}
|
|
}
|
|
);
|
|
},
|
|
sortable: true,
|
|
showColumns: false,
|
|
detailViewByClick: true,
|
|
detailView: true,
|
|
detailFilter: function(index, row) {
|
|
return row.allocations != null;
|
|
},
|
|
detailFormatter: function(index, row, element) {
|
|
// Contruct an 'inner table' which shows which stock items have been allocated
|
|
|
|
var subTableId = `allocation-table-${row.pk}`;
|
|
|
|
var html = `<div class='sub-table'><table class='table table-condensed table-striped' id='${subTableId}'></table></div>`;
|
|
|
|
element.html(html);
|
|
|
|
var lineItem = row;
|
|
|
|
var subTable = $(`#${subTableId}`);
|
|
|
|
subTable.bootstrapTable({
|
|
data: row.allocations,
|
|
showHeader: true,
|
|
columns: [
|
|
{
|
|
width: '50%',
|
|
field: 'quantity',
|
|
title: '{% trans "Assigned Stock" %}',
|
|
formatter: function(value, row, index, field) {
|
|
var text = '';
|
|
|
|
var url = '';
|
|
|
|
if (row.serial && row.quantity == 1) {
|
|
text = `{% trans "Serial Number" %}: ${row.serial}`;
|
|
} else {
|
|
text = `{% trans "Quantity" %}: ${row.quantity}`;
|
|
}
|
|
|
|
{% if build.status == BuildStatus.COMPLETE %}
|
|
url = `/stock/item/${row.pk}/`;
|
|
{% else %}
|
|
url = `/stock/item/${row.stock_item}/`;
|
|
{% endif %}
|
|
|
|
return renderLink(text, url);
|
|
}
|
|
},
|
|
{
|
|
field: 'location',
|
|
title: '{% trans "Location" %}',
|
|
formatter: function(value, row, index, field) {
|
|
if (row.stock_item_detail.location) {
|
|
var text = row.stock_item_detail.location_name;
|
|
var url = `/stock/location/${row.stock_item_detail.location}/`;
|
|
|
|
return renderLink(text, url);
|
|
} else {
|
|
return '<i>{% trans "No location set" %}</i>';
|
|
}
|
|
}
|
|
},
|
|
{
|
|
field: 'actions',
|
|
formatter: function(value, row, index, field) {
|
|
/* Actions available for a particular stock item allocation:
|
|
*
|
|
* - Edit the allocation quantity
|
|
* - Delete the allocation
|
|
*/
|
|
|
|
var pk = row.pk;
|
|
|
|
var html = `<div class='btn-group float-right' role='group'>`;
|
|
|
|
html += makeIconButton('fa-edit icon-blue', 'button-allocation-edit', pk, '{% trans "Edit stock allocation" %}');
|
|
|
|
html += makeIconButton('fa-trash-alt icon-red', 'button-allocation-delete', pk, '{% trans "Delete stock allocation" %}');
|
|
|
|
html += `</div>`;
|
|
|
|
return html;
|
|
}
|
|
}
|
|
]
|
|
});
|
|
|
|
// Assign button callbacks to the newly created allocation buttons
|
|
subTable.find('.button-allocation-edit').click(function() {
|
|
var pk = $(this).attr('pk');
|
|
launchModalForm(`/build/item/${pk}/edit/`, {
|
|
success: reloadTable,
|
|
});
|
|
});
|
|
|
|
subTable.find('.button-allocation-delete').click(function() {
|
|
var pk = $(this).attr('pk');
|
|
launchModalForm(`/build/item/${pk}/delete/`, {
|
|
success: reloadTable,
|
|
});
|
|
});
|
|
},
|
|
columns: [
|
|
{
|
|
field: 'pk',
|
|
visible: false,
|
|
},
|
|
{
|
|
field: 'sub_part_detail.full_name',
|
|
title: '{% trans "Required Part" %}',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
var url = `/part/${row.sub_part}/`;
|
|
var thumb = row.sub_part_detail.thumbnail;
|
|
var name = row.sub_part_detail.full_name;
|
|
|
|
var html = imageHoverIcon(thumb) + renderLink(name, url);
|
|
|
|
html += makePartIcons(row.sub_part_detail);
|
|
|
|
return html;
|
|
}
|
|
},
|
|
{
|
|
field: 'reference',
|
|
title: '{% trans "Reference" %}',
|
|
sortable: true,
|
|
},
|
|
{
|
|
field: 'quantity',
|
|
title: '{% trans "Quantity Per" %}',
|
|
sortable: true,
|
|
},
|
|
{
|
|
field: 'sub_part_detail.stock',
|
|
title: '{% trans "Available" %}',
|
|
},
|
|
{
|
|
field: 'allocated',
|
|
title: '{% trans "Allocated" %}',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
var allocated = 0;
|
|
|
|
if (row.allocations) {
|
|
row.allocations.forEach(function(item) {
|
|
allocated += item.quantity;
|
|
});
|
|
}
|
|
|
|
var required = requiredQuantity(row);
|
|
|
|
return makeProgressBar(allocated, required);
|
|
},
|
|
sorter: function(valA, valB, rowA, rowB) {
|
|
var aA = sumAllocations(rowA);
|
|
var aB = sumAllocations(rowB);
|
|
|
|
var qA = rowA.quantity;
|
|
var qB = rowB.quantity;
|
|
|
|
qA *= output.quantity;
|
|
qB *= output.quantity;
|
|
|
|
// Handle the case where both numerators are zero
|
|
if ((aA == 0) && (aB == 0)) {
|
|
return (qA > qB) ? 1 : -1;
|
|
}
|
|
|
|
// Handle the case where either denominator is zero
|
|
if ((qA == 0) || (qB == 0)) {
|
|
return 1;
|
|
}
|
|
|
|
var progressA = parseFloat(aA) / qA;
|
|
var progressB = parseFloat(aB) / qB;
|
|
|
|
// Handle the case where both ratios are equal
|
|
if (progressA == progressB) {
|
|
return (qA < qB) ? 1 : -1;
|
|
}
|
|
|
|
return (progressA < progressB) ? 1 : -1;
|
|
}
|
|
},
|
|
{
|
|
field: 'actions',
|
|
title: '{% trans "Actions" %}',
|
|
formatter: function(value, row, index, field) {
|
|
// Generate action buttons for this build output
|
|
var html = `<div class='btn-group float-right' role='group'>`;
|
|
|
|
if (sumAllocations(row) < requiredQuantity(row)) {
|
|
if (row.sub_part_detail.assembly) {
|
|
html += makeIconButton('fa-tools icon-blue', 'button-build', row.sub_part, '{% trans "Build stock" %}');
|
|
}
|
|
|
|
if (row.sub_part_detail.purchaseable) {
|
|
html += makeIconButton('fa-shopping-cart icon-blue', 'button-buy', row.sub_part, '{% trans "Order stock" %}', {disabled: true});
|
|
}
|
|
|
|
html += makeIconButton('fa-sign-in-alt icon-green', 'button-add', row.sub_part, '{% trans "Allocate stock" %}');
|
|
}
|
|
|
|
html += makeIconButton(
|
|
'fa-minus-circle icon-red', 'button-unallocate', row.sub_part,
|
|
'{% trans "Unallocate stock" %}',
|
|
{
|
|
disabled: row.allocations == null
|
|
}
|
|
);
|
|
|
|
html += '</div>';
|
|
|
|
return html;
|
|
}
|
|
},
|
|
]
|
|
});
|
|
}
|
|
|
|
|
|
function loadBuildTable(table, options) {
|
|
// Display a table of Build objects
|
|
|
|
var params = options.params || {};
|
|
|
|
var filters = {};
|
|
|
|
if (!options.disableFilters) {
|
|
loadTableFilters("build");
|
|
}
|
|
|
|
for (var key in params) {
|
|
filters[key] = params[key];
|
|
}
|
|
|
|
setupFilterList("build", table);
|
|
|
|
$(table).inventreeTable({
|
|
method: 'get',
|
|
formatNoMatches: function() {
|
|
return '{% trans "No builds matching query" %}';
|
|
},
|
|
url: options.url,
|
|
queryParams: filters,
|
|
groupBy: false,
|
|
name: 'builds',
|
|
original: params,
|
|
columns: [
|
|
{
|
|
field: 'pk',
|
|
title: 'ID',
|
|
visible: false,
|
|
switchable: false,
|
|
},
|
|
{
|
|
field: 'reference',
|
|
title: '{% trans "Build" %}',
|
|
sortable: true,
|
|
switchable: false,
|
|
formatter: function(value, row, index, field) {
|
|
|
|
var prefix = "{% settings_value 'BUILDORDER_REFERENCE_PREFIX' %}";
|
|
|
|
if (prefix) {
|
|
value = `${prefix}${value}`;
|
|
}
|
|
|
|
return renderLink(value, '/build/' + row.pk + '/');
|
|
}
|
|
},
|
|
{
|
|
field: 'title',
|
|
title: '{% trans "Description" %}',
|
|
sortable: true,
|
|
},
|
|
{
|
|
field: 'part',
|
|
title: '{% trans "Part" %}',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
|
|
var name = row.part_detail.full_name;
|
|
|
|
return imageHoverIcon(row.part_detail.thumbnail) + renderLink(name, '/part/' + row.part + '/');
|
|
}
|
|
},
|
|
{
|
|
field: 'quantity',
|
|
title: '{% trans "Quantity" %}',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
return makeProgressBar(
|
|
row.completed,
|
|
row.quantity,
|
|
{
|
|
style: 'max',
|
|
}
|
|
);
|
|
}
|
|
},
|
|
{
|
|
field: 'status',
|
|
title: '{% trans "Status" %}',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
return buildStatusDisplay(value);
|
|
},
|
|
},
|
|
{
|
|
field: 'creation_date',
|
|
title: '{% trans "Created" %}',
|
|
sortable: true,
|
|
},
|
|
{
|
|
field: 'completion_date',
|
|
title: '{% trans "Completed" %}',
|
|
sortable: true,
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
|
|
function updateAllocationTotal(id, count, required) {
|
|
|
|
count = parseFloat(count);
|
|
|
|
$('#allocation-total-'+id).html(count);
|
|
|
|
var el = $("#allocation-panel-" + id);
|
|
el.removeClass('part-allocation-pass part-allocation-underallocated part-allocation-overallocated');
|
|
|
|
if (count < required) {
|
|
el.addClass('part-allocation-underallocated');
|
|
} else if (count > required) {
|
|
el.addClass('part-allocation-overallocated');
|
|
} else {
|
|
el.addClass('part-allocation-pass');
|
|
}
|
|
}
|
|
|
|
function loadAllocationTable(table, part_id, part, url, required, button) {
|
|
|
|
// Load the allocation table
|
|
table.bootstrapTable({
|
|
url: url,
|
|
sortable: false,
|
|
formatNoMatches: function() { return '{% trans "No parts allocated for" %} ' + part; },
|
|
columns: [
|
|
{
|
|
field: 'stock_item_detail',
|
|
title: '{% trans "Stock Item" %}',
|
|
formatter: function(value, row, index, field) {
|
|
return '' + parseFloat(value.quantity) + ' x ' + value.part_name + ' @ ' + value.location_name;
|
|
}
|
|
},
|
|
{
|
|
field: 'stock_item_detail.quantity',
|
|
title: '{% trans "Available" %}',
|
|
formatter: function(value, row, index, field) {
|
|
return parseFloat(value);
|
|
}
|
|
},
|
|
{
|
|
field: 'quantity',
|
|
title: '{% trans "Allocated" %}',
|
|
formatter: function(value, row, index, field) {
|
|
var html = parseFloat(value);
|
|
|
|
var bEdit = "<button class='btn item-edit-button btn-sm' type='button' title='{% trans "Edit stock allocation" %}' url='/build/item/" + row.pk + "/edit/'><span class='fas fa-edit'></span></button>";
|
|
var bDel = "<button class='btn item-del-button btn-sm' type='button' title='{% trans "Delete stock allocation" %}' url='/build/item/" + row.pk + "/delete/'><span class='fas fa-trash-alt icon-red'></span></button>";
|
|
|
|
html += "<div class='btn-group' style='float: right;'>" + bEdit + bDel + "</div>";
|
|
|
|
return html;
|
|
}
|
|
}
|
|
],
|
|
});
|
|
|
|
// Callback for 'new-item' button
|
|
button.click(function() {
|
|
launchModalForm(button.attr('url'), {
|
|
success: function() {
|
|
table.bootstrapTable('refresh');
|
|
},
|
|
});
|
|
});
|
|
|
|
table.on('load-success.bs.table', function(data) {
|
|
// Extract table data
|
|
var results = table.bootstrapTable('getData');
|
|
|
|
var count = 0;
|
|
|
|
for (var i = 0; i < results.length; i++) {
|
|
count += parseFloat(results[i].quantity);
|
|
}
|
|
|
|
updateAllocationTotal(part_id, count, required);
|
|
});
|
|
|
|
// Button callbacks for editing and deleting the allocations
|
|
table.on('click', '.item-edit-button', function() {
|
|
var button = $(this);
|
|
|
|
launchModalForm(button.attr('url'), {
|
|
success: function() {
|
|
table.bootstrapTable('refresh');
|
|
}
|
|
});
|
|
});
|
|
|
|
table.on('click', '.item-del-button', function() {
|
|
var button = $(this);
|
|
|
|
launchModalForm(button.attr('url'), {
|
|
success: function() {
|
|
table.bootstrapTable('refresh');
|
|
}
|
|
});
|
|
});
|
|
|
|
} |