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:
conn = None
dbservice = DBService()
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):
conn = DBService().get_conn()
conn = self.dbservice.get_conn()
cursor = conn.cursor()
try:
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))
conn.commit()
except Exception as e:
print(e)
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()
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
# 根据文件路径获取hash
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()
sql = """
select id, checkCode, drawer, formType, invoiceAmountPreTax, invoiceCode,
@ -39,29 +45,30 @@ class DataService:
purchaserTaxNumber, recipient, remarks, reviewer,
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
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
"""
if invice_id:
sql += " where id = ?"
cursor.execute(sql, (invice_id,))
sql += " where id = '"+str(invice_id)+"'"
cursor.execute(sql)
else:
sql += " where file_path = ?"
cursor.execute(sql, (file_path,))
sql += " where file_path = '"+file_path+"'"
cursor.execute(sql)
rows = cursor.fetchall()
data = {}
if len(rows) > 0:
for i in range(len(rows[0])):
data[cursor.description[i][0]] = rows[0][i]
return data
# 根据文件hash获取文件
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.execute("""
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,))
rows = cursor.fetchall()
@ -70,11 +77,12 @@ class DataService:
data = {}
for i in range(len(rows[0])):
data[cursor.description[i][0]] = rows[0][i]
return data
return None
# 插入发票记录
def insert_invoice_log(self, data: dict, file_path: str):
conn = DBService().get_conn()
conn = self.dbservice.get_conn()
cursor = conn.cursor()
# 插入主表数据
invoice_insert = """
@ -86,7 +94,7 @@ class DataService:
purchaserTaxNumber, recipient, remarks, reviewer,
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
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 = (
data.get('checkCode', ''),
@ -122,37 +130,39 @@ class DataService:
cursor.execute(invoice_insert, invoice_values)
conn.commit()
invoice_id = cursor.lastrowid
return invoice_id
# 更新发票状态
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.execute(
"UPDATE invoice SET verify_time = ?, "
"verify_status = ?, "
"inspectionAmount = ?, "
"UPDATE invoice SET verify_time = %s, "
"verify_status = %s, "
"inspectionAmount = %s, "
"status = 'no'"
"WHERE id = ?",
"WHERE id = %s",
(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), verify_status,inspectionAmount, invoice_id))
conn.commit()
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.execute(
"UPDATE invoice SET "
"desc = ?,"
"desc_files = ?,"
"status = ? "
"WHERE id = ?",
"`desc` = %s,"
"desc_files = %s,"
"status = %s "
"WHERE id = %s",
(desc, desc_file,status, invoice_id))
conn.commit()
return "success"
# 查询验证记录
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.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,))
rows = cursor.fetchall()
@ -160,22 +170,24 @@ class DataService:
data = {}
for i in range(len(rows[0])):
data[cursor.description[i][0]] = rows[0][i]
return data
return None
# 插入验证记录
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.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))
conn.commit()
# 查询验证记录
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.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,))
rows = cursor.fetchall()
@ -187,10 +199,11 @@ class DataService:
'verify_time': row[2],
'file_path': row[3]
})
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]]:
conn = DBService().get_conn()
conn = self.dbservice.get_conn()
cursor = conn.cursor()
sql = """
select id, checkCode, drawer, formType, invoiceAmountPreTax, invoiceCode,
@ -199,7 +212,7 @@ class DataService:
purchaserBankAccountInfo, purchaserContactInfo, purchaserName,
purchaserTaxNumber, recipient, remarks, reviewer,
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
"""
if time_out != 'all':
@ -243,7 +256,7 @@ class DataService:
sql += "title like '%" + value + "%' or "
sql += "totalAmount like '%" + value + "%' or "
sql += "totalAmountInWords like '%" + value + "%' or "
sql += "desc like '%" + value + "%' or "
sql += "`desc` like '%" + value + "%' or "
sql += "desc_files like '%" + value + "%' "
sql += ")"
sql += " order by verify_time desc"
@ -256,4 +269,5 @@ class DataService:
for i in range(len(row)):
data[cursor.description[i][0]] = row[i]
datas.append(data)
return datas

View File

