Compare commits

1 Commits
Author SHA1 Message Date
jayus 6514a6a8f7 Initial commit 2025-08-17 13:22:49 +08:00
60 changed files with 173 additions and 9945 deletions
+172 -4
View File
@@ -1,5 +1,173 @@
runtime/
.idea/
.vscode/
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/
.pytest_cache/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# ---> Vue
# gitignore template for Vue.js projects
#
# Recommended template: Node.gitignore
# TODO: where does this rule come from?
docs/_book
# TODO: where does this rule come from?
test/
+1 -39
View File
@@ -1,40 +1,2 @@
# 发票核验完整工程示例
该项目为VerifyVATInvoice的完整工程示例。
该示例**无法在线调试**,如需调试可下载到本地后替换 [AK](https://usercenter.console.aliyun.com/#/manage/ak) 以及参数后进行调试。
## 运行条件
- 下载并解压需要语言的代码;
- 在阿里云帐户中获取您的 [凭证](https://usercenter.console.aliyun.com/#/manage/ak) 并通过它替换下载后代码中的 ACCESS_KEY_ID 以及 ACCESS_KEY_SECRET;
- 执行对应语言的构建及运行语句
## 执行步骤
下载的代码包,在根据自己需要更改代码中的参数和 AK 以后,可以在**解压代码所在目录下**按如下的步骤执行:
- *Python 版本要求 Python3*
```sh
python3 setup.py install && python ./alibabacloud_sample/sample.py
```
## 使用的 API
- VerifyVATInvoice:发票核验接口支持包括:增值税专用发票、增值税普通发票(折叠票)、增值税普通发票(卷票)、增值税电子普通发票(含收费公路通行费增值税电子普通发票)、机动车销售统一发票、二手车销售统一发票多种类型发票核验。您可以通过输入发票的关键验证字段,返回真实的票面信息,包括发票类型、发票代码、发票号码、作废标志、开票日期、购方税号及其他发票信息等。当天开具发票当日可查验(T+0)。注意:可能有几小时到十几小时的延迟。 更多信息可参考:[文档](https://next.api.aliyun.com/document/ocr-api/2021-07-07/VerifyVATInvoice)
## API 返回示例
*实际输出结构可能稍有不同,属于正常返回;下列输出值仅作为参考,以实际调用为准*
- JSON 格式
```js
{
"RequestId": "43A29C77-405E-4CC0-BC55-EE694AD00655",
"Data": "{\n \"code\": \"001\",\n \"data\": {\n \"afterTaxCode\": \"\",\n \"allTax\": \"9.67\",\n \"allValoremTax\": \"332.00\",\n \"blueInvoiceCode\": \"\",\n \"blueInvoiceNo\": \"\",\n \"brandVersion\": \"\",\n \"businessUnit\": \"\",\n \"businessUnitTaxNo\": \"\",\n \"busmessUnitAddress\": \"\",\n \"busmessUnitBankAndAccount\": \"\",\n \"busmessUnitPhone\": \"\",\n \"carPrice\": \"\",\n \"carType\": \"\",\n \"carTypeAndNumber\": \"\",\n \"carframeCode\": \"\",\n \"carrierName\": \"\",\n \"carrierTaxNo\": \"\",\n \"checkCode\": \"07122942791187744XXXX\",\n \"code\": \"\",\n \"consignorName\": \"\",\n \"consignorTaxNo\": \"\",\n \"cyjgxx\": \"查验成功发票一致\",\n \"detailList\": [\n {\n \"allTax\": \"9.67\",\n \"detailAmount\": \"322.33\",\n \"detailNo\": \"1\",\n \"expenseItem\": \"\",\n \"goodsName\": \"*餐饮服务*餐费\",\n \"netValue\": \"322.330097\",\n \"num\": \"1\",\n \"plate_no\": \"\",\n \"rowNo\": \"1\",\n \"standard\": \"\",\n \"taxClassifyCode\": \"0\",\n \"taxDetailAmount\": \"\",\n \"taxRate\": \"3\",\n \"taxUnitPrice\": \"\",\n \"trafficDateEnd\": \"\",\n \"trafficDateStart\": \"\",\n \"type\": \"\",\n \"unit\": \"\"\n }\n ],\n \"draweeName\": \"\",\n \"draweeTaxNo\": \"\",\n \"engineCode\": \"\",\n \"idCard\": \"\",\n \"importLicense\": \"\",\n \"inspectionAmount\": \"\",\n \"inspectionNumber\": \"\",\n \"invalidMark\": \"N\",\n \"invoiceCode\": \"01100180XXXX\",\n \"invoiceDate\": \"2018XXXX\",\n \"invoiceMoney\": \"322.XX\",\n \"invoiceNumber\": \"3531XXXX\",\n \"invoiceType\": \"10\",\n \"lemonMarket\": \"\",\n \"lemonMarketAddress\": \"\",\n \"lemonMarketBankAndAccount\": \"\",\n \"lemonMarketPhone\": \"\",\n \"lemonMarketTaxNo\": \"\",\n \"licenseCode\": \"\",\n \"licensePlate\": \"\",\n \"limitAmount\": \"\",\n \"machineCode\": \"49992273XXXX\",\n \"note\": \"机器编号:49992273XXXX\",\n \"producingArea\": \"\",\n \"purchaserAddressOrPhone\": \"杭州余杭区XXXX0571-8502XXXX\",\n \"purchaserBankAndNumber\": \"招商银行杭州高新支行571906593XXXXXX\",\n \"purchaserName\": \"XXXX软件有限公司\",\n \"purchaserPhone\": \"\",\n \"purchaserTaxpayerNumber\": \"913301007682XXXXXX\",\n \"purchaserUnitOrIndividual\": \"\",\n \"purchaserUnitOrIndividualAddress\": \"\",\n \"purchaserUnitcodeOrIdNo\": \"\",\n \"receiveName\": \"\",\n \"receiveTaxNo\": \"\",\n \"registrationNo\": \"\",\n \"salerAddress\": \"\",\n \"salerAddressOrPhone\": \"北京市海淀区XXX8211XXXX\",\n \"salerBankAccount\": \"中国银行海淀支行345456XXXXXX\",\n \"salerBankAndNumber\": \"中国银行海淀支行345456XXXXXX\",\n \"salerBankName\": \"\",\n \"salerName\": \"北京市XXX酒家\",\n \"salerPhone\": \"\",\n \"salerTaxpayerNumber\": \"911101081020XXXXXX\",\n \"sellerPhone\": \"\",\n \"sellerUnitCodeOrIdno\": \"\",\n \"sellerUnitOrIndividual\": \"北京市XXX酒家\",\n \"sellerUnitOrIndividualAddress\": \"\",\n \"taxDiskNumber\": \"\",\n \"taxRate\": \"\",\n \"taxUnitCode\": \"\",\n \"taxUnitName\": \"\",\n \"throughAddress\": \"\",\n \"trafficFeeFlag\": \"\",\n \"transferredVehicleOffice\": \"\",\n \"transportGoodsInfo\": \"\",\n \"unit\": \"\",\n \"vehicleTonnage\": \"\",\n \"zeroTaxRateFlag\": \"\"\n },\n \"msg\": \"成功\"\n}"
}
```
# VerifVATInvoice
-79
View File
@@ -1,79 +0,0 @@
Metadata-Version: 2.4
Name: alibabacloud_sample
Version: 1.0.0
Summary: Alibaba Cloud SDK Code Sample Library for Python
Home-page: https://github.com/aliyun/alibabacloud-sdk
Author:
Author-email:
License: Apache License 2.0
Keywords: alibabacloud,sample
Platform: any
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Topic :: Software Development
Requires-Python: >=3.6
Description-Content-Type: text/markdown
Requires-Dist: alibabacloud_ocr-api20210707<4.0.0,>=3.1.3
Requires-Dist: alibabacloud_tea_openapi<1.0.0,>=0.3.15
Requires-Dist: alibabacloud_tea_console<1.0.0,>=0.0.1
Requires-Dist: alibabacloud_tea_util<1.0.0,>=0.3.13
Requires-Dist: alibabacloud_credentials<2.0.0,>=1.0.2
Requires-Dist: flask
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: platform
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary
# 发票核验完整工程示例
该项目为VerifyVATInvoice的完整工程示例。
该示例**无法在线调试**,如需调试可下载到本地后替换 [AK](https://usercenter.console.aliyun.com/#/manage/ak) 以及参数后进行调试。
## 运行条件
- 下载并解压需要语言的代码;
- 在阿里云帐户中获取您的 [凭证](https://usercenter.console.aliyun.com/#/manage/ak) 并通过它替换下载后代码中的 ACCESS_KEY_ID 以及 ACCESS_KEY_SECRET;
- 执行对应语言的构建及运行语句
## 执行步骤
下载的代码包,在根据自己需要更改代码中的参数和 AK 以后,可以在**解压代码所在目录下**按如下的步骤执行:
- *Python 版本要求 Python3*
```sh
python3 setup.py install && python ./alibabacloud_sample/sample.py
```
## 使用的 API
- VerifyVATInvoice:发票核验接口支持包括:增值税专用发票、增值税普通发票(折叠票)、增值税普通发票(卷票)、增值税电子普通发票(含收费公路通行费增值税电子普通发票)、机动车销售统一发票、二手车销售统一发票多种类型发票核验。您可以通过输入发票的关键验证字段,返回真实的票面信息,包括发票类型、发票代码、发票号码、作废标志、开票日期、购方税号及其他发票信息等。当天开具发票当日可查验(T+0)。注意:可能有几小时到十几小时的延迟。 更多信息可参考:[文档](https://next.api.aliyun.com/document/ocr-api/2021-07-07/VerifyVATInvoice)
## API 返回示例
*实际输出结构可能稍有不同,属于正常返回;下列输出值仅作为参考,以实际调用为准*
- JSON 格式
```js
{
"RequestId": "43A29C77-405E-4CC0-BC55-EE694AD00655",
"Data": "{\n \"code\": \"001\",\n \"data\": {\n \"afterTaxCode\": \"\",\n \"allTax\": \"9.67\",\n \"allValoremTax\": \"332.00\",\n \"blueInvoiceCode\": \"\",\n \"blueInvoiceNo\": \"\",\n \"brandVersion\": \"\",\n \"businessUnit\": \"\",\n \"businessUnitTaxNo\": \"\",\n \"busmessUnitAddress\": \"\",\n \"busmessUnitBankAndAccount\": \"\",\n \"busmessUnitPhone\": \"\",\n \"carPrice\": \"\",\n \"carType\": \"\",\n \"carTypeAndNumber\": \"\",\n \"carframeCode\": \"\",\n \"carrierName\": \"\",\n \"carrierTaxNo\": \"\",\n \"checkCode\": \"07122942791187744XXXX\",\n \"code\": \"\",\n \"consignorName\": \"\",\n \"consignorTaxNo\": \"\",\n \"cyjgxx\": \"查验成功发票一致\",\n \"detailList\": [\n {\n \"allTax\": \"9.67\",\n \"detailAmount\": \"322.33\",\n \"detailNo\": \"1\",\n \"expenseItem\": \"\",\n \"goodsName\": \"*餐饮服务*餐费\",\n \"netValue\": \"322.330097\",\n \"num\": \"1\",\n \"plate_no\": \"\",\n \"rowNo\": \"1\",\n \"standard\": \"\",\n \"taxClassifyCode\": \"0\",\n \"taxDetailAmount\": \"\",\n \"taxRate\": \"3\",\n \"taxUnitPrice\": \"\",\n \"trafficDateEnd\": \"\",\n \"trafficDateStart\": \"\",\n \"type\": \"\",\n \"unit\": \"\"\n }\n ],\n \"draweeName\": \"\",\n \"draweeTaxNo\": \"\",\n \"engineCode\": \"\",\n \"idCard\": \"\",\n \"importLicense\": \"\",\n \"inspectionAmount\": \"\",\n \"inspectionNumber\": \"\",\n \"invalidMark\": \"N\",\n \"invoiceCode\": \"01100180XXXX\",\n \"invoiceDate\": \"2018XXXX\",\n \"invoiceMoney\": \"322.XX\",\n \"invoiceNumber\": \"3531XXXX\",\n \"invoiceType\": \"10\",\n \"lemonMarket\": \"\",\n \"lemonMarketAddress\": \"\",\n \"lemonMarketBankAndAccount\": \"\",\n \"lemonMarketPhone\": \"\",\n \"lemonMarketTaxNo\": \"\",\n \"licenseCode\": \"\",\n \"licensePlate\": \"\",\n \"limitAmount\": \"\",\n \"machineCode\": \"49992273XXXX\",\n \"note\": \"机器编号:49992273XXXX\",\n \"producingArea\": \"\",\n \"purchaserAddressOrPhone\": \"杭州余杭区XXXX0571-8502XXXX\",\n \"purchaserBankAndNumber\": \"招商银行杭州高新支行571906593XXXXXX\",\n \"purchaserName\": \"XXXX软件有限公司\",\n \"purchaserPhone\": \"\",\n \"purchaserTaxpayerNumber\": \"913301007682XXXXXX\",\n \"purchaserUnitOrIndividual\": \"\",\n \"purchaserUnitOrIndividualAddress\": \"\",\n \"purchaserUnitcodeOrIdNo\": \"\",\n \"receiveName\": \"\",\n \"receiveTaxNo\": \"\",\n \"registrationNo\": \"\",\n \"salerAddress\": \"\",\n \"salerAddressOrPhone\": \"北京市海淀区XXX8211XXXX\",\n \"salerBankAccount\": \"中国银行海淀支行345456XXXXXX\",\n \"salerBankAndNumber\": \"中国银行海淀支行345456XXXXXX\",\n \"salerBankName\": \"\",\n \"salerName\": \"北京市XXX酒家\",\n \"salerPhone\": \"\",\n \"salerTaxpayerNumber\": \"911101081020XXXXXX\",\n \"sellerPhone\": \"\",\n \"sellerUnitCodeOrIdno\": \"\",\n \"sellerUnitOrIndividual\": \"北京市XXX酒家\",\n \"sellerUnitOrIndividualAddress\": \"\",\n \"taxDiskNumber\": \"\",\n \"taxRate\": \"\",\n \"taxUnitCode\": \"\",\n \"taxUnitName\": \"\",\n \"throughAddress\": \"\",\n \"trafficFeeFlag\": \"\",\n \"transferredVehicleOffice\": \"\",\n \"transportGoodsInfo\": \"\",\n \"unit\": \"\",\n \"vehicleTonnage\": \"\",\n \"zeroTaxRateFlag\": \"\"\n },\n \"msg\": \"成功\"\n}"
}
```
-13
View File
@@ -1,13 +0,0 @@
README.md
setup.py
alibabacloud_sample/__init__.py
alibabacloud_sample/dataservice.py
alibabacloud_sample/dbservice.py
alibabacloud_sample/fileservice.py
alibabacloud_sample/main.py
alibabacloud_sample/service.py
alibabacloud_sample.egg-info/PKG-INFO
alibabacloud_sample.egg-info/SOURCES.txt
alibabacloud_sample.egg-info/dependency_links.txt
alibabacloud_sample.egg-info/requires.txt
alibabacloud_sample.egg-info/top_level.txt
@@ -1 +0,0 @@
@@ -1,6 +0,0 @@
alibabacloud_ocr-api20210707<4.0.0,>=3.1.3
alibabacloud_tea_openapi<1.0.0,>=0.3.15
alibabacloud_tea_console<1.0.0,>=0.0.1
alibabacloud_tea_util<1.0.0,>=0.3.13
alibabacloud_credentials<2.0.0,>=1.0.2
flask
@@ -1 +0,0 @@
alibabacloud_sample
-1
View File
@@ -1 +0,0 @@
__version__ = "1.0.0"
-273
View File
@@ -1,273 +0,0 @@
# 数据管理服务类
from datetime import datetime
from typing import Any
from dateutil import parser
from alibabacloud_sample.dbservice import DBService
class DataService:
conn = None
dbservice = DBService()
def __init__(self):
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 = 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(%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_name,file_path,file_size,file_type,file_time,file_hash from file_data where `file_hash` = %s", (file_hash,))
rows = cursor.fetchall()
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 = self.dbservice.get_conn()
cursor = conn.cursor()
sql = """
select id, checkCode, drawer, formType, invoiceAmountPreTax, invoiceCode,
invoiceDate, invoiceNumber, invoiceTax, invoiceType, machineCode,
passwordArea, printedInvoiceCode, printedInvoiceNumber,
purchaserBankAccountInfo, purchaserContactInfo, purchaserName,
purchaserTaxNumber, recipient, remarks, reviewer,
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
specialTag, title, totalAmount, totalAmountInWords,file_path,verify_time,
verify_time,verify_status,`desc`,desc_files,status
from invoice
"""
if invice_id:
sql += " where id = '"+str(invice_id)+"'"
cursor.execute(sql)
else:
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 = 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` = %s and file_size = %s
"""
, (file_hash,file_size,))
rows = cursor.fetchall()
if len(rows) > 0:
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 = self.dbservice.get_conn()
cursor = conn.cursor()
# 插入主表数据
invoice_insert = """
INSERT INTO invoice (
checkCode, drawer, formType, invoiceAmountPreTax, invoiceCode,
invoiceDate, invoiceNumber, invoiceTax, invoiceType, machineCode,
passwordArea, printedInvoiceCode, printedInvoiceNumber,
purchaserBankAccountInfo, purchaserContactInfo, purchaserName,
purchaserTaxNumber, recipient, remarks, reviewer,
sellerBankAccountInfo, sellerContactInfo, sellerName, sellerTaxNumber,
specialTag, title, totalAmount, totalAmountInWords,file_path
) 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', ''),
data.get('drawer', ''),
data.get('formType', ''),
float(data.get('invoiceAmountPreTax', 0.0)),
data.get('invoiceCode', ''),
data.get('invoiceDate', ''),
data.get('invoiceNumber', ''),
float(data.get('invoiceTax', 0.0)),
data.get('invoiceType', ''),
data.get('machineCode', ''),
data.get('passwordArea', ''),
data.get('printedInvoiceCode', ''),
data.get('printedInvoiceNumber', ''),
data.get('purchaserBankAccountInfo', ''),
data.get('purchaserContactInfo', ''),
data.get('purchaserName', ''),
data.get('purchaserTaxNumber', ''),
data.get('recipient', ''),
data.get('remarks', ''),
data.get('reviewer', ''),
data.get('sellerBankAccountInfo', ''),
data.get('sellerContactInfo', ''),
data.get('sellerName', ''),
data.get('sellerTaxNumber', ''),
data.get('specialTag', ''),
data.get('title', ''),
float(data.get('totalAmount', 0.0)),
data.get('totalAmountInWords', ''),
file_path
)
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 = self.dbservice.get_conn()
cursor = conn.cursor()
cursor.execute(
"UPDATE invoice SET verify_time = %s, "
"verify_status = %s, "
"inspectionAmount = %s, "
"status = 'no'"
"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 = self.dbservice.get_conn()
cursor = conn.cursor()
cursor.execute(
"UPDATE invoice SET "
"`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 = self.dbservice.get_conn()
cursor = conn.cursor()
cursor.execute("""
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()
if len(rows) > 0:
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 = self.dbservice.get_conn()
cursor = conn.cursor()
cursor.execute(
"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 = self.dbservice.get_conn()
cursor = conn.cursor()
cursor.execute("""
select inspectionAmount,cyjgxx,verify_time,file_path from verify_log where file_path = %s
"""
, (file_path,))
rows = cursor.fetchall()
data = []
for row in rows:
data.append({
'inspectionAmount': row[0],
'cyjgxx': row[1],
'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 = self.dbservice.get_conn()
cursor = conn.cursor()
sql = """
select id, checkCode, drawer, formType, invoiceAmountPreTax, invoiceCode,
invoiceDate, invoiceNumber, invoiceTax, invoiceType, machineCode,
passwordArea, printedInvoiceCode, printedInvoiceNumber,
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
from invoice where
"""
if time_out != 'all':
sql += " date('now', '-"+time_out+" day') >= date(verify_time) and verify_status == 'success' "
elif verify_status != 'all':
sql += " verify_status = '" + verify_status+"'"
else:
sql += " 1 = 1 "
if start_date is not None:
sql += " and verify_time >= '" + start_date + "'"
if end_date is not None:
sql += " and verify_time <= '" + end_date + "'"
if value is not None and value != '':
sql += " and ( "
sql += "file_path like '%" + value + "%' or "
sql += "checkCode like '%" + value + "%' or "
sql += "drawer like '%" + value + "%' or "
sql += "formType like '%" + value + "%' or "
sql += "invoiceAmountPreTax like '%" + value + "%' or "
sql += "invoiceCode like '%" + value + "%' or "
sql += "invoiceDate like '%" + value + "%' or "
sql += "invoiceNumber like '%" + value + "%' or "
sql += "invoiceTax like '%" + value + "%' or "
sql += "invoiceType like '%" + value + "%' or "
sql += "machineCode like '%" + value + "%' or "
sql += "passwordArea like '%" + value + "%' or "
sql += "printedInvoiceCode like '%" + value + "%' or "
sql += "printedInvoiceNumber like '%" + value + "%' or "
sql += "purchaserBankAccountInfo like '%" + value + "%' or "
sql += "purchaserContactInfo like '%" + value + "%' or "
sql += "purchaserName like '%" + value + "%' or "
sql += "purchaserTaxNumber like '%" + value + "%' or "
sql += "recipient like '%" + value + "%' or "
sql += "remarks like '%" + value + "%' or "
sql += "reviewer like '%" + value + "%' or "
sql += "sellerBankAccountInfo like '%" + value + "%' or "
sql += "sellerContactInfo like '%" + value + "%' or "
sql += "sellerName like '%" + value + "%' or "
sql += "sellerTaxNumber like '%" + value + "%' or "
sql += "specialTag like '%" + value + "%' or "
sql += "title like '%" + value + "%' or "
sql += "totalAmount like '%" + value + "%' or "
sql += "totalAmountInWords like '%" + value + "%' or "
sql += "`desc` like '%" + value + "%' or "
sql += "desc_files like '%" + value + "%' "
sql += ")"
sql += " order by verify_time desc"
print(sql)
cursor.execute(sql)
rows = cursor.fetchall()
datas = []
for row in rows:
data = {}
for i in range(len(row)):
data[cursor.description[i][0]] = row[i]
datas.append(data)
return datas
-165
View File
@@ -1,165 +0,0 @@
import mysql.connector
from mysql.connector import Error
class DBService:
# 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):
"""
创建数据库连接
该函数用于创建数据库连接,并返回连接对象
返回值:
连接对象
"""
if self.conn is not None and self.conn.is_connected():
return self.conn
try:
self.conn = mysql.connector.connect(**self.db_config)
except Error as e:
print(e)
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):
"""
创建验证记录表
该函数用于创建表,并返回创建结果
"""
try:
# delete_table_sql = """DROP TABLE IF EXISTS verify_log;"""
# c = self.get_conn().cursor()
# c.execute(delete_table_sql)
create_table_sql = """CREATE TABLE IF NOT EXISTS verify_log (
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):
"""
创建文件数据表
该函数用于创建表,并返回创建结果
"""
try:
# delete_table_sql = """DROP TABLE IF EXISTS file_data;"""
# c = self.get_conn().cursor()
# c.execute(delete_table_sql)
create_table_sql = """CREATE TABLE IF NOT EXISTS file_data (
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()
except Error as e:
print(e)
# 发票数据表
def create_invoice_table(self):
# delete_table_sql = """DROP TABLE IF EXISTS invoice;"""
# c = self.get_conn().cursor()
# c.execute(delete_table_sql)
create_table_sql = """
-- 主表存储发票基本信息
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)
-54
View File
@@ -1,54 +0,0 @@
# 文件服务接口
from typing import Any
from flask import Request
from werkzeug.utils import secure_filename
import os , time, hashlib
from alibabacloud_sample.dataservice import DataService
dataservice = DataService()
class FileService:
# 创建文件服务实例
def __init__(self):
pass
# 上传文件
def upload(self, request: Request, file_path: str) -> None | str | dict[Any, Any] | Any:
if request.method == 'POST':
# 检查是否有文件在请求中
if 'file' not in request.files:
return '没有文件被上传'
file = request.files['file']
if file.filename == '':
return '请重新选择文件'
if file:
date = time.strftime("%Y%m%d", time.localtime())
filetype = secure_filename(file.filename)
filename = str(int(time.time())) + "_" + file.filename
filepath = os.path.join(file_path, date, filename)
os.makedirs(os.path.dirname(filepath), exist_ok=True)
file.save(filepath)
file_size = os.path.getsize(filepath)
file_hash = self.get_hash(filepath)
v_file = dataservice.get_file(file_hash,file_size)
if v_file:
os.remove(filepath)
return v_file
else:
dataservice.insert_file_data(file.filename, filepath, file_size, filetype, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),file_hash)
v_file = dataservice.get_file(file_hash, file_size)
print("insert v_file:", v_file)
return v_file
return None
# 获取文件md5
@staticmethod
def get_hash(file_path: str) -> str:
with open(file_path, 'rb') as f:
md5 = hashlib.md5()
while True:
data = f.read(8192)
if not data:
break
md5.update(data)
return md5.hexdigest()
-97
View File
@@ -1,97 +0,0 @@
from flask import Flask, request, render_template, send_from_directory
from flask_cors import CORS
from alibabacloud_sample.dataservice import DataService
from alibabacloud_sample.fileservice import FileService
from alibabacloud_sample.service import Service
app = Flask(__name__)
CORS(app)
app.config['UPLOAD_FOLDER'] = '/data/uploads' # 指定上传文件夹
app.config['WEBAPP'] = 'templates'
dataservice = DataService()
@app.route('/index')
def index():
return render_template('index.html')
@app.route('/assets/<path:filename>')
def return_js(filename):
return send_from_directory(app.config.get('WEBAPP')+'/assets', str(filename))
@app.route('/data/uploads/<path:filename>')
def return_file(filename):
return send_from_directory(app.config.get('UPLOAD_FOLDER'), str(filename))
# 上传文件
@app.route('/upload', methods=['POST'])
def upload_file():
if request.method == 'POST':
file_service = FileService()
msg = file_service.upload(request,app.config['UPLOAD_FOLDER'])
if msg == "No file part" or msg == "No selected file":
return "请选择文件"
else:
return msg
return None
# 发票识别
@app.route('/recognize', methods=['GET'])
def recognize():
file_path = request.args.get('filePath')
service = Service()
data = dataservice.get_invoice(file_path=file_path)
if data is not None and data.get('file_path') is not None:
return data
return service.recognize(file_path=file_path)
# 发票验证
@app.route('/verify', methods=['GET'])
def verify():
file_path = request.args.get('filePath')
invoice_id = request.args.get('invoiceId')
if file_path is None:
return {"msg":"请选择文件","status":'fail'}
service = Service()
data = dataservice.get_invoice(file_path=file_path,invice_id=invoice_id)
if data is not None:
if data.get('status') == 'yes':
return {"msg":"请勿重复验证","status":'fail'}
return service.verify(data=data,file_path=file_path)
else:
return {"msg":"请先识别发票","status":'fail'}
# 发票复验
@app.route('/reverify', methods=['GET'])
def reverify():
file_path = request.args.get('filePath')
if file_path is None:
return "请选择文件"
service = Service()
data = dataservice.get_invoice(file_path=file_path)
return service.verify(data=data,file_path=file_path,reverify=True)
# 发票列表
@app.route('/listInvoice',methods=['POST'])
def list_invoice():
value = request.json.get('value')
verify_status = request.json.get('verify_status')
verify_time = request.json.get('verify_time')
start_date = None
end_date = None
if verify_time is not None:
start_date = verify_time[0].split(' ')[0]
end_date = verify_time[1].split(' ')[0]
return dataservice.get_invoice_list(value=value,verify_status=verify_status,start_date=start_date,end_date=end_date)
@app.route('/listInvoiceTimeOut',methods=['POST'])
def list_invoice_time_out():
time_out = request.form.get('timeOut')
return dataservice.get_invoice_list(value='',verify_status='',time_out=time_out)
# 发票日志列表
@app.route('/listLogs',methods=['GET'])
def list_logs():
file_path = request.args.get('filePath')
return dataservice.get_verify_log_list(file_path=file_path)
# 更新发票标注
@app.route('/updateInvoice',methods=['POST'])
def update_invoice():
invoice_id = request.json.get('invoiceId')
status = request.json.get('status')
desc = request.json.get('desc')
desc_files = request.json.get('desc_files')
return dataservice.update_invoice_desc(invoice_id=invoice_id,desc=desc,desc_file=desc_files,status=status)
if __name__ == '__main__':
# Service.verify(sys.argv[1:])
# Service.recognize(file_path="/home/jayus/图片/wechat_2025-07-31_131911_822.png")
app.run(host='0.0.0.0', port=5555, debug=True)
-150
View File
@@ -1,150 +0,0 @@
# -*- coding: utf-8 -*-
# This file is auto-generated, don't edit it. Thanks.
import os
import statistics
import sys
from typing import List
from alibabacloud_credentials.models import Config
from alibabacloud_ocr_api20210707.client import Client as ocr_api20210707Client, Client
from alibabacloud_credentials.client import Client as CredentialClient
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_ocr_api20210707 import models as ocr_api_20210707_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_console.client import Client as ConsoleClient
from alibabacloud_tea_util.client import Client as UtilClient
from alibabacloud_darabonba_stream.client import Client as StreamClient
from flask import json
from alibabacloud_sample.dataservice import DataService
class Service:
def __init__(self):
pass
# 发票类型字典
typeDict = {
"增值税专用发票": 1,
"增值税普通发票": 4,
"增值税普通发票(电子)": 10,
"增值税普通发票(卷式)": 11,
"增值税普通发票(通行费)": 14,
"增值税电子专用发票": 20,
"数电发票(增值税专用发票)": 31,
"数电发票(增值税普通发票)": 32,
"数电发票(纸质专用发票)": 85,
"数电发票(纸质普通发票)": 86,
}
@staticmethod
def create_client() -> ocr_api20210707Client:
"""
使用凭据初始化账号Client
@return: Client
@throws Exception
"""
# 工程代码建议使用更安全的无AK方式,凭据配置方式请参见:https://help.aliyun.com/document_detail/378659.html。
# credential = CredentialClient()
# config = open_api_models.Config(
# credential=credential
# )
config = Config(
type='access_key',
access_key_id='LTAI5t7481fKEcZjrvWyZp48',
access_key_secret='FwRfm4gst2Dk10tbXeJl0OV7EzL6qM'
# access_key_id = 'LTAI5tHvCWb5uHZ9Q7iUJTLp',
# access_key_secret = 'zKAL7WqvnJ0lN0GHsvJptAGRiuCOfM'
)
config.endpoint = f'ocr-api.cn-hangzhou.aliyuncs.com'
cred = CredentialClient(config)
cred.get_credential()
nconfig = open_api_models.Config(
credential=cred
)
# Endpoint 请参考 https://api.aliyun.com/product/ocr-api
nconfig.endpoint = f'ocr-api.cn-hangzhou.aliyuncs.com'
return ocr_api20210707Client(nconfig)
# 发票验证
@staticmethod
def verify(data: dict, file_path: str,reverify: bool = False):
dataservice = DataService()
# 复验
if not reverify:
data1 = dataservice.get_verify_log(file_path=file_path)
print(data1)
if data1 is not None and int(data1.get('inspectionAmount')) > 0:
return data1
client = Service.create_client()
type = Service.typeDict.get(data.get('invoiceType'))
sum = data.get('totalAmount')
if type == 1 or type == 20:
sum = data.get('totalAmountWithoutTax')
if data.get('checkCode') is not None:
verify_code = data.get('checkCode')[-6:]
else:
verify_code = None
date = data.get('invoiceDate').replace('', "").replace('', "").replace('', "")
verify_vatinvoice_request = ocr_api_20210707_models.VerifyVATInvoiceRequest(
invoice_no= data.get('invoiceNumber'),
invoice_code= data.get('invoiceCode'),
invoice_date= date,
invoice_sum= sum,
invoice_kind= type,
verify_code= verify_code,
)
runtime = util_models.RuntimeOptions()
try:
resp = client.verify_vatinvoice_with_options(verify_vatinvoice_request, runtime)
ConsoleClient.log(UtilClient.to_jsonstring(resp))
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:
resdata = {'cyjgxx': "未查询到发票信息", 'inspectionAmount': -1,'status': 'fail'}
else:
resdata.update({'status': 'success'})
resdata['status'] = 'success'
dataservice.insert_verify_log(resdata.get('inspectionAmount'), resdata.get('cyjgxx'), file_path)
dataservice.update_invoice_status(data.get('id'), resdata.get('status'), resdata.get('inspectionAmount'))
return resdata
except Exception as error:
# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
# 错误 message
print(error)
# 诊断地址
print(error.data.get("Recommend"))
UtilClient.assert_as_string(error.message)
# 发票识别
@staticmethod
def recognize(file_path: str):
client = Service.create_client()
dataservice = DataService()
body_stream = StreamClient.read_from_file_path(file_path)
recognize_mixed_invoices_request = ocr_api_20210707_models.RecognizeMixedInvoicesRequest(
body=body_stream
)
runtime = util_models.RuntimeOptions()
try:
# 复制代码运行请自行打印 API 的返回值
res = client.recognize_mixed_invoices_with_options(recognize_mixed_invoices_request, runtime)
print(UtilClient.to_jsonstring(res.body.data))
data = json.loads(UtilClient.to_jsonstring(res.body.data)).get('subMsgs')[0].get('result').get('data')
data_id = dataservice.insert_invoice_log(data, file_path)
data.update({'id': data_id})
return data
except Exception as error:
# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
# 错误 message
print(error)
# 诊断地址
UtilClient.assert_as_string(error)
# 发票验证记录
@staticmethod
def get_verify_log_list(file_path):
dataservice = DataService()
return dataservice.get_verify_log_list(file_path)
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
: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-d33302c4]{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-8ed0a2a4]{margin-bottom:16px;text-align:right}.table-operations>button[data-v-8ed0a2a4]{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}
-14
View File
@@ -1,14 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-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-B0bdG1dl.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-C6TrMyLy.css">
</head>
<body>
<div id="app"></div>
</body>
</html>
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.
@@ -1 +0,0 @@
__version__ = "1.0.0"
-81
View File
@@ -1,81 +0,0 @@
# -*- coding: utf-8 -*-
# This file is auto-generated, don't edit it. Thanks.
import os
import sys
from typing import List
from alibabacloud_ocr_api20210707.client import Client as ocr_api20210707Client
from alibabacloud_credentials.client import Client as CredentialClient
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_ocr_api20210707 import models as ocr_api_20210707_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_console.client import Client as ConsoleClient
from alibabacloud_tea_util.client import Client as UtilClient
class Sample:
def __init__(self):
pass
@staticmethod
def create_client() -> ocr_api20210707Client:
"""
使用凭据初始化账号Client
@return: Client
@throws Exception
"""
# 工程代码建议使用更安全的无AK方式,凭据配置方式请参见:https://help.aliyun.com/document_detail/378659.html。
credential = CredentialClient()
config = open_api_models.Config(
credential=credential
)
# Endpoint 请参考 https://api.aliyun.com/product/ocr-api
config.endpoint = f'ocr-api.cn-hangzhou.aliyuncs.com'
return ocr_api20210707Client(config)
@staticmethod
def main(
args: List[str],
) -> None:
client = Sample.create_client()
verify_vatinvoice_request = ocr_api_20210707_models.VerifyVATInvoiceRequest(
invoice_no='25617000000124363744',
invoice_date='20250620'
)
runtime = util_models.RuntimeOptions()
try:
resp = client.verify_vatinvoice_with_options(verify_vatinvoice_request, runtime)
ConsoleClient.log(UtilClient.to_jsonstring(resp))
except Exception as error:
# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
# 错误 message
print(error.message)
# 诊断地址
print(error.data.get("Recommend"))
UtilClient.assert_as_string(error.message)
@staticmethod
async def main_async(
args: List[str],
) -> None:
client = Sample.create_client()
verify_vatinvoice_request = ocr_api_20210707_models.VerifyVATInvoiceRequest(
invoice_no='25617000000124363744',
invoice_date='20250620'
)
runtime = util_models.RuntimeOptions()
try:
resp = await client.verify_vatinvoice_with_options_async(verify_vatinvoice_request, runtime)
ConsoleClient.log(UtilClient.to_jsonstring(resp))
except Exception as error:
# 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
# 错误 message
print(error.message)
# 诊断地址
print(error.data.get("Recommend"))
UtilClient.assert_as_string(error.message)
if __name__ == '__main__':
Sample.main(sys.argv[1:])
-10
View File
@@ -1,10 +0,0 @@
version: '3.8'
services:
python-app:
build: .
container_name: python-app
volumes:
- ./:/app
- ./data:/data
ports:
- "8555:5555" # 如果需要暴露 Flask 端口
-10
View File
@@ -1,10 +0,0 @@
FROM python:latest
WORKDIR /app
RUN git clone http://192.168.1.68:8418/jayus/VerifVATInvoice.git .
COPY . .
RUN pip install --no-cache-dir -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
RUN python setup.py install
WORKDIR /app/alibabacloud_sample
CMD ["python", "main.py"]
-12
View File
@@ -1,12 +0,0 @@
alibabacloud_credentials==1.0.2
alibabacloud_darabonba_stream==0.0.2
alibabacloud_ocr_api20210707==3.1.3
alibabacloud_tea_console==0.0.1
alibabacloud_tea_openapi==0.4.1
alibabacloud_tea_util==0.3.13
Flask==3.1.1
flask_cors==6.0.1
python_dateutil==2.9.0.post0
Werkzeug==3.1.3
setuptools==80.9.0
mysql-connector-python==9.4.0
-80
View File
@@ -1,80 +0,0 @@
# -*- coding: utf-8 -*-
"""
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
"""
import os
from setuptools import setup, find_packages
"""
setup module for alibabacloud_sample.
Created on 31/07/2025
@author:
"""
PACKAGE = "alibabacloud_sample"
NAME = "alibabacloud_sample" or "alibabacloud-package"
DESCRIPTION = "Alibaba Cloud SDK Code Sample Library for Python"
AUTHOR = ""
AUTHOR_EMAIL = ""
URL = "https://github.com/aliyun/alibabacloud-sdk"
VERSION = __import__(PACKAGE).__version__
REQUIRES = [
"alibabacloud_ocr-api20210707>=3.1.3, <4.0.0",
"alibabacloud_tea_openapi>=0.3.15, <1.0.0",
"alibabacloud_tea_console>=0.0.1, <1.0.0",
"alibabacloud_tea_util>=0.3.13, <1.0.0",
"alibabacloud_credentials>=1.0.2, <2.0.0", 'flask'
]
LONG_DESCRIPTION = ''
if os.path.exists('./README.md'):
with open("README.md", encoding='utf-8') as fp:
LONG_DESCRIPTION = fp.read()
setup(
name=NAME,
version=VERSION,
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
long_description_content_type='text/markdown',
author=AUTHOR,
author_email=AUTHOR_EMAIL,
license="Apache License 2.0",
url=URL,
keywords=["alibabacloud","sample"],
packages=find_packages(exclude=["tests*"]),
include_package_data=True,
platforms="any",
install_requires=REQUIRES,
python_requires=">=3.6",
classifiers=(
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
"Topic :: Software Development"
)
)
BIN
View File
Binary file not shown.
-15
View File
@@ -1,15 +0,0 @@
{
"name": "webapp",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/dateutil": {
"version": "0.1.0",
"resolved": "https://registry.npmmirror.com/dateutil/-/dateutil-0.1.0.tgz",
"integrity": "sha512-bI8Lm50mageQER89AvYr+bAxXn4MCAkjSg3M58QY2evrIypUk2aCQcMZ86f31tjmt2ceMrPkrHkhItYqOJsObw==",
"engines": {
"node": "*"
}
}
}
}
-19
View File
@@ -1,19 +0,0 @@
Copyright (c) 2010 Borgar Þorsteinsson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-224
View File
@@ -1,224 +0,0 @@
# Dateutil
Dateutil is a modest collection of utility methods for manipulating dates. It works both in Node.JS and in browsers. It's goal is to provide extendable mechanisms for parsing and formatting dates, as well as other convenient date methods.
Currently, the library supports formatting of nearly full spec of PHP style dates (minus the really useless bits), and parses about the full range of ISO 8901 formats. It supports translations (for formatter) but no timezones.
## Dateutil methods
### dateutil.date( [year], [month], [day], [hour], [min], [sec], [ms] )
Function returns a new *Date* instance set to the expected date. If no arguments are given, then it returns the current date. When any arguments are given they are handled in much the same way the native date constructor does, except the first argument is always treated as a year.
It is safe to pass strings as arguments.
**Please note:** Months are zero based in set just as they are in native *Date* construction.
### dateutil.isLeapYear( date / year )
Function accepts a *Date*, or a year, and will return true if the year is a leap year or false if not.
dateutil.isLeapYear( 1468 ) == true
### dateutil.daysInMonth( date )
Function accepts a *Date* and returns the number of days in it's month.
dateutil.daysInMonth( new Date(1920, 3, 1) ) == 30
### dateutil.isocalendar( date )
Function accepts a *Date* and returns a three value array containing the ISO 8901 year, week, and day (of the week), respectively.
dateutil.isocalendar( new Date(2010, 0, 3) ) == [2009, 53, 7]
### dateutil.set( date, values )
Function accepts a *Date* and an object of values. The function returns the input date (same instance) having set the units specified in the values collection.
var mydate = new Date( 2000, 9, 16, 10, 45, 12 );
dateutil.set( mydate, { hour: 0, minute: 0, second: 0 });
result: mydate == new Date( 2000, 9, 16, 0, 0, 0 );
The function will accept all or any of these keys:
`year`, `month`, `day`, `hour`, `minute`, `second`, `millisecond`. and their plural forms (`years`, `minutes`, etc. ); and these shorthand variations: `yr` (year), `mn` (month), `day` (day), `hr` (hour), `min` (minute), `sec` (second), `ms` (millisecond).
**Please note:** Months are zero based in set just as they are in native *Date* construction.
This function tries to avoid rollover gotchas that can occur when using native members to set date values. A simplified example of this:
var d = new Date( 1999, 1, 20 );
d.setUTCDate( 30 ); // Tue Mar 02 1999 00:00:00 GMT+0000 (GMT)
d.setUTCMonth( 0 ); // Sat Jan 02 1999 00:00:00 GMT+0000 (GMT)
The `dateutil.set` function is takes steps to avoid the problem:
var d = new Date( 1999, 1, 20 );
dateutil.set(d, {
'date': 30,
'month': 0
}); // Sat Jan 30 1999 00:00:00 GMT+0000 (GMT)
var d = new Date( 1999, 1, 20 );
dateutil.set(d, {
'month': 0,
'date': 30
}); // Sat Jan 30 1999 00:00:00 GMT+0000 (GMT)
If you want to be sure you get the correct date then you need to use the `dateutil.date`
### dateutil.parse( string )
Function accepts a string (representing a date) and will output a *Date* based on parsing the string.
dateutil.parse('2005-01-01') == new Date(2005, 0, 1)
The function will aways return a *Date* instance, valid or not. Internally it falls back to native parser if it fails to recognize the format.
A mostly complete list of recognized formats:
* yyyy-mm-dd hh:mm:ss.ffff+0000 &nbsp; &mdash; *(timezone is currently ignored)*
* yyyy-mm-dd hh:mm:ss.ffffZ
* yyyy-mm-dd hh:mm:ss.ffff
* yyyy-mm-dd hh:mm
* yyyy-mm-ddThh:mm:ss.ffff+0000 &nbsp; &mdash; *(timezone is currently ignored)*
* yyyy-mm-ddThh:mm:ss.ffffZ
* yyyy-mm-ddThh:mm:ss.ffff
* yyyy-mm-ddThh:mm
* yyyy-mm-dd
* yyyy-mmdd
* yyyymmdd
* yyyy-ddd &nbsp; &mdash; *year with day-of-the-year*
* yyyy-Www-d
* yyyy-Wwwd
* yyyy-Www
* yyyyWww-d
* yyyyWwwd
* yyyyWww
* yyyy-Qq &nbsp; &mdash; *year with quarter*
* yyyyQq
* yyyy-mm
* yyyy/mm
* yyyy
... In addition to the formats JavaScript can natively parse.
#### Adding a custom parser
You may add your own parser by assigning them into `dateutil._parsers`. A parser is simply an object with two members:
* `test`: a regular expression used to test if this date can be parsed by the parser. Keep these simple and avoid capture groups, or suffer the slowdown cost.
* `parse`: a function that handles turning the string into a `Date` instance.
An contrived example:
// year + excel week
dateutil._parsers['year_and_excel_week'] = {
test: /^\d{4}_[0-5]\d$/,
parse: function ( str ) {
var bits = str.split('_');
var year = parseInt( bits[0], 10 );
var dofy = parseInt( bits[1], 10 );
return new Date( year, 0, ((dofy - 1) * 7) + 1);
}
};
// usage:
dateutil.parse('2002_31') == new Date(2002, 6, 30)
### dateutil.format( date, format_string, [language] )
Function accepts a *Date, a *PHP* style [format string][1], and an optional language identifyer, and will return a formatted date string. Refer to the [PHP docs][1] for the full spec of available format characters.
var mydate = new Date( 2000, 9, 16, 10, 45, 12 );
dateutil.format( mydate, 'jS F Y' ) == "16th October 2000"
The `B`, `Z`, and `I` characters have been purposely omitted, and the following new characters added:
* `q` &mdash; quarter of the year
The third optional parameter will get passed through the formatting system until it reaches
The format method is smart about being assigned to the `Date.prototype` object and will work as expected:
Date.prototype.format = dateutil.format;
new Date( 1975, 9, 16 ).format( 'Y-m-d' ) == "1975-10-16"
#### Adding a custom formatter
You may add your own formatter by assigning them into `dateutil._formats`. A parser is simply a function that takes a *Date* parameter, a language parameter, and returns a string.
An example that adds *Swatch internet time* formatter:
// Swatch Internet time
dateutil._formats['B'] = function (d) {
var mo = 0; // This should really be: isDST * 60 + timeZoneOffsetInMinutes
return Math.round( ( d.getUTCHours() * 3600 +
( ( d.getUTCMinutes() - mo + 60 ) * 60 ) +
d.getUTCSeconds() ) * 1000 / 86400 ) % 1000;
};
var mydate = new Date( 1961, 0, 3, 1, 51, 10, 1 );
dateutil.format( mydate, 'B' ) == '119'
If you call `dateutil._`, or recursively call formatting or other specific formatting functions for delegating work, it is important that you keep passing the second parameter so that a specified language is perserved.
An example that adds upper case 4 letter month name:
dateutil._formats['R'] = function (d,l) {
var mont = this['F']( d, l ); // fetch translated month in "l" language
return mont.substr( 0, 4 ).toUpperCase();
};
### dateutil.today()
Function returns a new *Date* instance set to the current day.
### dateutil.now()
Function returns a new *Date* instance set to the current moment. Uses native implementation if it exists.
### dateutil._( string, [language] )
A string translation function. This function looks for the string argument as a key in `dateutil.lang[ language ]` and uses the the value if it exists, otherwise it falls back on the string argument.
You can feed the system translation strings and use it, or alternatively, if you already have another translation system then you can overwrite this function with your own translation function.
In order to use the built in system you would add translated strings like in this example (Icelandic language):
dateutil.lang.is = {
'January': 'janúar',
'February': 'febrúar',
'March': 'mars',
'April': 'apríl',
'May': 'maí',
'June': 'júní',
// and so on ...
};
You should provide translations for the following strings:
* January February March April May June July August September October November December
* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
* Sunday Monday Tuesday Wednesday Thursday Friday Saturday
* Sun Mon Tue Wed Thu Fri Sat
[1]: http://php.net/manual/en/function.date.php
-398
View File
@@ -1,398 +0,0 @@
/*
* Dateutil
* - provides formatting, parsing and other utility functions for dates.
*
* Copyright (c) 2009 Borgar Þorsteinsson
* Licensed under the terms of the MIT (LICENSE.txt) software license.
*
*/
/*jslint laxbreak: true, undef: true *//*global module */
(function(__global__){
var SECOND_SIZE = 1000;
var MINUTE_SIZE = SECOND_SIZE * 60;
var HOUR_SIZE = MINUTE_SIZE * 60;
var DAY_SIZE = HOUR_SIZE * 24;
var WEEK_SIZE = DAY_SIZE * 7;
var MONTH_SIZE = DAY_SIZE * 30.436875; // average month size
var YEAR_SIZE = DAY_SIZE * 365.2425; // average year size
var _gl = __global__.lang = { 'en': {} };
var _m = 'January February March April May June July August September October November December'.split(' ');
var _d = 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday'.split(' ');
var method_size = {
'FullYear': 6, 'Month': 5, 'Date': 4, 'Hours': 3,
'Minutes': 2, 'Seconds': 1, 'Milliseconds': 0
};
var method_map = {
'yr': 'FullYear',
'year': 'FullYear',
'years': 'FullYear',
'mn': 'Month',
'month': 'Month',
'months': 'Month',
'day': 'Date',
'days': 'Date',
'date': 'Date',
'hr': 'Hours',
'hour': 'Hours',
'hours': 'Hours',
'min': 'Minutes',
'minute': 'Minutes',
'minutes': 'Minutes',
'sec': 'Seconds',
'second': 'Seconds',
'seconds': 'Seconds',
'ms': 'Milliseconds',
'millisecond': 'Milliseconds',
'milliseconds': 'Milliseconds'
};
// *****************************************
// *** *** *** formats & parsers *** *** ***
// *****************************************
var date_parsers = __global__._parsers = {
// year + month + day + time
// -- currently doesn't really support fractions on anything other than seconds >> FIXME
// -- does not support timezones other than Zulu
date_and_time: {
test: /^[+\-]?\d{4,6}(?:(?:\-\d\d){1,2}|\d{4})[T ](?:\d\d)(?::?\d\d){0,2}(?:[\.,]\d+)?(?:Z|[+\-]\d\d(:?\d\d)?)?$/,
size: 1,
parse: function ( str ) {
var b = str.split( /[T ]/ );
var date = date_parsers.date.parse( b[0] );
var m = b[1].replace( /:/g, '' )
.match( /^(\d\d)(\d\d)?(\d\d)?(?:[.,](\d+))?([+\-](?:\d\d){1,2})?/ );
// TODO: timezone (I have no need for this feature yet)
// if ( m[5] ) { var zone = m[5] || '0000'; }
var fs = 0, t = date.getTime() +
parseInt( m[1], 10 ) * HOUR_SIZE +
parseInt( m[2] || '0', 10 ) * MINUTE_SIZE +
parseInt( m[3] || '0', 10 ) * SECOND_SIZE;
if ( m[3] ) { fs = SECOND_SIZE; }
else if ( m[2] ) { fs = MINUTE_SIZE; }
else if ( m[1] ) { fs = HOUR_SIZE; }
t += parseFloat( '0.' + ( m[4] || '0' ) ) * fs;
date.setTime( t );
date.size = 0;
return date;
}
},
// year + month + day
date: {
test: /^[+\-]?\d{4,6}(?:\-\d\d\-\d\d|-?\d\d\d\d)$/,
size: DAY_SIZE,
parse: function ( str ) {
var s = str.replace( /\D/g, '' ),
d = __global__.date(
s.substring( 0, s.length -4 ),
+s.substr( s.length -4, 2 ) - 1,
s.substr( s.length -2 )
);
d.size = DAY_SIZE;
return d;
}
},
// year + month
year_and_month: {
test: /^[+\-]?\d{4,6}[\/\-](?:0[1-9]|1[012])$/,
size: MONTH_SIZE,
parse: function ( str ) {
var b = str.split( /[\/\-]/ );
var d = __global__.date( b[0], +b[1] - 1, 1 );
d.size = __global__.daysInMonth( d ) * DAY_SIZE;
return d;
}
},
// year
year: {
test: /^[+\-]?\d{4,6}$/,
size: YEAR_SIZE,
parse: function ( str ) {
var d = __global__.date( str, 0, 1 );
d.size = DAY_SIZE * ( __global__.isLeapYear( d ) ? 366 : 365 );
return d;
}
},
// year + iso week + [day]
year_and_week: {
test: /^[+\-]?\d{4,6}\-?[Ww]\d\d(?:\-?\d)?$/,
size: WEEK_SIZE,
parse: function ( str ) {
var s = str.toLowerCase().replace( /[^w\d]/g, '' ).split('w');
var d = __global__.date( s[0], 0, 3 ); // Jan 3
d.setUTCDate( 3 - d.getUTCDay() +
( parseInt( s[1].substr( 0, 2 ), 10 ) - 1 ) * 7 +
parseInt( s[1].substr( 2, 1 ) || '1', 10 ) );
d.size = WEEK_SIZE;
return d;
}
},
// year + day-of-year
// -- we don't allow the short form yyyyddd because of ambiguity with yyyymmdd
// -- 5 letter years would clash with cal-dates: yyyyyddd ~ yyyymmdd
year_and_ordinal: {
test: /^[+\-]?\d{4,6}\-[0-3]\d\d$/,
size: DAY_SIZE,
parse: function ( str ) {
var d = new Date(0);
d.setUTCFullYear( parseInt( str.substr(0,str.length-4), 10 ) );
d.setDate( parseInt( str.substr(str.length-3), 10 ) );
d.size = DAY_SIZE;
return d;
}
},
// year + quarter
year_and_quarter: {
test: /^[+\-]?\d{4,6}\-?[Qq][1-4]$/,
size: YEAR_SIZE / 4,
parse: function ( str ) {
var b = str.split(/\-?[Qq]/),
d = __global__.date( b[0], ( parseInt( b[1], 10 ) - 1 ) * 3 );
d.size = DAY_SIZE;
return d;
}
}
};
var date_formatters = __global__._formats = {
// Lowercase Ante meridiem and Post meridiem
a: function (d) { return d.getUTCHours() >= 12 ? 'pm' : 'am'; },
// Uppercase Ante meridiem and Post meridiem
A: function (d) { return d.getUTCHours() >= 12 ? 'PM' : 'AM'; },
// ISO 8601 date
c: function (d,l) { return __global__.format( d, 'Y-m-d\\TH:i:s.', l ) + __global__.pad( d.getUTCMilliseconds(), 3 ) + 'Z'; },
// Day of the month, 2 digits with leading zeros
d: function (d) { return __global__.pad( d.getUTCDate() ); },
// A textual representation of a day, three letters
D: function (d,l) { return __global__._( _d[ d.getUTCDay() ].substr( 0, 3 ), l ); },
// Time zone identifier
e: function (d) { return 'UTC'; },
// A full textual representation of a month
F: function (d,l) { return __global__._( _m[ d.getUTCMonth() ], l ); },
// 12-hour format of an hour without leading zeros
g: function (d) { return d.getUTCHours() % 12 || 12; },
// 24-hour format of an hour without leading zeros
G: function (d) { return d.getUTCHours(); },
// 12-hour format of an hour with leading zeros
h: function (d) { return __global__.pad( d.getUTCHours() % 12 || 12 ); },
// 24-hour format of an hour with leading zeros
H: function (d) { return __global__.pad( d.getUTCHours() ); },
// Minutes with leading zeros
i: function (d) { return __global__.pad( d.getUTCMinutes() ); },
// Day of the month without leading zeros
j: function (d) { return d.getUTCDate(); },
// A full textual representation of the day of the week
l: function (d,l) { return __global__._( _d[ d.getUTCDay() ], l ); },
// Whether it's a leap year (0 = yes, 1 = no)
L: function (d) { return __global__.isLeapYear( d ) * 1; },
// Numeric representation of a month, with leading zeros
m: function (d) { return __global__.pad( d.getUTCMonth() + 1 ); },
// A short textual representation of a month, three letters
M: function (d,l) { return __global__._( _m[ d.getUTCMonth() ].substr( 0, 3 ), l ); },
// Numeric representation of a month, without leading zeros
n: function (d) { return d.getUTCMonth() + 1; },
// ISO-8601 numeric representation of the day of the week
N: function (d) { return d.getUTCDay() || 7; },
// ISO-8601 year number
o: function (d) { return __global__.pad( __global__.isocalendar(d)[0], 4 ); },
// Time zone designator
O: function (d) { return '+0000'; },
// Time zone difference
P: function (d) { return '+00:00'; },
// Quarter of the year
q: function (d) { return ~~( d.getUTCMonth() / 3 ) + 1; },
// RFC 2822 formatted date
r: function (d,l) { return __global__.format( d, 'D, d M Y H:i:s O', l ); },
// Seconds, with leading zeros
s: function (d) { return __global__.pad( d.getUTCSeconds() ); },
// English ordinal suffix for the day of the month, 2 characters
S: function (d) {
var a = d.getUTCDate() % 10, b = d.getUTCDate() % 100;
return (a === 1) && (b !== 11) && 'st' ||
(a === 2) && (b !== 12) && 'nd' ||
(a === 3) && (b !== 13) && 'rd' || 'th';
},
// Number of days in the given month
t: function (d) { return __global__.daysInMonth( d ); },
// Time zone abbreviation
T: function (d) { return 'UTC'; },
// Microseconds
u: function (d) { return __global__.pad( d.getUTCMilliseconds(), 6 ); },
// Seconds since the Unix Epoch
U: function (d) { return ~~( d / 1000 ); },
// Numeric representation of the day of the week
w: function (d) { return d.getUTCDay(); },
// ISO-8601 week number of year, weeks starting on Monday
W: function (d) { return __global__.pad( __global__.isocalendar(d)[1] ); },
// A short numeric representation of a year, 2 digits
y: function (d) { return (d.getUTCFullYear() + '').substr(2); },
// A full numeric representation of a year, 4 digits
Y: function (d) { return d.getUTCFullYear(); },
// The day of the year (starting from 0)
z: function (d) { return Math.floor( ( d - (new Date(Date.UTC(d.getUTCFullYear(), 0, 1))) ) / DAY_SIZE ); }
};
// **************************************
// *** *** *** module methods *** *** ***
// **************************************
__global__.date = function ( y, m, d, h, n, s, ms ) {
var ts = ( !arguments.length ) ? __global__.now()
: Date.UTC( parseInt( y||0, 10 ), parseInt( m||0, 10 ), parseInt( d||1, 10 ),
parseInt( h||0, 10 ), parseInt( n||0, 10 ), parseInt( s||0, 10 ),
parseInt( ms||0, 10 ) );
return new Date( ts );
};
// zero pad a string n to l places
__global__.pad = function ( n, l ) {
var s = __global__.pad.z;
if ( !s ) { // This mess is here because JSlint breaks on new Array(999)
var a = []; a[999] = '';
s = __global__.pad.z = a.join('0');
}
s += n;
return s.substring( s.length -( l || 2 ) );
};
// is a given year a leap year
__global__.isLeapYear = function ( y ) {
if ( y instanceof Date ) { y = y.getUTCFullYear(); }
return (( y % 4 === 0 ) && ( y % 100 !== 0 )) || ( y % 400 === 0 );
};
// return the number of days in a date's month
__global__.daysInMonth = function ( dt ) {
var m = dt.getUTCMonth();
if ( m === 1 ) {
return __global__.isLeapYear( dt ) ? 29 : 28;
}
return [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ][ m ];
};
// return a 3-tuple, (ISO year, ISO week number, ISO weekday).
__global__.isocalendar = function ( dt ) {
var d = dt.getUTCDay();
var t = new Date( dt.valueOf() );
t.setDate( t.getDate() - ((d + 6) % 7) + 3 );
var iso_year = t.getUTCFullYear();
var w = Math.floor( (t.getTime() - __global__.date(iso_year, 0, 1, -6)) / 86400000 );
return [ iso_year, 1+Math.floor(w/7), d||7 ];
};
// Allow setting multiple properties at once using object notation:
// `mydate.set({ hour: 8, minute: 12, second: 0 });`
__global__.set = function ( dt, values ) {
if ( typeof values === 'object' ) {
var s = [], n, i;
// step 1: collect a list of values to modify
for ( var key in values ) {
if ( key in method_map ) {
n = method_map[ key ];
s.push( [ values[ key ], n, method_size[ n ] ] );
}
}
// step 2: order values by size
s = s.sort(function ( a, b ) { return a[2] - b[2]; });
// step 3: little endian value zeroing
for (i=0; i<s.length; i++) {
dt[ 'setUTC' + s[i][1] ]( s[i][1] === 'Date' ? 1 : 0 );
}
// step 4: big endian value setting
for (i=s.length; i--; ) {
dt[ 'setUTC' + s[i][1] ]( s[i][0] );
}
}
return dt;
};
// parse a date
__global__.parse = function ( str ) {
var d;
if ( typeof str !== 'string' ) {
throw new Error( "dateutil parser can't parse non-strings." );
}
for ( var dtype in date_parsers ) {
if ( date_parsers[dtype].test.test( str ) ) {
d = date_parsers[ dtype ].parse( str );
d.type = dtype;
d.size = d.size || 0;
break;
}
}
// default parser supports RFC and a few more, or returns an "invalid date"
if ( !d ) {
d = new Date( str );
d.size = 0;
d.type = 'unknown_date';
}
return d;
};
// format a date to string
__global__.format = function ( d, fmt, lang ) {
if ( arguments.length === 1 && this instanceof Date ) {
fmt = d;
d = this;
}
else if ( !(d instanceof Date) ) {
throw new Error('No date passed to format.');
}
for ( var r=[], c, l=fmt.length, i=0; i<l; i++ ) {
c = fmt.charAt( i );
// format characters
if ( c !== '\\' ) {
r.push( (c in date_formatters) ? date_formatters[ c ]( d, lang ) : c );
}
// escaped characters & unreconized characters
else {
c = i < fmt.length ? fmt.charAt( ++i ) : c;
r.push( c );
}
}
return r.join( '' );
};
// return a Date object for the current date (0 time)
__global__.today = function () {
return __global__.set( __global__.date(), {
hour: 0, minute: 0, second: 0, millisecond: 0
});
};
// return timestamp for the moment
__global__.now = ( typeof Date.now === 'function' )
? Date.now
: function () { return +new Date(); };
// translation hook
__global__._ = function ( s, lang ) {
var l = lang && __global__.lang[ lang ];
return ( l && s in l ) ? l[s] : s;
};
}(
(typeof module !== 'undefined' && module.exports)
? module.exports
: (this.dateutil = {})
));
-25
View File
@@ -1,25 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 />
<title>dateutil tests</title>
<!-- links to qunit + jquery -->
<link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script>
<!-- JSON tests -->
<script src="dateutil.js"></script>
<script src="dateutil.testdates.js"></script>
<script src="dateutil.test.js"></script>
</head>
<body>
<h1 id="qunit-header">dateutil tests</h1>
<h2 id="qunit-banner"></h2>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
</body>
</html>
-396
View File
@@ -1,396 +0,0 @@
test('dateutil', function () {
ok( typeof dateutil === 'object', 'have dateutil' );
});
test("dateutil.isLeapYear", function () {
// expect( 10 );
ok( typeof dateutil.isLeapYear === 'function', 'dateutil.isLeapYear() is a function' );
same( dateutil.isLeapYear(1468), true , 'dateutil.isLeapYear(1468)' );
same( dateutil.isLeapYear(1600), true , 'dateutil.isLeapYear(1600)' );
same( dateutil.isLeapYear(1852), true , 'dateutil.isLeapYear(1852)' );
same( dateutil.isLeapYear(1920), true , 'dateutil.isLeapYear(1920)' );
same( dateutil.isLeapYear(1968), true , 'dateutil.isLeapYear(1968)' );
same( dateutil.isLeapYear(2000), true , 'dateutil.isLeapYear(2000)' );
same( dateutil.isLeapYear(2008), true , 'dateutil.isLeapYear(2008)' );
same( dateutil.isLeapYear(2400), true , 'dateutil.isLeapYear(2400)' );
same( dateutil.isLeapYear(2800), true , 'dateutil.isLeapYear(2800)' );
same( dateutil.isLeapYear(1933), false, 'dateutil.isLeapYear(1933)' );
same( dateutil.isLeapYear(1999), false, 'dateutil.isLeapYear(1999)' );
same( dateutil.isLeapYear(1800), false, 'dateutil.isLeapYear(1800)' );
same( dateutil.isLeapYear(1900), false, 'dateutil.isLeapYear(1900)' );
same( dateutil.isLeapYear(2100), false, 'dateutil.isLeapYear(2100)' );
same( dateutil.isLeapYear(2200), false, 'dateutil.isLeapYear(2200)' );
});
test("dateutil.daysInMonth", function () {
// expect( 10 );
ok( typeof dateutil.daysInMonth === 'function', 'dateutil.daysInMonth() is a function' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 0,1) )), 31, 'dateutil.daysInMonth( Jan. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 1,1) )), 28, 'dateutil.daysInMonth( Feb. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 2,1) )), 31, 'dateutil.daysInMonth( Mar. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 3,1) )), 30, 'dateutil.daysInMonth( Apr. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 4,1) )), 31, 'dateutil.daysInMonth( May. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 5,1) )), 30, 'dateutil.daysInMonth( Jun. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 6,1) )), 31, 'dateutil.daysInMonth( Jul. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 7,1) )), 31, 'dateutil.daysInMonth( Aug. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 8,1) )), 30, 'dateutil.daysInMonth( Sep. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999, 9,1) )), 31, 'dateutil.daysInMonth( Oct. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999,10,1) )), 30, 'dateutil.daysInMonth( Nov. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1999,11,1) )), 31, 'dateutil.daysInMonth( Dec. 1999 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 0,1) )), 31, 'dateutil.daysInMonth( Jan. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 1,1) )), 29, 'dateutil.daysInMonth( Feb. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 2,1) )), 31, 'dateutil.daysInMonth( Mar. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 3,1) )), 30, 'dateutil.daysInMonth( Apr. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 4,1) )), 31, 'dateutil.daysInMonth( May. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 5,1) )), 30, 'dateutil.daysInMonth( Jun. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 6,1) )), 31, 'dateutil.daysInMonth( Jul. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 7,1) )), 31, 'dateutil.daysInMonth( Aug. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 8,1) )), 30, 'dateutil.daysInMonth( Sep. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920, 9,1) )), 31, 'dateutil.daysInMonth( Oct. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920,10,1) )), 30, 'dateutil.daysInMonth( Nov. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(1920,11,1) )), 31, 'dateutil.daysInMonth( Dec. 1920 )' );
same( dateutil.daysInMonth(new Date( Date.UTC(2100, 1,1) )), 28, 'dateutil.daysInMonth( Feb. 2100 )' );
});
test('dateutil.isocalendar', function () {
same( dateutil.isocalendar(new Date(Date.UTC(2005, 0, 1))), [2004,53,6], "2004-W53-6" );
same( dateutil.isocalendar(new Date(Date.UTC(2005, 0, 2))), [2004,53,7], "2004-W53-7" );
same( dateutil.isocalendar(new Date(Date.UTC(2005,11,31))), [2005,52,6], "2005-W52-6" );
same( dateutil.isocalendar(new Date(Date.UTC(2007, 0, 1))), [2007, 1,1], "2007-W01-1" );
same( dateutil.isocalendar(new Date(Date.UTC(2007,11,30))), [2007,52,7], "2007-W52-7" );
same( dateutil.isocalendar(new Date(Date.UTC(2007,11,31))), [2008, 1,1], "2008-W01-1" );
same( dateutil.isocalendar(new Date(Date.UTC(2008, 0, 1))), [2008, 1,2], "2008-W01-2" );
same( dateutil.isocalendar(new Date(Date.UTC(2008,11,29))), [2009, 1,1], "2009-W01-1" );
same( dateutil.isocalendar(new Date(Date.UTC(2008,11,31))), [2009, 1,3], "2009-W01-3" );
same( dateutil.isocalendar(new Date(Date.UTC(2009, 0, 1))), [2009, 1,4], "2009-W01-4" );
same( dateutil.isocalendar(new Date(Date.UTC(2009,11,31))), [2009,53,4], "2009-W53-4" );
same( dateutil.isocalendar(new Date(Date.UTC(2010, 0, 3))), [2009,53,7], "2009-W53-7" );
same( dateutil.isocalendar(new Date(Date.UTC(2009,11,31))), [2009,53,4], "2009-W53-4" );
same( dateutil.isocalendar(new Date(Date.UTC(2010, 0, 1))), [2009,53,5], "2009-W53-5" );
same( dateutil.isocalendar(new Date(Date.UTC(2010, 0, 2))), [2009,53,6], "2009-W53-6" );
same( dateutil.isocalendar(new Date(Date.UTC(2010, 0, 3))), [2009,53,7], "2009-W53-7" );
same( dateutil.isocalendar(new Date(Date.UTC(2008,11,28))), [2008,52,7], "2008-W52-7" );
same( dateutil.isocalendar(new Date(Date.UTC(2008,11,29))), [2009, 1,1], "2009-W01-1" );
same( dateutil.isocalendar(new Date(Date.UTC(2008,11,30))), [2009, 1,2], "2009-W01-2" );
same( dateutil.isocalendar(new Date(Date.UTC(2008,11,31))), [2009, 1,3], "2009-W01-3" );
same( dateutil.isocalendar(new Date(Date.UTC(2009, 0, 1))), [2009, 1,4], "2009-W01-4" );
});
test("dateutil.set", function () {
// expect( 10 );
ok( typeof dateutil.set === 'function', 'dateutil.set() is a function' );
var dt = new Date(Date.UTC(1975,9,16,10,24,12,50));
var bt = dateutil.set(new Date(0), {
year: 1975,
month: 9,
day: 16,
hour: 10,
minute: 24,
second: 12,
millisecond: 50
});
ok( +bt == +dt, 'dateutil.set' );
// testing rollover mechanism
var d = dateutil.set(new Date( Date.UTC( 1999, 1, 20 ) ), {
'date': 30,
'month': 0
});
ok( +d === 917654400000, 'prevent rollovers: 1999-02-20 date,month' );
var d = dateutil.set(new Date( Date.UTC( 1999, 1, 20 ) ), {
'month': 0,
'date': 30
});
ok( +d === 917654400000, 'prevent rollovers: 1999-02-20 month,date' );
var d = dateutil.set(new Date( Date.UTC( 1600, 1, 29 ) ), {
'date': 30,
'month': 0
});
same( +d, -11673590400000, 'prevent rollovers: 1600-02-29 date,month' );
var d = dateutil.set(new Date( Date.UTC( 1600, 1, 29 ) ), {
'month': 0,
'date': 30
});
same( +d, -11673590400000, 'prevent rollovers: 1600-02-29 month,date' );
});
test('dateutil.parse', function(){
var corduroy_full = new Date(Date.UTC(2011,10,11, 11,11,11, 111));
var corduroy_sec = new Date(Date.UTC(2011,10,11, 11,11,11));
var corduroy_mfrc = new Date(Date.UTC(2011,10,11, 11,11,6, 660));
var corduroy_min = new Date(Date.UTC(2011,10,11, 11,11));
var corduroy_hfrc = new Date(Date.UTC(2011,10,11, 11,6,39,600));
var corduroy_hour = new Date(Date.UTC(2011,10,11, 11));
var corduroy_day = new Date(Date.UTC(2011,10,11));
var corduroy_mon = new Date(Date.UTC(2011,10,1));
var corduroy_year = new Date(Date.UTC(2011,0,1));
var INVALID = new Date('borked')+'';
// date_and_time
same( +dateutil.parse('2011-11-11T11:11:11.111Z'), +corduroy_full, "2011-11-11T11:11:11.111Z" );
same( +dateutil.parse('2011-11-11T11:11:11Z'), +corduroy_sec, "2011-11-11T11:11:11Z" );
same( +dateutil.parse('2011-11-11T11:11.111Z'), +corduroy_mfrc, "2011-11-11T11:11.111Z" );
same( +dateutil.parse('2011-11-11T11:11Z'), +corduroy_min, "2011-11-11T11:11Z" );
same( +dateutil.parse('2011-11-11T11.111Z'), +corduroy_hfrc, "2011-11-11T11.111Z" );
same( +dateutil.parse('2011-11-11T11Z'), +corduroy_hour, "2011-11-11T11Z" );
same( +dateutil.parse('2011-11-11T11:11:11.111'), +corduroy_full, "2011-11-11T11:11:11.111" );
same( +dateutil.parse('2011-11-11T11:11:11'), +corduroy_sec, "2011-11-11T11:11:11" );
same( +dateutil.parse('2011-11-11T11:11.111'), +corduroy_mfrc, "2011-11-11T11:11.111" );
same( +dateutil.parse('2011-11-11T11:11'), +corduroy_min, "2011-11-11T11:11" );
same( +dateutil.parse('2011-11-11T11.111'), +corduroy_hfrc, "2011-11-11T11.111" );
same( +dateutil.parse('2011-11-11T11'), +corduroy_hour, "2011-11-11T11" );
same( +dateutil.parse('2011-11-11T11:11:11.111+00:00'), +corduroy_full, "2011-11-11T11:11:11.111+00:00" );
same( +dateutil.parse('2011-11-11T11:11:11+00:00'), +corduroy_sec, "2011-11-11T11:11:11+00:00" );
same( +dateutil.parse('2011-11-11T11:11.111+00:00'), +corduroy_mfrc, "2011-11-11T11:11.111+00:00" );
same( +dateutil.parse('2011-11-11T11:11+00:00'), +corduroy_min, "2011-11-11T11:11+00:00" );
same( +dateutil.parse('2011-11-11T11.111+00:00'), +corduroy_hfrc, "2011-11-11T11.111+00:00" );
same( +dateutil.parse('2011-11-11T11+00:00'), +corduroy_hour, "2011-11-11T11+00:00" );
same( +dateutil.parse('2011-11-11T11:11:11.111+00'), +corduroy_full, "2011-11-11T11:11:11.111+00" );
same( +dateutil.parse('2011-11-11T11:11:11+00'), +corduroy_sec, "2011-11-11T11:11:11+00" );
same( +dateutil.parse('2011-11-11T11:11.111+00'), +corduroy_mfrc, "2011-11-11T11:11.111+00" );
same( +dateutil.parse('2011-11-11T11:11+00'), +corduroy_min, "2011-11-11T11:11+00" );
same( +dateutil.parse('2011-11-11T11.111+00'), +corduroy_hfrc, "2011-11-11T11.111+00" );
same( +dateutil.parse('2011-11-11T11+00'), +corduroy_hour, "2011-11-11T11+00" );
// date
same( +dateutil.parse('2011-11-11'), +corduroy_day, "2011-11-11" );
same( +dateutil.parse('2011-1111'), +corduroy_day, "2011-1111" );
// year_and_month
same( +dateutil.parse('2011-11'), +corduroy_mon, "2011-11" );
same( +dateutil.parse('2011/11'), +corduroy_mon, "2011/11" );
same( ''+dateutil.parse('2011-13'), INVALID, "2011-13" ); // should fail!
// year
same( +dateutil.parse('2011'), +corduroy_year, "2011" );
same( +dateutil.parse('12011'), +new Date(Date.UTC(12011,0,1)), "12011" );
same( +dateutil.parse('-12011'), +new Date(Date.UTC(-12011,0,1)), "-12011" );
// year_and_week
ok( +corduroy_day == +dateutil.parse('2011-W45-5'), "2011-W45-5" );
ok( +corduroy_day == +dateutil.parse('2011W45-5'), "2011W45-5" );
ok( +corduroy_day == +dateutil.parse('2011W455'), "2011W455" );
ok( +new Date(Date.UTC(2011,10,7)) == +dateutil.parse('2011-W45'), "2011-W45" );
ok( +new Date(Date.UTC(2011,10,7)) == +dateutil.parse('2011W45'), "2011W45" );
// year_and_ordinal
same( +dateutil.parse('-12011-314'), +new Date( Date.UTC( -12011,0,314 ) ), "-12011-314" );
same( +dateutil.parse('2011-314'), +new Date( Date.UTC( 2011,0,314 ) ), "2011-314" );
same( ''+dateutil.parse('2011-500'), INVALID, "2011-500" ); // should fail!
// year_and_quarter
var corduroy_q = new Date( Date.UTC( 2011,9,1 ) );
ok( +dateutil.parse('-12011-Q4') == +new Date(Date.UTC(-12011,9,1)), "-12011-Q4" );
ok( +corduroy_q == +dateutil.parse('2011Q4'), "2011Q4" );
ok( +corduroy_q == +dateutil.parse('2011-Q4'), "2011-Q4" );
ok( +corduroy_q == +dateutil.parse('2011q4'), "2011q4" );
ok( +corduroy_q == +dateutil.parse('2011-q4'), "2011-q4" );
});
test("dateutil.parse: JSON style calendar dates", function () {
for (var i=0,l=test_dates.length; i<l; i++) {
var test_date = test_dates[i];
var parsed_caldate = dateutil.parse( test_date[0] );
var org_timestamp = test_date[2];
with (Math) {
// I anticipate that there may be some floating point artifacts
// in the milliseconds. Currently allowing a variation of a about
// a microsecond
var diff = parsed_caldate - floor( org_timestamp * 1000 );
ok(
abs( diff ) <= 1,
test_date[0]
);
}
}
});
test("dateutil.parse: yyyy-Www-d", function () {
for (var i=0,l=test_dates.length; i<l; i++) {
var test_date = test_dates[i];
with (Math) {
var d = new Date( floor( test_date[2] * 1000 ) );
d.setUTCHours(0); d.setUTCMinutes(0); d.setUTCSeconds(0); d.setUTCMilliseconds(0);
same( +dateutil.parse( test_date[1] ), +d, test_date[1] );
}
}
});
test("dateutil.format", function () {
// expect( 10 );
ok( typeof dateutil.format === 'function', 'dateutil.format() is a function' );
var d = new Date( Date.UTC( 2001, 2, 10, 17, 16, 18, 13 ) );
same( dateutil.format( d, "F j, Y, g:i a"), "March 10, 2001, 5:16 pm", "F j, Y, g:i a" );
same( dateutil.format( d, "m.d.y"), "03.10.01", "m.d.y" );
same( dateutil.format( d, "j, n, Y"), "10, 3, 2001", "j, n, Y" );
same( dateutil.format( d, "Ymd"), "20010310", "Ymd" );
same( dateutil.format( d, 'h-i-s, j-m-y, it is w Day'), "05-16-18, 10-03-01, 1631 1618 6 Satpm01", "h-i-s, j-m-y, it is w Day" );
same( dateutil.format( d, '\\i\\t \\i\\s \\t\\h\\e jS \\d\\a\\y.'), "it is the 10th day.", "\\i\\t \\i\\s \\t\\h\\e jS \\d\\a\\y." );
same( dateutil.format( d, "D M j G:i:s T Y"), "Sat Mar 10 17:16:18 UTC 2001", "D M j G:i:s T Y" );
same( dateutil.format( d, 'H:m:s \\m \\i\\s\\ \\m\\o\\n\\t\\h'), "17:03:18 m is month", "H:m:s \\m \\i\\s\\ \\m\\o\\n\\t\\h" );
same( dateutil.format( d, "H:i:s"), "17:16:18", "Format: 17:16:18" );
var d = new Date( Date.UTC( 2006, 7, 10, 15, 5, 8, 123 ) );
equals( dateutil.format( d, 'd'), '10', 'format: d' );
equals( dateutil.format( d, 'D'), 'Thu', 'format: D' );
equals( dateutil.format( d, 'j'), '10', 'format: j' );
equals( dateutil.format( d, 'l'), 'Thursday', 'format: l' );
equals( dateutil.format( d, 'N'), '4', 'format: N' );
equals( dateutil.format( d, 'S'), 'th', 'format: S' );
equals( dateutil.format( d, 'w'), '4', 'format: w' );
equals( dateutil.format( d, 'z'), '221', 'format: z' );
equals( dateutil.format( d, 'W'), '32', 'format: W' );
equals( dateutil.format( d, 'F'), 'August', 'format: F' );
equals( dateutil.format( d, 'm'), '08', 'format: m' );
equals( dateutil.format( d, 'M'), 'Aug', 'format: M' );
equals( dateutil.format( d, 'n'), '8', 'format: n' );
equals( dateutil.format( d, 't'), '31', 'format: t' );
equals( dateutil.format( d, 'L'), '0', 'format: L' );
equals( dateutil.format( d, 'o'), '2006', 'format: o' );
equals( dateutil.format( d, 'Y'), '2006', 'format: Y' );
equals( dateutil.format( d, 'y'), '06', 'format: y' );
equals( dateutil.format( d, 'a'), 'pm', 'format: a' );
equals( dateutil.format( d, 'A'), 'PM', 'format: A' );
equals( dateutil.format( d, 'B'), 'B', 'format: B' ); // not supported
equals( dateutil.format( d, 'g'), '3', 'format: g' );
equals( dateutil.format( d, 'G'), '15', 'format: G' );
equals( dateutil.format( d, 'h'), '03', 'format: h' );
equals( dateutil.format( d, 'H'), '15', 'format: H' );
equals( dateutil.format( d, 'i'), '05', 'format: i' );
equals( dateutil.format( d, 's'), '08', 'format: s' );
equals( dateutil.format( d, 'u'), '000123', 'format: u' );
equals( dateutil.format( d, 'e'), 'UTC', 'format: e' );
equals( dateutil.format( d, 'I'), 'I', 'format: I' ); // not supported
equals( dateutil.format( d, 'O'), '+0000', 'format: O' );
equals( dateutil.format( d, 'P'), '+00:00', 'format: P' );
equals( dateutil.format( d, 'T'), 'UTC', 'format: T' );
equals( dateutil.format( d, 'Z'), 'Z', 'format: Z' ); // not supported
equals( dateutil.format( d, 'c'), '2006-08-10T15:05:08.123Z', 'format: c' );
equals( dateutil.format( d, 'r'), 'Thu, 10 Aug 2006 15:05:08 +0000', 'format: r' );
equals( dateutil.format( d, 'U'), '1155222308', 'format: U' );
var d = new Date( Date.UTC( 1961, 0, 3, 1, 51, 10, 1 ) );
equals( dateutil.format( d, 'd'), '03', 'format: d' );
equals( dateutil.format( d, 'D'), 'Tue', 'format: D' );
equals( dateutil.format( d, 'j'), '3', 'format: j' );
equals( dateutil.format( d, 'l'), 'Tuesday', 'format: l' );
equals( dateutil.format( d, 'N'), '2', 'format: N' );
equals( dateutil.format( d, 'S'), 'rd', 'format: S' );
equals( dateutil.format( d, 'w'), '2', 'format: w' );
equals( dateutil.format( d, 'z'), '2', 'format: z' );
equals( dateutil.format( d, 'W'), '01', 'format: W' );
equals( dateutil.format( d, 'F'), 'January', 'format: F' );
equals( dateutil.format( d, 'm'), '01', 'format: m' );
equals( dateutil.format( d, 'M'), 'Jan', 'format: M' );
equals( dateutil.format( d, 'n'), '1', 'format: n' );
equals( dateutil.format( d, 't'), '31', 'format: t' );
equals( dateutil.format( d, 'L'), '0', 'format: L' );
equals( dateutil.format( d, 'o'), '1961', 'format: o' );
equals( dateutil.format( d, 'Y'), '1961', 'format: Y' );
equals( dateutil.format( d, 'y'), '61', 'format: y' );
equals( dateutil.format( d, 'a'), 'am', 'format: a' );
equals( dateutil.format( d, 'A'), 'AM', 'format: A' );
equals( dateutil.format( d, 'B'), 'B', 'format: B' ); // unsupported
equals( dateutil.format( d, 'g'), '1', 'format: g' );
equals( dateutil.format( d, 'G'), '1', 'format: G' );
equals( dateutil.format( d, 'h'), '01', 'format: h' );
equals( dateutil.format( d, 'H'), '01', 'format: H' );
equals( dateutil.format( d, 'i'), '51', 'format: i' );
equals( dateutil.format( d, 's'), '10', 'format: s' );
equals( dateutil.format( d, 'u'), '000001', 'format: u' );
equals( dateutil.format( d, 'e'), 'UTC', 'format: e' );
equals( dateutil.format( d, 'I'), 'I', 'format: I' ); // not supported
equals( dateutil.format( d, 'O'), '+0000', 'format: O' );
equals( dateutil.format( d, 'P'), '+00:00', 'format: P' );
equals( dateutil.format( d, 'T'), 'UTC', 'format: T' );
equals( dateutil.format( d, 'Z'), 'Z', 'format: Z' ); // not supported
equals( dateutil.format( d, 'c'), '1961-01-03T01:51:10.001Z', 'format: c' );
equals( dateutil.format( d, 'r'), 'Tue, 03 Jan 1961 01:51:10 +0000', 'format: r' );
equals( dateutil.format( d, 'U'), '-283817329', 'format: U' );
// allow transfering to prototype
Date.prototype.format = dateutil.format;
var d = new Date( Date.UTC(1975, 9, 16) );
equals( d.format('Y-m-d'), "1975-10-16", 'format prototype assignment' );
try { delete Date.prototype.format; }
catch (err) {}
});
test("dateutil.today", function () {
// expect( 10 );
ok( typeof dateutil.today === 'function', 'dateutil.today() is a function' );
var d = new Date();
var today = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
same( +dateutil.today(), +today, 'dateutil.today()' );
same( +dateutil.today(), +dateutil.set(new Date, { hour:0, minute:0, second:0, millisecond:0 }), 'dateutil.today() vs. dateutil.set()' );
});
test("dateutil.now", function () {
var d = new Date(), now = dateutil.now();
// expect( 10 );
ok( typeof dateutil.now === 'function', 'dateutil.now() is a function' );
same( +d, +now, 'dateutil.now()' );
});
test("dateutil._", function () {
ok( typeof dateutil._ === 'function', 'dateutil._() is a function' );
// provide translations for icelandic:
dateutil.lang.is = {
"January":"janúar", "February":"febrúar", "March":"mars", "April":"apríl", "May":"maí", "June":"júní", "July":"júlí", "August":"ágúst", "September":"september", "October":"október", "November":"nóvember", "December":"desember",
"Sunday":"sunnudagur", "Monday":"mánudagur", "Tuesday":"þriðjudagur", "Wednesday":"miðvikudagur", "Thursday":"fimmtudagur", "Friday":"föstudagur", "Saturday":"laugardagur",
"Jan":"jan", "Feb":"feb", "Mar":"mar", "Apr":"apr", "Jun":"jún", "Jul":"júl", "Aug":"ágú", "Sep":"sep", "Oct":"okt", "Nov":"nóv", "Dec":"des",
"Sun":"sun", "Mon":"mán", "Tue":"þri", "Wed":"mið", "Thu":"fim", "Fri":"fös", "Sat":"lau"
};
var d = new Date( Date.UTC( 2006, 7, 10, 15, 5, 8, 123 ) );
equals( dateutil.format( d, 'D', 'is' ), 'fim', 'format: D' );
equals( dateutil.format( d, 'l', 'is' ), 'fimmtudagur', 'format: l' );
equals( dateutil.format( d, 'F', 'is' ), 'ágúst', 'format: F' );
equals( dateutil.format( d, 'M', 'is' ), 'ágú', 'format: M' );
dateutil._ = function () { return 'BORK'; };
equals( dateutil.format( d, 'D', 'is' ), 'BORK', 'format: D' );
equals( dateutil.format( d, 'l', 'is' ), 'BORK', 'format: l' );
equals( dateutil.format( d, 'F', 'is' ), 'BORK', 'format: F' );
equals( dateutil.format( d, 'M', 'is' ), 'BORK', 'format: M' );
});
-164
View File
@@ -1,164 +0,0 @@
/*
* This file implements a subset of the QUnit functions/features to allow
* running simple QUnit tests in Node.JS.
*
* Copyright (c) 2009 Borgar Þorsteinsson
* Licensed under the terms of the MIT (LICENSE.txt) software license.
*
*/
// the files to load for the test, test itself last:
var files = [
'dateutil.js',
'dateutil.testdates.js',
'dateutil.test.js'
];
/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */
var sys = require('sys'),
fs = require('fs'),
Script = process.binding('evals').Script,
assert = require('assert')
;
var tests = [];
var current_test;
var sandbox = {
expect: function ( num ) {
current_test.expected = num;
},
ok: function ( value, message ) {
current_test.results.push([ !!value, message ]);
},
equals: function ( rest, exp, msg ) {
try {
assert.equal(rest, exp);
}
catch ( err ) {
current_test.results.push([ false, msg + ', expected: '+exp+' result: ' + rest ]);
return;
}
current_test.results.push([ true, msg ]);
},
same: function ( rest, exp, msg ) {
try {
assert.deepEqual(rest, exp);
}
catch ( err ) {
current_test.results.push([ false, msg + ', expected: '+exp+' result: ' + rest ]);
return;
}
current_test.results.push([ true, msg ]);
},
test: function ( testName /*, expected, callback, async */ ) {
var tmap = {
'object':'environment',
'boolean':'async',
'function':'callback',
'number':'expected'
};
current_test = {
name: testName,
expected: null,
callback: null,
context: {},
async: false, // TODO: async doesn't actually do anything :-/
error: false,
results: []
};
tests.push( current_test );
for (var i=1,l=arguments.length; i<l; i++) {
current_test[ tmap[ typeof arguments[i] ] || 'error' ] = arguments[i];
}
try {
current_test.callback.call( current_test.context );
}
catch ( err ) {
current_test.results.push([ false, err ]);
}
if ( current_test.expected ) {
if ( current_test.expected != current_test.results.length ) {
current_test.results.push([ false, 'Expected '+current_test.expected+' assertions, but '+current_test.results.length+' were run' ]);
}
}
}
}
function pad ( s, l ) {
s = l + s;
return s.substr( s.length - l.length, l.length );
}
// ------------
// -- runner --
// ------------
var test_script = files.map(function ( fn ) {
try {
return fs.readFileSync( fn );
}
catch ( err ) {
console.log('Critical failure: Cannot load ' + fn );
process.exit(1);
}
}).join('\n;\n');
console.log('');
// time it...
console.time('Tests total time');
// run the tests
Script.runInNewContext( test_script, sandbox );
// reports
var total_ok = 0, total_fail = 0, total_tests = 0;
for (var t=0,tl=tests.length; t<tl; t++) {
var test = tests[t];
var report = [];
var ok = 0, fail = 0;
for (var r=0,rl=test.results.length; r<rl; r++) {
var res = test.results[r];
if ( res[0] ) {
ok++;
total_ok++;
}
else {
fail++;
total_fail++;
}
report.push( ' ' + pad(r,' ') + '. ' + (res[0]?'':'[FAIL]: ') + res[1] );
}
total_tests += test.results.length;
console.log( '' + pad(t,' ') + '. ' + test.name + ' ('+fail+', '+ok+', '+(test.results.length)+')' );
if ( fail ) {
console.log( report.join('\n') );
console.log('');
}
}
console.log('');
console.timeEnd('Tests total time');
console.log(total_ok+' tests of '+total_tests+' passed, '+total_fail+' failed');
File diff suppressed because it is too large Load Diff
-18
View File
@@ -1,18 +0,0 @@
{
"name": "dateutil",
"version": "0.1.0",
"author": "Borgar Þorsteinsson <borgar@borgar.net> (http://borgar.net/)",
"description": "A date parsing and formatting library. Complete ISO 8061 date/time parsing support including quarters and years. Full PHP style date formatting.",
"repository": {
"type": "git",
"url": "git://github.com/borgar/dateutil.git"
},
"main": "./dateutil.js",
"engines": {
"node": "*"
},
"tags": [ "date", "time", "format", "PHP", "parse", "ISO 8601" ],
"bugs": {
"url": "https://github.com/borgar/dateutil/issues"
}
}
-20
View File
@@ -1,20 +0,0 @@
{
"name": "webapp",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"dateutil": "^0.1.0"
}
},
"node_modules/dateutil": {
"version": "0.1.0",
"resolved": "https://registry.npmmirror.com/dateutil/-/dateutil-0.1.0.tgz",
"integrity": "sha512-bI8Lm50mageQER89AvYr+bAxXn4MCAkjSg3M58QY2evrIypUk2aCQcMZ86f31tjmt2ceMrPkrHkhItYqOJsObw==",
"engines": {
"node": "*"
}
}
}
}
-5
View File
@@ -1,5 +0,0 @@
{
"dependencies": {
"dateutil": "^0.1.0"
}
}
-24
View File
@@ -1,24 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
-5
View File
@@ -1,5 +0,0 @@
# Vue 3 + TypeScript + Vite
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
-13
View File
@@ -1,13 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-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>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
File diff suppressed because it is too large Load Diff
-26
View File
@@ -1,26 +0,0 @@
{
"name": "vite-project",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"ant-design-vue": "^4.2.6",
"axios": "^1.11.0",
"konva": "^9.3.22",
"querystring": "^0.2.1",
"vue": "^3.5.17",
"vue-konva": "^3.2.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.0",
"@vue/tsconfig": "^0.7.0",
"typescript": "~5.8.3",
"vite": "^7.0.4",
"vue-tsc": "^2.2.12"
}
}
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

