refactor(webapp): 重构发票验证功能

- 修改基础 URL为本地地址
- 优化发票验证和列表查询逻辑
- 更新数据库结构和查询语句
- 改进前端发票管理页面,增加验证结果展示
- 修复后端发票列表接口,支持 JSON 请求
This commit is contained in:
liuxiaoqing 2025-08-19 13:52:25 +08:00
parent c22a509633
commit 1e24287327
10 changed files with 59 additions and 71 deletions

View File

@ -38,7 +38,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,cyjgxx, 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
""" """
@ -124,14 +124,15 @@ class DataService:
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): def update_invoice_status(self, invoice_id: int, verify_status: str,inspectionAmount :str ):
conn = DBService().get_conn() conn = DBService().get_conn()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute( cursor.execute(
"UPDATE invoice SET verify_time = ?," "UPDATE invoice SET verify_time = ?,"
"verify_status = ?" "verify_status = ?"
"inspectionAmount = ?"
"WHERE id = ?", "WHERE id = ?",
(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), verify_status, 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): def update_invoice_desc(self, invoice_id: int|str, desc: str, desc_file: str,status: str):
conn = DBService().get_conn() conn = DBService().get_conn()
@ -145,20 +146,20 @@ class DataService:
(desc, desc_file,status, invoice_id)) (desc, desc_file,status, invoice_id))
conn.commit() conn.commit()
# 查询验证记录 # 查询验证记录
def get_verify_log(self, file_path: str) -> dict[Any, Any]: def get_verify_log(self, file_path: str) -> dict[Any, Any]|None:
conn = DBService().get_conn() conn = 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 verify_time desc limit 1 select inspectionAmount,cyjgxx,verify_time,file_path from verify_log where file_path = ? order by verify_time desc limit 1
""" """
, (file_path,)) , (file_path,))
rows = cursor.fetchall() rows = cursor.fetchall()
data = {}
if len(rows) > 0: if len(rows) > 0:
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
# 插入验证记录 # 插入验证记录
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 = DBService().get_conn()
@ -196,18 +197,18 @@ 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,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':
sql += " date('now', '-"+time_out+" day') >= date(verify_time) and verify_status == 'success' " sql += " date('now', '-"+time_out+" day') >= date(verify_time) and verify_status == 'success' "
else: else:
sql += " verify_status = " + verify_status sql += " verify_status = '" + verify_status+"'"
if start_date is not None: if start_date is not None:
sql += " and verify_time >= '" + start_date.strftime("%Y-%m-%d") + "'" sql += " and verify_time >= '" + start_date.strftime("%Y-%m-%d") + "'"
if end_date is not None: if end_date is not None:
sql += " and verify_time <= '" + end_date.strftime("%Y-%m-%d") + "'" sql += " and verify_time <= '" + end_date.strftime("%Y-%m-%d") + "'"
if value != '': if value is not None and value != '':
sql += " and ( " sql += " and ( "
sql += "file_path like '%" + value + "%' or " sql += "file_path like '%" + value + "%' or "
sql += "checkCode like '%" + value + "%' or " sql += "checkCode like '%" + value + "%' or "
@ -242,43 +243,13 @@ class DataService:
sql += "desc_files like '%" + value + "%' " sql += "desc_files like '%" + value + "%' "
sql += ")" sql += ")"
sql += " order by verify_time desc" sql += " order by verify_time desc"
print(sql)
cursor.execute(sql) cursor.execute(sql)
rows = cursor.fetchall() rows = cursor.fetchall()
data = [] datas = []
for row in rows: for row in rows:
data.append({ data = {}
'checkCode': row[0], for i in range(len(row)):
'drawer': row[1], data[cursor.description[i][0]] = row[i]
'formType': row[2], datas.append(data)
'invoiceAmountPreTax': row[3], return datas
'invoiceCode': row[4],
'invoiceDate': row[5],
'invoiceNumber': row[6],
'invoiceTax': row[7],
'invoiceType': row[8],
'machineCode': row[9],
'passwordArea': row[10],
'printedInvoiceCode': row[11],
'printedInvoiceNumber': row[12],
'purchaserBankAccountInfo': row[13],
'purchaserContactInfo': row[14],
'purchaserName': row[15],
'purchaserTaxNumber': row[16],
'recipient': row[17],
'remarks': row[18],
'reviewer': row[19],
'sellerBankAccountInfo': row[20],
'sellerContactInfo': row[21],
'sellerName': row[22],
'sellerTaxNumber': row[23],
'specialTag': row[24],
'title': row[25],
'totalAmount': row[26],
'totalAmountInWords': row[27],
'file_path': row[28],
'verify_time': row[29],
'verify_status': row[30],
'desc': row[31],
'desc_files': row[32]
})
return data

