disguise-ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,116 @@
1
- # Temporary Holding Version
1
+ # 嘻嘻 UI 库
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 从 elecbee-admin 抽出的列表、表单、上传组件。安装后不依赖原后台的接口、字典和权限,这些能力在启动时注入。
4
+
5
+ npm 包名是 `disguise-ui`。
6
+
7
+ ## 包含
8
+
9
+ `CrudPage`、`TableEntity`、`SchemaForm`、`SearchForm`、`DrawerFormPage`、`AsyncSelect`、`DictTag`、`ImportDialog`、`ImageUpload`、`PictureUpload`、`RichTextEditor`、`BaseCard`、`ElecbeeIcon`。
10
+
11
+ 业务实体(商品、部门、用户)没有打进包。远程下拉用 `registerEntity` 自己注册。
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ npm install disguise-ui vue element-plus @element-plus/icons-vue @vueuse/core @tanstack/vue-query dayjs vue-draggable-plus lucide-vue-next
17
+ ```
18
+
19
+ 富文本还需要 `@tiptap/vue-3`、`@tiptap/starter-kit` 以及编辑器里用到的 `@tiptap/extension-*`。
20
+
21
+ ## 使用
22
+
23
+ ```ts
24
+ import { createApp } from 'vue';
25
+ import { VueQueryPlugin } from '@tanstack/vue-query';
26
+ import ElementPlus from 'element-plus';
27
+ import { setupElecbeeUi } from 'disguise-ui';
28
+
29
+ import 'element-plus/dist/index.css';
30
+ import 'disguise-ui/style.css';
31
+
32
+ setupElecbeeUi({
33
+ locale: 'zh-CN',
34
+ imageBaseUrl: 'https://cdn.example.com',
35
+ getAccessToken: () => localStorage.getItem('token') ?? '',
36
+ hasAccess: (codes) => codes.every((code) => permissions.includes(code)),
37
+ fetchAllDictData: async () => {
38
+ const response = await fetch('/api/dict/values');
39
+ return response.json();
40
+ },
41
+ uploadFile: async (file) => {
42
+ const body = new FormData();
43
+ body.append('file', file);
44
+ const response = await fetch('/api/file_manager/upload', {
45
+ method: 'POST',
46
+ body,
47
+ });
48
+ return response.json();
49
+ },
50
+ request: {
51
+ getBaseUrl: () => '/api',
52
+ download: async (url, config) => {
53
+ const response = await fetch(url, {
54
+ method: String(config?.method ?? 'POST'),
55
+ body: config?.data ? JSON.stringify(config.data) : undefined,
56
+ });
57
+ return { data: await response.blob(), headers: response.headers };
58
+ },
59
+ upload: async (url, data) => {
60
+ const body = new FormData();
61
+ Object.entries(data ?? {}).forEach(([key, value]) => {
62
+ body.append(key, value as Blob | string);
63
+ });
64
+ const response = await fetch(url, { method: 'POST', body });
65
+ return response.json();
66
+ },
67
+ },
68
+ });
69
+
70
+ const app = createApp(App);
71
+ app.use(ElementPlus);
72
+ app.use(VueQueryPlugin);
73
+ ```
74
+
75
+ `fetchAllDictData` 返回 `{ 字典编码: 字典项[] }`。字典项至少包含 `code` 或 `dictValue`,以及 `name` 或 `dictLabel`。
76
+
77
+ 远程下拉:
78
+
79
+ ```ts
80
+ import { registerEntity } from 'disguise-ui';
81
+
82
+ registerEntity({
83
+ key: 'dept',
84
+ labelKey: 'name',
85
+ valueKey: 'id',
86
+ fetch: async ({ keyword, page, per_page }) => {
87
+ return { items: [], total: 0 };
88
+ },
89
+ });
90
+ ```
91
+
92
+ 页面里的工具类来自 Tailwind。使用方需要把构建产物加进扫描范围:
93
+
94
+ ```js
95
+ content: ['./node_modules/disguise-ui/dist/**/*.js']
96
+ ```
97
+
98
+ `ElecbeeIcon` 只负责拼接图标类名,图标字体样式需要使用方自己引入。
99
+
100
+ ## 文档站
101
+
102
+ 本地会启动一个类似 Element Plus 的组件说明站,包含实时示例、源码和 API:
103
+
104
+ ```bash
105
+ npm run docs:dev # 开发
106
+ npm run docs:preview # 先构建再预览正式包
107
+ ```
108
+
109
+ ## 构建
110
+
111
+ ```bash
112
+ npm install
113
+ npm run build
114
+ ```
115
+
116
+ 产物在 `dist/disguise-ui.js` 和 `dist/style.css`。
@@ -0,0 +1,7 @@
1
+ // \0plugin-vue:export-helper
2
+ var e = (e, t) => {
3
+ let n = e.__vccOpts || e;
4
+ for (let [e, r] of t) n[e] = r;
5
+ return n;
6
+ };
7
+ export { e as t };
@@ -0,0 +1,302 @@
1
+ import { n as e } from "./i18n-DQW_MS90.js";
2
+ import { t } from "./_plugin-vue_export-helper-Djzt4Yr7.js";
3
+ import { t as n } from "./use-image-url-hImb4UEO.js";
4
+ import { Fragment as r, computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createElementVNode as c, createTextVNode as l, createVNode as u, defineComponent as d, markRaw as f, mergeModels as p, mergeProps as m, nextTick as h, normalizeClass as g, normalizeStyle as ee, openBlock as _, ref as v, renderList as te, renderSlot as y, resolveComponent as b, resolveDynamicComponent as ne, toDisplayString as x, unref as S, useModel as re, useSlots as ie, watch as C, watchEffect as ae, withCtx as w } from "vue";
5
+ import { Badge as oe, Briefcase as se, Building2 as ce, Cake as le, CalendarDays as ue, Image as de, Mail as fe, Mars as T, Phone as pe, User as me, Venus as he } from "lucide-vue-next";
6
+ // src/components/user-avatar-info/index.vue?vue&type=script&setup=true&lang.ts
7
+ var ge = { class: "user-avatar-info-root" }, _e = {
8
+ key: 0,
9
+ class: "user-avatar-info__loading"
10
+ }, ve = { class: "user-avatar-info__skeleton-row" }, ye = { class: "user-avatar-info__skeleton-text" }, be = [
11
+ "role",
12
+ "tabindex",
13
+ "aria-label",
14
+ "aria-disabled"
15
+ ], xe = { class: "user-avatar-info__avatar-wrap" }, Se = { class: "user-avatar-info__name" }, Ce = {
16
+ key: 0,
17
+ class: "user-avatar-info__subtitle-wrap"
18
+ }, E = { class: "user-avatar-info__tooltip-text displaySubtitle" }, D = { class: "row-detail-drawer__header" }, O = { class: "row-detail-drawer__title" }, k = {
19
+ key: 0,
20
+ class: "user-avatar-info__drawer-slot"
21
+ }, A = {
22
+ key: 1,
23
+ class: "user-avatar-info__drawer"
24
+ }, we = { class: "user-avatar-info__hero" }, Te = { class: "user-avatar-info__hero-avatar" }, Ee = { class: "user-avatar-info__hero-main" }, De = { class: "user-avatar-info__hero-name-row" }, Oe = { class: "user-avatar-info__hero-name" }, ke = {
25
+ key: 0,
26
+ class: "user-avatar-info__hero-gender"
27
+ }, Ae = { class: "user-avatar-info__hero-meta" }, je = { key: 0 }, Me = { key: 1 }, Ne = { class: "user-avatar-info__card-grid" }, Pe = { class: "user-avatar-info__field-icon" }, Fe = { class: "user-avatar-info__field-content" }, Ie = { class: "user-avatar-info__field-label" }, Le = { class: "user-avatar-info__field-value" }, j = /*#__PURE__*/ t(/* @__PURE__ */ d({
28
+ __name: "index",
29
+ props: /*@__PURE__*/ p({
30
+ userId: { default: void 0 },
31
+ name: { default: void 0 },
32
+ subtitle: { default: "" },
33
+ src: {},
34
+ gender: { default: void 0 },
35
+ size: { default: 30 },
36
+ avatar: { default: void 0 },
37
+ drawerAvatarSize: { default: 64 },
38
+ age: { default: void 0 },
39
+ workYears: { default: void 0 },
40
+ email: { default: void 0 },
41
+ phone: { default: void 0 },
42
+ department: { default: void 0 },
43
+ jobLevel: { default: void 0 },
44
+ enableDrawer: {
45
+ type: Boolean,
46
+ default: !0
47
+ },
48
+ drawerTitle: { default: void 0 },
49
+ drawerSize: { default: "40%" },
50
+ drawerProps: { default: void 0 },
51
+ nickName: { default: "" },
52
+ deptName: { default: "" },
53
+ sex: { default: "" }
54
+ }, {
55
+ drawerVisible: {
56
+ type: Boolean,
57
+ default: !1
58
+ },
59
+ drawerVisibleModifiers: {}
60
+ }),
61
+ emits: ["update:drawerVisible"],
62
+ setup(t, { expose: d }) {
63
+ let p = t, { ensureImageBaseUrl: j, resolveImageUrl: M } = n();
64
+ j();
65
+ let N = re(t, "drawerVisible"), P = v(!1);
66
+ C(N, (e) => {
67
+ e && (P.value = !0);
68
+ }, { immediate: !0 });
69
+ function Re() {
70
+ P.value = !1;
71
+ }
72
+ let { t: F } = e(), ze = ie(), I = i(() => null), L = i(() => I.value?.data), Be = i(() => !1), Ve = i(() => !1), R = i(() => ({ isUserOnline: (e) => !1 })).value, He = i(() => Be.value && Ve.value && !I.value), z = i(() => p.nickName || p.name || ""), B = i(() => p.subtitle || p.deptName || ""), Ue = i(() => p.age), We = i(() => p.workYears), Ge = i(() => p.jobLevel), V = i(() => L.value?.nickName ?? L.value?.userName ?? ""), H = i(() => L.value?.userId ?? p.userId), Ke = i(() => !!ze.default), U = i(() => {
73
+ if (p.gender !== void 0 && p.gender !== null && p.gender !== "") return p.gender;
74
+ let e = p.sex;
75
+ return e === "0" ? "male" : e === "1" ? "female" : "unknown";
76
+ }), W = i(() => {
77
+ let e = L.value?.sex;
78
+ return e === "0" ? "male" : e === "1" ? "female" : "unknown";
79
+ }), G = i(() => W.value === "male" ? F("components.userAvatarInfo.genderMale") : W.value === "female" ? F("components.userAvatarInfo.genderFemale") : F("components.userAvatarInfo.genderUnknown")), qe = i(() => W.value === "male" || W.value === "female"), Je = i(() => ({
80
+ "user-avatar-info__meta--male": U.value === "male",
81
+ "user-avatar-info__meta--female": U.value === "female"
82
+ })), Ye = i(() => U.value === "male" || U.value === "female"), Xe = i(() => p.userId != null && String(p.userId) !== ""), Ze = i(() => R.isUserOnline(p.userId == null ? null : String(p.userId))), K = i(() => Math.max(10, Math.min(16, Math.round(p.size * .36)))), q = i(() => ({
83
+ ...p.avatar,
84
+ size: p.size,
85
+ src: M(p.src || "--"),
86
+ shape: "circle"
87
+ })), Qe = i(() => p.drawerTitle ?? F("components.userAvatarInfo.drawerTitle")), J = {
88
+ avatar: f(de),
89
+ name: f(me),
90
+ gender: f(T),
91
+ age: f(le),
92
+ workYears: f(ue),
93
+ email: f(fe),
94
+ phone: f(pe),
95
+ department: f(ce),
96
+ jobLevel: f(oe),
97
+ position: f(se)
98
+ }, $e = i(() => [
99
+ {
100
+ key: "name",
101
+ label: F("components.userAvatarInfo.fieldName"),
102
+ icon: J.name,
103
+ value: V.value
104
+ },
105
+ {
106
+ key: "gender",
107
+ label: F("components.userAvatarInfo.fieldGender"),
108
+ icon: J.gender,
109
+ value: G.value
110
+ },
111
+ {
112
+ key: "age",
113
+ label: F("components.userAvatarInfo.fieldAge"),
114
+ icon: J.age,
115
+ value: Y(Ue.value)
116
+ },
117
+ {
118
+ key: "workYears",
119
+ label: F("components.userAvatarInfo.fieldWorkYears"),
120
+ icon: J.workYears,
121
+ value: Y(We.value)
122
+ },
123
+ {
124
+ key: "jobLevel",
125
+ label: F("components.userAvatarInfo.fieldJobLevel"),
126
+ icon: J.position,
127
+ value: Y(Ge.value)
128
+ },
129
+ {
130
+ key: "phone",
131
+ label: F("components.userAvatarInfo.fieldPhone"),
132
+ icon: J.phone,
133
+ value: Y(L.value?.phonenumber ?? "")
134
+ },
135
+ {
136
+ key: "email",
137
+ label: F("components.userAvatarInfo.fieldEmail"),
138
+ icon: J.email,
139
+ value: Y(L.value?.email ?? "")
140
+ },
141
+ {
142
+ key: "department",
143
+ label: F("components.userAvatarInfo.fieldDepartment"),
144
+ icon: J.department,
145
+ value: X.value
146
+ }
147
+ ]), et = i(() => ({
148
+ appendToBody: !0,
149
+ destroyOnClose: !1,
150
+ ...p.drawerProps
151
+ })), tt = i(() => p.enableDrawer ? `${F("components.userAvatarInfo.ariaLabel")}, ${F("components.userAvatarInfo.clickToViewDetail")}` : F("components.userAvatarInfo.ariaLabel"));
152
+ function Y(e) {
153
+ return e == null || e === "" ? F("components.userAvatarInfo.empty") : String(e);
154
+ }
155
+ let X = i(() => Y(L.value?.dept?.deptName ?? ""));
156
+ function nt() {
157
+ p.enableDrawer && (N.value = !0);
158
+ }
159
+ function rt(e) {
160
+ p.enableDrawer && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), N.value = !0);
161
+ }
162
+ let Z = v(null), Q = v(!1);
163
+ function $() {
164
+ let e = Z.value;
165
+ e ? Q.value = e.scrollWidth > e.clientWidth + 1 : Q.value = !1;
166
+ }
167
+ ae((e) => {
168
+ let t = Z.value;
169
+ if (!t || typeof ResizeObserver > "u") {
170
+ Q.value = !1;
171
+ return;
172
+ }
173
+ $();
174
+ let n = new ResizeObserver(() => $());
175
+ n.observe(t), e(() => n.disconnect());
176
+ }), C(() => B.value, () => h($));
177
+ function it() {
178
+ N.value = !0;
179
+ }
180
+ function at() {
181
+ N.value = !1;
182
+ }
183
+ return d({
184
+ openDrawer: it,
185
+ closeDrawer: at,
186
+ remoteUser: L,
187
+ remoteDetail: I
188
+ }), (e, n) => {
189
+ let i = b("el-skeleton-item"), d = b("el-skeleton"), f = b("el-avatar"), h = b("el-tooltip"), v = b("el-drawer");
190
+ return _(), s("div", ge, [He.value ? (_(), s("div", _e, [u(d, { animated: "" }, {
191
+ template: w(() => [c("div", ve, [u(i, {
192
+ variant: "circle",
193
+ style: ee({
194
+ width: `${t.size}px`,
195
+ height: `${t.size}px`
196
+ })
197
+ }, null, 8, ["style"]), c("div", ye, [u(i, {
198
+ variant: "p",
199
+ style: { width: "55%" }
200
+ }), u(i, {
201
+ variant: "p",
202
+ style: { width: "40%" }
203
+ })])])]),
204
+ _: 1
205
+ })])) : (_(), s("div", {
206
+ key: 1,
207
+ class: g(["user-avatar-info", { "user-avatar-info--clickable": t.enableDrawer }]),
208
+ role: t.enableDrawer ? "button" : void 0,
209
+ tabindex: t.enableDrawer ? 0 : void 0,
210
+ "aria-label": tt.value,
211
+ "aria-disabled": !t.enableDrawer,
212
+ onClick: nt,
213
+ onKeydown: rt
214
+ }, [c("div", xe, [
215
+ u(f, m({ class: "user-avatar-info__avatar" }, q.value), {
216
+ default: w(() => [y(e.$slots, "avatar", {}, () => [l(x(z.value?.slice(0, 1)), 1)], !0)]),
217
+ _: 3
218
+ }, 16),
219
+ Ye.value ? (_(), s("span", {
220
+ key: 0,
221
+ class: g(["user-avatar-info__gender-badge", `user-avatar-info__gender-badge--${U.value}`]),
222
+ "aria-hidden": "true"
223
+ }, [U.value === "male" ? (_(), a(S(T), {
224
+ key: 0,
225
+ size: K.value,
226
+ "stroke-width": 2.5
227
+ }, null, 8, ["size"])) : (_(), a(S(he), {
228
+ key: 1,
229
+ size: K.value,
230
+ "stroke-width": 2.5
231
+ }, null, 8, ["size"]))], 2)) : o("", !0),
232
+ Xe.value ? (_(), s("span", {
233
+ key: 1,
234
+ class: g(["user-avatar-info__presence-badge", { "user-avatar-info__presence-badge--online": Ze.value }]),
235
+ "aria-hidden": "true"
236
+ }, null, 2)) : o("", !0)
237
+ ]), c("div", { class: g(["user-avatar-info__meta", Je.value]) }, [c("div", Se, [y(e.$slots, "name", {}, () => [l(x(z.value), 1)], !0)]), B.value || e.$slots.subtitle ? (_(), s("div", Ce, [u(h, {
238
+ placement: "top",
239
+ disabled: !Q.value,
240
+ "show-after": 200,
241
+ "popper-class": "user-avatar-info-tooltip"
242
+ }, {
243
+ content: w(() => [c("div", E, [y(e.$slots, "subtitle", {}, () => [l(x(B.value), 1)], !0)])]),
244
+ default: w(() => [c("div", {
245
+ ref_key: "subtitleRef",
246
+ ref: Z,
247
+ class: g(["user-avatar-info__subtitle", { "user-avatar-info__subtitle--overflow": Q.value }])
248
+ }, [y(e.$slots, "subtitle", {}, () => [l(x(B.value), 1)], !0)], 2)]),
249
+ _: 3
250
+ }, 8, ["disabled"])])) : o("", !0)], 2)], 42, be)), P.value ? (_(), a(v, m({
251
+ key: 2,
252
+ modelValue: N.value,
253
+ "onUpdate:modelValue": n[0] ||= (e) => N.value = e,
254
+ size: t.drawerSize,
255
+ class: "user-avatar-info-drawer row-detail-drawer"
256
+ }, et.value, { onClosed: Re }), {
257
+ header: w(() => [c("div", D, [c("span", O, x(Qe.value), 1)])]),
258
+ default: w(() => [Ke.value ? (_(), s("div", k, [y(e.$slots, "default", {}, void 0, !0)])) : (_(), s("div", A, [c("section", we, [c("div", Te, [y(e.$slots, "drawer-avatar", {}, () => [u(f, {
259
+ size: p.drawerAvatarSize,
260
+ src: q.value.src
261
+ }, {
262
+ default: w(() => [l(x(V.value?.slice(0, 1)), 1)]),
263
+ _: 1
264
+ }, 8, ["size", "src"])], !0)]), c("div", Ee, [c("div", De, [y(e.$slots, "drawer-name", {}, () => [c("strong", Oe, x(V.value), 1)], !0), qe.value ? (_(), s("span", ke, x(G.value), 1)) : o("", !0)]), c("div", Ae, [H.value ? (_(), s("span", je, x(S(F)("field.id")) + ": " + x(H.value), 1)) : o("", !0), X.value ? (_(), s("span", Me, x(X.value), 1)) : o("", !0)])])]), c("section", Ne, [(_(!0), s(r, null, te($e.value, (e) => (_(), s("div", {
265
+ key: e.key,
266
+ class: "user-avatar-info__field-card"
267
+ }, [c("div", Pe, [(_(), a(ne(e.icon), {
268
+ size: 18,
269
+ "stroke-width": 2.2
270
+ }))]), c("div", Fe, [c("div", Ie, x(e.label), 1), c("div", Le, x(e.value), 1)])]))), 128))])]))]),
271
+ _: 3
272
+ }, 16, ["modelValue", "size"])) : o("", !0)]);
273
+ };
274
+ }
275
+ }), [["__scopeId", "data-v-5b19a12c"]]), M = /* @__PURE__ */ d({
276
+ __name: "avatar-cell",
277
+ props: {
278
+ row: { default: () => ({}) },
279
+ value: { default: null }
280
+ },
281
+ setup(e) {
282
+ let t = e, n = i(() => t.row?.userId), r = i(() => t.row?.nickName ?? ""), o = i(() => t.row?.userName ?? ""), s = i(() => t.row?.avatar ?? ""), c = i(() => t.row?.sex ?? ""), l = i(() => t.row?.deptName ?? t.row?.dept?.deptName ?? "");
283
+ return (e, t) => (_(), a(j, {
284
+ "user-id": n.value,
285
+ "nick-name": r.value,
286
+ name: o.value,
287
+ src: s.value,
288
+ avatar: s.value,
289
+ sex: c.value,
290
+ "dept-name": l.value
291
+ }, null, 8, [
292
+ "user-id",
293
+ "nick-name",
294
+ "name",
295
+ "src",
296
+ "avatar",
297
+ "sex",
298
+ "dept-name"
299
+ ]));
300
+ }
301
+ });
302
+ export { M as default };
@@ -0,0 +1,34 @@
1
+ import { ref as e } from "vue";
2
+ // src/runtime/context.ts
3
+ var t = e("zh-CN"), n = e({}), r = e(() => !0), i = e(() => ""), a = e("hover"), o = null, s, c, l = "";
4
+ function u(e) {
5
+ e.locale && (t.value = e.locale), e.messages && (n.value = e.messages), e.request && (o = e.request), e.fetchAllDictData && (s = e.fetchAllDictData), e.uploadFile && (c = e.uploadFile), e.imageBaseUrl !== void 0 && (l = e.imageBaseUrl), e.hasAccess && (r.value = e.hasAccess), e.getAccessToken && (i.value = e.getAccessToken), e.cardShadow && (a.value = e.cardShadow);
6
+ }
7
+ function d() {
8
+ return t;
9
+ }
10
+ function f() {
11
+ return n;
12
+ }
13
+ function p() {
14
+ return o;
15
+ }
16
+ function m() {
17
+ return s?.() ?? Promise.resolve({});
18
+ }
19
+ function h() {
20
+ return c;
21
+ }
22
+ function g() {
23
+ return l;
24
+ }
25
+ function _() {
26
+ return r;
27
+ }
28
+ function v() {
29
+ return i.value();
30
+ }
31
+ function y() {
32
+ return a;
33
+ }
34
+ export { f as a, d as c, y as i, p as l, _ as n, h as o, v as r, g as s, u as t, m as u };