-55
View File
@@ -1,55 +0,0 @@
<script setup lang="ts">
import { ref } from 'vue';
import index from './components/check/index.vue'
import manage from './pages/manage.vue'
const selectedKeys1 = ref (['1']);
let activeItem = ref(1);
const handleSelectd= (e: any) => {
console.log('click ', e);
activeItem.value = e.key;
};
</script>
<template>
<a-layout class="container">
<a-layout-header class="header">
<div class="logo" />
<a-menu
v-model:selectedKeys="selectedKeys1"
theme="dark"
mode="horizontal"
:style="{ lineHeight: '64px' }"
@select="handleSelectd"
>
<a-menu-item key="1">发票查验</a-menu-item>
<a-menu-item key="2">发票管理</a-menu-item>
<a-menu-item key="3">发票复验</a-menu-item>
<a-menu-item key="4">发票统计</a-menu-item>
</a-menu>
</a-layout-header>
<a-layout-content style="padding: 0 10px">
<a-layout style="padding: 24px 0; background: #fff">
<index v-if="activeItem == 1" />
<manage v-if="activeItem == 2" />
</a-layout>
</a-layout-content>
</a-layout>
</template>
<style scoped>
#components-layout-demo-top-side .logo {
float: left;
height: 31px;
margin: 16px 24px 16px 0;
background: rgba(255, 255, 255, 0.3);
}
.ant-row-rtl #components-layout-demo-top-side .logo {
float: right;
margin: 16px 0 16px 24px;
}
.container {
height: 100%;
}
</style>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

