feat(database): 将数据库从 SQLite 迁移到 MySQL

- 修改了 DBService 类,增加了 MySQL 数据库连接配置
- 重新定义了表结构,适应 MySQL 数据库- 更新了相关的 SQL 查询语句
- 增加了创建数据库的逻辑
- 优化了表创建语句,使用 InnoDB 引擎和 UTF-8 字符集
This commit is contained in:
liuxiaoqing 2025-08-20 15:11:35 +08:00
parent 31c2394e8a
commit 11530baefb
12 changed files with 205 additions and 150 deletions

View File

@ -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

View File

@ -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_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): 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()
@ -84,48 +117,49 @@ class DBService:
# c.execute(delete_table_sql) # c.execute(delete_table_sql)
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)

View File

@ -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):

View File

@ -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}

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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
} }

View File

@ -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>

View File

@ -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)
} }
} }

View File

@ -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 实例