web-kxjl-components 0.0.0-stage → 1.0.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,52 @@
1
- # Temporary Holding Version
1
+ # web-kxjl-components
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
+ 公司公共组件库,基于 Vue 3 + TypeScript + Vite + Element Plus,发布到公网 npm。
4
+
5
+ ## 使用
6
+
7
+ ```bash
8
+ npm install web-kxjl-components
9
+ ```
10
+
11
+ 宿主项目需自带 `vue`、`element-plus`(peerDependencies),组件库不会重复打包这两个依赖。
12
+
13
+ 按需引入(推荐):
14
+
15
+ ```ts
16
+ import { KxEmpty } from "web-kxjl-components";
17
+ import "web-kxjl-components/style.css";
18
+ ```
19
+
20
+ 全量注册:
21
+
22
+ ```ts
23
+ import KxComponents from "web-kxjl-components";
24
+ import "web-kxjl-components/style.css";
25
+
26
+ app.use(KxComponents);
27
+ ```
28
+
29
+ ## 开发
30
+
31
+ ```bash
32
+ npm install
33
+ npm run build # vue-tsc 生成类型声明 + vite 库模式构建,产物在 dist/
34
+ ```
35
+
36
+ 新增组件:在 `src/components/<kx-xxx>/index.vue` 编写,然后在 `src/index.ts` 中导入、加入 `components` 并具名导出。
37
+
38
+ ## 提交约定
39
+
40
+ 直接在当前分支上提交,不额外新建分支;提交信息遵循 Conventional Commits(如 `feat(kx-xxx): ...`)。
41
+
42
+ ## 发布
43
+
44
+ 当前机器的 `~/.npmrc` 默认指向 npmmirror 镜像,镜像不能发布,`publishConfig` 已指定公网 registry。
45
+
46
+ ```bash
47
+ npm login --registry https://registry.npmjs.org/
48
+ npm version patch # 或 minor / major
49
+ npm publish
50
+ ```
51
+
52
+ 首次发布版本为 `1.0.0`。包发布到公网后任何人都能安装,不要放入内部地址、密钥等敏感内容。
@@ -0,0 +1,7 @@
1
+ type __VLS_Props = {
2
+ /** 图标地址,为空或加载失败时显示默认图标 */
3
+ src?: string;
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,28 @@
1
+ import type { ApiResult, Product } from "./types";
2
+ type __VLS_Props = {
3
+ /** 由宿主注入的请求函数,返回接口原始响应 */
4
+ fetcher: () => Promise<ApiResult<Product[]>>;
5
+ /** 由宿主注入的图标地址处理函数(拼接前缀、附带 token 等),仅处理相对路径;完整地址(http(s)、//、data、blob)不会传入;不传则图标地址原样使用 */
6
+ staticFileFormat?: (path: string) => string;
7
+ /** 无 sysUrl 的系统的悬浮提示 */
8
+ disabledTip?: string;
9
+ };
10
+ declare const __VLS_template: () => {
11
+ __VLS_Slots: {
12
+ default?: (props: {
13
+ visible: boolean;
14
+ }) => any;
15
+ };
16
+ };
17
+ type __VLS_Slots = ReturnType<typeof __VLS_template>['__VLS_Slots'];
18
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
19
+ disabledTip: string;
20
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
22
+ declare const _default: typeof __VLS_export;
23
+ export default _default;
24
+ type __VLS_WithSlots<T, S> = T & {
25
+ new (): {
26
+ $slots: S;
27
+ };
28
+ };
@@ -0,0 +1,31 @@
1
+ /** 产品下的系统 */
2
+ export interface ProductSystem {
3
+ id: number;
4
+ sysCode: string;
5
+ sysName: string;
6
+ description?: string;
7
+ /** 图标,相对路径交由 staticFileFormat 处理,完整地址直接使用,空则使用默认图标 */
8
+ icon?: string;
9
+ /** 系统地址,缺失时该系统置灰不可点;相对路径按当前域名拼接 */
10
+ sysUrl?: string;
11
+ /** 逗号分隔的标签 */
12
+ tags?: string;
13
+ sortNum?: number;
14
+ }
15
+ /** 产品(含其下系统) */
16
+ export interface Product {
17
+ id: number;
18
+ productCode: string;
19
+ productName: string;
20
+ description?: string;
21
+ icon?: string;
22
+ sortNum?: number;
23
+ systems: ProductSystem[];
24
+ }
25
+ /** 接口统一响应结构 */
26
+ export interface ApiResult<T> {
27
+ code: number;
28
+ data: T;
29
+ msg?: string;
30
+ dataType?: string;
31
+ }
@@ -0,0 +1,21 @@
1
+ type __VLS_Props = {
2
+ /** 提示文案 */
3
+ description?: string;
4
+ };
5
+ declare const __VLS_template: () => {
6
+ __VLS_Slots: {
7
+ default?: (props: {}) => any;
8
+ };
9
+ };
10
+ type __VLS_Slots = ReturnType<typeof __VLS_template>['__VLS_Slots'];
11
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
12
+ description: string;
13
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
17
+ type __VLS_WithSlots<T, S> = T & {
18
+ new (): {
19
+ $slots: S;
20
+ };
21
+ };
@@ -0,0 +1,10 @@
1
+ import type { App } from "vue";
2
+ import KxEmpty from "./components/kx-empty/index.vue";
3
+ import KxAppSwitcher from "./components/kx-app-switcher/index.vue";
4
+ export { KxEmpty, KxAppSwitcher };
5
+ export type { ApiResult, Product, ProductSystem, } from "./components/kx-app-switcher/types";
6
+ /** 全量注册:app.use(KxComponents) */
7
+ declare const _default: {
8
+ install(app: App): void;
9
+ };
10
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,163 @@
1
+ import { ElEmpty as e, ElLoadingDirective as t, ElPopover as n, ElTooltip as r } from "element-plus/es";
2
+ import "element-plus/es/components/base/style/css";
3
+ import "element-plus/es/components/empty/style/css";
4
+ import { Fragment as i, computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, createStaticVNode as u, createVNode as d, defineComponent as f, normalizeClass as p, openBlock as m, ref as h, renderList as g, renderSlot as _, toDisplayString as v, watch as y, withCtx as b, withDirectives as x } from "vue";
5
+ import "element-plus/es/components/loading/style/css";
6
+ import "element-plus/es/components/popover/style/css";
7
+ import "element-plus/es/components/tooltip/style/css";
8
+ // src/components/kx-empty/index.vue?vue&type=script&setup=true&lang.ts
9
+ var S = { class: "kx-empty" }, C = /*@__PURE__*/ f({
10
+ name: "KxEmpty",
11
+ __name: "index",
12
+ props: { description: { default: "暂无数据" } },
13
+ setup(t) {
14
+ return (n, r) => {
15
+ let i = e;
16
+ return m(), c("div", S, [d(i, { description: t.description }, {
17
+ default: b(() => [_(n.$slots, "default", {}, void 0, !0)]),
18
+ _: 3
19
+ }, 8, ["description"])]);
20
+ };
21
+ }
22
+ }), w = (e, t) => {
23
+ let n = e.__vccOpts || e;
24
+ for (let [e, r] of t) n[e] = r;
25
+ return n;
26
+ }, T = /*#__PURE__*/ w(C, [["__scopeId", "data-v-392d5d37"]]), E = ["src"], D = {
27
+ key: 1,
28
+ class: "kx-app-icon",
29
+ viewBox: "0 0 24 24",
30
+ "aria-hidden": "true"
31
+ }, O = /*#__PURE__*/ w(/* @__PURE__ */ f({
32
+ name: "KxAppIcon",
33
+ __name: "app-icon",
34
+ props: { src: {} },
35
+ setup(e) {
36
+ let t = e, n = h(!1);
37
+ return y(() => t.src, () => {
38
+ n.value = !1;
39
+ }), (t, r) => e.src && !n.value ? (m(), c("img", {
40
+ key: 0,
41
+ class: "kx-app-icon",
42
+ src: e.src,
43
+ alt: "",
44
+ onError: r[0] ||= (e) => n.value = !0
45
+ }, null, 40, E)) : (m(), c("svg", D, [...r[1] ||= [u("<rect width=\"24\" height=\"24\" rx=\"6\" fill=\"var(--el-color-primary)\" data-v-352f5b8f></rect><rect x=\"5\" y=\"5\" width=\"6\" height=\"6\" rx=\"1.5\" fill=\"#fff\" data-v-352f5b8f></rect><rect x=\"13\" y=\"5\" width=\"6\" height=\"6\" rx=\"1.5\" fill=\"#fff\" data-v-352f5b8f></rect><rect x=\"5\" y=\"13\" width=\"6\" height=\"6\" rx=\"1.5\" fill=\"#fff\" data-v-352f5b8f></rect><rect x=\"13\" y=\"13\" width=\"6\" height=\"6\" rx=\"1.5\" fill=\"#fff\" data-v-352f5b8f></rect>", 5)]]));
46
+ }
47
+ }), [["__scopeId", "data-v-352f5b8f"]]), k = { class: "kx-app-switcher__trigger" }, A = { class: "kx-app-switcher__panel" }, j = {
48
+ key: 0,
49
+ class: "kx-app-switcher__card kx-app-switcher__systems"
50
+ }, M = [
51
+ "aria-disabled",
52
+ "title",
53
+ "onClick"
54
+ ], N = { class: "kx-app-switcher__system-icon" }, P = { class: "kx-app-switcher__system-name" }, F = { class: "kx-app-switcher__card kx-app-switcher__products" }, I = [
55
+ "title",
56
+ "onMouseenter",
57
+ "onFocus",
58
+ "onClick"
59
+ ], L = { class: "kx-app-switcher__product-name" }, R = { class: "kx-app-switcher__product-icon" }, z = /*#__PURE__*/ w(/* @__PURE__ */ f({
60
+ name: "KxAppSwitcher",
61
+ __name: "index",
62
+ props: {
63
+ fetcher: {},
64
+ staticFileFormat: {},
65
+ disabledTip: { default: "暂未开通" }
66
+ },
67
+ setup(u) {
68
+ let f = u, S = h(!1), C = h(!1), w = h(!1), T = h([]), E = h(null), D = /^(https?:|data:|blob:|\/\/)/i;
69
+ function z(e) {
70
+ return [...e].sort((e, t) => (e.sortNum ?? 0) - (t.sortNum ?? 0));
71
+ }
72
+ let B = a(() => T.value.find((e) => e.id === E.value)?.systems ?? []);
73
+ async function V() {
74
+ if (!(C.value || w.value)) {
75
+ C.value = !0;
76
+ try {
77
+ let e = await f.fetcher();
78
+ e.code === 0 && Array.isArray(e.data) && (T.value = z(e.data).map((e) => ({
79
+ ...e,
80
+ systems: z(e.systems ?? [])
81
+ })), E.value = T.value[0]?.id ?? null, w.value = !0);
82
+ } catch {} finally {
83
+ C.value = !1;
84
+ }
85
+ }
86
+ }
87
+ y(S, (e) => {
88
+ e && V();
89
+ });
90
+ function H(e) {
91
+ return e ? D.test(e) ? e : f.staticFileFormat ? f.staticFileFormat(e) : e : "";
92
+ }
93
+ function U(e) {
94
+ if (!e.sysUrl) return;
95
+ let t;
96
+ try {
97
+ t = new URL(e.sysUrl, window.location.origin);
98
+ } catch {
99
+ return;
100
+ }
101
+ (t.protocol === "http:" || t.protocol === "https:") && (window.open(t.href, "_blank", "noopener,noreferrer"), S.value = !1);
102
+ }
103
+ return (a, f) => {
104
+ let h = r, y = e, w = n, D = t;
105
+ return m(), o(w, {
106
+ visible: S.value,
107
+ "onUpdate:visible": f[0] ||= (e) => S.value = e,
108
+ trigger: "click",
109
+ placement: "bottom-end",
110
+ width: 430,
111
+ "show-arrow": !1,
112
+ "popper-style": {
113
+ padding: 0,
114
+ border: "none",
115
+ background: "transparent",
116
+ boxShadow: "none"
117
+ }
118
+ }, {
119
+ reference: b(() => [l("span", k, [_(a.$slots, "default", { visible: S.value }, void 0, !0)])]),
120
+ default: b(() => [x((m(), c("div", A, [B.value.length ? (m(), c("div", j, [(m(!0), c(i, null, g(B.value, (e) => (m(), o(h, {
121
+ key: e.id,
122
+ content: u.disabledTip,
123
+ disabled: !!e.sysUrl,
124
+ placement: "left"
125
+ }, {
126
+ default: b(() => [l("button", {
127
+ type: "button",
128
+ class: p(["kx-app-switcher__system", { "is-disabled": !e.sysUrl }]),
129
+ "aria-disabled": !e.sysUrl,
130
+ title: e.description,
131
+ onClick: (t) => U(e)
132
+ }, [l("span", N, [d(O, { src: H(e.icon) }, null, 8, ["src"])]), l("span", P, v(e.sysName), 1)], 10, M)]),
133
+ _: 2
134
+ }, 1032, ["content", "disabled"]))), 128))])) : s("", !0), l("div", F, [
135
+ f[1] ||= l("div", { class: "kx-app-switcher__title" }, "应用切换", -1),
136
+ !C.value && !T.value.length ? (m(), o(y, {
137
+ key: 0,
138
+ "image-size": 60,
139
+ description: "暂无应用"
140
+ })) : s("", !0),
141
+ (m(!0), c(i, null, g(T.value, (e) => (m(), c("button", {
142
+ key: e.id,
143
+ type: "button",
144
+ class: p(["kx-app-switcher__product", { "is-active": e.id === E.value }]),
145
+ title: e.description,
146
+ onMouseenter: (t) => E.value = e.id,
147
+ onFocus: (t) => E.value = e.id,
148
+ onClick: (t) => E.value = e.id
149
+ }, [l("span", L, v(e.productName), 1), l("span", R, [d(O, { src: H(e.icon) }, null, 8, ["src"])])], 42, I))), 128))
150
+ ])])), [[D, C.value]])]),
151
+ _: 3
152
+ }, 8, ["visible"]);
153
+ };
154
+ }
155
+ }), [["__scopeId", "data-v-5a0f26bb"]]), B = {
156
+ KxEmpty: T,
157
+ KxAppSwitcher: z
158
+ }, V = { install(e) {
159
+ Object.entries(B).forEach(([t, n]) => {
160
+ e.component(t, n);
161
+ });
162
+ } };
163
+ export { z as KxAppSwitcher, T as KxEmpty, V as default };
@@ -0,0 +1,2 @@
1
+ .kx-empty[data-v-392d5d37]{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.kx-app-icon[data-v-352f5b8f]{object-fit:contain;width:100%;height:100%;display:block}.kx-app-switcher__trigger[data-v-5a0f26bb]{cursor:pointer;display:inline-flex}.kx-app-switcher__panel[data-v-5a0f26bb]{justify-content:flex-end;align-items:flex-start;gap:8px;min-height:80px;display:flex}.kx-app-switcher__card[data-v-5a0f26bb]{background:var(--el-bg-color-overlay);border:1px solid var(--el-border-color-light);box-shadow:var(--el-box-shadow-light);border-radius:8px;padding:12px}.kx-app-switcher__systems[data-v-5a0f26bb]{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.kx-app-switcher__system[data-v-5a0f26bb]{color:var(--el-text-color-primary);text-align:left;cursor:pointer;background:0 0;border:none;border-radius:6px;align-items:center;gap:10px;padding:8px;font-size:14px;display:flex}.kx-app-switcher__system[data-v-5a0f26bb]:hover{background:var(--el-fill-color-light)}.kx-app-switcher__system.is-disabled[data-v-5a0f26bb]{color:var(--el-text-color-disabled);cursor:not-allowed}.kx-app-switcher__system.is-disabled[data-v-5a0f26bb]:hover{background:0 0}.kx-app-switcher__system.is-disabled .kx-app-switcher__system-icon[data-v-5a0f26bb]{opacity:.4;filter:grayscale()}.kx-app-switcher__system-icon[data-v-5a0f26bb]{flex:none;width:24px;height:24px}.kx-app-switcher__system-name[data-v-5a0f26bb]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.kx-app-switcher__products[data-v-5a0f26bb]{flex-direction:column;flex:none;gap:8px;width:200px;display:flex}.kx-app-switcher__title[data-v-5a0f26bb]{color:var(--el-text-color-regular);font-size:14px}.kx-app-switcher__product[data-v-5a0f26bb]{height:56px;color:var(--el-text-color-primary);cursor:pointer;background:var(--el-fill-color-lighter);border:1px solid #0000;border-radius:8px;justify-content:space-between;align-items:center;padding:0 12px;font-size:15px;font-weight:600;display:flex}.kx-app-switcher__product.is-active[data-v-5a0f26bb]{background:var(--el-color-primary-light-9);border-color:var(--el-color-primary-light-5)}.kx-app-switcher__product-icon[data-v-5a0f26bb]{flex:none;width:36px;height:36px}
2
+ /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,49 @@
1
1
  {
2
2
  "name": "web-kxjl-components",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "公司公共组件库(Vue 3 + Element Plus)",
5
+ "type": "module",
6
+ "license": "UNLICENSED",
7
+ "sideEffects": [
8
+ "**/*.css"
9
+ ],
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "main": "./dist/index.js",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ },
21
+ "./style.css": "./dist/web-kxjl-components.css"
22
+ },
23
+ "publishConfig": {
24
+ "registry": "https://registry.npmjs.org/",
25
+ "access": "public"
26
+ },
27
+ "scripts": {
28
+ "dev": "vite build --watch",
29
+ "play": "vite",
30
+ "build": "vite build && vue-tsc -p tsconfig.build.json",
31
+ "prepublishOnly": "npm run build"
32
+ },
33
+ "peerDependencies": {
34
+ "element-plus": "^2.14.0",
35
+ "vue": "^3.5.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^24.12.3",
39
+ "@vitejs/plugin-vue": "^6.0.6",
40
+ "@vue/tsconfig": "^0.9.1",
41
+ "element-plus": "^2.14.1",
42
+ "sass-embedded": "^1.100.0",
43
+ "typescript": "~6.0.2",
44
+ "unplugin-vue-components": "^32.1.0",
45
+ "vite": "^8.0.12",
46
+ "vue": "^3.5.34",
47
+ "vue-tsc": "^3.2.8"
48
+ }
49
+ }