Merge pull request #281 feature-NEWDWH2021-1236 into develop
This commit is contained in:
commit
fc23443e0a
1018
ecs/jskult-webapp/Pipfile.lock
generated
1018
ecs/jskult-webapp/Pipfile.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,9 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from starlette import status
|
||||
|
||||
from src.depends.services import get_service
|
||||
from src.logging.get_logger import get_logger
|
||||
from src.model.internal.session import UserSession
|
||||
from src.model.request.bio import BioModel
|
||||
from src.model.view.bio_view_model import BioViewModel
|
||||
from src.router.session_router import AuthenticatedRoute
|
||||
from src.services.batch_status_service import BatchStatusService
|
||||
from src.services.bio_view_service import BioViewService
|
||||
@ -48,34 +44,3 @@ def bio_view(
|
||||
headers={'session_key': session_key}
|
||||
)
|
||||
return templates_response
|
||||
|
||||
|
||||
@router.post('/BioSearchList')
|
||||
def search_bio(
|
||||
request: Request,
|
||||
bio_form: Optional[BioModel] = Depends(BioModel.as_form),
|
||||
bio_service: BioViewService = Depends(get_service(BioViewService)),
|
||||
batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService))
|
||||
):
|
||||
session: UserSession = request.session
|
||||
# バッチ処理中の場合、機能を利用させない
|
||||
if batch_status_service.is_batch_processing():
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=constants.LOGOUT_REASON_BATCH_PROCESSING)
|
||||
|
||||
# 生物由来データを検索
|
||||
bio_sales_view_data = bio_service.search_bio_data(bio_form)
|
||||
# 検索項目などのデータを取得
|
||||
bio: BioViewModel = bio_service.prepare_bio_view(session)
|
||||
bio.bio_data = bio_sales_view_data
|
||||
bio.form_data = bio_form
|
||||
|
||||
# レスポンス
|
||||
session_key = session.session_key
|
||||
templates_response = templates.TemplateResponse(
|
||||
'bioSearchList.html', {
|
||||
'request': request,
|
||||
'bio': bio
|
||||
},
|
||||
headers={'session_key': session_key}
|
||||
)
|
||||
return templates_response
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
"""生物由来ファイルダウンロード APIRoute"""
|
||||
from datetime import datetime
|
||||
from typing import Union
|
||||
"""生物由来照会 APIRoute"""
|
||||
import datetime
|
||||
from typing import Optional, Union
|
||||
|
||||
import pandas as pd
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from fastapi.responses import JSONResponse
|
||||
from starlette import status
|
||||
|
||||
@ -13,6 +14,7 @@ from src.logging.get_logger import get_logger
|
||||
from src.model.internal.session import UserSession
|
||||
from src.model.request.bio import BioModel
|
||||
from src.model.request.bio_download import BioDownloadModel
|
||||
from src.model.view.bio_disp_model import BioDisplayModel
|
||||
from src.services.batch_status_service import BatchStatusService
|
||||
from src.services.bio_view_service import BioViewService
|
||||
from src.services.session_service import set_session
|
||||
@ -27,6 +29,67 @@ router = APIRouter()
|
||||
#########################
|
||||
|
||||
|
||||
@router.post('/search')
|
||||
def search_bio_data(
|
||||
bio_form: Optional[BioModel] = Depends(BioModel.as_form),
|
||||
bio_service: BioViewService = Depends(get_service(BioViewService)),
|
||||
batch_status_service: BatchStatusService = Depends(get_service(BatchStatusService)),
|
||||
session: Union[UserSession, None] = Depends(verify_session)
|
||||
):
|
||||
if session is None:
|
||||
return JSONResponse(content={'status': 'session_expired'}, status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
# バッチ処理中の場合、機能を利用させない
|
||||
if batch_status_service.is_batch_processing():
|
||||
return JSONResponse(content={'status': 'batch_processing'}, status_code=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# 生物由来データと件数を取得
|
||||
bio_sales_lot_data = bio_service.search_bio_data(bio_form)
|
||||
bio_sales_lot_count = bio_service.count_bio_data(bio_form, session)
|
||||
|
||||
# レスポンスデータを加工
|
||||
# 日付型のデータのエンコードエラーを解消するための措置
|
||||
def custom_encode(obj):
|
||||
encoded_obj = obj.model_dump()
|
||||
for key, value in encoded_obj.items():
|
||||
if type(value) == datetime.datetime:
|
||||
encoded_obj[key] = value.strftime("%Y-%m-%d %H:%M:%S") if obj is not None else ''
|
||||
if type(value) == datetime.date:
|
||||
encoded_obj[key] = value.strftime("%Y-%m-%d") if obj is not None else ''
|
||||
return encoded_obj
|
||||
|
||||
data = jsonable_encoder(
|
||||
bio_sales_lot_data,
|
||||
custom_encoder={
|
||||
BioDisplayModel: custom_encode
|
||||
}
|
||||
)
|
||||
|
||||
# セッション書き換え
|
||||
session.update(
|
||||
actions=[
|
||||
UserSession.last_access_time.set(UserSession.new_last_access_time()),
|
||||
UserSession.record_expiration_time.set(UserSession.new_record_expiration_time()),
|
||||
# 検索結果をキャッシュする
|
||||
UserSession.bio_search_condition.set(bio_form.model_dump()),
|
||||
UserSession.bio_search_count.set(bio_sales_lot_count),
|
||||
]
|
||||
)
|
||||
set_session(session)
|
||||
json_response = JSONResponse(content={
|
||||
'data': data,
|
||||
'count': bio_sales_lot_count
|
||||
})
|
||||
# クッキーも書き換え
|
||||
json_response.set_cookie(
|
||||
key='session',
|
||||
value=session.session_key,
|
||||
max_age=environment.SESSION_EXPIRE_MINUTE * 60, # cookieの有効期限は秒数指定なので、60秒をかける
|
||||
secure=True,
|
||||
httponly=True
|
||||
)
|
||||
return json_response
|
||||
|
||||
|
||||
@router.post('/download')
|
||||
async def download_bio_data(
|
||||
search_param: BioModel = Depends(BioModel.as_body),
|
||||
@ -40,7 +103,7 @@ async def download_bio_data(
|
||||
logger.info(f'ユーザーID: {download_param.user_id}')
|
||||
logger.info(f'拡張子: {download_param.ext}')
|
||||
# ファイル名に使用するタイムスタンプを初期化しておく
|
||||
current_timestamp = datetime.now()
|
||||
current_timestamp = datetime.datetime.now()
|
||||
# 出力ファイル名
|
||||
download_file_name = f'Result_{download_param.user_id}_{current_timestamp:%Y%m%d%H%M%S%f}.{download_param.ext}'
|
||||
if session is None:
|
||||
@ -50,7 +113,7 @@ async def download_bio_data(
|
||||
return {'status': 'batch_processing'}
|
||||
# 生物由来データを検索
|
||||
# 検索に使用したクエリも取得
|
||||
search_result_df, query = _search_bio_data(bio_service, search_param, download_param)
|
||||
search_result_df, query = _search_download_bio_data(bio_service, search_param, download_param)
|
||||
# アクセスログを記録
|
||||
bio_service.write_access_log(query, search_param, download_param.user_id, current_timestamp, download_file_name)
|
||||
|
||||
@ -100,7 +163,7 @@ async def download_bio_data(
|
||||
return json_response
|
||||
|
||||
|
||||
def _search_bio_data(
|
||||
def _search_download_bio_data(
|
||||
bio_service: BioViewService,
|
||||
search_param: BioModel,
|
||||
download_param: BioDownloadModel
|
||||
@ -5,7 +5,7 @@ from fastapi.staticfiles import StaticFiles
|
||||
from starlette import status
|
||||
|
||||
import src.static as static
|
||||
from src.controller import (bio, bio_download, healthcheck, login, logout,
|
||||
from src.controller import (bio, bio_api, healthcheck, login, logout,
|
||||
master_mainte, menu, root, ultmarc)
|
||||
from src.core import task
|
||||
from src.error.exception_handler import http_exception_handler
|
||||
@ -27,9 +27,9 @@ app.include_router(menu.router, prefix='/menu')
|
||||
app.include_router(bio.router, prefix='/bio')
|
||||
# アルトマークデータ照会のルーター
|
||||
app.include_router(ultmarc.router, prefix='/ultmarc')
|
||||
# 生物由来のダウンロード用APIルーター。
|
||||
# 生物由来照会のAPIルーター。
|
||||
# クライアントから非同期呼出しされるため、共通ルーターとは異なる扱いとする。
|
||||
app.include_router(bio_download.router, prefix='/bio')
|
||||
app.include_router(bio_api.router, prefix='/bio')
|
||||
# マスタメンテ
|
||||
app.include_router(master_mainte.router, prefix='/masterMainte')
|
||||
# ヘルスチェック用のルーター
|
||||
|
||||
@ -42,3 +42,7 @@ class BioSalesLotDBModel(BaseDBModel):
|
||||
data_kind: Optional[str]
|
||||
err_dtl_kind: Optional[str]
|
||||
expr_dt: Optional[date]
|
||||
|
||||
|
||||
class BioSalesLotCountDBModel(BaseDBModel):
|
||||
count: Optional[int]
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from pynamodb.attributes import NumberAttribute, UnicodeAttribute
|
||||
from pynamodb.attributes import (JSONAttribute, NumberAttribute,
|
||||
UnicodeAttribute)
|
||||
from pynamodb.models import Model as DynamoDBTableModel
|
||||
|
||||
from src.system_var import environment
|
||||
@ -23,6 +24,8 @@ class UserSession(DynamoDBTableModel):
|
||||
csrf_token = UnicodeAttribute()
|
||||
last_access_time = NumberAttribute()
|
||||
record_expiration_time = NumberAttribute()
|
||||
bio_search_condition = JSONAttribute(null=True, default=None)
|
||||
bio_search_count = NumberAttribute(null=True, default=None)
|
||||
|
||||
@classmethod
|
||||
def new_last_access_time(cls):
|
||||
|
||||
@ -21,6 +21,8 @@ class BioModel(BaseModel):
|
||||
rev_hsdnymd_srk_from: Optional[str]
|
||||
rev_hsdnymd_srk_to: Optional[str]
|
||||
iko_flg: Optional[str]
|
||||
pageNumber: Optional[int]
|
||||
pageSize: Optional[int]
|
||||
|
||||
@classmethod
|
||||
def as_form(
|
||||
@ -34,7 +36,9 @@ class BioModel(BaseModel):
|
||||
ctrl_maker_cd: str = Form(None),
|
||||
ctrl_rev_hsdnymd_srk_from: str = Form(None),
|
||||
ctrl_rev_hsdnymd_srk_to: str = Form(None),
|
||||
ikoFlg: str = Form(None)
|
||||
ikoFlg: str = Form(None),
|
||||
pageNumber: int = Form(None),
|
||||
pageSize: int = Form(None)
|
||||
):
|
||||
|
||||
return cls.__convert_request_param(
|
||||
@ -48,7 +52,9 @@ class BioModel(BaseModel):
|
||||
ctrl_maker_cd,
|
||||
ctrl_rev_hsdnymd_srk_from,
|
||||
ctrl_rev_hsdnymd_srk_to,
|
||||
ikoFlg
|
||||
ikoFlg,
|
||||
pageNumber,
|
||||
pageSize
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@ -91,7 +97,9 @@ class BioModel(BaseModel):
|
||||
ctrl_maker_cd: str,
|
||||
ctrl_rev_hsdnymd_srk_from: str,
|
||||
ctrl_rev_hsdnymd_srk_to: str,
|
||||
ikoFlg: str
|
||||
ikoFlg: str,
|
||||
pageNumber: int = None,
|
||||
pageSize: int = None
|
||||
):
|
||||
wholesaler_code = None
|
||||
wholesaler_sub_code = None
|
||||
@ -132,5 +140,7 @@ class BioModel(BaseModel):
|
||||
mkr_cd=ctrl_maker_cd,
|
||||
rev_hsdnymd_srk_from=rev_hsdnymd_srk_from,
|
||||
rev_hsdnymd_srk_to=rev_hsdnymd_srk_to,
|
||||
iko_flg=ikoFlg
|
||||
iko_flg=ikoFlg,
|
||||
pageNumber=pageNumber,
|
||||
pageSize=pageSize
|
||||
)
|
||||
|
||||
@ -3,6 +3,6 @@ from src.util.sanitize import sanitize
|
||||
|
||||
|
||||
@sanitize
|
||||
class BisDisplayModel(BioSalesLotDBModel):
|
||||
class BioDisplayModel(BioSalesLotDBModel):
|
||||
def __init__(self, param: BioSalesLotDBModel) -> None:
|
||||
super().__init__(**param.model_dump())
|
||||
|
||||
@ -1,14 +1,9 @@
|
||||
import json
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from src.model.db.pharmacy_product_master import PharmacyProductMasterModel
|
||||
from src.model.db.wholesaler_master import WholesalerMasterModel
|
||||
from src.model.request.bio import BioModel
|
||||
from src.model.view.bio_disp_model import BisDisplayModel
|
||||
from src.system_var import environment
|
||||
|
||||
|
||||
@ -17,9 +12,8 @@ class BioViewModel(BaseModel):
|
||||
user_id: str
|
||||
whs_models: list[WholesalerMasterModel]
|
||||
phm_models: list[PharmacyProductMasterModel]
|
||||
bio_data: Optional[list[BisDisplayModel]] = None
|
||||
form_data: BioModel = None
|
||||
excel_max_lines: int = str(environment.BIO_EXCEL_RESULT_MAX_COUNT)
|
||||
search_data_max_length: int = environment.BIO_SEARCH_RESULT_MAX_COUNT
|
||||
excel_max_lines: str = str(environment.BIO_EXCEL_RESULT_MAX_COUNT)
|
||||
|
||||
def display_wholesaler_names(self):
|
||||
display_names = [
|
||||
@ -49,114 +43,3 @@ class BioViewModel(BaseModel):
|
||||
'2': '除外'
|
||||
}
|
||||
)
|
||||
|
||||
def bio_data_json_str(self):
|
||||
"""生物由来ロット分解データの検索結果を指定された件数ごとに分割しながら返す"""
|
||||
def date_handler(obj):
|
||||
"""json.dumpsの日付項目のフォーマットハンドラ"""
|
||||
return obj.isoformat().replace('T', ' ') if hasattr(obj, 'isoformat') else obj
|
||||
|
||||
search_data_list = [model.model_dump() for model in self.bio_data]
|
||||
search_data_len = len(search_data_list)
|
||||
# 呼び出し一回あたりの分割数
|
||||
part_size = 500
|
||||
for i in range(0, search_data_len, part_size):
|
||||
json_str = json.dumps(search_data_list[i:i + part_size], ensure_ascii=False, default=date_handler)
|
||||
# JavaScriptに埋め込むため、バックスラッシュ、バッククォートをエスケープ
|
||||
json_str = json_str.replace('\\', '\\\\')
|
||||
json_str = json_str.replace("`", "\\`")
|
||||
yield json_str
|
||||
|
||||
def make_whs_name(self):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
if self.form_data.rec_whs_cd is None:
|
||||
return ''
|
||||
|
||||
form_wholesaler_full_name = \
|
||||
f'{self.form_data.rec_whs_cd}-{self.form_data.rec_whs_sub_cd}:{self.form_data.whs_name}'
|
||||
|
||||
return form_wholesaler_full_name
|
||||
|
||||
def is_selected_whs_name(self, selected_wholesaler):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
|
||||
form_wholesaler_full_name = \
|
||||
f'{self.form_data.rec_whs_cd}-{self.form_data.rec_whs_sub_cd}:{self.form_data.whs_name}'
|
||||
|
||||
return self._selected_value(form_wholesaler_full_name, selected_wholesaler)
|
||||
|
||||
def is_selected_org_kbn(self, selected_org_kbn):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
return self._selected_value(self.form_data.slip_org_kbn, selected_org_kbn)
|
||||
|
||||
def is_input_rec_ymd_from(self):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
|
||||
return self._format_date_string(self.form_data.rec_ymd_from)
|
||||
|
||||
def is_input_rec_ymd_to(self):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
|
||||
return self._format_date_string(self.form_data.rec_ymd_to)
|
||||
|
||||
def is_input_lot_num(self):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
|
||||
return self.form_data.rec_lot_num or ''
|
||||
|
||||
def is_selected_data_kbn(self, selected_data_kbn):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
|
||||
return self._selected_value(self.form_data.data_kbn, selected_data_kbn)
|
||||
|
||||
def is_selected_maker_cd(self, selected_maker_cd):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
|
||||
return self._selected_value(self.form_data.mkr_cd, selected_maker_cd)
|
||||
|
||||
def is_input_rev_hsdnymd_srk_from(self):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
|
||||
return self._format_date_string(self.form_data.rev_hsdnymd_srk_from)
|
||||
|
||||
def is_input_rev_hsdnymd_srk_to(self):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
|
||||
return self._format_date_string(self.form_data.rev_hsdnymd_srk_to)
|
||||
|
||||
def is_checked_iko_flg(self):
|
||||
if not self.is_form_submitted():
|
||||
return ''
|
||||
|
||||
return 'checked' if self.form_data.iko_flg else ''
|
||||
|
||||
def disabled_button(self):
|
||||
return 'disabled' if self.is_data_empty() or self.is_data_overflow_max_length() else ''
|
||||
|
||||
def is_form_submitted(self):
|
||||
return self.form_data is not None
|
||||
|
||||
def is_data_empty(self):
|
||||
return self.bio_data is None or len(self.bio_data) == 0
|
||||
|
||||
def is_data_overflow_max_length(self):
|
||||
return self.bio_data is None or len(self.bio_data) > environment.BIO_SEARCH_RESULT_MAX_COUNT
|
||||
|
||||
def _format_date_string(self, date_string):
|
||||
if date_string is None:
|
||||
return ''
|
||||
date = datetime.strptime(date_string, '%Y%m%d')
|
||||
return date.strftime('%Y/%m/%d')
|
||||
|
||||
def _selected_value(self, form_value: str, current_value: str):
|
||||
return 'selected' if form_value == current_value else ''
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
from src.db import sql_condition as condition
|
||||
from src.db.sql_condition import SQLCondition
|
||||
from src.logging.get_logger import get_logger
|
||||
from src.model.db.bio_sales_lot import BioSalesLotDBModel
|
||||
from src.model.db.bio_sales_lot import (BioSalesLotCountDBModel,
|
||||
BioSalesLotDBModel)
|
||||
from src.model.request.bio import BioModel
|
||||
from src.repositories.base_repository import BaseRepository
|
||||
from src.system_var import environment
|
||||
@ -68,12 +69,12 @@ class BioSalesLotRepository(BaseRepository):
|
||||
try:
|
||||
logger.debug('DB参照実行')
|
||||
where_clause = self.__build_condition(parameter)
|
||||
# システムとしての最大取得件数 +1 まで取る
|
||||
query = self.FETCH_SQL.format(where_clause=where_clause, limit=environment.BIO_SEARCH_RESULT_MAX_COUNT + 1)
|
||||
# ページングで取得するため、LIMIT,OFFSETを指定
|
||||
limit_clause = self.__build_paging_limit_clauses(parameter)
|
||||
query = self.FETCH_SQL.format(where_clause=where_clause, limit=limit_clause)
|
||||
logger.debug(f'SQL: {query}')
|
||||
result = self._database.execute_select(query, parameter.model_dump())
|
||||
models = [BioSalesLotDBModel(**r) for r in result]
|
||||
logger.debug(f'count= {len(models)}')
|
||||
return models
|
||||
except Exception as e:
|
||||
logger.exception(f"DB Error : Exception={e.args}")
|
||||
@ -93,6 +94,35 @@ class BioSalesLotRepository(BaseRepository):
|
||||
logger.exception(f"DB Error : Exception={e.args}")
|
||||
raise e
|
||||
|
||||
COUNT_SQL = """\
|
||||
SELECT
|
||||
COUNT(*) AS count
|
||||
FROM
|
||||
(
|
||||
SELECT 1
|
||||
FROM src05.bio_sales_lot
|
||||
WHERE
|
||||
{where_clause}
|
||||
LIMIT {limit}
|
||||
) AS t\
|
||||
"""
|
||||
|
||||
def fetch_count(self, parameter: BioModel) -> list[BioSalesLotDBModel]:
|
||||
try:
|
||||
logger.debug('DB参照実行')
|
||||
where_clause = self.__build_condition(parameter)
|
||||
# システムとしての最大取得件数 + 1まで取る
|
||||
query = self.COUNT_SQL.format(where_clause=where_clause, limit=environment.BIO_SEARCH_RESULT_MAX_COUNT + 1)
|
||||
logger.debug(f'SQL: {query}')
|
||||
result = self._database.execute_select(query, parameter.model_dump())
|
||||
models = [BioSalesLotCountDBModel(**r) for r in result]
|
||||
count = models[0].count if len(models) > 0 else 0
|
||||
logger.debug(f'count= {count}')
|
||||
return count
|
||||
except Exception as e:
|
||||
logger.exception(f"DB Error : Exception={e.args}")
|
||||
raise e
|
||||
|
||||
def __build_condition(self, parameter: BioModel):
|
||||
where_clauses: list[SQLCondition] = []
|
||||
|
||||
@ -142,3 +172,9 @@ class BioSalesLotRepository(BaseRepository):
|
||||
|
||||
logger.debug(f'条件設定終了:{where_clauses_str}')
|
||||
return where_clauses_str
|
||||
|
||||
def __build_paging_limit_clauses(self, parameter: BioModel) -> str:
|
||||
page_size = parameter.pageSize or 0
|
||||
page_number = parameter.pageNumber or 0
|
||||
|
||||
return f'{page_size} OFFSET {(page_number - 1) * page_size}'
|
||||
|
||||
@ -11,7 +11,7 @@ from src.aws.s3 import S3Client
|
||||
from src.logging.get_logger import get_logger
|
||||
from src.model.internal.session import UserSession
|
||||
from src.model.request.bio import BioModel
|
||||
from src.model.view.bio_disp_model import BisDisplayModel
|
||||
from src.model.view.bio_disp_model import BioDisplayModel
|
||||
from src.model.view.bio_view_model import BioViewModel
|
||||
from src.repositories.base_repository import BaseRepository
|
||||
from src.repositories.bio_sales_lot_repository import BioSalesLotRepository
|
||||
@ -65,12 +65,23 @@ class BioViewService(BaseService):
|
||||
|
||||
def search_bio_data(self, search_params: BioModel):
|
||||
# 生物由来データを検索
|
||||
bio_sales_view_data = self.bio_sales_repository.fetch_many(parameter=search_params)
|
||||
bio_sales_lot_data = self.bio_sales_repository.fetch_many(parameter=search_params)
|
||||
# 画面表示用に加工
|
||||
display_bio_data: list[BisDisplayModel] = [BisDisplayModel(data) for data in bio_sales_view_data]
|
||||
display_bio_data: list[BioDisplayModel] = [BioDisplayModel(data) for data in bio_sales_lot_data]
|
||||
|
||||
return display_bio_data
|
||||
|
||||
def count_bio_data(self, search_params: BioModel, session: UserSession) -> int:
|
||||
# 検索値が前回検索時と変更がない場合、キャッシュした件数を返す
|
||||
previous_search_params = session.bio_search_condition
|
||||
current_search_params = search_params.model_dump()
|
||||
if previous_search_params == current_search_params:
|
||||
return session.bio_search_count
|
||||
|
||||
# 生物由来データの件数をDBから取得
|
||||
bio_sales_data_count = self.bio_sales_repository.fetch_count(parameter=search_params)
|
||||
return bio_sales_data_count
|
||||
|
||||
def search_download_bio_data(
|
||||
self,
|
||||
search_params: BioModel,
|
||||
|
||||
@ -28,18 +28,16 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<form class="_form _border" id="bio_search" name="search" action="/bio/BioSearchList" method="POST" onsubmit="showLoading('_loading_for_other')">
|
||||
<form class="_form _border" id="bio_search" name="search">
|
||||
<table class="search_table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>卸:</td>
|
||||
<td class="search_tb" id="oroshi_dd">
|
||||
<select class="text search_dropdown" name="ctrl_wholesaler" value="" onChange="formBtDisabled();">
|
||||
<select class="text search_dropdown" name="ctrl_wholesaler" value="" onChange="formBtDisabled();applySearchParam(this)">
|
||||
<option value=""></option>
|
||||
{% for whs_name in bio.display_wholesaler_names() %}
|
||||
<option
|
||||
value="{{whs_name}}"
|
||||
{{bio.is_selected_whs_name(whs_name)}}>
|
||||
<option value="{{whs_name}}">
|
||||
{{whs_name}}
|
||||
</option>
|
||||
{% endfor %}
|
||||
@ -47,22 +45,24 @@
|
||||
</td>
|
||||
<td>データ種別:</td>
|
||||
<td class="search_tb">
|
||||
<select class="text search_dropdown" name="ctrl_org_kbn" onChange="formBtDisabled();" value="">
|
||||
<select class="text search_dropdown" name="ctrl_org_kbn" onChange="formBtDisabled();applySearchParam(this)" value="">
|
||||
{% for org_kbn_code, org_kbn_value in bio.display_org_kbn().items() %}
|
||||
<option value="{{org_kbn_code}}" {{bio.is_selected_org_kbn(org_kbn_code)}} >{{org_kbn_value}}</option>
|
||||
<option value="{{org_kbn_code}}">
|
||||
{{org_kbn_value}}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>処理日:</td>
|
||||
<td colspan="2">
|
||||
<input type="text" id="shoribi_start" class="date_picker" name="ctrl_rec_ymd_from" maxlength="10"
|
||||
value="{{bio.is_input_rec_ymd_from()}}"
|
||||
onchange="formBtDisabled()"
|
||||
value=""
|
||||
onchange="formBtDisabled();applySearchParam(this)"
|
||||
>
|
||||
~
|
||||
<input type="text" id="shoribi_end" class="date_picker" name="ctrl_rec_ymd_to" maxlength="10"
|
||||
value="{{bio.is_input_rec_ymd_to()}}"
|
||||
onchange="formBtDisabled()"
|
||||
value=""
|
||||
onchange="formBtDisabled();applySearchParam(this)"
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
@ -70,26 +70,27 @@
|
||||
<td>ロット番号:</td>
|
||||
<td class="search_tb">
|
||||
<input class="text" type="text" id="lot_tb" name="ctrl_rec_lot_num" style="ime-mode:disabled" maxlength="10"
|
||||
value="{{bio.is_input_lot_num()}}"
|
||||
oninput="checkSpaceForm(this); checkAimaiSearhForm(this); formBtDisabled()">
|
||||
value=""
|
||||
oninput="checkSpaceForm(this); checkAimaiSearhForm(this); formBtDisabled();applySearchParam(this)">
|
||||
</td>
|
||||
<td>データ区分:</td>
|
||||
<td class="search_tb">
|
||||
<select class="text search_dropdown" name="ctrl_data_kbn" onchange="formBtDisabled()">
|
||||
<select class="text search_dropdown" name="ctrl_data_kbn" onchange="formBtDisabled();applySearchParam(this)">
|
||||
{% for data_kbn_code, data_kbn_value in bio.display_data_kbn().items() %}
|
||||
<option value="{{data_kbn_value}}" {{bio.is_selected_data_kbn(data_kbn_value)}} >{{data_kbn_value}}</option>
|
||||
<option option value="{{data_kbn_value}}">
|
||||
{{data_kbn_value}}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>製品:</td>
|
||||
<td class="search_tb" id="seihin_dd">
|
||||
<select class="text search_dropdown" name="ctrl_maker_cd" value="" onChange="formBtDisabled();">
|
||||
<select class="text search_dropdown" name="ctrl_maker_cd" value="" onChange="formBtDisabled();applySearchParam(this);">
|
||||
<option value=""></option>
|
||||
{% for phm in bio.phm_models %}
|
||||
<option
|
||||
value="{{phm['mkr_cd']}}" {{bio.is_selected_maker_cd(phm['mkr_cd'])}}>
|
||||
{{phm['mkr_cd_name']}}
|
||||
</option>
|
||||
<option value="{{phm['mkr_cd']}}">
|
||||
{{phm['mkr_cd_name']}}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
@ -98,22 +99,22 @@
|
||||
<td>発伝年月日:</td>
|
||||
<td colspan="3">
|
||||
<input type="text" id="hsdnymd_start" class="date_picker" name="ctrl_rev_hsdnymd_srk_from" maxlength="10"
|
||||
value="{{bio.is_input_rev_hsdnymd_srk_from()}}"
|
||||
onchange="formBtDisabled()"
|
||||
value=""
|
||||
onchange="formBtDisabled();applySearchParam(this)"
|
||||
>
|
||||
~
|
||||
<input type="text" id="hsdnymd_end" class="date_picker" name="ctrl_rev_hsdnymd_srk_to" maxlength="10"
|
||||
value="{{bio.is_input_rev_hsdnymd_srk_to()}}"
|
||||
onchange="formBtDisabled()"
|
||||
value=""
|
||||
onchange="formBtDisabled();applySearchParam(this)"
|
||||
>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<input type="checkbox" id="ikoFlg" name="ikoFlg" value="true" {{bio.is_checked_iko_flg()}}>
|
||||
<input type="checkbox" id="ikoFlg" name="ikoFlg" value="true" oninput="applySearchParam(this)">
|
||||
<label for="ikoFlg">2017年11月以前のデータを含める</label>
|
||||
</td>
|
||||
<td>
|
||||
<input class="buttonSize" id="clear" type="button" name="clear_bt" value="クリア" onclick="clr()">
|
||||
<input class="buttonSize" id="search_bt" value="検索" type="submit">
|
||||
<input class="buttonSize" id="clear" type="button" name="clear_bt" value="クリア" onclick="clr();clearHidden('bioSearchHidden')">
|
||||
<input class="buttonSize" id="search_bt" value="検索" type="button" onclick="searchBioList()">
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -121,9 +122,9 @@
|
||||
</form>
|
||||
<!--検索結果-->
|
||||
<form class="_form" id="searchResult" name="searchResult">
|
||||
<input type="button" id="outExcel" name="outExcel" value="Excel出力" {{bio.disabled_button()}}
|
||||
<input type="button" id="outExcel" name="outExcel" value="Excel出力" disabled
|
||||
data-bs-toggle="modal" data-bs-target="#modal_xlsx" data-bs-message="生物由来卸販売データ一覧をExcel出力しますか?"/>
|
||||
<input type="button" id="outCSV" name="outCSV" value="CSV出力" {{bio.disabled_button()}}
|
||||
<input type="button" id="outCSV" name="outCSV" value="CSV出力" disabled
|
||||
data-bs-toggle="modal" data-bs-target="#modal_csv" data-bs-message="生物由来卸販売データ一覧をCSV出力しますか?" />
|
||||
<!--ページネーション-->
|
||||
<div id="light-pagination" class="pagination"></div>
|
||||
@ -173,50 +174,62 @@
|
||||
</thead>
|
||||
<tbody id="result_data" class="result_data"></tbody>
|
||||
</table>
|
||||
{% if bio.is_form_submitted() and bio.is_data_overflow_max_length() %}
|
||||
<div class="resultAreaMsg">
|
||||
検索結果が最大件数を超えました。検索条件を見直しして下さい。
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if bio.is_form_submitted() and bio.is_data_empty() %}
|
||||
<div class="resultAreaMsg">
|
||||
対象のデータが存在しません
|
||||
</div>
|
||||
{% endif %}
|
||||
<div id="message_area" class="resultAreaMsg"></div>
|
||||
</div>
|
||||
</form>
|
||||
<form id="bio_download">
|
||||
<input type="hidden" name="ctrl_wholesaler" value="{{bio.make_whs_name()}}">
|
||||
<input type="hidden" name="ctrl_org_kbn" value="{{bio.form_data.slip_org_kbn or ''}}">
|
||||
<input type="hidden" name="ctrl_rec_ymd_from" value="{{bio.is_input_rec_ymd_from()}}">
|
||||
<input type="hidden" name="ctrl_rec_ymd_to" value="{{bio.is_input_rec_ymd_to()}}">
|
||||
<input type="hidden" name="ctrl_rec_lot_num" value="{{bio.is_input_lot_num()}}">
|
||||
<input type="hidden" name="ctrl_data_kbn" value="{{bio.form_data.data_kbn or ''}}">
|
||||
<input type="hidden" name="ctrl_maker_cd" value="{{bio.form_data.mkr_cd or ''}}">
|
||||
<input type="hidden" name="ctrl_rev_hsdnymd_srk_from" value="{{bio.is_input_rev_hsdnymd_srk_from()}}">
|
||||
<input type="hidden" name="ctrl_rev_hsdnymd_srk_to" value="{{bio.is_input_rev_hsdnymd_srk_to()}}">
|
||||
<input type="checkbox" name="ikoFlg" value="true" {{bio.is_checked_iko_flg()}} style="display: none;">
|
||||
<form id="search_param_hidden" name="bioSearchHidden">
|
||||
<input type="hidden" name="ctrl_wholesaler" value="">
|
||||
<input type="hidden" name="ctrl_org_kbn" value="">
|
||||
<input type="hidden" name="ctrl_rec_ymd_from" value="">
|
||||
<input type="hidden" name="ctrl_rec_ymd_to" value="">
|
||||
<input type="hidden" name="ctrl_rec_lot_num" value="">
|
||||
<input type="hidden" name="ctrl_data_kbn" value="">
|
||||
<input type="hidden" name="ctrl_maker_cd" value="">
|
||||
<input type="hidden" name="ctrl_rev_hsdnymd_srk_from" value="">
|
||||
<input type="hidden" name="ctrl_rev_hsdnymd_srk_to" value="">
|
||||
<input type="checkbox" name="ikoFlg" value="true" style="display: none;">
|
||||
</form>
|
||||
<form id="download_hidden" name="bioDownloadHidden">
|
||||
<input type="hidden" name="ctrl_wholesaler" value="">
|
||||
<input type="hidden" name="ctrl_org_kbn" value="">
|
||||
<input type="hidden" name="ctrl_rec_ymd_from" value="">
|
||||
<input type="hidden" name="ctrl_rec_ymd_to" value="">
|
||||
<input type="hidden" name="ctrl_rec_lot_num" value="">
|
||||
<input type="hidden" name="ctrl_data_kbn" value="">
|
||||
<input type="hidden" name="ctrl_maker_cd" value="">
|
||||
<input type="hidden" name="ctrl_rev_hsdnymd_srk_from" value="">
|
||||
<input type="hidden" name="ctrl_rev_hsdnymd_srk_to" value="">
|
||||
<input type="checkbox" name="ikoFlg" value="true" style="display: none;">
|
||||
</form>
|
||||
|
||||
<!-- CSV/Excelダウンロード処理-->
|
||||
<script type="text/javascript">
|
||||
|
||||
function clearHidden(hiddenName) {
|
||||
// 非表示項目をクリア
|
||||
const formElement = document[hiddenName]
|
||||
const formInputElements = Array.from(formElement.elements)
|
||||
for (const formInput of formInputElements) {
|
||||
if (formInput.name.startsWith('ctrl_')) {
|
||||
formInput.value = "";
|
||||
}
|
||||
if (formInput.type === 'checkbox') {
|
||||
formInput.checked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// CSV/Excelダウンロード処理
|
||||
function download(ext) {
|
||||
// ローディング開始
|
||||
const loading = new Loading();
|
||||
loading.start();
|
||||
|
||||
// 検索パラメータを取得
|
||||
const formData = $('#bio_download').serializeArray()
|
||||
// リクエスト用に加工
|
||||
const searchParams = {}
|
||||
for (let i = 0; i < formData.length; i++) {
|
||||
searchParams[formData[i].name] = formData[i].value
|
||||
}
|
||||
// ダウンロード固有のパラメータを設定
|
||||
const downloadRequestParams = {
|
||||
user_id: '{{bio.user_id}}',
|
||||
ext: ext,
|
||||
}
|
||||
// 検索パラメータを取得
|
||||
const searchParams = createSearchParams('download_hidden')
|
||||
$.extend(downloadRequestParams, searchParams)
|
||||
|
||||
$.ajax({
|
||||
@ -229,7 +242,7 @@
|
||||
success: function(data) {
|
||||
try {
|
||||
if (data.status === 'batch_processing') {
|
||||
location.href='/logout/?reason=batchProcessing';
|
||||
location.href='/logout/?reason=batch_processing';
|
||||
return
|
||||
}
|
||||
|
||||
@ -272,13 +285,41 @@
|
||||
});
|
||||
}
|
||||
|
||||
// <! --ページネーションの作成-- >
|
||||
$(function() {
|
||||
const searchResultData = generateSearchResult();
|
||||
if (searchResultData.length == 0) return;
|
||||
function createSearchParams(paramId) {
|
||||
// 検索パラメータを取得
|
||||
const formData = $(`#${paramId}`).serializeArray()
|
||||
// リクエスト用に加工
|
||||
const searchParams = {}
|
||||
for (let i = 0; i < formData.length; i++) {
|
||||
searchParams[formData[i].name] = formData[i].value
|
||||
}
|
||||
|
||||
$(".pagination").pagination({
|
||||
dataSource: searchResultData,
|
||||
return searchParams
|
||||
}
|
||||
|
||||
function applySearchParam(elem) {
|
||||
const bioSearchHiddenForm = document['bioSearchHidden']
|
||||
bioSearchHiddenForm[elem.name].value = elem.value
|
||||
|
||||
if (elem.type === 'checkbox') {
|
||||
bioSearchHiddenForm[elem.name].checked = elem.checked
|
||||
}
|
||||
}
|
||||
|
||||
// 生物由来データの検索&ページネーションの作成
|
||||
function searchBioList() {
|
||||
const messageArea = $('#message_area')
|
||||
messageArea.text('')
|
||||
messageArea.hide()
|
||||
const loading = new Loading('_loading_for_other')
|
||||
const searchParams = createSearchParams('search_param_hidden')
|
||||
$('.pagination').pagination({
|
||||
dataSource: '/bio/search',
|
||||
locator: 'data',
|
||||
totalNumberLocator: function(response) {
|
||||
// you can return totalNumber by analyzing response content
|
||||
return response.count
|
||||
},
|
||||
pageNumber: 1, // 初期ページ番号
|
||||
pageSize: 100, //表示するコンテンツ数
|
||||
pageRange: 2, //選択されているページネーション番号の両隣に表示する個数
|
||||
@ -287,8 +328,73 @@
|
||||
nextText: 'Next', //「次へ」の文字。エスケープ文字
|
||||
showNavigator: true,
|
||||
formatNavigator: '件数: <%= totalNumber %>件 ページ数: <%= totalPage %>',
|
||||
ajax: {
|
||||
type: 'POST',
|
||||
data: searchParams,
|
||||
async: true,
|
||||
beforeSend: function() {
|
||||
loading.start()
|
||||
}
|
||||
},
|
||||
formatAjaxError: function(jqXHR, textStatus, errorThrown) {
|
||||
loading.stop()
|
||||
const responseJson = jqXHR.responseJSON
|
||||
|
||||
if (!responseJson) {
|
||||
$(`#ErrorModal_Unexpected`).modal('toggle')
|
||||
return
|
||||
}
|
||||
|
||||
const status = responseJson?.status
|
||||
if (status === 'batch_processing') {
|
||||
location.href='/logout/?reason=batch_processing';
|
||||
return
|
||||
}
|
||||
|
||||
if (status === 'session_expired') {
|
||||
location.href='/logout/?reason=session_expired';
|
||||
return
|
||||
}
|
||||
|
||||
},
|
||||
callback: function(data, pagination) {
|
||||
// ダウンロード用の非表示項目に検索値を埋め込む
|
||||
const bioSearchHiddenForm = document['bioSearchHidden']
|
||||
const bioDownloadHiddenForm = document['bioDownloadHidden']
|
||||
for (const key of Object.keys(searchParams)) {
|
||||
const elem = bioDownloadHiddenForm[key]
|
||||
elem.value = searchParams[key]
|
||||
if (elem.type === 'checkbox') {
|
||||
elem.checked = searchParams[key] === 'true' ? true : false
|
||||
}
|
||||
}
|
||||
$('#result_data').html('')
|
||||
if (pagination.totalNumber === 0) {
|
||||
loading.stop()
|
||||
messageArea.text('対象のデータが存在しません')
|
||||
messageArea.show()
|
||||
$('.pagination').pagination('hide')
|
||||
$('#outExcel').attr('disabled', 'disabled')
|
||||
$('#outCSV').attr('disabled', 'disabled')
|
||||
return
|
||||
}
|
||||
|
||||
if (pagination.totalNumber > bioDataOverflowMaxLength()) {
|
||||
loading.stop()
|
||||
messageArea.text('検索結果が最大件数を超えました。検索条件を見直しして下さい。')
|
||||
messageArea.show()
|
||||
$('.pagination').pagination('hide')
|
||||
$('#outExcel').attr('disabled', 'disabled')
|
||||
$('#outCSV').attr('disabled', 'disabled')
|
||||
return
|
||||
}
|
||||
messageArea.hide()
|
||||
$('.pagination').pagination('show')
|
||||
$('#result_data').html(pagination_content(data))
|
||||
loading.stop()
|
||||
$('#outExcel').removeAttr('disabled')
|
||||
$('#outCSV').removeAttr('disabled')
|
||||
|
||||
$('.paginationjs-pages > ul > li').not('.disabled,.active').each(function(index, val) {
|
||||
// paginationにtabindexをつける
|
||||
$(val).attr('tabindex', '0')
|
||||
@ -303,11 +409,16 @@
|
||||
})
|
||||
})
|
||||
// ページ送りしたときにヘッダがずれるのを修正
|
||||
FixedMidashi.remove();
|
||||
FixedMidashi.create();
|
||||
FixedMidashi.remove()
|
||||
FixedMidashi.create()
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function bioDataOverflowMaxLength() {
|
||||
const maxlength = '{{bio.search_data_max_length}}'
|
||||
return Number(maxlength)
|
||||
}
|
||||
|
||||
function pagination_content(datas) {
|
||||
const display_keys = [
|
||||
@ -364,20 +475,6 @@
|
||||
})
|
||||
}
|
||||
|
||||
function generateSearchResult(){
|
||||
const searchResultData = []
|
||||
// {% if bio.is_form_submitted() and not (bio.is_data_overflow_max_length() or bio.is_data_empty()) %}
|
||||
// {% autoescape False%}
|
||||
// ジェネレータですこしずつ取得してリストに詰める
|
||||
// {% for bio_data_json_str in bio.bio_data_json_str() %}
|
||||
// unicode制御文字をエスケープしてからJSON.parseする
|
||||
searchResultData.push(...JSON.parse(`{{bio_data_json_str}}`.replace(/[\u0000-\u001F]+/g, " ")))
|
||||
// {% endfor %}
|
||||
// {% endautoescape%}
|
||||
// {% endif %}
|
||||
return searchResultData
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- Excel出力モーダル -->
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user