Kaynağa Gözat

web端数据更新接口编写提交

wanger 8 ay önce
ebeveyn
işleme
e996366b33

+ 2 - 2
processing/algs/gdal/GdalAlgorithmDialog.py

@@ -128,11 +128,11 @@ class GdalParametersPanel(ParametersPanel):
 
         label = QLabel()
         label.setText(self.tr("控制台"))
-        label.setHidden(gdalHidden)
+        # label.setHidden(gdalHidden)
         layout.addWidget(label)
         self.text = QPlainTextEdit()
         self.text.setReadOnly(True)
-        self.text.setHidden(gdalHidden)
+        # self.text.setHidden(gdalHidden)
         layout.addWidget(self.text)
 
         w.setLayout(layout)

+ 38 - 5
processing/algs/gdal/postgisrestore.py

@@ -52,6 +52,7 @@ from processing.tools.PrintUtils import printStr
 from processing.tools.StringUtils import getConnectionStr
 from processing.tools.GeoServer.Geoserver import Geoserver
 from processing.tools.PostgreSQL.PostgreSQL import PostgreSQL
+from processing.tools.Login.Redis import Redis
 
 from processing.tools.system import isWindows
 
@@ -65,6 +66,8 @@ class Postgisrestore(GdalAlgorithm):
     LOGIN_USER = "admin"
     UPDATEFILE = 'UPDATEFILE'
     RESTORETABLE = 'RESTORETABLE'
+    RESTOREVERSION = 'RESTOREVERSION'
+    CURVERSION = "CURVERSION"
     ALLOWOVERLAP = "ALLOWOVERLAP"
     DATABASE = 'DATABASE'
     INPUTFILE = 'INPUTFILE'
@@ -85,13 +88,31 @@ class Postgisrestore(GdalAlgorithm):
     def initAlgorithm(self, config=None):
         pgconn = PostgreSQL(schema='base')
         self.tables = pgconn.getManagerTables(username=self.LOGIN_USER)
-        pgconn.close()
         tablenames = []
         for row in self.tables:
             tablenames.append(row[2])
         self.addParameter(QgsProcessingParameterEnum(name=self.RESTORETABLE,
                                                      description=self.tr('目标数据源'),
                                                      options=tablenames))
+        redis = Redis()
+        tablename = redis.get("curRestoreTable")
+        print(tablename)
+        if tablename is not None:
+            tablename = tablename.decode('utf-8')
+            versions = pgconn.getTableVersions(tablename=tablename)
+            curversion = pgconn.getTableCurVersion(tablename=tablename)
+            tableversion_param = QgsProcessingParameterString(
+                self.CURVERSION,
+                self.tr('当前版本号'), defaultValue=curversion)
+            self.addParameter(tableversion_param)
+            self.versionlist = []
+            for row in versions:
+                self.versionlist.append(row[0])
+            self.addParameter(QgsProcessingParameterEnum(name=self.RESTOREVERSION,
+                                                         description=self.tr('目标版本'),
+                                                         options=self.versionlist))
+
+        pgconn.close()
 
     def name(self):
         return 'postgisrestore'
@@ -125,14 +146,26 @@ class Postgisrestore(GdalAlgorithm):
 
     def restoreVector(self, parameters, context, feedback, executing=True):
         print("版本回退开始啦")
+        pgconn = PostgreSQL(schema='base')
         tableinfo = self.tables[parameters[self.RESTORETABLE]]
         tablename = tableinfo[1]
-        pgconn = PostgreSQL(schema='base')
-        print("===========备份表===========")
-        pgconn.restoreBackTable(tablename=tablename)
+        # 判断回退版本关系
+        curversion = parameters[self.CURVERSION]
+        targetversion = self.versionlist[parameters[self.RESTOREVERSION]]
+        message = "版本回退成功"
+        if curversion == targetversion:
+            message = "版本相同不需要操作"
+        elif curversion > targetversion:
+            print("需要删除近期版本更新的数据")
+            pgconn.deleteVectorRecords(tablename=tablename, rksj_sw=targetversion)
+        else:
+            pgconn.insertVectorRecords(tablename=tablename, curversion=curversion, targetversion=targetversion)
+            print("需要插入近期版本更新的数据")
+        # print("===========备份表===========")
+        # pgconn.restoreBackTable(tablename=tablename)
         pgconn.close()
         return {
-            "状态": "版本回退成功"
+            "状态": message
         }
 
     # 判断数据是否为字符串