Before

Width:  |  Height:  |  Size: 496 B

@@ -1,161 +0,0 @@
<template>
<a-layout-content>
<a-row >
<a-col :mx="15" :sm="24">
<!-- <v-stage v-if="fileType === 'img'" :config="stageConfig">-->
<!-- <v-layer>-->
<!--&lt;!&ndash; <v-image :config="{image: image,x:0,y:0}" />&ndash;&gt;-->
<!-- <v-shape :config="{x: 100, y: 100, width: 100, height: 100, fill: 'red'}" />-->
<!-- </v-layer>-->
<!-- </v-stage>-->
<img v-if="fileType === 'img'" :src="fileUrl" alt="" class="pdf" />
<iframe v-if="fileType==='pdf'" :src="fileUrl" class="pdf">
</iframe>
</a-col>
<a-col :mx="8" :sm="24">
<a-form
:model="formState"
name="basic"
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
autocomplete="off"
@finish="onFinish"
@finishFailed="onFinishFailed"
>
<a-form-item label="发票类型">
<a-input v-model:value="formState.invoiceType" />
</a-form-item>
<a-form-item label="发票号码">
<a-input v-model:value="formState.invoiceNumber" />
</a-form-item>
<a-form-item label="开票日期">
<a-input v-model:value="formState.invoiceDate" />
</a-form-item>
<a-form-item label="不含税金额">
<a-input v-model:value="formState.invoiceAmountPreTax" />
</a-form-item>
<a-form-item label="税额">
<a-input v-model:value="formState.invoiceTax" />
</a-form-item>
<a-form-item label="价税合计">
<a-input v-model:value="formState.totalAmount" />
</a-form-item>
<a-form-item label="销方名称">
<a-input v-model:value="formState.sellerName" />
</a-form-item>
<a-form-item label="销方税号">
<a-input v-model:value="formState.sellerTaxNumber" />
</a-form-item>
<a-form-item label="购方名称">
<a-input v-model:value="formState.purchaserName" />
</a-form-item>
<a-form-item label="购方税号">
<a-input v-model:value="formState.purchaserTaxNumber" />
</a-form-item>
<a-form-item label="发票代码">
<a-input v-model:value="formState.invoiceCode" />
</a-form-item>
<!-- <a-form-item >-->
<!-- <a-row>-->
<!-- <a-col :span="12" offset="24">-->
<!-- <a-space>-->
<!-- <a-button type="primary" html-type="submit">识别发票</a-button>-->
<!-- </a-space>-->
<!-- </a-col>-->
<!-- </a-row>-->
<!-- </a-form-item>-->
</a-form>
</a-col>
</a-row>
</a-layout-content>
</template>
<script lang="ts" setup>
import {ref,onMounted } from 'vue';
import request from "../../utils/request.ts";
import {baseURL} from "../../utils/baseurl.ts";
export type FormState = {
"invoiceCode": string,//发票代码
"invoiceNumber": string,//发票号码
"invoiceDate": string,//开票日期
"purchaserName": string,//购方名称
"purchaserTaxNumber": string,//购方税号
"invoiceAmountPreTax": number,//不含税金额
"invoiceTax": number,//税额
"totalAmount": number,//价税合计
"sellerName": string,//销方名称
"sellerTaxNumber": string,//销方税号
"sellerContactInfo": string,//销方联系方式
"sellerBankAccountInfo": string,
"drawer": string,//开票人
"remarks": string,//备注
"title": string,//标题
"invoiceType": string,//发票类型
"specialTag": string,//特殊标记
"invoiceDetails": [{
"itemName": string,//项目名称
"amount": number,//金额
"taxRate": number,//税率
"tax": number//税额
}]
}
const props = defineProps({ filePath: String,formState: String,});
const emit= defineEmits(['update:formState'])
const fileType = ref<string>('img')
onMounted(() => {
// alert(props.filePath)
if(props.filePath){
fileType.value = props.filePath.split('.').pop() ==='pdf'?'pdf':'img'
request.get('/recognize?filePath='+encodeURIComponent(props.filePath)).then((res) => {
console.log(res.data)
formState.value = res.data
emit('update:formState', JSON.stringify(res.data))
})
fileUrl.value = baseURL+"/"+props.filePath
}
})
//
const fileUrl = ref('')
let formState = ref<FormState>({
drawer: "",
invoiceAmountPreTax: 0,
invoiceCode: "",
invoiceDate: "",
invoiceDetails: [{amount: 0, itemName: "", tax: 0, taxRate: 0}],
invoiceNumber: "",
invoiceTax: 0,
invoiceType: "",
purchaserName: "",
purchaserTaxNumber: "",
remarks: "",
sellerBankAccountInfo: "",
sellerContactInfo: "",
sellerName: "",
sellerTaxNumber: "",
specialTag: "",
title: "",
totalAmount: 0
});
const onFinish = (values: any) => {
console.log('Success:', values);
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
</script>
<style scoped>
.pdf{
width: 100%;
height: 100%;
}
</style>
@@ -1,75 +0,0 @@
<script setup lang="ts">
import {h, ref} from 'vue';
import {
UploadOutlined,
FileDoneOutlined,
FileProtectOutlined,
// SmileOutlined,
} from '@ant-design/icons-vue'
import type {StepProps} from "ant-design-vue"
import Check from './Check.vue'
import upload from './upload.vue'
import Report from "./report.vue"
// 步骤
const items = [
{
title: '上传发票',
icon: h(UploadOutlined),
},
{
title: '识别发票',
icon: h(FileDoneOutlined),
},
{
title: '验证发票',
icon: h(FileProtectOutlined),
},
] as StepProps[];
// 文件路径
const filePath = ref('');
const current = ref<number>(0);
// 下一步
const nextPage = () => {
current.value ++;
};
// 上一步
const previousPage = () => {
current.value--;
};
// 保存
const saveReport = () => {
current.value = 0
}
// 表单数据
const formState = ref<string>('');
</script>
<template>
<a-steps :current="current" :items="items"></a-steps>
<a-layout>
<a-layout-content class="container">
<upload v-if="current == 0" v-model:filePath="filePath" />
<Check v-if="current == 1" v-model:filePath="filePath" v-model:formState="formState"/>
<report v-if="current == 2" v-model:filePath="filePath" v-model:formState="formState" />
</a-layout-content>
<a-layout-footer>
<a-row>
<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 " :disabled="!filePath" @click="nextPage">下一步</a-button>
<a-button type="dashed" v-if="current == items.length-1" @click="saveReport">完成</a-button>
</a-space>
</a-col>
</a-row>
</a-layout-footer>
</a-layout>
</template>
<style scoped>
.ant-steps{
padding: 0 20px 20px 20px;
}
</style>
@@ -1,52 +0,0 @@
<template>
<a-layout-content>
<a-spin v-if="loadding">
</a-spin>
<a-result
:status="formState.status"
:title="formState.cyjgxx"
>
<template #subTitle >
<p v-if="formState.status === 'success'">查验次数: {{formState.inspectionAmount}}</p>
<p v-if="formState.status === 'success'">已存入发票库</p>
</template>
</a-result>
</a-layout-content>
</template>
<script lang="ts" setup>
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)
if(props.filePath){
fileType.value = props.filePath.split('.').pop() ==='pdf'?'pdf':'img'
request.get('/verify?filePath='+encodeURIComponent(props.filePath)).then((res) => {
console.log(res)
formState.value = res.data
loadding.value = false
})
fileUrl.value = baseURL+"/"+props.filePath
}
})
//
const fileUrl = ref('')
let formState = ref({
status:"",
inspectionAmount: "",
cyjgxx: "",
verify_time: "",
});
</script>
<style scoped>
.pdf{
width: 100%;
height: 100%;
}
</style>
@@ -1,80 +0,0 @@
<script setup lang="ts">
import type { UploadProps} from "ant-design-vue";
import {ref} from "vue";
import {
UploadOutlined
} from '@ant-design/icons-vue';
import {baseURL} from "../../utils/baseurl.ts";
const fileList1 = ref<UploadProps['fileList']>([]);
const props = defineProps({ filePath: String });
const emit= defineEmits(['update:filePath'])
const handleRemove = (file: UploadProps['fileList']) => {
console.log( file)
return false;
};
console.log(props.filePath)
const handleUpload = (options: any) => {
const { file, onSuccess, onError, onProgress } = options;
// 创建 FormData 对象
const formData = new FormData();
formData.append('file', file);
// 使用 XMLHttpRequest 进行上传
const xhr = new XMLHttpRequest();
// 监听上传进度
xhr.upload.onprogress = (event) => {
if (event.lengthComputable) {
onProgress({ percent: (event.loaded / event.total) * 100 }, file);
}
};
// 上传成功回调
xhr.onload = () => {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
onSuccess(xhr.responseText, file);
let res = JSON.parse(xhr.responseText)
emit('update:filePath', res.file_path)
} else {
onError(new Error(`Upload failed with status ${xhr.status}`));
}
};
// 上传错误回调
xhr.onerror = () => {
onError(new Error('Network error'));
};
// 发送请求到服务器
xhr.open('POST', baseURL+'/upload');
xhr.send(formData);
};
</script>
<template>
<a-layout-content class="container">
<a-upload
v-model:file-list="fileList1"
:customRequest="handleUpload"
list-type="picture"
class="upload-list-inline"
:max-count="1"
@remove="handleRemove"
>
<a-button>
<upload-outlined></upload-outlined>
上传发票
</a-button>
</a-upload>
</a-layout-content>
</template>
<style scoped>
.container {
margin-top: 50px;
height: 100%;
}
</style>
-11
View File
@@ -1,11 +0,0 @@
import { createApp } from 'vue'
import Antd from 'ant-design-vue';
import './style.css'
import App from './App.vue'
import 'ant-design-vue/dist/reset.css';
import VueKonva from 'vue-konva';
const app = createApp(App)
app.use(Antd);
app.use(VueKonva);
app.mount('#app')
-360
View File
@@ -1,360 +0,0 @@
<script setup lang="ts">
import {h, onMounted, ref} from "vue";
import {
SearchOutlined,
FileSearchOutlined,
PlusOutlined
} from '@ant-design/icons-vue'
import request from '../utils/request.ts';
import {baseURL} from "../utils/baseurl.ts";
import type {TableProps, UploadChangeParam, UploadProps} from "ant-design-vue";
import { message } from 'ant-design-vue';
import zhCN from 'ant-design-vue/es/locale/zh_CN';
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import type {UploadFile} from "ant-design-vue/es/upload/interface";
import type {Key} from "ant-design-vue/es/_util/type";
const [messageApi, contextHolder] = message.useMessage();
interface DataType {
id: string;
status: string;
desc: string;
desc_list: string;
}
const columns = [
// {
// title: '全选',
// dataIndex: 'status',
// key: 'status',
// showSelection: true,
// },
{
title: '发票号码',
dataIndex: 'invoiceNumber',
key: 'invoiceNumber',
// showSelection: true,
},
{
title: '销方名称',
dataIndex: 'sellerName',
key: 'sellerName',
},
{
title: '销方税号',
dataIndex: 'sellerTaxNumber',
key: 'sellerTaxNumber',
},
{
title: '不含税金额',
dataIndex: 'invoiceAmountPreTax',
key: 'invoiceAmountPreTax',
},
{
title: '税额',
dataIndex: 'invoiceTax',
key: 'invoiceTax',
},
{
title: '价税合计',
dataIndex: 'totalAmount',
key: 'totalAmount',
},
{
title: '开票日期',
dataIndex: 'invoiceDate',
key: 'invoiceDate',
},
{
title: '查验结果',
dataIndex: 'verify_status',
key: 'verify_status',
},
{
title: '查验次数',
dataIndex: 'inspectionAmount',
key: 'inspectionAmount',
},
{
title: '查验时间',
dataIndex: 'verify_time',
key: 'verify_time',
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
}
]
// 数据
let data = ref( [])
let searchParams = ref({
page: 1,
pageSize: 100,
total: 0,
params: {
verify_status: 'success',
value: null,
verify_time: null,
}
});
// 下拉框
const rowSelection: TableProps['rowSelection'] = {
onChange: (selectedRowKeys: Key[], selectedRows: DataType[]) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
},
getCheckboxProps: (record: DataType) => ({
disabled: record.status === 'yes', // Column configuration not to be checked
name: record.status,
}),
};
// 弹窗
const openModal = ref(false);
const modalTitle = ref('')
const confirmLoading = ref(false);
const formData = ref({
id: '',
status: false,
desc: '',
desc_files: '',
fileIds: new Array<String>(),
});
const handleOk = () => {
confirmLoading.value = true;
request.post("/updateInvoice", {
invoiceId: formData.value.id,
status: formData.value.status?'yes':'no',
desc: formData.value.desc,
desc_files: formData.value.fileIds?.join(','),
}).then(( res ) => {
if(res.status == 200){
openModal.value = false;
confirmLoading.value = false;
messageApi.success("修改成功")
getList();//刷新
}
})
};
const handleOpen = (record:any) => {
if (record.status === 'yes') {
modalTitle.value = "备注"
}else {
modalTitle.value = "入账"
}
formData.value = Object.assign({}, record);
formData.value.status = (record.status === 'yes')
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++) {
fileList.value.push({
uid: paths[i],
name: paths[i].split("/")[2],
url: baseURL+"/"+paths[i],
});
}
}
openModal.value = true;
};
// 数据列表
const getList = () => {
request.post("/listInvoice", {
verify_status : searchParams.value.params.verify_status,
value : searchParams.value.params.value,
verify_time : searchParams.value.params.verify_time,
}).then(( res ) => {
console.log(res)
data.value = res.data
})
}
const fileList = ref<UploadProps['fileList']>([])
const previewVisible = ref(false);
const previewImage = ref('');
const previewTitle = ref('');
function getBase64(file: File) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}
//
const handleCancelPreview = () => {
previewVisible.value = false;
previewTitle.value = '';
};
const handlePreview = async (file: any) => {
if (!file.url && !file.preview) {
file.preview = (await getBase64(file.originFileObj)) as string;
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
};
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)
}
}
const handleFileRemove = (file: UploadFile ) => {
let index = formData.value.fileIds.indexOf(file.uid)
formData.value.fileIds.splice(index, 1);
}
const handleUpload = (options: any) => {
const { file, onSuccess, onError, onProgress } = options;
// 创建 FormData 对象
const formData1 = new FormData();
formData1.append('file', file);
// 使用 XMLHttpRequest 进行上传
const xhr = new XMLHttpRequest();
// 监听上传进度
xhr.upload.onprogress = (event) => {
if (event.lengthComputable) {
onProgress({ percent: (event.loaded / event.total) * 100 }, file);
}
};
// 上传成功回调
xhr.onload = () => {
if (xhr.status === 200 || xhr.status === 201) {
console.log(xhr.responseText);
onSuccess(xhr.responseText, file);
let res = JSON.parse(xhr.responseText)
if(formData.value.desc_files){
formData.value.desc_files += ",";
}else{
formData.value.desc_files = ""
}
formData.value.desc_files += res.file_path;
} else {
onError(new Error(`Upload failed with status ${xhr.status}`));
}
};
// 上传错误回调
xhr.onerror = () => {
onError(new Error('Network error'));
};
// 发送请求到服务器
xhr.open('POST', baseURL+'/upload');
xhr.send(formData1);
};
dayjs.locale('zh-cn')
onMounted(() => {
getList()
})
</script>
<template>
<div class="table-operations">
<a-row :gutter="20" >
<a-col :span="22" :align="'end'" offset="2">
<a-form v-model:value="searchParams" layout="inline">
<a-form-item label="验证时间">
<a-range-picker
v-model:value="searchParams.params.verify_time"
valueFormat="YYYY-MM-DD HH:mm:ss"
:locale="zhCN.DatePicker"
></a-range-picker>
</a-form-item>
<a-form-item label="关键字">
<a-input v-model:value="searchParams.params.value" allow-clear></a-input>
</a-form-item>
<a-form-item label="验证结果">
<a-radio-group v-model:value="searchParams.params.verify_status">
<a-radio-button value="success">正常</a-radio-button>
<a-radio-button value="faild">异常</a-radio-button>
<a-radio-button value="all">全部</a-radio-button>
</a-radio-group>
</a-form-item>
<a-form-item>
<a-button type="primary" :icon="h(SearchOutlined)" @click="getList">搜索</a-button>
</a-form-item>
</a-form>
</a-col>
</a-row>
</div>
<a-table :columns="columns" :data-source="data" :row-selection="rowSelection" rowKey="id" >
<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 v-if="column.key === 'action'" >
<a-button type="primary" v-if="record.status ==='yes'" @click="handleOpen(record)">备注</a-button>
<a-button type="primary" v-if="record.status ==='no'" @click="handleOpen(record)">报销</a-button>
</template>
</template>
<template #expandedRowRender="{ record }">
<a-row >
<a-col :span="8">
<a-image-preview-group v-if="record.desc_files">
<a-image :width="200" v-for="file in record.desc_files.split(',')" :src="baseURL+'/'+file"/>
</a-image-preview-group>
</a-col>
<a-col :span="16">
<a-typography-title :level="4" >备注</a-typography-title>
<a-typography-paragraph>
<blockquote>{{ record.desc }}</blockquote>
</a-typography-paragraph>
</a-col>
</a-row>
</template>
<template #expandColumnTitle>
<FileSearchOutlined />
</template>
</a-table>
<a-modal v-model:open="openModal" :title="modalTitle" :confirm-loading="confirmLoading" @ok="handleOk">
<a-form v-model:value="formData" >
<a-form-item label="是否已报销">
<a-switch v-model:checked="formData.status"></a-switch>
</a-form-item>
<a-form-item label="备注">
<a-textarea v-model:value="formData.desc" :rows="6"></a-textarea>
</a-form-item>
<a-form-item label="附件">
<div class="clearfix">
<a-upload
v-model:file-list="fileList"
:customRequest="handleUpload"
@change="handleFileChange"
@remove="handleFileRemove"
list-type="picture-card"
@preview="handlePreview"
>
<div>
<PlusOutlined />
<div style="margin-top: 8px">上传</div>
</div>
</a-upload>
<a-modal :open="previewVisible" :title="previewTitle" :footer="null" @cancel="handleCancelPreview">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
</a-form-item>
</a-form>
</a-modal>
<context-holder />
</template>
<style scoped>
.table-operations {
margin-bottom: 16px;
text-align: right;
}
.table-operations > button {
margin-right: 8px;
}
</style>
-11
View File
@@ -1,11 +0,0 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped>
</style>
-81
View File
@@ -1,81 +0,0 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
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: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
/*max-width: 1280px;*/
width: 100%;
height: 100%;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
-2
View File
@@ -1,2 +0,0 @@
// export const baseURL = "http://127.0.0.1:5555"
export const baseURL = "http://101.200.148.149:8555"
-12
View File
@@ -1,12 +0,0 @@
/* request.ts 这里博主用的是 TypeScript */
// 引入 Axios 库的功能,AxiosInstance 是 Axios 中自带的接口类型
import axios, {type AxiosInstance} from 'axios';
import {baseURL} from "./baseurl.ts";
const service: AxiosInstance = axios.create({
baseURL: baseURL,
timeout: 50000,
});
// 导出 axios 实例
export default service;
-1
View File
@@ -1 +0,0 @@
/// <reference types="vite/client" />
-15
View File
@@ -1,15 +0,0 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}
-7
View File
@@ -1,7 +0,0 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
-25
View File
@@ -1,25 +0,0 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}
-26
View File
@@ -1,26 +0,0 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vite.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
host: '0.0.0.0',
port: 5173,
proxy: {
'/api/': {
changeOrigin: true,
}
}
},
resolve: {
alias: {
'#': '/src'
}
},
build: {
outDir: '../../alibabacloud_sample/templates',
emptyOutDir: true,
},
})