diff --git a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java index 25b023081a..77b17ba08f 100644 --- a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java +++ b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java @@ -558,6 +558,12 @@ public class ChartViewService { return data; } + public Boolean containDetailField(ChartViewDTO view) { + List detailFieldViewTypes = new ArrayList<>(); + detailFieldViewTypes.add("map"); + return detailFieldViewTypes.contains(view.getType()); + } + public ChartViewDTO calcData(ChartViewDTO view, ChartExtRequest chartExtRequest, boolean cache) throws Exception { ChartViewDTO chartViewDTO = new ChartViewDTO(); if (ObjectUtils.isEmpty(view)) { @@ -906,6 +912,9 @@ public class ChartViewService { pageInfo.setGoPage(chartExtRequest.getGoPage()); pageInfo.setPageSize(chartExtRequest.getPageSize()); + List detailFieldList = new ArrayList<>(); + String detailFieldSql = null; + List detailData = new ArrayList<>(); //如果不是插件视图 走原生逻辑 if (table.getMode() == 0) {// 直连 if (ObjectUtils.isEmpty(ds)) { @@ -931,6 +940,11 @@ public class ChartViewService { totalPageSql = qp.getResultCount(true, dataTableInfoDTO.getTable(), xAxis, fieldCustomFilter, rowPermissionsTree, extFilterList, ds, view); } else { querySql = qp.getSQL(dataTableInfoDTO.getTable(), xAxis, yAxis, fieldCustomFilter, rowPermissionsTree, extFilterList, ds, view); + if (containDetailField(view) && CollectionUtils.isNotEmpty(viewFields)) { + detailFieldList.addAll(xAxis); + detailFieldList.addAll(viewFields); + detailFieldSql = qp.getSQLWithPage(true, dataTableInfoDTO.getTable(), detailFieldList, fieldCustomFilter, rowPermissionsTree, extFilterList, ds, view, pageInfo); + } } } else if (StringUtils.equalsIgnoreCase(table.getType(), DatasetType.SQL.name())) { String sql = dataTableInfoDTO.isBase64Encryption() ? new String(java.util.Base64.getDecoder().decode(dataTableInfoDTO.getSql())) : dataTableInfoDTO.getSql(); @@ -994,6 +1008,11 @@ public class ChartViewService { logger.info(datasourceAssistRequest.getQuery()); assistData = datasourceProvider.getData(datasourceAssistRequest); } + + if (StringUtils.isNotBlank(detailFieldSql)) { + datasourceRequest.setQuery(detailFieldSql); + detailData = datasourceProvider.getData(datasourceRequest); + } } else if (table.getMode() == 1) {// 抽取 // 连接doris,构建doris数据源查询 datasourceRequest.setDatasource(ds); @@ -1200,6 +1219,9 @@ public class ChartViewService { } // table组件,明细表,也用于导出数据 Map mapTableNormal = ChartDataBuild.transTableNormal(xAxis, yAxis, view, data, extStack, desensitizationList); + if (CollectionUtils.isNotEmpty(detailData)) { + mapTableNormal = ChartDataBuild.transTableNormalWithDetail(xAxis, yAxis, data, detailFieldList, detailData, desensitizationList); + } chartViewDTO = uniteViewResult(datasourceRequest.getQuery(), mapChart, mapTableNormal, view, isDrill, drillFilters, dynamicAssistFields, assistData); chartViewDTO.setTotalPage(totalPage); chartViewDTO.setTotalItems(totalItems); diff --git a/backend/src/main/java/io/dataease/service/chart/util/ChartDataBuild.java b/backend/src/main/java/io/dataease/service/chart/util/ChartDataBuild.java index 71e32cb73f..9ac2538320 100644 --- a/backend/src/main/java/io/dataease/service/chart/util/ChartDataBuild.java +++ b/backend/src/main/java/io/dataease/service/chart/util/ChartDataBuild.java @@ -1,5 +1,6 @@ package io.dataease.service.chart.util; +import cn.hutool.core.util.ArrayUtil; import io.dataease.plugins.common.base.domain.ChartViewWithBLOBs; import io.dataease.dto.chart.*; import io.dataease.plugins.common.dto.chart.ChartViewFieldDTO; @@ -952,6 +953,46 @@ public class ChartDataBuild { return transTableNormal(fields, view, data, desensitizationList); } + public static Map transTableNormalWithDetail(List xAxis, List yAxis, List data, List detailFields, List detailData, Map desensitizationList) { + int detailIndex = xAxis.size(); + + List realDetailFields = detailFields.subList(detailIndex, detailFields.size()); + + List fields = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(xAxis)) + fields.addAll(xAxis); + if (CollectionUtils.isNotEmpty(yAxis)) + fields.addAll(yAxis); + Map map = transTableNormal(fields, null, data, desensitizationList); + List> tableRow = (List>) map.get("tableRow"); + final int xEndIndex = detailIndex; + Map> groupDataList = detailData.stream().collect(Collectors.groupingBy(item -> ArrayUtil.join(ArrayUtil.sub(item, 0, xEndIndex), "-de-", "(", ")"))); + + tableRow.forEach(row -> { + String key = xAxis.stream().map(x -> row.get(x.getDataeaseName()).toString()).collect(Collectors.joining("-de-", "(", ")")); + List detailFieldValueList = groupDataList.get(key); + List> detailValueMapList = detailFieldValueList.stream().map((detailArr -> { + Map temp = new HashMap<>(); + for (int i = 0; i < realDetailFields.size(); i++) { + ChartViewFieldDTO realDetailField = realDetailFields.get(i); + temp.put(realDetailField.getDataeaseName(), detailArr[detailIndex + i]); + } + return temp; + })).collect(Collectors.toList()); + row.put("details", detailValueMapList); + }); + + ChartViewFieldDTO detailFieldDTO = new ChartViewFieldDTO(); + detailFieldDTO.setId("DataEase-Detail"); + detailFieldDTO.setName("detail"); + detailFieldDTO.setDataeaseName("detail"); + fields.add(detailFieldDTO); + map.put("fields", fields); + map.put("detailFields", realDetailFields); + map.put("tableRow", tableRow); + return map; + } + // 表格 public static Map transTableNormal(Map> fieldMap, ChartViewWithBLOBs view, List data, Map desensitizationList) { diff --git a/frontend/src/components/deIconPicker/eIcon/e-icon.vue b/frontend/src/components/deIconPicker/eIcon/e-icon.vue new file mode 100644 index 0000000000..c5de26eb24 --- /dev/null +++ b/frontend/src/components/deIconPicker/eIcon/e-icon.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/frontend/src/components/deIconPicker/eIconList.js b/frontend/src/components/deIconPicker/eIconList.js new file mode 100644 index 0000000000..565a38c7c2 --- /dev/null +++ b/frontend/src/components/deIconPicker/eIconList.js @@ -0,0 +1 @@ +export default ['xianxingbenzitubiao1', 'xianxinganquansuotubiao', 'xianxingbenzitubiao2', 'xianxingdianzantubiao', 'xianxingdiannaotubiao', 'xianxingjishibentubiao', 'xianxingdianhuatubiao', 'xianxinghuishouzhantubiao', 'xianxingWIFItubiao', 'xianxingduihuakuangtubiao', 'xianxinglajitongtubiao', 'xianxingjiangpaitubiao2', 'xianxingjiaoyoutubiao', 'xianxingquerentubiao', 'xianxingrenwutubiao', 'xianxingjiangpaitubiao1', 'xianxingshoujitubiao', 'xianxinglianxirentubiao', 'xianxingrenyuantubiao', 'xianxinggongjutubiao', 'xianxingshenfentubiao', 'xianxingxiangjitubiao', 'xianxingwendatubiao', 'xianxingyanjingtubiao', 'xianxingxinxitubiao', 'xianxingxinjiantubiao', 'xianxingtudingtubiao', 'xianxingshijiantubiao', 'xianxingqianbaotubiao', 'xianxingtupiantubiao', 'xianxingzhifubaotubiao', 'xianxingyoujiantubiao', 'xianxingzhifeijitubiao', 'xianxingyuantubiao', 'xianxingxiangfatubiao', 'diannao-01', 'jiaojuan-01', 'shuji-01', 'gujianzhu-01', 'simiao-01', 'yundong-yumaoqiu', 'sanjiaojia-01', 'zhaoxiangji-01', 'shuihu-01', 'yumaopai-01', 'yanjing-01', 'chalaoban-01', 'shouji-01', 'yinzhang-01', 'xiangyan-01', 'guangpan-01', 'kafei-01', 'erji-01', 'foling-01', 'xiong-01', 'bingxiang', 'diannao', 'chufangcheng', 'biludianshi', 'dayinji', 'guangpan', 'jiashiqi', 'fengshan', 'kongtiao', 'dianfanbao', 'fengrenji', 'dianzicheng', 'mensuo', 'shexiangji', 'saodijiqiren', 'lvshuiji', 'shuzhuodeng', 'kafeiji', 'jisuanqi', 'xiyiji', 'shexiangtou'].map(s => 'eiconfont e-icon-' + s) diff --git a/frontend/src/components/deIconPicker/elementUI.js b/frontend/src/components/deIconPicker/elementUI.js new file mode 100644 index 0000000000..65ee23694f --- /dev/null +++ b/frontend/src/components/deIconPicker/elementUI.js @@ -0,0 +1 @@ +export default ['platform-eleme', 'eleme', 'delete-solid', 'delete', 's-tools', 'setting', 'user-solid', 'user', 'phone', 'phone-outline', 'more', 'more-outline', 'star-on', 'star-off', 's-goods', 'goods', 'warning', 'warning-outline', 'question', 'info', 'remove', 'circle-plus', 'success', 'error', 'zoom-in', 'zoom-out', 'remove-outline', 'circle-plus-outline', 'circle-check', 'circle-close', 's-help', 'help', 'minus', 'plus', 'check', 'close', 'picture', 'picture-outline', 'picture-outline-round', 'upload', 'upload2', 'download', 'camera-solid', 'camera', 'video-camera-solid', 'video-camera', 'message-solid', 'bell', 's-cooperation', 's-order', 's-platform', 's-fold', 's-unfold', 's-operation', 's-promotion', 's-home', 's-release', 's-ticket', 's-management', 's-open', 's-shop', 's-marketing', 's-flag', 's-comment', 's-finance', 's-claim', 's-custom', 's-opportunity', 's-data', 's-check', 's-grid', 'menu', 'share', 'd-caret', 'caret-left', 'caret-right', 'caret-bottom', 'caret-top', 'bottom-left', 'bottom-right', 'back', 'right', 'bottom', 'top', 'top-left', 'top-right', 'arrow-left', 'arrow-right', 'arrow-down', 'arrow-up', 'd-arrow-left', 'd-arrow-right', 'video-pause', 'video-play', 'refresh', 'refresh-right', 'refresh-left', 'finished', 'sort', 'sort-up', 'sort-down', 'rank', 'loading', 'view', 'c-scale-to-original', 'date', 'edit', 'edit-outline', 'folder', 'folder-opened', 'folder-add', 'folder-remove', 'folder-delete', 'folder-checked', 'tickets', 'document-remove', 'document-delete', 'document-copy', 'document-checked', 'document', 'document-add', 'printer', 'paperclip', 'takeaway-box', 'search', 'monitor', 'attract', 'mobile', 'scissors', 'umbrella', 'headset', 'brush', 'mouse', 'coordinate', 'magic-stick', 'reading', 'data-line', 'data-board', 'pie-chart', 'data-analysis', 'collection-tag', 'film', 'suitcase', 'suitcase-1', 'receiving', 'collection', 'files', 'notebook-1', 'notebook-2', 'toilet-paper', 'office-building', 'school', 'table-lamp', 'house', 'no-smoking', 'smoking', 'shopping-cart-full', 'shopping-cart-1', 'shopping-cart-2', 'shopping-bag-1', 'shopping-bag-2', 'sold-out', 'sell', 'present', 'box', 'bank-card', 'money', 'coin', 'wallet', 'discount', 'price-tag', 'news', 'guide', 'male', 'female', 'thumb', 'cpu', 'link', 'connection', 'open', 'turn-off', 'set-up', 'chat-round', 'chat-line-round', 'chat-square', 'chat-dot-round', 'chat-dot-square', 'chat-line-square', 'message', 'postcard', 'position', 'turn-off-microphone', 'microphone', 'close-notification', 'bangzhu', 'time', 'odometer', 'crop', 'aim', 'switch-button', 'full-screen', 'copy-document', 'mic', 'stopwatch', 'medal-1', 'medal', 'trophy', 'trophy-1', 'first-aid-kit', 'discover', 'place', 'location', 'location-outline', 'location-information', 'add-location', 'delete-location', 'map-location', 'alarm-clock', 'timer', 'watch-1', 'watch', 'lock', 'unlock', 'key', 'service', 'mobile-phone', 'bicycle', 'truck', 'ship', 'basketball', 'football', 'soccer', 'baseball', 'wind-power', 'light-rain', 'lightning', 'heavy-rain', 'sunrise', 'sunrise-1', 'sunset', 'sunny', 'cloudy', 'partly-cloudy', 'cloudy-and-sunny', 'moon', 'moon-night', 'dish', 'dish-1', 'food', 'chicken', 'fork-spoon', 'knife-fork', 'burger', 'tableware', 'sugar', 'dessert', 'ice-cream', 'hot-water', 'water-cup', 'coffee-cup', 'cold-drink', 'goblet', 'goblet-full', 'goblet-square', 'goblet-square-full', 'refrigerator', 'grape', 'watermelon', 'cherry', 'apple', 'pear', 'orange', 'coffee', 'ice-tea', 'ice-drink', 'milk-tea', 'potato-strips', 'lollipop', 'ice-cream-square', 'ice-cream-round'].map(s => 'el-icon-' + s) diff --git a/frontend/src/components/deIconPicker/fontAwesome.js b/frontend/src/components/deIconPicker/fontAwesome.js new file mode 100644 index 0000000000..d6b6a0553c --- /dev/null +++ b/frontend/src/components/deIconPicker/fontAwesome.js @@ -0,0 +1 @@ +export default ['slack', 'arrows-alt', 'wpexplorer', 'video-camera', 'cutlery', 'times-rectangle-o', 'coffee', 'play-circle', 'chain', 'hand-rock-o', 'list-ul', 'sitemap', 'step-backward', 'columns', 'arrow-left', 'fa', 'italic', 'turkish-lira', 'github-square', 'mobile', 'file-o', 'paw', 'tree', 'remove', 'adn', 'google-plus', 'external-link', 'maxcdn', 'battery-three-quarters', 'cc', 'wpbeginner', 'universal-access', 'hand-grab-o', 'vine', 'hacker-news', 'sticky-note', 'caret-square-o-right', 'yahoo', 'shopping-basket', 'code-fork', 'user', 'codepen', 'reorder', 'cc-mastercard', 'laptop', 'sheqel', 'chevron-circle-left', 'meh-o', 'spoon', 'cloud', 'file-pdf-o', 'th-list', 'address-book-o', 'quote-right', 'battery-2', 'battery-1', 'bookmark', 'battery-4', 'file-sound-o', 'battery-3', 'caret-square-o-up', 'xing', 'battery-0', 'upload', 'commenting-o', 'chevron-circle-right', 'times', 'pie-chart', 'leanpub', 'glass', 'toggle-left', 'hand-o-right', 'file-code-o', 'hand-spock-o', 'asl-interpreting', 'pencil', 'calendar', 'i-cursor', 'shirtsinbulk', 'caret-up', 'snapchat-ghost', 'user-circle', 'user-times', 'tencent-weibo', 'close', 'tags', 'skype', 'ge', 'digg', 'ravelry', 'binoculars', 'gg', 'soccer-ball-o', 'google', 'beer', 'contao', 'mars-stroke', 'cube', 'align-justify', 'file-archive-o', 'toggle-on', 'whatsapp', 'suitcase', 'pencil-square', 'font', 'eercast', 'trello', 'calendar-plus-o', 'arrow-circle-left', 'pencil-square-o', 'connectdevelop', 'bullhorn', 'thermometer-half', 'chevron-left', 'stack-exchange', 'book', 'arrows', 'window-close-o', 'shekel', 'git', 'scissors', 'fast-forward', 'cc-amex', 'car', 'tint', 'outdent', 'flickr', 'arrow-up', 'music', 'mercury', 'html5', 'microphone-slash', 'simplybuilt', 'inr', 'send-o', 'krw', 'long-arrow-up', 'thumbs-down', 'diamond', 'bolt', 'hand-pointer-o', 'bomb', 'paste', 'birthday-cake', 'jsfiddle', 'file-movie-o', 'tag', 'youtube', 'thumbs-o-up', 'keyboard-o', 'hand-peace-o', 'blind', 'list-ol', 'id-card', 'cab', 'delicious', 'file-powerpoint-o', 'dollar', 'shield fa-rotate-270', 'ils', 'backward', 'etsy', 'circle-thin', 'copyright', 'folder', 'group', 'spotify', 'television', 'vimeo', 'hospital-o', 'volume-control-phone', 'sort-desc', 'mail-forward', 'twitter', 'bluetooth-b', 'chevron-circle-up', 'ioxhost', 'at', 'pause', 'angle-left', 'quora', 'eraser', 'rss-square', 'thermometer-three-quarters', 'hdd-o', 'gittip', 'mobile-phone', 'users', 'assistive-listening-systems', 'caret-square-o-down', 'unlock', 'play', 'superscript', 'chevron-right', 'sign-in', 'paint-brush', 'youtube-play', 'odnoklassniki', 'empire', 'deafness', 'arrow-circle-up', 'photo', 'reddit-alien', 'shopping-cart', 'fire-extinguisher', 'share-square', 'picture-o', 'cc-diners-club', 'square', 'times-circle-o', 'wechat', 'search-plus', 'window-restore', 'sort-alpha-asc', 'gbp', 'font-awesome', 'facebook-official', 'quote-left', 'thumbs-o-down', 'hand-scissors-o', 'linux', 'steam', 'building', 'soundcloud', 'sticky-note-o', 'amazon', 'eye-slash', 'lightbulb-o', 'arrow-circle-o-left', 'align-right', 'long-arrow-right', 'bar-chart-o', 'modx', 'android', 'times-rectangle', 'cc-discover', 'star-half-o', 'firefox', 'snowflake-o', 'glide-g', 'paypal', 'pied-piper-alt', 'cloud-download', 'circle-o', 'github', 'gratipay', 'underline', 'key', 'magic', 'caret-right', 'grav', 'facebook-f', 'address-card', 'object-group', 'google-plus-square', 'btc', 'viacoin', 'address-book', 'battery', 'windows', 'bus', 'sun-o', 'strikethrough', 'tablet', 'bold', 'life-bouy', 'image', 'align-left', 'crop', 'microphone', 'bug', 'wpforms', 'slideshare', 'xing-square', 'transgender', 'hotel', 'file-image-o', 'battery-half', 'pause-circle-o', 'indent', 'share-square-o', 'codiepie', 'rotate-left', 'toggle-right', 'behance-square', 'exchange', 'mail-reply-all', 'ship', 'exclamation', 'umbrella', 'meanpath', 'warning', 'spinner', 'exclamation-circle', 'google-plus-circle', 'share-alt-square', 'external-link-square', 'wheelchair-alt', 'low-vision', 'step-forward', 'asterisk', 'angle-double-down', 'sort-amount-asc', 'arrows-v', 'support', 's15', 'undo', 'signing', 'tachometer', 'long-arrow-left', 'comment-o', 'flask', 'flash', 'youtube-square', 'arrows-h', 'steam-square', 'dedent', 'hard-of-hearing', 'dashcube', 'language', 'newspaper-o', 'trophy', 'forumbee', 'genderless', 'angle-double-right', 'imdb', 'automobile', 'list', 'calendar-check-o', 'heart', 'pinterest', 'vcard', 'pinterest-square', 'flag-checkered', 'user-circle-o', 'mars-double', 'circle', 'envelope-square', 'briefcase', 'check-circle', 'check-square', 'houzz', 'calendar-o', 'paperclip', 'caret-left', 'money', 'id-badge', 'expeditedssl', 'calendar-times-o', 'credit-card', 'sort-down', 'map', 'clock-o', 'rupee', 'usd', 'save', 'terminal', 'venus-mars', 'bicycle', 'graduation-cap', 'usb', 'window-close', 'shield fa-rotate-90', 'database', 'yelp', 'thermometer-empty', 'text-height', 'gear', 'share-alt', 'star-half-empty', 'intersex', 'sort-alpha-desc', 'reddit-square', 'retweet', 'foursquare', 'sellsy', 'minus', 'share', 'neuter', 'phone-square', 'volume-down', 'paper-plane-o', 'linode', 'gift', 'bluetooth', 'floppy-o', 'gears', 'arrow-circle-right', 'hand-o-left', 'weixin', 'crosshairs', 'bell-o', 'puzzle-piece', 'industry', 'stack-overflow', 'tasks', 'drupal', 'hand-o-down', 'battery-full', 'smile-o', 'align-center', 'link', 'power-off', 'stop', 'chevron-circle-down', 'handshake-o', 'moon-o', 'resistance', 'y-combinator-square', 'hourglass-start', 'signal', 'paper-plane', 'desktop', 'life-buoy', 'microchip', 'qrcode', 'random', 'won', 'bitcoin', 'arrow-circle-o-up', 'user-md', 'git-square', 'adjust', 'search-minus', 'odnoklassniki-square', 'battery-empty', 'pied-piper-pp', 'opencart', 'camera', 'square-o', 'sort-asc', 'info-circle', 'eyedropper', 'instagram', 'lastfm', 'folder-open-o', 'thermometer-4', 'star-o', 'bell-slash', 'google-wallet', 'angle-down', 'file-audio-o', 'sort-numeric-desc', 'plus-square-o', 'reply', 'chevron-up', 'mixcloud', 'bed', 'question-circle-o', 'cc-jcb', 'chevron-down', 'thermometer-full', 'trash', 'arrow-circle-down', 'forward', 'file-word-o', 'id-card-o', 'podcast', 'glide', 'comments-o', 'wheelchair', 'long-arrow-down', 'unlink', 'snapchat-square', 'location-arrow', 'ban', 'envelope-open-o', 'google-plus-official', 'file-video-o', 'window-minimize', 'caret-down', 'thermometer-1', 'thermometer-0', 'thermometer-3', 'thermometer-2', 'bar-chart', 'question-circle', 'black-tie', 'cloud-upload', 'tripadvisor', 'file-text-o', 'lemon-o', 'wordpress', 'mars', 'first-order', 'envelope-open', 'barcode', 'expand', 'plane', 'arrow-right', 'map-marker', 'euro', 'unsorted', 'joomla', 'bath', 'meetup', 'chrome', 'repeat', 'toggle-down', 'rouble', 'download', 'life-ring', 'shield fa-flip-vertical', 'globe', 'jpy', 'arrow-down', 'shield', 'balance-scale', 'apple', 'fort-awesome', 'tumblr', 'file-photo-o', 'stop-circle-o', 'stumbleupon', 'header', 'twitch', 'venus', 'openid', 'institution', 'question', 'chain-broken', 'recycle', 'skyatlas', 'file-excel-o', 'bars', 'hand-stop-o', 'frown-o', 'paragraph', 'print', 'circle-o-notch', 'clipboard', 'inbox', 'sign-out', 'navicon', 'drivers-license-o', 'legal', 'leaf', 'flag', 'hand-lizard-o', 'bookmark-o', 'copy', 'scribd', 'mars-stroke-v', 'shield fa-rotate-180', 'life-saver', 'envelope', 'sort-amount-desc', 'comments', '500px', 'reply-all', 'map-pin', 'send', 'arrow-circle-o-right', 'university', 'credit-card-alt', 'road', 'trash-o', 'cart-plus', 'futbol-o', 'fax', 'wifi', 'user-o', 'percent', 'mars-stroke-h', 'refresh', 'medkit', 'safari', 'server', 'mouse-pointer', 'files-o', 'dot-circle-o', 'buysellads', 'gamepad', 'train', 'times-circle', 'angle-double-up', 'braille', 'product-hunt', 'cubes', 'eject', 'cc-stripe', 'address-card-o', 'yen', 'pagelines', 'battery-quarter', 'code', 'rebel', 'wikipedia-w', 'th-large', 'thermometer', 'history', 'unlock-alt', 'angellist', 'minus-circle', 'edit', 'hourglass-half', 'phone', 'vk', 'user-secret', 'male', 'internet-explorer', 'plus', 'shower', 'sort', 'rotate-right', 'dropbox', 'feed', 'bullseye', 'sign-language', 'comment', 'level-up', 'heart-o', 'themeisle', 'subscript', 'wrench', 'file-text', 'shield fa-flip-horizontal', 'american-sign-language-interpreting', 'edge', 'building-o', 'tv', 'certificate', 'reddit', 'th', 'viadeo-square', 'calculator', 'minus-square-o', 'archive', 'rocket', 'sort-numeric-asc', 'caret-square-o-left', 'cogs', 'twitter-square', 'heartbeat', 'headphones', 'cc-visa', 'anchor', 'motorcycle', 'shopping-bag', 'viadeo', 'angle-up', 'superpowers', 'tumblr-square', 'commenting', 'rss', 'play-circle-o', 'flag-o', 'mail-reply', 'gg-circle', 'thermometer-quarter', 'rub', 'sort-up', 'pinterest-p', 'volume-up', 'text-width', 'get-pocket', 'level-down', 'renren', 'css3', 'bathtub', 'vimeo-square', 'taxi', 'gitlab', 'fast-backward', 'area-chart', 'stethoscope', 'pause-circle', 'deviantart', 'h-square', 'weibo', 'fire', 'angle-right', 'cart-arrow-down', 'bank', 'cut', 'mortar-board', 'yc', 'toggle-off', 'window-maximize', 'star', 'exclamation-triangle', 'eye', 'trademark', 'bitbucket', 'stumbleupon-circle', 'compass', 'female', 'folder-o', 'audio-description', 'home', 'envelope-o', 'filter', 'registered', 'check-square-o', 'bitbucket-square', 'map-o', 'vcard-o', 'dribbble', 'bandcamp', 'snapchat', 'arrow-circle-o-down', 'plus-circle', 'bell', 'venus-double', 'transgender-alt', 'envira', 'yc-square', 'tty', 'compress', 'fonticons', 'toggle-up', 'space-shuttle', 'truck', 'street-view', 'folder-open', 'hashtag', 'facebook-square', 'minus-square', 'file-zip-o', 'cc-paypal', 'hourglass-end', 'subway', 'info', 'facebook', 'eur', 'github-alt', 'search', 'clone', 'try', 'thumb-tack', 'behance', 'linkedin', 'ellipsis-h', 'ra', 'hand-o-up', 'hourglass-o', 'star-half-full', 'object-ungroup', 'creative-commons', 'qq', 'fighter-jet', 'file-picture-o', 'linkedin-square', 'opera', 'plus-square', 'y-combinator', 'magnet', 'rmb', 'user-plus', 'ambulance', 'sliders', 'free-code-camp', 'file', 'child', 'ticket', 'pied-piper', 'gavel', 'list-alt', 'film', 'cog', 'line-chart', 'check-circle-o', 'cny', 'ellipsis-v', 'plug', 'thumbs-up', 'yoast', 'optin-monster', 'lastfm-square', 'medium', 'hourglass-1', 'drivers-license', 'table', 'hourglass-2', 'hourglass-3', 'ruble', 'check', 'stop-circle', 'lock', 'calendar-minus-o', 'bell-slash-o', 'star-half', 'angle-double-left', 'hourglass', 'telegram', 'map-signs', 'camera-retro', 'dashboard', 'hand-paper-o', 'volume-off'].map(s => 'fa fa-' + s) diff --git a/frontend/src/components/deIconPicker/iconList.js b/frontend/src/components/deIconPicker/iconList.js new file mode 100644 index 0000000000..aadb561162 --- /dev/null +++ b/frontend/src/components/deIconPicker/iconList.js @@ -0,0 +1,48 @@ +import { TypeUtil } from './utils/index' +import fontAwesome from './fontAwesome' +import elementUI from './elementUI' +import eIconList from './eIconList' + +const add = function(list, item) { + let arr = [] + if (item && TypeUtil.isArray(item)) { + arr = list.concat(item) + } else if (item && TypeUtil.isString(item)) { + arr = arr.concat(list) + arr.push(item) + } + return arr +} + +const remove = function(list, item) { + if (item && TypeUtil.isArray(item)) { + for (let i = 0; i < item.length; i++) { + for (let j = 0; j < list.length; j++) { + if (list[j] === item[i]) { + list.splice(j, 1) + j-- + } + } + } + } else if (item && TypeUtil.isString(item)) { + list = list.filter(function(i) { + return i !== item + }) + } + return list +} + +const iconList = { + list: [], + + addIcon: function(item) { + this.list = add(this.list, item) + }, + + removeIcon: function(item) { + this.list = remove(this.list, item) + } +} + +export { fontAwesome, elementUI, eIconList } +export default iconList diff --git a/frontend/src/components/deIconPicker/index.vue b/frontend/src/components/deIconPicker/index.vue new file mode 100644 index 0000000000..f47284928e --- /dev/null +++ b/frontend/src/components/deIconPicker/index.vue @@ -0,0 +1,539 @@ + + + + + diff --git a/frontend/src/components/deIconPicker/utils/TypeUtil.js b/frontend/src/components/deIconPicker/utils/TypeUtil.js new file mode 100644 index 0000000000..2f4dc79a1c --- /dev/null +++ b/frontend/src/components/deIconPicker/utils/TypeUtil.js @@ -0,0 +1,27 @@ + +export const TypeUtil = { + + isArray: function(obj) { + return (typeof obj === 'object') && obj.constructor === Array + }, + + isString: function(obj) { + return (typeof obj === 'string') && obj.constructor === String + }, + + isNumber: function(obj) { + return (typeof obj === 'number') && obj.constructor === Number + }, + + isDate: function(obj) { + return (typeof obj === 'object') && obj.constructor === Date + }, + + isFunction: function(obj) { + return (typeof obj === 'function') && obj.constructor === Function + }, + + isObject: function(obj) { + return (typeof obj === 'object') && obj.constructor === Object + } +} diff --git a/frontend/src/components/deIconPicker/utils/dom.js b/frontend/src/components/deIconPicker/utils/dom.js new file mode 100644 index 0000000000..08438c5716 --- /dev/null +++ b/frontend/src/components/deIconPicker/utils/dom.js @@ -0,0 +1,36 @@ +import { isServer } from './util' + +export const on = (function() { + if (!isServer) { + if (document && document.addEventListener) { + return function(element, event, handler) { + if (element && event && handler) { + element.addEventListener(event, handler, false) + } + } + } else { + return function(element, event, handler) { + if (element && event && handler) { + element.attachEvent('on' + event, handler) + } + } + } + } +})() +export const off = (function() { + if (!isServer) { + if (document && document.removeEventListener) { + return function(element, event, handler) { + if (element && event) { + element.removeEventListener(event, handler, false) + } + } + } else { + return function(element, event, handler) { + if (element && event) { + element.detachEvent('on' + event, handler) + } + } + } + } +})() diff --git a/frontend/src/components/deIconPicker/utils/getSvg.js b/frontend/src/components/deIconPicker/utils/getSvg.js new file mode 100644 index 0000000000..e1c8afcda0 --- /dev/null +++ b/frontend/src/components/deIconPicker/utils/getSvg.js @@ -0,0 +1,15 @@ +const req = require.context(process.env.VUE_APP_SVG, false, /\.svg$/) + +const requireAllFile = requireContext => requireContext.keys().map(requireContext) +requireAllFile(req) + +const re = /\.\/(.*)\.svg/ + +const requireAll = requireContext => requireContext.keys() + +const svgIcons = requireAll(req).map(i => { + return '#' + i.match(re)[1] +}) + +export default svgIcons + diff --git a/frontend/src/components/deIconPicker/utils/index.js b/frontend/src/components/deIconPicker/utils/index.js new file mode 100644 index 0000000000..8d188d1a8e --- /dev/null +++ b/frontend/src/components/deIconPicker/utils/index.js @@ -0,0 +1,28 @@ +(function(e, d, w) { + if (!e.composedPath) { + e.composedPath = function() { + if (this.path) { + return this.path + } + let target = this.target + + this.path = [] + while (target.parentNode !== null) { + this.path.push(target) + target = target.parentNode + } + this.path.push(d, w) + return this.path + } + } + if (!String.prototype.startsWith) { + // eslint-disable-next-line no-extend-native + String.prototype.startsWith = function(search, pos) { + return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search + } + } +})(Event.prototype, document, window) + +export * from './util' +export * from './dom' +export * from './TypeUtil' diff --git a/frontend/src/components/deIconPicker/utils/util.js b/frontend/src/components/deIconPicker/utils/util.js new file mode 100644 index 0000000000..1b9beb5f51 --- /dev/null +++ b/frontend/src/components/deIconPicker/utils/util.js @@ -0,0 +1,53 @@ + +export const analyzingIconForIconfont = function(json) { + let font_family = '' + let css_prefix_text = '' + let list = [] + if (json) { + if (json.font_family) { + font_family = json.font_family + } + if (json.css_prefix_text) { + css_prefix_text = json.css_prefix_text + } + if (json.glyphs) { + list = json.glyphs.map(function(value, index, array) { + return font_family + ' ' + css_prefix_text + value.font_class + }) + } + } + return { + font_family, + css_prefix_text, + list + } +} + +export const eIconSymbol = function(json) { + let font_family = '' + let css_prefix_text = '' + let list = [] + if (json) { + if (json.font_family) { + font_family = json.font_family + } + if (json.css_prefix_text) { + css_prefix_text = json.css_prefix_text + } + if (json.glyphs) { + list = json.glyphs.map(function(value, index, array) { + return '#' + css_prefix_text + value.font_class + }) + } + } + return { + font_family, + css_prefix_text, + list + } +} + +export function isExternal(path) { + return /^(https?:|data:|\/\/?)/.test(path) +} +export const isServer = typeof window === 'undefined' diff --git a/frontend/src/deicons/index.js b/frontend/src/deicons/index.js new file mode 100644 index 0000000000..67a0f02c2a --- /dev/null +++ b/frontend/src/deicons/index.js @@ -0,0 +1,15 @@ +const req = require.context('./svg', false, /\.svg$/) + +const requireAllFile = requireContext => requireContext.keys().map(requireContext) +requireAllFile(req) + +const re = /\.\/(.*)\.svg/ + +const requireAll = requireContext => requireContext.keys() + +const deSvgIcons = requireAll(req).map(i => { + return '#' + i.match(re)[1] +}) + +export default deSvgIcons + diff --git a/frontend/src/deicons/svg/ai37.svg b/frontend/src/deicons/svg/ai37.svg new file mode 100644 index 0000000000..48eff1273f --- /dev/null +++ b/frontend/src/deicons/svg/ai37.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/ai65.svg b/frontend/src/deicons/svg/ai65.svg new file mode 100644 index 0000000000..c5154d2dcc --- /dev/null +++ b/frontend/src/deicons/svg/ai65.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/bumanyi.svg b/frontend/src/deicons/svg/bumanyi.svg new file mode 100644 index 0000000000..6d72da5cb8 --- /dev/null +++ b/frontend/src/deicons/svg/bumanyi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/chaping-yuankuang.svg b/frontend/src/deicons/svg/chaping-yuankuang.svg new file mode 100644 index 0000000000..78435c9b6e --- /dev/null +++ b/frontend/src/deicons/svg/chaping-yuankuang.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/chaping.svg b/frontend/src/deicons/svg/chaping.svg new file mode 100644 index 0000000000..db73c2e151 --- /dev/null +++ b/frontend/src/deicons/svg/chaping.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/circle.svg b/frontend/src/deicons/svg/circle.svg new file mode 100644 index 0000000000..5f182a5354 --- /dev/null +++ b/frontend/src/deicons/svg/circle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/cuowuguanbiquxiao-yuankuang.svg b/frontend/src/deicons/svg/cuowuguanbiquxiao-yuankuang.svg new file mode 100644 index 0000000000..1e2492895b --- /dev/null +++ b/frontend/src/deicons/svg/cuowuguanbiquxiao-yuankuang.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/five-star.svg b/frontend/src/deicons/svg/five-star.svg new file mode 100644 index 0000000000..c996d5b85d --- /dev/null +++ b/frontend/src/deicons/svg/five-star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/gantanhao-yuankuang.svg b/frontend/src/deicons/svg/gantanhao-yuankuang.svg new file mode 100644 index 0000000000..0a40a39a80 --- /dev/null +++ b/frontend/src/deicons/svg/gantanhao-yuankuang.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/haoping-yuankuang.svg b/frontend/src/deicons/svg/haoping-yuankuang.svg new file mode 100644 index 0000000000..31c5a0265e --- /dev/null +++ b/frontend/src/deicons/svg/haoping-yuankuang.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/haoping.svg b/frontend/src/deicons/svg/haoping.svg new file mode 100644 index 0000000000..d484e7a397 --- /dev/null +++ b/frontend/src/deicons/svg/haoping.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/jiantou-copy-copy-2.svg b/frontend/src/deicons/svg/jiantou-copy-copy-2.svg new file mode 100644 index 0000000000..ade81018fb --- /dev/null +++ b/frontend/src/deicons/svg/jiantou-copy-copy-2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/jiantou-copy-copy-copy.svg b/frontend/src/deicons/svg/jiantou-copy-copy-copy.svg new file mode 100644 index 0000000000..820539d967 --- /dev/null +++ b/frontend/src/deicons/svg/jiantou-copy-copy-copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/jiantou-copy-copy.svg b/frontend/src/deicons/svg/jiantou-copy-copy.svg new file mode 100644 index 0000000000..9632db94ce --- /dev/null +++ b/frontend/src/deicons/svg/jiantou-copy-copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/lingxing.svg b/frontend/src/deicons/svg/lingxing.svg new file mode 100644 index 0000000000..23044b85ae --- /dev/null +++ b/frontend/src/deicons/svg/lingxing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/manyi.svg b/frontend/src/deicons/svg/manyi.svg new file mode 100644 index 0000000000..1823ee3eb0 --- /dev/null +++ b/frontend/src/deicons/svg/manyi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/paixu.svg b/frontend/src/deicons/svg/paixu.svg new file mode 100644 index 0000000000..03eb83ffa4 --- /dev/null +++ b/frontend/src/deicons/svg/paixu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/qizi.svg b/frontend/src/deicons/svg/qizi.svg new file mode 100644 index 0000000000..d5e9cbd575 --- /dev/null +++ b/frontend/src/deicons/svg/qizi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/rect.svg b/frontend/src/deicons/svg/rect.svg new file mode 100644 index 0000000000..4abcdc2ba7 --- /dev/null +++ b/frontend/src/deicons/svg/rect.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/shangjiantou.svg b/frontend/src/deicons/svg/shangjiantou.svg new file mode 100644 index 0000000000..c6c8bd91ac --- /dev/null +++ b/frontend/src/deicons/svg/shangjiantou.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/weizhi.svg b/frontend/src/deicons/svg/weizhi.svg new file mode 100644 index 0000000000..8334aae50e --- /dev/null +++ b/frontend/src/deicons/svg/weizhi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/wenhao-yuankuang.svg b/frontend/src/deicons/svg/wenhao-yuankuang.svg new file mode 100644 index 0000000000..7e5d3f190f --- /dev/null +++ b/frontend/src/deicons/svg/wenhao-yuankuang.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/wujiaoxing.svg b/frontend/src/deicons/svg/wujiaoxing.svg new file mode 100644 index 0000000000..ad9ddfa54b --- /dev/null +++ b/frontend/src/deicons/svg/wujiaoxing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/xiajiantou.svg b/frontend/src/deicons/svg/xiajiantou.svg new file mode 100644 index 0000000000..d3331d189b --- /dev/null +++ b/frontend/src/deicons/svg/xiajiantou.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/xiangshang.svg b/frontend/src/deicons/svg/xiangshang.svg new file mode 100644 index 0000000000..64dad63c94 --- /dev/null +++ b/frontend/src/deicons/svg/xiangshang.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/xiangyou.svg b/frontend/src/deicons/svg/xiangyou.svg new file mode 100644 index 0000000000..21e90511c1 --- /dev/null +++ b/frontend/src/deicons/svg/xiangyou.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/xiangzuo.svg b/frontend/src/deicons/svg/xiangzuo.svg new file mode 100644 index 0000000000..14fd56a839 --- /dev/null +++ b/frontend/src/deicons/svg/xiangzuo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/yiban.svg b/frontend/src/deicons/svg/yiban.svg new file mode 100644 index 0000000000..24e624762e --- /dev/null +++ b/frontend/src/deicons/svg/yiban.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/youjiantou.svg b/frontend/src/deicons/svg/youjiantou.svg new file mode 100644 index 0000000000..9b4650a3e3 --- /dev/null +++ b/frontend/src/deicons/svg/youjiantou.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/zheng-triangle.svg b/frontend/src/deicons/svg/zheng-triangle.svg new file mode 100644 index 0000000000..347d2c8da5 --- /dev/null +++ b/frontend/src/deicons/svg/zheng-triangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/zhengquewancheng-yuankuang.svg b/frontend/src/deicons/svg/zhengquewancheng-yuankuang.svg new file mode 100644 index 0000000000..8eec7dd2d3 --- /dev/null +++ b/frontend/src/deicons/svg/zhengquewancheng-yuankuang.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svg/zuojiantou.svg b/frontend/src/deicons/svg/zuojiantou.svg new file mode 100644 index 0000000000..57beea3da4 --- /dev/null +++ b/frontend/src/deicons/svg/zuojiantou.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/deicons/svgo.yml b/frontend/src/deicons/svgo.yml new file mode 100644 index 0000000000..d11906aec2 --- /dev/null +++ b/frontend/src/deicons/svgo.yml @@ -0,0 +1,22 @@ +# replace default config + +# multipass: true +# full: true + +plugins: + + # - name + # + # or: + # - name: false + # - name: true + # + # or: + # - name: + # param1: 1 + # param2: 2 + +- removeAttrs: + attrs: + - 'fill' + - 'fill-rule' diff --git a/frontend/src/lang/en.js b/frontend/src/lang/en.js index 62968c5caf..e09d2322f0 100644 --- a/frontend/src/lang/en.js +++ b/frontend/src/lang/en.js @@ -931,6 +931,12 @@ export default { password_input_error: 'Original password input error' }, chart: { + mark_field: 'Field', + mark_value: 'Value', + function_style: 'Function style', + condition_style: 'Mark style', + longitude: 'Longitude', + latitude: 'Latitude', gradient: 'Gradient', layer_controller: 'Quota switch', suspension: 'Suspension', diff --git a/frontend/src/lang/tw.js b/frontend/src/lang/tw.js index 69a3d2c1f9..397b2136d3 100644 --- a/frontend/src/lang/tw.js +++ b/frontend/src/lang/tw.js @@ -930,6 +930,12 @@ export default { password_input_error: '原始密碼輸入錯誤' }, chart: { + mark_field: '字段', + mark_value: '值', + function_style: '功能型樣式', + condition_style: '標記樣式', + longitude: '經度', + latitude: '緯度', gradient: '漸變', layer_controller: '指標切換', suspension: '懸浮', diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js index f0971cd637..ab0dc77529 100644 --- a/frontend/src/lang/zh.js +++ b/frontend/src/lang/zh.js @@ -929,6 +929,12 @@ export default { password_input_error: '原始密码输入错误' }, chart: { + mark_field: '字段', + mark_value: '值', + function_style: '功能型样式', + condition_style: '标记样式', + longitude: '经度', + latitude: '纬度', gradient: '渐变', layer_controller: '指标切换', suspension: '悬浮', diff --git a/frontend/src/views/chart/chart/chart.js b/frontend/src/views/chart/chart/chart.js index 98cf7ed868..19dc72e6dc 100644 --- a/frontend/src/views/chart/chart/chart.js +++ b/frontend/src/views/chart/chart/chart.js @@ -132,6 +132,11 @@ export const DEFAULT_SIZE = { export const DEFAULT_SUSPENSION = { show: true } + +export const DEFAULT_MARK = { + fieldId: '', + conditions: [] +} export const DEFAULT_LABEL = { show: false, position: 'top', @@ -892,14 +897,25 @@ export const BASE_MAP = { inRange: { color: ['lightskyblue', 'yellow', 'orangered'] }, + seriesIndex: 0, textStyle: {}, right: 0 }, + geo: { + map: 'MAP', + roam: true, + nameMap: { + + }, + itemStyle: { + + } + }, series: [ { name: '', type: 'map', - map: 'MAP', + geoIndex: 0, roam: true, data: [], itemStyle: { diff --git a/frontend/src/views/chart/chart/map/map.js b/frontend/src/views/chart/chart/map/map.js index fbc331b0cb..0068d79fef 100644 --- a/frontend/src/views/chart/chart/map/map.js +++ b/frontend/src/views/chart/chart/map/map.js @@ -159,7 +159,80 @@ export function baseMapOption(chart_option, chart, themeStyle, curAreaCode, seri if (chart.senior) { const senior = JSON.parse(chart.senior) - senior && senior.mapMapping && senior.mapMapping[curAreaCode] && (chart_option.series[0].nameMap = senior.mapMapping[curAreaCode]) + senior && senior.mapMapping && senior.mapMapping[curAreaCode] && (chart_option.geo.nameMap = senior.mapMapping[curAreaCode]) + } + + if (chart.data?.detailFields?.length > 1) { + const deNameArray = ['x', 'y'] + chart.data.detailFields.forEach(item => { + if (item?.busiType === 'locationXaxis') { + deNameArray[0] = item + } else if (item?.busiType === 'locationYaxis') { + deNameArray[1] = item + } else { + deNameArray.push(item) + } + }) + let markData = [] + chart.data.tableRow.forEach(row => { + if (row?.details) { + markData = markData.concat(row.details.map(detail => { + const temp = deNameArray.map(key => detail[key.dataeaseName]) + temp.push(1) + return temp + })) + } + }) + + if (markData.length) { + let valueIndex = -1 + const markCondition = customAttr.mark + if (markCondition?.fieldId && markCondition.conditions?.length) { + for (let i = 0; i < deNameArray.length; i++) { + if (deNameArray[i].id === markCondition.fieldId) { + valueIndex = i + break + } + } + } + const markSeries = { + type: 'scatter', + coordinateSystem: 'geo', + geoIndex: 0, + symbolSize: function(params) { + return 20 + }, + symbol: (values, param) => { + if (valueIndex < 0) { + return svgPathData() + } + const val = values[valueIndex] + const field = deNameArray[valueIndex] + const con = getSvgCondition(val, field, markCondition.conditions) + let svgName = null + if (con) { + svgName = con.icon + if (svgName && svgName.startsWith('#')) { + svgName = svgName.substr(1) + } + } + return svgPathData(svgName) + }, + itemStyle: { + color: params => { + const { value } = params + const val = value[valueIndex] + const con = getSvgCondition(val, null, markCondition.conditions) + return con?.color || '#b02a02' + } + }, + encode: { + tooltip: 2 + }, + data: markData + } + chart_option.series.push(markSeries) + } } } } @@ -167,3 +240,100 @@ export function baseMapOption(chart_option, chart, themeStyle, curAreaCode, seri return chart_option } +const getSvgCondition = (val, field, conditions) => { + for (let i = 0; i < conditions.length; i++) { + const condition = conditions[i] + if (conditionMatch(condition, val)) { + return condition + } + } + return null +} +const conditionMatch = (condition, curVal) => { + let matchResult = false + const { calc, value, startv, endv } = condition + if (!curVal || (!value && !startv && !endv)) { + return matchResult + } + switch (calc) { + case 'eq': + matchResult = curVal === value + break + case 'ne': + matchResult = curVal !== value + break + case 'contain': + matchResult = curVal.includes(value) + break + case 'uncontain': + matchResult = !curVal.includes(value) + break + case 'start': + matchResult = curVal.startsWith(value) + break + case 'end': + matchResult = curVal.endsWith(value) + break + + case 'gt': + matchResult = parseFloat(curVal) > parseFloat(value) + break + case 'ge': + matchResult = parseFloat(curVal) >= parseFloat(value) + break + case 'lt': + matchResult = parseFloat(curVal) < parseFloat(value) + break + case 'le': + matchResult = parseFloat(curVal) <= parseFloat(value) + break + case 'between': + if (startv) { + matchResult = parseFloat(curVal) >= parseFloat(startv) + } + if (endv) { + matchResult = parseFloat(curVal) <= parseFloat(endv) + } + break + + default: + matchResult = false + break + } + return matchResult +} +const loadXML = xmlString => { + const domParser = new DOMParser() + const xmlDoc = domParser.parseFromString(xmlString, 'text/xml') + return xmlDoc +} + +const svgPathData = iconName => { + iconName = iconName || 'weizhi' + const defaultNode = require(`@/deicons/svg/${iconName}.svg`).default + if (!defaultNode?.content) return null + const content = defaultNode.content + const xmlRoot = loadXML(content) + const pathDataList = [] + const stack = [] + stack.push(xmlRoot) + + let curNode + while (stack.length) { + curNode = stack.pop() + if (curNode?.tagName === 'path') { + pathDataList.push(curNode.getAttribute('d')) + } + if (curNode.childNodes?.length) { + let childLen = curNode.childNodes.length + while (childLen--) { + stack.push(curNode.childNodes[childLen]) + } + } + } + if (pathDataList.length) { + return pathDataList.map(item => 'path://' + item).join('') + } + return null +} + diff --git a/frontend/src/views/chart/chart/util.js b/frontend/src/views/chart/chart/util.js index 604118ac6c..5808b3f900 100644 --- a/frontend/src/views/chart/chart/util.js +++ b/frontend/src/views/chart/chart/util.js @@ -3170,7 +3170,8 @@ export const TYPE_CONFIGS = [ 'label-selector', 'tooltip-selector', 'title-selector', - 'suspension-selector' + 'suspension-selector', + 'condition-style-selector' ], propertyInner: { @@ -3207,6 +3208,9 @@ export const TYPE_CONFIGS = [ ], 'suspension-selector': [ 'show' + ], + 'condition-style-selector': [ + 'show' ] } } diff --git a/frontend/src/views/chart/components/dragItem/DetailItem.vue b/frontend/src/views/chart/components/dragItem/DetailItem.vue new file mode 100644 index 0000000000..879da8c748 --- /dev/null +++ b/frontend/src/views/chart/components/dragItem/DetailItem.vue @@ -0,0 +1,154 @@ + + + + + diff --git a/frontend/src/views/chart/components/functionStyle/MapMarkSelector.vue b/frontend/src/views/chart/components/functionStyle/MapMarkSelector.vue new file mode 100644 index 0000000000..d3a885b885 --- /dev/null +++ b/frontend/src/views/chart/components/functionStyle/MapMarkSelector.vue @@ -0,0 +1,403 @@ + + + + + diff --git a/frontend/src/views/chart/components/map/MarkMapDataEditor.vue b/frontend/src/views/chart/components/map/MarkMapDataEditor.vue new file mode 100644 index 0000000000..92097c5785 --- /dev/null +++ b/frontend/src/views/chart/components/map/MarkMapDataEditor.vue @@ -0,0 +1,669 @@ + + + + + diff --git a/frontend/src/views/chart/components/table/TableNormal.vue b/frontend/src/views/chart/components/table/TableNormal.vue index 373864104a..71b75c6e52 100644 --- a/frontend/src/views/chart/components/table/TableNormal.vue +++ b/frontend/src/views/chart/components/table/TableNormal.vue @@ -21,6 +21,7 @@ :row-style="getRowStyle" class="table-class" :class="chart.id" + :merge-cells="mergeCells" :show-summary="showSummary" :summary-method="summaryMethod" :index-config="{seqMethod}" @@ -32,12 +33,20 @@ + > + + { + if (field.id === 'DataEase-Detail' && field.dataeaseName === 'detail') { + field.child = JSON.parse(JSON.stringify(this.chart.data.detailFields)) + } + }) + } + this.fields = fields const attr = JSON.parse(this.chart.customAttr) this.currentPage.pageSize = parseInt(attr.size.tablePageSize ? attr.size.tablePageSize : 20) @@ -269,13 +288,38 @@ export default { data = [] this.resetPage() } - data.forEach(item => { - Object.keys(item).forEach(key => { - if (typeof item[key] === 'object') { - item[key] = '' + if (this.chart.data.detailFields?.length) { + let result = [] + let groupRowIndex = 0 + data.forEach(item => { + const baseObj = JSON.parse(JSON.stringify(item)) + delete baseObj.details + + const details = JSON.parse(JSON.stringify(item.details)) + let colsIndex = this.fields.length - 1 + while (colsIndex--) { + const mergeItem = { + row: groupRowIndex, + col: colsIndex, + rowspan: details.length, + colspan: 1 + } + this.mergeCells.push(mergeItem) } + groupRowIndex += details.length + result = result.concat(details.map(detail => Object.assign(detail, baseObj))) }) - }) + data = result + } else { + data.forEach(item => { + Object.keys(item).forEach(key => { + if (typeof item[key] === 'object') { + item[key] = '' + } + }) + }) + } + this.$refs.plxTable.reloadData(data) this.$nextTick(() => { this.initStyle() @@ -295,6 +339,12 @@ export default { if (this.chart.data) { if (this.chart.type === 'table-info') { tableHeight = (this.currentPage.pageSize + 2) * 36 - pageHeight + } else if (this.chart.data.detailFields?.length) { + let rowLength = 0 + this.chart.data.tableRow.forEach(row => { + rowLength += (row?.details?.length || 1) + }) + tableHeight = (rowLength + 2) * 36 - pageHeight } else { tableHeight = (this.chart.data.tableRow.length + 2) * 36 - pageHeight } diff --git a/frontend/src/views/chart/view/ChartEdit.vue b/frontend/src/views/chart/view/ChartEdit.vue index 8e65f66030..4931d8baba 100644 --- a/frontend/src/views/chart/view/ChartEdit.vue +++ b/frontend/src/views/chart/view/ChartEdit.vue @@ -863,6 +863,17 @@ {{ $t('chart.placeholder_field') }} + + + + + + {{ $t('chart.function_style') }} + + + + + + + @@ -338,6 +366,7 @@ import BackgroundColorSelector from '@/views/chart/components/componentStyle/Bac import SplitSelector from '@/views/chart/components/componentStyle/SplitSelector' import SplitSelectorAntV from '@/views/chart/components/componentStyle/SplitSelectorAntV' import SuspensionSelector from '@/components/suspensionSelector' +import MapMarkSelector from '@/views/chart/components/functionStyle/MapMarkSelector' import { mapState } from 'vuex' export default { @@ -366,7 +395,8 @@ export default { ColorSelector, MarginSelector, PluginCom, - SuspensionSelector + SuspensionSelector, + MapMarkSelector }, props: { chart: { @@ -498,6 +528,10 @@ export default { onChangeBackgroundForm(val, propertyName) { val['propertyName'] = propertyName this.$emit('onChangeBackgroundForm', val) + }, + onMarkChange(val, propertyName) { + val['propertyName'] = propertyName + this.$emit('onMarkChange', val) } } } diff --git a/frontend/vue.config.js b/frontend/vue.config.js index 459a5938bd..6f079d4649 100644 --- a/frontend/vue.config.js +++ b/frontend/vue.config.js @@ -94,6 +94,17 @@ module.exports = { deleteOriginalAssets: true // 删除源文件 })) */ } + + config.module + .rule('icons') + .test(/\.svg$/) + .include.add(resolve('src/deicons')) + .end() + .use('svg-sprite-loader') + .loader('svg-sprite-loader') + .options({ + symbolId: '[name]' + }) }, css: { loaderOptions: { @@ -102,7 +113,7 @@ module.exports = { } }, extract: { - ignoreOrder: true, + ignoreOrder: true } }