上传文件

上传文件的后端服务

使用Python Flask实现。

import osfrom flask import Flask, request, redirect, url_for, send_from_directoryfrom werkzeug import secure_filenamefrom flask_cors import CORSUPLOAD_FOLDER = '/path/to/the/uploads'ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])app = Flask(__name__)CORS(app)app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDERdef allowed_file(filename):    return '.' in filename and \           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS@app.route('/', methods=['GET', 'POST'])def upload_file():    if request.method == 'POST':        file = request.files['file']        if file and allowed_file(file.filename):            filename = secure_filename(file.filename)            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))            return redirect(url_for('uploaded_file',                                    filename=filename))    return '''    <!doctype html>    <title>Upload new File</title>    <h1>Upload new File</h1>    <form action="" method=post enctype=multipart/form-data>      <p><input type=file name=file>         <input type=submit value=Upload>    </form>    '''@app.route('/uploads/<filename>')def uploaded_file(filename):    return send_from_directory(app.config['UPLOAD_FOLDER'],                               filename)

解决跨域访问,需安装flask-cors

上传组件

使用Element UI实现

// action指定上传文件后台服务, on-success指定上传成功后执行的方法<el-upload    class="upload-demo"          action="http://xxxx:xxxx/upload"    :on-success="handleSuccess"    :show-file-list="true"    >    <el-button size="small" type="primary">点击上传</el-button>    <div slot="tip" class="el-upload__tip">只能上传txt文件,分隔符为\t</div></el-upload>// 在Vue中指定数据fileName、计算属性fileContent、以及上传成功后的方法handleSuccessnew Vue({  el: '#app',  data: {     fileName: null  },    computed: {      fileContent: function() {        if(this.fileName != null) {          return this.fileName.response;        }      }  },  methods: {        handleSuccess: function(response, file, fileList) {      this.fileName = file;      return this.$confirm(`上传 ${ file.name }成功!`);    }    }});

TSV解析

使用d3-dsv库。

<script src="https://d3js.org/d3-dsv.v1.min.js"></script>d3.tsvParse("foo\tbar\n1\t2"); // [{foo: "1", bar: "2"}, columns: ["foo", "bar"]]

表格

使用v-for实现动态列名

<el-table :data="inputData" style="width: 100%" height="250">      <el-table-column         v-for="col in columns"        :prop="col" :label="col" >      </el-table-column></el-table>

JS数组操作

资料
创建、排序、删除、追加、reverse、slice、join转字符串、concat拼接数组、forEach循环

JS字符串操作

split拆分、parseInt等类型转换

事件

表格点击行事件

<el-table      :data="getPageData()"      style="width: 100%" @row-click="updateRow"></el-table>

Leaflet组件

Vue.component("leaflet", {  props: ['table_data', 'selected_row'],  data() {    return {      map: null,      layer: null,      point: null    };  },  template: '<div></div>',  mounted: function() {    this.init();    this.update();    this.highlight();  },  watch: {    table_data: function () {      this.update();    },    selected_row: function() {      this.highlight();    }  },  methods: {    init: function() {      this.map = L.map(this.$el.id).setView([29.802946,106.396835], zoom = 10);            L.tileLayer(                'https://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0',                {                    maxZoom: 18,                    subdomains: "0123",                    tms: true,                    attribution: '&copy; <a href="http://map.qq.com/">腾讯地图</a>',                }            ).addTo(this.map);    },        update: function() {          if(this.layer != null) this.layer.removeFrom(this.map);          if(this.point != null)  this.point.removeFrom(this.map);          // 绘制数据            var markerArray = Array();            this.table_data.forEach((pnt) => {                var date = new Date(pnt['collecttime']*1000);                markerArray.push(L.circle([pnt["bmuserlat"], pnt["bmuserlng"]]).bindTooltip(date+""));                // L.circle([pnt["bmuserlat"], pnt["bmuserlng"]], {radius:15}).addTo(this.map);            });            this.layer = L.featureGroup(markerArray).addTo(this.map);            this.map.fitBounds(this.layer.getBounds());        },        highlight: function() {          if(this.point != null)  this.point.removeFrom(this.map);          // 绘制选中点          if(this.selected_row != null) {            this.point = L.circleMarker([this.selected_row['bmuserlat'], this.selected_row['bmuserlng']], {color: "red"}).addTo(this.map).bindPopup(this.selected_row['collecttime'] + "");           }        }  }});

ECharts组件

Vue.component('echarts-heatmap', {  props: ['table_data'],  data: function() {    return {      map: null    }  },  computed: {    plot_data: function() {      //GCJ-02 to BD-09      function bd_encrypt(gcjLat, gcjLon)      {          x_pi = 3.14159265358979324 * 3000.0 / 180.0;          var x = gcjLon, y = gcjLat;          var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);          var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);          var bdLon = z * Math.cos(theta) + 0.0065;          var bdLat = z * Math.sin(theta) + 0.006;          return { 'lat': bdLat, 'lon': bdLon };      }            var heatArray = Array();      this.table_data.forEach(function(item) {        var x = Math.round(item['bmuserlng'] * 1000) / 1000;        var y = Math.round(item['bmuserlat'] * 1000) / 1000;        var res = bd_encrypt(y, x);        var x = res.lon;        var y = res.lat;        var idx = item["color_idx"]        heatArray.push([x, y, idx]);      });            var heatMap = [];      heatArray.reduce(function(res, value){        if(!res[value]) {          res[value] = value;          heatMap.push(value);        }        return res;      }, {});            var result = [];      heatMap.reduce(function(res, value) {        k = [value[0], value[1]]        if(!res[k]) {          res[k] = [value[0], value[1], 0];          result.push(res[k]);        }        res[k][2] += 1;        return res;      }, {});            var max = 0;      result.reduce(function(res, value){        if(res < value[2]) {          res = value[2];          max = res;        }        return res;      }, 0);      //result = result.filter(word => word[2] == max);      console.log(result);      return(result);    },    option: function() {      var points = this.plot_data;      center = points.reduce(function(res, value){        return [res[0] + value[0], res[1] + value[1]];      }, [0,0]);      let center_x = center[0] / points.length;      let center_y = center[1] / points.length;      return {        animation: false,        bmap: {            center: [center_x, center_y],            zoom: 14,            roam: true        },        visualMap: {            show: false,            top: 'top',            min: 0,            max: 5,            seriesIndex: 0,            calculable: true,            inRange: {                color: ['blue', 'blue', 'green', 'yellow', 'red']            }        },        series: [{            type: 'heatmap',            coordinateSystem: 'bmap',            data: points,            pointSize: 5,            blurSize: 6        }]}          }      },   template: '<div></div>',   mounted: function() {    this.initMap();    this.updateMap();  },  watch: {    table_data: function() {      this.updateMap();    }  },  methods: {    initMap: function() {      this.map = echarts.init(this.$el);    } ,    updateMap: function() {      var app = {};      app.title = '热力图与百度地图扩展';      this.map.setOption(option = this.option);      var bmap = this.map.getModel().getComponent('bmap').getBMap();      bmap.addControl(new BMap.MapTypeControl());      this.map.setOption(option, true);    }  }  });