feat: 生物由来照会画面のパフォーマンス改善. ページネーションの1ページ分のみ取得するように修正。

This commit is contained in:
shimoda.m@nds-tyo.co.jp 2023-10-04 17:08:13 +09:00
parent 426fa534b2
commit ad557d499e
7 changed files with 182 additions and 41 deletions

View File

@ -79,3 +79,22 @@ def search_bio(
headers={'session_key': session_key}
)
return templates_response
@router.post('/BioSearchListAjax')
def search_bio_ajax(
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_lot_data = bio_service.search_bio_data(bio_form)
bio_sales_lot_count = bio_service.count_bio_data(bio_form, session)
return {'data': bio_sales_lot_data, 'count': bio_sales_lot_count}

View File

@ -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]

View File

@ -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
)

View File

@ -152,6 +152,9 @@ class BioViewModel(BaseModel):
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 data_overflow_max_length(self):
return environment.BIO_SEARCH_RESULT_MAX_COUNT
def _format_date_string(self, date_string):
if date_string is None:
return ''

View File

@ -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
@ -67,12 +68,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}")
@ -92,6 +93,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] = []
@ -141,3 +171,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}'

View File

@ -71,6 +71,11 @@ class BioViewService(BaseService):
return display_bio_data
def count_bio_data(self, search_params: BioModel, session: UserSession):
# 生物由来データの件数を取得
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,

View File

@ -28,13 +28,13 @@
</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
@ -47,7 +47,7 @@
</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>
{% endfor %}
@ -57,12 +57,12 @@
<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()"
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()"
onchange="formBtDisabled();applySearchParam(this)"
>
</td>
</tr>
@ -71,11 +71,11 @@
<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()">
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>
{% endfor %}
@ -83,7 +83,7 @@
</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
@ -99,21 +99,22 @@
<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()"
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()"
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" {{bio.is_checked_iko_flg()}} 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="search_bt" value="検索" type="submit"> -->
<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,10 +174,10 @@
</thead>
<tbody id="result_data" class="result_data"></tbody>
</table>
<div id="message_area" class="resultAreaMsg"></div>
{% 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">
@ -185,7 +186,7 @@
{% endif %}
</div>
</form>
<form id="bio_download">
<form id="search_param_hidden" name="bioHidden">
<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()}}">
@ -198,25 +199,20 @@
<input type="checkbox" name="ikoFlg" value="true" {{bio.is_checked_iko_flg()}} style="display: none;">
</form>
<!-- CSV/Excelダウンロード処理-->
<script type="text/javascript">
// 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()
$.extend(downloadRequestParams, searchParams)
$.ajax({
@ -272,13 +268,42 @@
});
}
// <! --ページネーションの作成-- >
$(function() {
const searchResultData = generateSearchResult();
if (searchResultData.length == 0) return;
function createSearchParams() {
// 検索パラメータを取得
const formData = $('#search_param_hidden').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) {
console.log(elem.value)
console.log(elem.name)
const bioHiddenForm = document['bioHidden']
bioHiddenForm[elem.name].value = elem.value
if (bioHiddenForm[elem.name].type === 'checkbox') {
bioHiddenForm[elem.name].checked = elem.checked
}
console.log(bioHiddenForm[elem.name].value)
}
// <! --ページネーションの作成-- >
function searchBioList() {
const messageArea = $('#message_area')
messageArea.text('')
const loading = new Loading();
const searchParams = createSearchParams()
$('.pagination').pagination({
dataSource: '/bio/BioSearchListAjax',
locator: 'data',
totalNumberLocator: function(response) {
// you can return totalNumber by analyzing response content
return response.count
},
pageNumber: 1, // 初期ページ番号
pageSize: 100, //表示するコンテンツ数
pageRange: 2, //選択されているページネーション番号の両隣に表示する個数
@ -287,8 +312,42 @@
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();
$(`#ErrorModal_Unexpected`).modal('toggle');
},
callback: function(data, pagination) {
$('#result_data').html('')
if (pagination.totalNumber === 0) {
loading.stop();
messageArea.text('対象のデータが存在しません')
$('.pagination').pagination('hide')
$('#outExcel').attr('disabled', 'disabled')
$('#outCSV').attr('disabled', 'disabled')
return
}
if (pagination.totalNumber > bioDataOverflowMaxLength()) {
loading.stop();
messageArea.text('検索結果が最大件数を超えました。検索条件を見直しして下さい。')
$('.pagination').pagination('hide')
$('#outExcel').attr('disabled', 'disabled')
$('#outCSV').attr('disabled', 'disabled')
return
}
$('.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')
@ -307,7 +366,12 @@
FixedMidashi.create();
}
})
});
}
function bioDataOverflowMaxLength() {
const maxlength = '{{bio.data_overflow_max_length()}}'
return Number(maxlength)
}
function pagination_content(datas) {
const display_keys = [