Files
dpb/backend/scripts/_backup_query_param/seed_treatment__index.vue.bak
34047007@qq.com b95053c52c init: 初始化 dpb 桃育种系统代码库
前后端 + 后端 FastAPI 全量源码、部署脚本与文档。
2026-08-06 00:17:49 +08:00

587 lines
17 KiB
Plaintext

<template>
<div class="fa-full-height">
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
:items="SeedTreatmentSearchItems"
:rules="searchBarRules"
:is-expand="false"
:show-expand="true"
:show-reset="true"
:show-search="true"
:disabled-search="false"
:default-expanded="false"
include-audit
@search="handleSearch"
@reset="onResetSearch"
/>
<ElCard class="fa-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_bre:seed_treatment:create']"
:perm-import="['module_bre:seed_treatment:import']"
:perm-export="['module_bre:seed_treatment:export']"
:perm-delete="['module_bre:seed_treatment:delete']"
:delete-loading="batchDeleting"
:create-loading="createLoading"
@add="handleAdd"
@import="openImport"
@export="openExport"
@delete="handleBatchDelete"
/>
</template>
</FaTableHeader>
<FaTable
ref="faTableRef"
:loading="loading"
:data="data"
:columns="columns"
:pagination="pagination"
@selection-change="onTableSelectionChange"
@pagination:size-change="handleSizeChange"
@pagination:current-change="handleCurrentChange"
/>
</ElCard>
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="920px"
dialog-class="crud-embed-dialog"
modal-class="crud-embed-dialog"
:form-mode="dialogVisible.type"
:confirm-loading="submitLoading"
:close-on-click-modal="false"
@cancel="crud.handleCloseDialog"
@close="crud.handleCloseDialog"
@confirm="crud.handleSubmit"
>
<template v-if="dialogVisible.type === 'detail'">
<FaDescriptions
:column="4"
:data="detailFormData"
:items="SeedTreatmentDetailItems"
max-height="70vh"
/>
</template>
<template v-else>
<FaForm
:key="SeedTreatmentFormRenderKey"
scrollbar
max-height="70vh"
ref="dataFormRef"
v-model="formData"
:items="SeedTreatmentDialogFormItems"
:rules="rules"
label-suffix=":"
:label-width="120"
label-position="right"
:span="12"
:gutter="16"
:show-reset="false"
:show-submit="false"
class="crud-dialog-art-form"
/>
</template>
</FaDialog>
<FaImportDialog
v-model="importVisible"
:content-config="SeedTreatmentImportContentConfig"
default-template-file-name="seed_treatment_import_template.xlsx"
@upload="handleCrudImportUpload"
/>
<FaExportDialog
v-model="exportVisible"
:content-config="SeedTreatmentExportContentConfig"
:query-params="exportQueryParams"
:page-data="data"
:selection-data="selectedRows"
/>
</div>
</template>
<script setup lang="ts">
import type { TableOperationAction } from "@/utils/table";
import { renderTableOperationCell, stripPaginationParams, toCrudCols } from "@utils";
import { useCrudForm } from "@/hooks/core/useCrudForm";
import { ResultEnum } from "@/enums/api/result.enum";
import type { IContentConfig, IObject } from "@/components/modal/types";
import type { AuditSearchFormParams } from "@/components/forms/fa-search-bar/auditSearchFormItems";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import CrossCombinationAPI, { type CrossCombinationOption } from "@/api/module_bre/cross_combination";
import PersonnelAPI, { type PersonnelOption } from "@/api/module_bre/personnel";
import SeedTreatmentAPI, { type SeedTreatmentForm, type SeedTreatmentPageQuery, type SeedTreatmentTable } from "@/api/module_bre/seed_treatment";
import type { ColumnOption } from "@/types/component";
import FaDescriptions from "@/components/others/fa-descriptions/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
defineOptions({
name: "SeedTreatment",
inheritAttrs: false,
});
const cross_combinationOptions = ref<CrossCombinationOption[]>([]);
const personnelOptions = ref<PersonnelOption[]>([]);
const cross_combinationOptionsMap = computed(() => {
const m: Record<number, string> = {};
for (const o of cross_combinationOptions.value) m[o.value] = o.label;
return m;
});
const personnelOptionsMap = computed(() => {
const m: Record<number, string> = {};
for (const o of personnelOptions.value) m[o.value] = o.label;
return m;
});
async function loadCrossCombinationOptions() {
try {
const res = await CrossCombinationAPI.getCrossCombinationOptions();
if (res.data.code === ResultEnum.SUCCESS) {
cross_combinationOptions.value = res.data.data ?? [];
}
} catch (error: unknown) {
if (import.meta.env.DEV) console.error("[SeedTreatment] loadCrossCombinationOptions", error);
}
}
async function loadPersonnelOptions() {
try {
const res = await PersonnelAPI.getPersonnelOptions();
if (res.data.code === ResultEnum.SUCCESS) {
personnelOptions.value = res.data.data ?? [];
}
} catch (error: unknown) {
if (import.meta.env.DEV) console.error("[SeedTreatment] loadPersonnelOptions", error);
}
}
const createInitialFormData = (): SeedTreatmentForm => ({
id: undefined,
combination_id: undefined,
treatment_method: undefined,
treatment_start: undefined,
treatment_end: undefined,
germination_rate: undefined,
bre_personnel_id: undefined,
remark: undefined,
});
type SeedTreatmentSearchFormParams = {
combination_id?: number;
treatment_method?: string;
bre_personnel_id?: number;
} & AuditSearchFormParams;
const searchForm = ref<SeedTreatmentSearchFormParams>({
combination_id: undefined,
treatment_method: undefined,
bre_personnel_id: undefined,
created_id: undefined,
updated_id: undefined,
created_time: [],
updated_time: [],
});
const showSearchBar = ref(true);
const searchBarRef = ref<{ validate: () => Promise<boolean> } | null>(null);
const searchBarRules: Record<string, unknown> = {};
const SeedTreatmentSearchItems = computed(() => [
{
label: "杂交组合",
key: "combination_id",
type: "select",
props: {
placeholder: "请选择杂交组合",
options: cross_combinationOptions.value,
clearable: true,
filterable: true,
},
span: 8,
},
{
label: "处理方式",
key: "treatment_method",
type: "radiogroup",
props: {
placeholder: "请选择处理方式",
options: [{ label: "沙藏", value: "沙藏" }, { label: "层积", value: "层积" }, { label: "低温冷藏", value: "低温冷藏" }, { label: "常温", value: "常温" }],
clearable: true,
},
span: 8,
},
{
label: "种子处理人",
key: "bre_personnel_id",
type: "select",
props: {
placeholder: "请选择种子处理人",
options: personnelOptions.value,
clearable: true,
filterable: true,
},
span: 8,
},
]);
const faTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const { selectedRows, selectedIds, batchDeleting, onTableSelectionChange } = useTableSelection<SeedTreatmentTable>();
const createLoading = ref(false);
const {
columns,
columnChecks,
data,
loading,
pagination,
searchParams,
getData,
replaceSearchParams,
resetSearchParams,
handleSizeChange,
handleCurrentChange,
refreshData,
refreshCreate,
refreshUpdate,
refreshRemove,
} = useTable({
core: {
apiFn: SeedTreatmentAPI.getSeedTreatmentList,
apiParams: {
page_no: 1,
page_size: 10,
},
columnsFactory: (): ColumnOption<SeedTreatmentTable>[] => [
{ type: "globalIndex", width: 56, label: "序号" },
{ type: "selection", width: 48, fixed: "left" },
{ prop: "combination_name", label: "杂交组合", minWidth: 140, showOverflowTooltip: true },
{ prop: "treatment_method", label: "处理方式", minWidth: 140, showOverflowTooltip: true },
{ prop: "treatment_start", label: "处理开始日期", minWidth: 140, showOverflowTooltip: true },
{ prop: "treatment_end", label: "处理结束日期", minWidth: 140, showOverflowTooltip: true },
{ prop: "germination_rate", label: "发芽率(%)", minWidth: 100 },
{ prop: "bre_personnel_name", label: "种子处理人", minWidth: 140, showOverflowTooltip: true },
{
prop: "created_time",
label: "创建时间",
width: 168,
sortable: true,
showOverflowTooltip: true,
},
{
prop: "updated_time",
label: "更新时间",
width: 168,
sortable: true,
showOverflowTooltip: true,
},
{
prop: "created_by",
label: "创建人",
minWidth: 100,
formatter: (row: SeedTreatmentTable) => row.created_by?.name ?? "—",
},
{
prop: "updated_by",
label: "更新人",
minWidth: 100,
formatter: (row: SeedTreatmentTable) => row.updated_by?.name ?? "—",
},
{
prop: "operation",
label: "操作",
width: 180,
fixed: "right",
align: "center",
formatter: (row: SeedTreatmentTable) => formatSeedTreatmentOperationCell(row),
},
],
},
});
const SeedTreatmentCrudCols = toCrudCols(columns);
const exportQueryParams = computed(() => {
return stripPaginationParams(searchParams as Record<string, unknown>);
});
const SeedTreatmentImportContentConfig = computed<IContentConfig>(() => ({
permPrefix: "module_bre:seed_treatment",
cols: SeedTreatmentCrudCols.value,
indexAction: async () => ({}),
importTemplate: () => SeedTreatmentAPI.downloadTemplateSeedTreatment(),
}));
const SeedTreatmentExportContentConfig = computed(() => ({
permPrefix: "module_bre:seed_treatment",
cols: SeedTreatmentCrudCols.value,
exportsBlobAction: async (params: IObject) => {
const merged = {
...(exportQueryParams.value as unknown as Record<string, unknown>),
...params,
} as unknown as SeedTreatmentPageQuery;
const res = await SeedTreatmentAPI.exportSeedTreatment(merged);
return res.data as Blob;
},
}));
const { dialogVisible } = useCrudDialog();
const detailFormData = ref<SeedTreatmentTable>({});
const SeedTreatmentDetailItems: import("@/components/others/fa-descriptions/index.vue").DescriptionsItem[] = [
{ label: "杂交组合", prop: "combination_name" },
{ label: "处理方式", prop: "treatment_method" },
{ label: "处理开始日期", prop: "treatment_start" },
{ label: "处理结束日期", prop: "treatment_end" },
{ label: "发芽率(%)", prop: "germination_rate" },
{ label: "种子处理人", prop: "bre_personnel_name" },
{ label: "备注", prop: "remark" },
{ label: "UUID", prop: "uuid" },
{ label: "创建人", prop: "created_by.name" },
{ label: "更新人", prop: "updated_by.name" },
{ label: "创建时间", prop: "created_time" },
{ label: "更新时间", prop: "updated_time" },
];
const SeedTreatmentDialogFormItems = computed<FormItem[]>(() => [
{
key: "combination_id",
label: "杂交组合",
type: "select",
props: {
placeholder: "请选择杂交组合",
options: cross_combinationOptions.value,
clearable: true,
filterable: true,
},
span: 12,
},
{
key: "treatment_method",
label: "处理方式",
type: "radiogroup",
props: {
placeholder: "请选择处理方式",
options: [{ label: "沙藏", value: "沙藏" }, { label: "层积", value: "层积" }, { label: "低温冷藏", value: "低温冷藏" }, { label: "常温", value: "常温" }],
clearable: true,
},
span: 12,
},
{
key: "treatment_start",
label: "处理开始日期",
type: "date",
props: {
type: "date",
placeholder: "请选择处理开始日期",
},
span: 12,
},
{
key: "treatment_end",
label: "处理结束日期",
type: "date",
props: {
type: "date",
placeholder: "请选择处理结束日期",
},
span: 12,
},
{
key: "germination_rate",
label: "发芽率(%)",
type: "number",
props: { placeholder: "请输入发芽率(%)" },
span: 12,
},
{
key: "bre_personnel_id",
label: "种子处理人",
type: "select",
props: {
placeholder: "请选择种子处理人",
options: personnelOptions.value,
clearable: true,
filterable: true,
},
span: 12,
},
{
key: "remark",
label: "备注",
type: "input",
props: { type: "textarea", rows: 3, placeholder: "请输入备注" },
span: 24,
},
]);
const formData = ref<SeedTreatmentForm>(createInitialFormData());
const rules = reactive({
combination_id: [{ required: true, message: "请选择杂交组合", trigger: "change" }],
});
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const SeedTreatmentFormRenderKey = ref(0);
const crud = useCrudForm<SeedTreatmentForm>({
formData,
initialFormData: createInitialFormData(),
dialogVisible,
dataFormRef,
formRenderKey: SeedTreatmentFormRenderKey,
detailApi: SeedTreatmentAPI.getSeedTreatmentDetail,
createApi: SeedTreatmentAPI.createSeedTreatment,
updateApi: SeedTreatmentAPI.updateSeedTreatment,
titles: { create: "新增种子处理", update: "修改种子处理", detail: "种子处理详情" },
detailFormData,
onCreateSuccess: async () => {
await refreshCreate();
},
onUpdateSuccess: async () => {
await refreshUpdate();
},
});
const { submitLoading } = crud;
const { importVisible, exportVisible, openImport, openExport } = useImportExport();
const handleSearch = async (params: SeedTreatmentSearchFormParams) => {
await searchBarRef.value?.validate();
replaceSearchParams({
combination_id: params.combination_id,
treatment_method: params.treatment_method,
bre_personnel_id: params.bre_personnel_id,
created_id: params.created_id ?? undefined,
updated_id: params.updated_id ?? undefined,
created_time:
Array.isArray(params.created_time) && params.created_time.length === 2
? params.created_time
: undefined,
updated_time:
Array.isArray(params.updated_time) && params.updated_time.length === 2
? params.updated_time
: undefined,
} as Record<string, unknown>);
await getData();
};
const onResetSearch = async () => {
searchForm.value = {
combination_id: undefined,
treatment_method: undefined,
bre_personnel_id: undefined,
created_id: undefined,
updated_id: undefined,
created_time: [],
updated_time: [],
};
await resetSearchParams();
};
function buildSeedTreatmentRowActions(row: SeedTreatmentTable): TableOperationAction[] {
const all: TableOperationAction[] = [
{
key: "detail",
label: "详情",
artType: "view",
perm: "module_bre:seed_treatment:detail",
run: () => void crud.handleOpenDialog("detail", row.id),
},
{
key: "edit",
label: "编辑",
artType: "edit",
icon: "ri:edit-2-line",
perm: "module_bre:seed_treatment:update",
run: () => void crud.handleOpenDialog("update", row.id),
},
{
key: "delete",
label: "删除",
artType: "delete",
icon: "ri:delete-bin-4-line",
perm: "module_bre:seed_treatment:delete",
run: () => deleteSeedTreatmentRow(row),
},
];
return all;
}
function formatSeedTreatmentOperationCell(row: SeedTreatmentTable) {
return renderTableOperationCell(buildSeedTreatmentRowActions(row), {
wrapperClass: "inline-flex flex-wrap items-center justify-end gap-1",
});
}
async function handleAdd() {
createLoading.value = true;
try {
await crud.handleOpenDialog("create");
} finally {
createLoading.value = false;
}
}
const deleteSeedTreatmentRow = async (row: SeedTreatmentTable) => {
if (!row.id) return;
try {
await confirmDelete(`确定删除「${row.id ?? row.id}」吗?此操作不可恢复!`);
await SeedTreatmentAPI.deleteSeedTreatment([row.id!]);
faTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} catch {
// 用户取消
}
};
async function handleBatchDelete() {
const ids = selectedIds.value;
if (ids.length === 0) return;
try {
await confirmBatchDelete(ids.length);
batchDeleting.value = true;
await SeedTreatmentAPI.deleteSeedTreatment(ids);
faTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} catch {
// 用户取消
} finally {
batchDeleting.value = false;
}
}
async function handleCrudImportUpload(uploadFormData: FormData) {
try {
const res = await SeedTreatmentAPI.importSeedTreatment(uploadFormData);
if (res.data.code === ResultEnum.SUCCESS) {
ElMessage.success(res.data.msg || "导入成功");
importVisible.value = false;
await refreshData();
}
} catch (error: unknown) {
if (import.meta.env.DEV) console.error("[Import]", error);
}
}
onMounted(() => {
loadCrossCombinationOptions();
loadPersonnelOptions();
});
</script>