优化项目结构

This commit is contained in:
2025-12-31 19:53:51 +08:00
parent dd78da8403
commit 5d8c3e269d
14 changed files with 337 additions and 202 deletions
+3 -1
View File
@@ -76,4 +76,6 @@ jspm_packages/
.env
test/
*.ipynb
# 忽略project_files文件夹下以_ed为结尾的py文件
project_files/*_ed.py
+5 -7
View File
@@ -12,6 +12,7 @@ MyapsDbActions
import os, importlib
from config.settings import MYAPS_MAIN_DB, TURN_ON_SCHEDULE_TASK
from ..utils.scheduler import cron_task
from apps.io_api.common import dict_to_lower_keys
@@ -28,12 +29,11 @@ except:
#################################################################################
# ⬇️定时任务HOOK
#################################################################################
schedule_task_hour = current_project.DefaultParams.SCHEDULE_TASK_HOUR
schedule_task_minute = current_project.DefaultParams.SCHEDULE_TASK_MINUTE
turn_on_schedule_task = os.getenv('TURN_ON_SCHEDULE_TASK', 'True').lower() == 'true'
schedule_task_hour = "6,8,10,12,14,16"
schedule_task_minute = "55"
if turn_on_schedule_task:
if TURN_ON_SCHEDULE_TASK:
@cron_task(hour=schedule_task_hour, minute=schedule_task_minute)
async def refresh_stock(db_name: str | None = None):
return await current_project.ScheduleTasks.refresh_stock(db_name)
@@ -45,10 +45,8 @@ if turn_on_schedule_task:
#################################################################################
from apps.data_opt.utils.mysqlmonitor import mysql_monitor
main_db = os.getenv('MYAPS_MAIN_DB')
@mysql_monitor.on_update_for_table("t_supply", database=main_db)
@mysql_monitor.on_update_for_table("t_supply", database=MYAPS_MAIN_DB)
async def handle_update_supply(database: str, table: str, data: dict, data_diff: dict):
"""处理t_supply表的更新事件"""
supply_type = data['new']['Type']
+5 -11
View File
@@ -4,21 +4,22 @@
"""
# import threading
import os
# import os
import logging
from typing import Literal
from abc import ABC#, abstractmethod
# from tortoise import Tortoise
from config.settings import MYAPS_MAIN_DB, THIS_SERVER_PORT, THIS_PROTOCOL#, MYAPS_BASE_URL
from config.settings import MYAPS_MAIN_DB, THIS_SERVER_PORT, THIS_PROTOCOL, SCHEDULED_DBS#, MYAPS_BASE_URL
from apps.data_opt.utils.common import get_session
# ❗⬇️不要删掉,便于各项目文件引用
from globalobjects import file_timed_logger
from apps.io_api.common import standard_response
from apps.data_opt.components.hap import HapConnection
from ..utils.scheduler import cron_task
from ..utils.common import add_basic_auth_requests
# 配置日志
@@ -31,7 +32,7 @@ console_log = logging.getLogger(__name__)
class ScheduleTasksAbc(ABC):
this_base_url = f'{THIS_PROTOCOL}localhost:{THIS_SERVER_PORT}'
scheduled_dbs = os.getenv('SCHEDULED_DBS').split(',')
scheduled_dbs = SCHEDULED_DBS
_session = get_session()
@classmethod
@@ -106,13 +107,6 @@ class MyapsDbActionsAbc(ABC):
return response
class DefaultParamsAbc:
SCHEDULE_TASK_HOUR = "6,8,10,12,14,16"
SCHEDULE_TASK_MINUTE = "55"
class DefaultValueAbc:
myaps_is_pro = 1 # 1 / 0 MyAPS是否专业版
+1 -3
View File
@@ -9,7 +9,7 @@ from datetime import datetime
from fastapi import status
from ._base import (
ScheduleTasksAbc, MyapsDbActionsAbc, DefaultValueAbc, DefaultParamsAbc,
ScheduleTasksAbc, MyapsDbActionsAbc, DefaultValueAbc,
file_log, console_log, standard_response, get_session, HapConnection
)
@@ -23,8 +23,6 @@ hap_conn = HapConnection(
sign='...'
)
class DefaultParams(DefaultParamsAbc):
pass
class DefaultValue(DefaultValueAbc):
+70 -86
View File
@@ -1,17 +1,20 @@
"""江阴海达橡塑"""
import requests, logging#, os, atexit
import requests, uuid#, logging#, os, atexit
import pandas as pd
from datetime import datetime
from fastapi import status
from config.settings import MYAPS_MAIN_DB, SCHEDULED_DBS, THIS_BASE_URL, TURN_ON_SCHEDULE_TASK
from ._base import (
ScheduleTasksAbc, MyapsDbActionsAbc, DefaultValueAbc, DefaultParamsAbc,
file_log, console_log, standard_response, get_session, HapConnection
ScheduleTasksAbc, MyapsDbActionsAbc, DefaultValueAbc,
file_log, console_log, standard_response, get_session, HapConnection,
cron_task, add_basic_auth_requests
)
#################################################################################
# ⬇️对象及项目参数
#################################################################################
@@ -22,22 +25,17 @@ hap_conn = HapConnection(
)
class DefaultParams(DefaultParamsAbc):
pass
class DefaultValue(DefaultValueAbc):
MAT_PLANT = "1600" # 默认工厂
MAT_PLANNER = "haida" # 默认计划员
MAT_LOCATION = "1600" # 默认车间
main_db = MyapsDbActionsAbc.main_db
werks = "1600"
#################################################################################
# ⬇️项目可复用逻辑
#################################################################################
from apps.data_opt.utils.common import add_basic_auth_requests
sap_url1 = 'http://192.168.201.2:8000/zrestful_test2?sap-client=800' # 库存
sap_url2 = 'http://192.168.201.2:8000/zrestful_plan?sap-client=800' # 计划
@@ -45,15 +43,9 @@ sap_username = 'T058'
sap_password = '123456'
# 创建requests会话
sap_session = get_session(allowed_methods=["GET", "POST"])
# sap_session2 = get_session(allowed_methods=["GET", "POST"])
# 添加Basic认证
add_basic_auth_requests(sap_session, sap_username, sap_password)
# add_basic_auth_requests(sap_session2, sap_username, sap_password)
# import json
import uuid
# from typing import Dict, Any, Optional
async def sap_post(url: str, session: requests.Session, interface_id: str, data: dict):
@@ -92,76 +84,69 @@ async def sap_post(url: str, session: requests.Session, interface_id: str, data:
#################################################################################
# ⬇️定时任务设置
#################################################################################
class ScheduleTasks(ScheduleTasksAbc):
schedule_task_hour = '6,8,10,12,14,16'
schedule_task_minute = '55'
@classmethod
async def refresh_stock(cls, db_name: str | None = None):
"""
刷新库存,先清空supply中类型为ST的数据,再从ERP同步1600厂全部库存数据
db_name: 账套名称,默认刷新所有账套
"""
console_log.info("开始执行刷新库存任务")
response = None
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
try:
response = sap_session.get(url=f"{sap_url1}", headers={'interface': 'stock', 'werks': werks})
data = response.json()['data']
stock = pd.DataFrame(data)
stock = stock.astype({
'werks': 'str',
'matnr': 'str',
'lgort': 'str',
'labst': 'int32',
'labst2': 'int32',
'charg': 'str'
})
stock['avail_qty'] = stock['labst'] + stock['labst2']
stock['supplyno'] = stock['werks'] + '-' + stock['matnr'] # 注意不要用f string,否则supplyno会变成所有料号的超长字符串
stock['type'] = 'ST'
stock['priority'] = 0
stock['avail_date'] = now
stock['dt_req'] = now
stock['status'] = 'NEW'
stock['category'] = ''
stock['create_date'] = now
stock = (stock
.groupby(['supplyno'], as_index=False)
.agg({
'matnr': 'first',
'avail_qty': 'sum',
'type': 'first',
'avail_date': 'first',
'dt_req': 'first',
'priority': 'first',
'status': 'first',
'category': 'first',
'create_date': 'first',
}))
stock = stock.rename(columns={
'matnr': 'materialno',
})
stock_data = stock.to_dict(orient='records')
dbs = db_name or ','.join(cls.scheduled_dbs)
cls._session.delete(f"{cls.this_base_url}/api/t_supply?db_name={dbs}&type=ST")
cls._session.post(f"{cls.this_base_url}/api/t_supply?db_name={dbs}", json=stock_data)
console_log.info(f"刷新库存任务执行完成,账套:{dbs}")
response = standard_response(message=f"刷新库存任务执行完成,账套:{dbs}")
except Exception as e:
console_log.error(f"刷新库存任务执行失败: {str(e)}")
response = standard_response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, success=0, message=f"刷新库存任务执行失败: {str(e)}")
return response
@classmethod
async def get_bom(cls):
"""
从SAP获取BOM数据
"""
response = sap_session.get(url=sap_url1, headers={'interface': 'bom', 'werks': "1600"})
bom_json_data = response.json()['data']
return bom_json_data
@cron_task(hour=schedule_task_hour, minute=schedule_task_minute)
def refresh_stock(db_name: str | None = None):
"""
刷新库存,先清空supply中类型为ST的数据,再从ERP同步1600厂全部库存数据
db_name: 账套名称,默认刷新所有账套
"""
console_log.info("开始执行刷新库存任务")
response = None
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
try:
response = sap_session.get(url=f"{sap_url1}", headers={'interface': 'stock', 'werks': werks})
data = response.json()['data']
stock = pd.DataFrame(data)
stock = stock.astype({
'werks': 'str',
'matnr': 'str',
'lgort': 'str',
'labst': 'int32',
'labst2': 'int32',
'charg': 'str'
})
stock['avail_qty'] = stock['labst'] + stock['labst2']
stock['supplyno'] = stock['werks'] + '-' + stock['matnr'] # 注意不要用f string,否则supplyno会变成所有料号的超长字符串
stock['type'] = 'ST'
stock['priority'] = 0
stock['avail_date'] = now
stock['dt_req'] = now
stock['status'] = 'NEW'
stock['category'] = ''
stock['create_date'] = now
stock = (stock
.groupby(['supplyno'], as_index=False)
.agg({
'matnr': 'first',
'avail_qty': 'sum',
'type': 'first',
'avail_date': 'first',
'dt_req': 'first',
'priority': 'first',
'status': 'first',
'category': 'first',
'create_date': 'first',
}))
stock = stock.rename(columns={
'matnr': 'materialno',
})
stock_data = stock.to_dict(orient='records')
dbs = db_name or SCHEDULED_DBS
sap_session.delete(f"{THIS_BASE_URL}/api/t_supply?db_name={dbs}&type=ST")
sap_session.post(f"{THIS_BASE_URL}/api/t_supply?db_name={dbs}", json=stock_data)
console_log.info(f"刷新库存任务执行完成,账套:{dbs}")
response = standard_response(message=f"刷新库存任务执行完成,账套:{dbs}")
except Exception as e:
console_log.error(f"刷新库存任务执行失败: {str(e)}")
response = standard_response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, success=0, message=f"刷新库存任务执行失败: {str(e)}")
return response
#################################################################################
# ⬇️数据库事件处理
#################################################################################
@@ -173,7 +158,7 @@ class MyapsDbActions(MyapsDbActionsAbc):
确认计划任务,将主账套中需要转MO的PL推送到SAP,将计划任务状态更新为已确认
"""
try:
supply_response = cls._session.get(f"{cls.this_base_url}/api/v_supply_mo?db_name={main_db}&supplyno={pl_data['supplyno']}")
supply_response = sap_session.get(f"{THIS_BASE_URL}/api/v_supply_mo?db_name={MYAPS_MAIN_DB}&supplyno={pl_data['supplyno']}")
supply_response_json = supply_response.json()
supply_data = supply_response_json['data'][0]
start_datetime = supply_data['dt_ordstart']#.strftime('%Y%m%d %H:%M:%S')
@@ -188,7 +173,6 @@ class MyapsDbActions(MyapsDbActionsAbc):
"GSTRP": start_datetime.split('T')[0], # 基本开始日期
"GLTRP": end_datetime.split('T')[0], # 基本完成日期
"GAMNG": supply_data['avail_qty'], # 总订单数量
# "FEVOR": "SAP", # 生产主管
"WEMPF": "SAP", # 产线代码
"BACKUP1": ','.join([i['workcenter'] for i in orderwc])
}
@@ -200,7 +184,7 @@ class MyapsDbActions(MyapsDbActionsAbc):
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if sap_mo_data['STATUS'] == 'S':
log_msg = f"✅推送计划任务执行成功,账套:{main_db}MO单号:{sap_mo_data['AUFNR']}"
log_msg = f"✅推送计划任务执行成功,账套:{MYAPS_MAIN_DB}MO单号:{sap_mo_data['AUFNR']}"
console_log.info(log_msg)
file_log.info(log_msg)
pl_data['mono'] = sap_mo_data['AUFNR']
@@ -208,7 +192,7 @@ class MyapsDbActions(MyapsDbActionsAbc):
pl_data['memo'] = f'{now} @ERP【{sap_mo_data['MESSAGE']}'
pl_data['is_execute_updates'] = True
else:
log_msg = f"🚫推送计划任务执行失败,账套:{main_db},错误信息:{sap_mo_data['MESSAGE']}"
log_msg = f"🚫推送计划任务执行失败,账套:{MYAPS_MAIN_DB},错误信息:{sap_mo_data['MESSAGE']}"
console_log.error(log_msg)
file_log.error(log_msg)
pl_data['mono'] = ''
+227
View File
@@ -0,0 +1,227 @@
"""江阴海达橡塑"""
import requests#, logging#, os, atexit
import pandas as pd
from datetime import datetime
from fastapi import status
from ._base import (
ScheduleTasksAbc, MyapsDbActionsAbc, DefaultValueAbc,
file_log, console_log, standard_response, get_session, HapConnection
)
#################################################################################
# ⬇️对象及项目参数
#################################################################################
hap_conn = HapConnection(
base_url='https://api.mingdao.com',
app_key='d519a8ea60f9efa6',
sign='NjAwYzI5OWJlMTNhNTcwODM5ZTEwOWE2YjE3ZDZiNWRmYzk4NTJjNTZmODQ4N2EzNGNjNWM2ZGMzNTBlYjY0Ng=='
)
class DefaultValue(DefaultValueAbc):
MAT_PLANT = "1600" # 默认工厂
MAT_PLANNER = "haida" # 默认计划员
MAT_LOCATION = "1600" # 默认车间
main_db = MyapsDbActionsAbc.main_db
werks = "1600"
#################################################################################
# ⬇️项目可复用逻辑
#################################################################################
from apps.data_opt.utils.common import add_basic_auth_requests
sap_url1 = 'http://192.168.201.2:8000/zrestful_test2?sap-client=800' # 库存
sap_url2 = 'http://192.168.201.2:8000/zrestful_plan?sap-client=800' # 计划
sap_username = 'T058'
sap_password = '123456'
# 创建requests会话
sap_session = get_session(allowed_methods=["GET", "POST"])
# sap_session2 = get_session(allowed_methods=["GET", "POST"])
# 添加Basic认证
add_basic_auth_requests(sap_session, sap_username, sap_password)
# add_basic_auth_requests(sap_session2, sap_username, sap_password)
# import json
import uuid
# from typing import Dict, Any, Optional
async def sap_post(url: str, session: requests.Session, interface_id: str, data: dict):
"""
向SAP系统发送POST请求
url: 请求URL
session: requests会话
data: 请求数据
"""
headers = {
"INTF_ID": interface_id,
"SRC_SYSTEM": "APS",
"DEST_SYSTEM": "SAP",
"SRC_MSGID": str(uuid.uuid4()).replace("-", ""),
"BACKUP1": "",
"BACKUP2": ""
}
response: requests.Response = session.post(url, headers=headers, json={
"HEAD": headers,
"BODY": [data]
})
response_json = {}
if response.status_code == status.HTTP_200_OK:
response_json = response.json()
console_log.info(f"POST请求成功,状态码:{response.status_code},响应内容:{response_json}")
else:
console_log.error(f"POST请求失败,状态码:{response.status_code},响应内容:{response.text}")
return {
'status_code': response.status_code,
'response_text': response.text,
'response_json': response_json
}
#################################################################################
# ⬇️定时任务设置
#################################################################################
class ScheduleTasks(ScheduleTasksAbc):
@classmethod
async def refresh_stock(cls, db_name: str | None = None):
"""
刷新库存,先清空supply中类型为ST的数据,再从ERP同步1600厂全部库存数据
db_name: 账套名称,默认刷新所有账套
"""
console_log.info("开始执行刷新库存任务")
response = None
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
try:
response = sap_session.get(url=f"{sap_url1}", headers={'interface': 'stock', 'werks': werks})
data = response.json()['data']
stock = pd.DataFrame(data)
stock = stock.astype({
'werks': 'str',
'matnr': 'str',
'lgort': 'str',
'labst': 'int32',
'labst2': 'int32',
'charg': 'str'
})
stock['avail_qty'] = stock['labst'] + stock['labst2']
stock['supplyno'] = stock['werks'] + '-' + stock['matnr'] # 注意不要用f string,否则supplyno会变成所有料号的超长字符串
stock['type'] = 'ST'
stock['priority'] = 0
stock['avail_date'] = now
stock['dt_req'] = now
stock['status'] = 'NEW'
stock['category'] = ''
stock['create_date'] = now
stock = (stock
.groupby(['supplyno'], as_index=False)
.agg({
'matnr': 'first',
'avail_qty': 'sum',
'type': 'first',
'avail_date': 'first',
'dt_req': 'first',
'priority': 'first',
'status': 'first',
'category': 'first',
'create_date': 'first',
}))
stock = stock.rename(columns={
'matnr': 'materialno',
})
stock_data = stock.to_dict(orient='records')
dbs = db_name or ','.join(cls.scheduled_dbs)
cls._session.delete(f"{cls.this_base_url}/api/t_supply?db_name={dbs}&type=ST")
cls._session.post(f"{cls.this_base_url}/api/t_supply?db_name={dbs}", json=stock_data)
console_log.info(f"刷新库存任务执行完成,账套:{dbs}")
response = standard_response(message=f"刷新库存任务执行完成,账套:{dbs}")
except Exception as e:
console_log.error(f"刷新库存任务执行失败: {str(e)}")
response = standard_response(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, success=0, message=f"刷新库存任务执行失败: {str(e)}")
return response
@classmethod
async def get_bom(cls):
"""
从SAP获取BOM数据
"""
response = sap_session.get(url=sap_url1, headers={'interface': 'bom', 'werks': "1600"})
bom_json_data = response.json()['data']
return bom_json_data
#################################################################################
# ⬇️数据库事件处理
#################################################################################
class MyapsDbActions(MyapsDbActionsAbc):
@classmethod
async def confirm_pl(cls, pl_data: dict):
"""
确认计划任务,将主账套中需要转MO的PL推送到SAP,将计划任务状态更新为已确认
"""
try:
supply_response = cls._session.get(f"{cls.this_base_url}/api/v_supply_mo?db_name={main_db}&supplyno={pl_data['supplyno']}")
supply_response_json = supply_response.json()
supply_data = supply_response_json['data'][0]
start_datetime = supply_data['dt_ordstart']#.strftime('%Y%m%d %H:%M:%S')
end_datetime = supply_data['dt_ordend']#.strftime('%Y%m%d %H:%M:%S')
orderwc = supply_data['orderwc']
data = {
# "CY_SEQNR": supply_data['supplyno'], # APS单号
"WERKS": werks, # 工厂
"MATNR": supply_data['materialno'],
"AUART": "ZP01", # 订单类型
"VERID": "SAP", # 生产版本
"GSTRP": start_datetime.split('T')[0], # 基本开始日期
"GLTRP": end_datetime.split('T')[0], # 基本完成日期
"GAMNG": supply_data['avail_qty'], # 总订单数量
# "FEVOR": "SAP", # 生产主管
"WEMPF": "SAP", # 产线代码
"BACKUP1": ','.join([i['workcenter'] for i in orderwc])
}
# sap_response = await sap_post(url=sap_url2, session=sap_session2, interface_id="ZPP_PLAN_ORD_CREATE", data=data)
sap_response = await sap_post(url=sap_url2, session=sap_session, interface_id="ZPP_PLAN_ORD_CREATE", data=data)
sap_response_json = sap_response['response_json']
sap_mo_data = sap_response_json['BODY'][0]
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if sap_mo_data['STATUS'] == 'S':
log_msg = f"✅推送计划任务执行成功,账套:{main_db}MO单号:{sap_mo_data['AUFNR']}"
console_log.info(log_msg)
file_log.info(log_msg)
pl_data['mono'] = sap_mo_data['AUFNR']
pl_data['status'] = 'E2A'
pl_data['memo'] = f'{now} @ERP【{sap_mo_data['MESSAGE']}'
pl_data['is_execute_updates'] = True
else:
log_msg = f"🚫推送计划任务执行失败,账套:{main_db},错误信息:{sap_mo_data['MESSAGE']}"
console_log.error(log_msg)
file_log.error(log_msg)
pl_data['mono'] = ''
pl_data['status'] = 'CRE' # ❗❗失败情况下,状态务必回撤为 CRE ,否则后续无法再次下达
pl_data['memo'] = f'🚫{now} @ERP【{sap_mo_data['MESSAGE']}'
pl_data['is_execute_updates'] = False
except Exception as e:
log_msg = f"🚫推送计划任务执行失败: {str(e)}"
console_log.error(log_msg)
file_log.error(log_msg)
pl_data['mono'] = ''
pl_data['status'] = 'CRE'
pl_data['memo'] = f'🚫{now} @APS【{str(e)}'
pl_data['is_execute_updates'] = False
await super().confirm_pl(pl_data)
@@ -12,7 +12,7 @@ from datetime import datetime
from fastapi import status
from ._base import (
ScheduleTasksAbc, MyapsDbActionsAbc, DefaultValueAbc, DefaultParamsAbc,
ScheduleTasksAbc, MyapsDbActionsAbc, DefaultValueAbc,
file_log, console_log, standard_response, get_session, HapConnection
)
@@ -26,8 +26,6 @@ hap_conn = HapConnection(
sign='NjAwYzI5OWJlMTNhNTcwODM5ZTEwOWE2YjE3ZDZiNWRmYzk4NTJjNTZmODQ4N2EzNGNjNWM2ZGMzNTBlYjY0Ng=='
)
class DefaultParams(DefaultParamsAbc):
pass
class DefaultValue(DefaultValueAbc):
@@ -16,8 +16,8 @@ from typing import Dict, Optional, Union, Tuple, Any
import qrcode
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.moduledrawers import RoundedModuleDrawer
from qrcode.image.styles.colormasks import SquareGradiantColorMask
from qrcode.image.svg import SvgImage, SvgFragmentImage
# from qrcode.image.styles.colormasks import SquareGradiantColorMask
from qrcode.image.svg import SvgImage#, SvgFragmentImage
import barcode
from barcode.writer import ImageWriter, SVGWriter
from PIL import Image, ImageDraw, ImageFont
+1 -1
View File
@@ -1,4 +1,4 @@
import os, base64, requests, json, ast, re
import base64, requests, json, ast, re#,os,
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
from typing import Optional, Dict, Union
+4 -2
View File
@@ -8,6 +8,8 @@ from apscheduler.executors.pool import ThreadPoolExecutor
from apscheduler.jobstores.memory import MemoryJobStore
from apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_MISSED
from config.settings import TURN_ON_SCHEDULE_TASK
# 配置日志
logging.basicConfig(
level=logging.INFO,
@@ -248,7 +250,7 @@ def weekly_task(day_of_week: str = 'mon', hour: int = 0, minute: int = 0):
def initialize_scheduler():
"""初始化并启动调度器"""
if os.getenv("TURN_ON_SCHEDULE_TASK", "False").lower() == "true":
if TURN_ON_SCHEDULE_TASK:
if scheduler_manager.init_scheduler():
scheduler_manager.start()
atexit.register(scheduler_manager.shutdown)
@@ -268,7 +270,7 @@ def get_scheduler_status() -> Dict:
}
# 应用启动时自动初始化
# if os.getenv("TURN_ON_SCHEDULE_TASK", "False").lower() == "true":
# if TURN_ON_SCHEDULE_TASK:
# # initialize_scheduler()
# # 或者在模块导入后合适的时机调用
# pass
+4 -4
View File
@@ -8,7 +8,7 @@ import functools
from fastapi import APIRouter, Query, Body, status#, Request, Path
# from tortoise import Tortoise
from config import settings
from config.settings import MYAPS_DB_SET, MYAPS_MAIN_DB
from globalobjects import globalconst as gc
from .models import TMaterial, TWorkcenter, TMatWc, TMatVer, TMatWcBom, TSupply, TDemand, TMold, TMatWcMold, TConfirm#,TortoiseBaseModel
from .schemas import (
@@ -144,9 +144,9 @@ async def get_meta():
success=1,
message="获取元数据成功",
meta={
"db_set": settings.MYAPS_DB_SET,
"dbs_str": ",".join(settings.MYAPS_DB_SET),
"main_db": settings.MYAPS_MAIN_DB,
"db_set": MYAPS_DB_SET,
"dbs_str": ",".join(MYAPS_DB_SET),
"main_db": MYAPS_MAIN_DB,
},
)
+5
View File
@@ -18,11 +18,14 @@ MYAPS_DB_USER = os.getenv("MYAPS_DB_USER")
MYAPS_DB_PASSWORD = os.getenv("MYAPS_DB_PASSWORD")
MYAPS_DB_SET = os.getenv("MYAPS_DB_SET").split(",")
MYAPS_MAIN_DB = os.getenv("MYAPS_MAIN_DB")
SCHEDULED_DBS = os.getenv('SCHEDULED_DBS')
TEST_DB = os.getenv("TEST_DB", "testdb")
THIS_PROTOCOL = os.getenv("THIS_PROTOCOL", "http://")
THIS_SERVER_HOST = os.getenv("THIS_SERVER_HOST")
THIS_SERVER_PORT = int(os.getenv("THIS_SERVER_PORT"))
THIS_BASE_URL = f"{THIS_PROTOCOL}localhost:{THIS_SERVER_PORT}"
# 本API数据库配置<postgreSQL>
THIS_DB_HOST = os.getenv("THIS_DB_HOST")
THIS_DB_PORT = int(os.getenv("THIS_DB_PORT"))
@@ -30,6 +33,8 @@ THIS_DB_USER = os.getenv("THIS_DB_USER")
THIS_DB_PASSWORD = os.getenv("THIS_DB_PASSWORD")
THIS_DB_NAME = os.getenv("THIS_DB_NAME")
TURN_ON_SCHEDULE_TASK = os.getenv('TURN_ON_SCHEDULE_TASK', 'true').lower() == 'true'
######################################################################################
# 数据库配置
connections = {}
+2 -2
View File
@@ -8,7 +8,7 @@ from fastapi.responses import JSONResponse
from fastapi.openapi.docs import get_swagger_ui_html
from tortoise.contrib.fastapi import register_tortoise
from config.settings import TORTOISE_ORM_CONFIG, THIS_SERVER_PORT, BASE_DIR
from config.settings import TORTOISE_ORM_CONFIG, THIS_SERVER_PORT, BASE_DIR, TURN_ON_SCHEDULE_TASK
from globalobjects import file_timed_logger
from apps.io_api.routers import rt as io_rt
from apps.io_api.common import register_exception_handlers
@@ -200,7 +200,7 @@ register_tortoise(
)
# 检查是否开启定时任务
if os.getenv("TURN_ON_SCHEDULE_TASK", False).lower() == "true":
if TURN_ON_SCHEDULE_TASK:
# 初始化定时任务管理器
from apps.data_opt.utils.scheduler import initialize_scheduler, get_scheduler_status
initialize_scheduler()
+7 -80
View File
@@ -205,33 +205,13 @@
}
}
/* 本地访问提示样式 */
.local-access-notice {
background-color: #e3f2fd;
border: 1px solid #2196f3;
border-radius: 4px;
padding: 12px;
margin-bottom: 20px;
font-size: 14px;
color: #1976d2;
}
.local-access-notice .icon {
margin-right: 8px;
color: #2196f3;
}
</style>
</head>
<body>
<div class="container">
<h1>数据校验工具</h1>
<!-- 本地访问提示 -->
<div class="local-access-notice" id="localAccessNotice" style="display: none;">
<span class="icon">🏠</span>
<strong>本地访问检测到</strong>:API密钥输入框已自动隐藏,无需输入API密钥即可使用。
</div>
<div class="tab-container">
<div class="tab-nav">
<button class="tab-button active" data-tab="bom">BOM校验</button>
@@ -248,8 +228,8 @@
</div>
<div class="form-group" id="bomApiKeyGroup">
<label for="bomApiKey">API密钥 <span class="required">*</span></label>
<input type="text" id="bomApiKey" placeholder="请输入API密钥" required>
<label for="bomApiKey">API密钥 <span class="optional">(可选)</span></label>
<input type="text" id="bomApiKey" placeholder="本地访问可留空,远程访问请输入API密钥">
</div>
<div class="form-group">
@@ -308,8 +288,8 @@
</div>
<div class="form-group" id="routeApiKeyGroup">
<label for="routeApiKey">API密钥 <span class="required">*</span></label>
<input type="text" id="routeApiKey" placeholder="请输入API密钥" required>
<label for="routeApiKey">API密钥 <span class="optional">(可选)</span></label>
<input type="text" id="routeApiKey" placeholder="本地访问可留空,远程访问请输入API密钥">
</div>
<div class="form-group">
@@ -351,43 +331,8 @@
</div>
<script>
// 检测是否为本地访问
function isLocalAccess() {
const hostname = window.location.hostname;
const protocol = window.location.protocol;
// 本地访问的特征:
// 1. hostname为 localhost 或 127.0.0.1
// 2. hostname以 .local 或 .localhost 结尾
// 3. 私有IP地址范围 (192.168.x.x, 10.x.x.x, 172.16.x.x-172.31.x.x)
return hostname === 'localhost' ||
hostname === '127.0.0.1' ||
hostname.endsWith('.local') ||
hostname.endsWith('.localhost') ||
hostname.startsWith('192.168.') ||
hostname.startsWith('10.') ||
(hostname.startsWith('172.16.') || hostname.startsWith('172.17.') ||
hostname.startsWith('172.18.') || hostname.startsWith('172.19.') ||
hostname.startsWith('172.20.') || hostname.startsWith('172.21.') ||
hostname.startsWith('172.22.') || hostname.startsWith('172.23.') ||
hostname.startsWith('172.24.') || hostname.startsWith('172.25.') ||
hostname.startsWith('172.26.') || hostname.startsWith('172.27.') ||
hostname.startsWith('172.28.') || hostname.startsWith('172.29.') ||
hostname.startsWith('172.30.') || hostname.startsWith('172.31.'));
}
// TAB切换功能
document.addEventListener('DOMContentLoaded', function() {
// 检测本地访问并隐藏API密钥输入框
if (isLocalAccess()) {
// 隐藏API密钥输入框
document.getElementById('bomApiKeyGroup').style.display = 'none';
document.getElementById('routeApiKeyGroup').style.display = 'none';
// 显示本地访问提示
document.getElementById('localAccessNotice').style.display = 'block';
}
const tabButtons = document.querySelectorAll('.tab-button');
const tabContents = document.querySelectorAll('.tab-content');
@@ -452,16 +397,7 @@
return;
}
// 检测是否为本地访问,使用不同的API密钥获取方式
const isLocal = isLocalAccess();
const apiKey = isLocal ? 'local_access' : document.getElementById('bomApiKey').value;
// 如果不是本地访问且没有输入API密钥,则提示输入
if (!isLocal && !apiKey) {
alert('请输入API密钥');
return;
}
const apiKey = document.getElementById('bomApiKey').value || 'local_access';
const parentCol = document.getElementById('bomParentCol').value;
const childCol = document.getElementById('bomChildCol').value;
const numeratorCol = document.getElementById('bomNumeratorCol').value;
@@ -590,16 +526,7 @@
return;
}
// 检测是否为本地访问,使用不同的API密钥获取方式
const isLocal = isLocalAccess();
const apiKey = isLocal ? 'local_access' : document.getElementById('routeApiKey').value;
// 如果不是本地访问且没有输入API密钥,则提示输入
if (!isLocal && !apiKey) {
alert('请输入API密钥');
return;
}
const apiKey = document.getElementById('routeApiKey').value || 'local_access';
const productCol = document.getElementById('routeProductCol').value;
const productVersionCol = document.getElementById('routeProductVersionCol').value;
const sortNoCol = document.getElementById('routeSortNoCol').value;
@@ -684,4 +611,4 @@
}
</script>
</body>
</html>
</html>