| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- $(document).ready(function() {
- autoFlashHeight();
- const RangeType = {
- unitType: 1,
- unit: 2,
- user: 3,
- };
- const typeIndex = {};
- const unitIndex = {};
- const userIndex = {};
- dataRangeTree.forEach(type => {
- typeIndex[Number(type.id)] = type;
- type.units.forEach(unit => {
- unit.parentTypeId = Number(type.id);
- unitIndex[Number(unit.id)] = unit;
- unit.users.forEach(user => {
- user.parentTypeId = Number(type.id);
- user.parentUnitId = Number(unit.id);
- userIndex[Number(user.id)] = user;
- });
- });
- });
- dataRangeUnassignedUsers.forEach(user => {
- user.parentTypeId = Number(user.account_group) || 0;
- userIndex[Number(user.id)] = user;
- });
- const makeSelection = function(config) {
- return {
- unitTypeIds: new Set((config.unit_type_ids || []).map(Number)),
- unitIds: new Set((config.unit_ids || []).map(Number)),
- userIds: new Set((config.user_ids || []).map(Number)),
- };
- };
- const cloneSelection = function(source) {
- return {
- unitTypeIds: new Set(Array.from(source.unitTypeIds)),
- unitIds: new Set(Array.from(source.unitIds)),
- userIds: new Set(Array.from(source.userIds)),
- };
- };
- let savedSelection = makeSelection(dataRangeConfig);
- let savedConfigured = Boolean(dataRangeConfig.configured);
- let currentSelection = cloneSelection(savedSelection);
- const escapeHtml = function(value) {
- return $('<div>').text(value === undefined || value === null ? '' : value).html();
- };
- const containsKeyword = function(value, keyword) {
- return !keyword || String(value || '').toLowerCase().indexOf(keyword) >= 0;
- };
- const getSelectionSet = function(rangeType) {
- if (rangeType === RangeType.unitType) return currentSelection.unitTypeIds;
- if (rangeType === RangeType.unit) return currentSelection.unitIds;
- return currentSelection.userIds;
- };
- const getSelectionSetFrom = function(selection, rangeType) {
- if (rangeType === RangeType.unitType) return selection.unitTypeIds;
- if (rangeType === RangeType.unit) return selection.unitIds;
- return selection.userIds;
- };
- const getRangeName = function(rangeType, targetId) {
- let node;
- if (rangeType === RangeType.unitType) node = typeIndex[targetId];
- if (rangeType === RangeType.unit) node = unitIndex[targetId];
- if (rangeType === RangeType.user) node = userIndex[targetId];
- return node ? node.name : '';
- };
- const getRangeTitle = function(rangeType) {
- if (rangeType === RangeType.unitType) return '单位类型';
- if (rangeType === RangeType.unit) return '单位';
- return '用户';
- };
- const removeTypeDescendants = function(typeId) {
- const type = typeIndex[typeId];
- if (!type) return;
- type.units.forEach(unit => {
- currentSelection.unitIds.delete(Number(unit.id));
- unit.users.forEach(user => currentSelection.userIds.delete(Number(user.id)));
- });
- dataRangeUnassignedUsers.forEach(user => {
- if (Number(user.parentTypeId) === Number(typeId)) currentSelection.userIds.delete(Number(user.id));
- });
- };
- const removeUnitDescendants = function(unitId) {
- const unit = unitIndex[unitId];
- if (!unit) return;
- unit.users.forEach(user => currentSelection.userIds.delete(Number(user.id)));
- };
- const renderCheckbox = function(rangeType, targetId, disabled) {
- const checked = getSelectionSet(rangeType).has(Number(targetId)) ? ' checked' : '';
- const disabledAttr = disabled ? ' disabled' : '';
- return `<input type="checkbox" class="mr-1 data-range-check" data-range-type="${rangeType}" data-target-id="${targetId}"${checked}${disabledAttr}>`;
- };
- const renderNode = function(options) {
- const indent = options.level * 20;
- const toggle = options.hasChildren
- ? '<span class="data-range-toggle"><i class="fa fa-caret-down"></i></span>'
- : '<span class="data-range-toggle empty"></span>';
- const checkbox = options.selectable === false ? '' : renderCheckbox(options.rangeType, options.targetId, options.disabled);
- const icon = options.rangeType === RangeType.user
- ? '<i class="fa fa-user text-warning mr-1"></i>'
- : '<i class="fa fa-folder text-warning mr-1"></i>';
- const extra = options.extra ? ` <small class="text-muted">${escapeHtml(options.extra)}</small>` : '';
- return `<div class="data-range-node" style="padding-left:${indent}px">${toggle}${checkbox}${icon}<span>${escapeHtml(options.name)}</span>${extra}</div>`;
- };
- const renderTree = function() {
- const keyword = $('#data-range-keyword').val().trim().toLowerCase();
- const html = [];
- dataRangeTree.forEach(type => {
- const typeMatch = containsKeyword(type.name, keyword);
- const visibleUnits = [];
- type.units.forEach(unit => {
- const unitMatch = containsKeyword(unit.name, keyword);
- const users = typeMatch || unitMatch ? unit.users : unit.users.filter(user => {
- return containsKeyword(user.name, keyword) || containsKeyword(user.role, keyword);
- });
- if (!keyword || typeMatch || unitMatch || users.length > 0) visibleUnits.push({ unit, users });
- });
- if (keyword && !typeMatch && visibleUnits.length === 0) return;
- html.push('<div class="data-range-tree-group">');
- html.push(renderNode({
- level: 0,
- hasChildren: visibleUnits.length > 0,
- rangeType: RangeType.unitType,
- targetId: Number(type.id),
- name: type.name,
- }));
- html.push('<div class="data-range-children">');
- visibleUnits.forEach(item => {
- const typeSelected = currentSelection.unitTypeIds.has(Number(type.id));
- html.push('<div class="data-range-tree-group">');
- html.push(renderNode({
- level: 1,
- hasChildren: item.users.length > 0,
- rangeType: RangeType.unit,
- targetId: Number(item.unit.id),
- name: item.unit.name,
- disabled: typeSelected,
- }));
- html.push('<div class="data-range-children">');
- item.users.forEach(user => {
- const unitSelected = currentSelection.unitIds.has(Number(item.unit.id));
- html.push(renderNode({
- level: 2,
- hasChildren: false,
- rangeType: RangeType.user,
- targetId: Number(user.id),
- name: user.name,
- extra: user.role,
- disabled: typeSelected || unitSelected,
- }));
- });
- html.push('</div></div>');
- });
- html.push('</div></div>');
- });
- const otherUsers = keyword ? dataRangeUnassignedUsers.filter(user => {
- return containsKeyword(user.name, keyword) || containsKeyword(user.company, keyword) || containsKeyword(user.role, keyword);
- }) : dataRangeUnassignedUsers;
- if (otherUsers.length > 0) {
- html.push('<div class="data-range-tree-group">');
- html.push(renderNode({ level: 0, hasChildren: true, selectable: false, name: '未关联单位用户' }));
- html.push('<div class="data-range-children">');
- otherUsers.forEach(user => {
- const typeSelected = currentSelection.unitTypeIds.has(Number(user.parentTypeId));
- html.push(renderNode({
- level: 1,
- hasChildren: false,
- rangeType: RangeType.user,
- targetId: Number(user.id),
- name: user.name,
- extra: user.company || user.role,
- disabled: typeSelected,
- }));
- });
- html.push('</div></div>');
- }
- if (html.length === 0) html.push('<div class="text-muted text-center py-4">没有匹配的数据</div>');
- $('#data-range-tree').html(html.join(''));
- };
- const renderSelected = function() {
- const html = [];
- const appendItems = function(rangeType, ids) {
- Array.from(ids).sort((a, b) => a - b).forEach(targetId => {
- html.push('<div class="data-range-selected-item d-flex align-items-center">');
- html.push(`<span class="badge badge-light mr-2">${getRangeTitle(rangeType)}</span>`);
- html.push(`<span>${escapeHtml(getRangeName(rangeType, targetId))}</span>`);
- html.push(`<a href="javascript:void(0);" class="ml-auto text-danger remove-data-range" data-range-type="${rangeType}" data-target-id="${targetId}" title="移除"><i class="fa fa-times"></i></a>`);
- html.push('</div>');
- });
- };
- appendItems(RangeType.unitType, currentSelection.unitTypeIds);
- appendItems(RangeType.unit, currentSelection.unitIds);
- appendItems(RangeType.user, currentSelection.userIds);
- const total = currentSelection.unitTypeIds.size + currentSelection.unitIds.size + currentSelection.userIds.size;
- if (total === 0) html.push('<div class="text-muted text-center py-4">暂未选择范围</div>');
- $('#data-range-selected-count').text(total);
- $('#selected-unit-type-count').text(currentSelection.unitTypeIds.size);
- $('#selected-unit-count').text(currentSelection.unitIds.size);
- $('#selected-user-count').text(currentSelection.userIds.size);
- $('#data-range-selected-list').html(html.join(''));
- };
- const renderSummary = function() {
- if (!savedConfigured) {
- $('#data-range-summary').text('当前未配置数据范围,默认可选择当前子项目全部启用成员。');
- return;
- }
- $('#data-range-summary').text(
- `已设置:单位类型 ${savedSelection.unitTypeIds.size} 项,单位 ${savedSelection.unitIds.size} 项,具体用户 ${savedSelection.userIds.size} 项。`
- );
- };
- const renderMainSelection = function() {
- const html = [];
- const appendItems = function(rangeType, ids) {
- Array.from(ids).sort((a, b) => a - b).forEach(targetId => {
- const rangeName = getRangeName(rangeType, targetId);
- if (!rangeName) return;
- html.push(`<span class="data-range-value-item" title="${escapeHtml(getRangeTitle(rangeType))}">`);
- html.push(`<span class="data-range-value-name">${escapeHtml(rangeName)}</span>`);
- html.push(`<a href="javascript:void(0);" class="remove-main-data-range" data-range-type="${rangeType}" data-target-id="${targetId}" title="移除${escapeHtml(rangeName)}" aria-label="移除${escapeHtml(rangeName)}"><i class="fa fa-times"></i></a>`);
- html.push('</span>');
- });
- };
- appendItems(RangeType.unitType, savedSelection.unitTypeIds);
- appendItems(RangeType.unit, savedSelection.unitIds);
- appendItems(RangeType.user, savedSelection.userIds);
- $('#data-range-value-list').html(html.join(''));
- };
- const selectionToRanges = function(selection) {
- const ranges = [];
- const appendRanges = function(rangeType, ids) {
- ids.forEach(targetId => ranges.push({ range_type: rangeType, target_id: targetId }));
- };
- appendRanges(RangeType.unitType, selection.unitTypeIds);
- appendRanges(RangeType.unit, selection.unitIds);
- appendRanges(RangeType.user, selection.userIds);
- return ranges;
- };
- let saving = false;
- const saveSelection = function(selection, successCallback) {
- if (saving) return;
- saving = true;
- $('#save-data-range').prop('disabled', true);
- postData(`/sp/${dataRangeSpid}/setting/user/data-range/update`, {
- module_key: dataRangeModuleKey,
- ranges: selectionToRanges(selection),
- }, function(result) {
- const config = result || {
- configured: selectionToRanges(selection).length > 0,
- unit_type_ids: Array.from(selection.unitTypeIds),
- unit_ids: Array.from(selection.unitIds),
- user_ids: Array.from(selection.userIds),
- };
- savedSelection = makeSelection(config);
- savedConfigured = Boolean(config.configured);
- saving = false;
- $('#save-data-range').prop('disabled', false);
- renderMainSelection();
- renderSummary();
- if (successCallback) successCallback();
- }, function() {
- saving = false;
- $('#save-data-range').prop('disabled', false);
- });
- };
- const refreshModal = function() {
- renderTree();
- renderSelected();
- };
- $('#open-data-range-modal').on('click keydown', function(event) {
- if ($(event.target).closest('.remove-main-data-range').length > 0) return;
- if (event.type === 'keydown' && event.keyCode !== 13 && event.keyCode !== 32) return;
- event.preventDefault();
- currentSelection = cloneSelection(savedSelection);
- $('#data-range-keyword').val('');
- refreshModal();
- $('#data-range-modal').modal('show');
- });
- $('body').on('click', '.remove-main-data-range', function(event) {
- event.preventDefault();
- event.stopPropagation();
- if (saving) return;
- const rangeType = Number($(this).attr('data-range-type'));
- const targetId = Number($(this).attr('data-target-id'));
- const nextSelection = cloneSelection(savedSelection);
- getSelectionSetFrom(nextSelection, rangeType).delete(targetId);
- saveSelection(nextSelection, function() {
- toastr.success('授权用户范围已移除');
- });
- });
- $('#data-range-search').click(renderTree);
- $('#data-range-keyword').on('keydown', function(event) {
- if (event.keyCode === 13) {
- event.preventDefault();
- renderTree();
- }
- });
- $('#data-range-keyword').on('input', renderTree);
- $('body').on('click', '.data-range-toggle:not(.empty)', function() {
- const children = $(this).parent().next('.data-range-children');
- children.toggleClass('collapsed');
- $('i', this).toggleClass('fa-caret-down fa-caret-right');
- });
- $('body').on('change', '.data-range-check', function() {
- const rangeType = Number($(this).attr('data-range-type'));
- const targetId = Number($(this).attr('data-target-id'));
- const selection = getSelectionSet(rangeType);
- if (this.checked) {
- selection.add(targetId);
- if (rangeType === RangeType.unitType) removeTypeDescendants(targetId);
- if (rangeType === RangeType.unit) removeUnitDescendants(targetId);
- } else {
- selection.delete(targetId);
- }
- refreshModal();
- });
- $('body').on('click', '.remove-data-range', function() {
- const rangeType = Number($(this).attr('data-range-type'));
- const targetId = Number($(this).attr('data-target-id'));
- getSelectionSet(rangeType).delete(targetId);
- refreshModal();
- });
- $('#save-data-range').click(function() {
- saveSelection(currentSelection, function() {
- $('#data-range-modal').modal('hide');
- toastr.success('数据范围保存成功');
- });
- });
- renderMainSelection();
- renderSummary();
- });
|