define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { var Controller = { index: function () { Table.api.init({ extend: { index_url: 'split.ticket/index' + location.search, add_url: 'split.ticket/add', edit_url: 'split.ticket/edit', del_url: 'split.ticket/del', multi_url: 'split.ticket/multi', table: 'split_ticket', } }); var table = $("#table"); table.bootstrapTable({ url: $.fn.bootstrapTable.defaults.extend.index_url, pk: 'id', sortName: 'id', sortOrder: 'desc', fixedColumns: true, fixedRightNumber: 1, columns: [ [ {checkbox: true}, { field: 'ticket_type', title: __('Ticket_type'), searchList: Config.ticketTypeList, operate: false, formatter: Controller.api.formatter.ticketTypePlain }, {field: 'ticket_name', title: __('Ticket_name'), operate: 'LIKE'}, { field: 'link_code_text', title: __('Split_link_id'), operate: false, formatter: Controller.api.formatter.splitLinkCode }, { field: 'start_time_text', title: __('Start_time'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, sortable: true }, { field: 'end_time_text', title: __('End_time'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, sortable: true }, {field: 'order_limit', title: __('Order_limit'), operate: false}, {field: 'assign_ratio', title: __('Assign_ratio'), operate: false}, {field: 'ticket_total', title: __('Ticket_total'), operate: false, sortable: true}, {field: 'complete_count', title: __('Complete_count'), operate: false, sortable: true}, { field: 'ticket_progress_text', title: __('Ticket_progress'), operate: false, formatter: Table.api.formatter.content }, { field: 'inbound_ratio_text', title: __('Inbound_ratio'), operate: false, formatter: Table.api.formatter.content }, { field: 'speed_per_hour', title: __('Speed_per_hour'), operate: false, formatter: Controller.api.formatter.speedPerHour }, { field: 'number_count', title: __('Number_count'), operate: false, formatter: Controller.api.formatter.numberCount }, { field: 'sync_display_text', title: __('Sync_status'), operate: false, formatter: Controller.api.formatter.syncDisplay }, { field: 'status', title: __('Status'), searchList: Config.statusList, formatter: Table.api.formatter.toggle, yes: 'normal', no: 'hidden' }, { field: 'createtime', title: __('Createtime'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, formatter: Table.api.formatter.datetime, sortable: true }, { field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate } ] ] }); Table.api.bindevent(table); Controller.api.syncingTicketIds = []; window.__splitTicketPendingPostAddSyncIds = window.__splitTicketPendingPostAddSyncIds || []; table.on('load-success.bs.table', function () { var pendingIds = window.__splitTicketPendingPostAddSyncIds; if (!pendingIds || !pendingIds.length) { return; } window.__splitTicketPendingPostAddSyncIds = []; Controller.api.startBackgroundSync(table, pendingIds, false); }); table.on('check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table', function () { var ids = Table.api.selectedids(table); $('.btn-sync').toggleClass('btn-disabled disabled', ids.length === 0); }); $('.btn-sync').on('click', function (e) { e.preventDefault(); e.stopPropagation(); var ids = Table.api.selectedids(table); if (!ids.length) { Toastr.error(__('Please select at least one record')); return false; } var syncConfirmMsg = (typeof Config.syncConfirmMsg !== 'undefined' && Config.syncConfirmMsg) ? Config.syncConfirmMsg : '确定同步所选工单吗?任务将在后台执行,完成后自动提示结果。'; var syncBackgroundMsg = (typeof Config.syncBackgroundStartedMsg !== 'undefined' && Config.syncBackgroundStartedMsg) ? Config.syncBackgroundStartedMsg : '同步任务已在后台执行,请稍候…'; Layer.confirm(syncConfirmMsg, {icon: 3, title: __('Sync_status_btn')}, function (index) { Layer.close(index); Toastr.info(syncBackgroundMsg); Controller.api.startBackgroundSync(table, ids, true); }); return false; }); }, add: function () { Form.api.bindevent($('form[role=form]'), function (data, ret) { var ticketId = ret.data && ret.data.id ? parseInt(ret.data.id, 10) : 0; var syncTicketMsg = (typeof Config.syncTicketStartedMsg !== 'undefined' && Config.syncTicketStartedMsg) ? Config.syncTicketStartedMsg : '正在同步工单'; if (ticketId > 0) { parent.__splitTicketPendingPostAddSyncIds = parent.__splitTicketPendingPostAddSyncIds || []; parent.__splitTicketPendingPostAddSyncIds.push(ticketId); } if (parent && parent.Toastr) { parent.Toastr.info(syncTicketMsg); } parent.$('.btn-refresh').trigger('click'); if (window.name) { var layerIndex = parent.Layer.getFrameIndex(window.name); parent.Layer.close(layerIndex); } return false; }); Controller.api.fixSelectPlaceholder(); Controller.api.bindNumberTypeToggle(); Controller.api.bindEndTimeCheck(); }, edit: function () { Controller.api.bindevent(); }, api: { /** @type {number[]} 正在手动同步的工单 ID */ syncingTicketIds: [], /** * 后台同步:标记「同步中」并请求 sync 接口 * * @param {object} table bootstrapTable 实例 * @param {number[]} ids 工单 ID * @param {boolean} disableSyncBtn 是否禁用工具栏同步按钮 */ startBackgroundSync: function (table, ids, disableSyncBtn) { ids = (ids || []).map(function (id) { return parseInt(id, 10); }).filter(function (id) { return !isNaN(id) && id > 0; }); if (!ids.length) { return; } Controller.api.markTicketsSyncing(table, ids); if (disableSyncBtn) { $('.btn-sync').addClass('btn-disabled disabled'); } Fast.api.ajax({ url: 'split.ticket/sync', data: {ids: ids.join(',')}, loading: false }, function () { Controller.api.finishTicketsSync(table); }, function () { Controller.api.finishTicketsSync(table); }); }, /** * 将选中工单标记为「同步中」并刷新列表展示(不请求后端) */ markTicketsSyncing: function (table, ids) { Controller.api.syncingTicketIds = (ids || []).map(function (id) { return parseInt(id, 10); }).filter(function (id) { return !isNaN(id) && id > 0; }); var data = table.bootstrapTable('getData'); table.bootstrapTable('load', data); }, /** * 同步结束:清除标记并刷新列表数据 */ finishTicketsSync: function (table) { Controller.api.syncingTicketIds = []; table.bootstrapTable('refresh'); var ids = Table.api.selectedids(table); $('.btn-sync').toggleClass('btn-disabled disabled', ids.length === 0); }, formatter: { /** * 工单类型:纯文本展示,无链接/标签样式 */ ticketTypePlain: function (value, row) { var text = row.ticket_type_text != null && row.ticket_type_text !== '' ? String(row.ticket_type_text) : (value != null ? String(value) : ''); if (text === '') { return '-'; } return '' + Fast.api.escape(text) + ''; }, /** * 分流链接:纯文本 + 边框背景标记,不可点击 */ splitLinkCode: function (value) { value = value == null ? '' : String(value); if ($.trim(value) === '') { return '-'; } var safe = Fast.api.escape(value); return '' + safe + ''; }, speedPerHour: function (value) { var num = parseFloat(value); if (isNaN(num)) { return '0.00'; } return num.toFixed(2); }, numberCount: function (value, row) { var total = parseInt(value, 10) || 0; var offline = parseInt(row.number_offline_count, 10) || 0; var banned = parseInt(row.number_banned_count, 10) || 0; var tip = __('Number_count_detail').replace('%s', offline).replace('%s', banned); if (offline > 0 || banned > 0) { return '' + total + ''; } return String(total); }, syncDisplay: function (value, row) { var rowId = parseInt(row.id, 10); if (Controller.api.syncingTicketIds.indexOf(rowId) !== -1) { return Controller.api.formatter.syncingDisplayHtml(); } var text = value || ''; var color = 'danger'; if (row.sync_status === 'success') { color = 'success'; } else if (row.sync_status === 'pending') { color = 'muted'; } return '' + Fast.api.escape(text) + ''; }, syncingDisplayHtml: function () { var label = (typeof Config.syncInProgressMsg !== 'undefined' && Config.syncInProgressMsg) ? Config.syncInProgressMsg : '同步中'; return '' + '' + '' + Fast.api.escape(label) + '' + ''; } }, bindevent: function () { Form.api.bindevent($('form[role=form]')); Controller.api.fixSelectPlaceholder(); Controller.api.bindNumberTypeToggle(); Controller.api.bindEndTimeCheck(); }, /** * selectpicker 空选项文案改为中文「请选择」 */ fixSelectPlaceholder: function () { var text = __('Please select'); if (!text || text === 'Please select' || text === 'Please Select') { text = '请选择'; } $('#c-ticket_type, #c-split_link_id').each(function () { var $el = $(this); $el.attr({'data-none-selected-text': text, 'title': text}); $el.find('option[value=""]').first().text(text); if ($el.data('selectpicker')) { $el.selectpicker('render'); } }); }, /** * 号码类型为 custom 时显示自定义输入框 */ bindNumberTypeToggle: function () { var $type = $('#c-number_type'); var $wrap = $('.split-number-type-custom'); var $custom = $('#c-number_type_custom'); if (!$type.length) { return; } var toggle = function () { var val = $type.val(); if (val === 'custom') { $wrap.removeClass('hide'); $custom.attr('data-rule', 'required'); } else { $wrap.addClass('hide'); $custom.removeAttr('data-rule'); $custom.val(''); } if ($custom.data('validator')) { $custom.trigger('validate'); } }; $type.on('changed.bs.select change', toggle); toggle(); }, /** * 前端预校验:到期时间须晚于开始时间(后端为准) */ bindEndTimeCheck: function () { var $form = $('form[role=form]'); var $start = $('#c-start_time'); var $end = $('#c-end_time'); if (!$start.length || !$end.length) { return; } var parseTs = function (str) { str = $.trim(str || ''); if (!str) { return 0; } var d = new Date(str.replace(/-/g, '/')); return isNaN(d.getTime()) ? 0 : Math.floor(d.getTime() / 1000); }; $form.on('submit', function (e) { var s = parseTs($start.val()); var en = parseTs($end.val()); if (s > 0 && en > 0 && en <= s) { e.preventDefault(); e.stopImmediatePropagation(); Layer.msg(__('End time must after start')); return false; } }); } } }; return Controller; });