刘光辉
5 小时以前 cf11e63b659afcc9792ab3e395f1b45d844431a8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import type { DmsPrintConfig } from '#/components/GlobalOfficeDocumentModal/types';
 
import { v4 as uuidv4 } from 'uuid';
 
import { defHttp } from '#/api/request';
 
export interface DmsPrintBatch {
  id: string;
  pages: number[];
  items: number[];
  state: 'READY' | 'SENDING' | 'SUBMITTED';
  token?: string;
}
 
export interface DmsPrintAttempt {
  id: string;
  tenantId: string;
  userId: string;
  taskId: string;
  fileVersionId: string;
  copies: number;
  state: 'OPEN' | 'CONFIRMED' | 'CLOSED';
  batchesJson: string;
  numbersJson: string;
}
 
const endpoint = '/api/dms/biz/wenjian/dayin/renwu/';
async function request<T>(path: string, data: unknown): Promise<T> {
  const response = await defHttp.post<{ code: number; data: T; msg?: string }>({ url: endpoint + path, data }, { errorMessageMode: 'none' });
  if (response.code !== 200) throw new Error(response.msg || '保存打印发送进度失败');
  return response.data;
}
 
/** Reuse fixed task numbers; the online form controls barcode display text. */
export async function loadDmsPrintPreviewNumber(taskId: string, fileVersionId: string) {
  return request<import('./dmsPrintBarcode').DmsFixedPrintNumber>('yulan-canshu', { taskId, fileVersionId });
}
 
export function prepareDmsPrintAttempt(config: DmsPrintConfig, copies: number) {
  return request<DmsPrintAttempt>('zhunbei-fasong', {
    requestId: uuidv4(),
    taskId: config.printTaskId,
    fileVersionId: config.fileVersionId,
    copies,
  });
}
 
export function attemptContext(attempt: DmsPrintAttempt) {
  return { requestId: attempt.id, taskId: attempt.taskId, fileVersionId: attempt.fileVersionId, copies: attempt.copies };
}
 
export function updateDmsPrintAttempt(attempt: DmsPrintAttempt, action: string, data: Record<string, unknown> = {}) {
  return request<DmsPrintAttempt>(action, { ...attemptContext(attempt), ...data });
}
 
export function attemptBatches(attempt: DmsPrintAttempt): DmsPrintBatch[] {
  return JSON.parse(attempt.batchesJson);
}
 
export async function confirmDmsPrintAttempt(attempt: DmsPrintAttempt) {
  await request('queren-fasong', { ...attemptContext(attempt), clientResult: 'SUBMITTED' });
}
 
export async function finishDmsPrintAttempt(attempt: DmsPrintAttempt) {
  await confirmDmsPrintAttempt(attempt);
  await request('jieshu-fasong', attemptContext(attempt));
}
 
function receiptKey(attempt: DmsPrintAttempt, batchId: string) {
  return `dms-print-receipt:${encodeURIComponent(attempt.tenantId)}:${encodeURIComponent(attempt.userId)}:${attempt.id}:${batchId}`;
}
 
/** 只有实际成功回调才能写入此 outbox;按租户/账号隔离,恢复时仍由服务端核对令牌。 */
export async function recordDmsBatchSubmitted(attempt: DmsPrintAttempt, batch: DmsPrintBatch, token: string) {
  const key = receiptKey(attempt, batch.id);
  try {
    localStorage.setItem(key, token);
  } catch {
    /* 服务端仍为权威;本地存储不可用时不能假定成功。 */
  }
  const saved = await updateDmsPrintAttempt(attempt, 'queren-pici', { batchId: batch.id, token });
  try {
    localStorage.removeItem(key);
  } catch {
    /* 重复回执由服务端幂等处理。 */
  }
  // 晚回传同样可推进正式确认,即使原页面等待已经超时。
  if (attemptBatches(saved).every((item) => item.state === 'SUBMITTED')) await confirmDmsPrintAttempt(saved);
  return saved;
}
 
export async function recoverDmsBatchReceipts(attempt: DmsPrintAttempt) {
  let saved = attempt;
  for (const batch of attemptBatches(attempt)) {
    let token: null | string = null;
    try {
      token = localStorage.getItem(receiptKey(attempt, batch.id));
    } catch {
      /* 不具备本地证据时保持未知。 */
    }
    if (token) saved = await recordDmsBatchSubmitted(saved, batch, token);
  }
  return saved;
}