View File

@ -117,6 +117,7 @@ class DBService:
file_path TEXT, -- 文件哈希 file_path TEXT, -- 文件哈希
verify_time TEXT, -- 验证时间 verify_time TEXT, -- 验证时间
verify_status TEXT, -- 验证结果 verify_status TEXT, -- 验证结果
inspectionAmount TEXT, -- 验证次数
desc TEXT, -- 备注 desc TEXT, -- 备注
desc_files TEXT, -- 备注附件 desc_files TEXT, -- 备注附件
status TEXT, -- 是否报销yes,no status TEXT, -- 是否报销yes,no

View File

@ -65,8 +65,8 @@ def reverify():
# 发票列表 # 发票列表
@app.route('/listInvoice',methods=['POST']) @app.route('/listInvoice',methods=['POST'])
def list_invoice(): def list_invoice():
value = request.form.get('value') value = request.json.get('value')
verify_status = request.form.get('verifyStatus') verify_status = request.json.get('verify_status')
return dataservice.get_invoice_list(value=value,verify_status=verify_status) return dataservice.get_invoice_list(value=value,verify_status=verify_status)
@app.route('/listInvoiceTimeOut',methods=['POST']) @app.route('/listInvoiceTimeOut',methods=['POST'])
def list_invoice_time_out(): def list_invoice_time_out():

View File

@ -71,8 +71,8 @@ class Service:
# 复验 # 复验
if not reverify: if not reverify:
data1 = dataservice.get_verify_log(file_path=file_path) data1 = dataservice.get_verify_log(file_path=file_path)
print(data) print(data1)
if data1 is not None and data1.get('inspectionAmount') > 0: if data1 is not None and int(data1.get('inspectionAmount')) > 0:
return data1 return data1
client = Service.create_client() client = Service.create_client()
type = Service.typeDict.get(data.get('invoiceType')) type = Service.typeDict.get(data.get('invoiceType'))
@ -96,13 +96,17 @@ class Service:
try: try:
resp = client.verify_vatinvoice_with_options(verify_vatinvoice_request, runtime) resp = client.verify_vatinvoice_with_options(verify_vatinvoice_request, runtime)
ConsoleClient.log(UtilClient.to_jsonstring(resp)) ConsoleClient.log(UtilClient.to_jsonstring(resp))
resdata = json.loads(UtilClient.to_jsonstring(resp.body.data)).get('data') respjson = json.loads(UtilClient.to_jsonstring(resp.body.data))
code = respjson.get('code')
if code != '001':
return {'cyjgxx': respjson.get('msg'), 'inspectionAmount': -1,'status': 'fail'}
resdata = respjson.get('data')
if resdata is None: if resdata is None:
resdata = {'cyjgxx': "未查询到发票信息", 'inspectionAmount': -1,'status': 'fail'} resdata = {'cyjgxx': "未查询到发票信息", 'inspectionAmount': -1,'status': 'fail'}
else: else:
resdata.update({'status': 'success'}) resdata.update({'status': 'success'})
dataservice.insert_verify_log(resdata.get('inspectionAmount'), resdata.get('cyjgxx'), file_path) dataservice.insert_verify_log(resdata.get('inspectionAmount'), resdata.get('cyjgxx'), file_path)
dataservice.update_invoice_status(data.get('id'), resdata.get('status')) dataservice.update_invoice_status(data.get('id'), resdata.get('status'), resdata.get('inspectionAmount'))
return resdata return resdata
except Exception as error: except Exception as error:
# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。 # 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。

