feat(database): 将数据库从 SQLite 迁移到 MySQL
- 修改了 DBService 类,增加了 MySQL 数据库连接配置 - 重新定义了表结构,适应 MySQL 数据库- 更新了相关的 SQL 查询语句 - 增加了创建数据库的逻辑 - 优化了表创建语句,使用 InnoDB 引擎和 UTF-8 字符集
This commit is contained in:
parent
31c2394e8a
commit
11530baefb
@ -9,27 +9,33 @@ from alibabacloud_sample.dbservice import DBService
|
|||||||
|
|
||||||
class DataService:
|
class DataService:
|
||||||
conn = None
|
conn = None
|
||||||
|
dbservice = DBService()
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.conn = DBService().get_conn()
|
self.conn = self.dbservice.get_conn()
|
||||||
# 插入文件记录
|
# 插入文件记录
|
||||||
def insert_file_data(self, file_name: str, file_path: str, file_size: int, file_type: str,file_time: str, file_hash: str):
|
def insert_file_data(self, file_name: str, file_path: str, file_size: int, file_type: str,file_time: str, file_hash: str):
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
try:
|
try:
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"INSERT INTO file_data(file_name,file_path,file_size,file_type,file_time,file_hash) values(?,?,?,?,?,?)",
|
"INSERT INTO file_data(file_name,file_path,file_size,file_type,file_time,file_hash) values(%s,%s,%s,%s,%s,%s)",
|
||||||
(file_name, file_path, file_size, file_type, file_time, file_hash))
|
(file_name, file_path, file_size, file_type, file_time, file_hash))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
cursor.execute("select file_path from file_data where file_hash = ?", (file_hash,))
|
cursor.execute("select file_name,file_path,file_size,file_type,file_time,file_hash from file_data where `file_hash` = %s", (file_hash,))
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
return rows[0][0]
|
data = {}
|
||||||
|
for i in range(len(rows[0])):
|
||||||
|
data[cursor.description[i][0]] = rows[0][i]
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
return file_path
|
return file_path
|
||||||
# 根据文件路径获取hash
|
# 根据文件路径获取hash
|
||||||
def get_invoice(self, file_path: str = None,invice_id: int = None) -> dict[Any, Any]:
|
def get_invoice(self, file_path: str = None,invice_id: int = None) -> dict[Any, Any]:
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
sql = """
|
sql = """
|
||||||
select id, checkCode, drawer, formType, invoiceAmountPreTax, invoiceCode,
|
select id, checkCode, drawer, formType, invoiceAmountPreTax, invoiceCode,
|
||||||
@ -39,29 +45,30 @@ class DataService:
|
|||||||
purchaserTaxNumber, recipient, remarks, reviewer,
|
purchaserTaxNumber, recipient, remarks, reviewer,
|
||||||
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
|
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
|
||||||
specialTag, title, totalAmount, totalAmountInWords,file_path,verify_time,
|
specialTag, title, totalAmount, totalAmountInWords,file_path,verify_time,
|
||||||
verify_time,verify_status,desc,desc_files,status
|
verify_time,verify_status,`desc`,desc_files,status
|
||||||
from invoice
|
from invoice
|
||||||
"""
|
"""
|
||||||
if invice_id:
|
if invice_id:
|
||||||
sql += " where id = ?"
|
sql += " where id = '"+str(invice_id)+"'"
|
||||||
cursor.execute(sql, (invice_id,))
|
cursor.execute(sql)
|
||||||
else:
|
else:
|
||||||
sql += " where file_path = ?"
|
sql += " where file_path = '"+file_path+"'"
|
||||||
cursor.execute(sql, (file_path,))
|
cursor.execute(sql)
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
data = {}
|
data = {}
|
||||||
if len(rows) > 0:
|
if len(rows) > 0:
|
||||||
for i in range(len(rows[0])):
|
for i in range(len(rows[0])):
|
||||||
data[cursor.description[i][0]] = rows[0][i]
|
data[cursor.description[i][0]] = rows[0][i]
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
# 根据文件hash获取文件
|
# 根据文件hash获取文件
|
||||||
def get_file(self, file_hash: str,file_size: int) -> dict[Any, Any] | None:
|
def get_file(self, file_hash: str,file_size: int) -> dict[Any, Any] | None:
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
select file_name,file_path,file_size,file_type,file_time,file_hash
|
select file_name,file_path,file_size,file_type,file_time,file_hash
|
||||||
from file_data where file_hash = ? and file_size = ?
|
from file_data where `file_hash` = %s and file_size = %s
|
||||||
"""
|
"""
|
||||||
, (file_hash,file_size,))
|
, (file_hash,file_size,))
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
@ -70,11 +77,12 @@ class DataService:
|
|||||||
data = {}
|
data = {}
|
||||||
for i in range(len(rows[0])):
|
for i in range(len(rows[0])):
|
||||||
data[cursor.description[i][0]] = rows[0][i]
|
data[cursor.description[i][0]] = rows[0][i]
|
||||||
|
|
||||||
return data
|
return data
|
||||||
return None
|
return None
|
||||||
# 插入发票记录
|
# 插入发票记录
|
||||||
def insert_invoice_log(self, data: dict, file_path: str):
|
def insert_invoice_log(self, data: dict, file_path: str):
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
# 插入主表数据
|
# 插入主表数据
|
||||||
invoice_insert = """
|
invoice_insert = """
|
||||||
@ -86,7 +94,7 @@ class DataService:
|
|||||||
purchaserTaxNumber, recipient, remarks, reviewer,
|
purchaserTaxNumber, recipient, remarks, reviewer,
|
||||||
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
|
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
|
||||||
specialTag, title, totalAmount, totalAmountInWords,file_path
|
specialTag, title, totalAmount, totalAmountInWords,file_path
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
"""
|
"""
|
||||||
invoice_values = (
|
invoice_values = (
|
||||||
data.get('checkCode', ''),
|
data.get('checkCode', ''),
|
||||||
@ -122,37 +130,39 @@ class DataService:
|
|||||||
cursor.execute(invoice_insert, invoice_values)
|
cursor.execute(invoice_insert, invoice_values)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
invoice_id = cursor.lastrowid
|
invoice_id = cursor.lastrowid
|
||||||
|
|
||||||
return invoice_id
|
return invoice_id
|
||||||
# 更新发票状态
|
# 更新发票状态
|
||||||
def update_invoice_status(self, invoice_id: int, verify_status: str,inspectionAmount :str ):
|
def update_invoice_status(self, invoice_id: int, verify_status: str,inspectionAmount :str ):
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"UPDATE invoice SET verify_time = ?, "
|
"UPDATE invoice SET verify_time = %s, "
|
||||||
"verify_status = ?, "
|
"verify_status = %s, "
|
||||||
"inspectionAmount = ?, "
|
"inspectionAmount = %s, "
|
||||||
"status = 'no'"
|
"status = 'no'"
|
||||||
"WHERE id = ?",
|
"WHERE id = %s",
|
||||||
(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), verify_status,inspectionAmount, invoice_id))
|
(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), verify_status,inspectionAmount, invoice_id))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
def update_invoice_desc(self, invoice_id: int|str, desc: str, desc_file: str,status: str) -> str:
|
def update_invoice_desc(self, invoice_id: int|str, desc: str, desc_file: str,status: str) -> str:
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"UPDATE invoice SET "
|
"UPDATE invoice SET "
|
||||||
"desc = ?,"
|
"`desc` = %s,"
|
||||||
"desc_files = ?,"
|
"desc_files = %s,"
|
||||||
"status = ? "
|
"status = %s "
|
||||||
"WHERE id = ?",
|
"WHERE id = %s",
|
||||||
(desc, desc_file,status, invoice_id))
|
(desc, desc_file,status, invoice_id))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return "success"
|
return "success"
|
||||||
# 查询验证记录
|
# 查询验证记录
|
||||||
def get_verify_log(self, file_path: str) -> dict[Any, Any]|None:
|
def get_verify_log(self, file_path: str) -> dict[Any, Any]|None:
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
select inspectionAmount,cyjgxx,verify_time,file_path from verify_log where file_path = ? order by verify_time desc limit 1
|
select inspectionAmount,cyjgxx,verify_time,file_path from verify_log where file_path = %s order by verify_time desc limit 1
|
||||||
"""
|
"""
|
||||||
, (file_path,))
|
, (file_path,))
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
@ -160,22 +170,24 @@ class DataService:
|
|||||||
data = {}
|
data = {}
|
||||||
for i in range(len(rows[0])):
|
for i in range(len(rows[0])):
|
||||||
data[cursor.description[i][0]] = rows[0][i]
|
data[cursor.description[i][0]] = rows[0][i]
|
||||||
|
|
||||||
return data
|
return data
|
||||||
return None
|
return None
|
||||||
# 插入验证记录
|
# 插入验证记录
|
||||||
def insert_verify_log(self, inspection_amount: str, cyjgxx: str, file_path: str):
|
def insert_verify_log(self, inspection_amount: str, cyjgxx: str, file_path: str):
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"INSERT INTO verify_log(inspectionAmount,cyjgxx,verify_time,file_path) values(?,?,?,?)",
|
"INSERT INTO verify_log(inspectionAmount,cyjgxx,verify_time,file_path) values(%s,%s,%s,%s)",
|
||||||
(inspection_amount,cyjgxx,parser.parse(datetime.now().strftime("%Y-%m-%d %H:%M:%S")),file_path))
|
(inspection_amount,cyjgxx,parser.parse(datetime.now().strftime("%Y-%m-%d %H:%M:%S")),file_path))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
# 查询验证记录
|
# 查询验证记录
|
||||||
def get_verify_log_list(self, file_path: str) -> list[dict[Any, Any]]:
|
def get_verify_log_list(self, file_path: str) -> list[dict[Any, Any]]:
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
select inspectionAmount,cyjgxx,verify_time,file_path from verify_log where file_path = ?
|
select inspectionAmount,cyjgxx,verify_time,file_path from verify_log where file_path = %s
|
||||||
"""
|
"""
|
||||||
, (file_path,))
|
, (file_path,))
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
@ -187,10 +199,11 @@ class DataService:
|
|||||||
'verify_time': row[2],
|
'verify_time': row[2],
|
||||||
'file_path': row[3]
|
'file_path': row[3]
|
||||||
})
|
})
|
||||||
|
|
||||||
return data
|
return data
|
||||||
# 查询发票列表
|
# 查询发票列表
|
||||||
def get_invoice_list(self, value: str, verify_status: str, time_out = 'all' ,start_date: datetime = None, end_date: datetime = None) -> list[dict[Any, Any]]:
|
def get_invoice_list(self, value: str, verify_status: str, time_out = 'all' ,start_date: datetime = None, end_date: datetime = None) -> list[dict[Any, Any]]:
|
||||||
conn = DBService().get_conn()
|
conn = self.dbservice.get_conn()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
sql = """
|
sql = """
|
||||||
select id, checkCode, drawer, formType, invoiceAmountPreTax, invoiceCode,
|
select id, checkCode, drawer, formType, invoiceAmountPreTax, invoiceCode,
|
||||||
@ -199,7 +212,7 @@ class DataService:
|
|||||||
purchaserBankAccountInfo, purchaserContactInfo, purchaserName,
|
purchaserBankAccountInfo, purchaserContactInfo, purchaserName,
|
||||||
purchaserTaxNumber, recipient, remarks, reviewer,
|
purchaserTaxNumber, recipient, remarks, reviewer,
|
||||||
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
|
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
|
||||||
specialTag, title, totalAmount, totalAmountInWords,file_path,verify_time,verify_status,inspectionAmount,desc,desc_files,status
|
specialTag, title, totalAmount, totalAmountInWords,file_path,verify_time,verify_status,inspectionAmount,`desc`,desc_files,status
|
||||||
from invoice where
|
from invoice where
|
||||||
"""
|
"""
|
||||||
if time_out != 'all':
|
if time_out != 'all':
|
||||||
@ -243,7 +256,7 @@ class DataService:
|
|||||||
sql += "title like '%" + value + "%' or "
|
sql += "title like '%" + value + "%' or "
|
||||||
sql += "totalAmount like '%" + value + "%' or "
|
sql += "totalAmount like '%" + value + "%' or "
|
||||||
sql += "totalAmountInWords like '%" + value + "%' or "
|
sql += "totalAmountInWords like '%" + value + "%' or "
|
||||||
sql += "desc like '%" + value + "%' or "
|
sql += "`desc` like '%" + value + "%' or "
|
||||||
sql += "desc_files like '%" + value + "%' "
|
sql += "desc_files like '%" + value + "%' "
|
||||||
sql += ")"
|
sql += ")"
|
||||||
sql += " order by verify_time desc"
|
sql += " order by verify_time desc"
|
||||||
@ -256,4 +269,5 @@ class DataService:
|
|||||||
for i in range(len(row)):
|
for i in range(len(row)):
|
||||||
data[cursor.description[i][0]] = row[i]
|
data[cursor.description[i][0]] = row[i]
|
||||||
datas.append(data)
|
datas.append(data)
|
||||||
|
|
||||||
return datas
|
return datas
|
||||||
@ -1,20 +1,30 @@
|
|||||||
import sqlite3
|
import mysql.connector
|
||||||
from sqlite3 import Error
|
from mysql.connector import Error
|
||||||
|
|
||||||
|
|
||||||
class DBService:
|
class DBService:
|
||||||
db_file = "/data/verify.db"
|
# MySQL数据库连接配置
|
||||||
|
db_config = {
|
||||||
|
'host': '101.200.148.149',
|
||||||
|
'port': 4406,
|
||||||
|
'user': 'root',
|
||||||
|
'password': 'Jian(1@3)',
|
||||||
|
'database': 'verify_db'
|
||||||
|
}
|
||||||
conn = None
|
conn = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
初始化函数
|
初始化函数
|
||||||
"""
|
"""
|
||||||
self.conn = self.get_conn()
|
self.conn = self.get_conn()
|
||||||
print("DBService init")
|
print("DBService init")
|
||||||
|
self.create_database()
|
||||||
self.create_file_data_table()
|
self.create_file_data_table()
|
||||||
self.create_invoice_table()
|
self.create_invoice_table()
|
||||||
self.create_verify_log_table()
|
self.create_verify_log_table()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_conn(self):
|
def get_conn(self):
|
||||||
"""
|
"""
|
||||||
创建数据库连接
|
创建数据库连接
|
||||||
@ -22,15 +32,36 @@ class DBService:
|
|||||||
返回值:
|
返回值:
|
||||||
连接对象
|
连接对象
|
||||||
"""
|
"""
|
||||||
if self.conn is not None:
|
if self.conn is not None and self.conn.is_connected():
|
||||||
return self.conn
|
return self.conn
|
||||||
try:
|
try:
|
||||||
self.conn = sqlite3.connect(self.db_file)
|
self.conn = mysql.connector.connect(**self.db_config)
|
||||||
except Error as e:
|
except Error as e:
|
||||||
print(e)
|
print(e)
|
||||||
return self.conn
|
return self.conn
|
||||||
def create_verify_log_table(self):
|
|
||||||
|
|
||||||
|
def create_database(self):
|
||||||
|
"""
|
||||||
|
创建数据库
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 连接 MySQL 服务器(不指定数据库)
|
||||||
|
server_config = self.db_config.copy()
|
||||||
|
server_config.pop('database', None)
|
||||||
|
server_conn = mysql.connector.connect(**server_config)
|
||||||
|
cursor = server_conn.cursor()
|
||||||
|
|
||||||
|
# 创建数据库
|
||||||
|
cursor.execute(f"CREATE DATABASE IF NOT EXISTS {self.db_config['database']} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")
|
||||||
|
cursor.close()
|
||||||
|
server_conn.close()
|
||||||
|
|
||||||
|
# 重新连接到指定数据库
|
||||||
|
self.conn = self.get_conn()
|
||||||
|
except Error as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
def create_verify_log_table(self):
|
||||||
"""
|
"""
|
||||||
创建验证记录表
|
创建验证记录表
|
||||||
该函数用于创建表,并返回创建结果
|
该函数用于创建表,并返回创建结果
|
||||||
@ -40,17 +71,19 @@ class DBService:
|
|||||||
# c = self.get_conn().cursor()
|
# c = self.get_conn().cursor()
|
||||||
# c.execute(delete_table_sql)
|
# c.execute(delete_table_sql)
|
||||||
create_table_sql = """CREATE TABLE IF NOT EXISTS verify_log (
|
create_table_sql = """CREATE TABLE IF NOT EXISTS verify_log (
|
||||||
id integer PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
cyjgxx text NOT NULL,
|
cyjgxx TEXT NOT NULL,
|
||||||
inspectionAmount text NOT NULL,
|
inspectionAmount VARCHAR(255) NOT NULL,
|
||||||
verify_time text NOT NULL,
|
verify_time VARCHAR(255) NOT NULL,
|
||||||
file_path text NOT NULL,
|
file_path TEXT NOT NULL,
|
||||||
desc text
|
`desc` TEXT
|
||||||
);"""
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"""
|
||||||
c = self.get_conn().cursor()
|
c = self.get_conn().cursor()
|
||||||
c.execute(create_table_sql)
|
c.execute(create_table_sql)
|
||||||
|
self.get_conn().commit()
|
||||||
except Error as e:
|
except Error as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
# 文件数据表
|
# 文件数据表
|
||||||
def create_file_data_table(self):
|
def create_file_data_table(self):
|
||||||
"""
|
"""
|
||||||
@ -62,15 +95,15 @@ class DBService:
|
|||||||
# c = self.get_conn().cursor()
|
# c = self.get_conn().cursor()
|
||||||
# c.execute(delete_table_sql)
|
# c.execute(delete_table_sql)
|
||||||
create_table_sql = """CREATE TABLE IF NOT EXISTS file_data (
|
create_table_sql = """CREATE TABLE IF NOT EXISTS file_data (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
file_name text NOT NULL,
|
file_name TEXT NOT NULL,
|
||||||
file_path text NOT NULL,
|
file_path TEXT NOT NULL,
|
||||||
file_size integer NOT NULL,
|
file_size INT NOT NULL,
|
||||||
file_type text NOT NULL,
|
file_type VARCHAR(50) NOT NULL,
|
||||||
file_time text NOT NULL,
|
file_time VARCHAR(50) NOT NULL,
|
||||||
file_hash text NOT NULL,
|
file_hash VARCHAR(255) NOT NULL,
|
||||||
UNIQUE (file_hash) -- 联合唯一约束
|
UNIQUE KEY unique_file_hash (file_hash)
|
||||||
);"""
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"""
|
||||||
c = self.get_conn().cursor()
|
c = self.get_conn().cursor()
|
||||||
c.execute(create_table_sql)
|
c.execute(create_table_sql)
|
||||||
self.get_conn().commit()
|
self.get_conn().commit()
|
||||||
@ -85,47 +118,48 @@ class DBService:
|
|||||||
create_table_sql = """
|
create_table_sql = """
|
||||||
-- 主表存储发票基本信息
|
-- 主表存储发票基本信息
|
||||||
CREATE TABLE IF NOT EXISTS invoice (
|
CREATE TABLE IF NOT EXISTS invoice (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
checkCode TEXT NOT NULL UNIQUE, -- 校验码(唯一)
|
checkCode VARCHAR(255), -- 校验码(唯一)
|
||||||
drawer TEXT, -- 开票人
|
drawer VARCHAR(100), -- 开票人
|
||||||
formType TEXT, -- 表单类型
|
formType VARCHAR(100), -- 表单类型
|
||||||
invoiceAmountPreTax REAL, -- 税前金额
|
invoiceAmountPreTax DECIMAL(15,2), -- 税前金额
|
||||||
invoiceCode TEXT NOT NULL, -- 发票代码
|
invoiceCode VARCHAR(50) NOT NULL, -- 发票代码
|
||||||
invoiceDate TEXT, -- 开票日期
|
invoiceDate VARCHAR(50), -- 开票日期
|
||||||
invoiceNumber TEXT NOT NULL, -- 发票号码
|
invoiceNumber VARCHAR(50) NOT NULL, -- 发票号码
|
||||||
invoiceTax REAL, -- 发票税额
|
invoiceTax DECIMAL(15,2), -- 发票税额
|
||||||
invoiceType TEXT, -- 发票类型
|
invoiceType VARCHAR(100), -- 发票类型
|
||||||
machineCode TEXT, -- 机器编号
|
machineCode VARCHAR(50), -- 机器编号
|
||||||
passwordArea TEXT, -- 密码区
|
passwordArea TEXT, -- 密码区
|
||||||
printedInvoiceCode TEXT, -- 打印发票代码
|
printedInvoiceCode VARCHAR(50), -- 打印发票代码
|
||||||
printedInvoiceNumber TEXT, -- 打印发票号码
|
printedInvoiceNumber VARCHAR(50), -- 打印发票号码
|
||||||
purchaserBankAccountInfo TEXT, -- 购买方银行信息
|
purchaserBankAccountInfo TEXT, -- 购买方银行信息
|
||||||
purchaserContactInfo TEXT, -- 购买方联系信息
|
purchaserContactInfo TEXT, -- 购买方联系信息
|
||||||
purchaserName TEXT, -- 购买方名称
|
purchaserName VARCHAR(255), -- 购买方名称
|
||||||
purchaserTaxNumber TEXT, -- 购买方税号
|
purchaserTaxNumber VARCHAR(100), -- 购买方税号
|
||||||
recipient TEXT, -- 收款人
|
recipient VARCHAR(100), -- 收款人
|
||||||
remarks TEXT, -- 备注
|
remarks TEXT, -- 备注
|
||||||
reviewer TEXT, -- 复核人
|
reviewer VARCHAR(100), -- 复核人
|
||||||
sellerBankAccountInfo TEXT, -- 销售方银行信息
|
sellerBankAccountInfo TEXT, -- 销售方银行信息
|
||||||
sellerContactInfo TEXT, -- 销售方联系信息
|
sellerContactInfo TEXT, -- 销售方联系信息
|
||||||
sellerName TEXT, -- 销售方名称
|
sellerName VARCHAR(255), -- 销售方名称
|
||||||
sellerTaxNumber TEXT, -- 销售方税号
|
sellerTaxNumber VARCHAR(100), -- 销售方税号
|
||||||
specialTag TEXT, -- 特殊标记
|
specialTag VARCHAR(50), -- 特殊标记
|
||||||
title TEXT, -- 发票标题
|
title VARCHAR(255), -- 发票标题
|
||||||
totalAmount REAL, -- 合计金额
|
totalAmount DECIMAL(15,2), -- 合计金额
|
||||||
totalAmountInWords TEXT, -- 大写金额
|
totalAmountInWords VARCHAR(255), -- 大写金额
|
||||||
file_path TEXT, -- 文件哈希
|
file_path TEXT, -- 文件哈希
|
||||||
verify_time TEXT, -- 验证时间
|
verify_time VARCHAR(50), -- 验证时间
|
||||||
verify_status TEXT, -- 验证结果
|
verify_status VARCHAR(50), -- 验证结果
|
||||||
inspectionAmount TEXT, -- 验证次数
|
inspectionAmount VARCHAR(50), -- 验证次数
|
||||||
desc TEXT, -- 备注
|
`desc` TEXT, -- 备注
|
||||||
desc_files TEXT, -- 备注附件
|
desc_files TEXT, -- 备注附件
|
||||||
status TEXT, -- 是否报销(yes,no)
|
status VARCHAR(20), -- 是否报销(yes,no)
|
||||||
UNIQUE (invoiceCode, invoiceNumber) -- 联合唯一约束
|
UNIQUE KEY unique_invoice (invoiceCode, invoiceNumber)
|
||||||
);
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
c = self.get_conn().cursor()
|
c = self.get_conn().cursor()
|
||||||
c.execute(create_table_sql)
|
c.execute(create_table_sql)
|
||||||
|
self.get_conn().commit()
|
||||||
except Error as e:
|
except Error as e:
|
||||||
print(e)
|
print(e)
|
||||||
@ -137,10 +137,9 @@ class Service:
|
|||||||
except Exception as error:
|
except Exception as error:
|
||||||
# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
|
# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
|
||||||
# 错误 message
|
# 错误 message
|
||||||
print(error.message)
|
print(error)
|
||||||
# 诊断地址
|
# 诊断地址
|
||||||
print(error.data.get("Recommend"))
|
UtilClient.assert_as_string(error)
|
||||||
UtilClient.assert_as_string(error.message)
|
|
||||||
# 发票验证记录
|
# 发票验证记录
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_verify_log_list(file_path):
|
def get_verify_log_list(file_path):
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
|||||||
:root{font-family:system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;background-color:#242424;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}body{margin:0;display:flex;place-items:center;min-width:320px;min-height:100vh}h1{font-size:3.2em;line-height:1.1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}.card{padding:2em}#app{width:100%;height:100%;margin:0 auto;padding:2rem;text-align:center}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}}.pdf[data-v-9e6af8d9]{width:100%;height:100%}.container[data-v-070d63cc]{margin-top:50px;height:100%}.pdf[data-v-5e9f78dd]{width:100%;height:100%}.ant-steps[data-v-85ed0412]{padding:0 20px 20px}.table-operations[data-v-31c060b8]{margin-bottom:16px;text-align:right}.table-operations>button[data-v-31c060b8]{margin-right:8px}#components-layout-demo-top-side .logo[data-v-274d3151]{float:left;height:31px;margin:16px 24px 16px 0;background:#ffffff4d}.ant-row-rtl #components-layout-demo-top-side .logo[data-v-274d3151]{float:right;margin:16px 0 16px 24px}.container[data-v-274d3151]{height:100%}html,body{width:100%;height:100%}input::-ms-clear,input::-ms-reveal{display:none}*,*:before,*:after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0)}@-ms-viewport{width:device-width}body{margin:0}[tabindex="-1"]:focus{outline:none}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5em;font-weight:500}p{margin-top:0;margin-bottom:1em}abbr[title],abbr[data-original-title]{-webkit-text-decoration:underline dotted;text-decoration:underline;text-decoration:underline dotted;border-bottom:0;cursor:help}address{margin-bottom:1em;font-style:normal;line-height:inherit}input[type=text],input[type=password],input[type=number],textarea{-webkit-appearance:none}ol,ul,dl{margin-top:0;margin-bottom:1em}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}pre,code,kbd,samp{font-size:1em;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace}pre{margin-top:0;margin-bottom:1em;overflow:auto}figure{margin:0 0 1em}img{vertical-align:middle;border-style:none}a,area,button,[role=button],input:not([type=range]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75em;padding-bottom:.3em;text-align:left;caption-side:bottom}input,button,select,optgroup,textarea{margin:0;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;margin:0;padding:0;border:0}legend{display:block;width:100%;max-width:100%;margin-bottom:.5em;padding:0;color:inherit;font-size:1.5em;line-height:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{padding:.2em;background-color:#feffe6}
|
:root{font-family:system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;background-color:#242424;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}body{margin:0;display:flex;place-items:center;min-width:320px;min-height:100vh}h1{font-size:3.2em;line-height:1.1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}.card{padding:2em}#app{width:100%;height:100%;margin:0 auto;padding:2rem;text-align:center}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}}.pdf[data-v-9e6af8d9]{width:100%;height:100%}.container[data-v-80a50284]{margin-top:50px;height:100%}.pdf[data-v-c4a3080b]{width:100%;height:100%}.ant-steps[data-v-f2a9b4bc]{padding:0 20px 20px}.table-operations[data-v-2eaa32bb]{margin-bottom:16px;text-align:right}.table-operations>button[data-v-2eaa32bb]{margin-right:8px}#components-layout-demo-top-side .logo[data-v-274d3151]{float:left;height:31px;margin:16px 24px 16px 0;background:#ffffff4d}.ant-row-rtl #components-layout-demo-top-side .logo[data-v-274d3151]{float:right;margin:16px 0 16px 24px}.container[data-v-274d3151]{height:100%}html,body{width:100%;height:100%}input::-ms-clear,input::-ms-reveal{display:none}*,*:before,*:after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0)}@-ms-viewport{width:device-width}body{margin:0}[tabindex="-1"]:focus{outline:none}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5em;font-weight:500}p{margin-top:0;margin-bottom:1em}abbr[title],abbr[data-original-title]{-webkit-text-decoration:underline dotted;text-decoration:underline;text-decoration:underline dotted;border-bottom:0;cursor:help}address{margin-bottom:1em;font-style:normal;line-height:inherit}input[type=text],input[type=password],input[type=number],textarea{-webkit-appearance:none}ol,ul,dl{margin-top:0;margin-bottom:1em}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}pre,code,kbd,samp{font-size:1em;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace}pre{margin-top:0;margin-bottom:1em;overflow:auto}figure{margin:0 0 1em}img{vertical-align:middle;border-style:none}a,area,button,[role=button],input:not([type=range]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75em;padding-bottom:.3em;text-align:left;caption-side:bottom}input,button,select,optgroup,textarea{margin:0;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;margin:0;padding:0;border:0}legend{display:block;width:100%;max-width:100%;margin-bottom:.5em;padding:0;color:inherit;font-size:1.5em;line-height:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{padding:.2em;background-color:#feffe6}
|
||||||
@ -5,8 +5,8 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + Vue + TS</title>
|
<title>Vite + Vue + TS</title>
|
||||||
<script type="module" crossorigin src="/assets/index-CxFq9mgc.js"></script>
|
<script type="module" crossorigin src="/assets/index-Y26lO6c_.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-T_5mvQco.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-wINpQLiP.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@ -8,4 +8,5 @@ Flask==3.1.1
|
|||||||
flask_cors==6.0.1
|
flask_cors==6.0.1
|
||||||
python_dateutil==2.9.0.post0
|
python_dateutil==2.9.0.post0
|
||||||
Werkzeug==3.1.3
|
Werkzeug==3.1.3
|
||||||
setuptools
|
setuptools==80.9.0
|
||||||
|
mysql-connector-python==9.4.0
|
||||||
@ -38,7 +38,7 @@ const previousPage = () => {
|
|||||||
};
|
};
|
||||||
// 保存
|
// 保存
|
||||||
const saveReport = () => {
|
const saveReport = () => {
|
||||||
console.log('保存成功')
|
current.value = 0
|
||||||
}
|
}
|
||||||
// 表单数据
|
// 表单数据
|
||||||
const formState = ref<string>('');
|
const formState = ref<string>('');
|
||||||
@ -58,7 +58,7 @@ const formState = ref<string>('');
|
|||||||
<a-col :span="12" offset="16">
|
<a-col :span="12" offset="16">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button type="default" v-if="current > 0" @click="previousPage">上一步</a-button>
|
<a-button type="default" v-if="current > 0" @click="previousPage">上一步</a-button>
|
||||||
<a-button type="primary" v-if="current < items.length-1 " @click="nextPage">下一步</a-button>
|
<a-button type="primary" v-if="current < items.length-1 " :disabled="!filePath" @click="nextPage">下一步</a-button>
|
||||||
<a-button type="dashed" v-if="current == items.length-1" @click="saveReport">完成</a-button>
|
<a-button type="dashed" v-if="current == items.length-1" @click="saveReport">完成</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-layout-content>
|
<a-layout-content>
|
||||||
|
<a-spin v-if="loadding">
|
||||||
|
</a-spin>
|
||||||
<a-result
|
<a-result
|
||||||
:status="formState.status"
|
:status="formState.status"
|
||||||
:title="formState.cyjgxx"
|
:title="formState.cyjgxx"
|
||||||
@ -16,7 +18,7 @@ import {ref,onMounted } from 'vue';
|
|||||||
import request from "../../utils/request.ts";
|
import request from "../../utils/request.ts";
|
||||||
const props = defineProps({ filePath: String });
|
const props = defineProps({ filePath: String });
|
||||||
import {baseURL} from "../../utils/baseurl.ts";
|
import {baseURL} from "../../utils/baseurl.ts";
|
||||||
|
let loadding = ref(true)
|
||||||
const fileType = ref<string>('img')
|
const fileType = ref<string>('img')
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// alert(props.filePath)
|
// alert(props.filePath)
|
||||||
@ -25,6 +27,7 @@ onMounted(() => {
|
|||||||
request.get('/verify?filePath='+encodeURIComponent(props.filePath)).then((res) => {
|
request.get('/verify?filePath='+encodeURIComponent(props.filePath)).then((res) => {
|
||||||
console.log(res)
|
console.log(res)
|
||||||
formState.value = res.data
|
formState.value = res.data
|
||||||
|
loadding.value = false
|
||||||
})
|
})
|
||||||
fileUrl.value = baseURL+"/"+props.filePath
|
fileUrl.value = baseURL+"/"+props.filePath
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,7 +63,7 @@ const handleUpload = (options: any) => {
|
|||||||
:max-count="1"
|
:max-count="1"
|
||||||
@remove="handleRemove"
|
@remove="handleRemove"
|
||||||
>
|
>
|
||||||
<a-button >
|
<a-button>
|
||||||
<upload-outlined></upload-outlined>
|
<upload-outlined></upload-outlined>
|
||||||
上传发票
|
上传发票
|
||||||
</a-button>
|
</a-button>
|
||||||
|
|||||||
@ -129,12 +129,13 @@ const handleOk = () => {
|
|||||||
invoiceId: formData.value.id,
|
invoiceId: formData.value.id,
|
||||||
status: formData.value.status?'yes':'no',
|
status: formData.value.status?'yes':'no',
|
||||||
desc: formData.value.desc,
|
desc: formData.value.desc,
|
||||||
desc_files: formData.value.fileIds.join(','),
|
desc_files: formData.value.fileIds?.join(','),
|
||||||
}).then(( res ) => {
|
}).then(( res ) => {
|
||||||
if(res.status == 200){
|
if(res.status == 200){
|
||||||
openModal.value = false;
|
openModal.value = false;
|
||||||
confirmLoading.value = false;
|
confirmLoading.value = false;
|
||||||
messageApi.success("修改成功")
|
messageApi.success("修改成功")
|
||||||
|
getList();//刷新
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
@ -146,8 +147,8 @@ const handleOpen = (record:any) => {
|
|||||||
}
|
}
|
||||||
formData.value = Object.assign({}, record);
|
formData.value = Object.assign({}, record);
|
||||||
formData.value.status = (record.status === 'yes')
|
formData.value.status = (record.status === 'yes')
|
||||||
formData.value.fileIds = record.desc_files.split(',');
|
|
||||||
if (record.desc_files) {
|
if (record.desc_files) {
|
||||||
|
formData.value.fileIds = record.desc_files.split(',');
|
||||||
let paths = record.desc_files.split(",")
|
let paths = record.desc_files.split(",")
|
||||||
fileList.value = []
|
fileList.value = []
|
||||||
for(let i = 0; i < paths.length; i++) {
|
for(let i = 0; i < paths.length; i++) {
|
||||||
@ -201,6 +202,9 @@ const handlePreview = async (file: any) => {
|
|||||||
const handleFileChange = (info: UploadChangeParam) => {
|
const handleFileChange = (info: UploadChangeParam) => {
|
||||||
if(info.file.status === 'done'){
|
if(info.file.status === 'done'){
|
||||||
info.file.uid = info.file.response.file_path
|
info.file.uid = info.file.response.file_path
|
||||||
|
if (!formData.value.fileIds){
|
||||||
|
formData.value.fileIds = new Array<String>();
|
||||||
|
}
|
||||||
formData.value.fileIds.push(info.file.response.file_path)
|
formData.value.fileIds.push(info.file.response.file_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import axios, {type AxiosInstance} from 'axios';
|
|||||||
import {baseURL} from "./baseurl.ts";
|
import {baseURL} from "./baseurl.ts";
|
||||||
const service: AxiosInstance = axios.create({
|
const service: AxiosInstance = axios.create({
|
||||||
baseURL: baseURL,
|
baseURL: baseURL,
|
||||||
timeout: 5000,
|
timeout: 50000,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 导出 axios 实例
|
// 导出 axios 实例
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user