+ 6 - 4
processing/algs/gdal/postgisupdate.py

@@ -49,10 +49,9 @@ from qgis.core import (QgsProcessing,
 from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
 from processing.algs.gdal.GdalUtils import GdalUtils
 from processing.tools.PrintUtils import printStr
-from processing.tools.StringUtils import getConnectionStr
+from processing.tools.StringUtils import (getConnectionStr, getNow)
 from processing.tools.GeoServer.Geoserver import Geoserver
 from processing.tools.PostgreSQL.PostgreSQL import PostgreSQL
-
 from processing.tools.system import isWindows
 
 pluginPath = os.path.normpath(os.path.join(
@@ -132,6 +131,8 @@ class Postgisupdate(GdalAlgorithm):
     def updateVector(self, parameters, context, feedback, executing=True):
         print("增量更新开始啦")
         print("===========进行数据更新开始===========")
+        #当前时间
+        now = getNow()
         ogrLayer, layername = self.getOgrCompatibleSource(self.UPDATEFILE, parameters, context, feedback, executing)
         print(ogrLayer)
         allowoverlap = self.parameterAsBoolean(parameters, self.ALLOWOVERLAP, context)
@@ -140,7 +141,7 @@ class Postgisupdate(GdalAlgorithm):
         ywlx = tableinfo[3]
         pgconn = PostgreSQL(schema='base')
         print("===========备份表===========")
-        pgconn.resetBackTable(tablename=tablename)
+        # pgconn.resetBackTable(tablename=tablename)
         srid = pgconn.getVectorTableSrid(tablename=tablename)
         geomtype = pgconn.getVectorTableGeomType(tablename=tablename)
         print("===========打开矢量数据===========")
@@ -188,8 +189,9 @@ class Postgisupdate(GdalAlgorithm):
                         else:
                             insertvalus.append(None)
                 pgconn.insertVectorFeature(tablename=tablename, fields=alltablefiled, values=insertvalus, wkt=geom_wkt,
-                                           wktsrid=vectorepsg, geomtype=geomtype)
+                                           wktsrid=vectorepsg, geomtype=geomtype, rksj=now)
                 insertcount += 1
+        pgconn.updateVectorVersion(tablename=tablename, version=now)
         pgconn.close()
         return {
             "状态": "更新成功",

+ 113 - 0
processing/app.py

@@ -0,0 +1,113 @@
+# -*- coding: utf-8 -*-
+from flask import Flask, request, jsonify, send_from_directory, Response, make_response
+import uuid
+import requests
+from PIL import Image
+from io import BytesIO
+
+app = Flask(__name__)
+
+# 设置静态文件夹(如果您想指定路径)
+app.config['UPLOAD_FOLDER'] = 'predict/output'
+host = 'http://192.168.60.2'
+
+uploadPath = 'predict/upload/'
+outputPath = 'predict/output/'
+
+
+# GET 请求接口示例
+@app.route('/api/get_data', methods=['GET'])
+def get_data():
+    # 获取请求参数
+    param = request.args.get('param')
+    # 返回 JSON 响应
+    data = jsonify({
+        "message": "GET 请求成功",
+        "param": param
+    })
+    response = make_response(data)
+    # response.headers['Content-Type'] = 'text/plain; charset=utf-8'
+    return response
+
+
+# GET 请求接口示例
+@app.route('/api/postgisupdate', methods=['POST'])
+def postgisupdate():
+    # 获取请求参数
+    param = request.args.get('param')
+    # 返回 JSON 响应
+    return jsonify({
+        "message": "POST 请求成功",
+        "param": param
+    })
+
+
+# POST 上传图片
+@app.route('/api/upload_image', methods=['POST'])
+def upload_image():
+    # 获取上传的文件
+    img1 = request.files['img1']
+    img2 = request.files['img2']
+    # 保存文件
+    filePath1 = uploadPath + str(uuid.uuid4()) + img1.filename
+    filePath2 = uploadPath + str(uuid.uuid4()) + img2.filename
+
+    img1.save(filePath1)
+    img2.save(filePath2)
+    return jsonify({
+        "message": "上传成功",
+        "data": {
+            "img1": filePath1,
+            "img2": filePath2
+        }
+    })
+
+
+# POST 通过url保存图片到本地
+@app.route('/api/save_image', methods=['POST'])
+def save_image():
+    # 获取图片路径
+    data = request.get_json()
+    img1 = data['img1']
+    img2 = data['img2']
+
+    response1 = requests.get('http://192.168.60.63' + img1)
+    if response1.status_code != 200:
+        return jsonify({
+            "message": "图片1不存在",
+            "data": {
+                "img1": img1
+            }
+        })
+    img1 = Image.open(BytesIO(response1.content))
+    img1Path = uploadPath + str(uuid.uuid4()) + '.png'
+    img1.save(img1Path, format='PNG')
+
+    response2 = requests.get('http://192.168.60.63' + img2)
+    if response2.status_code != 200:
+        return jsonify({
+            "message": "图片2不存在",
+            "data": {
+                "img2": img2
+            }
+        })
+    img2 = Image.open(BytesIO(response2.content))
+    img2Path = uploadPath + str(uuid.uuid4()) + '.png'
+    img2.save(img2Path, format='PNG')
+
+    return jsonify({
+        "message": "保存成功",
+        "data": {
+            "img1": img1Path,
+            "img2": img2Path,
+        }
+    })
+
+
+# 访问静态文件
+@app.route('/predict/<filename>')
+def view_file(filename):
+    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
+
+if __name__ == '__main__':
+    app.run(debug=True, host='0.0.0.0', port=6500)

+ 106 - 0
processing/main.py

@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+import os
+import sys
+import json
+import utils
+import importlib, sys
+
+from osgeo import ogr
+
+from tools.PostgreSQL.PostgreSQL import PostgreSQL
+from tools.StringUtils import (getConnectionStr, getNow)
+
+importlib.reload(sys)
+
+
+def run(fun, data):
+    try:
+        message = eval("{0}".format(fun))(data)
+        print(message)
+        # 输出成功信息 做交互用
+        # print("####OK####")
+    except:
+        msg = str(sys.exc_info()).decode('string-escape')
+        print("####ERROR####" + msg)
+
+
+# 测试
+def test(data):
+    print(data["bsm"])
+
+
+# postgisupdate
+def postgisupdate(data):
+    print("===========进行数据更新开始===========")
+    # 当前时间
+    now = getNow()
+    # 获取参数
+    # ogrLayer = "D:\\gisdata\\三亚\\规划地块部分数据\\4525.shp"
+    # allowoverlap = True
+    # tablename = "vector.updatetest"
+    ogrLayer = data["source"]
+    allowoverlap = data["allowoverlap"]
+    tablename = data["target"]
+    pgconn = PostgreSQL(schema='base')
+    srid = pgconn.getVectorTableSrid(tablename=tablename)
+    geomtype = pgconn.getVectorTableGeomType(tablename=tablename)
+    ds = ogr.Open(ogrLayer, 0)
+    layer = ds.GetLayer()
+    layer_spatial_ref = layer.GetSpatialRef()
+    layer_def = layer.GetLayerDefn()
+    vectorepsg = layer_spatial_ref.GetAttrValue('AUTHORITY', 1)
+    alltablefiled = pgconn.getAllTableField(tablename=tablename)
+    insertcount = 0
+    misscount = 0
+    for feature in layer:
+        geom_wkt = feature.GetGeometryRef().ExportToWkt()
+        # 判断是否允许更新重叠数据
+        updatebool = True
+        if allowoverlap == False:
+            instersectsCount = pgconn.getInstersectsCount(tablename=tablename, tablesrid=srid, wkts=[geom_wkt],
+                                                          wktsrid=vectorepsg)
+            count = int(instersectsCount)
+            if count > 0:
+                updatebool = False
+                misscount += 1
+        if updatebool == True:
+            # 遍历当前数据的属性信息
+            attributes = {}
+            for i in range(layer_def.GetFieldCount()):
+                field_def = layer_def.GetFieldDefn(i)
+                field_name = field_def.GetName()
+                field_value = feature.GetField(i)
+                attributes[field_name] = field_value
+                # print(field_value)
+                # if self.is_string(field_value) == True:
+                #     print(field_value.encode('utf-8'))
+            # 拼接insert into语句
+            insertvalus = []
+            for field in alltablefiled:
+                b = utils.contains_keys(attributes, [field.lower()])
+                if b == True:
+                    insertvalus.append(attributes[field.lower()])
+                else:
+                    b = utils.contains_keys(attributes, [field.upper()])
+                    if b == True:
+                        insertvalus.append(attributes[field.upper()])
+                    else:
+                        insertvalus.append(None)
+            pgconn.insertVectorFeature(tablename=tablename, fields=alltablefiled, values=insertvalus, wkt=geom_wkt,
+                                       wktsrid=vectorepsg, geomtype=geomtype, rksj=now)
+            insertcount += 1
+    pgconn.updateVectorVersion(tablename=tablename, version=now)
+    pgconn.close()
+    return str({
+        "status": "更新成功",
+        "insert": str(insertcount) + "条记录",
+        "miss": str(misscount) + "条记录,存在空间叠加。"
+    })
+
+
+if __name__ == '__main__':
+    if len(sys.argv) == 3:
+        fun = sys.argv[1]
+        jsonData = utils.b64Decode(sys.argv[2])
+        print(jsonData)
+        run(fun, json.loads(jsonData))

+ 101 - 6
processing/tools/PostgreSQL/PostgreSQL.py

@@ -12,7 +12,9 @@ import psycopg2
 import uuid
 from ..FTP.FtpUitl import FtpOper
 from ..FTP.FtpConfig import *
-from processing.tools.FileUtils import getInputFileName
+from ..FileUtils import getInputFileName
+from ..StringUtils import (getNow, base64str, enbase64str)
+from datetime import datetime
 
 
 class PostgreSQL:
@@ -30,6 +32,10 @@ class PostgreSQL:
     BackTable = "_back"
     # 序列名称后缀
     Sequence = "_id_seq"
+    # 版本控制表
+    Vector_Version = "t_vector_version"
+    # 版本控制详情表
+    Vector_Version_Details = "t_vector_version_details"
 
     def __init__(
             self,
@@ -103,15 +109,69 @@ class PostgreSQL:
         else:
             table_alias = ''
         self.deleteVectorStorage(name=record_id)
+        self.deleteVectorVersion(tablename=record_id)
         self.insertVectorStorage(id=id, name=record_id, year=parameters.get("VECTOR_YEAR"),
                                  xmlx=zyml, sjly=parameters.get("VECTOR_SJLY"),
                                  xzqh=ssxzqh, xzqh_field=parameters.get("XZQH_FIELD"),
                                  ywlx=ywlx, sjlx=parameters.get("SOURCE_TYPE"), sjywz=ogrLayer,
                                  glbm=glbm, table_alias=table_alias)
+        self.insertVectorVersion(tablename=record_id)
         # 附件上传
         if fileliststr is not None and fileliststr != "":
             self.uploadAttachment(layername=record_id, layerid=id, fileliststr=fileliststr)
 
+    # 删除版本控制表
+    def deleteVectorVersion(self, tablename):
+        sql = "delete from {} where tablename = '{}'".format(self.Vector_Version, tablename)
+        self.cur.execute(sql)
+        self.conn.commit()
+
+    # 删除版本数据
+    def deleteVectorRecords(self, tablename, rksj_sw):
+        sql = "delete from {} t where t.rksj_sw > '{}'".format(tablename, rksj_sw)
+        self.cur.execute(sql)
+        self.conn.commit()
+        sql = "update {} set version = '{}' where tablename = '{}'".format(self.Vector_Version, rksj_sw,
+                                                                           tablename)
+        self.cur.execute(sql)
+        self.conn.commit()
+
+    # 插入版本数据
+    def insertVectorRecords(self, tablename, curversion ,targetversion):
+        sql = "select insertsql from {} t where t.tablename = '{}' and  t.version > '{}' and t.version <= '{}'".format(self.Vector_Version_Details, tablename, curversion, targetversion)
+        self.cur.execute(sql)
+        rows = self.cur.fetchall()
+        for row in rows:
+            sql = enbase64str(row[0])
+            self.cur.execute(sql)
+        sql = "update {} set version = '{}' where tablename = '{}'".format(self.Vector_Version, targetversion,
+                                                                           tablename)
+        self.cur.execute(sql)
+        self.conn.commit()
+
+    # 创建版本控制表
+    def insertVectorVersion(self, tablename):
+        formatted_time = getNow()
+        # 输出结果
+        print("当前时间:{}".format(formatted_time))
+        sql = "insert into {} (tablename, version, type) values ('{}', '{}', '{}')".format(self.Vector_Version,
+                                                                                           tablename, formatted_time,
+                                                                                           "base")
+        self.cur.execute(sql)
+        self.conn.commit()
+        sql = "alter table {} add column rksj_sw timestamp".format(tablename)
+        self.cur.execute(sql)
+        self.conn.commit()
+        sql = "update {} SET rksj_sw = to_timestamp('{}', 'YYYY-MM-DD HH24:MI:SS')".format(tablename, formatted_time)
+        self.cur.execute(sql)
+        self.conn.commit()
+        details = "insert into {} (tablename, version, insertsql) values ('{}', '{}', '{}')".format(
+            self.Vector_Version_Details, tablename, formatted_time,
+            "")
+        print(details)
+        self.cur.execute(details)
+        self.conn.commit()
+
     # 获取文件名称
     def getInputFileName(self, file):
         filename = file.split("/")[len(file.split("/")) - 1]
@@ -235,10 +295,10 @@ class PostgreSQL:
         return fields
 
     # 保存矢量要素
-    def insertVectorFeature(self, tablename, fields, values, wkt, wktsrid, geomtype):
+    def insertVectorFeature(self, tablename, fields, values, wkt, wktsrid, geomtype, rksj):
         arr = tablename.split(".")
         insertvalues = ""
-        print(values)
+        # print(values)
         for value in values:
             if value == None:
                 insertvalues += "null,"
@@ -248,8 +308,8 @@ class PostgreSQL:
                     insertvalues += f'\'{value}\','
                 else:
                     insertvalues += f'{value},'
-        print(insertvalues)
-        print(insertvalues[:-1])
+        # print(insertvalues)
+        # print(insertvalues[:-1])
         # 判断几何类型是否一致
         if wkt.startswith(geomtype) == False:
             if geomtype.startswith("MULTI"):  # 转换为Multi
@@ -259,9 +319,44 @@ class PostgreSQL:
                 wkt = wkt.replace("(((", "((").replace(")))", "))").replace("MULTI", "")
         sql = f'insert into {arr[0]}."{arr[1]}" ({",".join(fields)} , geom) values ({insertvalues[:-1]} , public.st_geomfromtext( \'{wkt}\', {wktsrid}))'
         sql = sql.replace("None", "null")
-        print(sql)
+        # print(sql)
         self.cur.execute(sql)
         self.conn.commit()
+        # 插入到更新详情表
+        details = "insert into {} (tablename, version, insertsql) values ('{}', '{}', '{}')".format(
+            self.Vector_Version_Details, tablename, rksj,
+            base64str(sql))
+        # print(details)
+        self.cur.execute(details)
+        self.conn.commit()
+
+    def updateVectorVersion(self, tablename, version):
+        details = "update {} set rksj_sw = to_timestamp('{}', 'YYYY-MM-DD HH24:MI:SS') where rksj_sw is null".format(
+            tablename, version)
+        self.cur.execute(details)
+        self.conn.commit()
+        details = "update {} set version = '{}', type = 'update' where tablename = '{}'".format(self.Vector_Version,
+                                                                                                version, tablename)
+        self.cur.execute(details)
+        self.conn.commit()
+
+    # 通过表名称获取版本集合
+    def getTableVersions(self, tablename):
+        sql = "select distinct(version) from {} t  where t.tablename = '{}' order by version desc".format(
+            self.Vector_Version_Details, tablename)
+        print(sql)
+        self.cur.execute(sql)
+        rows = self.cur.fetchall()
+        return rows
+
+    # 通过表名称获取当前版本
+    def getTableCurVersion(self, tablename):
+        sql = "select version from {} t where t.tablename = '{}'".format(
+            self.Vector_Version, tablename)
+        print(sql)
+        self.cur.execute(sql)
+        rows = self.cur.fetchall()
+        return rows[0][0]
 
     # 获取矢量数据表的坐标系
     def getVectorTableSrid(self, tablename):

+ 31 - 0
processing/tools/StringUtils.py

@@ -1,6 +1,8 @@
 import uuid
 import os
 import platform
+from datetime import datetime
+import base64
 
 
 def getConnectionStr(connstr, index):
@@ -55,3 +57,32 @@ def getUUID():
     id = uuid.uuid4().__str__()
     id = id.replace("-", "")
     return id
+
+# 获取当前时间
+def getNow():
+    # 获取当前时间
+    current_time = datetime.now()
+    # 将当前时间转换为 'YYYY-MM-DD HH:MM:SS' 格式
+    formatted_time = current_time.strftime('%Y-%m-%d %H:%M:%S')
+    return formatted_time
+
+# base64加密
+def base64str(string):
+    # 将字符串编码为字节
+    string_bytes = string.encode('utf-8')
+    # 使用 base64 编码
+    base64_bytes = base64.b64encode(string_bytes)
+    # 将编码后的字节转换为字符串
+    base64_string = base64_bytes.decode('utf-8')
+    # 输出结果
+    return base64_string
+
+#base64解密
+def enbase64str(base64_string):
+    # 将 Base64 字符串转换为字节
+    base64_bytes = base64_string.encode('utf-8')
+    # 使用 base64 解码
+    decoded_bytes = base64.b64decode(base64_bytes)
+    # 将字节解码为原始字符串
+    decoded_string = decoded_bytes.decode('utf-8')
+    return decoded_string

+ 71 - 0
processing/utils.py

@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+
+import datetime
+import uuid
+import base64
+import json
+import re
+
+
+def getUuid():
+    """获取UUID
+    :return: UUID字符串
+    """
+    return ''.join(str(uuid.uuid1()).split('-'))
+
+
+def b64Decode(b64):
+    """base64解码
+    :param b64: base64加密字符
+    :return: 解密字符串
+    """
+    return base64.b64decode(b64).decode('utf-8')
+
+
+def getNowTime():
+    """获取当前时间
+    :return: 当前时间
+    """
+    return datetime.datetime.now()
+
+
+def getNowTimeStr(format="%Y%m%d%H%M%S"):
+    """获取当前时间字符
+    :param format: 格式化字符串,默认返回yyyyMMddHHmmss
+    :return: 时间字符串
+    """
+    return getNowTime().strftime(format)
+
+
+def getTimeStr(time, format="%Y%m%d%H%M%S"):
+    """获取当前时间字符
+    :param format: 格式化字符串,默认返回yyyyMMddHHmmss
+    :return: 时间字符串
+    """
+    return time.strftime(format)
+
+
+def toJson(jstr):
+    """字符串转Json对象
+    :param jstr: Json字符串
+    :return: Json对象
+    """
+    return json.loads(jstr)
+
+
+# ———————— 正则 ————————
+def regDkh(str):
+    """正则 大括号
+    :param str: 字符串
+    :return: 数组
+    """
+    p = re.compile(r"[{](.*?)[}]", re.S)
+    return re.findall(p, str)
+
+def contains_keys(obj, keys):
+    if isinstance(obj, dict):
+        return all(key in obj.keys() for key in keys)
+    elif hasattr(type(obj), '__dict__'):
+        return all(key in obj.__dict__ for key in keys)
+    else:
+        raise ValueError("Invalid object type")