diff --git a/api-report/apps/api/src/modules/interaction/index.d.ts b/api-report/apps/api/src/modules/interaction/index.d.ts
index 9caf8c3..21a234a 100644
--- a/api-report/apps/api/src/modules/interaction/index.d.ts
+++ b/api-report/apps/api/src/modules/interaction/index.d.ts
@@ -7,6 +7,6 @@ export type { Audience, Clock, HumanEventPublisher, IdGenerator, InteractionStor
export type { InteractionServiceDeps } from './internal/usecase/interaction-service.ts';
export { createInteractionService, visibleTo } from './internal/usecase/interaction-service.ts';
export { CONTROL_HOLDERS, checkTemplate, handoverHappens, inputControl, INTERACTION_PHASES, outputControl, templateIsSafe, } from './internal/domain/control-handover.ts';
-export { renderView, renderTemplate, renderRows, escapeHtml, displayValue } from './internal/domain/view-render.ts';
+export { renderView, renderTemplate, renderRows, fillOptions, escapeHtml, displayValue } from './internal/domain/view-render.ts';
export { createInteractionStore } from './internal/adapter/interaction-store.ts';
export { chatMessageTable, taskViewTable } from './internal/adapter/interaction-schema.ts';
diff --git a/apps/api/src/modules/interaction/__tests__/view-render.test.ts b/apps/api/src/modules/interaction/__tests__/view-render.test.ts
index 1656502..cdf1888 100644
--- a/apps/api/src/modules/interaction/__tests__/view-render.test.ts
+++ b/apps/api/src/modules/interaction/__tests__/view-render.test.ts
@@ -435,3 +435,46 @@ describe('嵌套行模版与 data-by —— 一个候选一张表', () => {
expect(all.split('使能逻辑').length - 1).toBe(2);
});
});
+
+describe('data-options:下拉的选项从台账现读', () => {
+ const scope = {
+ 'parts.chip_type': [
+ { type_id: 1, type_name: 'DC-DC 降压稳压器' },
+ { type_id: 2, type_name: 'LDO 线性稳压器' },
+ ],
+ chip_type_id: 2,
+ };
+
+ it('把选项铺进去,并留一个空选项(「还没选」要说得出来)', () => {
+ const html = '';
+ const out = renderView(html, scope);
+ expect(out).toContain('');
+ expect(out).toContain('');
+ expect(out).toContain('');
+ });
+
+ it('选项文字要转义 —— 台账里的值是人填的', () => {
+ const out = renderView(
+ '',
+ { 't.t': [{ v: 'x', l: '坏' }], c: '' },
+ );
+ expect(out).toContain('<b>坏</b>');
+ expect(out).not.toContain('坏');
+ });
+
+ it('地址取不到 → 只留那个空选项,不塞假数据(界面不撒谎)', () => {
+ const out = renderView('', {});
+ expect(out).toContain('');
+ expect(out).not.toContain('undefined');
+ });
+
+ it('行内的下拉:每一行都铺同一份选项,选中的按各行自己的值', () => {
+ const html =
+ '
' +
+ '
' +
+ '';
+ const out = renderView(html, { ...scope, 'mine:a.b': [{ chip_type_id: 1 }, { chip_type_id: 2 }] });
+ expect(out.match(/