Compare commits
16 Commits
330f8d3b8c
...
main
Author | SHA1 | Date | |
---|---|---|---|
d514e82e9b | |||
0c602a8ccd | |||
559af65260 | |||
7e5eaa82e3 | |||
b1c336e43c | |||
1f2c23c157 | |||
b88b78a946 | |||
d0faf8b8b2 | |||
d663087c41 | |||
6d01222ce4 | |||
d2965c64e1 | |||
232c7da723 | |||
446210ea4c | |||
cf301559de | |||
78d13ece36 | |||
57ade9911d |
@@ -18,7 +18,6 @@ class Inventory(db.Model):
|
|||||||
tag = db.Column(db.Text)
|
tag = db.Column(db.Text)
|
||||||
amount = db.Column(db.Integer)
|
amount = db.Column(db.Integer)
|
||||||
checked = db.Column(db.Boolean, default=False)
|
checked = db.Column(db.Boolean, default=False)
|
||||||
name = db.Column(db.Text)
|
|
||||||
# mtime = db.Column(db.Date)
|
# mtime = db.Column(db.Date)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,3 +1,6 @@
|
|||||||
|
body {
|
||||||
|
background-color: azure;
|
||||||
|
}
|
||||||
main {
|
main {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 894 B |
@@ -16,8 +16,8 @@ function checknext() {
|
|||||||
var id = parseInt(idelement.innerText, 10); // 第二个参数10表示解析的基数,这里是十进制
|
var id = parseInt(idelement.innerText, 10); // 第二个参数10表示解析的基数,这里是十进制
|
||||||
var tagelement = document.getElementById("inventory-tag");
|
var tagelement = document.getElementById("inventory-tag");
|
||||||
var tag = tagelement.innerText;
|
var tag = tagelement.innerText;
|
||||||
var name = "A"
|
|
||||||
var msg = document.getElementById("flash-msg");
|
var msg = document.getElementById("flash-msg");
|
||||||
|
var location = document.getElementById("inventory-location");
|
||||||
// var params = new URLSearchParams({
|
// var params = new URLSearchParams({
|
||||||
// checked: 1,
|
// checked: 1,
|
||||||
// id: id,
|
// id: id,
|
||||||
@@ -29,7 +29,7 @@ function checknext() {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({id: id, amount: amount.value, name: name})
|
body: JSON.stringify({id: id, amount: amount.value})
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
@@ -38,57 +38,14 @@ function checknext() {
|
|||||||
tagelement.innerText = data.tag;
|
tagelement.innerText = data.tag;
|
||||||
idelement.innerText = data.id;
|
idelement.innerText = data.id;
|
||||||
msg.innerText = data.checkedone + " 盘点数 " + data.checkedamount;
|
msg.innerText = data.checkedone + " 盘点数 " + data.checkedamount;
|
||||||
|
location.innerText = data.location;
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(error => console.error('Error:', error));
|
.catch(error => console.error('Error:', error));
|
||||||
|
|
||||||
}
|
}
|
||||||
// function apiAuth() {
|
|
||||||
// if (!window.h5sdk) {
|
|
||||||
// alert("请在飞书客户端中打开");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// window.h5sdk.ready(() => {
|
function backtoroot(msg="已完成,返回") {
|
||||||
// tt.requestAccess({
|
alert(msg);
|
||||||
// appID: "your_app_id",
|
location.href="/";
|
||||||
// scopeList: [],
|
}
|
||||||
// success(res) {
|
|
||||||
// // 将 code 发送到服务端
|
|
||||||
// fetch(`/callback?code=${res.code}`)
|
|
||||||
// .then(response => response.json())
|
|
||||||
// .then(data => {
|
|
||||||
// console.log("用户信息:", data);
|
|
||||||
// // 在页面上展示用户姓名
|
|
||||||
// document.getElementById("username").innerText = data.name;
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// fail(err) {
|
|
||||||
// console.error("获取授权码失败:", err);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// apiAuth();
|
|
||||||
|
|
||||||
function apiAuth() {
|
|
||||||
tt.requestAccess({
|
|
||||||
appID: "cli_a70da4f71bf1d00c",
|
|
||||||
scopeList: [],
|
|
||||||
success(res) {
|
|
||||||
// 将 code 发送到服务端
|
|
||||||
fetch(`/callback?code=${res.code}`)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
// console.log("用户信息:", data);
|
|
||||||
// 在页面上展示用户姓名
|
|
||||||
document.getElementById("username").innerText = data.name;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
fail(err) {
|
|
||||||
console.error("获取授权码失败:", err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
apiAuth();
|
|
16
inventory_check/templates/after.html
Normal file
16
inventory_check/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>
|
@@ -16,14 +16,13 @@
|
|||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
<footer>
|
<footer>
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
<small id="username"> luff
|
<small> 2025 © SDHLMH
|
||||||
</small>
|
</small>
|
||||||
<!-- <p><a id="bottom" href="#" title="Go Top">↑</a></p> -->
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</footer>
|
</footer>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script type="text/javascript" src="{{ url_for('static', filename='js/script.js') }}"></script>
|
<script type="text/javascript" src="{{ url_for('static', filename='js/script.js') }}"></script>
|
||||||
|
{% block scripts %}{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@@ -7,7 +7,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="handler">
|
<div class="handler">
|
||||||
<a href="/"><button type="button">返回</button></a>
|
<a href="/"><button type="button">返回</button></a>
|
||||||
<div></div><div><p id="inventory-id" hidden>{{ inventory.id }}</p></div>
|
<div id="inventory-location"></div><div><p id="inventory-id" hidden>{{ inventory.id }}</p></div>
|
||||||
</div>
|
</div>
|
||||||
<h1 id="inventory-tag">{{ inventory.tag }}</h1>
|
<h1 id="inventory-tag">{{ inventory.tag }}</h1>
|
||||||
<hr>
|
<hr>
|
||||||
|
@@ -5,9 +5,6 @@
|
|||||||
<form method=get action="/upload">
|
<form method=get action="/upload">
|
||||||
<input style="width:150px;" type=submit value=上传XLSX>
|
<input style="width:150px;" type=submit value=上传XLSX>
|
||||||
</form>
|
</form>
|
||||||
<form method=get action="/list">
|
|
||||||
<input style="width:150px;" type=submit value=显示列表>
|
|
||||||
</form>
|
|
||||||
<form method=get action="/check">
|
<form method=get action="/check">
|
||||||
<input style="width:150px;" type=submit value=继续盘点>
|
<input style="width:150px;" type=submit value=继续盘点>
|
||||||
</form>
|
</form>
|
||||||
|
@@ -1,62 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div id="flash-msg">
|
|
||||||
开始盘点>>>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<div class="handler">
|
|
||||||
<a href="/"><button type="button">返回</button></a>
|
|
||||||
<div></div><div><p id="inventory-id" hidden>0</p></div>
|
|
||||||
</div>
|
|
||||||
<div class="handler">
|
|
||||||
<button onclick="previousPage()" type="button">上页</button>
|
|
||||||
<div></div>
|
|
||||||
<button onclick="nextPage()" type="button">下页</button>
|
|
||||||
</div>
|
|
||||||
<table style="width:100%">
|
|
||||||
<tr>
|
|
||||||
<th>标签</th>
|
|
||||||
<th>数量</th>
|
|
||||||
<th>已盘</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td id="tag1">一月</td>
|
|
||||||
<td id="amount1">¥3400</td>
|
|
||||||
<td id="checked1">¥3400</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td id="tag2">一月</td>
|
|
||||||
<td id="amount2">¥3400</td>
|
|
||||||
<td id="checked2">¥3400</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td id="tag3">一月</td>
|
|
||||||
<td id="amount3">¥3400</td>
|
|
||||||
<td id="checked3">¥3400</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td id="tag4">一月</td>
|
|
||||||
<td id="amount4">¥3400</td>
|
|
||||||
<td id="checked4">¥3400</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td id="tag5">一月</td>
|
|
||||||
<td id="amount5">¥3400</td>
|
|
||||||
<td id="checked5">¥3400</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td id="tag6">一月</td>
|
|
||||||
<td id="amount6">¥3400</td>
|
|
||||||
<td id="checked6">¥3400</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="handler">
|
|
||||||
<button onclick="previousPage()" type="button">上页</button>
|
|
||||||
<div></div>
|
|
||||||
<button onclick="nextPage()" type="button">下页</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@@ -3,11 +3,13 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>上传Excel XLSX文件</h1>
|
<h1>上传Excel XLSX文件</h1>
|
||||||
<form method=get action="/">
|
<div class="handler">
|
||||||
<input style="width:150px;" type=submit value=返回>
|
<a href="/"><button type="button">返回</button></a>
|
||||||
</form>
|
<div></div><div></div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
<form method=post enctype=multipart/form-data action="/import">
|
<form method=post enctype=multipart/form-data action="/import">
|
||||||
<div><input style="width:300px;" type=file name=选择></div>
|
<div><input style="width:300px;" type=file name=file></div>
|
||||||
<div class="handler"><div></div><input style="width:100px;"type=submit value=上传></div>
|
<div class="handler"><div></div><input style="width:100px;"type=submit value=上传></div>
|
||||||
</form>
|
</form>
|
||||||
<div>
|
<div>
|
||||||
|
@@ -5,8 +5,9 @@
|
|||||||
:copyright: © 2025 luffmims <luffmims@hotmaill.com>
|
:copyright: © 2025 luffmims <luffmims@hotmaill.com>
|
||||||
:license: MIT, see LICENSE for more details.
|
:license: MIT, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
import time
|
||||||
from flask import jsonify, redirect, request, url_for, render_template, send_file
|
from flask import jsonify, redirect, request, url_for, render_template, send_file
|
||||||
from flask import make_response, session
|
from flask import make_response
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from openpyxl import Workbook
|
from openpyxl import Workbook
|
||||||
from inventory_check import app, db
|
from inventory_check import app, db
|
||||||
@@ -17,16 +18,11 @@ from werkzeug.exceptions import BadRequest
|
|||||||
def index():
|
def index():
|
||||||
return render_template('index.html')
|
return render_template('index.html')
|
||||||
|
|
||||||
@app.route('/list')
|
|
||||||
def list():
|
|
||||||
return render_template('list.html')
|
|
||||||
|
|
||||||
@app.route('/check', methods=['GET'])
|
@app.route('/check', methods=['GET'])
|
||||||
def check():
|
def check():
|
||||||
inventory = Inventory.query.filter_by(checked=False).first()
|
inventory = Inventory.query.filter_by(checked=False).first()
|
||||||
print(inventory)
|
|
||||||
if not inventory:
|
if not inventory:
|
||||||
return "All checked"
|
return render_template('after.html',msg="未导入或已盘完")
|
||||||
return render_template('check.html',inventory=inventory)
|
return render_template('check.html',inventory=inventory)
|
||||||
|
|
||||||
@app.route('/get_inventory', methods=['POST'])
|
@app.route('/get_inventory', methods=['POST'])
|
||||||
@@ -36,7 +32,6 @@ def update_inventory():
|
|||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
inventory_id = data['id']
|
inventory_id = data['id']
|
||||||
amount = data['amount']
|
amount = data['amount']
|
||||||
name = data['name']
|
|
||||||
|
|
||||||
if not inventory_id or not amount:
|
if not inventory_id or not amount:
|
||||||
raise BadRequest('Missing inventory id or amount')
|
raise BadRequest('Missing inventory id or amount')
|
||||||
@@ -47,7 +42,6 @@ def update_inventory():
|
|||||||
raise BadRequest('Inventory not found')
|
raise BadRequest('Inventory not found')
|
||||||
checkedone = inventory.tag
|
checkedone = inventory.tag
|
||||||
inventory.amount = amount
|
inventory.amount = amount
|
||||||
inventory.name = name
|
|
||||||
inventory.checked = True
|
inventory.checked = True
|
||||||
|
|
||||||
# 提交更改
|
# 提交更改
|
||||||
@@ -63,6 +57,7 @@ def update_inventory():
|
|||||||
return jsonify({
|
return jsonify({
|
||||||
'id': inventory.id,
|
'id': inventory.id,
|
||||||
'tag': inventory.tag,
|
'tag': inventory.tag,
|
||||||
|
'location': inventory.location,
|
||||||
'amount': inventory.amount,
|
'amount': inventory.amount,
|
||||||
'checkedone': checkedone,
|
'checkedone': checkedone,
|
||||||
'checkedamount': amount
|
'checkedamount': amount
|
||||||
@@ -94,7 +89,7 @@ def import_file():
|
|||||||
file_path = 'data.xlsx'
|
file_path = 'data.xlsx'
|
||||||
file.save(file_path)
|
file.save(file_path)
|
||||||
import_from_xlsx(file_path)
|
import_from_xlsx(file_path)
|
||||||
return '文件导入成功! <a href="/">返回</a>'
|
return render_template('after.html',msg="成功")
|
||||||
|
|
||||||
return redirect(url_for('upload_form'))
|
return redirect(url_for('upload_form'))
|
||||||
|
|
||||||
@@ -102,6 +97,7 @@ def import_file():
|
|||||||
|
|
||||||
@app.route('/download-xlsx')
|
@app.route('/download-xlsx')
|
||||||
def download_xlsx():
|
def download_xlsx():
|
||||||
|
filename = "PD-" + time.strftime("%Y%m%d", time.localtime()) + ".xlsx"
|
||||||
# 创建一个 Excel 工作簿
|
# 创建一个 Excel 工作簿
|
||||||
inventorys = Inventory.query.all() # 查询所有数据, and sort data by sort
|
inventorys = Inventory.query.all() # 查询所有数据, and sort data by sort
|
||||||
# 创建一个工作簿
|
# 创建一个工作簿
|
||||||
@@ -111,65 +107,16 @@ def download_xlsx():
|
|||||||
# 设置工作表名称
|
# 设置工作表名称
|
||||||
ws.title = "Inventory"
|
ws.title = "Inventory"
|
||||||
# 设置工作表列名
|
# 设置工作表列名
|
||||||
ws.append(["sort", "location", "tag", "amount", "checked", "name"])
|
ws.append(["序号", "位置", "标签", "数量", "已确认"])
|
||||||
# 写入数据
|
# 写入数据
|
||||||
for inventory in inventorys:
|
for inventory in inventorys:
|
||||||
ws.append([inventory.sort, inventory.location, inventory.tag, inventory.amount, inventory.checked, inventory.name])
|
ws.append([inventory.sort, inventory.location, inventory.tag, inventory.amount, inventory.checked])
|
||||||
|
|
||||||
output = BytesIO()
|
output = BytesIO()
|
||||||
wb.save(output)
|
wb.save(output)
|
||||||
output.seek(0) # 移动到字节流的开头
|
output.seek(0) # 移动到字节流的开头
|
||||||
|
|
||||||
# 设置响应头,提供下载功能
|
# 设置响应头,提供下载功能
|
||||||
response = make_response(send_file(output, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', as_attachment=True, download_name='example.xlsx'))
|
response = make_response(send_file(output, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', as_attachment=True, download_name=filename))
|
||||||
response.headers["Content-Disposition"] = "attachment; filename=example.xlsx"
|
response.headers["Content-Disposition"] = "attachment; filename=" + filename
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# 应用凭证信息
|
|
||||||
APP_ID = "cli_a70da4f71bf1d00c"
|
|
||||||
APP_SECRET = "4zV9xcunWUE8E4kKS4hw5e3m6pgjoduz"
|
|
||||||
|
|
||||||
# 获取 app_access_token
|
|
||||||
def get_app_access_token():
|
|
||||||
url = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal/"
|
|
||||||
payload = {
|
|
||||||
"app_id": APP_ID,
|
|
||||||
"app_secret": APP_SECRET
|
|
||||||
}
|
|
||||||
response = request.post(url, json=payload)
|
|
||||||
return response.json().get("app_access_token")
|
|
||||||
|
|
||||||
# 获取 user_access_token
|
|
||||||
def get_user_access_token(app_access_token, code):
|
|
||||||
url = "https://open.feishu.cn/open-apis/authen/v1/access_token"
|
|
||||||
headers = {"Authorization": f"Bearer {app_access_token}"}
|
|
||||||
payload = {"grant_type": "authorization_code", "code": code}
|
|
||||||
response = request.post(url, headers=headers, json=payload)
|
|
||||||
return response.json().get("data", {}).get("access_token")
|
|
||||||
|
|
||||||
# 获取用户信息
|
|
||||||
def get_user_info(user_access_token):
|
|
||||||
url = "https://open.feishu.cn/open-apis/authen/v1/user_info"
|
|
||||||
headers = {"Authorization": f"Bearer {user_access_token}"}
|
|
||||||
response = request.get(url, headers=headers)
|
|
||||||
return response.json().get("data")
|
|
||||||
|
|
||||||
@app.route("/callback", methods=["GET"])
|
|
||||||
def callback():
|
|
||||||
code = request.args.get("code")
|
|
||||||
if not code:
|
|
||||||
return jsonify({"error": "Missing code parameter"}), 400
|
|
||||||
|
|
||||||
# 获取 app_access_token
|
|
||||||
app_access_token = get_app_access_token()
|
|
||||||
|
|
||||||
# 获取 user_access_token
|
|
||||||
user_access_token = get_user_access_token(app_access_token, code)
|
|
||||||
|
|
||||||
# 获取用户信息
|
|
||||||
user_info = get_user_info(user_access_token)
|
|
||||||
|
|
||||||
# 存储用户信息到 session
|
|
||||||
session["user_info"] = user_info
|
|
||||||
|
|
||||||
return jsonify(user_info)
|
|
BIN
sheet.xlsx
Normal file
BIN
sheet.xlsx
Normal file
Binary file not shown.
BIN
游芯盘点表.xlsx
BIN
游芯盘点表.xlsx
Binary file not shown.
Reference in New Issue
Block a user