Binary file not shown.

View File

@ -107,7 +107,7 @@ const emit= defineEmits(['update:formState'])
const fileType = ref<string>('img') const fileType = ref<string>('img')
onMounted(() => { onMounted(() => {
alert(props.filePath) // alert(props.filePath)
if(props.filePath){ if(props.filePath){
fileType.value = props.filePath.split('.').pop() ==='pdf'?'pdf':'img' fileType.value = props.filePath.split('.').pop() ==='pdf'?'pdf':'img'
request.get('/recognize?filePath='+encodeURIComponent(props.filePath)).then((res) => { request.get('/recognize?filePath='+encodeURIComponent(props.filePath)).then((res) => {

View File

@ -35,7 +35,8 @@ const handleUpload = (options: any) => {
if (xhr.status === 200 || xhr.status === 201) { if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText); console.log(xhr.responseText);
onSuccess(xhr.responseText, file); onSuccess(xhr.responseText, file);
emit('update:filePath', xhr.responseText) let res = JSON.parse(xhr.responseText)
emit('update:filePath', res.file_path)
} else { } else {
onError(new Error(`Upload failed with status ${xhr.status}`)); onError(new Error(`Upload failed with status ${xhr.status}`));
} }

View File

@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import {h,ref} from "vue"; import {h, onMounted, ref} from "vue";
import { import {
SearchOutlined SearchOutlined
} from '@ant-design/icons-vue' } from '@ant-design/icons-vue'
import request from "#/utils/request.ts"; import request from '#/utils/request.ts';
const columns = [ const columns = [
// { // {
// title: '', // title: '',
@ -49,8 +49,8 @@ const columns = [
{ {
title: '查验结果', title: '查验结果',
dataIndex: 'cyjgxx', dataIndex: 'verify_status',
key: 'cyjgxx', key: 'verify_status',
}, },
{ {
title: '查验次数', title: '查验次数',
@ -69,20 +69,25 @@ let data = ref( [])
let searchParams = ref({ let searchParams = ref({
page: 1, page: 1,
pageSize: 10, pageSize: 100,
data: { current: 1,
status: '1' params: {
verify_status: 'success',
value: null,
} }
}); });
const getList = () => { const getList = () => {
request.post("/listInvoice", { request.post("/listInvoice", {
verify_status : 'yes' verify_status : 'success'
}).then(( res ) => { }).then(( res ) => {
console.log(res) console.log(res)
data.value = res.data
}) })
} }
onMounted(() => {
getList() getList()
})
</script> </script>
<template> <template>
@ -94,12 +99,12 @@ getList()
<a-range-picker></a-range-picker> <a-range-picker></a-range-picker>
</a-form-item> </a-form-item>
<a-form-item label="销售方"> <a-form-item label="销售方">
<a-input></a-input> <a-input v-model="searchParams.params.value"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="验证结果"> <a-form-item label="验证结果">
<a-radio-group v-model:value="searchParams.data.status"> <a-radio-group v-model:value="searchParams.params.verify_status">
<a-radio-button value="1">正常</a-radio-button> <a-radio-button value="success">正常</a-radio-button>
<a-radio-button value="2">异常</a-radio-button> <a-radio-button value="faild">异常</a-radio-button>
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
@ -110,6 +115,12 @@ getList()
</a-row> </a-row>
</div> </div>
<a-table :columns="columns" :data-source="data"> <a-table :columns="columns" :data-source="data">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'verify_status'">
<a-tag v-if="record.verify_status === 'success'" color="green">正常</a-tag>
<a-tag v-if="record.verify_status === 'fail'" color="red">异常</a-tag>
</template>
</template>
</a-table> </a-table>
</template> </template>

View File

@ -1,2 +1,2 @@
export const baseURL = "http://192.168.1.100:5555" export const baseURL = "http://127.0.0.1:5555"
// export const baseURL = "http://101.200.148.149:8555" // export const baseURL = "http://101.200.148.149:8555"