"""按任务扫描库内行,得到「全表至少一格非空」的列,供摘要 / 浏览 / 导出一致裁剪。""" from __future__ import annotations from .csv_schema import ( COMMENT_CSV_COLUMNS, COMMENT_CSV_TO_FIELD, DETAIL_CSV_COLUMNS, DETAIL_CSV_TO_FIELD, JD_SEARCH_CSV_HEADERS, JD_SEARCH_INTERNAL_KEYS, MERGED_FIELD_TO_CSV_HEADER, MERGED_INTERNAL_KEYS, ) from .models import JdJobCommentRow, JdJobDetailRow, JdJobMergedRow, JdJobSearchRow, PipelineJob from .row_serialize import COMMENT_FIELDS_ORDER, DETAIL_FIELDS_ORDER def _is_nonempty(val) -> bool: if val is None: return False return str(val).strip() != "" def nonempty_search_keys_for_job(job: PipelineJob) -> list[str]: qs = JdJobSearchRow.objects.filter(job=job) present = {k: False for k in JD_SEARCH_INTERNAL_KEYS} for row in qs.iterator(chunk_size=400): for k in JD_SEARCH_INTERNAL_KEYS: if not present[k] and _is_nonempty(getattr(row, k, None)): present[k] = True return [k for k in JD_SEARCH_INTERNAL_KEYS if present[k]] def nonempty_detail_fields_for_job(job: PipelineJob) -> list[str]: qs = JdJobDetailRow.objects.filter(job=job) present = {k: False for k in DETAIL_FIELDS_ORDER} for row in qs.iterator(chunk_size=400): for k in DETAIL_FIELDS_ORDER: if not present[k] and _is_nonempty(getattr(row, k, None)): present[k] = True return [k for k in DETAIL_FIELDS_ORDER if present[k]] def nonempty_comment_fields_for_job(job: PipelineJob) -> list[str]: qs = JdJobCommentRow.objects.filter(job=job) present = {k: False for k in COMMENT_FIELDS_ORDER} for row in qs.iterator(chunk_size=400): for k in COMMENT_FIELDS_ORDER: if not present[k] and _is_nonempty(getattr(row, k, None)): present[k] = True return [k for k in COMMENT_FIELDS_ORDER if present[k]] def nonempty_merged_fields_for_job(job: PipelineJob) -> list[str]: qs = JdJobMergedRow.objects.filter(job=job) present = {k: False for k in MERGED_INTERNAL_KEYS} for row in qs.iterator(chunk_size=400): for k in MERGED_INTERNAL_KEYS: if not present[k] and _is_nonempty(getattr(row, k, None)): present[k] = True return [k for k in MERGED_INTERNAL_KEYS if present[k]] def search_columns_for_api(job: PipelineJob) -> list[dict[str, str]]: return [{"key": k, "label": JD_SEARCH_CSV_HEADERS[k]} for k in nonempty_search_keys_for_job(job)] def _detail_field_to_csv_col(field: str) -> str: for col, fn in DETAIL_CSV_TO_FIELD.items(): if fn == field: return col return field def detail_columns_for_api(job: PipelineJob) -> list[dict[str, str]]: return [ {"key": f, "label": _detail_field_to_csv_col(f)} for f in nonempty_detail_fields_for_job(job) ] def _comment_field_to_csv_col(field: str) -> str: for col, fn in COMMENT_CSV_TO_FIELD.items(): if fn == field: return col return field def comment_columns_for_api(job: PipelineJob) -> list[dict[str, str]]: return [ {"key": f, "label": _comment_field_to_csv_col(f)} for f in nonempty_comment_fields_for_job(job) ] def merged_columns_for_api(job: PipelineJob) -> list[dict[str, str]]: return [ {"key": k, "label": MERGED_FIELD_TO_CSV_HEADER[k]} for k in nonempty_merged_fields_for_job(job) ] def search_export_headers(job: PipelineJob) -> list[str]: keys = nonempty_search_keys_for_job(job) return ["id", "row_index"] + [JD_SEARCH_CSV_HEADERS[k] for k in keys] def detail_export_headers(job: PipelineJob) -> list[str]: fields = set(nonempty_detail_fields_for_job(job)) cols = [c for c in DETAIL_CSV_COLUMNS if DETAIL_CSV_TO_FIELD[c] in fields] return ["id", "row_index"] + cols def comment_export_headers(job: PipelineJob) -> list[str]: fields = set(nonempty_comment_fields_for_job(job)) cols = [c for c in COMMENT_CSV_COLUMNS if COMMENT_CSV_TO_FIELD[c] in fields] return ["id", "row_index"] + cols def merged_export_headers(job: PipelineJob) -> list[str]: keys = nonempty_merged_fields_for_job(job) return ["id", "row_index"] + [MERGED_FIELD_TO_CSV_HEADER[k] for k in keys]