Files
qhmes/jeecgboot-vue3/src/views/mes/material/MesRawMaterialInspectStdList.vue

385 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<template #tableTitle>
<a-button type="primary" v-auth="'mes:mes_raw_material_inspect_std:add'" @click="handleAdd" preIcon="ant-design:plus-outlined">
新增
</a-button>
<JDictSelectTag
v-model:value="printDotWsUrl"
dictCode="xslmes_print_dot_ws"
:showChooseOption="false"
style="width: 280px; margin-left: 8px"
placeholder="选择 PrintDot 地址"
@change="onPrintDotWsUrlChange"
/>
<a-button v-if="!printDotConnected" style="margin-left: 8px" @click="downloadPrintPlugin">下载打印插件</a-button>
<a-select
v-model:value="selectedPrinterName"
:options="printerOptions"
style="width: 220px; margin-left: 8px"
allow-clear
show-search
option-filter-prop="label"
:placeholder="printerSelectPlaceholder"
/>
<a-button style="margin-left: 8px" @click="() => refreshPrinterOptions(true)">刷新打印机</a-button>
<a-button
type="primary"
ghost
v-auth="'mes:mes_raw_material_inspect_std:edit'"
:loading="printLoading"
:disabled="selectedRowKeys.length === 0"
@click="handlePrintSelected"
>
<Icon icon="ant-design:printer-outlined" />
打印选中
</a-button>
</template>
<template #action="{ record }">
<TableAction
:actions="getTableAction(record)"
:dropDownActions="getDropDownAction(record)"
/>
</template>
</BasicTable>
<MesRawMaterialInspectStdModal @register="registerModal" @success="reload" />
<MesRawMaterialInspectStdPrintPreviewModal
v-model:open="printPreviewOpen"
:std-id="printPreviewStdId"
:standard-no="printPreviewStandardNo"
/>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, watch } from 'vue';
import { Icon } from '/@/components/Icon';
import { BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage';
import { initDictOptions } from '/@/utils/dict';
import { JDictSelectTag } from '/@/components/Form';
import MesRawMaterialInspectStdModal from './modules/MesRawMaterialInspectStdModal.vue';
import MesRawMaterialInspectStdPrintPreviewModal from './modules/MesRawMaterialInspectStdPrintPreviewModal.vue';
import { columns, searchFormSchema } from './MesRawMaterialInspectStd.data';
import { list, deleteOne, setEnable, prepareNativePrint } from './MesRawMaterialInspectStd.api';
import { useMessage } from '/@/hooks/web/useMessage';
import {
PRINT_TEMPLATE_SELECTED_PRINTER_KEY,
printNativeSchemaViaPrintDot,
} from '/@/views/print/template/utils/printNativeViaPrintDot';
import { normalizeImportedNativeSchema } from '/@/views/print/template/native/core/nativeSchemaNormalize';
import {
fetchPrintDotPrinters,
getPrintDotBridgeConfig,
setPrintDotBridgeConfig,
} from '/@/views/print/template/utils/printDotBridge';
const { createMessage } = useMessage();
const PRINT_DOT_WS_DICT = 'xslmes_print_dot_ws';
const printDotWsUrl = ref('');
const printDotConnected = ref(false);
function persistPrintDotConfig() {
setPrintDotBridgeConfig(String(printDotWsUrl.value || '').trim(), '');
void refreshPrinterOptions(false);
}
function onPrintDotWsUrlChange() {
printDotConnected.value = false;
persistPrintDotConfig();
}
function downloadPrintPlugin() {
const base = import.meta.env.BASE_URL || '/';
const normalizedBase = base.endsWith('/') ? base : `${base}/`;
const url = `${normalizedBase}print-plugin/XSL-PrintDot.exe`;
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'XSL-PrintDot.exe');
link.rel = 'noopener';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
const [registerModal, { openModal }] = useModal();
const { tableContext } = useListPage({
tableProps: {
title: '原材料检验标准',
api: list,
columns,
canResize: true,
formConfig: { labelWidth: 100, schemas: searchFormSchema, autoSubmitOnEnter: true },
actionColumn: { width: 280, fixed: 'right' },
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys, selectedRows }] = tableContext;
const printPreviewOpen = ref(false);
const printPreviewStdId = ref<string | null>(null);
const printPreviewStandardNo = ref<string | undefined>(undefined);
function handlePrintPreview(record: Recordable) {
printPreviewStdId.value = record.id as string;
printPreviewStandardNo.value = record.standardNo as string | undefined;
printPreviewOpen.value = true;
}
const printerOptions = ref<Array<{ label: string; value: string }>>([]);
const selectedPrinterName = ref<string>('__system_default__');
const printLoading = ref(false);
const PRINT_ROW_LOADING_KEY = 'mesRawMaterialInspectStd-print-row';
const PRINT_BATCH_LOADING_KEY = 'mesRawMaterialInspectStd-print-batch';
const printerSelectPlaceholder = '选择打印机PrintDot 桥接)';
watch(selectedPrinterName, (v) => {
if (v) {
localStorage.setItem(PRINT_TEMPLATE_SELECTED_PRINTER_KEY, v);
}
});
async function refreshPrinterOptions(showMessage = true) {
const optionMap = new Map<string, { label: string; value: string }>();
optionMap.set('__system_default__', { label: '系统默认打印机', value: '__system_default__' });
try {
const dotList = await fetchPrintDotPrinters();
printDotConnected.value = true;
dotList.forEach((p) => {
const name = String(p.name || '').trim();
if (!name) return;
const defMark = p.isDefault ? '(默认)' : '';
optionMap.set(name, { label: `${name}${defMark}`, value: name });
});
printerOptions.value = Array.from(optionMap.values());
if (showMessage) {
if (dotList.length) {
createMessage.success(`已从 PrintDot 桥接识别 ${dotList.length} 台打印机`);
} else {
createMessage.warning('PrintDot 已连接但未返回打印机列表');
}
}
} catch (e: unknown) {
printDotConnected.value = false;
printerOptions.value = Array.from(optionMap.values());
if (showMessage) {
createMessage.warning(`PrintDot${e instanceof Error ? e.message : String(e)}`);
}
}
}
async function executePrint(record: Recordable, options?: { silentSuccess?: boolean }) {
try {
const prep = (await prepareNativePrint(record.id as string)) as Record<string, unknown>;
const templateJsonRaw = prep.templateJson as string;
const printData = prep.printData as Record<string, unknown>;
const paperWidthMm = Number((prep as any).paperWidthMm ?? 0);
const paperHeightMm = Number((prep as any).paperHeightMm ?? 0);
const paperOrientation = String((prep as any).paperOrientation || '').toLowerCase();
if (!templateJsonRaw) {
throw new Error('模板 JSON 为空');
}
let raw: unknown;
try {
raw = typeof templateJsonRaw === 'string' ? JSON.parse(templateJsonRaw) : templateJsonRaw;
} catch {
throw new Error('模板 JSON 格式错误');
}
const schema = normalizeImportedNativeSchema(raw);
if (paperWidthMm > 0 && paperHeightMm > 0) {
const orient = paperOrientation === 'landscape' ? 'landscape' : paperOrientation === 'portrait' ? 'portrait' : '';
const normalized =
orient === 'landscape'
? {
width: Math.max(paperWidthMm, paperHeightMm),
height: Math.min(paperWidthMm, paperHeightMm),
}
: orient === 'portrait'
? {
width: Math.min(paperWidthMm, paperHeightMm),
height: Math.max(paperWidthMm, paperHeightMm),
}
: {
width: paperWidthMm,
height: paperHeightMm,
};
schema.page.width = normalized.width;
schema.page.height = normalized.height;
}
const no = String(record.standardNo || '').trim();
await printNativeSchemaViaPrintDot({
schema,
data: printData as Record<string, unknown>,
jobName: `原材料检验标准-${no || record.id}.pdf`,
printerSelection:
selectedPrinterName.value ||
localStorage.getItem(PRINT_TEMPLATE_SELECTED_PRINTER_KEY) ||
'__system_default__',
});
if (!options?.silentSuccess) {
createMessage.success('已通过 PrintDot 提交打印');
}
} catch (e: unknown) {
throw new Error(e instanceof Error ? e.message : String(e));
}
}
function handlePrintSelected() {
const rows = selectedRows.value || [];
if (!rows.length) {
createMessage.warning('请至少勾选一条记录后再点击「打印选中」');
return;
}
printLoading.value = true;
createMessage.destroy(PRINT_BATCH_LOADING_KEY);
createMessage.loading({
content: `正在打印 ${rows.length} 条记录,请稍候…`,
key: PRINT_BATCH_LOADING_KEY,
duration: 0,
});
(async () => {
try {
let ok = 0;
let firstError = '';
for (const row of rows) {
try {
await executePrint(row, { silentSuccess: true });
ok += 1;
} catch (e: unknown) {
if (!firstError) {
firstError = e instanceof Error ? e.message : String(e);
}
}
}
if (ok === rows.length) {
createMessage.success(`已通过 PrintDot 提交 ${ok} 条打印任务`);
} else {
createMessage.warning(
`打印完成:成功 ${ok},失败 ${rows.length - ok}${firstError ? `。首条错误:${firstError}` : ''}`,
);
}
} finally {
createMessage.destroy(PRINT_BATCH_LOADING_KEY);
printLoading.value = false;
}
})();
}
async function handlePrintRow(record: Recordable) {
printLoading.value = true;
createMessage.destroy(PRINT_ROW_LOADING_KEY);
createMessage.loading({
content: '正在生成 PDF 并提交打印,版面复杂时可能需数十秒,请稍候…',
key: PRINT_ROW_LOADING_KEY,
duration: 0,
});
try {
await executePrint(record, { silentSuccess: true });
createMessage.success('已通过 PrintDot 提交打印');
} catch (e: unknown) {
createMessage.error(e instanceof Error ? e.message : String(e));
} finally {
createMessage.destroy(PRINT_ROW_LOADING_KEY);
printLoading.value = false;
}
}
onMounted(async () => {
const cfg = getPrintDotBridgeConfig();
setPrintDotBridgeConfig(cfg.wsUrl, '');
printDotWsUrl.value = cfg.wsUrl || '';
try {
const raw = await initDictOptions(PRINT_DOT_WS_DICT);
const items = Array.isArray(raw) ? raw : [];
const values = items
.map((it: Recordable) => String(it.value ?? it.itemValue ?? '').trim())
.filter(Boolean);
const valueSet = new Set(values);
if (valueSet.size && printDotWsUrl.value && !valueSet.has(String(printDotWsUrl.value).trim())) {
printDotWsUrl.value = values[0];
setPrintDotBridgeConfig(printDotWsUrl.value, '');
} else if (valueSet.size && !printDotWsUrl.value.trim()) {
printDotWsUrl.value = values[0];
setPrintDotBridgeConfig(printDotWsUrl.value, '');
}
} catch {
/* 字典未配置时沿用 localStorage */
}
const savedPrinter = localStorage.getItem(PRINT_TEMPLATE_SELECTED_PRINTER_KEY);
if (savedPrinter) {
selectedPrinterName.value = savedPrinter;
}
await refreshPrinterOptions(false);
});
function handleAdd() {
openModal(true, { isUpdate: false, showFooter: true });
}
function handleEdit(record: Recordable) {
openModal(true, { record, isUpdate: true, showFooter: true });
}
function handleDetail(record: Recordable) {
openModal(true, { record, isUpdate: true, showFooter: false });
}
async function handleDelete(record) {
await deleteOne({ id: record.id }, reload);
}
async function handleEnable(record: Recordable) {
await setEnable({ id: record.id, enableFlag: 1 });
createMessage.success('已启用');
reload();
}
async function handleDisable(record: Recordable) {
await setEnable({ id: record.id, enableFlag: 0 });
createMessage.success('已停用');
reload();
}
function getTableAction(record: Recordable) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'mes:mes_raw_material_inspect_std:edit',
},
{
label: '打印预览',
onClick: handlePrintPreview.bind(null, record),
auth: 'mes:mes_raw_material_inspect_std:edit',
},
{
label: '打印',
onClick: handlePrintRow.bind(null, record),
auth: 'mes:mes_raw_material_inspect_std:edit',
},
];
}
function getDropDownAction(record: Recordable) {
const actions: any[] = [
{ label: '详情', onClick: handleDetail.bind(null, record) },
{
label: '删除',
popConfirm: { title: '是否确认删除', confirm: handleDelete.bind(null, record) },
auth: 'mes:mes_raw_material_inspect_std:delete',
},
];
if (record.enableFlag !== 1) {
actions.push({
label: '启用',
auth: 'mes:mes_raw_material_inspect_std:enable',
popConfirm: { title: '启用后将记录当前时间到生效日期', confirm: () => handleEnable(record) },
});
} else {
actions.push({
label: '停用',
auth: 'mes:mes_raw_material_inspect_std:enable',
popConfirm: { title: '停用后将清除生效日期', confirm: () => handleDisable(record) },
});
}
return actions;
}
</script>