@ -1,20 +1,30 @@
import sqlite3
from sqlite3 import Error
import mysql.connector
from mysql.connector import Error
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
def __init__(self):
"""
初始化函数
"""
self.conn = self.get_conn()
print("DBService init")
self.create_database()
self.create_file_data_table()
self.create_invoice_table()
self.create_verify_log_table()
pass
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
try:
self.conn = sqlite3.connect(self.db_file)
self.conn = mysql.connector.connect(**self.db_config)
except Error as e:
print(e)
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.execute(delete_table_sql)
create_table_sql = """CREATE TABLE IF NOT EXISTS verify_log (
id integer PRIMARY KEY,
cyjgxx text NOT NULL,
inspectionAmount text NOT NULL,
verify_time text NOT NULL,
file_path text NOT NULL,
desc text
);"""
id INT AUTO_INCREMENT PRIMARY KEY,
cyjgxx TEXT NOT NULL,
inspectionAmount VARCHAR(255) NOT NULL,
verify_time VARCHAR(255) NOT NULL,
file_path TEXT NOT NULL,
`desc` TEXT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"""
c = self.get_conn().cursor()
c.execute(create_table_sql)
self.get_conn().commit()
except Error as e:
print(e)
# 文件数据表
def create_file_data_table(self):
"""
@ -62,15 +95,15 @@ class DBService:
# c = self.get_conn().cursor()
# c.execute(delete_table_sql)
create_table_sql = """CREATE TABLE IF NOT EXISTS file_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
file_name text NOT NULL,
file_path text NOT NULL,
file_size integer NOT NULL,
file_type text NOT NULL,
file_time text NOT NULL,
file_hash text NOT NULL,
UNIQUE (file_hash) -- 联合唯一约束
);"""
id INT AUTO_INCREMENT PRIMARY KEY,
file_name TEXT NOT NULL,
file_path TEXT NOT NULL,
file_size INT NOT NULL,
file_type VARCHAR(50) NOT NULL,
file_time VARCHAR(50) NOT NULL,
file_hash VARCHAR(255) NOT NULL,
UNIQUE KEY unique_file_hash (file_hash)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"""
c = self.get_conn().cursor()
c.execute(create_table_sql)
self.get_conn().commit()
@ -84,48 +117,49 @@ class DBService:
# c.execute(delete_table_sql)
create_table_sql = """
-- 主表存储发票基本信息
CREATE TABLE IF NOT EXISTS invoice (
id INTEGER PRIMARY KEY AUTOINCREMENT,
checkCode TEXT NOT NULL UNIQUE, -- 校验码(唯一)
drawer TEXT, -- 开票人
formType TEXT, -- 表单类型
invoiceAmountPreTax REAL, -- 税前金额
invoiceCode TEXT NOT NULL, -- 发票代码
invoiceDate TEXT, -- 开票日期
invoiceNumber TEXT NOT NULL, -- 发票号码
invoiceTax REAL, -- 发票税额
invoiceType TEXT, -- 发票类型
machineCode TEXT, -- 机器编号
passwordArea TEXT, -- 密码区
printedInvoiceCode TEXT, -- 打印发票代码
printedInvoiceNumber TEXT, -- 打印发票号码
purchaserBankAccountInfo TEXT, -- 购买方银行信息
purchaserContactInfo TEXT, -- 购买方联系信息
purchaserName TEXT, -- 购买方名称
purchaserTaxNumber TEXT, -- 购买方税号
recipient TEXT, -- 收款人
remarks TEXT, -- 备注
reviewer TEXT, -- 复核人
sellerBankAccountInfo TEXT, -- 销售方银行信息
sellerContactInfo TEXT, -- 销售方联系信息
sellerName TEXT, -- 销售方名称
sellerTaxNumber TEXT, -- 销售方税号
specialTag TEXT, -- 特殊标记
title TEXT, -- 发票标题
totalAmount REAL, -- 合计金额
totalAmountInWords TEXT, -- 大写金额
file_path TEXT, -- 文件哈希
verify_time TEXT, -- 验证时间
verify_status TEXT, -- 验证结果
inspectionAmount TEXT, -- 验证次数
desc TEXT, -- 备注
desc_files TEXT, -- 备注附件
status TEXT, -- 是否报销yes,no
UNIQUE (invoiceCode, invoiceNumber) -- 联合唯一约束
);
CREATE TABLE IF NOT EXISTS invoice (
id INT AUTO_INCREMENT PRIMARY KEY,
checkCode VARCHAR(255), -- 校验码(唯一)
drawer VARCHAR(100), -- 开票人
formType VARCHAR(100), -- 表单类型
invoiceAmountPreTax DECIMAL(15,2), -- 税前金额
invoiceCode VARCHAR(50) NOT NULL, -- 发票代码
invoiceDate VARCHAR(50), -- 开票日期
invoiceNumber VARCHAR(50) NOT NULL, -- 发票号码
invoiceTax DECIMAL(15,2), -- 发票税额
invoiceType VARCHAR(100), -- 发票类型
machineCode VARCHAR(50), -- 机器编号
passwordArea TEXT, -- 密码区
printedInvoiceCode VARCHAR(50), -- 打印发票代码
printedInvoiceNumber VARCHAR(50), -- 打印发票号码
purchaserBankAccountInfo TEXT, -- 购买方银行信息
purchaserContactInfo TEXT, -- 购买方联系信息
purchaserName VARCHAR(255), -- 购买方名称
purchaserTaxNumber VARCHAR(100), -- 购买方税号
recipient VARCHAR(100), -- 收款人
remarks TEXT, -- 备注
reviewer VARCHAR(100), -- 复核人
sellerBankAccountInfo TEXT, -- 销售方银行信息
sellerContactInfo TEXT, -- 销售方联系信息
sellerName VARCHAR(255), -- 销售方名称
sellerTaxNumber VARCHAR(100), -- 销售方税号
specialTag VARCHAR(50), -- 特殊标记
title VARCHAR(255), -- 发票标题
totalAmount DECIMAL(15,2), -- 合计金额
totalAmountInWords VARCHAR(255), -- 大写金额
file_path TEXT, -- 文件哈希
verify_time VARCHAR(50), -- 验证时间
verify_status VARCHAR(50), -- 验证结果
inspectionAmount VARCHAR(50), -- 验证次数
`desc` TEXT, -- 备注
desc_files TEXT, -- 备注附件
status VARCHAR(20), -- 是否报销yes,no
UNIQUE KEY unique_invoice (invoiceCode, invoiceNumber)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
"""
try:
c = self.get_conn().cursor()
c.execute(create_table_sql)
self.get_conn().commit()
except Error as e:
print(e)

View File

@ -137,10 +137,9 @@ class Service:
except Exception as error:
# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
# 错误 message
print(error.message)
print(error)
# 诊断地址
print(error.data.get("Recommend"))
UtilClient.assert_as_string(error.message)
UtilClient.assert_as_string(error)
# 发票验证记录
@staticmethod
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" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
<script type="module" crossorigin src="/assets/index-CxFq9mgc.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-T_5mvQco.css">
<script type="module" crossorigin src="/assets/index-Y26lO6c_.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-wINpQLiP.css">
</head>
<body>
<div id="app"></div>

View File

@ -8,4 +8,5 @@ Flask==3.1.1
flask_cors==6.0.1
python_dateutil==2.9.0.post0
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 = () => {
console.log('保存成功')
current.value = 0
}
//
const formState = ref<string>('');
@ -58,7 +58,7 @@ const formState = ref<string>('');
<a-col :span="12" offset="16">
<a-space>
<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-space>
</a-col>

View File

@ -1,5 +1,7 @@
<template>
<a-layout-content>
<a-spin v-if="loadding">
</a-spin>
<a-result
:status="formState.status"
:title="formState.cyjgxx"
@ -16,7 +18,7 @@ import {ref,onMounted } from 'vue';
import request from "../../utils/request.ts";
const props = defineProps({ filePath: String });
import {baseURL} from "../../utils/baseurl.ts";
let loadding = ref(true)
const fileType = ref<string>('img')
onMounted(() => {
// alert(props.filePath)
@ -25,6 +27,7 @@ onMounted(() => {
request.get('/verify?filePath='+encodeURIComponent(props.filePath)).then((res) => {
console.log(res)
formState.value = res.data
loadding.value = false
})
fileUrl.value = baseURL+"/"+props.filePath
}

View File

@ -63,7 +63,7 @@ const handleUpload = (options: any) => {
:max-count="1"
@remove="handleRemove"
>
<a-button >
<a-button>
<upload-outlined></upload-outlined>
上传发票
</a-button>

View File

@ -129,12 +129,13 @@ const handleOk = () => {
invoiceId: formData.value.id,
status: formData.value.status?'yes':'no',
desc: formData.value.desc,
desc_files: formData.value.fileIds.join(','),
desc_files: formData.value.fileIds?.join(','),
}).then(( res ) => {
if(res.status == 200){
openModal.value = false;
confirmLoading.value = false;
messageApi.success("修改成功")
getList();//
}
})
};
@ -146,8 +147,8 @@ const handleOpen = (record:any) => {
}
formData.value = Object.assign({}, record);
formData.value.status = (record.status === 'yes')
formData.value.fileIds = record.desc_files.split(',');
if (record.desc_files) {
formData.value.fileIds = record.desc_files.split(',');
let paths = record.desc_files.split(",")
fileList.value = []
for(let i = 0; i < paths.length; i++) {
@ -201,6 +202,9 @@ const handlePreview = async (file: any) => {
const handleFileChange = (info: UploadChangeParam) => {
if(info.file.status === 'done'){
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)
}
}

View File

@ -5,7 +5,7 @@ import axios, {type AxiosInstance} from 'axios';
import {baseURL} from "./baseurl.ts";
const service: AxiosInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
timeout: 50000,
});
// 导出 axios 实例