@gspwidget/wisedoc-mobile-selector 0.0.0-stage → 1.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.
@@ -0,0 +1 @@
1
+ .mobile-frame[data-v-1a3b612f]{--accent: #2660ff;font-family:PingFang SC,-apple-system,BlinkMacSystemFont,Microsoft YaHei,sans-serif;color:#1a1a1a;background:#fff;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}.mobile-frame[data-v-1a3b612f],.mobile-frame[data-v-1a3b612f] *,.mobile-frame[data-v-1a3b612f] *:before,.mobile-frame[data-v-1a3b612f] *:after{box-sizing:border-box}button[data-v-1a3b612f]{font:inherit}button[data-v-1a3b612f]{cursor:pointer;-webkit-tap-highlight-color:transparent}button[data-v-1a3b612f]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.mobile-frame[data-v-1a3b612f]{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;max-width:600px;margin:0 auto;background:#fff;overflow:hidden}.selector-sheet[data-v-1a3b612f]{display:flex;flex:1 1 auto;flex-direction:column;min-height:0;overflow:hidden;background:#fff}.sheet-header[data-v-1a3b612f]{position:relative;display:flex;flex:0 0 76px;align-items:center;justify-content:center;padding-top:4px}.sheet-header h1[data-v-1a3b612f]{margin:0;padding:0 48px;font-size:17px;font-weight:500;line-height:24px;letter-spacing:.3px}.header-back[data-v-1a3b612f],.header-close[data-v-1a3b612f]{position:absolute;top:18px;display:grid;width:44px;height:44px;padding:0;place-items:center;border:0;background:transparent;color:#1a1a1a}.header-back[data-v-1a3b612f]{left:0}.header-close[data-v-1a3b612f]{right:0}.header-icon[data-v-1a3b612f]{display:block;width:16px;height:16px}.tabs[data-v-1a3b612f],.breadcrumbs[data-v-1a3b612f]{display:flex;align-items:center;min-width:0}.tabs[data-v-1a3b612f]{flex:0 0 48px;height:48px;padding:0 16px;border-bottom:1px solid #e6e6e6;font-size:16px;line-height:24px;white-space:nowrap}.tab-active[data-v-1a3b612f]{position:relative;display:flex;align-items:center;height:48px;color:var(--accent);font-weight:500}.tab-active[data-v-1a3b612f]:after{position:absolute;bottom:0;left:0;width:100%;height:3px;border-radius:2px;background:linear-gradient(267deg,#2660ff,#3b82ff);content:""}.breadcrumbs[data-v-1a3b612f]{flex:0 0 56px;height:56px;gap:0;padding:8px 16px 0;overflow-x:auto;scrollbar-width:none;white-space:nowrap}.breadcrumbs[data-v-1a3b612f]::-webkit-scrollbar{display:none}.breadcrumbs button[data-v-1a3b612f]{flex:0 0 auto;max-width:min(47vw,176px);overflow:hidden;padding:0;border:0;background:transparent;color:#666;font-size:16px;line-height:24px;text-overflow:ellipsis;white-space:nowrap}.breadcrumbs .crumb-current[data-v-1a3b612f]{max-width:min(30vw,160px);color:#1a1a1a;font-weight:500}.crumb-divider[data-v-1a3b612f]{display:grid;flex:0 0 16px;place-items:center;width:16px;height:24px;color:#d1d1d1;font-size:16px;line-height:24px}.content-list[data-v-1a3b612f]{flex:1 1 auto;min-height:0;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}.content-list[data-v-1a3b612f]::-webkit-scrollbar{display:none}.root-list[data-v-1a3b612f]{padding-top:8px}.entry-row[data-v-1a3b612f]{display:flex;align-items:center;gap:12px;min-width:0;height:56px;padding:0 16px}.check-button[data-v-1a3b612f]{position:relative;display:grid;flex:0 0 24px;place-items:center;width:24px;height:24px;padding:0;border:0;background:transparent}.check-button[data-v-1a3b612f]:before{position:absolute;top:1px;right:1px;bottom:1px;left:1px;border:1px solid #999;border-radius:50%;background:#fff;content:""}.check-button.checked[data-v-1a3b612f]:before,.check-button.indeterminate[data-v-1a3b612f]:before{border-color:var(--accent);background:var(--accent)}.check-button.locked[data-v-1a3b612f]{cursor:not-allowed}.content-list:not(.selected-list) .check-button[data-v-1a3b612f]{margin-right:4px}.check-mark[data-v-1a3b612f]{position:relative;width:12px;height:7px;margin-top:-2px;transform:rotate(-45deg);border-left:2px solid #fff;border-bottom:2px solid #fff}.half-mark[data-v-1a3b612f]{position:relative;width:10px;height:2px;border-radius:1px;background:#fff}.entry-icon[data-v-1a3b612f]{flex:0 0 32px;width:32px;height:32px;object-fit:contain}.entry-name[data-v-1a3b612f]{flex:1 1 auto;min-width:0;overflow:hidden;padding:0;border:0;background:transparent;color:#1a1a1a;font-size:16px;font-weight:400;line-height:24px;text-align:left;text-overflow:ellipsis;white-space:nowrap}.row-next[data-v-1a3b612f]{display:grid;flex:0 0 28px;place-items:center;width:28px;height:44px;margin-right:-8px;padding:0;border:0;background:transparent}.right-chevron[data-v-1a3b612f]{display:inline-block;flex:0 0 auto;width:9px;height:9px;transform:rotate(-45deg);border-right:1.6px solid #a1a1a1;border-bottom:1.6px solid #a1a1a1}.status[data-v-1a3b612f]{display:flex;flex-direction:column;align-items:center;gap:14px;justify-content:center;min-height:160px;padding:24px;color:#777;font-size:14px;text-align:center}.status.error[data-v-1a3b612f]{color:#d9363e}.empty-state[data-v-1a3b612f]{min-height:240px;gap:16px;color:gray;font-size:14px;line-height:22px}.empty-state img[data-v-1a3b612f]{display:block;width:120px;height:100px}.status button[data-v-1a3b612f],.inline-error button[data-v-1a3b612f],.more-button[data-v-1a3b612f]{padding:0;border:0;background:transparent;color:var(--accent)}.more-button[data-v-1a3b612f]{display:block;width:100%;height:48px;font-size:14px}.more-button[data-v-1a3b612f]:disabled{color:#aaa}.inline-error[data-v-1a3b612f]{padding:12px 16px;color:#d9363e;font-size:13px;text-align:center}.selected-list[data-v-1a3b612f]{padding-top:0}.selected-list .entry-row[data-v-1a3b612f]{gap:12px}.selected-name[data-v-1a3b612f]{margin-right:auto}.remove-button[data-v-1a3b612f]{position:relative;display:grid;flex:0 0 32px;place-items:center;width:32px;height:44px;margin-right:-8px;margin-left:-4px;padding:0;border:0;background:transparent;font-size:0}.remove-button[data-v-1a3b612f]:before,.remove-button[data-v-1a3b612f]:after{position:absolute;width:14px;height:1.5px;background:#999;content:""}.remove-button[data-v-1a3b612f]:before{transform:rotate(45deg)}.remove-button[data-v-1a3b612f]:after{transform:rotate(-45deg)}.footer-bar[data-v-1a3b612f]{display:flex;flex:0 0 64px;align-items:center;gap:16px;height:64px;margin:0;padding:0 16px;border-top:1px solid #e6e6e6;background:rgba(255,255,255,.95)}.selection-summary[data-v-1a3b612f]{display:flex;flex:1 1 auto;align-items:center;gap:8px;min-width:0;min-height:40px;padding:0;border:0;background:transparent;color:#1a1a1a;font-size:14px;line-height:24px;text-align:left}.summary-arrow[data-v-1a3b612f]{display:block;flex:0 0 12px;width:12px;height:12px;color:#999}.selection-summary .summary-label[data-v-1a3b612f]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.summary-label strong[data-v-1a3b612f]{font-weight:500}.selection-summary[data-v-1a3b612f]:disabled{color:#777;cursor:default}.confirm-button[data-v-1a3b612f]{flex:0 0 64px;width:64px;height:32px;padding:0;border:0;border-radius:6px;background:var(--accent);color:#fff;font-size:14px;font-weight:500}.confirm-button[data-v-1a3b612f]:disabled{background:#aabfff}.notice[data-v-1a3b612f]{position:fixed;right:16px;bottom:80px;left:16px;max-width:500px;margin:0 auto;padding:10px 14px;border-radius:8px;background:rgba(0,0,0,.78);color:#fff;font-size:13px;text-align:center}@media (max-width: 350px){.entry-row[data-v-1a3b612f]{gap:9px;padding:0 12px}.entry-name[data-v-1a3b612f]{font-size:15px}.footer-bar[data-v-1a3b612f]{gap:8px;padding-right:12px;padding-left:12px}}
@@ -0,0 +1,48 @@
1
+ import { type KnowledgeApiOptions } from './shared/data-source';
2
+ import type { KnowledgeDataSource, KnowledgeSelection, KnowledgeSelectionResult } from './shared/types';
3
+ declare function setSelection(value: unknown): void;
4
+ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
5
+ dataSource?: KnowledgeDataSource | undefined;
6
+ apiOptions?: KnowledgeApiOptions | undefined;
7
+ initialSelection?: KnowledgeSelection[] | undefined;
8
+ iframeMessaging?: boolean | undefined;
9
+ }>, {
10
+ iframeMessaging: boolean;
11
+ }>>, {
12
+ setSelection: typeof setSelection;
13
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
+ error: (error: unknown) => void;
15
+ close: () => void;
16
+ confirm: (payload: KnowledgeSelectionResult, selections: KnowledgeSelection[]) => void;
17
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<{
18
+ dataSource?: KnowledgeDataSource | undefined;
19
+ apiOptions?: KnowledgeApiOptions | undefined;
20
+ initialSelection?: KnowledgeSelection[] | undefined;
21
+ iframeMessaging?: boolean | undefined;
22
+ }>, {
23
+ iframeMessaging: boolean;
24
+ }>>> & Readonly<{
25
+ onError?: ((error: unknown) => any) | undefined;
26
+ onClose?: (() => any) | undefined;
27
+ onConfirm?: ((payload: KnowledgeSelectionResult, selections: KnowledgeSelection[]) => any) | undefined;
28
+ }>, {
29
+ iframeMessaging: boolean;
30
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
31
+ export default _default;
32
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
33
+ type __VLS_TypePropsToRuntimeProps<T> = {
34
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
35
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
36
+ } : {
37
+ type: import('vue').PropType<T[K]>;
38
+ required: true;
39
+ };
40
+ };
41
+ type __VLS_WithDefaults<P, D> = {
42
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
43
+ default: D[K];
44
+ }> : P[K];
45
+ };
46
+ type __VLS_Prettify<T> = {
47
+ [K in keyof T]: T[K];
48
+ } & {};
@@ -0,0 +1,3 @@
1
+ import type { KnowledgeDataSource } from './shared/types';
2
+ /** Development-only visual fixture; production always uses the real API source. */
3
+ export declare const demoSource: KnowledgeDataSource;
@@ -0,0 +1,7 @@
1
+ import type { MobileKnowledgeSelectorComponent } from './public-types';
2
+ export declare const MobileKnowledgeSelector: MobileKnowledgeSelectorComponent;
3
+ export default MobileKnowledgeSelector;
4
+ export type { MobileKnowledgeSelectorProps } from './public-types';
5
+ export { createKnowledgeDataSource, DEFAULT_KNOWLEDGE_SELECTOR_CONFIG_URL } from './shared/data-source';
6
+ export type { KnowledgeApiConfig, KnowledgeApiOptions } from './shared/data-source';
7
+ export type { KnowledgeKind, KnowledgeNode, KnowledgeSelection, KnowledgeSelectionResult, KnowledgeChildren, KnowledgeDataSource } from './shared/types';
@@ -0,0 +1,15 @@
1
+ import type { ComponentOptionsMixin, DefineComponent } from 'vue';
2
+ import type { KnowledgeApiOptions } from './shared/data-source';
3
+ import type { KnowledgeDataSource, KnowledgeSelection, KnowledgeSelectionResult } from './shared/types';
4
+ export interface MobileKnowledgeSelectorProps {
5
+ dataSource?: KnowledgeDataSource;
6
+ apiOptions?: KnowledgeApiOptions;
7
+ initialSelection?: KnowledgeSelection[];
8
+ }
9
+ export type MobileKnowledgeSelectorComponent = DefineComponent<MobileKnowledgeSelectorProps, {
10
+ setSelection(value: KnowledgeSelection[]): void;
11
+ }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
12
+ confirm: (result: KnowledgeSelectionResult, selections: KnowledgeSelection[]) => void;
13
+ close: () => void;
14
+ error: (error: unknown) => void;
15
+ }>;
@@ -0,0 +1,25 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { KnowledgeDataSource } from './types';
3
+ export interface KnowledgeApiOptions {
4
+ /** Inject the host Axios instance to reuse authentication interceptors. */
5
+ http?: AxiosInstance;
6
+ baseURL?: string;
7
+ withCredentials?: boolean;
8
+ /** Resolve config, API and authentication URLs against the selector server when used as a remote script. */
9
+ serviceOrigin?: string;
10
+ /** Runtime configuration, useful when the host already loaded its own settings. */
11
+ config?: KnowledgeApiConfig;
12
+ /** Overrides the shared deploy-time JSON URL; an empty string disables file loading. */
13
+ configUrl?: string;
14
+ }
15
+ /** Shared static file under the 5300 service's web root, independent of the host app directory. */
16
+ export declare const DEFAULT_KNOWLEDGE_SELECTOR_CONFIG_URL = "/subapp/wisedoc/knowledge-selector.config.json";
17
+ export interface KnowledgeApiConfig {
18
+ /** true: /api/wisedoc/rest; false: /api/cms/cs/v1.0. Defaults to true. */
19
+ useWisedocApi?: boolean;
20
+ /** Optional origin or reverse-proxy prefix, e.g. https://host:5200 or /cms-proxy. */
21
+ apiBaseUrl?: string;
22
+ }
23
+ /** Uses the existing wisedoc/CMS endpoint contracts without depending on the host application. */
24
+ export declare function createKnowledgeDataSource(options?: KnowledgeApiOptions): KnowledgeDataSource;
25
+ export declare const knowledgeDataSource: KnowledgeDataSource;
@@ -0,0 +1,14 @@
1
+ import type { KnowledgeSelection } from './types';
2
+ export declare const selectionKey: (item: KnowledgeSelection) => string;
3
+ export declare function covers(parent: KnowledgeSelection, child: KnowledgeSelection): boolean;
4
+ export declare function toSelection(item: KnowledgeSelection): KnowledgeSelection;
5
+ /** Also validates iframe input before it becomes reactive application state. */
6
+ export declare function normalizeSelection(value: unknown): KnowledgeSelection[];
7
+ export declare function selectionState(item: KnowledgeSelection, selected: KnowledgeSelection[]): {
8
+ checked: boolean;
9
+ disabled: boolean;
10
+ indeterminate: boolean;
11
+ inheritedFrom: string | undefined;
12
+ };
13
+ export declare function toggleSelection(item: KnowledgeSelection, selected: KnowledgeSelection[]): KnowledgeSelection[];
14
+ export declare function toIdResult(selected: KnowledgeSelection[]): import('./types').KnowledgeSelectionResult;
@@ -0,0 +1,34 @@
1
+ export type KnowledgeKind = 'library' | 'directory' | 'document';
2
+ /** A selected range, not an enumeration of every document it covers. */
3
+ export interface KnowledgeSelection {
4
+ id: string;
5
+ /** Document attachment metadata ID(s). Present for document selections. */
6
+ attachments?: string;
7
+ type: KnowledgeKind;
8
+ name: string;
9
+ libraryId: string;
10
+ parentId: string | null;
11
+ /** Ordered from the library to the immediate parent; library itself has []. */
12
+ ancestorIds: string[];
13
+ includeDescendants: boolean;
14
+ }
15
+ export interface KnowledgeNode extends KnowledgeSelection {
16
+ icon?: string;
17
+ pathNames: string[];
18
+ }
19
+ export interface KnowledgeChildren {
20
+ directories: KnowledgeNode[];
21
+ documents: KnowledgeNode[];
22
+ /** Total before backend permission filtering; do not infer the last page from row count. */
23
+ total: number;
24
+ }
25
+ export interface KnowledgeDataSource {
26
+ getLibraries(signal?: AbortSignal): Promise<KnowledgeNode[]>;
27
+ getChildren(parent: KnowledgeNode, page: number, size: number, signal?: AbortSignal): Promise<KnowledgeChildren>;
28
+ }
29
+ /** Explicit selected scopes grouped by entity kind. DocIds contains document attachments values. */
30
+ export interface KnowledgeSelectionResult {
31
+ KBIds: string[];
32
+ DirIds: string[];
33
+ DocIds: string[];
34
+ }
@@ -0,0 +1,165 @@
1
+ # 移动端知识库选择组件:npm 接入与发布
2
+
3
+ 包名:`@gspwidget/wisedoc-mobile-selector`,本次版本:`1.1.0`。适用于 **Vue 3.4.38 及以上的 Vue 3 项目**,不支持 Vue 2,也不直接作为原生 App 组件运行;原生 App 可在 Vue WebView 页面中集成。
4
+
5
+ 该包只包含移动端选择组件、接口和选择逻辑、图标、组件样式及 TypeScript 类型,不包含独立页面、设计稿、示例项目、node_modules 或整个前端工程。Vue 由使用方工程提供,Axios 是 npm 安装时解析的运行依赖。原来的 iframe 页面仍可通过 `npm run build` 单独构建。
6
+
7
+ ## 1. 安装
8
+
9
+ 未发布时,把交付的 tgz 文件发给同事,在对方项目根目录执行(换成实际文件路径):
10
+
11
+ ```powershell
12
+ npm install 'D:\交付物\gspwidget-wisedoc-mobile-selector-1.1.0.tgz'
13
+ ```
14
+
15
+ 发布后:
16
+
17
+ ```powershell
18
+ npm install @gspwidget/wisedoc-mobile-selector --registry=https://registry.npmjs.org/
19
+ ```
20
+
21
+ ## 2. Vue 页面直接使用
22
+
23
+ ```vue
24
+ <script setup lang="ts">
25
+ import { ref } from 'vue'
26
+ import { MobileKnowledgeSelector } from '@gspwidget/wisedoc-mobile-selector'
27
+ import type { KnowledgeSelection, KnowledgeSelectionResult } from '@gspwidget/wisedoc-mobile-selector'
28
+ import '@gspwidget/wisedoc-mobile-selector/style.css'
29
+
30
+ const opened = ref(false)
31
+ const selection = ref<KnowledgeSelection[]>([])
32
+
33
+ function onConfirm(result: KnowledgeSelectionResult, selections: KnowledgeSelection[]) {
34
+ // result = { KBIds: string[], DirIds: string[], DocIds: string[] }
35
+ // DocIds 是文档 attachments 字段的原始字符串,不是文档主键。
36
+ console.log(result)
37
+ selection.value = selections // 下次打开时回显
38
+ opened.value = false
39
+ }
40
+ </script>
41
+
42
+ <template>
43
+ <button @click="opened = true">选择知识库文件</button>
44
+ <div v-if="opened" class="kb-mask">
45
+ <div class="kb-panel">
46
+ <MobileKnowledgeSelector
47
+ :initial-selection="selection"
48
+ @confirm="onConfirm"
49
+ @close="opened = false"
50
+ @error="error => console.error(error)"
51
+ />
52
+ </div>
53
+ </div>
54
+ </template>
55
+
56
+ <style scoped>
57
+ .kb-mask { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: flex-end; background: rgb(0 0 0 / 40%); }
58
+ .kb-panel { width: 100%; height: calc(100dvh - 44px); overflow: hidden; border-radius: 16px 16px 0 0; background: white; }
59
+ </style>
60
+ ```
61
+
62
+ 也可以放进已有的 Popup / Dialog 内容区域,**必须给组件父容器明确高度**,组件使用 100% 高度,内部列表滚动;组件不创建遮罩,不设置宿主 body 或 #app 样式。底部操作栏固定 64px,紧贴容器底部,不再自动叠加 safe-area。如果宿主需要避开系统 Home 指示器,由宿主容器统一处理,避免重复留白。
63
+
64
+ ### Props、事件和回显
65
+
66
+ | 名称 | 说明 |
67
+ | --- | --- |
68
+ | `initialSelection` | 可选 `KnowledgeSelection[]`,首次挂载时读取;传上次 `confirm` 的第二个参数用于回显 |
69
+ | `apiOptions` | 可选接口选项,首次挂载时读取,见下一节 |
70
+ | `dataSource` | 可选自定义 `KnowledgeDataSource`,优先于 `apiOptions` |
71
+ | `@confirm` | 两个参数:`(result, selections)`;第一个只含 KBIds / DirIds / DocIds,第二个用于回显 |
72
+ | `@close` | 点击右上角关闭按钮时触发,无参数,不提交本轮变更 |
73
+ | `@error` | 数据加载失败时触发,参数为错误对象,界面保留重试入口 |
74
+ | `ref.setSelection(selections)` | 组件实例方法,用于挂载后主动更新回显 |
75
+
76
+ 下钻时标题左侧返回上一级;已选列表的返回按钮回到之前的浏览位置。确定与关闭只发出事件,由宿主关闭自己的弹窗。示例使用 `v-if`,关闭时卸载,下次打开重建。若使用 `v-show` 保持实例,重新打开时可调用 `setSelection`;接口配置变化后请重新挂载。
77
+
78
+ 选择某知识库或目录即覆盖它的全部下级,下级不能单独取消;可以跨库混选。结果只列出显式选择的范围,不枚举所覆盖的全部子项。DocIds 中每个值保留对应 attachments 原始字符串,不按逗号拆分。
79
+
80
+ ## 3. 配置文件和接口地址
81
+
82
+ 默认仍从**宿主页面所在服务**读取:
83
+
84
+ ```text
85
+ /subapp/wisedoc/knowledge-selector.config.json
86
+ ```
87
+
88
+ 配置不存在(404)时默认走 Wisedoc;配置格式错误或其他请求错误会显示加载错误。配置示例:
89
+
90
+ ```json
91
+ { "useWisedocApi": false, "apiBaseUrl": "/cms-proxy" }
92
+ ```
93
+
94
+ `useWisedocApi` 缺省或为 true 时使用 Wisedoc;false 时使用 CMS,并保留 CMS 未登录认证、`Accept: text/html` 和会话建立等待逻辑。
95
+
96
+ 如果宿主也部署在 5300 的 web 目录下,无需配置 URL,不受宿主子目录影响。**npm 包安装位置不代表接口服务地址**。若宿主部署在另一个服务,而公共配置仍在 5300,显式提供接口选项:
97
+
98
+ ```ts
99
+ const apiOptions = {
100
+ serviceOrigin: 'https://实际5300服务域名:5300',
101
+ withCredentials: true
102
+ }
103
+ // <MobileKnowledgeSelector :api-options="apiOptions" ... />
104
+ ```
105
+
106
+ 此时公共 JSON、相对 API 路径、认证路径都以该服务为基准,JSON 中的绝对 apiBaseUrl 仍按原配置使用。也支持 `config` 直接传配置(跳过 JSON)、`configUrl` 覆盖配置路径、`http` 注入 Axios 实例。一般保持默认即可。同源网关代理最省事;跨域请求的 CORS、Cookie 和认证跳转仍须由服务端配置,npm 集成本身不会消除接口跨域。
107
+
108
+ ## 4. 本工程构建和打包
109
+
110
+ ```powershell
111
+ Set-Location 'D:\Java\doc\移动端选择\wisedoc-mobile-selector'
112
+ npm ci
113
+ npm test
114
+ npm run build:lib
115
+ npm run pack:lib
116
+ ```
117
+
118
+ - `build:lib`:生成 `dist-lib/index.js`(ESM)、`index.cjs`(CommonJS)、`style.css` 和 `types/` 声明文件,供打包工具引入。
119
+ - `pack:lib`:运行 `npm pack`,其 prepack 会自动重新执行 `build:lib`,然后按 package.json 的 files 白名单生成 `gspwidget-wisedoc-mobile-selector-1.1.0.tgz`。仅想生成 tgz,直接执行这一条即可。
120
+ - `npm run build`:仍生成 iframe 独立页面 `dist/`,与 npm 包分开。
121
+
122
+ ## 5. 第一次发布到 npm 官方仓库(由你操作)
123
+
124
+ `@gspwidget/widget-devkit` 是组织作用域下的一个包;本次会新增另一个包 `@gspwidget/wisedoc-mobile-selector`,不会覆盖 widget-devkit。你需要自己的 npm 账号,并请 @gspwidget 管理员为你授予该组织的创建/发布包权限。包名中的 @gspwidget 不能仅靠本地配置获得权限。若组织使用内部 registry,请先向管理员确认;以下命令明确针对 npm 官方仓库。
125
+
126
+ 1. 到 [npm 官网](https://www.npmjs.com/) 注册/登录账号,并按照页面提示启用发布所需的双因素认证。然后在终端登录(认证由你完成,不要将 token 写入交付物):
127
+
128
+ ```powershell
129
+ npm login --registry=https://registry.npmjs.org/
130
+ npm whoami --registry=https://registry.npmjs.org/
131
+ ```
132
+
133
+ 2. 在项目目录检查包名、版本和实际将上传的文件。dry-run 不发布:
134
+
135
+ ```powershell
136
+ npm pkg get name version
137
+ npm run pack:lib
138
+ npm publish ./gspwidget-wisedoc-mobile-selector-1.1.0.tgz --dry-run --access public --registry=https://registry.npmjs.org/
139
+ ```
140
+
141
+ 3. 确认预览后,发布已经检查过的同一个 tgz,按提示完成认证:
142
+
143
+ ```powershell
144
+ npm publish ./gspwidget-wisedoc-mobile-selector-1.1.0.tgz --access public --registry=https://registry.npmjs.org/
145
+ ```
146
+
147
+ `--access public` 表示任何人都能下载这个包。若希望仅公司人员访问,请由组织管理员确认私有包服务/权限后使用 restricted,勿直接执行公开发布命令。官方 scoped public 包的发布方式见 [npm 官方说明](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/)。发布认证要求见 [npm 双因素认证说明](https://docs.npmjs.com/requiring-2fa-for-package-publishing-and-settings-modification/)。
148
+
149
+ 4. 检查发布结果,让同事执行前面的安装命令:
150
+
151
+ ```powershell
152
+ npm view @gspwidget/wisedoc-mobile-selector version --registry=https://registry.npmjs.org/
153
+ ```
154
+
155
+ 若报 403,通常需要核对组织发布权限、包名归属或发布认证。后续更新不能覆盖已发布的同一版本。修改代码后可用下面的命令更新版本并重新打包(这些命令不执行 Git 操作):
156
+
157
+ ```powershell
158
+ npm pkg set version=1.1.1
159
+ npm install --package-lock-only --ignore-scripts
160
+ npm test
161
+ npm run pack:lib
162
+ # 然后对新生成的 1.1.1.tgz 做 dry-run 和 publish
163
+ ```
164
+
165
+ 本次只生成交付物,未登录或向 npm 上传任何包。
package/package.json CHANGED
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "name": "@gspwidget/wisedoc-mobile-selector",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.1.0",
4
+ "description": "Vue 3 移动端知识库、目录和文档选择组件",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "scripts": {
8
+ "dev": "vite --host 0.0.0.0 --port 4203",
9
+ "build": "vue-tsc --noEmit && vite build",
10
+ "build:page": "vue-tsc --noEmit && vite build",
11
+ "build:lib": "vue-tsc --noEmit && vite build --config vite.lib.config.ts && vue-tsc -p tsconfig.lib.json",
12
+ "pack:lib": "npm pack",
13
+ "prepack": "npm run build:lib",
14
+ "preview": "vite preview --host 0.0.0.0 --port 4203",
15
+ "test": "node tests/run-tests.mjs"
16
+ },
17
+ "main": "./dist-lib/index.cjs",
18
+ "module": "./dist-lib/index.js",
19
+ "types": "./dist-lib/types/index.d.ts",
20
+ "exports": {
21
+ ".": { "types": "./dist-lib/types/index.d.ts", "import": "./dist-lib/index.js", "require": "./dist-lib/index.cjs" },
22
+ "./style.css": "./dist-lib/style.css"
23
+ },
24
+ "files": ["dist-lib", "README.md", "npm接入与发布说明.md"],
25
+ "sideEffects": ["**/*.css"],
26
+ "publishConfig": { "registry": "https://registry.npmjs.org/", "access": "public" },
27
+ "peerDependencies": { "vue": "^3.4.38" },
28
+ "dependencies": {
29
+ "axios": "^1.7.9"
30
+ },
31
+ "devDependencies": {
32
+ "vue": "^3.4.38",
33
+ "@types/node": "^20.19.0",
34
+ "@vitejs/plugin-vue": "^4.6.2",
35
+ "typescript": "~5.3.3",
36
+ "vite": "^4.5.5",
37
+ "vue-tsc": "^1.8.27"
38
+ }
39
+ }