刘光辉
13 小时以前 0dfe84494048ce27ba8449831782128412d3eb13
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import type { FillFieldType } from '../domain/types';
 
export function inspectFieldsCommand(): string {
  function errorMessage(error: unknown): string {
    return error instanceof Error ? error.message : String(error);
  }
 
  function textOf(control: any): string {
    return String(control.GetRange().GetText() ?? '');
  }
 
  function kindOf(control: any): FillFieldType {
    if (control.IsCheckBox?.()) return 'checkbox';
    if (control.IsComboBox?.() || control.IsDropDownList?.()) return 'select';
    if (control.IsDatePicker?.()) return 'date';
    if (control.IsBlockLevel?.()) return 'multiline';
    return 'text';
  }
 
  function optionsOf(control: any): Array<{ display: string; value: string }> {
    const list = control.GetDropdownList?.();
    if (!list?.GetElementsCount || !list.GetItem) return [];
    const options = [];
    for (let index = 0; index < list.GetElementsCount(); index += 1) {
      const item = list.GetItem(index);
      options.push({ display: String(item.GetText()), value: String(item.GetValue()) });
    }
    return options;
  }
 
  function readValue(control: any, type: FillFieldType): boolean | string {
    const text = textOf(control);
    if (type === 'checkbox') return ['☒', '☑'].includes(text);
    if (type === 'select') return optionsOf(control).find((item) => item.display === text)?.value ?? '';
    return text;
  }
 
  try {
    const controls = Api.GetDocument().GetAllContentControls();
    const fields = controls.filter((control: any) => /^eln\.(field\.[^.]+|repeat\.[^.]+\.[^.]+\.[^.]+)$/u.test(control.GetTag())).map((control: any) => {
      const type = kindOf(control);
      return {
        alias: String(control.GetAlias?.() ?? ''),
        currentValue: readValue(control, type),
        internalId: String(control.GetInternalId?.() ?? ''),
        options: type === 'select' ? optionsOf(control) : [],
        tag: String(control.GetTag()),
        type,
      };
    });
    const tags = fields.map((field: any) => field.tag);
    if (new Set(tags).size !== tags.length) throw new Error('文档存在重复字段 Tag');
    return JSON.stringify({ ok: true, fields });
  } catch (error) {
    return JSON.stringify({ ok: false, error: errorMessage(error), fields: [] });
  }
}
 
export function applyFieldsCommand(): string {
  function errorMessage(error: unknown): string {
    return error instanceof Error ? error.message : String(error);
  }
 
  function textOf(control: any): string {
    return String(control.GetRange().GetText() ?? '');
  }
 
  function kindOf(control: any): FillFieldType {
    if (control.IsCheckBox?.()) return 'checkbox';
    if (control.IsComboBox?.() || control.IsDropDownList?.()) return 'select';
    if (control.IsDatePicker?.()) return 'date';
    if (control.IsBlockLevel?.()) return 'multiline';
    return 'text';
  }
 
  function optionsOf(control: any): Array<{ display: string; value: string }> {
    const list = control.GetDropdownList?.();
    if (!list?.GetElementsCount || !list.GetItem) return [];
    const options = [];
    for (let index = 0; index < list.GetElementsCount(); index += 1) {
      const item = list.GetItem(index);
      options.push({ display: String(item.GetText()), value: String(item.GetValue()) });
    }
    return options;
  }
 
  function readValue(control: any, type: FillFieldType): boolean | string {
    const text = textOf(control);
    if (type === 'checkbox') return ['☒', '☑'].includes(text);
    if (type === 'select') return optionsOf(control).find((item) => item.display === text)?.value ?? '';
    return text;
  }
 
  function writeValue(control: any, type: FillFieldType, value: boolean | string): void {
    if (type === 'checkbox') {
      control.SetCheckBoxChecked(Boolean(value));
      return;
    }
    if (type === 'select') {
      if (!optionsOf(control).some((item) => item.value === value)) throw new Error('下拉值不在文档选项中');
      control.SelectListItem(value);
      return;
    }
    if (type === 'date') {
      const parts = String(value).split('-').map(Number);
      if (parts.length !== 3 || parts.some((part) => !Number.isInteger(part))) throw new Error('日期格式无效');
      control.SetDate(new Date(parts[0]!, parts[1]! - 1, parts[2]!));
      return;
    }
    control.RemoveAllElements();
    if (type === 'multiline') {
      String(value).split('\n').forEach((line, index) => {
        const paragraph = Api.CreateParagraph();
        const run = Api.CreateRun();
        run.AddText(line);
        paragraph.AddElement(run);
        control.AddElement(paragraph, index);
      });
      return;
    }
    const run = Api.CreateRun();
    run.AddText(String(value));
    control.AddElement(run, 0);
  }
 
  const changes = Asc.scope.elnTemplateFillChanges;
  if (!Array.isArray(changes)) return JSON.stringify({ ok: false, error: '缺少字段修改', results: [] });
  const controls = Api.GetDocument().GetAllContentControls();
  const results = changes.map((change) => {
    const matches = controls.filter((control: any) => control.GetTag() === change.tag);
    if (matches.length !== 1) return { tag: change.tag, ok: false, error: '无法按 Tag 定位唯一控件' };
    const control = matches[0];
    const actualType = kindOf(control);
    if (actualType !== change.type) return { tag: change.tag, ok: false, error: '字段类型与文档控件不一致' };
    const before = readValue(control, actualType);
    try {
      writeValue(control, actualType, change.value);
      if (readValue(control, actualType) !== change.value) throw new Error('字段写入后回读不一致');
      return { tag: change.tag, ok: true };
    } catch (error) {
      try { writeValue(control, actualType, before); } catch { /* 原生撤销是最终恢复手段。 */ }
      return { tag: change.tag, ok: false, error: errorMessage(error) };
    }
  });
  return JSON.stringify({ ok: true, results });
}