to test
This commit is contained in:
6
.flaskenv
Normal file
6
.flaskenv
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
FLASK_APP=inventory_check_lark
|
||||||
|
FLASK_ENV=development
|
||||||
|
SECRET_KEY=asdASS3434dfE5tgfg
|
||||||
|
LARK_APP_ID=cli_a7359bac85b9d01c
|
||||||
|
LARK_APP_SECRECT=vZdiNrSiszH9ODD2qzuI1fHRupOwY5wY
|
||||||
|
LARK_TB_TOKEN=EciWbKOEXa68HIsnh5Ac7vZgnff
|
@ -1,2 +1,8 @@
|
|||||||
# inventory_check_lark
|
# inventory_check
|
||||||
|
|
||||||
|
|
||||||
|
Flask
|
||||||
|
gunicorn
|
||||||
|
python-dotenv
|
||||||
|
lark-oapi
|
||||||
|
Flask-SQLAlchemy
|
18
inventory_check_lark/__init__.py
Normal file
18
inventory_check_lark/__init__.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
:author: luffmims
|
||||||
|
:url: http://yum2.cc
|
||||||
|
:copyright: © 2025 luffmims <luffmims@hotmaill.com>
|
||||||
|
:license: MIT, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
from flask import Flask
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
|
application = Flask('inventory_check_lark')
|
||||||
|
application.config.from_pyfile('settings.py')
|
||||||
|
application.jinja_env.trim_blocks = True
|
||||||
|
application.jinja_env.lstrip_blocks = True
|
||||||
|
|
||||||
|
db = SQLAlchemy(application)
|
||||||
|
|
||||||
|
from inventory_check_lark import views, errors, commands
|
19
inventory_check_lark/commands.py
Normal file
19
inventory_check_lark/commands.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
:author: luffmims
|
||||||
|
:url: http://yum2.cc
|
||||||
|
:copyright: © 2025 luffmims <luffmims@hotmaill.com>
|
||||||
|
:license: MIT, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
import click
|
||||||
|
|
||||||
|
from inventory_check_lark import application
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@application.cli.command()
|
||||||
|
@click.option('--drop', is_flag=True, help='Create after drop.')
|
||||||
|
def initdb(drop):
|
||||||
|
"""Initialize the database."""
|
||||||
|
click.echo('Initialized database.')
|
||||||
|
|
20
inventory_check_lark/errors.py
Normal file
20
inventory_check_lark/errors.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
:author: luffmims
|
||||||
|
:url: http://yum2.cc
|
||||||
|
:copyright: © 2025 luffmims <luffmims@hotmaill.com>
|
||||||
|
:license: MIT, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
from flask import render_template
|
||||||
|
|
||||||
|
from inventory_check_lark import application
|
||||||
|
|
||||||
|
|
||||||
|
@application.errorhandler(404)
|
||||||
|
def page_not_found(e):
|
||||||
|
return render_template('errors/404.html'), 404
|
||||||
|
|
||||||
|
|
||||||
|
@application.errorhandler(500)
|
||||||
|
def internal_server_error(e):
|
||||||
|
return render_template('errors/500.html'), 500
|
211
inventory_check_lark/models.py
Normal file
211
inventory_check_lark/models.py
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
:author: luffmims
|
||||||
|
:url: http://yum2.cc
|
||||||
|
:copyright: © 2025 luffmims <luffmims@hotmaill.com>
|
||||||
|
:license: MIT, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# from datetime import datetime
|
||||||
|
from inventory_check_lark import application, db
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import lark_oapi as lark
|
||||||
|
from lark_oapi.api.auth.v3 import *
|
||||||
|
from lark_oapi.api.bitable.v1 import *
|
||||||
|
|
||||||
|
class Inventory(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
tag = db.Column(db.Text)
|
||||||
|
amount = db.Column(db.Integer)
|
||||||
|
checked = db.Column(db.Boolean, default=False)
|
||||||
|
recordid = db.Column(db.Text)
|
||||||
|
tableid = db.Column(db.Text)
|
||||||
|
# lasttime = db.Column(db.DateTime, default=datetime.now())
|
||||||
|
|
||||||
|
client = lark.Client.builder() \
|
||||||
|
.app_id(application.config['LARK_APP_ID']) \
|
||||||
|
.app_secret(application.config['LARK_APP_SECRECT']) \
|
||||||
|
.log_level(lark.LogLevel.DEBUG) \
|
||||||
|
.build()
|
||||||
|
|
||||||
|
TIMER = time.time()
|
||||||
|
def get_access_token():
|
||||||
|
# 构造请求对象
|
||||||
|
request: InternalAppAccessTokenRequest = InternalAppAccessTokenRequest.builder() \
|
||||||
|
.request_body(InternalAppAccessTokenRequestBody.builder()
|
||||||
|
.app_id(application.config['LARK_APP_ID'])
|
||||||
|
.app_secret(application.config['LARK_APP_SECRECT'])
|
||||||
|
.build()) \
|
||||||
|
.build()
|
||||||
|
|
||||||
|
# 发起请求
|
||||||
|
response: InternalAppAccessTokenResponse = client.auth.v3.app_access_token.internal(request)
|
||||||
|
|
||||||
|
# 处理失败返回
|
||||||
|
# if not response.success():
|
||||||
|
# lark.logger.error(
|
||||||
|
# f"client.auth.v3.app_access_token.internal failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
|
||||||
|
# return
|
||||||
|
if not response.success():
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
# # 处理业务结果
|
||||||
|
# res = eval(response.raw.content)
|
||||||
|
# return {"access_token": res["tenant_access_token"], "expire": res["expire"], "code": res["code"]}
|
||||||
|
|
||||||
|
def get_table_record(id, page_token=None):
|
||||||
|
global TIMER
|
||||||
|
if time.time() - TIMER > 7000:
|
||||||
|
get_access_token()
|
||||||
|
TIMER = time.time()
|
||||||
|
# 构造请求对象
|
||||||
|
if page_token:
|
||||||
|
request: SearchAppTableRecordRequest = SearchAppTableRecordRequest.builder() \
|
||||||
|
.app_token(application.config['LARK_TB_TOKEN']) \
|
||||||
|
.table_id(id['table_id']) \
|
||||||
|
.page_token(page_token) \
|
||||||
|
.page_size(50) \
|
||||||
|
.request_body(SearchAppTableRecordRequestBody.builder()
|
||||||
|
.view_id(id['view_id'])
|
||||||
|
.field_names(["规格", "外库数量", "排序", "已盘"])
|
||||||
|
.sort([Sort.builder()
|
||||||
|
.field_name("排序")
|
||||||
|
.desc(False)
|
||||||
|
.build()
|
||||||
|
])
|
||||||
|
.automatic_fields(True)
|
||||||
|
.build()) \
|
||||||
|
.build()
|
||||||
|
else:
|
||||||
|
request: SearchAppTableRecordRequest = SearchAppTableRecordRequest.builder() \
|
||||||
|
.app_token(application.config['LARK_TB_TOKEN']) \
|
||||||
|
.table_id(id['table_id']) \
|
||||||
|
.page_size(50) \
|
||||||
|
.request_body(SearchAppTableRecordRequestBody.builder()
|
||||||
|
.view_id(id['view_id'])
|
||||||
|
.field_names(["规格", "外库数量", "排序", "已盘"])
|
||||||
|
.sort([Sort.builder()
|
||||||
|
.field_name("排序")
|
||||||
|
.desc(False)
|
||||||
|
.build()
|
||||||
|
])
|
||||||
|
.automatic_fields(True)
|
||||||
|
.build()) \
|
||||||
|
.build()
|
||||||
|
|
||||||
|
# 发起请求
|
||||||
|
response: SearchAppTableRecordResponse = client.bitable.v1.app_table_record.search(request)
|
||||||
|
|
||||||
|
# 处理失败返回
|
||||||
|
if not response.success():
|
||||||
|
lark.logger.error(
|
||||||
|
f"client.bitable.v1.app_table_record.search failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
|
||||||
|
return
|
||||||
|
rep = json.loads(response.raw.content)
|
||||||
|
res = []
|
||||||
|
page_token = None
|
||||||
|
if rep['data']['has_more']:
|
||||||
|
page_token = rep['data']['page_token']
|
||||||
|
for i in rep['data']['items']:
|
||||||
|
if '已盘' in i['fields']:
|
||||||
|
cd = i['fields']['已盘']
|
||||||
|
else:
|
||||||
|
cd = False
|
||||||
|
res.append({
|
||||||
|
"sort": int(i['fields']['排序']),
|
||||||
|
"tag": i['fields']['规格'][0]['text'],
|
||||||
|
"amount": int(i['fields']['外库数量']) if '外库数量' in i['fields'] else 0,
|
||||||
|
"checked": cd,
|
||||||
|
"recordid": i['record_id'],
|
||||||
|
})
|
||||||
|
|
||||||
|
return res, page_token
|
||||||
|
|
||||||
|
def update_record(id, recordid, amount):
|
||||||
|
global TIMER
|
||||||
|
if time.time() - TIMER > 200:
|
||||||
|
get_access_token()
|
||||||
|
TIMER = time.time()
|
||||||
|
# 构造请求对象
|
||||||
|
request: UpdateAppTableRecordRequest = UpdateAppTableRecordRequest.builder() \
|
||||||
|
.app_token(application.config['LARK_TB_TOKEN']) \
|
||||||
|
.table_id(id['table_id']) \
|
||||||
|
.record_id(recordid) \
|
||||||
|
.request_body(AppTableRecord.builder()
|
||||||
|
.fields({"已盘":True,"外库数量":amount})
|
||||||
|
.build()) \
|
||||||
|
.build()
|
||||||
|
|
||||||
|
# 发起请求
|
||||||
|
response: UpdateAppTableRecordResponse = client.bitable.v1.app_table_record.update(request)
|
||||||
|
|
||||||
|
# 处理失败返回
|
||||||
|
# if not response.success():
|
||||||
|
# lark.logger.error(
|
||||||
|
# f"client.bitable.v1.app_table_record.update failed, code: {response.code}, msg: {response.msg}, log_id: {response.get_log_id()}, resp: \n{json.dumps(json.loads(response.raw.content), indent=4, ensure_ascii=False)}")
|
||||||
|
# return
|
||||||
|
if not response.success():
|
||||||
|
return False
|
||||||
|
# 处理业务结果
|
||||||
|
# lark.logger.info(lark.JSON.marshal(response.raw.content, indent=4))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def init_db():
|
||||||
|
get_access_token()
|
||||||
|
with application.app_context():
|
||||||
|
db.drop_all()
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
|
youxin, page_token= get_table_record(application.config['YOUXIN_ID'])
|
||||||
|
for i in youxin:
|
||||||
|
inv = Inventory()
|
||||||
|
inv.id = i['sort']
|
||||||
|
inv.tag = i['tag']
|
||||||
|
inv.amount = i['amount']
|
||||||
|
inv.checked = i['checked']
|
||||||
|
inv.recordid = i['recordid']
|
||||||
|
inv.tableid = application.config['YOUXIN_ID']
|
||||||
|
db.session.add(inv)
|
||||||
|
while page_token:
|
||||||
|
youxin, page_token = get_table_record(application.config['YOUXIN_ID'], page_token)
|
||||||
|
if not youxin:
|
||||||
|
break
|
||||||
|
for i in youxin:
|
||||||
|
inv = Inventory()
|
||||||
|
inv.id = i['sort']
|
||||||
|
inv.tag = i['tag']
|
||||||
|
inv.amount = i['amount']
|
||||||
|
inv.checked = i['checked']
|
||||||
|
inv.recordid = i['recordid']
|
||||||
|
inv.tableid = application.config['YOUXIN_ID']
|
||||||
|
db.session.add(inv)
|
||||||
|
|
||||||
|
waimo, page_token= get_table_record(application.config['WAIMO_ID'])
|
||||||
|
for i in waimo:
|
||||||
|
inv = Inventory()
|
||||||
|
inv.id = i['sort']
|
||||||
|
inv.tag = i['tag']
|
||||||
|
inv.amount = i['amount']
|
||||||
|
inv.checked = i['checked']
|
||||||
|
inv.recordid = i['recordid']
|
||||||
|
inv.tableid = application.config['WAIMO_ID']
|
||||||
|
db.session.add(inv)
|
||||||
|
while page_token:
|
||||||
|
waimo, page_token = get_table_record(application.config['WAIMO_ID'], page_token)
|
||||||
|
if not waimo:
|
||||||
|
break
|
||||||
|
for i in waimo:
|
||||||
|
inv = Inventory()
|
||||||
|
inv.id = i['sort']
|
||||||
|
inv.tag = i['tag']
|
||||||
|
inv.amount = i['amount']
|
||||||
|
inv.checked = i['checked']
|
||||||
|
inv.recordid = i['recordid']
|
||||||
|
inv.tableid = application.config['WAIMO_ID']
|
||||||
|
db.session.add(inv)
|
||||||
|
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return True
|
||||||
|
|
45
inventory_check_lark/settings.py
Normal file
45
inventory_check_lark/settings.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
:author: luffmims
|
||||||
|
:url: http://yum2.cc
|
||||||
|
:copyright: © 2025 luffmims <luffmims@hotmaill.com>
|
||||||
|
:license: MIT, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from inventory_check_lark import application
|
||||||
|
|
||||||
|
# sqlite URI compatible
|
||||||
|
WIN = sys.platform.startswith('win')
|
||||||
|
if WIN:
|
||||||
|
prefix = 'sqlite:///'
|
||||||
|
else:
|
||||||
|
prefix = 'sqlite:////'
|
||||||
|
|
||||||
|
dev_db = prefix + os.path.join(os.path.dirname(application.root_path), 'data.db')
|
||||||
|
|
||||||
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URI', dev_db)
|
||||||
|
SECRET_KEY = os.getenv('SECRET_KEY', 'secret string')
|
||||||
|
|
||||||
|
application.config['LARK_APP_ID'] = os.getenv('LARK_APP_ID', 'lark_app_id')
|
||||||
|
application.config['LARK_APP_SECRECT'] = os.getenv('LARK_APP_SECRECT', 'lark_app_secrect')
|
||||||
|
application.config['LARK_TB_TOKEN'] = os.getenv('LARK_TB_TOKEN', 'lark_app_secrect')
|
||||||
|
|
||||||
|
application.config['WAIMO_ID'] = {
|
||||||
|
'table_id': 'tbluSufkcQm0noBz',
|
||||||
|
'view_id': 'vewLYvBFns',
|
||||||
|
'tag_id': 'fld2xdCqrs',
|
||||||
|
'amount_id': 'fldC9cnnAY',
|
||||||
|
'checked_id': 'fldJkHhQgQ'
|
||||||
|
}
|
||||||
|
|
||||||
|
application.config['YOUXIN_ID'] = {
|
||||||
|
'table_id': 'tbl9NPZQMl5IVHQ2',
|
||||||
|
'view_id': 'vewrOuK32q',
|
||||||
|
'tag_id': 'fldrxqL8uz',
|
||||||
|
'amount_id': 'fldsOIpOBk',
|
||||||
|
'checked_id': 'fldsuS6SuR'
|
||||||
|
}
|
||||||
|
|
39
inventory_check_lark/static/css/style.css
Normal file
39
inventory_check_lark/static/css/style.css
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
body {
|
||||||
|
background-color: azure;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
width: 4ch;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
width: 350px;
|
||||||
|
height: 3px;
|
||||||
|
}
|
||||||
|
.grail{
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.handler {
|
||||||
|
width: 350px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: space-between;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
button, input {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
form {
|
||||||
|
width:350px;
|
||||||
|
}
|
BIN
inventory_check_lark/static/favicon.ico
Normal file
BIN
inventory_check_lark/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 894 B |
51
inventory_check_lark/static/js/script.js
Normal file
51
inventory_check_lark/static/js/script.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
function increment() {
|
||||||
|
var amount = document.getElementById("inventory-amount");
|
||||||
|
amount.value = parseInt(amount.value) + 1;
|
||||||
|
}
|
||||||
|
function decrement() {
|
||||||
|
var amount = document.getElementById("inventory-amount");
|
||||||
|
if (amount.value > 0) {
|
||||||
|
amount.value = parseInt(amount.value) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function checknext() {
|
||||||
|
var amount = document.getElementById("inventory-amount");
|
||||||
|
// 获取ID为"forid"的元素
|
||||||
|
var idelement = document.getElementById("inventory-id");
|
||||||
|
// 获取该元素的文本内容,并解析为整数
|
||||||
|
var id = parseInt(idelement.innerText, 10); // 第二个参数10表示解析的基数,这里是十进制
|
||||||
|
var tagelement = document.getElementById("inventory-tag");
|
||||||
|
var tag = tagelement.innerText;
|
||||||
|
var msg = document.getElementById("flash-msg");
|
||||||
|
var location = document.getElementById("inventory-location");
|
||||||
|
// var params = new URLSearchParams({
|
||||||
|
// checked: 1,
|
||||||
|
// id: id,
|
||||||
|
// amount: amount.value
|
||||||
|
// });
|
||||||
|
// var url = `/check?${params.toString()}`;
|
||||||
|
fetch('/get_inventory', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({id: id, amount: amount.value})
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
// console.log('Success:', data);
|
||||||
|
amount.value = data.amount;
|
||||||
|
tagelement.innerText = data.tag;
|
||||||
|
idelement.innerText = data.id;
|
||||||
|
msg.innerText = data.checkedone + " 盘点数 " + data.checkedamount;
|
||||||
|
location.innerText = data.location;
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error:', error));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function backtoroot(msg="已完成,返回") {
|
||||||
|
alert(msg);
|
||||||
|
location.href="/";
|
||||||
|
}
|
16
inventory_check_lark/templates/after.html
Normal file
16
inventory_check_lark/templates/after.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>盘库助手</title>
|
||||||
|
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/script.js') }}"></script>
|
||||||
|
<script>
|
||||||
|
backtoroot( "{{ msg }}" );
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
28
inventory_check_lark/templates/base.html
Normal file
28
inventory_check_lark/templates/base.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>盘库助手</title>
|
||||||
|
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="grail">
|
||||||
|
<header>
|
||||||
|
<h1>盘点 </h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
<footer>
|
||||||
|
{% block footer %}
|
||||||
|
<small> 2025 © SDHLMH
|
||||||
|
</small>
|
||||||
|
{% endblock %}
|
||||||
|
</footer>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/script.js') }}"></script>
|
||||||
|
{% block scripts %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
27
inventory_check_lark/templates/check.html
Normal file
27
inventory_check_lark/templates/check.html
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="flash-msg">
|
||||||
|
开始盘点>>>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="handler">
|
||||||
|
<a href="/"><button type="button">返回</button></a>
|
||||||
|
<div id="inventory-location"></div><div><p id="inventory-id" hidden>{{ inventory.id }}</p></div>
|
||||||
|
</div>
|
||||||
|
<h1 id="inventory-tag">{{ inventory.tag }}</h1>
|
||||||
|
<hr>
|
||||||
|
<div class="handler">
|
||||||
|
<button onclick="decrement()" type="button">减一</button>
|
||||||
|
<input type="number" id="inventory-amount" value="{{ inventory.amount }}" min="0">
|
||||||
|
<button onclick="increment()" type="button">加一</button>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="handler">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<button onclick="checknext()" type="button">确认,下一个</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
11
inventory_check_lark/templates/errors/404.html
Normal file
11
inventory_check_lark/templates/errors/404.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}404 Error{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<p class="text-center">Page Not Found</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block footer %}
|
||||||
|
<a href="{{ url_for('index') }}">← Go Back</a>
|
||||||
|
{% endblock %}
|
11
inventory_check_lark/templates/errors/500.html
Normal file
11
inventory_check_lark/templates/errors/500.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}500 Error{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<p class="text-center">Internal Server Error</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block footer %}
|
||||||
|
<a href="{{ url_for('index') }}">← Go Back</a>
|
||||||
|
{% endblock %}
|
16
inventory_check_lark/templates/index.html
Normal file
16
inventory_check_lark/templates/index.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<form method=get action="/init">
|
||||||
|
<input style="width:150px;" type=submit value=初始化>
|
||||||
|
</form>
|
||||||
|
<form method=get action="/check">
|
||||||
|
<input style="width:150px;" type=submit value=继续盘点>
|
||||||
|
</form>
|
||||||
|
<!-- <form method=get action="/download-xlsx">
|
||||||
|
<input style="width:150px;" type=submit value=下载XLSX>
|
||||||
|
</form> -->
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
17
inventory_check_lark/templates/init.html
Normal file
17
inventory_check_lark/templates/init.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}上传Excel文件{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>初始化</h1>
|
||||||
|
<div class="handler">
|
||||||
|
<a href="/"><button type="button">返回</button></a>
|
||||||
|
<div></div><div></div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<form method=post enctype=multipart/form-data action="/import">
|
||||||
|
<div>初始化是从多维表格获取数据,修改多维表格后务必运行,花费约1-5分钟,请耐心等待</div>
|
||||||
|
<div class="handler"><div></div><input style="width:100px;"type=submit value=初始化></div>
|
||||||
|
</form>
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
76
inventory_check_lark/views.py
Normal file
76
inventory_check_lark/views.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
:author: luffmims
|
||||||
|
:url: http://yum2.cc
|
||||||
|
:copyright: © 2025 luffmims <luffmims@hotmaill.com>
|
||||||
|
:license: MIT, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from flask import jsonify, request, render_template
|
||||||
|
from inventory_check_lark import application, db
|
||||||
|
from inventory_check_lark.models import init_db, get_access_token, get_table_record, update_record, Inventory
|
||||||
|
from werkzeug.exceptions import BadRequest
|
||||||
|
|
||||||
|
@application.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
@application.route('/init')
|
||||||
|
def init():
|
||||||
|
return 'ok' if init_db() else 'error'
|
||||||
|
|
||||||
|
@application.route('/check', methods=['GET'])
|
||||||
|
def check():
|
||||||
|
inventory = Inventory.query.filter_by(checked=False).first()
|
||||||
|
if not inventory:
|
||||||
|
return render_template('after.html',msg="未初始化或已盘完")
|
||||||
|
return render_template('check.html',inventory=inventory)
|
||||||
|
|
||||||
|
@application.route('/get_youxin_inventory', methods=['POST'])
|
||||||
|
def update_youxin_inventory():
|
||||||
|
try:
|
||||||
|
# 获取并验证表单数据
|
||||||
|
data = request.get_json()
|
||||||
|
inventory_id = data['id']
|
||||||
|
amount = data['amount']
|
||||||
|
|
||||||
|
if not inventory_id or not amount:
|
||||||
|
raise BadRequest('Missing inventory id or amount')
|
||||||
|
|
||||||
|
# 查询并更新库存对象
|
||||||
|
inventory = Inventory.query.get(inventory_id)
|
||||||
|
if not inventory:
|
||||||
|
raise BadRequest('Inventory not found')
|
||||||
|
checkedone = inventory.tag
|
||||||
|
inventory.amount = amount
|
||||||
|
inventory.checked = True
|
||||||
|
update_record(inventory.tableid, inventory.recordid, amount)
|
||||||
|
|
||||||
|
# 提交更改
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
# 显示成功消息
|
||||||
|
# flash(f'{inventory.tag} checked and updated')
|
||||||
|
id = inventory_id + 1
|
||||||
|
inventory = Inventory.query.get(id)
|
||||||
|
if not inventory:
|
||||||
|
raise BadRequest('Inventory not found')
|
||||||
|
# 返回更新后的库存信息
|
||||||
|
return jsonify({
|
||||||
|
'id': inventory.id,
|
||||||
|
'tag': inventory.tag,
|
||||||
|
'amount': inventory.amount,
|
||||||
|
'checkedone': checkedone,
|
||||||
|
'checkedamount': amount
|
||||||
|
})
|
||||||
|
|
||||||
|
except BadRequest as e:
|
||||||
|
# 处理错误情况
|
||||||
|
# flash(str(e))
|
||||||
|
return jsonify({'error': str(e)}), 400
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# 处理其他可能的错误
|
||||||
|
db.session.rollback()
|
||||||
|
# flash('An error occurred while updating the inventory')
|
||||||
|
return jsonify({'error': 'Internal server error'}), 500
|
Reference in New Issue
Block a user