字典选择器 ​
在选择器上管理字典选项、重载和请求取消。
基础用法 ​
示例通过本地 provider 获取字典,支持模型更新、暂停与重载。所有请求都留在演示内部。
点击“读取当前标签”读取实例的只读 selectedLabel:空模型返回空字符串,选择后返回当前标签。 完整说明。
本地字典与生命周期
<template><StandaloneDemo /></template>
<script lang="ts" setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external: any = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules: any = {
"Demo.vue": (module: any, exports: any, require: any) => {
"use strict";
var __importDefault: any = function (mod?: any) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
const Child_vue_1: any = __importDefault(require("./Child.vue"));
const provider_js_1: any = require("./provider.js");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectBasicDemoExample' },
__name: 'Demo',
setup(__props?: any) {
const host: any = (0, vue_3.ref)();
let app: any;
(0, vue_3.onMounted)(() => {
if (!host.value)
return;
app = (0, vue_3.createApp)(Child_vue_1.default);
(0, ui_1.provideAsamData)(app, provider_js_1.provider, { scope: 'doc-status' });
app.mount(host.value);
});
(0, vue_3.onBeforeUnmount)(() => app?.unmount());
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"Child.vue": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = { class: "data-demo demo-spacing-1" };
const _hoisted_2: any = {
class: "example-paragraph",
role: "status"
};
const _hoisted_3: any = { "data-testid": "selected-label" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectBasicExample' },
__name: 'Child',
setup(__props?: any) {
const value: any = (0, vue_3.ref)(null);
const active: any = (0, vue_3.ref)(true);
const multipleMode: any = (0, vue_3.ref)(false);
const multipleValue: any = (0, vue_3.ref)([]);
const control: any = (0, vue_3.ref)();
const selectedLabel: any = (0, vue_3.ref)('');
function readSelectedLabel() {
selectedLabel.value = control.value?.selectedLabel ?? '';
}
const error: any = (0, vue_3.ref)('');
const result: any = (0, vue_3.ref)('');
async function reload() {
const response: any = await control.value?.reload({ force: true });
result.value = response?.status ?? 'cancelled';
}
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("section", _hoisted_1, [
(0, vue_2.createCommentVNode)(" prettier-ignore "),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamCheckboxItem), {
modelValue: active.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event?: any) => ((active).value = $event))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[12] || (_cache[12] = [
(0, vue_2.createTextVNode)("启用请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_2.createCommentVNode)(" prettier-ignore "),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamCheckboxItem), {
modelValue: multipleMode.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event?: any) => ((multipleMode).value = $event))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[13] || (_cache[13] = [
(0, vue_2.createTextVNode)("启用多选", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(!multipleMode.value)
? ((0, vue_2.openBlock)(), (0, vue_2.createBlock)((0, vue_2.unref)(ui_1.AsamDictSelect), {
key: 0,
ref_key: "control",
ref: control,
modelValue: value.value,
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event?: any) => ((value).value = $event)),
"dict-type": "doc-status",
active: active.value,
size: "default",
placeholder: "请选择或输入",
onError: _cache[3] || (_cache[3] = ($event?: any) => (error.value = $event.message)),
onSuccess: _cache[4] || (_cache[4] = ($event?: any) => (error.value = ''))
}, {
prefix: (0, vue_2.withCtx)(() => [...(_cache[14] || (_cache[14] = [
(0, vue_2.createElementVNode)("span", { "aria-hidden": "true" }, "状态", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "active"]))
: ((0, vue_2.openBlock)(), (0, vue_2.createBlock)((0, vue_2.unref)(ui_1.AsamDictSelect), {
key: 1,
ref_key: "control",
ref: control,
modelValue: multipleValue.value,
"onUpdate:modelValue": _cache[5] || (_cache[5] = ($event?: any) => ((multipleValue).value = $event)),
multiple: "",
"dict-type": "doc-status",
active: active.value,
size: "default",
placeholder: "请选择或输入",
onError: _cache[6] || (_cache[6] = ($event?: any) => (error.value = $event.message)),
onSuccess: _cache[7] || (_cache[7] = ($event?: any) => (error.value = ''))
}, {
prefix: (0, vue_2.withCtx)(() => [...(_cache[15] || (_cache[15] = [
(0, vue_2.createElementVNode)("span", { "aria-hidden": "true" }, "状态", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "active"])),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: !active.value,
onClick: reload
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[16] || (_cache[16] = [
(0, vue_2.createTextVNode)("强制重载", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[8] || (_cache[8] = ($event?: any) => (control.value?.cancel()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[17] || (_cache[17] = [
(0, vue_2.createTextVNode)("取消请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: readSelectedLabel
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[18] || (_cache[18] = [
(0, vue_2.createTextVNode)("读取当前标签", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[9] || (_cache[9] = ($event?: any) => (control.value?.focus()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[19] || (_cache[19] = [
(0, vue_2.createTextVNode)("聚焦选择器", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onMousedown: _cache[10] || (_cache[10] = (0, vue_2.withModifiers)(() => { }, ["prevent"])),
onClick: _cache[11] || (_cache[11] = ($event?: any) => (control.value?.blur()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[20] || (_cache[20] = [
(0, vue_2.createTextVNode)("失焦选择器", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createElementVNode)("p", _hoisted_2, (0, vue_2.toDisplayString)(result.value) + " " + (0, vue_2.toDisplayString)(error.value), 1 /* TEXT */),
(0, vue_2.createElementVNode)("pre", null, (0, vue_2.toDisplayString)(multipleMode.value ? multipleValue.value : value.value), 1 /* TEXT */),
(0, vue_2.createElementVNode)("pre", _hoisted_3, (0, vue_2.toDisplayString)(selectedLabel.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-453f7937";
},
"provider.ts": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.provider = void 0;
exports.provider = {
dict: {
async refresh(context?: any) {
context.signal.throwIfAborted();
},
async get(dictType?: any, context?: any) {
context.signal.throwIfAborted();
if (dictType !== 'doc-status')
throw new Error('未知演示字典');
return [
{ label: '准备', value: 'ready' },
{ label: '进行', value: 'running' }
];
}
}
};
},
};
const __dependencies: any = {"Demo.vue":{"./Child.vue":"Child.vue","./provider.js":"provider.ts"},"Child.vue":{},"provider.ts":{}};
const __cache: any = Object.create(null);
function __require(id: any): any {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module: any = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency: any) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-spacing-1[data-v-453f7937] {
display: grid;
gap: var(--asam-space-md);
}
p[data-v-453f7937]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template><StandaloneDemo /></template>
<script setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules = {
"Demo.vue": (module, exports, require) => {
"use strict";
var __importDefault = function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
const Child_vue_1 = __importDefault(require("./Child.vue"));
const provider_js_1 = require("./provider.js");
exports.default = Object.assign({ name: 'AsamDictSelectBasicDemoExample' }, {
__name: 'Demo',
setup(__props) {
const host = (0, vue_2.ref)();
let app;
(0, vue_2.onMounted)(() => {
if (!host.value)
return;
app = (0, vue_2.createApp)(Child_vue_1.default);
(0, ui_1.provideAsamData)(app, provider_js_1.provider, { scope: 'doc-status' });
app.mount(host.value);
});
(0, vue_2.onBeforeUnmount)(() => app?.unmount());
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"Child.vue": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = { class: "data-demo demo-spacing-1" };
const _hoisted_2 = {
class: "example-paragraph",
role: "status"
};
const _hoisted_3 = { "data-testid": "selected-label" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
exports.default = Object.assign({ name: 'AsamDictSelectBasicExample' }, {
__name: 'Child',
setup(__props) {
const value = (0, vue_2.ref)(null);
const active = (0, vue_2.ref)(true);
const multipleMode = (0, vue_2.ref)(false);
const multipleValue = (0, vue_2.ref)([]);
const control = (0, vue_2.ref)();
const selectedLabel = (0, vue_2.ref)('');
function readSelectedLabel() {
selectedLabel.value = control.value?.selectedLabel ?? '';
}
const error = (0, vue_2.ref)('');
const result = (0, vue_2.ref)('');
async function reload() {
const response = await control.value?.reload({ force: true });
result.value = response?.status ?? 'cancelled';
}
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("section", _hoisted_1, [
(0, vue_1.createCommentVNode)(" prettier-ignore "),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamCheckboxItem), {
modelValue: active.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => ((active).value = $event))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[12] || (_cache[12] = [
(0, vue_1.createTextVNode)("启用请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_1.createCommentVNode)(" prettier-ignore "),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamCheckboxItem), {
modelValue: multipleMode.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = $event => ((multipleMode).value = $event))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[13] || (_cache[13] = [
(0, vue_1.createTextVNode)("启用多选", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(!multipleMode.value)
? ((0, vue_1.openBlock)(), (0, vue_1.createBlock)((0, vue_1.unref)(ui_1.AsamDictSelect), {
key: 0,
ref_key: "control",
ref: control,
modelValue: value.value,
"onUpdate:modelValue": _cache[2] || (_cache[2] = $event => ((value).value = $event)),
"dict-type": "doc-status",
active: active.value,
size: "default",
placeholder: "请选择或输入",
onError: _cache[3] || (_cache[3] = $event => (error.value = $event.message)),
onSuccess: _cache[4] || (_cache[4] = $event => (error.value = ''))
}, {
prefix: (0, vue_1.withCtx)(() => [...(_cache[14] || (_cache[14] = [
(0, vue_1.createElementVNode)("span", { "aria-hidden": "true" }, "状态", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "active"]))
: ((0, vue_1.openBlock)(), (0, vue_1.createBlock)((0, vue_1.unref)(ui_1.AsamDictSelect), {
key: 1,
ref_key: "control",
ref: control,
modelValue: multipleValue.value,
"onUpdate:modelValue": _cache[5] || (_cache[5] = $event => ((multipleValue).value = $event)),
multiple: "",
"dict-type": "doc-status",
active: active.value,
size: "default",
placeholder: "请选择或输入",
onError: _cache[6] || (_cache[6] = $event => (error.value = $event.message)),
onSuccess: _cache[7] || (_cache[7] = $event => (error.value = ''))
}, {
prefix: (0, vue_1.withCtx)(() => [...(_cache[15] || (_cache[15] = [
(0, vue_1.createElementVNode)("span", { "aria-hidden": "true" }, "状态", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "active"])),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: !active.value,
onClick: reload
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[16] || (_cache[16] = [
(0, vue_1.createTextVNode)("强制重载", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled"]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[8] || (_cache[8] = $event => (control.value?.cancel()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[17] || (_cache[17] = [
(0, vue_1.createTextVNode)("取消请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: readSelectedLabel
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[18] || (_cache[18] = [
(0, vue_1.createTextVNode)("读取当前标签", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[9] || (_cache[9] = $event => (control.value?.focus()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[19] || (_cache[19] = [
(0, vue_1.createTextVNode)("聚焦选择器", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onMousedown: _cache[10] || (_cache[10] = (0, vue_1.withModifiers)(() => { }, ["prevent"])),
onClick: _cache[11] || (_cache[11] = $event => (control.value?.blur()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[20] || (_cache[20] = [
(0, vue_1.createTextVNode)("失焦选择器", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createElementVNode)("p", _hoisted_2, (0, vue_1.toDisplayString)(result.value) + " " + (0, vue_1.toDisplayString)(error.value), 1 /* TEXT */),
(0, vue_1.createElementVNode)("pre", null, (0, vue_1.toDisplayString)(multipleMode.value ? multipleValue.value : value.value), 1 /* TEXT */),
(0, vue_1.createElementVNode)("pre", _hoisted_3, (0, vue_1.toDisplayString)(selectedLabel.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-98fd6791";
},
"provider.js": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.provider = void 0;
exports.provider = {
dict: {
async refresh(context) {
context.signal.throwIfAborted();
},
async get(dictType, context) {
context.signal.throwIfAborted();
if (dictType !== 'doc-status')
throw new Error('未知演示字典');
return [
{ label: '准备', value: 'ready' },
{ label: '进行', value: 'running' }
];
}
}
};
},
};
const __dependencies = {"Demo.vue":{"./Child.vue":"Child.vue","./provider.js":"provider.js"},"Child.vue":{},"provider.js":{}};
const __cache = Object.create(null);
function __require(id) {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-spacing-1[data-v-98fd6791] {
display: grid;
gap: var(--asam-space-md);
}
p[data-v-98fd6791]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
本地创建与字典规范项 ​
allow-create 与 filterable 开启后,createOption(text) 同步返回完整 AsamOption<V, I>。 默认创建值为字符串;数字、布尔值或自定义 raw 必须提供类型一致的同步工厂。 示例包含独立 provider 初始化、完整实体工厂和来源接受同值项的对照。
本地创建、规范项与来源重置
<template><StandaloneDemo /></template>
<script lang="ts" setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external: any = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules: any = {
"Child.vue": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = { class: "data-demo demo-spacing-1" };
const _hoisted_2: any = { class: "actions" };
const _hoisted_3: any = {
class: "example-paragraph",
role: "status"
};
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectLocalCreationChild' },
__name: 'Child',
setup(__props?: any) {
const state: any = (0, vue_3.inject)('selection-local-demo');
if (!state)
throw new Error('Demo.vue 必须先配置演示 provider。');
const { tenant, failure, canonical }: any = state;
const value: any = (0, vue_3.ref)(null);
const control: any = (0, vue_3.ref)();
const createdTexts: any = (0, vue_3.ref)([]);
const providerValues: any = (0, vue_3.ref)([]);
const message: any = (0, vue_3.ref)('');
const result: any = (0, vue_3.ref)('');
const createOption: any = (text?: any) => {
createdTexts.value.push(text);
return { label: text, value: text, raw: { id: 'local-' + text, label: text, value: text } };
};
async function reload() {
await (0, vue_3.nextTick)();
result.value = (await control.value?.reload({ force: true }))?.status ?? 'cancelled';
if (result.value === 'success')
message.value = '';
}
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("section", _hoisted_1, [
(0, vue_2.createElementVNode)("div", _hoisted_2, [
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: reload
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[8] || (_cache[8] = [
(0, vue_2.createTextVNode)("强制重载", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[0] || (_cache[0] = ($event?: any) => (control.value?.clearCreatedOptions()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[9] || (_cache[9] = [
(0, vue_2.createTextVNode)("清空本地创建集合", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[1] || (_cache[1] = ($event?: any) => (value.value = null))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[10] || (_cache[10] = [
(0, vue_2.createTextVNode)("清空模型", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[2] || (_cache[2] = ($event?: any) => (tenant.value = (0, vue_2.unref)(tenant) === 'a' ? 'b' : 'a'))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[11] || (_cache[11] = [
(0, vue_2.createTextVNode)("切换逻辑来源", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamCheckboxItem), {
modelValue: (0, vue_2.unref)(failure),
"onUpdate:modelValue": _cache[3] || (_cache[3] = ($event?: any) => ((0, vue_2.isRef)(failure) ? (failure).value = $event : null))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[12] || (_cache[12] = [
(0, vue_2.createTextVNode)("模拟失败", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamCheckboxItem), {
modelValue: (0, vue_2.unref)(canonical),
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event?: any) => ((0, vue_2.isRef)(canonical) ? (canonical).value = $event : null))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[13] || (_cache[13] = [
(0, vue_2.createTextVNode)("来源接受 Omega 同值项", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"])
]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamDictSelect), {
ref_key: "control",
ref: control,
modelValue: value.value,
"onUpdate:modelValue": _cache[5] || (_cache[5] = ($event?: any) => ((value).value = $event)),
"dict-type": (0, vue_2.unref)(tenant),
"create-option": createOption,
"value-mode": "object",
"allow-create": "",
filterable: "",
clearable: "",
size: "default",
placeholder: "输入 Omega 并选择创建项",
onSuccess: _cache[6] || (_cache[6] = ($event?: any) => (providerValues.value = $event.map((item?: any) => item.value))),
onError: _cache[7] || (_cache[7] = ($event?: any) => (message.value = $event.message))
}, {
header: (0, vue_2.withCtx)(() => [...(_cache[14] || (_cache[14] = [
(0, vue_2.createElementVNode)("p", { class: "example-paragraph" }, "本地创建和来源选项分别保存", -1 /* CACHED */)
]))]),
footer: (0, vue_2.withCtx)(() => [...(_cache[15] || (_cache[15] = [
(0, vue_2.createElementVNode)("p", { class: "example-paragraph" }, "刷新保留本地项,逻辑来源改变时清空本地集合", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "dict-type"]),
(0, vue_2.createElementVNode)("p", _hoisted_3, (0, vue_2.toDisplayString)(result.value) + " " + (0, vue_2.toDisplayString)(message.value), 1 /* TEXT */),
(0, vue_2.createElementVNode)("pre", null, "模型:" + (0, vue_2.toDisplayString)(JSON.stringify(value.value)), 1 /* TEXT */),
(0, vue_2.createElementVNode)("pre", null, "工厂调用:" + (0, vue_2.toDisplayString)(JSON.stringify(createdTexts.value)), 1 /* TEXT */),
(0, vue_2.createElementVNode)("pre", null, "provider success 值:" + (0, vue_2.toDisplayString)(JSON.stringify(providerValues.value)), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-d782ffa5";
},
"Demo.vue": (module: any, exports: any, require: any) => {
"use strict";
var __importDefault: any = function (mod?: any) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
const Child_vue_1: any = __importDefault(require("./Child.vue"));
const provider_js_1: any = require("./provider.js");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectLocalCreationDemo' },
__name: 'Demo',
setup(__props?: any) {
const host: any = (0, vue_3.ref)();
let app: any;
(0, vue_3.onMounted)(() => {
if (!host.value)
return;
const state: any = (0, provider_js_1.createDemoState)();
app = (0, vue_3.createApp)(Child_vue_1.default);
app.provide('selection-local-demo', state);
(0, ui_1.provideAsamData)(app, (0, provider_js_1.createDemoProvider)(state), { scope: 'selection-demo' });
app.mount(host.value);
});
(0, vue_3.onBeforeUnmount)(() => app?.unmount());
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"provider.ts": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDemoState = createDemoState;
exports.createDemoProvider = createDemoProvider;
const vue_1: any = require("vue");
function createDemoState() {
return { tenant: (0, vue_1.ref)('a'), failure: (0, vue_1.ref)(false), canonical: (0, vue_1.ref)(false) };
}
function createDemoProvider(state?: any) {
return {
dict: {
async refresh(context?: any) {
context.signal.throwIfAborted();
},
async get(type?: any, context?: any) {
await new Promise((done?: any) => setTimeout(done, 150));
context.signal.throwIfAborted();
if (state.failure.value)
throw new Error('演示字典失败');
if (!['a', 'b'].includes(type))
throw new Error('未知演示字典');
const items: any = [{ id: 'server', label: 'Server', value: 'server' }];
if (state.canonical.value)
items.push({ id: 'saved', label: 'Server Omega', value: 'Omega' });
return items;
}
}
};
}
},
};
const __dependencies: any = {"Child.vue":{"./provider.js":"provider.ts"},"Demo.vue":{"./Child.vue":"Child.vue","./provider.js":"provider.ts"},"provider.ts":{}};
const __cache: any = Object.create(null);
function __require(id: any): any {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module: any = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency: any) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.actions[data-v-d782ffa5] {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
}
pre[data-v-d782ffa5] {
white-space: pre-wrap;
overflow-wrap: anywhere;
}
.demo-spacing-1[data-v-d782ffa5] {
display: grid;
gap: var(--asam-space-md);
}
p[data-v-d782ffa5]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template><StandaloneDemo /></template>
<script setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules = {
"Child.vue": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = { class: "data-demo demo-spacing-1" };
const _hoisted_2 = { class: "actions" };
const _hoisted_3 = {
class: "example-paragraph",
role: "status"
};
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
exports.default = Object.assign({ name: 'AsamDictSelectLocalCreationChild' }, {
__name: 'Child',
setup(__props) {
const state = (0, vue_2.inject)('selection-local-demo');
if (!state)
throw new Error('Demo.vue 必须先配置演示 provider。');
const { tenant, failure, canonical } = state;
const value = (0, vue_2.ref)(null);
const control = (0, vue_2.ref)();
const createdTexts = (0, vue_2.ref)([]);
const providerValues = (0, vue_2.ref)([]);
const message = (0, vue_2.ref)('');
const result = (0, vue_2.ref)('');
const createOption = (text) => {
createdTexts.value.push(text);
return { label: text, value: text, raw: { id: 'local-' + text, label: text, value: text } };
};
async function reload() {
await (0, vue_2.nextTick)();
result.value = (await control.value?.reload({ force: true }))?.status ?? 'cancelled';
if (result.value === 'success')
message.value = '';
}
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("section", _hoisted_1, [
(0, vue_1.createElementVNode)("div", _hoisted_2, [
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: reload
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[8] || (_cache[8] = [
(0, vue_1.createTextVNode)("强制重载", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[0] || (_cache[0] = $event => (control.value?.clearCreatedOptions()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[9] || (_cache[9] = [
(0, vue_1.createTextVNode)("清空本地创建集合", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[1] || (_cache[1] = $event => (value.value = null))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[10] || (_cache[10] = [
(0, vue_1.createTextVNode)("清空模型", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[2] || (_cache[2] = $event => (tenant.value = (0, vue_1.unref)(tenant) === 'a' ? 'b' : 'a'))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[11] || (_cache[11] = [
(0, vue_1.createTextVNode)("切换逻辑来源", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createCommentVNode)(" prettier-ignore "),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamCheckboxItem), {
modelValue: (0, vue_1.unref)(failure),
"onUpdate:modelValue": _cache[3] || (_cache[3] = $event => ((0, vue_1.isRef)(failure) ? (failure).value = $event : null))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[12] || (_cache[12] = [
(0, vue_1.createTextVNode)("模拟失败", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_1.createCommentVNode)(" prettier-ignore "),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamCheckboxItem), {
modelValue: (0, vue_1.unref)(canonical),
"onUpdate:modelValue": _cache[4] || (_cache[4] = $event => ((0, vue_1.isRef)(canonical) ? (canonical).value = $event : null))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[13] || (_cache[13] = [
(0, vue_1.createTextVNode)("来源接受 Omega 同值项", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"])
]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamDictSelect), {
ref_key: "control",
ref: control,
modelValue: value.value,
"onUpdate:modelValue": _cache[5] || (_cache[5] = $event => ((value).value = $event)),
"dict-type": (0, vue_1.unref)(tenant),
"create-option": createOption,
"value-mode": "object",
"allow-create": "",
filterable: "",
clearable: "",
size: "default",
placeholder: "输入 Omega 并选择创建项",
onSuccess: _cache[6] || (_cache[6] = $event => (providerValues.value = $event.map((item) => item.value))),
onError: _cache[7] || (_cache[7] = $event => (message.value = $event.message))
}, {
header: (0, vue_1.withCtx)(() => [...(_cache[14] || (_cache[14] = [
(0, vue_1.createElementVNode)("p", { class: "example-paragraph" }, "本地创建和来源选项分别保存", -1 /* CACHED */)
]))]),
footer: (0, vue_1.withCtx)(() => [...(_cache[15] || (_cache[15] = [
(0, vue_1.createElementVNode)("p", { class: "example-paragraph" }, "刷新保留本地项,逻辑来源改变时清空本地集合", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "dict-type"]),
(0, vue_1.createElementVNode)("p", _hoisted_3, (0, vue_1.toDisplayString)(result.value) + " " + (0, vue_1.toDisplayString)(message.value), 1 /* TEXT */),
(0, vue_1.createElementVNode)("pre", null, "模型:" + (0, vue_1.toDisplayString)(JSON.stringify(value.value)), 1 /* TEXT */),
(0, vue_1.createElementVNode)("pre", null, "工厂调用:" + (0, vue_1.toDisplayString)(JSON.stringify(createdTexts.value)), 1 /* TEXT */),
(0, vue_1.createElementVNode)("pre", null, "provider success 值:" + (0, vue_1.toDisplayString)(JSON.stringify(providerValues.value)), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-c8ef29cf";
},
"Demo.vue": (module, exports, require) => {
"use strict";
var __importDefault = function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
const Child_vue_1 = __importDefault(require("./Child.vue"));
const provider_js_1 = require("./provider.js");
exports.default = Object.assign({ name: 'AsamDictSelectLocalCreationDemo' }, {
__name: 'Demo',
setup(__props) {
const host = (0, vue_2.ref)();
let app;
(0, vue_2.onMounted)(() => {
if (!host.value)
return;
const state = (0, provider_js_1.createDemoState)();
app = (0, vue_2.createApp)(Child_vue_1.default);
app.provide('selection-local-demo', state);
(0, ui_1.provideAsamData)(app, (0, provider_js_1.createDemoProvider)(state), { scope: 'selection-demo' });
app.mount(host.value);
});
(0, vue_2.onBeforeUnmount)(() => app?.unmount());
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"provider.js": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDemoState = createDemoState;
exports.createDemoProvider = createDemoProvider;
const vue_1 = require("vue");
function createDemoState() {
return { tenant: (0, vue_1.ref)('a'), failure: (0, vue_1.ref)(false), canonical: (0, vue_1.ref)(false) };
}
function createDemoProvider(state) {
return {
dict: {
async refresh(context) {
context.signal.throwIfAborted();
},
async get(type, context) {
await new Promise((done) => setTimeout(done, 150));
context.signal.throwIfAborted();
if (state.failure.value)
throw new Error('演示字典失败');
if (!['a', 'b'].includes(type))
throw new Error('未知演示字典');
const items = [{ id: 'server', label: 'Server', value: 'server' }];
if (state.canonical.value)
items.push({ id: 'saved', label: 'Server Omega', value: 'Omega' });
return items;
}
}
};
}
},
};
const __dependencies = {"Child.vue":{},"Demo.vue":{"./Child.vue":"Child.vue","./provider.js":"provider.js"},"provider.js":{}};
const __cache = Object.create(null);
function __require(id) {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.actions[data-v-c8ef29cf] {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
}
pre[data-v-c8ef29cf] {
white-space: pre-wrap;
overflow-wrap: anywhere;
}
.demo-spacing-1[data-v-c8ef29cf] {
display: grid;
gap: var(--asam-space-md);
}
p[data-v-c8ef29cf]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
本地创建集合只属于当前组件,不写入字典 provider/cache,success 只含来源项。 同类型同值去重,字典同值规范项优先;已传给父组件的对象模型不会因刷新自动替换。
clearCreatedOptions() 只清空本地集合及基础文本 memo,不清空模型。相同字典刷新、 一般 epoch 更新与错误重试保留本地项;dictType、dictValueType、真实 dataSource 或 provider/scope 变化自动清空。清空模型仍由调用方另行更新 v-model。
数据来源与覆盖 ​
dictType 与 dataSource 只选一种;dataSource 使用 defineAsamDictSource 创建,不能再传 dictValueType。 完整说明。
单选值模式使用标量或 null;对象模式使用规范化 AsamOption。多选的数组与分隔字符串模式由 multiple、valueMode、multipleValueMode 联合约束;对象模式不能使用字符串存储。切换值策略时同时调整模型类型。
来源接管 options、loading 和远端查询;数据组件不开放基础选择器的 native 值模式。基础页中只使用与本组件公开分支兼容的能力。
生命周期、事件与实例 ​
active=false 暂停请求并保留上次成功数据;reload({ force: true }) 请求新数据,cancel() 取消当前请求。 完整说明。
immediate 控制初始化是否请求,active 控制请求是否启用。初始化和默认值以本页自动 API 的原始来源为准。
插槽与基础能力 ​
prefix、header、footer、empty、loading、tag、label 等插槽保留各自基础作用域;selectedLabel 为只读标签结果,focus/blur 用于焦点控制。虚拟选择器 default 插槽使用基础虚拟选项作用域。
本站继承关系 ​
- 选择器:适用的基础展示、交互与公开 API。
本页数据来源、模型、事件和实例的覆盖规则优先;本站链接不扩大本组件公开契约。尺寸使用基础组件的 ASAM 尺寸规则,示例使用 default。
字典刷新与示例 Provider ​
强制重载会先调用 provider.dict.refresh,再重新读取字典。示例 provider 同时提供 get 和 refresh,并检查请求取消信号;使用固定字典数据,不连接真实后端。宿主接入时应在 refresh 中实现实际缓存更新。
选项和标签的完整展示 ​
完整示例在两个独立实例中演示按来源 raw.team 分组的 OptionGroup/Option 插槽、prefix/header/footer/loading/empty/label 和可删除 tag。 完整说明。
示例按钮可关闭或恢复标签折叠,将可见标签数量在 1 与 3 之间切换,并将多选数量上限在 3 与 0(不限数量)之间切换。展示设置不改变来源和已选模型;取消上限后可以选择第四项。恢复初始多选由调用方将模型设回 [1, 3, 4],随后恢复上限,区别于用户删除标签触发的 remove-tag。
展示示例还逐次记录单选原始数字、多选原始数组的 update:modelValue/change,以及完整规范化选项的 success。可制造一次刷新失败,观察 error 的 kind/message 与旧选中值保留,再恢复;持有请求的取消不产生额外成功事件。每条记录保存独立载荷快照。
选项模板、标签折叠与加载插槽
<template><StandaloneDemo /></template>
<script lang="ts" setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external: any = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules: any = {
"Demo.vue": (module: any, exports: any, require: any) => {
"use strict";
var __importDefault: any = function (mod?: any) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
const Child_vue_1: any = __importDefault(require("./Child.vue"));
const provider_js_1: any = require("./provider.js");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectNativePresentationDemo' },
__name: 'Demo',
setup(__props?: any) {
const host: any = (0, vue_3.ref)();
let app: any;
(0, vue_3.onMounted)(() => {
if (!host.value)
return;
const state: any = (0, provider_js_1.createDemoState)();
app = (0, vue_3.createApp)(Child_vue_1.default);
app.provide('selection-presentation', state);
(0, ui_1.provideAsamData)(app, (0, provider_js_1.createDemoProvider)(state), { scope: 'native-presentation' });
app.mount(host.value);
});
(0, vue_3.onBeforeUnmount)(() => app?.unmount());
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"Child.vue": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = { class: "demo-spacing-1" };
const _hoisted_2: any = { class: "demo-spacing-2" };
const _hoisted_3: any = { "data-testid": "presentation-label" };
const _hoisted_4: any = { "data-testid": "presentation-tag" };
const _hoisted_5: any = { "data-testid": "presentation-state" };
const _hoisted_6: any = {
class: "example-paragraph",
"data-testid": "selection-event-result"
};
const _hoisted_7: any = { "data-testid": "selection-data-events" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectNativePresentationChild' },
__name: 'Child',
setup(__props?: any) {
const injected: any = (0, vue_3.inject)('selection-presentation');
if (!injected)
throw new Error('Demo.vue must install its local provider before Child.vue mounts.');
const state: any = injected;
const singleControl: any = (0, vue_3.ref)();
const singleValue: any = (0, vue_3.ref)(null);
const dataEvents: any = (0, vue_3.ref)([]);
const eventResult: any = (0, vue_3.ref)('');
function recordEvent(mode?: any, name?: any, payload?: any) {
const snapshot: any = JSON.parse(JSON.stringify(payload));
dataEvents.value = [...dataEvents.value, { mode, name, payload: snapshot }];
}
function onModelUpdate(payload?: any, mode?: any) {
recordEvent(mode, 'update:modelValue', payload);
}
function onModelChange(payload?: any, mode?: any) {
recordEvent(mode, 'change', payload);
}
function onSuccess(payload?: any) {
recordEvent('single', 'success', payload);
}
function onError(payload?: any) {
recordEvent('single', 'error', { kind: payload.kind, message: payload.message });
}
async function failReload() {
state.failure.value = true;
eventResult.value = (await singleControl.value?.reload({ force: true }))?.status ?? 'cancelled';
}
async function recoverReload() {
state.failure.value = false;
eventResult.value = (await singleControl.value?.reload({ force: true }))?.status ?? 'cancelled';
}
async function cancelHeld() {
state.held.value = true;
const pending: any = singleControl.value?.reload({ force: true });
setTimeout(() => singleControl.value?.cancel(), 30);
eventResult.value = (await pending)?.status ?? 'cancelled';
state.release();
}
const multipleValues: any = (0, vue_3.ref)([1, 3, 4]);
const removed: any = (0, vue_3.ref)([]);
const customTag: any = (0, vue_3.ref)(false);
const disabled: any = (0, vue_3.ref)(false);
const collapseTags: any = (0, vue_3.ref)(true);
const collapseTagsTooltip: any = (0, vue_3.ref)(true);
const popperStyleMode: any = (0, vue_3.ref)('object');
const popperStyle: any = (0, vue_3.computed)(() => {
if (popperStyleMode.value === 'object')
return { minWidth: '320px' };
if (popperStyleMode.value === 'string')
return 'min-width: 360px';
if (popperStyleMode.value === 'array')
return [{ minWidth: '400px' }, [{ maxWidth: '460px' }]];
if (popperStyleMode.value === 'false')
return false;
if (popperStyleMode.value === 'null')
return null;
return undefined;
});
const maxCollapseTags: any = (0, vue_3.ref)(1);
const multipleLimit: any = (0, vue_3.ref)(3);
const singleOptions: any = (0, vue_3.ref)([]);
const groups: any = (0, vue_3.computed)(() => ['一组', '二组'].map((team?: any) => ({
team,
options: singleOptions.value.filter((item?: any) => item.raw.team === team)
})));
function holdAndReload() {
state.held.value = true;
void singleControl.value?.reload({ force: true });
}
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("section", _hoisted_1, [
(0, vue_2.createElementVNode)("div", _hoisted_2, [
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: failReload
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[24] || (_cache[24] = [
(0, vue_2.createTextVNode)("制造刷新失败", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: recoverReload
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[25] || (_cache[25] = [
(0, vue_2.createTextVNode)("恢复失败请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: cancelHeld
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[26] || (_cache[26] = [
(0, vue_2.createTextVNode)("取消持有请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: holdAndReload
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[27] || (_cache[27] = [
(0, vue_2.createTextVNode)("等待并重载单选", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[0] || (_cache[0] = ($event?: any) => ((0, vue_2.unref)(state).release()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[28] || (_cache[28] = [
(0, vue_2.createTextVNode)("完成当前请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[1] || (_cache[1] = ($event?: any) => {
(0, vue_2.unref)(state).empty.value = !(0, vue_2.unref)(state).empty.value;
singleControl.value?.reload({ force: true });
})
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[29] || (_cache[29] = [
(0, vue_2.createTextVNode)(" 切换空结果 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[2] || (_cache[2] = ($event?: any) => (customTag.value = !customTag.value))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[30] || (_cache[30] = [
(0, vue_2.createTextVNode)("切换自定义标签", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[3] || (_cache[3] = ($event?: any) => (disabled.value = !disabled.value))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[31] || (_cache[31] = [
(0, vue_2.createTextVNode)("切换多选禁用", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[4] || (_cache[4] = ($event?: any) => (collapseTags.value = !collapseTags.value))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[32] || (_cache[32] = [
(0, vue_2.createTextVNode)("切换标签折叠", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[5] || (_cache[5] = ($event?: any) => (collapseTagsTooltip.value = !collapseTagsTooltip.value))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[33] || (_cache[33] = [
(0, vue_2.createTextVNode)(" 切换折叠标签提示 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[6] || (_cache[6] = ($event?: any) => (popperStyleMode.value = 'object'))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[34] || (_cache[34] = [
(0, vue_2.createTextVNode)("使用对象弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[7] || (_cache[7] = ($event?: any) => (popperStyleMode.value = 'string'))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[35] || (_cache[35] = [
(0, vue_2.createTextVNode)("使用字符串弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[8] || (_cache[8] = ($event?: any) => (popperStyleMode.value = 'array'))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[36] || (_cache[36] = [
(0, vue_2.createTextVNode)("使用数组弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[9] || (_cache[9] = ($event?: any) => (popperStyleMode.value = 'false'))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[37] || (_cache[37] = [
(0, vue_2.createTextVNode)("使用 false 弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[10] || (_cache[10] = ($event?: any) => (popperStyleMode.value = 'null'))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[38] || (_cache[38] = [
(0, vue_2.createTextVNode)("使用 null 弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[11] || (_cache[11] = ($event?: any) => (popperStyleMode.value = 'undefined'))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[39] || (_cache[39] = [
(0, vue_2.createTextVNode)("清空弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[12] || (_cache[12] = ($event?: any) => (maxCollapseTags.value = maxCollapseTags.value === 1 ? 3 : 1))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[40] || (_cache[40] = [
(0, vue_2.createTextVNode)(" 切换可见标签数量 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[13] || (_cache[13] = ($event?: any) => (multipleLimit.value = multipleLimit.value === 3 ? 0 : 3))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[41] || (_cache[41] = [
(0, vue_2.createTextVNode)(" 切换多选数量上限 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[14] || (_cache[14] = ($event?: any) => (multipleValues.value = [1, 3, 4]))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[42] || (_cache[42] = [
(0, vue_2.createTextVNode)("恢复初始多选", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[15] || (_cache[15] = ($event?: any) => (multipleValues.value = []))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[43] || (_cache[43] = [
(0, vue_2.createTextVNode)("清空多选模型", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
})
]),
_cache[50] || (_cache[50] = (0, vue_2.createElementVNode)("label", null, "单选展示", -1 /* CACHED */)),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamDictSelect), {
ref_key: "singleControl",
ref: singleControl,
modelValue: singleValue.value,
"onUpdate:modelValue": [
_cache[16] || (_cache[16] = ($event?: any) => ((singleValue).value = $event)),
_cache[17] || (_cache[17] = ($event?: any) => (onModelUpdate($event, 'single')))
],
"dict-type": "presentation",
"dict-value-type": "number",
style: { "width": "280px" },
"popper-style": popperStyle.value,
"popper-class": "data009-presentation-popper",
clearable: "",
placeholder: "演示单选",
teleported: false,
onChange: _cache[18] || (_cache[18] = ($event?: any) => (onModelChange($event, 'single'))),
onError: onError,
onSuccess: _cache[19] || (_cache[19] = ($event?: any) => {
singleOptions.value = $event;
onSuccess($event);
})
}, {
prefix: (0, vue_2.withCtx)(() => [...(_cache[44] || (_cache[44] = [
(0, vue_2.createElementVNode)("span", { "data-testid": "presentation-prefix" }, "前缀", -1 /* CACHED */)
]))]),
header: (0, vue_2.withCtx)(() => [...(_cache[45] || (_cache[45] = [
(0, vue_2.createElementVNode)("p", {
class: "example-paragraph",
"data-testid": "presentation-header"
}, "选项列表说明", -1 /* CACHED */)
]))]),
footer: (0, vue_2.withCtx)(() => [...(_cache[46] || (_cache[46] = [
(0, vue_2.createElementVNode)("p", {
class: "example-paragraph",
"data-testid": "presentation-footer"
}, "由本地来源加载", -1 /* CACHED */)
]))]),
loading: (0, vue_2.withCtx)(() => [...(_cache[47] || (_cache[47] = [
(0, vue_2.createElementVNode)("span", { "data-testid": "presentation-loading" }, "正在读取本地选项", -1 /* CACHED */)
]))]),
empty: (0, vue_2.withCtx)(() => [...(_cache[48] || (_cache[48] = [
(0, vue_2.createElementVNode)("p", {
class: "example-paragraph",
"data-testid": "presentation-empty"
}, "当前来源没有匹配项", -1 /* CACHED */)
]))]),
label: (0, vue_2.withCtx)(({ label, value }: any) => [
(0, vue_2.createElementVNode)("span", _hoisted_3, (0, vue_2.toDisplayString)(label) + " [" + (0, vue_2.toDisplayString)(value) + "]", 1 /* TEXT */)
]),
default: (0, vue_2.withCtx)(() => [
((0, vue_2.openBlock)(true), (0, vue_2.createElementBlock)(vue_2.Fragment, null, (0, vue_2.renderList)(groups.value, (group?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createBlock)((0, vue_2.unref)(ui_1.AsamOptionGroup), {
key: group.team,
label: group.team
}, {
default: (0, vue_2.withCtx)(() => [
((0, vue_2.openBlock)(true), (0, vue_2.createElementBlock)(vue_2.Fragment, null, (0, vue_2.renderList)(group.options, (option?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createBlock)((0, vue_2.unref)(ui_1.AsamOption), {
key: option.value,
label: option.label,
value: option.value,
disabled: option.disabled
}, {
default: (0, vue_2.withCtx)(() => [
(0, vue_2.createElementVNode)("span", null, (0, vue_2.toDisplayString)(option.label) + " · " + (0, vue_2.toDisplayString)(option.raw.team), 1 /* TEXT */)
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["label", "value", "disabled"]));
}), 128 /* KEYED_FRAGMENT */))
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["label"]));
}), 128 /* KEYED_FRAGMENT */))
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "popper-style"]),
_cache[51] || (_cache[51] = (0, vue_2.createElementVNode)("label", null, "多选展示", -1 /* CACHED */)),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamDictSelect), {
modelValue: multipleValues.value,
"onUpdate:modelValue": [
_cache[20] || (_cache[20] = ($event?: any) => ((multipleValues).value = $event)),
_cache[22] || (_cache[22] = ($event?: any) => (onModelUpdate($event, 'multiple')))
],
"dict-type": "presentation",
"dict-value-type": "number",
multiple: "",
"collapse-tags": collapseTags.value,
"collapse-tags-tooltip": collapseTagsTooltip.value,
"max-collapse-tags": maxCollapseTags.value,
"multiple-limit": multipleLimit.value,
disabled: disabled.value,
style: { "width": "280px" },
clearable: "",
placeholder: "演示多选",
teleported: false,
onRemoveTag: _cache[21] || (_cache[21] = ($event?: any) => (removed.value.push($event))),
onChange: _cache[23] || (_cache[23] = ($event?: any) => (onModelChange($event, 'multiple')))
}, (0, vue_2.createSlots)({ _: 2 /* DYNAMIC */ }, [
(customTag.value)
? {
name: "tag",
fn: (0, vue_2.withCtx)(({ data, deleteTag }: any) => [
(0, vue_2.createElementVNode)("span", _hoisted_4, [
(0, vue_2.createTextVNode)(" 已选 " + (0, vue_2.toDisplayString)(data.length) + " 项 ", 1 /* TEXT */),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: disabled.value || !data.length,
onClick: ($event?: any) => (deleteTag($event, data[0]))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[49] || (_cache[49] = [
(0, vue_2.createTextVNode)(" 删除首个标签 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled", "onClick"])
])
]),
key: "0"
}
: undefined
]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "collapse-tags", "collapse-tags-tooltip", "max-collapse-tags", "multiple-limit", "disabled"]),
(0, vue_2.createElementVNode)("pre", _hoisted_5, (0, vue_2.toDisplayString)(JSON.stringify({
singleValue: singleValue.value,
multipleValues: multipleValues.value,
removed: removed.value,
customTag: customTag.value,
disabled: disabled.value,
collapseTags: collapseTags.value,
collapseTagsTooltip: collapseTagsTooltip.value,
popperStyleMode: popperStyleMode.value,
maxCollapseTags: maxCollapseTags.value,
multipleLimit: multipleLimit.value,
calls: (0, vue_2.unref)(state).calls.value
})), 1 /* TEXT */),
(0, vue_2.createElementVNode)("p", _hoisted_6, (0, vue_2.toDisplayString)(eventResult.value), 1 /* TEXT */),
(0, vue_2.createElementVNode)("pre", _hoisted_7, (0, vue_2.toDisplayString)(JSON.stringify(dataEvents.value)), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-0a8d6f5b";
},
"provider.ts": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDemoState = createDemoState;
exports.createDemoProvider = createDemoProvider;
const vue_1: any = require("vue");
const rows: any = [
{ label: 'Alpha', value: 1, id: 1, team: '一组' },
{ label: 'Beta', value: 2, id: 2, team: '一组', disabled: true },
{ label: 'Gamma', value: 3, id: 3, team: '二组' },
{ label: 'Delta', value: 4, id: 4, team: '二组' },
{ label: 'Epsilon', value: 5, id: 5, team: '二组' }
];
function createDemoState() {
const held: any = (0, vue_1.ref)(false), empty: any = (0, vue_1.ref)(false), failure: any = (0, vue_1.ref)(false), calls: any = (0, vue_1.ref)(0);
const pending: any = new Set();
async function read(signal?: any, text?: any) {
signal.throwIfAborted();
calls.value++;
if (held.value)
await new Promise((done?: any, reject?: any) => {
const finish: any = () => {
pending.delete(finish);
signal.removeEventListener('abort', abort);
done();
};
const abort: any = () => {
pending.delete(finish);
signal.removeEventListener('abort', abort);
reject(signal.reason);
};
pending.add(finish);
signal.addEventListener('abort', abort, { once: true });
if (signal.aborted)
abort();
});
signal.throwIfAborted();
if (failure.value)
throw new Error('演示选择器请求失败');
return empty.value
? []
: rows.filter((item?: any) => item.label.toLowerCase().includes(text.toLowerCase()));
}
function release() {
held.value = false;
for (const finish of ([...pending] as any))
finish();
}
return { held, empty, failure, calls, read, release };
}
function createDemoProvider(state?: any) {
return {
dict: {
async refresh(context?: any) {
context.signal.throwIfAborted();
},
async get(type?: any, context?: any) {
if (type !== 'presentation')
throw new Error('Unknown local dictionary');
return (await state.read(context.signal, '')).map((item?: any) => ({ ...item }));
}
}
};
}
},
};
const __dependencies: any = {"Demo.vue":{"./Child.vue":"Child.vue","./provider.js":"provider.ts"},"Child.vue":{"./provider.js":"provider.ts"},"provider.ts":{}};
const __cache: any = Object.create(null);
function __require(id: any): any {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module: any = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency: any) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-spacing-1[data-v-0a8d6f5b] {
display: grid;
gap: var(--asam-space-md);
}
.demo-spacing-2[data-v-0a8d6f5b] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-md);
}
p[data-v-0a8d6f5b]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template><StandaloneDemo /></template>
<script setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules = {
"Demo.vue": (module, exports, require) => {
"use strict";
var __importDefault = function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
const Child_vue_1 = __importDefault(require("./Child.vue"));
const provider_js_1 = require("./provider.js");
exports.default = Object.assign({ name: 'AsamDictSelectNativePresentationDemo' }, {
__name: 'Demo',
setup(__props) {
const host = (0, vue_2.ref)();
let app;
(0, vue_2.onMounted)(() => {
if (!host.value)
return;
const state = (0, provider_js_1.createDemoState)();
app = (0, vue_2.createApp)(Child_vue_1.default);
app.provide('selection-presentation', state);
(0, ui_1.provideAsamData)(app, (0, provider_js_1.createDemoProvider)(state), { scope: 'native-presentation' });
app.mount(host.value);
});
(0, vue_2.onBeforeUnmount)(() => app?.unmount());
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"Child.vue": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = { class: "demo-spacing-1" };
const _hoisted_2 = { class: "demo-spacing-2" };
const _hoisted_3 = { "data-testid": "presentation-label" };
const _hoisted_4 = { "data-testid": "presentation-tag" };
const _hoisted_5 = { "data-testid": "presentation-state" };
const _hoisted_6 = {
class: "example-paragraph",
"data-testid": "selection-event-result"
};
const _hoisted_7 = { "data-testid": "selection-data-events" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
exports.default = Object.assign({ name: 'AsamDictSelectNativePresentationChild' }, {
__name: 'Child',
setup(__props) {
const injected = (0, vue_2.inject)('selection-presentation');
if (!injected)
throw new Error('Demo.vue must install its local provider before Child.vue mounts.');
const state = injected;
const singleControl = (0, vue_2.ref)();
const singleValue = (0, vue_2.ref)(null);
const dataEvents = (0, vue_2.ref)([]);
const eventResult = (0, vue_2.ref)('');
function recordEvent(mode, name, payload) {
const snapshot = JSON.parse(JSON.stringify(payload));
dataEvents.value = [...dataEvents.value, { mode, name, payload: snapshot }];
}
function onModelUpdate(payload, mode) {
recordEvent(mode, 'update:modelValue', payload);
}
function onModelChange(payload, mode) {
recordEvent(mode, 'change', payload);
}
function onSuccess(payload) {
recordEvent('single', 'success', payload);
}
function onError(payload) {
recordEvent('single', 'error', { kind: payload.kind, message: payload.message });
}
async function failReload() {
state.failure.value = true;
eventResult.value = (await singleControl.value?.reload({ force: true }))?.status ?? 'cancelled';
}
async function recoverReload() {
state.failure.value = false;
eventResult.value = (await singleControl.value?.reload({ force: true }))?.status ?? 'cancelled';
}
async function cancelHeld() {
state.held.value = true;
const pending = singleControl.value?.reload({ force: true });
setTimeout(() => singleControl.value?.cancel(), 30);
eventResult.value = (await pending)?.status ?? 'cancelled';
state.release();
}
const multipleValues = (0, vue_2.ref)([1, 3, 4]);
const removed = (0, vue_2.ref)([]);
const customTag = (0, vue_2.ref)(false);
const disabled = (0, vue_2.ref)(false);
const collapseTags = (0, vue_2.ref)(true);
const collapseTagsTooltip = (0, vue_2.ref)(true);
const popperStyleMode = (0, vue_2.ref)('object');
const popperStyle = (0, vue_2.computed)(() => {
if (popperStyleMode.value === 'object')
return { minWidth: '320px' };
if (popperStyleMode.value === 'string')
return 'min-width: 360px';
if (popperStyleMode.value === 'array')
return [{ minWidth: '400px' }, [{ maxWidth: '460px' }]];
if (popperStyleMode.value === 'false')
return false;
if (popperStyleMode.value === 'null')
return null;
return undefined;
});
const maxCollapseTags = (0, vue_2.ref)(1);
const multipleLimit = (0, vue_2.ref)(3);
const singleOptions = (0, vue_2.ref)([]);
const groups = (0, vue_2.computed)(() => ['一组', '二组'].map((team) => ({
team,
options: singleOptions.value.filter((item) => item.raw.team === team)
})));
function holdAndReload() {
state.held.value = true;
void singleControl.value?.reload({ force: true });
}
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("section", _hoisted_1, [
(0, vue_1.createElementVNode)("div", _hoisted_2, [
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: failReload
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[24] || (_cache[24] = [
(0, vue_1.createTextVNode)("制造刷新失败", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: recoverReload
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[25] || (_cache[25] = [
(0, vue_1.createTextVNode)("恢复失败请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: cancelHeld
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[26] || (_cache[26] = [
(0, vue_1.createTextVNode)("取消持有请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: holdAndReload
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[27] || (_cache[27] = [
(0, vue_1.createTextVNode)("等待并重载单选", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[0] || (_cache[0] = $event => ((0, vue_1.unref)(state).release()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[28] || (_cache[28] = [
(0, vue_1.createTextVNode)("完成当前请求", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[1] || (_cache[1] = $event => {
(0, vue_1.unref)(state).empty.value = !(0, vue_1.unref)(state).empty.value;
singleControl.value?.reload({ force: true });
})
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[29] || (_cache[29] = [
(0, vue_1.createTextVNode)(" 切换空结果 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[2] || (_cache[2] = $event => (customTag.value = !customTag.value))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[30] || (_cache[30] = [
(0, vue_1.createTextVNode)("切换自定义标签", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[3] || (_cache[3] = $event => (disabled.value = !disabled.value))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[31] || (_cache[31] = [
(0, vue_1.createTextVNode)("切换多选禁用", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[4] || (_cache[4] = $event => (collapseTags.value = !collapseTags.value))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[32] || (_cache[32] = [
(0, vue_1.createTextVNode)("切换标签折叠", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[5] || (_cache[5] = $event => (collapseTagsTooltip.value = !collapseTagsTooltip.value))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[33] || (_cache[33] = [
(0, vue_1.createTextVNode)(" 切换折叠标签提示 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[6] || (_cache[6] = $event => (popperStyleMode.value = 'object'))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[34] || (_cache[34] = [
(0, vue_1.createTextVNode)("使用对象弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[7] || (_cache[7] = $event => (popperStyleMode.value = 'string'))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[35] || (_cache[35] = [
(0, vue_1.createTextVNode)("使用字符串弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[8] || (_cache[8] = $event => (popperStyleMode.value = 'array'))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[36] || (_cache[36] = [
(0, vue_1.createTextVNode)("使用数组弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[9] || (_cache[9] = $event => (popperStyleMode.value = 'false'))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[37] || (_cache[37] = [
(0, vue_1.createTextVNode)("使用 false 弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[10] || (_cache[10] = $event => (popperStyleMode.value = 'null'))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[38] || (_cache[38] = [
(0, vue_1.createTextVNode)("使用 null 弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[11] || (_cache[11] = $event => (popperStyleMode.value = 'undefined'))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[39] || (_cache[39] = [
(0, vue_1.createTextVNode)("清空弹层样式", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[12] || (_cache[12] = $event => (maxCollapseTags.value = maxCollapseTags.value === 1 ? 3 : 1))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[40] || (_cache[40] = [
(0, vue_1.createTextVNode)(" 切换可见标签数量 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[13] || (_cache[13] = $event => (multipleLimit.value = multipleLimit.value === 3 ? 0 : 3))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[41] || (_cache[41] = [
(0, vue_1.createTextVNode)(" 切换多选数量上限 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[14] || (_cache[14] = $event => (multipleValues.value = [1, 3, 4]))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[42] || (_cache[42] = [
(0, vue_1.createTextVNode)("恢复初始多选", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[15] || (_cache[15] = $event => (multipleValues.value = []))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[43] || (_cache[43] = [
(0, vue_1.createTextVNode)("清空多选模型", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
})
]),
_cache[50] || (_cache[50] = (0, vue_1.createElementVNode)("label", null, "单选展示", -1 /* CACHED */)),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamDictSelect), {
ref_key: "singleControl",
ref: singleControl,
modelValue: singleValue.value,
"onUpdate:modelValue": [
_cache[16] || (_cache[16] = $event => ((singleValue).value = $event)),
_cache[17] || (_cache[17] = $event => (onModelUpdate($event, 'single')))
],
"dict-type": "presentation",
"dict-value-type": "number",
style: { "width": "280px" },
"popper-style": popperStyle.value,
"popper-class": "data009-presentation-popper",
clearable: "",
placeholder: "演示单选",
teleported: false,
onChange: _cache[18] || (_cache[18] = $event => (onModelChange($event, 'single'))),
onError: onError,
onSuccess: _cache[19] || (_cache[19] = $event => {
singleOptions.value = $event;
onSuccess($event);
})
}, {
prefix: (0, vue_1.withCtx)(() => [...(_cache[44] || (_cache[44] = [
(0, vue_1.createElementVNode)("span", { "data-testid": "presentation-prefix" }, "前缀", -1 /* CACHED */)
]))]),
header: (0, vue_1.withCtx)(() => [...(_cache[45] || (_cache[45] = [
(0, vue_1.createElementVNode)("p", {
class: "example-paragraph",
"data-testid": "presentation-header"
}, "选项列表说明", -1 /* CACHED */)
]))]),
footer: (0, vue_1.withCtx)(() => [...(_cache[46] || (_cache[46] = [
(0, vue_1.createElementVNode)("p", {
class: "example-paragraph",
"data-testid": "presentation-footer"
}, "由本地来源加载", -1 /* CACHED */)
]))]),
loading: (0, vue_1.withCtx)(() => [...(_cache[47] || (_cache[47] = [
(0, vue_1.createElementVNode)("span", { "data-testid": "presentation-loading" }, "正在读取本地选项", -1 /* CACHED */)
]))]),
empty: (0, vue_1.withCtx)(() => [...(_cache[48] || (_cache[48] = [
(0, vue_1.createElementVNode)("p", {
class: "example-paragraph",
"data-testid": "presentation-empty"
}, "当前来源没有匹配项", -1 /* CACHED */)
]))]),
label: (0, vue_1.withCtx)(({ label, value }) => [
(0, vue_1.createElementVNode)("span", _hoisted_3, (0, vue_1.toDisplayString)(label) + " [" + (0, vue_1.toDisplayString)(value) + "]", 1 /* TEXT */)
]),
default: (0, vue_1.withCtx)(() => [
((0, vue_1.openBlock)(true), (0, vue_1.createElementBlock)(vue_1.Fragment, null, (0, vue_1.renderList)(groups.value, (group) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createBlock)((0, vue_1.unref)(ui_1.AsamOptionGroup), {
key: group.team,
label: group.team
}, {
default: (0, vue_1.withCtx)(() => [
((0, vue_1.openBlock)(true), (0, vue_1.createElementBlock)(vue_1.Fragment, null, (0, vue_1.renderList)(group.options, (option) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createBlock)((0, vue_1.unref)(ui_1.AsamOption), {
key: option.value,
label: option.label,
value: option.value,
disabled: option.disabled
}, {
default: (0, vue_1.withCtx)(() => [
(0, vue_1.createElementVNode)("span", null, (0, vue_1.toDisplayString)(option.label) + " · " + (0, vue_1.toDisplayString)(option.raw.team), 1 /* TEXT */)
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["label", "value", "disabled"]));
}), 128 /* KEYED_FRAGMENT */))
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["label"]));
}), 128 /* KEYED_FRAGMENT */))
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "popper-style"]),
_cache[51] || (_cache[51] = (0, vue_1.createElementVNode)("label", null, "多选展示", -1 /* CACHED */)),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamDictSelect), {
modelValue: multipleValues.value,
"onUpdate:modelValue": [
_cache[20] || (_cache[20] = $event => ((multipleValues).value = $event)),
_cache[22] || (_cache[22] = $event => (onModelUpdate($event, 'multiple')))
],
"dict-type": "presentation",
"dict-value-type": "number",
multiple: "",
"collapse-tags": collapseTags.value,
"collapse-tags-tooltip": collapseTagsTooltip.value,
"max-collapse-tags": maxCollapseTags.value,
"multiple-limit": multipleLimit.value,
disabled: disabled.value,
style: { "width": "280px" },
clearable: "",
placeholder: "演示多选",
teleported: false,
onRemoveTag: _cache[21] || (_cache[21] = $event => (removed.value.push($event))),
onChange: _cache[23] || (_cache[23] = $event => (onModelChange($event, 'multiple')))
}, (0, vue_1.createSlots)({ _: 2 /* DYNAMIC */ }, [
(customTag.value)
? {
name: "tag",
fn: (0, vue_1.withCtx)(({ data, deleteTag }) => [
(0, vue_1.createElementVNode)("span", _hoisted_4, [
(0, vue_1.createTextVNode)(" 已选 " + (0, vue_1.toDisplayString)(data.length) + " 项 ", 1 /* TEXT */),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: disabled.value || !data.length,
onClick: $event => (deleteTag($event, data[0]))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[49] || (_cache[49] = [
(0, vue_1.createTextVNode)(" 删除首个标签 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled", "onClick"])
])
]),
key: "0"
}
: undefined
]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "collapse-tags", "collapse-tags-tooltip", "max-collapse-tags", "multiple-limit", "disabled"]),
(0, vue_1.createElementVNode)("pre", _hoisted_5, (0, vue_1.toDisplayString)(JSON.stringify({
singleValue: singleValue.value,
multipleValues: multipleValues.value,
removed: removed.value,
customTag: customTag.value,
disabled: disabled.value,
collapseTags: collapseTags.value,
collapseTagsTooltip: collapseTagsTooltip.value,
popperStyleMode: popperStyleMode.value,
maxCollapseTags: maxCollapseTags.value,
multipleLimit: multipleLimit.value,
calls: (0, vue_1.unref)(state).calls.value
})), 1 /* TEXT */),
(0, vue_1.createElementVNode)("p", _hoisted_6, (0, vue_1.toDisplayString)(eventResult.value), 1 /* TEXT */),
(0, vue_1.createElementVNode)("pre", _hoisted_7, (0, vue_1.toDisplayString)(JSON.stringify(dataEvents.value)), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-75db2b34";
},
"provider.js": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDemoState = createDemoState;
exports.createDemoProvider = createDemoProvider;
const vue_1 = require("vue");
const rows = [
{ label: 'Alpha', value: 1, id: 1, team: '一组' },
{ label: 'Beta', value: 2, id: 2, team: '一组', disabled: true },
{ label: 'Gamma', value: 3, id: 3, team: '二组' },
{ label: 'Delta', value: 4, id: 4, team: '二组' },
{ label: 'Epsilon', value: 5, id: 5, team: '二组' }
];
function createDemoState() {
const held = (0, vue_1.ref)(false), empty = (0, vue_1.ref)(false), failure = (0, vue_1.ref)(false), calls = (0, vue_1.ref)(0);
const pending = new Set();
async function read(signal, text) {
signal.throwIfAborted();
calls.value++;
if (held.value)
await new Promise((done, reject) => {
const finish = () => {
pending.delete(finish);
signal.removeEventListener('abort', abort);
done();
};
const abort = () => {
pending.delete(finish);
signal.removeEventListener('abort', abort);
reject(signal.reason);
};
pending.add(finish);
signal.addEventListener('abort', abort, { once: true });
if (signal.aborted)
abort();
});
signal.throwIfAborted();
if (failure.value)
throw new Error('演示选择器请求失败');
return empty.value
? []
: rows.filter((item) => item.label.toLowerCase().includes(text.toLowerCase()));
}
function release() {
held.value = false;
for (const finish of [...pending])
finish();
}
return { held, empty, failure, calls, read, release };
}
function createDemoProvider(state) {
return {
dict: {
async refresh(context) {
context.signal.throwIfAborted();
},
async get(type, context) {
if (type !== 'presentation')
throw new Error('Unknown local dictionary');
return (await state.read(context.signal, '')).map((item) => ({ ...item }));
}
}
};
}
},
};
const __dependencies = {"Demo.vue":{"./Child.vue":"Child.vue","./provider.js":"provider.js"},"Child.vue":{},"provider.js":{}};
const __cache = Object.create(null);
function __require(id) {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-spacing-1[data-v-75db2b34] {
display: grid;
gap: var(--asam-space-md);
}
.demo-spacing-2[data-v-75db2b34] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-md);
}
p[data-v-75db2b34]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
折叠标签提示可独立关闭和恢复;关闭提示仍保留折叠数量及模型。 完整说明。
芋道宿主桥接与生命周期 ​
完整示例从 @asam-ui/ui-yudao 导入实际 createYudaoProvider,并在独立子应用安装。 完整说明。
实际芋道桥接、共享确保与可选刷新
<!-- 此演示还使用 @asam-ui/ui-yudao,请按官网对应指南配置这些公开依赖。 -->
<template><StandaloneDemo /></template>
<script lang="ts" setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
import * as __external2 from "@asam-ui/ui-yudao";
const __external: any = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true },
"@asam-ui/ui-yudao": { ...__external2, __esModule: true }};
const __modules: any = {
"Demo.vue": (module: any, exports: any, require: any) => {
"use strict";
var __importDefault: any = function (mod?: any) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = { class: "demo-layout-1" };
const _hoisted_2: any = { "data-testid": "yudao-contract-result" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
const Child_vue_1: any = __importDefault(require("./Child.vue"));
const provider_js_1: any = require("./provider.js");
const contract_js_1: any = require("./contract.js");
const UploadConsumer_vue_1: any = __importDefault(require("./UploadConsumer.vue"));
const upload_js_1: any = require("./upload.js");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectYudaoBridgeDemo' },
__name: 'Demo',
setup(__props?: any) {
const uploadHost: any = (0, vue_3.ref)();
let uploadApp: any;
let uploadDemo: any;
function showUploadProtocol() {
if (!uploadHost.value || uploadApp)
return;
uploadDemo = (0, upload_js_1.createUploadDemo)();
uploadApp = (0, vue_3.createApp)(UploadConsumer_vue_1.default);
uploadApp.provide('data009-upload-demo', uploadDemo);
(0, ui_1.provideAsamData)(uploadApp, uploadDemo.provider, { scope: 'data009-upload-contract' });
uploadApp.mount(uploadHost.value);
}
const contractResult: any = (0, vue_3.ref)('未执行');
async function checkBridge() {
try {
contractResult.value = JSON.stringify(await (0, contract_js_1.runYudaoBridgeContract)());
}
catch (error: any) {
contractResult.value = JSON.stringify({
status: 'FAIL',
message: error instanceof Error ? error.message : String(error)
});
}
}
const host: any = (0, vue_3.ref)();
const withoutRefreshHost: any = (0, vue_3.ref)();
let app: any;
let withoutRefreshApp: any;
(0, vue_3.onMounted)(() => {
if (!host.value)
return;
const demo: any = (0, provider_js_1.createBridge)();
app = (0, vue_3.createApp)(Child_vue_1.default);
app.provide('yudao-bridge-demo', demo);
(0, ui_1.provideAsamData)(app, demo.provider, { scope: 'yudao-local-demo' });
app.mount(host.value);
});
function showWithoutRefresh() {
if (!withoutRefreshHost.value || withoutRefreshApp)
return;
const demo: any = (0, provider_js_1.createBridge)(false);
withoutRefreshApp = (0, vue_3.createApp)(Child_vue_1.default);
withoutRefreshApp.provide('yudao-bridge-demo', demo);
(0, ui_1.provideAsamData)(withoutRefreshApp, demo.provider, { scope: 'yudao-no-refresh-demo' });
withoutRefreshApp.mount(withoutRefreshHost.value);
}
(0, vue_3.onBeforeUnmount)(() => {
uploadApp?.unmount();
uploadDemo?.releaseHeld();
app?.unmount();
withoutRefreshApp?.unmount();
});
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("section", _hoisted_1, [
(0, vue_2.createElementVNode)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: showWithoutRefresh
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[0] || (_cache[0] = [
(0, vue_2.createTextVNode)("展示未提供 refresh 的桥接", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createElementVNode)("div", {
ref_key: "withoutRefreshHost",
ref: withoutRefreshHost,
"data-testid": "yudao-without-refresh"
}, null, 512 /* NEED_PATCH */),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: checkBridge
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[1] || (_cache[1] = [
(0, vue_2.createTextVNode)("检查完整宿主桥", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createElementVNode)("pre", _hoisted_2, (0, vue_2.toDisplayString)(contractResult.value), 1 /* TEXT */),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: showUploadProtocol
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[2] || (_cache[2] = [
(0, vue_2.createTextVNode)("展示上传数据协议", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createElementVNode)("div", {
ref_key: "uploadHost",
ref: uploadHost
}, null, 512 /* NEED_PATCH */)
]));
};
}
});
exports.default.__scopeId = "data-v-831fb3cf";
},
"provider.ts": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createBridge = createBridge;
const vue_1: any = require("vue");
const ui_yudao_1: any = require("@asam-ui/ui-yudao");
/** Host cache and transport are local to this complete example; no URL is contacted. */
function createBridge(supportsRefresh: any = true) {
const state: any = (0, vue_1.reactive)({
supportsRefresh,
generation: 0,
slow: false,
failure: false,
aborts: 0,
reads: 0,
calls: []
});
let release: any = () => undefined;
const record: any = (kind?: any, context?: any) => state.calls.push({
kind,
scope: context.scope,
epoch: context.epoch,
requestId: context.requestId
});
const provider: any = (0, ui_yudao_1.createYudaoProvider)({
dict: {
async ensure(context?: any) {
record('ensure', context);
context.signal.throwIfAborted();
if (state.slow)
await new Promise((resolve?: any, reject?: any) => {
const abort: any = () => {
state.aborts++;
context.signal.removeEventListener('abort', abort);
reject(context.signal.reason);
};
context.signal.addEventListener('abort', abort, { once: true });
release = () => {
context.signal.removeEventListener('abort', abort);
resolve();
};
});
context.signal.throwIfAborted();
if (state.failure)
throw new Error('Local host dictionary failed');
},
get(type?: any) {
if (type !== 'members')
throw new Error('Unknown local dictionary');
state.reads++;
return [
{ label: '第一成员 G' + state.generation, value: 1 },
{ label: '第二成员 G' + state.generation, value: 2 }
];
},
...(supportsRefresh
? {
async refresh(context?: any) {
record('refresh', context);
context.signal.throwIfAborted();
state.generation++;
}
}
: {})
}
});
return { state, provider, release: () => release() };
}
},
"Child.vue": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = { class: "demo-spacing-1" };
const _hoisted_2: any = { "data-testid": "yudao-observation" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectYudaoBridgeChild' },
__name: 'Child',
setup(__props?: any) {
const injected: any = (0, vue_3.inject)('yudao-bridge-demo');
if (!injected)
throw new Error('Demo.vue must provide its local bridge');
const demo: any = injected;
const first: any = (0, vue_3.ref)();
const second: any = (0, vue_3.ref)();
const firstValue: any = (0, vue_3.ref)(null);
const secondValue: any = (0, vue_3.ref)(null);
const firstStatus: any = (0, vue_3.ref)('loading');
const secondStatus: any = (0, vue_3.ref)('loading');
const transaction: any = (0, vue_3.ref)('idle');
async function reload() {
const results: any = await Promise.all([
first.value?.reload({ force: true }),
second.value?.reload({ force: true })
]);
transaction.value = results.map((result?: any) => result?.status).join('/');
}
async function cached() {
const results: any = await Promise.all([first.value?.reload(), second.value?.reload()]);
transaction.value = results.map((result?: any) => result?.status).join('/');
}
function hold() {
demo.state.slow = true;
transaction.value = 'waiting';
void reload();
first.value?.cancel();
}
function release() {
demo.state.slow = false;
demo.release();
}
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("section", _hoisted_1, [
(0, vue_2.createCommentVNode)(" prettier-ignore "),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamCheckboxItem), {
modelValue: (0, vue_2.unref)(demo).state.failure,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event?: any) => (((0, vue_2.unref)(demo).state.failure) = $event))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[7] || (_cache[7] = [
(0, vue_2.createTextVNode)(" 模拟宿主字典失败 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: cached
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[8] || (_cache[8] = [
(0, vue_2.createTextVNode)("重读宿主字典缓存", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: reload
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[9] || (_cache[9] = [
(0, vue_2.createTextVNode)("重载两个字典", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: hold
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[10] || (_cache[10] = [
(0, vue_2.createTextVNode)("重载并取消第一字典", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: release
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[11] || (_cache[11] = [
(0, vue_2.createTextVNode)("完成宿主 ensure", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: reload
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[12] || (_cache[12] = [
(0, vue_2.createTextVNode)("刷新宿主世代", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamDictSelect), {
ref_key: "first",
ref: first,
modelValue: firstValue.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event?: any) => ((firstValue).value = $event)),
"dict-type": "members",
"dict-value-type": "number",
teleported: false,
onSuccess: _cache[2] || (_cache[2] = ($event?: any) => (firstStatus.value = 'success')),
onError: _cache[3] || (_cache[3] = ($event?: any) => (firstStatus.value = $event.kind))
}, null, 8 /* PROPS */, ["modelValue"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamDictSelect), {
ref_key: "second",
ref: second,
modelValue: secondValue.value,
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event?: any) => ((secondValue).value = $event)),
"dict-type": "members",
"dict-value-type": "number",
teleported: false,
onSuccess: _cache[5] || (_cache[5] = ($event?: any) => (secondStatus.value = 'success')),
onError: _cache[6] || (_cache[6] = ($event?: any) => (secondStatus.value = $event.kind))
}, null, 8 /* PROPS */, ["modelValue"]),
(0, vue_2.createElementVNode)("pre", _hoisted_2, (0, vue_2.toDisplayString)(JSON.stringify({
firstValue: firstValue.value,
secondValue: secondValue.value,
firstStatus: firstStatus.value,
secondStatus: secondStatus.value,
transaction: transaction.value,
...(0, vue_2.unref)(demo).state
})), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-8542b023";
},
"contract.ts": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runYudaoBridgeContract = runYudaoBridgeContract;
const ui_yudao_1: any = require("@asam-ui/ui-yudao");
const ui_1: any = require("@asam-ui/ui");
/** All transports and files are local fixtures; this function contacts no endpoint. */
async function runYudaoBridgeContract() {
const observations: any = [];
const check: any = (value?: any, label?: any) => {
if (!value)
throw Error(label);
};
const record: any = (phase?: any, state?: any) => observations.push({ phase, state });
const requests: any = [];
const notices: any = [];
const ownedCause: any = Error('host already notified');
const bridge: any = {
request: async (config?: any, context?: any) => {
requests.push({ config, context });
return { code: 0, data: [{ label: 'Local', value: 0 }] };
},
upload: async (config?: any, input?: any, context?: any) => {
context.reportProgress({ loaded: input.file.size, total: input.file.size });
return { config, input, context };
},
isErrorNotified: (cause?: any) => cause === ownedCause,
onError: (error?: any) => {
notices.push(error);
}
};
const provider: any = (0, ui_yudao_1.createYudaoProvider)(bridge);
check(requests.length === 0 && notices.length === 0, 'construction must be inert');
check(provider.request === bridge.request &&
provider.upload === bridge.upload &&
provider.onError === bridge.onError &&
provider.isErrorNotified === bridge.isErrorNotified, 'callbacks must retain identity');
check(Object.isFrozen(provider) &&
Object.isFrozen(provider.pagination) &&
!Object.isFrozen(bridge), 'freeze provider rather than host bridge');
record('yudao-inert-construction-frozen-provider-and-original-callbacks', {
calls: requests.length,
notices: notices.length,
callbackIdentity: true,
providerFrozen: true,
paginationFrozen: true,
hostFrozen: false,
pagination: provider.pagination
});
const runtime: any = (0, ui_1.createAsamDataRuntime)({ provider, scope: 'yudao-contract' });
const context: any = runtime.createContext();
try {
const params: any = { tenant: 'local' }, data: any = { body: true };
const source: any = (0, ui_1.defineAsamOptions)().request({
request: { url: '/local-contract', method: 'post', params, data }
});
const options: any = await (0, ui_1.resolveAsamOptions)(source, { provider, context });
check(requests.length === 1 && requests[0].context === context, 'request context identity');
check(requests[0].config.params === params && requests[0].config.data === data, 'request payload ownership');
check(options[0].value === 0, 'request unwrap and core normalization');
record('yudao-real-core-request-context-and-payload-ownership', {
url: requests[0].config.url,
method: requests[0].config.method,
scope: context.scope,
sameContext: true,
sameParams: true,
sameData: true,
values: options.map((o?: any) => o.value)
});
const progress: any = [], input: any = {
file: new File(['abc'], 'local.txt', { type: 'text/plain' }),
fieldName: 'attachment',
data: { tenant: 'local', payload: new Blob(['z']) }
};
const uploadContext: any = {
...context,
reportProgress: (p?: any) => {
progress.push(p.loaded);
}
};
const config: any = { url: '/local-upload', method: 'put', params };
const uploaded: any = await provider.upload(config, input, uploadContext);
if (typeof uploaded !== 'object' || uploaded === null)
throw Error('upload echo');
check(Reflect.get(uploaded, 'input') === input &&
Reflect.get(uploaded, 'context') === uploadContext &&
Reflect.get(uploaded, 'config') === config, 'upload passthrough identity');
check(progress.length === 1 && progress[0] === 3, 'upload progress forwarding');
record('yudao-upload-original-transport-and-progress-passthrough', {
sameConfig: true,
sameInput: true,
sameContext: true,
name: input.file.name,
fieldName: input.fieldName,
progress
});
const row: any = { label: 'Decoded', value: false };
const values: any = [];
for (const response of ([
[row],
{ data: [row] },
{ code: 0, data: [row] },
{ code: 200, data: [row] }
] as any)) {
const source: any = (0, ui_1.defineAsamOptions)().api({
api: async () => response,
params: undefined
});
values.push((await (0, ui_1.resolveAsamOptions)(source, { provider, context }))[0].value);
}
const badCodes: any = ['0', 500, null, undefined];
const failures: any = [];
for (const response of ([
...badCodes.map((code?: any) => ({ code, data: [row] })),
{ code: 0, data: { data: [row] } }
] as any)) {
try {
await (0, ui_1.resolveAsamOptions)((0, ui_1.defineAsamOptions)().api({ api: async () => response, params: undefined }), { provider, context });
throw Error('invalid response accepted');
}
catch (error: any) {
check(typeof error === 'object' &&
error !== null &&
Reflect.get(error, 'kind') === 'response', 'one-envelope response rejection');
failures.push('response');
}
}
check(values.length === 4 && values.every((value?: any) => value === false), 'accepted envelopes preserve false');
record('yudao-one-layer-options-and-five-response-rejections', { values, failures });
const pages: any = [
{ list: [{ id: 0 }], total: 1 },
{ code: 0, data: { list: [{ id: 0 }], total: 1 } },
{ code: 200, list: [{ id: 0 }], total: 1 }
].map((response?: any) => (0, ui_1.resolveAsamPage)(response, undefined, provider));
for (const page of (pages as any))
check(page.total === 1 && page.list[0].id === 0, 'page decoding');
let ambiguous: any = false;
try {
(0, ui_1.resolveAsamPage)({ code: 0, list: [{ id: 1 }], total: 1, data: { list: [{ id: 2 }], total: 1 } }, undefined, provider);
}
catch (error: any) {
ambiguous =
typeof error === 'object' &&
error !== null &&
Reflect.get(error, 'kind') === 'response';
}
check(ambiguous, 'competing page paths rejected');
record('yudao-page-default-keys-one-envelope-and-ambiguity', {
pages: pages.map((page?: any) => ({
ids: page.list.map((row?: any) => row.id),
total: page.total
})),
ambiguous
});
const owned: any = {
kind: 'request',
message: 'owned',
cause: ownedCause,
notified: false
};
const ownedResult: any = runtime.reportError(owned, context);
check(ownedResult.notified && notices.length === 0, 'host ownership suppresses duplicate notice');
const fresh: any = {
kind: 'request',
message: 'new',
cause: Error('new'),
notified: false
};
const first: any = runtime.reportError(fresh, context), second: any = runtime.reportError(fresh, context);
check(first === second && notices.length === 1 && first.notified, 'normal notice deduplicates');
record('yudao-explicit-host-error-ownership-and-notice-deduplication', {
hostOwnedNotified: ownedResult.notified,
freshNotified: first.notified,
notices: notices.length,
sameReportedError: first === second
});
const invalid: any = [
null,
[],
'bridge',
{ request: 1 },
{ upload: 1 },
{ isErrorNotified: true },
{ onError: true },
{ dict: null },
{ dict: [] },
{ dict: {} },
{ dict: { ensure: async () => { }, get: 1 } },
{ dict: { ensure: 1, get: () => [] } },
{ dict: { ensure: async () => { }, get: () => [], refresh: 1 } }
];
const rejected: any = [];
for (const value of (invalid as any)) {
try {
(Reflect.apply(ui_yudao_1.createYudaoProvider, undefined, [value]) as any);
throw Error('invalid bridge accepted');
}
catch (error: any) {
check(typeof error === 'object' &&
error !== null &&
Reflect.get(error, 'kind') === 'config', 'bridge shape rejected before IO');
rejected.push('config');
}
}
const empty: any = (0, ui_yudao_1.createYudaoProvider)({});
check(empty.request === undefined &&
empty.upload === undefined &&
empty.dict === undefined &&
typeof empty.adaptOptions === 'function' &&
typeof empty.adaptPage === 'function', 'empty bridge supports decoding only');
record('yudao-thirteen-invalid-bridges-and-empty-bridge', {
rejected,
emptyHasTransport: false,
emptyHasAdapters: true
});
return { status: 'PASS', observations };
}
finally {
runtime.release(context);
}
}
},
"UploadConsumer.vue": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = {
class: "demo-spacing-1",
"data-testid": "upload-protocol-consumer"
};
const _hoisted_2: any = {
class: "demo-spacing-2",
"data-testid": "upload-handler"
};
const _hoisted_3: any = {
class: "demo-spacing-3",
"data-testid": "upload-request"
};
const _hoisted_4: any = { "data-testid": "upload-data-state" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'Data009UploadProtocolConsumer' },
__name: 'UploadConsumer',
setup(__props?: any) {
const provided: any = (0, vue_3.inject)('data009-upload-demo');
if (!provided)
throw Error('upload demo provider is required');
const demo: any = provided;
function acceptModel(owner?: any, value?: any) {
if (value !== null && !('id' in value))
throw Error('single resource model is required');
if (owner === 'handler')
handlerModel.value = value;
else
requestModel.value = value;
}
const handlerControl: any = (0, vue_3.ref)();
const requestControl: any = (0, vue_3.ref)();
const handlerModel: any = (0, vue_3.ref)(null), requestModel: any = (0, vue_3.ref)(null);
const handlerProgress: any = (0, vue_3.ref)([]), requestProgress: any = (0, vue_3.ref)([]);
const handlerSuccess: any = (0, vue_3.ref)(0), requestSuccess: any = (0, vue_3.ref)(0), handlerCancelled: any = (0, vue_3.ref)(0), requestCancelled: any = (0, vue_3.ref)(0);
const errors: any = (0, vue_3.ref)([]);
function recordError(owner?: any, error?: any) {
errors.value.push({ owner, kind: error.kind, message: error.message });
}
const request: any = (0, vue_3.computed)(() => {
const config: any = {
url: '/local-upload',
params: demo.params,
transform: demo.transform
};
return demo.state.method === 'put' ? { ...config, method: 'put' } : config;
});
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("section", _hoisted_1, [
(0, vue_2.createElementVNode)("label", null, [
_cache[17] || (_cache[17] = (0, vue_2.createElementVNode)("span", null, "上传响应场景", -1 /* CACHED */)),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamSelect), {
modelValue: (0, vue_2.unref)(demo).state.responseCase,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event?: any) => (((0, vue_2.unref)(demo).state.responseCase) = $event)),
"aria-label": "上传响应场景"
}, {
default: (0, vue_2.withCtx)(() => [
((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)(vue_2.Fragment, null, (0, vue_2.renderList)([
'valid',
'empty-id',
'unsafe-url',
'nan-size',
'reject',
'transform-throw',
'thenable',
'hold'
], (value?: any) => {
return (0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamOption), {
key: value,
label: value,
value: value
}, {
default: (0, vue_2.withCtx)(() => [
(0, vue_2.createTextVNode)((0, vue_2.toDisplayString)(value), 1 /* TEXT */)
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["label", "value"]);
}), 64 /* STABLE_FRAGMENT */))
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"])
]),
(0, vue_2.createElementVNode)("label", null, [
_cache[20] || (_cache[20] = (0, vue_2.createElementVNode)("span", null, "请求上传方法", -1 /* CACHED */)),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamSelect), {
modelValue: (0, vue_2.unref)(demo).state.method,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event?: any) => (((0, vue_2.unref)(demo).state.method) = $event)),
"aria-label": "请求上传方法"
}, {
default: (0, vue_2.withCtx)(() => [
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamOption), {
label: 'default',
value: 'default'
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[18] || (_cache[18] = [
(0, vue_2.createTextVNode)("default", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamOption), {
label: 'put',
value: 'put'
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[19] || (_cache[19] = [
(0, vue_2.createTextVNode)("put", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
})
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"])
]),
(0, vue_2.createElementVNode)("fieldset", _hoisted_2, [
_cache[23] || (_cache[23] = (0, vue_2.createElementVNode)("legend", null, "完整资源处理器", -1 /* CACHED */)),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamUpload), {
ref_key: "handlerControl",
ref: handlerControl,
"model-value": handlerModel.value,
mode: "resource",
upload: (0, vue_2.unref)(demo).upload,
data: (0, vue_2.unref)(demo).data,
"field-name": "attachment",
size: "default",
"onUpdate:modelValue": _cache[2] || (_cache[2] = (value?: any) => acceptModel('handler', value)),
onProgress: _cache[3] || (_cache[3] = ($event?: any) => (handlerProgress.value.push($event.percent ?? null))),
onSuccess: _cache[4] || (_cache[4] = ($event?: any) => (handlerSuccess.value++)),
onError: _cache[5] || (_cache[5] = ($event?: any) => (recordError('handler', $event))),
onCancelled: _cache[6] || (_cache[6] = ($event?: any) => (handlerCancelled.value++))
}, null, 8 /* PROPS */, ["model-value", "upload", "data"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[7] || (_cache[7] = ($event?: any) => (handlerControl.value?.clear()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[21] || (_cache[21] = [
(0, vue_2.createTextVNode)("清空直接上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[8] || (_cache[8] = ($event?: any) => (handlerControl.value?.cancel()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[22] || (_cache[22] = [
(0, vue_2.createTextVNode)("取消直接上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
})
]),
(0, vue_2.createElementVNode)("fieldset", _hoisted_3, [
_cache[26] || (_cache[26] = (0, vue_2.createElementVNode)("legend", null, "未知响应传输与同步转换", -1 /* CACHED */)),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamUpload), {
ref_key: "requestControl",
ref: requestControl,
"model-value": requestModel.value,
mode: "resource",
request: request.value,
data: (0, vue_2.unref)(demo).data,
"field-name": "attachment",
size: "default",
"onUpdate:modelValue": _cache[9] || (_cache[9] = (value?: any) => acceptModel('request', value)),
onProgress: _cache[10] || (_cache[10] = ($event?: any) => (requestProgress.value.push($event.percent ?? null))),
onSuccess: _cache[11] || (_cache[11] = ($event?: any) => (requestSuccess.value++)),
onError: _cache[12] || (_cache[12] = ($event?: any) => (recordError('request', $event))),
onCancelled: _cache[13] || (_cache[13] = ($event?: any) => (requestCancelled.value++))
}, null, 8 /* PROPS */, ["model-value", "request", "data"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[14] || (_cache[14] = ($event?: any) => (requestControl.value?.clear()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[24] || (_cache[24] = [
(0, vue_2.createTextVNode)("清空请求上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[15] || (_cache[15] = ($event?: any) => (requestControl.value?.cancel()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[25] || (_cache[25] = [
(0, vue_2.createTextVNode)("取消请求上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
})
]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[16] || (_cache[16] = ($event?: any) => ((0, vue_2.unref)(demo).releaseHeld()))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[27] || (_cache[27] = [
(0, vue_2.createTextVNode)("完成迟到上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_2.createElementVNode)("pre", _hoisted_4, (0, vue_2.toDisplayString)(JSON.stringify({
handlerModel: handlerModel.value,
requestModel: requestModel.value,
handlerProgress: handlerProgress.value,
requestProgress: requestProgress.value,
handlerSuccess: handlerSuccess.value,
requestSuccess: requestSuccess.value,
handlerCancelled: handlerCancelled.value,
requestCancelled: requestCancelled.value,
errors: errors.value,
calls: (0, vue_2.unref)(demo).state.calls,
notices: (0, vue_2.unref)(demo).state.notices,
held: (0, vue_2.unref)(demo).state.held,
released: (0, vue_2.unref)(demo).state.released,
abortedHeld: (0, vue_2.unref)(demo).state.abortedHeld,
transformSameInput: (0, vue_2.unref)(demo).state.transformSameInput
})), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-22e84804";
},
"upload.ts": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createUploadDemo = createUploadDemo;
const vue_1: any = require("vue");
function createUploadDemo() {
const state: any = (0, vue_1.reactive)({
responseCase: 'valid',
method: 'default',
calls: [],
notices: 0,
held: 0,
released: 0,
abortedHeld: 0,
transformSameInput: []
});
const params: any = Object.freeze({ tenant: 'local' });
const data: any = Object.freeze({
tenant: 'local',
payload: new Blob(['extra'])
});
const pending: any = new Set();
let transportedInput: any;
async function transfer(owner?: any, input?: any, context?: any, method?: any, sameParams?: any) {
state.calls.push({
owner,
name: input.file.name,
size: input.file.size,
fieldName: input.fieldName,
tenant: input.data?.tenant,
blobText: input.data?.payload instanceof Blob ? await input.data.payload.text() : '',
fileIsFile: input.file instanceof File,
scope: context.scope,
signalIsAbortSignal: context.signal instanceof AbortSignal,
method,
sameParams
});
context.reportProgress({ loaded: 0 });
context.reportProgress({ loaded: 2, total: 4 });
context.reportProgress({ loaded: -1, total: 4 });
context.reportProgress({ loaded: 5, total: 4 });
context.reportProgress({ loaded: NaN });
if (state.responseCase === 'reject')
throw Error('local upload transport rejected');
if (state.responseCase === 'hold') {
await new Promise((resolve?: any) => {
const operation: any = { input, context, resolve };
pending.add(operation);
state.held = pending.size;
context.signal.addEventListener('abort', () => {
if (pending.has(operation))
state.abortedHeld++;
}, { once: true });
});
}
context.reportProgress({ loaded: 4, total: 4 });
}
function resource(input?: any, owner?: any) {
return {
id: state.responseCase === 'empty-id' ? '' : `${owner}:${input.file.name}`,
name: input.file.name,
url: state.responseCase === 'unsafe-url'
? 'javascript:bad'
: '/local-resources/' + encodeURIComponent(input.file.name),
mimeType: input.file.type,
size: state.responseCase === 'nan-size' ? NaN : input.file.size
};
}
const provider: any = {
upload: async (config?: any, input?: any, context?: any) => {
transportedInput = input;
await transfer('request', input, context, config.method ?? null, config.params === params);
return { kind: 'local-resource', name: input.file.name };
},
onError: () => {
state.notices++;
}
};
return {
state,
provider,
params,
data,
async upload(input?: any, context?: any) {
await transfer('handler', input, context, null, true);
return resource(input, 'handler');
},
transform(response?: any, input?: any) {
state.transformSameInput.push(input === transportedInput);
if (!response ||
typeof response !== 'object' ||
Reflect.get(response, 'kind') !== 'local-resource' ||
Reflect.get(response, 'name') !== input.file.name)
throw Error('invalid local response');
if (state.responseCase === 'transform-throw')
throw Error('local transform rejected');
const result: any = resource(input, 'request');
if (state.responseCase === 'thenable') {
const thenable: any = {
...result,
then(resolve?: any) {
resolve(result);
}
};
return thenable;
}
return result;
},
releaseHeld() {
for (const operation of (pending as any)) {
pending.delete(operation);
operation.resolve();
state.released++;
}
state.held = pending.size;
}
};
}
},
};
const __dependencies: any = {"Demo.vue":{"./Child.vue":"Child.vue","./provider.js":"provider.ts","./contract.js":"contract.ts","./UploadConsumer.vue":"UploadConsumer.vue","./upload.js":"upload.ts"},"provider.ts":{},"Child.vue":{"./provider.js":"provider.ts"},"contract.ts":{},"UploadConsumer.vue":{"./upload.js":"upload.ts"},"upload.ts":{}};
const __cache: any = Object.create(null);
function __require(id: any): any {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module: any = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency: any) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-layout-1[data-v-831fb3cf] {
display: grid;
gap: var(--asam-space-md);
}
.demo-spacing-1[data-v-8542b023] {
display: grid;
gap: var(--asam-space-md);
}
.demo-spacing-1[data-v-22e84804] {
display: grid;
gap: var(--asam-space-md);
}
.demo-spacing-2[data-v-22e84804] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-md);
}
.demo-spacing-3[data-v-22e84804] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-md);
}
</style>
<!-- 此演示还使用 @asam-ui/ui-yudao,请按官网对应指南配置这些公开依赖。 -->
<template><StandaloneDemo /></template>
<script setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
import * as __external2 from "@asam-ui/ui-yudao";
const __external = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true },
"@asam-ui/ui-yudao": { ...__external2, __esModule: true }};
const __modules = {
"Demo.vue": (module, exports, require) => {
"use strict";
var __importDefault = function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = { class: "demo-layout-1" };
const _hoisted_2 = { "data-testid": "yudao-contract-result" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
const Child_vue_1 = __importDefault(require("./Child.vue"));
const provider_js_1 = require("./provider.js");
const contract_js_1 = require("./contract.js");
const UploadConsumer_vue_1 = __importDefault(require("./UploadConsumer.vue"));
const upload_js_1 = require("./upload.js");
exports.default = Object.assign({ name: 'AsamDictSelectYudaoBridgeDemo' }, {
__name: 'Demo',
setup(__props) {
const uploadHost = (0, vue_2.ref)();
let uploadApp;
let uploadDemo;
function showUploadProtocol() {
if (!uploadHost.value || uploadApp)
return;
uploadDemo = (0, upload_js_1.createUploadDemo)();
uploadApp = (0, vue_2.createApp)(UploadConsumer_vue_1.default);
uploadApp.provide('data009-upload-demo', uploadDemo);
(0, ui_1.provideAsamData)(uploadApp, uploadDemo.provider, { scope: 'data009-upload-contract' });
uploadApp.mount(uploadHost.value);
}
const contractResult = (0, vue_2.ref)('未执行');
async function checkBridge() {
try {
contractResult.value = JSON.stringify(await (0, contract_js_1.runYudaoBridgeContract)());
}
catch (error) {
contractResult.value = JSON.stringify({
status: 'FAIL',
message: error instanceof Error ? error.message : String(error)
});
}
}
const host = (0, vue_2.ref)();
const withoutRefreshHost = (0, vue_2.ref)();
let app;
let withoutRefreshApp;
(0, vue_2.onMounted)(() => {
if (!host.value)
return;
const demo = (0, provider_js_1.createBridge)();
app = (0, vue_2.createApp)(Child_vue_1.default);
app.provide('yudao-bridge-demo', demo);
(0, ui_1.provideAsamData)(app, demo.provider, { scope: 'yudao-local-demo' });
app.mount(host.value);
});
function showWithoutRefresh() {
if (!withoutRefreshHost.value || withoutRefreshApp)
return;
const demo = (0, provider_js_1.createBridge)(false);
withoutRefreshApp = (0, vue_2.createApp)(Child_vue_1.default);
withoutRefreshApp.provide('yudao-bridge-demo', demo);
(0, ui_1.provideAsamData)(withoutRefreshApp, demo.provider, { scope: 'yudao-no-refresh-demo' });
withoutRefreshApp.mount(withoutRefreshHost.value);
}
(0, vue_2.onBeforeUnmount)(() => {
uploadApp?.unmount();
uploadDemo?.releaseHeld();
app?.unmount();
withoutRefreshApp?.unmount();
});
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("section", _hoisted_1, [
(0, vue_1.createElementVNode)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: showWithoutRefresh
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[0] || (_cache[0] = [
(0, vue_1.createTextVNode)("展示未提供 refresh 的桥接", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createElementVNode)("div", {
ref_key: "withoutRefreshHost",
ref: withoutRefreshHost,
"data-testid": "yudao-without-refresh"
}, null, 512 /* NEED_PATCH */),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: checkBridge
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[1] || (_cache[1] = [
(0, vue_1.createTextVNode)("检查完整宿主桥", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createElementVNode)("pre", _hoisted_2, (0, vue_1.toDisplayString)(contractResult.value), 1 /* TEXT */),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: showUploadProtocol
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[2] || (_cache[2] = [
(0, vue_1.createTextVNode)("展示上传数据协议", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createElementVNode)("div", {
ref_key: "uploadHost",
ref: uploadHost
}, null, 512 /* NEED_PATCH */)
]));
};
}
});
exports.default.__scopeId = "data-v-48bdd1fe";
},
"provider.js": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createBridge = createBridge;
const vue_1 = require("vue");
const ui_yudao_1 = require("@asam-ui/ui-yudao");
/** Host cache and transport are local to this complete example; no URL is contacted. */
function createBridge(supportsRefresh = true) {
const state = (0, vue_1.reactive)({
supportsRefresh,
generation: 0,
slow: false,
failure: false,
aborts: 0,
reads: 0,
calls: []
});
let release = () => undefined;
const record = (kind, context) => state.calls.push({
kind,
scope: context.scope,
epoch: context.epoch,
requestId: context.requestId
});
const provider = (0, ui_yudao_1.createYudaoProvider)({
dict: {
async ensure(context) {
record('ensure', context);
context.signal.throwIfAborted();
if (state.slow)
await new Promise((resolve, reject) => {
const abort = () => {
state.aborts++;
context.signal.removeEventListener('abort', abort);
reject(context.signal.reason);
};
context.signal.addEventListener('abort', abort, { once: true });
release = () => {
context.signal.removeEventListener('abort', abort);
resolve();
};
});
context.signal.throwIfAborted();
if (state.failure)
throw new Error('Local host dictionary failed');
},
get(type) {
if (type !== 'members')
throw new Error('Unknown local dictionary');
state.reads++;
return [
{ label: '第一成员 G' + state.generation, value: 1 },
{ label: '第二成员 G' + state.generation, value: 2 }
];
},
...(supportsRefresh
? {
async refresh(context) {
record('refresh', context);
context.signal.throwIfAborted();
state.generation++;
}
}
: {})
}
});
return { state, provider, release: () => release() };
}
},
"Child.vue": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = { class: "demo-spacing-1" };
const _hoisted_2 = { "data-testid": "yudao-observation" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
exports.default = Object.assign({ name: 'AsamDictSelectYudaoBridgeChild' }, {
__name: 'Child',
setup(__props) {
const injected = (0, vue_2.inject)('yudao-bridge-demo');
if (!injected)
throw new Error('Demo.vue must provide its local bridge');
const demo = injected;
const first = (0, vue_2.ref)();
const second = (0, vue_2.ref)();
const firstValue = (0, vue_2.ref)(null);
const secondValue = (0, vue_2.ref)(null);
const firstStatus = (0, vue_2.ref)('loading');
const secondStatus = (0, vue_2.ref)('loading');
const transaction = (0, vue_2.ref)('idle');
async function reload() {
const results = await Promise.all([
first.value?.reload({ force: true }),
second.value?.reload({ force: true })
]);
transaction.value = results.map((result) => result?.status).join('/');
}
async function cached() {
const results = await Promise.all([first.value?.reload(), second.value?.reload()]);
transaction.value = results.map((result) => result?.status).join('/');
}
function hold() {
demo.state.slow = true;
transaction.value = 'waiting';
void reload();
first.value?.cancel();
}
function release() {
demo.state.slow = false;
demo.release();
}
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("section", _hoisted_1, [
(0, vue_1.createCommentVNode)(" prettier-ignore "),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamCheckboxItem), {
modelValue: (0, vue_1.unref)(demo).state.failure,
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (((0, vue_1.unref)(demo).state.failure) = $event))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[7] || (_cache[7] = [
(0, vue_1.createTextVNode)(" 模拟宿主字典失败 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: cached
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[8] || (_cache[8] = [
(0, vue_1.createTextVNode)("重读宿主字典缓存", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: reload
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[9] || (_cache[9] = [
(0, vue_1.createTextVNode)("重载两个字典", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: hold
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[10] || (_cache[10] = [
(0, vue_1.createTextVNode)("重载并取消第一字典", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: release
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[11] || (_cache[11] = [
(0, vue_1.createTextVNode)("完成宿主 ensure", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: reload
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[12] || (_cache[12] = [
(0, vue_1.createTextVNode)("刷新宿主世代", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamDictSelect), {
ref_key: "first",
ref: first,
modelValue: firstValue.value,
"onUpdate:modelValue": _cache[1] || (_cache[1] = $event => ((firstValue).value = $event)),
"dict-type": "members",
"dict-value-type": "number",
teleported: false,
onSuccess: _cache[2] || (_cache[2] = $event => (firstStatus.value = 'success')),
onError: _cache[3] || (_cache[3] = $event => (firstStatus.value = $event.kind))
}, null, 8 /* PROPS */, ["modelValue"]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamDictSelect), {
ref_key: "second",
ref: second,
modelValue: secondValue.value,
"onUpdate:modelValue": _cache[4] || (_cache[4] = $event => ((secondValue).value = $event)),
"dict-type": "members",
"dict-value-type": "number",
teleported: false,
onSuccess: _cache[5] || (_cache[5] = $event => (secondStatus.value = 'success')),
onError: _cache[6] || (_cache[6] = $event => (secondStatus.value = $event.kind))
}, null, 8 /* PROPS */, ["modelValue"]),
(0, vue_1.createElementVNode)("pre", _hoisted_2, (0, vue_1.toDisplayString)(JSON.stringify({
firstValue: firstValue.value,
secondValue: secondValue.value,
firstStatus: firstStatus.value,
secondStatus: secondStatus.value,
transaction: transaction.value,
...(0, vue_1.unref)(demo).state
})), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-b3695ce2";
},
"contract.js": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runYudaoBridgeContract = runYudaoBridgeContract;
const ui_yudao_1 = require("@asam-ui/ui-yudao");
const ui_1 = require("@asam-ui/ui");
/** All transports and files are local fixtures; this function contacts no endpoint. */
async function runYudaoBridgeContract() {
const observations = [];
const check = (value, label) => {
if (!value)
throw Error(label);
};
const record = (phase, state) => observations.push({ phase, state });
const requests = [];
const notices = [];
const ownedCause = Error('host already notified');
const bridge = {
request: async (config, context) => {
requests.push({ config, context });
return { code: 0, data: [{ label: 'Local', value: 0 }] };
},
upload: async (config, input, context) => {
context.reportProgress({ loaded: input.file.size, total: input.file.size });
return { config, input, context };
},
isErrorNotified: (cause) => cause === ownedCause,
onError: (error) => {
notices.push(error);
}
};
const provider = (0, ui_yudao_1.createYudaoProvider)(bridge);
check(requests.length === 0 && notices.length === 0, 'construction must be inert');
check(provider.request === bridge.request &&
provider.upload === bridge.upload &&
provider.onError === bridge.onError &&
provider.isErrorNotified === bridge.isErrorNotified, 'callbacks must retain identity');
check(Object.isFrozen(provider) &&
Object.isFrozen(provider.pagination) &&
!Object.isFrozen(bridge), 'freeze provider rather than host bridge');
record('yudao-inert-construction-frozen-provider-and-original-callbacks', {
calls: requests.length,
notices: notices.length,
callbackIdentity: true,
providerFrozen: true,
paginationFrozen: true,
hostFrozen: false,
pagination: provider.pagination
});
const runtime = (0, ui_1.createAsamDataRuntime)({ provider, scope: 'yudao-contract' });
const context = runtime.createContext();
try {
const params = { tenant: 'local' }, data = { body: true };
const source = (0, ui_1.defineAsamOptions)().request({
request: { url: '/local-contract', method: 'post', params, data }
});
const options = await (0, ui_1.resolveAsamOptions)(source, { provider, context });
check(requests.length === 1 && requests[0].context === context, 'request context identity');
check(requests[0].config.params === params && requests[0].config.data === data, 'request payload ownership');
check(options[0].value === 0, 'request unwrap and core normalization');
record('yudao-real-core-request-context-and-payload-ownership', {
url: requests[0].config.url,
method: requests[0].config.method,
scope: context.scope,
sameContext: true,
sameParams: true,
sameData: true,
values: options.map((o) => o.value)
});
const progress = [], input = {
file: new File(['abc'], 'local.txt', { type: 'text/plain' }),
fieldName: 'attachment',
data: { tenant: 'local', payload: new Blob(['z']) }
};
const uploadContext = {
...context,
reportProgress: (p) => {
progress.push(p.loaded);
}
};
const config = { url: '/local-upload', method: 'put', params };
const uploaded = await provider.upload(config, input, uploadContext);
if (typeof uploaded !== 'object' || uploaded === null)
throw Error('upload echo');
check(Reflect.get(uploaded, 'input') === input &&
Reflect.get(uploaded, 'context') === uploadContext &&
Reflect.get(uploaded, 'config') === config, 'upload passthrough identity');
check(progress.length === 1 && progress[0] === 3, 'upload progress forwarding');
record('yudao-upload-original-transport-and-progress-passthrough', {
sameConfig: true,
sameInput: true,
sameContext: true,
name: input.file.name,
fieldName: input.fieldName,
progress
});
const row = { label: 'Decoded', value: false };
const values = [];
for (const response of [
[row],
{ data: [row] },
{ code: 0, data: [row] },
{ code: 200, data: [row] }
]) {
const source = (0, ui_1.defineAsamOptions)().api({
api: async () => response,
params: undefined
});
values.push((await (0, ui_1.resolveAsamOptions)(source, { provider, context }))[0].value);
}
const badCodes = ['0', 500, null, undefined];
const failures = [];
for (const response of [
...badCodes.map((code) => ({ code, data: [row] })),
{ code: 0, data: { data: [row] } }
]) {
try {
await (0, ui_1.resolveAsamOptions)((0, ui_1.defineAsamOptions)().api({ api: async () => response, params: undefined }), { provider, context });
throw Error('invalid response accepted');
}
catch (error) {
check(typeof error === 'object' &&
error !== null &&
Reflect.get(error, 'kind') === 'response', 'one-envelope response rejection');
failures.push('response');
}
}
check(values.length === 4 && values.every((value) => value === false), 'accepted envelopes preserve false');
record('yudao-one-layer-options-and-five-response-rejections', { values, failures });
const pages = [
{ list: [{ id: 0 }], total: 1 },
{ code: 0, data: { list: [{ id: 0 }], total: 1 } },
{ code: 200, list: [{ id: 0 }], total: 1 }
].map((response) => (0, ui_1.resolveAsamPage)(response, undefined, provider));
for (const page of pages)
check(page.total === 1 && page.list[0].id === 0, 'page decoding');
let ambiguous = false;
try {
(0, ui_1.resolveAsamPage)({ code: 0, list: [{ id: 1 }], total: 1, data: { list: [{ id: 2 }], total: 1 } }, undefined, provider);
}
catch (error) {
ambiguous =
typeof error === 'object' &&
error !== null &&
Reflect.get(error, 'kind') === 'response';
}
check(ambiguous, 'competing page paths rejected');
record('yudao-page-default-keys-one-envelope-and-ambiguity', {
pages: pages.map((page) => ({
ids: page.list.map((row) => row.id),
total: page.total
})),
ambiguous
});
const owned = { kind: 'request', message: 'owned', cause: ownedCause, notified: false };
const ownedResult = runtime.reportError(owned, context);
check(ownedResult.notified && notices.length === 0, 'host ownership suppresses duplicate notice');
const fresh = { kind: 'request', message: 'new', cause: Error('new'), notified: false };
const first = runtime.reportError(fresh, context), second = runtime.reportError(fresh, context);
check(first === second && notices.length === 1 && first.notified, 'normal notice deduplicates');
record('yudao-explicit-host-error-ownership-and-notice-deduplication', {
hostOwnedNotified: ownedResult.notified,
freshNotified: first.notified,
notices: notices.length,
sameReportedError: first === second
});
const invalid = [
null,
[],
'bridge',
{ request: 1 },
{ upload: 1 },
{ isErrorNotified: true },
{ onError: true },
{ dict: null },
{ dict: [] },
{ dict: {} },
{ dict: { ensure: async () => { }, get: 1 } },
{ dict: { ensure: 1, get: () => [] } },
{ dict: { ensure: async () => { }, get: () => [], refresh: 1 } }
];
const rejected = [];
for (const value of invalid) {
try {
Reflect.apply(ui_yudao_1.createYudaoProvider, undefined, [value]);
throw Error('invalid bridge accepted');
}
catch (error) {
check(typeof error === 'object' &&
error !== null &&
Reflect.get(error, 'kind') === 'config', 'bridge shape rejected before IO');
rejected.push('config');
}
}
const empty = (0, ui_yudao_1.createYudaoProvider)({});
check(empty.request === undefined &&
empty.upload === undefined &&
empty.dict === undefined &&
typeof empty.adaptOptions === 'function' &&
typeof empty.adaptPage === 'function', 'empty bridge supports decoding only');
record('yudao-thirteen-invalid-bridges-and-empty-bridge', {
rejected,
emptyHasTransport: false,
emptyHasAdapters: true
});
return { status: 'PASS', observations };
}
finally {
runtime.release(context);
}
}
},
"UploadConsumer.vue": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = {
class: "demo-spacing-1",
"data-testid": "upload-protocol-consumer"
};
const _hoisted_2 = {
class: "demo-spacing-2",
"data-testid": "upload-handler"
};
const _hoisted_3 = {
class: "demo-spacing-3",
"data-testid": "upload-request"
};
const _hoisted_4 = { "data-testid": "upload-data-state" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
exports.default = Object.assign({ name: 'Data009UploadProtocolConsumer' }, {
__name: 'UploadConsumer',
setup(__props) {
const provided = (0, vue_2.inject)('data009-upload-demo');
if (!provided)
throw Error('upload demo provider is required');
const demo = provided;
function acceptModel(owner, value) {
if (value !== null && !('id' in value))
throw Error('single resource model is required');
if (owner === 'handler')
handlerModel.value = value;
else
requestModel.value = value;
}
const handlerControl = (0, vue_2.ref)();
const requestControl = (0, vue_2.ref)();
const handlerModel = (0, vue_2.ref)(null), requestModel = (0, vue_2.ref)(null);
const handlerProgress = (0, vue_2.ref)([]), requestProgress = (0, vue_2.ref)([]);
const handlerSuccess = (0, vue_2.ref)(0), requestSuccess = (0, vue_2.ref)(0), handlerCancelled = (0, vue_2.ref)(0), requestCancelled = (0, vue_2.ref)(0);
const errors = (0, vue_2.ref)([]);
function recordError(owner, error) {
errors.value.push({ owner, kind: error.kind, message: error.message });
}
const request = (0, vue_2.computed)(() => {
const config = {
url: '/local-upload',
params: demo.params,
transform: demo.transform
};
return demo.state.method === 'put' ? { ...config, method: 'put' } : config;
});
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("section", _hoisted_1, [
(0, vue_1.createElementVNode)("label", null, [
_cache[17] || (_cache[17] = (0, vue_1.createElementVNode)("span", null, "上传响应场景", -1 /* CACHED */)),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamSelect), {
modelValue: (0, vue_1.unref)(demo).state.responseCase,
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (((0, vue_1.unref)(demo).state.responseCase) = $event)),
"aria-label": "上传响应场景"
}, {
default: (0, vue_1.withCtx)(() => [
((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)(vue_1.Fragment, null, (0, vue_1.renderList)([
'valid',
'empty-id',
'unsafe-url',
'nan-size',
'reject',
'transform-throw',
'thenable',
'hold'
], (value) => {
return (0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamOption), {
key: value,
label: value,
value: value
}, {
default: (0, vue_1.withCtx)(() => [
(0, vue_1.createTextVNode)((0, vue_1.toDisplayString)(value), 1 /* TEXT */)
]),
_: 2 /* DYNAMIC */
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["label", "value"]);
}), 64 /* STABLE_FRAGMENT */))
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"])
]),
(0, vue_1.createElementVNode)("label", null, [
_cache[20] || (_cache[20] = (0, vue_1.createElementVNode)("span", null, "请求上传方法", -1 /* CACHED */)),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamSelect), {
modelValue: (0, vue_1.unref)(demo).state.method,
"onUpdate:modelValue": _cache[1] || (_cache[1] = $event => (((0, vue_1.unref)(demo).state.method) = $event)),
"aria-label": "请求上传方法"
}, {
default: (0, vue_1.withCtx)(() => [
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamOption), {
label: 'default',
value: 'default'
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[18] || (_cache[18] = [
(0, vue_1.createTextVNode)("default", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamOption), {
label: 'put',
value: 'put'
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[19] || (_cache[19] = [
(0, vue_1.createTextVNode)("put", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
})
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue"])
]),
(0, vue_1.createElementVNode)("fieldset", _hoisted_2, [
_cache[23] || (_cache[23] = (0, vue_1.createElementVNode)("legend", null, "完整资源处理器", -1 /* CACHED */)),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamUpload), {
ref_key: "handlerControl",
ref: handlerControl,
"model-value": handlerModel.value,
mode: "resource",
upload: (0, vue_1.unref)(demo).upload,
data: (0, vue_1.unref)(demo).data,
"field-name": "attachment",
size: "default",
"onUpdate:modelValue": _cache[2] || (_cache[2] = (value) => acceptModel('handler', value)),
onProgress: _cache[3] || (_cache[3] = $event => (handlerProgress.value.push($event.percent ?? null))),
onSuccess: _cache[4] || (_cache[4] = $event => (handlerSuccess.value++)),
onError: _cache[5] || (_cache[5] = $event => (recordError('handler', $event))),
onCancelled: _cache[6] || (_cache[6] = $event => (handlerCancelled.value++))
}, null, 8 /* PROPS */, ["model-value", "upload", "data"]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[7] || (_cache[7] = $event => (handlerControl.value?.clear()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[21] || (_cache[21] = [
(0, vue_1.createTextVNode)("清空直接上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[8] || (_cache[8] = $event => (handlerControl.value?.cancel()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[22] || (_cache[22] = [
(0, vue_1.createTextVNode)("取消直接上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
})
]),
(0, vue_1.createElementVNode)("fieldset", _hoisted_3, [
_cache[26] || (_cache[26] = (0, vue_1.createElementVNode)("legend", null, "未知响应传输与同步转换", -1 /* CACHED */)),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamUpload), {
ref_key: "requestControl",
ref: requestControl,
"model-value": requestModel.value,
mode: "resource",
request: request.value,
data: (0, vue_1.unref)(demo).data,
"field-name": "attachment",
size: "default",
"onUpdate:modelValue": _cache[9] || (_cache[9] = (value) => acceptModel('request', value)),
onProgress: _cache[10] || (_cache[10] = $event => (requestProgress.value.push($event.percent ?? null))),
onSuccess: _cache[11] || (_cache[11] = $event => (requestSuccess.value++)),
onError: _cache[12] || (_cache[12] = $event => (recordError('request', $event))),
onCancelled: _cache[13] || (_cache[13] = $event => (requestCancelled.value++))
}, null, 8 /* PROPS */, ["model-value", "request", "data"]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[14] || (_cache[14] = $event => (requestControl.value?.clear()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[24] || (_cache[24] = [
(0, vue_1.createTextVNode)("清空请求上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[15] || (_cache[15] = $event => (requestControl.value?.cancel()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[25] || (_cache[25] = [
(0, vue_1.createTextVNode)("取消请求上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
})
]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
onClick: _cache[16] || (_cache[16] = $event => ((0, vue_1.unref)(demo).releaseHeld()))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[27] || (_cache[27] = [
(0, vue_1.createTextVNode)("完成迟到上传", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}),
(0, vue_1.createElementVNode)("pre", _hoisted_4, (0, vue_1.toDisplayString)(JSON.stringify({
handlerModel: handlerModel.value,
requestModel: requestModel.value,
handlerProgress: handlerProgress.value,
requestProgress: requestProgress.value,
handlerSuccess: handlerSuccess.value,
requestSuccess: requestSuccess.value,
handlerCancelled: handlerCancelled.value,
requestCancelled: requestCancelled.value,
errors: errors.value,
calls: (0, vue_1.unref)(demo).state.calls,
notices: (0, vue_1.unref)(demo).state.notices,
held: (0, vue_1.unref)(demo).state.held,
released: (0, vue_1.unref)(demo).state.released,
abortedHeld: (0, vue_1.unref)(demo).state.abortedHeld,
transformSameInput: (0, vue_1.unref)(demo).state.transformSameInput
})), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-df748fa8";
},
"upload.js": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createUploadDemo = createUploadDemo;
const vue_1 = require("vue");
function createUploadDemo() {
const state = (0, vue_1.reactive)({
responseCase: 'valid',
method: 'default',
calls: [],
notices: 0,
held: 0,
released: 0,
abortedHeld: 0,
transformSameInput: []
});
const params = Object.freeze({ tenant: 'local' });
const data = Object.freeze({ tenant: 'local', payload: new Blob(['extra']) });
const pending = new Set();
let transportedInput;
async function transfer(owner, input, context, method, sameParams) {
state.calls.push({
owner,
name: input.file.name,
size: input.file.size,
fieldName: input.fieldName,
tenant: input.data?.tenant,
blobText: input.data?.payload instanceof Blob ? await input.data.payload.text() : '',
fileIsFile: input.file instanceof File,
scope: context.scope,
signalIsAbortSignal: context.signal instanceof AbortSignal,
method,
sameParams
});
context.reportProgress({ loaded: 0 });
context.reportProgress({ loaded: 2, total: 4 });
context.reportProgress({ loaded: -1, total: 4 });
context.reportProgress({ loaded: 5, total: 4 });
context.reportProgress({ loaded: NaN });
if (state.responseCase === 'reject')
throw Error('local upload transport rejected');
if (state.responseCase === 'hold') {
await new Promise((resolve) => {
const operation = { input, context, resolve };
pending.add(operation);
state.held = pending.size;
context.signal.addEventListener('abort', () => {
if (pending.has(operation))
state.abortedHeld++;
}, { once: true });
});
}
context.reportProgress({ loaded: 4, total: 4 });
}
function resource(input, owner) {
return {
id: state.responseCase === 'empty-id' ? '' : `${owner}:${input.file.name}`,
name: input.file.name,
url: state.responseCase === 'unsafe-url'
? 'javascript:bad'
: '/local-resources/' + encodeURIComponent(input.file.name),
mimeType: input.file.type,
size: state.responseCase === 'nan-size' ? NaN : input.file.size
};
}
const provider = {
upload: async (config, input, context) => {
transportedInput = input;
await transfer('request', input, context, config.method ?? null, config.params === params);
return { kind: 'local-resource', name: input.file.name };
},
onError: () => {
state.notices++;
}
};
return {
state,
provider,
params,
data,
async upload(input, context) {
await transfer('handler', input, context, null, true);
return resource(input, 'handler');
},
transform(response, input) {
state.transformSameInput.push(input === transportedInput);
if (!response ||
typeof response !== 'object' ||
Reflect.get(response, 'kind') !== 'local-resource' ||
Reflect.get(response, 'name') !== input.file.name)
throw Error('invalid local response');
if (state.responseCase === 'transform-throw')
throw Error('local transform rejected');
const result = resource(input, 'request');
if (state.responseCase === 'thenable') {
const thenable = {
...result,
then(resolve) {
resolve(result);
}
};
return thenable;
}
return result;
},
releaseHeld() {
for (const operation of pending) {
pending.delete(operation);
operation.resolve();
state.released++;
}
state.held = pending.size;
}
};
}
},
};
const __dependencies = {"Demo.vue":{"./Child.vue":"Child.vue","./provider.js":"provider.js","./contract.js":"contract.js","./UploadConsumer.vue":"UploadConsumer.vue","./upload.js":"upload.js"},"provider.js":{},"Child.vue":{},"contract.js":{},"UploadConsumer.vue":{},"upload.js":{}};
const __cache = Object.create(null);
function __require(id) {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-layout-1[data-v-48bdd1fe] {
display: grid;
gap: var(--asam-space-md);
}
.demo-spacing-1[data-v-b3695ce2] {
display: grid;
gap: var(--asam-space-md);
}
.demo-spacing-1[data-v-df748fa8] {
display: grid;
gap: var(--asam-space-md);
}
.demo-spacing-2[data-v-df748fa8] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-md);
}
.demo-spacing-3[data-v-df748fa8] {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--asam-space-md);
}
</style>
点击“展示未提供 refresh 的桥接”会创建另一个独立子应用与本地宿主缓存。 完整说明。
完整芋道桥协议 ​
createYudaoProvider(bridge) 返回 AsamDataProvider;构造时只校验配置与保存宿主回调,不执行传输、字典读取或通知。 完整说明。
| 桥成员 | 约定 |
|---|---|
| request | 接收 AsamRequestConfig 和原 AsamRequestContext,返回 Promise 中的未知响应。 |
| upload | 原样转交上传配置、输入 File/附加表单数据及含 reportProgress 的上下文,返回 Promise 中的未知响应。 |
| dict | ensure 返回 Promise,get 同步读取宿主字典,refresh 可选并返回 Promise;读取与刷新按 scope/epoch/世代协调。 |
| isErrorNotified | 同步判断原始 cause 是否已由宿主通知,返回 boolean。 |
| onError | 接收 AsamDataError,通知归属由运行时协调;已通知的错误不重复提示。 |
adapter 不配置 Axios、凭据、端点、Pinia 或宿主缓存。 完整说明。
默认适配只展开一层自有 data。 完整说明。
yudao-bridge 完整 TS/JS 示例的“检查完整宿主桥”按钮实际验证构造无副作用、原请求上下文与载荷、上传 File/进度转交、一层响应与失败、分页歧义、宿主通知去重、13 种无效桥以及空桥。 完整说明。
上传数据协议与完整消费者 ​
yudao-bridge 的“展示上传数据协议”按钮在独立子应用中挂载两个真实资源上传入口,分别消费完整资源处理器和未知响应传输。File、Blob、传输响应、资源地址和进度均在本地示例中构造,示例 URL 不发网络请求。原字典与桥的运行时、缓存和检查按钮独立保留。
| 公开类型 | 数据约定 |
|---|---|
| AsamUploadFormData | 只读字段记录,每个字段为 string 或 Blob;File 是 Blob 的子类型。 |
| AsamUploadInput | 只读 file: File、fieldName: string、可选 data。字段名和附加表单数据由调用方提供。 |
| AsamUploadedResource | 只读 id、name、url、mimeType 字符串和 size 数字;处理器返回完整资源。 |
| AsamUploadProgress | 只读 loaded 数字和可选 total 数字。 |
| AsamUploadContext | 继承请求的 signal/requestId/scope/epoch,并提供 reportProgress(progress) 方法;该方法签名本身不是 readonly 回调属性。 |
| AsamUploadHandler | 接收输入和上传上下文,返回 Promise 中的完整资源。 |
| AsamUploadRequestConfig | 只读 URL、可选 post/put 方法及 params、必填同步 transform(response, input);原响应为 unknown。 |
| AsamUploadTransport | 接收去掉 transform 的请求配置、输入及上传上下文,返回 Promise 中的 unknown,由调用方转换和校验。 |
类型只描述结构,不保证字符串非空、数值有限、地址安全或 Blob 的内容满足业务规则。 完整说明。
reportProgress 不直接提交模型。 完整说明。
取消会中止该上传上下文,已经取消或卸载的操作不能用迟到资源覆盖模型,也不能再发成功、错误或进度。示例可以持有两个来源的操作,取消后再完成,观察 signal 中止、模型保持为空和进度计数不增加。这里消费上传数据协议,不定义或验收上传入口的原生 file-list API。
完整 provider 数据能力 ​
provider 按需提供请求、上传、字典和数据适配能力;实际使用时必须配置对应能力。 完整说明。
provider 的静态只读引用不等于冻结宿主缓存、原始响应或方法内部状态;dict 的 get/refresh 方法签名也不是 readonly 方法引用。 完整说明。
局部请求错误插槽 ​
可选 error 插槽仅在当前请求错误存在时调用,接收只读 { error, stale, retry }。 完整说明。
retry 不接收参数,返回强制 reload 的 Promise,并遵守取消和卸载规则。 完整说明。
提供该插槽时,自有内容替换整个默认局部错误区;返回空内容也表示主动替换。 未提供时继续显示原错误文字、过期提示和默认重试按钮。无 error 的单独 stale 状态 不调用此插槽;empty、loading 和其他基础插槽继续使用原作用域。
以下完整 TS/JS 示例先制造失败,再等待插槽 retry 的返回结果;成功后可再次制造 更新失败,观察旧结果与模型保留。每次挂载使用独立子 app 和本地 provider。
局部错误定制、等待重试与过期恢复
<template><StandaloneDemo /></template>
<script lang="ts" setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external: any = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules: any = {
"Demo.vue": (module: any, exports: any, require: any) => {
"use strict";
var __importDefault: any = function (mod?: any) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
const Child_vue_1: any = __importDefault(require("./Child.vue"));
const transport_js_1: any = require("./transport.js");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectDemoLocalErrorExample' },
__name: 'Demo',
setup(__props?: any) {
const host: any = (0, vue_3.ref)();
let app: any;
(0, vue_3.onMounted)(() => {
if (!host.value)
return;
const transport: any = (0, transport_js_1.createTransport)();
app = (0, vue_3.createApp)(Child_vue_1.default, { transport });
(0, ui_1.provideAsamData)(app, transport.provider, { scope: 'AsamDictSelect-local-error' });
app.mount(host.value);
});
(0, vue_3.onBeforeUnmount)(() => app?.unmount());
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"Child.vue": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1: any = require("vue");
const vue_2: any = require("vue");
const _hoisted_1: any = { class: "demo-spacing-1" };
const _hoisted_2: any = {
role: "alert",
"data-testid": "local-error"
};
const _hoisted_3: any = { class: "example-paragraph" };
const _hoisted_4: any = {
key: 0,
class: "example-paragraph"
};
const _hoisted_5: any = {
class: "example-paragraph",
role: "status",
"data-testid": "retry-result"
};
const _hoisted_6: any = {
class: "example-paragraph",
"data-testid": "transport-count"
};
const _hoisted_7: any = { "data-testid": "local-model" };
const vue_3: any = require("vue");
const ui_1: any = require("@asam-ui/ui");
exports.default = (0, vue_1.defineComponent)({
...{ name: 'AsamDictSelectChildLocalErrorExample' },
__name: 'Child',
props: {
transport: { type: null, required: true }
},
setup(__props?: any) {
const props: any = __props;
const transport: any = props.transport;
const value: any = (0, vue_3.ref)(null);
const control: any = (0, vue_3.ref)();
const busy: any = (0, vue_3.ref)(false), result: any = (0, vue_3.ref)('');
const dataSource: any = (0, ui_1.defineAsamDictSource)({ dictType: 'local-error-status' });
(0, vue_3.onMounted)(async () => {
const response: any = await control.value?.reload();
result.value = response?.status ?? 'cancelled';
});
async function recover(retry?: any) {
busy.value = true;
transport.failing.value = false;
try {
const response: any = await retry();
result.value = response.status;
}
finally {
busy.value = false;
}
}
async function failAgain() {
busy.value = true;
transport.failing.value = true;
try {
const response: any = await control.value?.reload({ force: true });
result.value = response?.status ?? 'cancelled';
}
finally {
busy.value = false;
}
}
return (_ctx?: any, _cache?: any) => {
return ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("section", _hoisted_1, [
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamDictSelect), {
ref_key: "control",
ref: control,
modelValue: value.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event?: any) => ((value).value = $event)),
"data-source": (0, vue_2.unref)(dataSource),
immediate: false
}, {
error: (0, vue_2.withCtx)(({ error, stale, retry }: any) => [
(0, vue_2.createElementVNode)("div", _hoisted_2, [
(0, vue_2.createElementVNode)("p", _hoisted_3, (0, vue_2.toDisplayString)(error.message) + "(" + (0, vue_2.toDisplayString)(error.kind) + ")", 1 /* TEXT */),
stale
? ((0, vue_2.openBlock)(), (0, vue_2.createElementBlock)("p", _hoisted_4, "已保留上次成功结果。"))
: (0, vue_2.createCommentVNode)("v-if", true),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: busy.value,
onClick: ($event?: any) => (recover(retry))
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[1] || (_cache[1] = [
(0, vue_2.createTextVNode)(" 恢复并重试 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled", "onClick"])
])
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "data-source"]),
(0, vue_2.createVNode)((0, vue_2.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: busy.value,
onClick: failAgain
}, {
default: (0, vue_2.withCtx)(() => [...(_cache[2] || (_cache[2] = [
(0, vue_2.createTextVNode)("模拟更新失败", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled"]),
(0, vue_2.createElementVNode)("p", _hoisted_5, (0, vue_2.toDisplayString)(result.value), 1 /* TEXT */),
(0, vue_2.createElementVNode)("p", _hoisted_6, " 请求 " + (0, vue_2.toDisplayString)((0, vue_2.unref)(transport).calls.value) + " 次,字典刷新 " + (0, vue_2.toDisplayString)((0, vue_2.unref)(transport).refreshes.value) + " 次 ", 1 /* TEXT */),
(0, vue_2.createElementVNode)("pre", _hoisted_7, (0, vue_2.toDisplayString)(value.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-0e8a364c";
},
"transport.ts": (module: any, exports: any, require: any) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTransport = createTransport;
const vue_1: any = require("vue");
function createTransport() {
const failing: any = (0, vue_1.ref)(true), calls: any = (0, vue_1.ref)(0), refreshes: any = (0, vue_1.ref)(0);
const api: any = async () => {
calls.value++;
if (failing.value)
throw Error('演示请求暂不可用');
return [
{ id: 1, value: 'ready', label: '准备' },
{ id: 2, value: 'running', label: '进行' }
];
};
const provider: any = {
dict: {
get: async (_type?: any, context?: any) => {
context.signal.throwIfAborted();
return api();
},
refresh: async (context?: any) => {
context.signal.throwIfAborted();
refreshes.value++;
}
}
};
return { failing, calls, refreshes, api, provider };
}
},
};
const __dependencies: any = {"Demo.vue":{"./Child.vue":"Child.vue","./transport.js":"transport.ts"},"Child.vue":{"./transport.js":"transport.ts"},"transport.ts":{}};
const __cache: any = Object.create(null);
function __require(id: any): any {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module: any = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency: any) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-spacing-1[data-v-0e8a364c] {
display: grid;
gap: var(--asam-space-md);
}
p[data-v-0e8a364c]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
<template><StandaloneDemo /></template>
<script setup>
import * as __external0 from "vue";
import * as __external1 from "@asam-ui/ui";
const __external = {"vue": { ...__external0, __esModule: true },
"@asam-ui/ui": { ...__external1, __esModule: true }};
const __modules = {
"Demo.vue": (module, exports, require) => {
"use strict";
var __importDefault = function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
const Child_vue_1 = __importDefault(require("./Child.vue"));
const transport_js_1 = require("./transport.js");
exports.default = Object.assign({ name: 'AsamDictSelectDemoLocalErrorExample' }, {
__name: 'Demo',
setup(__props) {
const host = (0, vue_2.ref)();
let app;
(0, vue_2.onMounted)(() => {
if (!host.value)
return;
const transport = (0, transport_js_1.createTransport)();
app = (0, vue_2.createApp)(Child_vue_1.default, { transport });
(0, ui_1.provideAsamData)(app, transport.provider, { scope: 'AsamDictSelect-local-error' });
app.mount(host.value);
});
(0, vue_2.onBeforeUnmount)(() => app?.unmount());
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("div", {
ref_key: "host",
ref: host
}, null, 512 /* NEED_PATCH */));
};
}
});
},
"Child.vue": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const vue_1 = require("vue");
const _hoisted_1 = { class: "demo-spacing-1" };
const _hoisted_2 = {
role: "alert",
"data-testid": "local-error"
};
const _hoisted_3 = { class: "example-paragraph" };
const _hoisted_4 = {
key: 0,
class: "example-paragraph"
};
const _hoisted_5 = {
class: "example-paragraph",
role: "status",
"data-testid": "retry-result"
};
const _hoisted_6 = {
class: "example-paragraph",
"data-testid": "transport-count"
};
const _hoisted_7 = { "data-testid": "local-model" };
const vue_2 = require("vue");
const ui_1 = require("@asam-ui/ui");
exports.default = Object.assign({ name: 'AsamDictSelectChildLocalErrorExample' }, {
__name: 'Child',
props: { transport: { type: Object, required: true } },
setup(__props) {
const props = __props;
const transport = props.transport;
const value = (0, vue_2.ref)(null);
const control = (0, vue_2.ref)();
const busy = (0, vue_2.ref)(false), result = (0, vue_2.ref)('');
const dataSource = (0, ui_1.defineAsamDictSource)({ dictType: 'local-error-status' });
(0, vue_2.onMounted)(async () => {
const response = await control.value?.reload();
result.value = response?.status ?? 'cancelled';
});
async function recover(retry) {
busy.value = true;
transport.failing.value = false;
try {
const response = await retry();
result.value = response.status;
}
finally {
busy.value = false;
}
}
async function failAgain() {
busy.value = true;
transport.failing.value = true;
try {
const response = await control.value?.reload({ force: true });
result.value = response?.status ?? 'cancelled';
}
finally {
busy.value = false;
}
}
return (_ctx, _cache) => {
return ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("section", _hoisted_1, [
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamDictSelect), {
ref_key: "control",
ref: control,
modelValue: value.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => ((value).value = $event)),
"data-source": (0, vue_1.unref)(dataSource),
immediate: false
}, {
error: (0, vue_1.withCtx)(({ error, stale, retry }) => [
(0, vue_1.createElementVNode)("div", _hoisted_2, [
(0, vue_1.createElementVNode)("p", _hoisted_3, (0, vue_1.toDisplayString)(error.message) + "(" + (0, vue_1.toDisplayString)(error.kind) + ")", 1 /* TEXT */),
stale
? ((0, vue_1.openBlock)(), (0, vue_1.createElementBlock)("p", _hoisted_4, "已保留上次成功结果。"))
: (0, vue_1.createCommentVNode)("v-if", true),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: busy.value,
onClick: $event => (recover(retry))
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[1] || (_cache[1] = [
(0, vue_1.createTextVNode)(" 恢复并重试 ", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled", "onClick"])
])
]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["modelValue", "data-source"]),
(0, vue_1.createVNode)((0, vue_1.unref)(ui_1.AsamButton), {
type: "default",
"native-type": "button",
disabled: busy.value,
onClick: failAgain
}, {
default: (0, vue_1.withCtx)(() => [...(_cache[2] || (_cache[2] = [
(0, vue_1.createTextVNode)("模拟更新失败", -1 /* CACHED */)
]))]),
_: 1 /* STABLE */
}, 8 /* PROPS */, ["disabled"]),
(0, vue_1.createElementVNode)("p", _hoisted_5, (0, vue_1.toDisplayString)(result.value), 1 /* TEXT */),
(0, vue_1.createElementVNode)("p", _hoisted_6, " 请求 " + (0, vue_1.toDisplayString)((0, vue_1.unref)(transport).calls.value) + " 次,字典刷新 " + (0, vue_1.toDisplayString)((0, vue_1.unref)(transport).refreshes.value) + " 次 ", 1 /* TEXT */),
(0, vue_1.createElementVNode)("pre", _hoisted_7, (0, vue_1.toDisplayString)(value.value), 1 /* TEXT */)
]));
};
}
});
exports.default.__scopeId = "data-v-7051ffc2";
},
"transport.js": (module, exports, require) => {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createTransport = createTransport;
const vue_1 = require("vue");
function createTransport() {
const failing = (0, vue_1.ref)(true), calls = (0, vue_1.ref)(0), refreshes = (0, vue_1.ref)(0);
const api = async () => {
calls.value++;
if (failing.value)
throw Error('演示请求暂不可用');
return [
{ id: 1, value: 'ready', label: '准备' },
{ id: 2, value: 'running', label: '进行' }
];
};
const provider = {
dict: {
get: async (_type, context) => {
context.signal.throwIfAborted();
return api();
},
refresh: async (context) => {
context.signal.throwIfAborted();
refreshes.value++;
}
}
};
return { failing, calls, refreshes, api, provider };
}
},
};
const __dependencies = {"Demo.vue":{"./Child.vue":"Child.vue","./transport.js":"transport.js"},"Child.vue":{},"transport.js":{}};
const __cache = Object.create(null);
function __require(id) {
if (__external[id]) return __external[id];
if (__cache[id]) return __cache[id].exports;
const module = { exports: {} };
__cache[id] = module;
__modules[id](module, module.exports, (dependency) => __require(__dependencies[id][dependency] || dependency));
return module.exports;
}
const StandaloneDemo = __require('Demo.vue').default;
</script>
<style>
.demo-spacing-1[data-v-7051ffc2] {
display: grid;
gap: var(--asam-space-md);
}
p[data-v-7051ffc2]:where(.example-paragraph) {
margin-block: 16px;
line-height: 1.8;
overflow-wrap: anywhere;
}
</style>
局部与全局浮层 ​
基础示例使用默认的全局挂载;局部挂载示例展示显式配置的 teleported 或 appendTo。先打开控件浮层,再观察其所在容器。挂载位置与控件值、请求协议互相独立。
API
属性 AsamDictSelectProps
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
ariaLabel | — | string | undefined | — |
id | — | string | undefined | — |
effect | — | enum"light" | "dark"完整类型:(AsamDictSelectProps<V, I>)["effect"] | — |
popperClass | — | AsamSelectRuntimeProps["popperClass"] | — |
popperStyle | — | (AsamDictSelectProps<V, I>)["popperStyle"] | — |
fallbackPlacements | — | (AsamDictSelectProps<V, I>)["fallbackPlacements"] | — |
offset | — | number | undefined | — |
placement | — | enum"auto" | "auto-start" | "auto-end" | "top" | "bottom" | "right" | "left" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "right-start" | "right-end" | "left-start" | "left-end"完整类型:(AsamDictSelectProps<V, I>)["placement"] | — |
popperOptions | — | (AsamDictSelectProps<V, I>)["popperOptions"] | — |
showArrow | — | (AsamDictSelectProps<V, I>)["showArrow"] | — |
appendTo | — | (AsamDictSelectProps<V, I>)["appendTo"] | — |
persistent | — | (AsamDictSelectProps<V, I>)["persistent"] | — |
teleported | — | boolean | undefined | — |
disabled | — | boolean | undefined | — |
tabindex | — | (AsamDictSelectProps<V, I>)["tabindex"] | — |
size | — | enum"large" | "big" | "default" | "small"完整类型:AsamControlSize | undefined | — |
props | — | (AsamDictSelectProps<V, I>)["props"] | — |
name | — | string | undefined | — |
separator | — | string | undefined | — |
modelValue | — | V | null | undefined | AsamSelectOption<V, I> | null | undefined | readonly V[] | undefined | string | undefined | readonly AsamSelectOption<V, I>[] | undefined | — |
filterMethod | — | ((query: string) => void) | undefined | — |
multiple | — | false | undefined | true | — |
valueMode | — | enum"value" | "object"完整类型:"value" | undefined | "object" | — |
multipleValueMode | — | enum"array" | "string"完整类型:undefined | "array" | undefined | "string" | — |
emptyValues | — | unknown[] | undefined | — |
valueOnClear | — | (AsamDictSelectProps<V, I>)["valueOnClear"] | — |
validateEvent | — | (AsamDictSelectProps<V, I>)["validateEvent"] | — |
clearable | — | boolean | undefined | — |
automaticDropdown | — | boolean | undefined | — |
clearIcon | — | (AsamDictSelectProps<V, I>)["clearIcon"] | — |
placeholder | — | string | undefined | — |
autocomplete | — | string | undefined | — |
filterable | — | boolean | undefined | — |
allowCreate | — | boolean | undefined | false | undefined | true | — |
debounce | — | number | undefined | — |
loadingText | — | string | undefined | — |
noMatchText | — | string | undefined | — |
noDataText | — | string | undefined | — |
multipleLimit | — | number | undefined | — |
defaultFirstOption | — | boolean | undefined | — |
reserveKeyword | — | (AsamDictSelectProps<V, I>)["reserveKeyword"] | — |
valueKey | — | string | undefined | — |
collapseTags | — | boolean | undefined | — |
collapseTagsTooltip | — | boolean | undefined | — |
tagTooltip | — | (AsamDictSelectProps<V, I>)["tagTooltip"] | — |
maxCollapseTags | — | number | undefined | — |
fitInputWidth | — | boolean | undefined | — |
suffixIcon | — | (AsamDictSelectProps<V, I>)["suffixIcon"] | — |
tagType | — | enum"primary" | "success" | "danger" | "warning" | "info"完整类型:(AsamDictSelectProps<V, I>)["tagType"] | — |
tagEffect | — | enum"light" | "dark" | "plain"完整类型:(AsamDictSelectProps<V, I>)["tagEffect"] | — |
remoteShowSuffix | — | boolean | undefined | — |
immediate | — | boolean | undefined | — |
active | — | boolean | undefined | true |
dataSource | — | AsamOptionsSource<V, I, "dict"> | undefined | undefined |
dictType | — | undefined | string | undefined |
dictValueType | — | enum"string" | "number" | "boolean"完整类型:AsamDictValueType | undefined | undefined |
createOption | — | AsamCreateOption<V, I> | undefined | — |
事件 AsamSelectDataEmits
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
clear | — | (AsamSelectDataEmits<V, I>)["clear"] | — |
focus | — | [event: FocusEvent] | — |
end-reached | — | [direction: AsamScrollbarDirection] | — |
error | — | [error: AsamDataError] | — |
blur | — | [event: FocusEvent] | — |
visible-change | — | [visible: boolean] | — |
remove-tag | — | [value: unknown] | — |
popup-scroll | — | [event: { scrollTop: number; scrollLeft: number; }] | — |
update:modelValue | — | [value: string | V | AsamOption<V, I> | readonly V[] | readonly AsamOption<V, I>[] | null] | — |
change | — | [value: string | V | AsamOption<V, I> | readonly V[] | readonly AsamOption<V, I>[] | null] | — |
success | — | [data: readonly AsamOption<V, I>[]] | — |
插槽 AsamAsyncSelectSlots
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
default | — | (() => unknown) | undefined | — |
prefix | — | (() => unknown) | undefined | — |
header | — | (() => unknown) | undefined | — |
footer | — | (() => unknown) | undefined | — |
empty | — | (() => unknown) | undefined | — |
loading | — | (() => unknown) | undefined | — |
tag | — | 查看完整类型((scope: { data: AsamTreeSelectTagOption[]; selectDisabled: boolean; deleteTag: (event: MouseEvent, option: AsamTreeSelectTagOption) => void; }) => unknown) | undefined | — |
label | — | ((scope: { index: number; label: any; value: any; }) => unknown) | undefined | — |
error | 替换本地错误区域;重试返回现有强制重新加载的 Promise。 | (AsamAsyncSelectSlots<V, I>)["error"] | — |
实例方法与状态 AsamAsyncSelectExpose
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
selectedLabel | — | string | string[] | — |
reload | — | (options?: { readonly force?: boolean; }) => Promise<AsamReloadResult<readonly AsamOption<V, I>[]>> | — |
cancel | — | () => void | — |
focus | 聚焦原生输入控件。 | () => void | — |
blur | — | () => void | — |
clearCreatedOptions | 仅在逻辑数据来源或作用域变化时重置本地创建项,不因搜索、刷新或错误重置。 | () => void | — |
用法与契约补充说明 ​
基础用法 ​
点击“读取当前标签”读取实例的只读 selectedLabel:空模型返回空字符串,选择后返回当前标签。focus() 与 blur() 为无参数方法,仅控制输入焦点,不改写模型;失焦按钮阻止鼠标按下时抢走焦点,以便观察 blur() 的实际作用。勾选“启用多选”切换到独立数组模型;空选择读取空数组,选择多个选项后返回标签数组,输入焦点方法仍不改写模型。
数据来源与覆盖 ​
dictType 与 dataSource 只选一种;dataSource 使用 defineAsamDictSource 创建,不能再传 dictValueType。短来源的 dictValueType 可将字典值转换为 string、number 或 boolean。应用通过 provideAsamData 注入 dict.get,演示在独立子应用中使用本地字典,切换语言或离开时卸载。
生命周期、事件与实例 ​
active=false 暂停请求并保留上次成功数据;reload({ force: true }) 请求新数据,cancel() 取消当前请求。success 返回规范化选项数组,error 返回 AsamDataError;旧成功数据更新失败时组件显示过期状态。reload 的 status 为 success、error 或 cancelled;不能把取消当作成功。
选项和标签的完整展示 ​
完整示例在两个独立实例中演示按来源 raw.team 分组的 OptionGroup/Option 插槽、prefix/header/footer/loading/empty/label 和可删除 tag。来源仍返回规范化的平面实体;分组仅组织 default 插槽中的原生选项,不改变来源与模型。多选使用原始数值数组,保留折叠标签提示、maxCollapseTags、multipleLimit 和 disabled;自定义 tag 通过原生 deleteTag 删除并触发 remove-tag,不直接改内部标签。完成请求按钮释放本地等待操作,便于观察真实 loading 与 empty 插槽;卸载时请求随独立子应用取消。普通选择器通过 popperStyle.minWidth=320px 设置弹层最小宽度。
选项和标签的完整展示 ​
折叠标签提示可独立关闭和恢复;关闭提示仍保留折叠数量及模型。弹层样式按钮演示 StyleValue 的对象、字符串、嵌套数组和 false/null/undefined 清空形式。示例最小宽度分别为 320、360、400px,清空后恢复原生宽度,切换展示设置不重新读取来源。数组样式恢复为对象时会清除之前的 maxWidth。
芋道宿主桥接与生命周期 ​
完整示例从 @asam-ui/ui-yudao 导入实际 createYudaoProvider,并在独立子应用安装。宿主拥有 ensure/get/refresh 与字典缓存,ASAM 只协调同 scope/epoch 的操作。两个数字值字典共享 ensure,保留各自 v-model;取消一个消费者不会中止另一个消费者的宿主操作。失败保持上次结果,恢复后重载;reload({ force: true }) 更新宿主世代并等待当前 ensure;普通 reload() 重读宿主字典缓存而不调用 refresh,没有额外 refreshDict 公共标志。示例所有宿主操作都在本地完成,不访问服务器。宿主真实 Axios/Pinia 接入见独立 adapter 包的 README,业务实现通过 bridge 注入,不由通用包引用。
芋道宿主桥接与生命周期 ​
点击“展示未提供 refresh 的桥接”会创建另一个独立子应用与本地宿主缓存。bridge.dict.ensure 和同步 get 仍然必需,refresh 可以省略;省略后普通 reload() 可以重新确保并读取缓存,reload({ force: true }) 则返回 config 错误并保留已选模型和上次成功数据,不会静默退回普通读取。使用普通重载可以恢复成功状态。这两个子应用的 scope、运行时和模型互相独立,卸载时分别回收;示例按钮不会替换已经安装的 provider。
完整芋道桥协议 ​
createYudaoProvider(bridge) 返回 AsamDataProvider;构造时只校验配置与保存宿主回调,不执行传输、字典读取或通知。AsamYudaoBridge 的 request、upload、dict、isErrorNotified、onError 均可省略且引用只读。空桥仍提供响应适配和 pageNo/pageSize 分页键,但没有请求、上传或字典能力;需要这些能力时由宿主注入。
完整芋道桥协议 ​
adapter 不配置 Axios、凭据、端点、Pinia 或宿主缓存。request/upload/通知回调保持构造时的函数身份;provider 及分页键对象冻结,不冻结宿主 bridge,也不通过事后替换 bridge 成员更新 provider。TypeScript 的 void 回调类型不会拒绝所有异步函数,运行时对通知回调另外要求同步完成。
完整芋道桥协议 ​
默认适配只展开一层自有 data。存在自有 code 时只接受数值 0 或 200,字符串 "0"、其他码、null 和显式 undefined 都失败;不存在 code 不等同于显式 undefined。选项和分页的最终形状由核心规范化校验,不能递归猜测多层 data。页响应同时含合法 list/total 和 data 页路径时判为歧义。业务自定义 transform 的优先关系沿用数据来源协议。
完整芋道桥协议 ​
yudao-bridge 完整 TS/JS 示例的“检查完整宿主桥”按钮实际验证构造无副作用、原请求上下文与载荷、上传 File/进度转交、一层响应与失败、分页歧义、宿主通知去重、13 种无效桥以及空桥。传输和文件均在示例内部构造,不访问按钮中的示例 URL。原字典的共享、取消、刷新、恢复与缺省 refresh 示例仍可独立操作;上传在这里只验证桥转交协议,不代替上传组件的文件校验与资源模型。
上传数据协议与完整消费者 ​
类型只描述结构,不保证字符串非空、数值有限、地址安全或 Blob 的内容满足业务规则。资源消费者在发送前检查字段名、来源配置与附加数据;完成后要求资源字段有效、size 为非负安全整数、URL 为无凭据的 HTTP(S) 或站内绝对路径,并满足可序列化结构。空 id、javascript 地址和 NaN size 不会进入资源模型。上传请求默认 POST,支持 PUT,不能沿用普通数据请求的 GET/DELETE;同步 transform 保留传输输入,Promise/thenable 转换结果被拒绝。
上传数据协议与完整消费者 ​
reportProgress 不直接提交模型。没有 total 的有效 loaded 可以报告不确定进度;有 total 时仅接受有限、非负 loaded 和大于零的 total,且 loaded 不超过 total。无效进度被忽略,不发新的 progress 事件。完成资源会触发 success 和模型更新;处理器/传输失败归入 upload 阶段,转换和请求模式资源校验失败归入 transform 阶段,均保留原失败信息。
完整 provider 数据能力 ​
provider 的静态只读引用不等于冻结宿主缓存、原始响应或方法内部状态;dict 的 get/refresh 方法签名也不是 readonly 方法引用。运行时校验可调用成员、分页键和当前上下文,通知钩子另有同步与去重约束。TS/JS 示例通过独立 provider 实际传输 File/Blob 和进度,原数据来源、分页与错误归属示例展示其他成员;无需给核心包引入业务 API 或全局 store。
局部请求错误插槽 ​
可选 error 插槽仅在当前请求错误存在时调用,接收只读 { error, stale, retry }。
error 与本实例 error 事件中的 AsamDataError 为同一对象,保留 cause、kind、
message 与 notified;渲染插槽不会再次通知 provider。stale 表示保留的数据已过期。
更多参数与事件说明 ​
完整 provider 数据能力 ​
AsamDataProvider 的 request、upload、adaptOptions、adaptPage、dict、isErrorNotified、onError、pagination 都是可选的只读引用;空对象可以安装,但具体来源缺少对应传输或字典能力时会报 config 错误。request 返回未知响应的 Promise,upload 使用上表的上传传输;adaptOptions 和 adaptPage 同步返回选项原记录或分页,来源的显式 transform 优先。dict.get 必填,dict.refresh 可选。pagination 的两个只读字段须为非空且不同的参数名。
局部请求错误插槽 ​
retry() 不接收参数,直接返回现有 reload({ force: true }) 的 Promise,结果为
AsamReloadResult<readonly AsamOption<V, I>[]> 的 success、error 或 cancelled 分支。
重试遵守 active、当前来源、取消和卸载规则,不改写模型。字典强刷沿用 provider 的 refresh 后 get;缺少 refresh 仍是原配置错误。
继承能力
本入口的独有 API 见上表,基础能力见本站对应页面。
关联组件
参数与事件补充说明
组合契约按分支生效;请同时查看公开类型。
参数与事件说明
ariaLabel
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
id
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
effect
必填:否;声明来源:上游声明。
effect 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"light" / "dark"
默认值与来源
未知 / 未声明固定上游文档默认:light(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'light'(2.14.7;源码事实,未作为 ASAM 运行实测)
popperClass
必填:否;声明来源:上游声明。
popperClass 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false
默认值与来源
未知 / 未声明固定上游文档默认:''(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:''(2.14.7;源码事实,未作为 ASAM 运行实测)
popperStyle
必填:否;声明来源:上游声明。
popperStyle 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false
嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:undefined(2.14.7;源码事实,未作为 ASAM 运行实测)
fallbackPlacements
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:['bottom-start', 'top-start', 'right', 'left'](2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:['bottom-start', 'top-start', 'right', 'left'](2.14.7;源码事实,未作为 ASAM 运行实测)
offset
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:12(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:12(2.14.7;源码事实,未作为 ASAM 运行实测)
placement
必填:否;声明来源:上游声明。
placement 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"auto" / "auto-start" / "auto-end" / "top" / "bottom" / "right" / "left" / "top-start" / "top-end" / "bottom-start" / "bottom-end" / "right-start" / "right-end" / "left-start" / "left-end"
默认值与来源
未知 / 未声明固定上游文档默认:bottom-start(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'bottom-start'(2.14.7;源码事实,未作为 ASAM 运行实测)
popperOptions
必填:否;声明来源:上游声明。
popperOptions 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
popperOptions.placement:PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["popperOptions"]>, "placement">— 依赖声明枚举:
"auto"/"auto-start"/"auto-end"/"top"/"bottom"/"right"/"left"/"top-start"/"top-end"/"bottom-start"/"bottom-end"/"right-start"/"right-end"/"left-start"/"left-end"popperOptions.modifiers:PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["popperOptions"]>, "modifiers">— 依赖声明popperOptions.strategy:PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["popperOptions"]>, "strategy">— 依赖声明枚举:
"fixed"/"absolute"popperOptions.onFirstUpdate:PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["popperOptions"]>, "onFirstUpdate">— 依赖声明事件参数:
(arg0: Parameters<Extract<NonNullable<PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["popperOptions"]>, "onFirstUpdate">>, (...args: never[]) => unknown>>[0]): void
默认值与来源
未知 / 未声明固定上游文档默认:{}(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => ({}) as Partial<Options>(2.14.7;源码事实,未作为 ASAM 运行实测)
showArrow
必填:否;声明来源:上游声明。
showArrow 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
未知 / 未声明固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
appendTo
必填:否;声明来源:上游声明。
appendTo 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
嵌套展开边界:大型实例类型;完整类型见公开类型视图。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
persistent
必填:否;声明来源:上游声明。
persistent 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
未知 / 未声明固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
teleported
必填:否;声明来源:ASAM 声明。
teleported 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
disabled
必填:否;声明来源:ASAM 声明。
disabled 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
tabindex
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:0(2.14.7;源码事实,未作为 ASAM 运行实测)
size
必填:否;声明来源:ASAM 声明。
size 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"large" / "big" / "default" / "small"
props
必填:否;声明来源:上游声明。
props 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
props.label:string | undefined— 上游声明指定节点标签为节点对象的某个属性值
固定上游文档默认:
label(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)props.value:string | undefined— 上游声明指定选项的值为选项对象的某个属性值
固定上游文档默认:
value(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)props.disabled:string | undefined— 上游声明指定选项的禁用为选项对象的某个属性值
固定上游文档默认:
disabled(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)props.options:string | undefined— 上游声明指定选项的子选项为选项对象的某个属性值
固定上游文档默认:
options(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => defaultProps(2.14.7;源码事实,未作为 ASAM 运行实测)
name
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
separator
必填:否;声明来源:ASAM 声明。
modelValue
必填:否;声明来源:ASAM 声明。
modelValue 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
modelValue.label:string— 数据 / provider 协议modelValue.value:V— 数据 / provider 协议modelValue.disabled:boolean | undefined— 数据 / provider 协议枚举:
false/truemodelValue.raw:I— 数据 / provider 协议modelValue.children:readonly AsamOption<V, I>[] | undefined— 数据 / provider 协议
filterMethod
必填:否;声明来源:上游声明。
filterMethod 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(query: string): void
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码未声明 default(2.14.7;源码事实,未作为 ASAM 运行实测)
multiple
必填:否;声明来源:ASAM 声明。
multiple 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false
枚举:true
valueMode
必填:否;声明来源:ASAM 声明。
valueMode 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"value"
枚举:"object"
multipleValueMode
必填:否;声明来源:ASAM 声明。
multipleValueMode 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"array"
枚举:"string"
emptyValues
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
valueOnClear
必填:否;声明来源:上游声明。
valueOnClear 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
valueOnClear.apply:(this: Function, thisArg: any, argArray?: any) => any— 依赖声明调用函数,以指定对象作为 this,并使用指定数组作为函数参数。
事件参数:
(this: Function, thisArg: any, argArray?: any): any嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.call:(this: Function, thisArg: any, ...argArray: any[]) => any— 依赖声明调用对象方法,并以另一个对象作为当前 this。
事件参数:
(this: Function, thisArg: any, ...argArray: any[]): any嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.bind:(this: Function, thisArg: any, ...argArray: any[]) => any— 依赖声明创建具有相同函数体的绑定函数,将 this 绑定到指定对象,并设置初始参数。
事件参数:
(this: Function, thisArg: any, ...argArray: any[]): any嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.toString:() => string— 依赖声明返回函数的字符串表示。
事件参数:
(): string嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.prototype:any— 依赖声明valueOnClear.length:number— 依赖声明valueOnClear.arguments:any— 依赖声明valueOnClear.caller:Function— 依赖声明嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
valueOnClear.name:string— 依赖声明返回函数名称;函数名称只读,不能修改。
valueOnClear.__@hasInstance@8888:(value: any) => boolean— 依赖声明当函数用作构造函数时,判断指定值是否继承自该函数;构造函数可以覆盖此方法,控制 instanceof 对实例的识别。
事件参数:
(value: any): boolean嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
validateEvent
必填:否;声明来源:上游声明。
validateEvent 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
未知 / 未声明固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
clearable
必填:否;声明来源:ASAM 声明。
clearable 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
automaticDropdown
必填:否;声明来源:上游声明。
automaticDropdown 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
未知 / 未声明固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
clearIcon
必填:否;声明来源:上游声明。
clearIcon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: any, ctx: Parameters<Extract<NonNullable<(AsamDictSelectProps<V, I>)["clearIcon"]>, (...args: never[]) => unknown>>[1]): any
clearIcon.__isFragment:undefined— 依赖声明clearIcon.__isTeleport:undefined— 依赖声明clearIcon.__isSuspense:undefined— 依赖声明
默认值与来源
未知 / 未声明固定上游文档默认:CircleClose(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:CircleClose(2.14.7;源码事实,未作为 ASAM 运行实测)
placeholder
必填:否;声明来源:ASAM 声明。
autocomplete
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:off(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'off'(2.14.7;源码事实,未作为 ASAM 运行实测)
filterable
必填:否;声明来源:ASAM 声明。
filterable 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
allowCreate
必填:否;声明来源:ASAM 声明。
allowCreate 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
枚举:false
枚举:true
debounce
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:300(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:300(2.14.7;源码事实,未作为 ASAM 运行实测)
loadingText
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
noMatchText
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
noDataText
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
multipleLimit
必填:否;声明来源:ASAM 声明。
defaultFirstOption
必填:否;声明来源:上游声明。
defaultFirstOption 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
未知 / 未声明固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
reserveKeyword
必填:否;声明来源:上游声明。
reserveKeyword 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
未知 / 未声明固定上游文档默认:true(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:true(2.14.7;源码事实,未作为 ASAM 运行实测)
valueKey
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:value(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:'value'(2.14.7;源码事实,未作为 ASAM 运行实测)
collapseTags
必填:否;声明来源:ASAM 声明。
collapseTags 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
collapseTagsTooltip
必填:否;声明来源:ASAM 声明。
collapseTagsTooltip 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
tagTooltip
必填:否;声明来源:上游声明。
tagTooltip 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
tagTooltip.appendTo:string | HTMLElement | undefined— 上游声明指示 Tooltip 的内容将附加在哪一个网页元素上
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)嵌套展开边界:大型实例类型;完整类型见公开类型视图。
tagTooltip.placement:PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["tagTooltip"]>, "placement">— 上游声明Tooltip 组件出现的位置
固定上游文档默认:
bottom(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)枚举:
"auto"/"auto-start"/"auto-end"/"top"/"bottom"/"right"/"left"/"top-start"/"top-end"/"bottom-start"/"bottom-end"/"right-start"/"right-end"/"left-start"/"left-end"tagTooltip.fallbackPlacements:AsamSelectRuntimeProps["fallbackPlacements"]— 上游声明提示浮层可采用的位置列表,参阅 Popper 的 fallbackPlacements。
固定上游文档默认:
['bottom', 'top', 'right', 'left'](2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)tagTooltip.effect:PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["tagTooltip"]>, "effect">— 上游声明Tooltip 主题,内置了 dark / light 两种
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)枚举:
"light"/"dark"tagTooltip.popperClass:AsamSelectRuntimeProps["popperClass"]— 上游声明为 Tooltip 的 popper 添加自定义类名
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)枚举:
falsetagTooltip.popperStyle:AsamSelectRuntimeProps["popperStyle"]— 上游声明为 Tooltip 的 popper 添加自定义样式
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)枚举:
false嵌套展开边界:框架 / 平台类型;完整类型见公开类型视图。
tagTooltip.transition:string | undefined— 上游声明动画名称
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)tagTooltip.teleported:boolean | undefined— 上游声明是否使用 teleport。设置成 true则会被追加到 append-to 的位置
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)枚举:
false/truetagTooltip.popperOptions:AsamSelectRuntimeProps["popperOptions"]— 上游声明Popper 配置参数。
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)tagTooltip.popperOptions.placement:PublicMember<NonNullable<PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["tagTooltip"]>, "popperOptions">>, "placement">— 依赖声明枚举:
"auto"/"auto-start"/"auto-end"/"top"/"bottom"/"right"/"left"/"top-start"/"top-end"/"bottom-start"/"bottom-end"/"right-start"/"right-end"/"left-start"/"left-end"tagTooltip.popperOptions.modifiers:PublicMember<NonNullable<PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["tagTooltip"]>, "popperOptions">>, "modifiers">— 依赖声明tagTooltip.popperOptions.strategy:PublicMember<NonNullable<PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["tagTooltip"]>, "popperOptions">>, "strategy">— 依赖声明枚举:
"fixed"/"absolute"tagTooltip.popperOptions.onFirstUpdate:PublicMember<NonNullable<PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["tagTooltip"]>, "popperOptions">>, "onFirstUpdate">— 依赖声明事件参数:
(arg0: Parameters<Extract<NonNullable<PublicMember<NonNullable<PublicMember<NonNullable<(AsamDictSelectProps<V, I>)["tagTooltip"]>, "popperOptions">>, "onFirstUpdate">>, (...args: never[]) => unknown>>[0]): void
tagTooltip.showAfter:number | undefined— 上游声明在触发后多久显示内容,单位毫秒
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)tagTooltip.hideAfter:number | undefined— 上游声明关闭时的延迟
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)tagTooltip.autoClose:number | undefined— 上游声明tooltip 出现后自动隐藏延时,单位毫秒
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)tagTooltip.offset:number | undefined— 上游声明Tooltip 出现位置的偏移量
固定上游文档默认:
未声明(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
默认值与来源
未知 / 未声明固定上游文档默认:{}(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码工厂(未执行):() => ({})(2.14.7;源码事实,未作为 ASAM 运行实测)
maxCollapseTags
必填:否;声明来源:上游声明。
默认值与来源
未知 / 未声明固定上游文档默认:1(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:1(2.14.7;源码事实,未作为 ASAM 运行实测)
fitInputWidth
必填:否;声明来源:上游声明。
fitInputWidth 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
未知 / 未声明固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
suffixIcon
必填:否;声明来源:上游声明。
suffixIcon 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(props: any, ctx: Parameters<Extract<NonNullable<(AsamDictSelectProps<V, I>)["suffixIcon"]>, (...args: never[]) => unknown>>[1]): any
suffixIcon.__isFragment:undefined— 依赖声明suffixIcon.__isTeleport:undefined— 依赖声明suffixIcon.__isSuspense:undefined— 依赖声明
默认值与来源
未知 / 未声明固定上游文档默认:ArrowDown(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
固定上游源码默认表达式:ArrowDown(2.14.7;源码事实,未作为 ASAM 运行实测)
tagType
必填:否;声明来源:上游声明。
tagType 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"primary" / "success" / "danger" / "warning" / "info"
默认值与来源
未知 / 未声明固定上游文档默认:info(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
tagEffect
必填:否;声明来源:上游声明。
tagEffect 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:"light" / "dark" / "plain"
默认值与来源
未知 / 未声明固定上游文档默认:light(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
remoteShowSuffix
必填:否;声明来源:上游声明。
remoteShowSuffix 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
未知 / 未声明固定上游文档默认:false(2.14.7;文档事实,实际默认以 ASAM 源码 / 安装包为准)
immediate
必填:否;声明来源:数据 / provider 协议。
immediate 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
active
必填:否;声明来源:数据 / provider 协议。
active 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
枚举:false / true
默认值与来源
true(源码表达式;ASAM 声明)dataSource
必填:否;声明来源:数据 / provider 协议。
dataSource 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
dataSource.kind:"dict"— 数据 / provider 协议枚举:
"dict"dataSource.__@sourceBrand@58165:{ readonly value: V; readonly raw: I; }— 数据 / provider 协议dataSource.__@sourceBrand@58165.value:V— 数据 / provider 协议dataSource.__@sourceBrand@58165.raw:I— 数据 / provider 协议
默认值与来源
undefined(源码表达式;ASAM 声明)dictType
必填:否;声明来源:数据 / provider 协议。
默认值与来源
undefined(源码表达式;ASAM 声明)dictValueType
必填:按分支;声明来源:数据 / provider 协议。
dictValueType 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
契约分支 2
枚举:"string" / "number" / "boolean"
默认值与来源
undefined(源码表达式;ASAM 声明)createOption
必填:按分支;声明来源:ASAM 声明。
createOption 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
契约分支 3
事件参数:(text: string): AsamOption<V, I>
AsamDictSelectProps 公开类型视图
import type { Attrs } from 'vue';
import type { AsamDictSelectProps, AsamValue, AsamRecord, AsamSelectRuntimeProps, AsamControlSize, AsamSelectNativeProps, AsamSelectV2NativeProps, AsamSelectValueMode, AsamOptionsSource, AsamDictValueType, AsamSelectOption, AsamOption, AsamCreateOption } from '@asam-ui/ui';
type PublicMember<T, K extends PropertyKey> = T extends unknown ? K extends keyof T ? T[K] : never : never;
// AsamDictSelectProps
type PublicContract<V extends AsamValue = AsamValue, I extends object = AsamRecord> = AsamDictSelectProps<V, I>;
参数与事件说明
clear
必填:是;声明来源:数据 / provider 协议。
focus
必填:是;声明来源:数据 / provider 协议。
end-reached
必填:是;声明来源:数据 / provider 协议。
error
必填:是;声明来源:数据 / provider 协议。
blur
必填:是;声明来源:数据 / provider 协议。
visible-change
必填:是;声明来源:数据 / provider 协议。
remove-tag
必填:是;声明来源:数据 / provider 协议。
popup-scroll
必填:是;声明来源:数据 / provider 协议。
update:modelValue
必填:是;声明来源:数据 / provider 协议。
change
必填:是;声明来源:数据 / provider 协议。
success
必填:是;声明来源:数据 / provider 协议。
AsamSelectDataEmits 公开类型视图
import type { AsamSelectDataEmits, AsamValue, AsamSelectEmits, AsamScrollbarDirection, AsamDataError, AsamOption } from '@asam-ui/ui';
// AsamSelectDataEmits
type PublicContract<V extends AsamValue = AsamValue, I extends object = object> = {
"clear": (AsamSelectDataEmits<V, I>)["clear"];
"focus": [event: FocusEvent];
"end-reached": [direction: AsamScrollbarDirection];
"error": [error: AsamDataError];
"blur": [event: FocusEvent];
"visible-change": [visible: boolean];
"remove-tag": [value: unknown];
"popup-scroll": [event: { scrollTop: number; scrollLeft: number; }];
"update:modelValue": [value: string | V | AsamOption<V, I> | readonly V[] | readonly AsamOption<V, I>[] | null];
"change": [value: string | V | AsamOption<V, I> | readonly V[] | readonly AsamOption<V, I>[] | null];
"success": [data: readonly AsamOption<V, I>[]];
};
参数与事件说明
default
必填:否;声明来源:数据 / provider 协议。
default 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
prefix
必填:否;声明来源:数据 / provider 协议。
prefix 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
header
必填:否;声明来源:数据 / provider 协议。
header 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
footer
必填:否;声明来源:数据 / provider 协议。
footer 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
empty
必填:否;声明来源:数据 / provider 协议。
empty 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
loading
必填:否;声明来源:数据 / provider 协议。
loading 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): unknown
tag
必填:否;声明来源:数据 / provider 协议。
tag 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(scope: { data: AsamTreeSelectTagOption[]; selectDisabled: boolean; deleteTag: (event: MouseEvent, option: AsamTreeSelectTagOption) => void; }): unknown
label
必填:否;声明来源:数据 / provider 协议。
label 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(scope: { index: number; label: AsamSelectV2NativeProps["modelValue"]["label"]; value: AsamSelectV2NativeProps["modelValue"]["value"]; }): unknown
error
必填:否;声明来源:数据 / provider 协议。
error 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(scope: Parameters<Extract<NonNullable<(AsamAsyncSelectSlots<V, I>)["error"]>, (...args: never[]) => unknown>>[0]): unknown
AsamAsyncSelectSlots 公开类型视图
import type { AsamAsyncSelectSlots, AsamValue, AsamTreeSelectTagOption, AsamSelectSlots, AsamSelectV2NativeProps, AsamDataError, AsamOption, AsamReloadResult } from '@asam-ui/ui';
// AsamAsyncSelectSlots
type PublicContract<V extends AsamValue = AsamValue, I extends object = object> = {
"default"?: (() => unknown) | undefined;
"prefix"?: (() => unknown) | undefined;
"header"?: (() => unknown) | undefined;
"footer"?: (() => unknown) | undefined;
"empty"?: (() => unknown) | undefined;
"loading"?: (() => unknown) | undefined;
"tag"?: ((scope: { data: AsamTreeSelectTagOption[]; selectDisabled: boolean; deleteTag: (event: MouseEvent, option: AsamTreeSelectTagOption) => void; }) => unknown) | undefined;
"label"?: ((scope: { index: number; label: any; value: any; }) => unknown) | undefined;
"error"?: (AsamAsyncSelectSlots<V, I>)["error"];
};
数据选择实例继承基础选择入口的 clearCreatedOptions():仅清空组件本地创建集合 和文本 memo,不写回 modelValue,也不修改 provider/cache。真实来源或 scope 改变时自动调用;搜索、同来源 reload、epoch 更新与失败重试保留本地项。
参数与事件说明
selectedLabel
必填:是;声明来源:数据 / provider 协议。
reload
必填:是;声明来源:数据 / provider 协议。
reload 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(options?: { readonly force?: boolean; } | undefined): Promise<AsamReloadResult<readonly AsamOption<V, I>[]>>
cancel
必填:是;声明来源:数据 / provider 协议。
cancel 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
focus
必填:是;声明来源:ASAM 声明。
focus 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
blur
必填:是;声明来源:ASAM 声明。
blur 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
clearCreatedOptions
必填:是;声明来源:ASAM 声明。
clearCreatedOptions 参数与事件数据
下列为声明可读视图;可导入类型以公开类型视图为准。分支条件与父属性一致。
事件参数:(): void
AsamAsyncSelectExpose 公开类型视图
import type { AsamAsyncSelectExpose, AsamValue, AsamRecord, AsamSelectExpose, AsamOption, AsamReloadResult } from '@asam-ui/ui';
// AsamAsyncSelectExpose
type PublicContract<V extends AsamValue = AsamValue, I extends object = AsamRecord> = {
readonly "selectedLabel": string | string[];
"reload": (options?: { readonly force?: boolean; }) => Promise<AsamReloadResult<readonly AsamOption<V, I>[]>>;
"cancel": () => void;
"focus": () => void;
"blur": () => void;
"clearCreatedOptions": () => void;
};