@veltra/desktop 1.0.9 → 1.0.11
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/dist/components/action/action-group.vue.d.ts +1 -1
- package/dist/components/action/action.vue.d.ts +3 -3
- package/dist/components/auto-complete/auto-complete.vue.d.ts +1 -1
- package/dist/components/batch-edit/batch-edit.js.map +1 -1
- package/dist/components/batch-edit/style.js +2 -2
- package/dist/components/batch-edit/use-edit.js.map +1 -1
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/button/button.vue.d.ts +1 -1
- package/dist/components/cascade/cascade.vue.d.ts +6 -6
- package/dist/components/cascade/use-select.js.map +1 -1
- package/dist/components/checkbox-group/checkbox-group.js.map +1 -1
- package/dist/components/code-editor/code-editor.js +2 -0
- package/dist/components/code-editor/code-editor.js.map +1 -1
- package/dist/components/date-panel/date-panel.js.map +1 -1
- package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
- package/dist/components/date-picker/date-picker.vue.d.ts +1 -1
- package/dist/components/date-range-picker/date-range-picker.vue.d.ts +1 -1
- package/dist/components/drawer/drawer.js.map +1 -1
- package/dist/components/expression-editor/expression-editor.js.map +1 -1
- package/dist/components/expression-editor/internal/editor-runtime/create-runtime.js.map +1 -1
- package/dist/components/expression-editor/internal/features/commands/register-command-packs.js.map +1 -1
- package/dist/components/expression-editor/internal/features/insertion/insertion-service.js.map +1 -1
- package/dist/components/expression-editor/use-decorators.js.map +1 -1
- package/dist/components/expression-editor/use-expression-drag-drop.js.map +1 -1
- package/dist/components/file-picker/file-picker.js.map +1 -1
- package/dist/components/file-picker/file-picker.vue.d.ts +1 -1
- package/dist/components/file-viewer/file-viewer.js +195 -30
- package/dist/components/file-viewer/file-viewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/docx-previewer.js +7 -5
- package/dist/components/file-viewer/previewers/docx-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/image-previewer.js +6 -6
- package/dist/components/file-viewer/previewers/image-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/pdf-previewer.js +5 -3
- package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -1
- package/dist/components/file-viewer/previewers/sheet-previewer.js.map +1 -1
- package/dist/components/file-viewer/style2.css +387 -136
- package/dist/components/form/form-model.js +2 -1
- package/dist/components/form/form-model.js.map +1 -1
- package/dist/components/grid/grid.js.map +1 -1
- package/dist/components/grid/use-responsive.js.map +1 -1
- package/dist/components/grid-input/grid-input.vue.d.ts +1 -1
- package/dist/components/input/input.vue.d.ts +3 -3
- package/dist/components/list/list.js.map +1 -1
- package/dist/components/loading/directive.js.map +1 -1
- package/dist/components/menu/menu-item.js.map +1 -1
- package/dist/components/message/message2.js.map +1 -1
- package/dist/components/multi-select/multi-select.js.map +1 -1
- package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
- package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +6 -6
- package/dist/components/notification/index.js.map +1 -1
- package/dist/components/notification/notification.vue.d.ts +1 -1
- package/dist/components/number-input/number-input.js.map +1 -1
- package/dist/components/number-input/number-input.vue.d.ts +1 -1
- package/dist/components/number-range-input/number-range-input.vue.d.ts +2 -2
- package/dist/components/palette/color-transform.js.map +1 -1
- package/dist/components/palette/palette-sv.js.map +1 -1
- package/dist/components/password-input/password-input.vue.d.ts +1 -1
- package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
- package/dist/components/progress/progress.js +1 -1
- package/dist/components/progress/progress.js.map +1 -1
- package/dist/components/progress-nodes/progress-nodes.js.map +1 -1
- package/dist/components/progress-nodes/progress-nodes.vue.d.ts +3 -3
- package/dist/components/rich-text-editor/rich-text-editor.js.map +1 -1
- package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +2 -2
- package/dist/components/rich-text-editor/toolbar.js.map +1 -1
- package/dist/components/scroll/scroll.js.map +1 -1
- package/dist/components/select/select.vue.d.ts +2 -2
- package/dist/components/slider/slider-thumb.js.map +1 -1
- package/dist/components/table/di.js.map +1 -1
- package/dist/components/table/style.js +1 -1
- package/dist/components/table/table-row.js +1 -2
- package/dist/components/table/table-row.js.map +1 -1
- package/dist/components/table/table.js +1 -2
- package/dist/components/table/table.js.map +1 -1
- package/dist/components/table/use-columns.js +4 -0
- package/dist/components/table/use-columns.js.map +1 -1
- package/dist/components/table/use-table.js +25 -0
- package/dist/components/table/use-table.js.map +1 -1
- package/dist/components/tabs/style2.css +3 -2
- package/dist/components/tabs/tabs-horizontal.js +2 -2
- package/dist/components/tabs/tabs-horizontal.js.map +1 -1
- package/dist/components/tabs/tabs-horizontal.vue.d.ts +14 -3
- package/dist/components/tabs/tabs-vertical.js +2 -2
- package/dist/components/tabs/tabs-vertical.js.map +1 -1
- package/dist/components/tabs/tabs-vertical.vue.d.ts +13 -3
- package/dist/components/tabs/tabs.vue.d.ts +2 -2
- package/dist/components/text/text.js.map +1 -1
- package/dist/components/textarea/textarea.js.map +1 -1
- package/dist/components/textarea/textarea.vue.d.ts +3 -3
- package/dist/components/theme/theme.js.map +1 -1
- package/dist/components/tip/tip.vue.d.ts +2 -2
- package/dist/components/tree/tree-node2.js.map +1 -1
- package/dist/components/tree/tree.vue.d.ts +2 -2
- package/dist/components/tree/use-tree-nodes.js.map +1 -1
- package/dist/components/tree-select/tree-select.vue.d.ts +4 -4
- package/dist/components/watermark/watermark.vue.d.ts +1 -1
- package/package.json +13 -12
- package/src/components/code-editor/code-editor.vue +2 -0
- package/src/components/file-viewer/file-viewer.vue +250 -24
- package/src/components/file-viewer/previewers/docx-previewer.vue +4 -3
- package/src/components/file-viewer/previewers/image-previewer.vue +4 -5
- package/src/components/file-viewer/previewers/pdf-previewer.vue +4 -3
- package/src/components/file-viewer/style.scss +503 -161
- package/src/components/progress/progress.vue +1 -1
- package/src/components/table/di.ts +51 -53
- package/src/components/table/table.vue +0 -1
- package/src/components/tabs/style.scss +7 -4
- package/src/components/tabs/tabs-horizontal.vue +10 -7
- package/src/components/tabs/tabs-vertical.vue +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-tree-nodes.js","names":["TreeNode"],"sources":["../../../src/components/tree/use-tree-nodes.ts"],"sourcesContent":["import { Forest } from '@cat-kit/core'\nimport { computed, shallowRef, triggerRef, watch, type ShallowRef, type ComputedRef } from 'vue'\n\nimport type { TreeProps } from '../../types'\nimport { TreeNode } from './tree-node'\n\ninterface Options {\n props: TreeProps\n}\n\ninterface UseTreeNodesReturned {\n nodes: ShallowRef<TreeNode[]>\n forest: ComputedRef<Forest<Record<string, unknown>, any>>\n getFlattedNodes: () => void\n nodeDict: ComputedRef<Map<string | number, TreeNode>>\n /** 强制刷新 `nodes` 的订阅者(供字段级别变化但列表引用不变时手动触发)。 */\n triggerNodes: () => void\n}\n\nexport function useTreeNodes(options: Options): UseTreeNodesReturned {\n const { props } = options\n\n // forest / nodeDict 保持为 shallowRef 而非 computed:\n // - computed 会因为任一 prop 变化(尤其是内联 disabledNode 函数)而整棵重建,\n // 丢失 expanded/checked/visible 等运行时状态;\n // - 显式 watch 仅在真正影响结构的输入变化时才重建,行为可控、可测量。\n const forestRef = shallowRef<Forest<Record<string, unknown>, any>>(\n new Forest<Record<string, unknown>, any>({\n data: [],\n childrenKey: props.childrenKey ?? 'children'\n })\n )\n\n const nodeDictRef = shallowRef<Map<string | number, TreeNode>>(new Map())\n\n const nodes = shallowRef<TreeNode[]>([])\n\n function buildForest(): Forest<Record<string, unknown>, any> {\n const { disabledNode, expandAll = false, valueKey, labelKey } = props\n const childrenKey = props.childrenKey ?? 'children'\n\n function createNode(\n data: Record<string, any>,\n index: number,\n depth: number,\n parent?: TreeNode\n ): TreeNode {\n const node = new TreeNode({\n data,\n index,\n depth,\n parent,\n valueKey: valueKey!,\n labelKey: labelKey!\n })\n node.expanded = expandAll\n return node\n }\n\n return new Forest<Record<string, unknown>, any>({\n data: (props.data ?? []) as Record<string, unknown>[],\n childrenKey,\n createNode: disabledNode\n ? (data, index, depth, _f, parent) => {\n const node = createNode(data as Record<string, any>, index, depth, parent as TreeNode)\n if (data) {\n node.disabled = disabledNode(data as Record<string, any>, node) ?? false\n }\n return node\n }\n : (data, index, depth, _f, parent) =>\n createNode(data as Record<string, any>, index, depth, parent as TreeNode)\n })\n }\n\n function rebuildForest(): void {\n const nextForest = buildForest()\n const nextDict = new Map<string | number, TreeNode>()\n\n // 构建森林的同时一次 DFS 同步填充字典,\n // 避免旧版 “forest computed → nodeDict computed” 两次完整遍历。\n nextForest.dfs((node) => {\n nextDict.set(node.key, node)\n })\n\n forestRef.value = nextForest\n nodeDictRef.value = nextDict\n\n getFlattedNodes()\n }\n\n /** 按展开与可见性扁平化:仅一次 DFS。 */\n function getFlattedNodes(): void {\n const result: TreeNode[] = []\n const roots = forestRef.value.roots as TreeNode[]\n\n const stack: TreeNode[] = []\n for (let i = roots.length - 1; i >= 0; i--) {\n stack.push(roots[i]!)\n }\n\n while (stack.length) {\n const node = stack.pop()!\n if (!node.visible) continue\n result.push(node)\n if (node.expanded && node.children && node.children.length) {\n for (let i = node.children.length - 1; i >= 0; i--) {\n stack.push(node.children[i]!)\n }\n }\n }\n\n nodes.value = result\n }\n\n function triggerNodes(): void {\n triggerRef(nodes)\n }\n\n watch(\n [\n () => props.data,\n () => props.disabledNode,\n () => props.childrenKey,\n () => props.valueKey,\n () => props.labelKey,\n () => props.expandAll\n ],\n () => {\n rebuildForest()\n },\n { immediate: true }\n )\n\n const forest = computed(() => forestRef.value)\n const nodeDict = computed(() => nodeDictRef.value)\n\n return { nodes, forest, getFlattedNodes, nodeDict, triggerNodes }\n}\n"],"mappings":";;;;AAmBA,SAAgB,aAAa,SAAwC;CACnE,MAAM,EAAE,UAAU;CAMlB,MAAM,YAAY,WAChB,IAAI,OAAqC;EACvC,MAAM,EAAE;EACR,aAAa,MAAM,eAAe;EACnC,CAAC,CACH;CAED,MAAM,cAAc,2BAA2C,IAAI,KAAK,CAAC;CAEzE,MAAM,QAAQ,WAAuB,EAAE,CAAC;CAExC,SAAS,cAAoD;EAC3D,MAAM,EAAE,cAAc,YAAY,OAAO,UAAU,aAAa;EAChE,MAAM,cAAc,MAAM,eAAe;EAEzC,SAAS,WACP,MACA,OACA,OACA,QACU;GACV,MAAM,OAAO,IAAIA,WAAS;IACxB;IACA;IACA;IACA;IACU;IACA;IACX,CAAC;AACF,QAAK,WAAW;AAChB,UAAO;;AAGT,SAAO,IAAI,OAAqC;GAC9C,MAAO,MAAM,QAAQ,EAAE;GACvB;GACA,YAAY,gBACP,MAAM,OAAO,OAAO,IAAI,WAAW;IAClC,MAAM,OAAO,WAAW,MAA6B,OAAO,OAAO,OAAmB;AACtF,QAAI,KACF,MAAK,WAAW,aAAa,MAA6B,KAAK,IAAI;AAErE,WAAO;QAER,MAAM,OAAO,OAAO,IAAI,WACvB,WAAW,MAA6B,OAAO,OAAO,OAAmB;GAChF,CAAC;;CAGJ,SAAS,gBAAsB;EAC7B,MAAM,aAAa,aAAa;EAChC,MAAM,2BAAW,IAAI,KAAgC;AAIrD,aAAW,KAAK,SAAS;AACvB,YAAS,IAAI,KAAK,KAAK,KAAK;IAC5B;AAEF,YAAU,QAAQ;AAClB,cAAY,QAAQ;AAEpB,mBAAiB;;;CAInB,SAAS,kBAAwB;EAC/B,MAAM,SAAqB,EAAE;EAC7B,MAAM,QAAQ,UAAU,MAAM;EAE9B,MAAM,QAAoB,EAAE;AAC5B,OAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,IACrC,OAAM,KAAK,MAAM,GAAI;AAGvB,SAAO,MAAM,QAAQ;GACnB,MAAM,OAAO,MAAM,KAAK;AACxB,OAAI,CAAC,KAAK,QAAS;AACnB,UAAO,KAAK,KAAK;AACjB,OAAI,KAAK,YAAY,KAAK,YAAY,KAAK,SAAS,OAClD,MAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,IAC7C,OAAM,KAAK,KAAK,SAAS,GAAI;;AAKnC,QAAM,QAAQ;;CAGhB,SAAS,eAAqB;AAC5B,aAAW,MAAM;;AAGnB,OACE;QACQ,MAAM;QACN,MAAM;QACN,MAAM;QACN,MAAM;QACN,MAAM;QACN,MAAM;EACb,QACK;AACJ,iBAAe;IAEjB,EAAE,WAAW,MAAM,CACpB;AAKD,QAAO;EAAE;EAAO,QAHD,eAAe,UAAU,
|
|
1
|
+
{"version":3,"file":"use-tree-nodes.js","names":["TreeNode"],"sources":["../../../src/components/tree/use-tree-nodes.ts"],"sourcesContent":["import { Forest } from '@cat-kit/core'\nimport { computed, shallowRef, triggerRef, watch, type ShallowRef, type ComputedRef } from 'vue'\n\nimport type { TreeProps } from '../../types'\nimport { TreeNode } from './tree-node'\n\ninterface Options {\n props: TreeProps\n}\n\ninterface UseTreeNodesReturned {\n nodes: ShallowRef<TreeNode[]>\n forest: ComputedRef<Forest<Record<string, unknown>, any>>\n getFlattedNodes: () => void\n nodeDict: ComputedRef<Map<string | number, TreeNode>>\n /** 强制刷新 `nodes` 的订阅者(供字段级别变化但列表引用不变时手动触发)。 */\n triggerNodes: () => void\n}\n\nexport function useTreeNodes(options: Options): UseTreeNodesReturned {\n const { props } = options\n\n // forest / nodeDict 保持为 shallowRef 而非 computed:\n // - computed 会因为任一 prop 变化(尤其是内联 disabledNode 函数)而整棵重建,\n // 丢失 expanded/checked/visible 等运行时状态;\n // - 显式 watch 仅在真正影响结构的输入变化时才重建,行为可控、可测量。\n const forestRef = shallowRef<Forest<Record<string, unknown>, any>>(\n new Forest<Record<string, unknown>, any>({\n data: [],\n childrenKey: props.childrenKey ?? 'children'\n })\n )\n\n const nodeDictRef = shallowRef<Map<string | number, TreeNode>>(new Map())\n\n const nodes = shallowRef<TreeNode[]>([])\n\n function buildForest(): Forest<Record<string, unknown>, any> {\n const { disabledNode, expandAll = false, valueKey, labelKey } = props\n const childrenKey = props.childrenKey ?? 'children'\n\n function createNode(\n data: Record<string, any>,\n index: number,\n depth: number,\n parent?: TreeNode\n ): TreeNode {\n const node = new TreeNode({\n data,\n index,\n depth,\n parent,\n valueKey: valueKey!,\n labelKey: labelKey!\n })\n node.expanded = expandAll\n return node\n }\n\n return new Forest<Record<string, unknown>, any>({\n data: (props.data ?? []) as Record<string, unknown>[],\n childrenKey,\n createNode: disabledNode\n ? (data, index, depth, _f, parent) => {\n const node = createNode(data as Record<string, any>, index, depth, parent as TreeNode)\n if (data) {\n node.disabled = disabledNode(data as Record<string, any>, node) ?? false\n }\n return node\n }\n : (data, index, depth, _f, parent) =>\n createNode(data as Record<string, any>, index, depth, parent as TreeNode)\n })\n }\n\n function rebuildForest(): void {\n const nextForest = buildForest()\n const nextDict = new Map<string | number, TreeNode>()\n\n // 构建森林的同时一次 DFS 同步填充字典,\n // 避免旧版 “forest computed → nodeDict computed” 两次完整遍历。\n nextForest.dfs((node) => {\n nextDict.set(node.key, node)\n })\n\n forestRef.value = nextForest\n nodeDictRef.value = nextDict\n\n getFlattedNodes()\n }\n\n /** 按展开与可见性扁平化:仅一次 DFS。 */\n function getFlattedNodes(): void {\n const result: TreeNode[] = []\n const roots = forestRef.value.roots as TreeNode[]\n\n const stack: TreeNode[] = []\n for (let i = roots.length - 1; i >= 0; i--) {\n stack.push(roots[i]!)\n }\n\n while (stack.length) {\n const node = stack.pop()!\n if (!node.visible) continue\n result.push(node)\n if (node.expanded && node.children && node.children.length) {\n for (let i = node.children.length - 1; i >= 0; i--) {\n stack.push(node.children[i]!)\n }\n }\n }\n\n nodes.value = result\n }\n\n function triggerNodes(): void {\n triggerRef(nodes)\n }\n\n watch(\n [\n () => props.data,\n () => props.disabledNode,\n () => props.childrenKey,\n () => props.valueKey,\n () => props.labelKey,\n () => props.expandAll\n ],\n () => {\n rebuildForest()\n },\n { immediate: true }\n )\n\n const forest = computed(() => forestRef.value)\n const nodeDict = computed(() => nodeDictRef.value)\n\n return { nodes, forest, getFlattedNodes, nodeDict, triggerNodes }\n}\n"],"mappings":";;;;AAmBA,SAAgB,aAAa,SAAwC;CACnE,MAAM,EAAE,UAAU;CAMlB,MAAM,YAAY,WAChB,IAAI,OAAqC;EACvC,MAAM,EAAE;EACR,aAAa,MAAM,eAAe;EACnC,CAAC,CACH;CAED,MAAM,cAAc,2BAA2C,IAAI,KAAK,CAAC;CAEzE,MAAM,QAAQ,WAAuB,EAAE,CAAC;CAExC,SAAS,cAAoD;EAC3D,MAAM,EAAE,cAAc,YAAY,OAAO,UAAU,aAAa;EAChE,MAAM,cAAc,MAAM,eAAe;EAEzC,SAAS,WACP,MACA,OACA,OACA,QACU;GACV,MAAM,OAAO,IAAIA,WAAS;IACxB;IACA;IACA;IACA;IACU;IACA;IACX,CAAC;AACF,QAAK,WAAW;AAChB,UAAO;;AAGT,SAAO,IAAI,OAAqC;GAC9C,MAAO,MAAM,QAAQ,EAAE;GACvB;GACA,YAAY,gBACP,MAAM,OAAO,OAAO,IAAI,WAAW;IAClC,MAAM,OAAO,WAAW,MAA6B,OAAO,OAAO,OAAmB;AACtF,QAAI,KACF,MAAK,WAAW,aAAa,MAA6B,KAAK,IAAI;AAErE,WAAO;QAER,MAAM,OAAO,OAAO,IAAI,WACvB,WAAW,MAA6B,OAAO,OAAO,OAAmB;GAChF,CAAC;;CAGJ,SAAS,gBAAsB;EAC7B,MAAM,aAAa,aAAa;EAChC,MAAM,2BAAW,IAAI,KAAgC;AAIrD,aAAW,KAAK,SAAS;AACvB,YAAS,IAAI,KAAK,KAAK,KAAK;IAC5B;AAEF,YAAU,QAAQ;AAClB,cAAY,QAAQ;AAEpB,mBAAiB;;;CAInB,SAAS,kBAAwB;EAC/B,MAAM,SAAqB,EAAE;EAC7B,MAAM,QAAQ,UAAU,MAAM;EAE9B,MAAM,QAAoB,EAAE;AAC5B,OAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,IACrC,OAAM,KAAK,MAAM,GAAI;AAGvB,SAAO,MAAM,QAAQ;GACnB,MAAM,OAAO,MAAM,KAAK;AACxB,OAAI,CAAC,KAAK,QAAS;AACnB,UAAO,KAAK,KAAK;AACjB,OAAI,KAAK,YAAY,KAAK,YAAY,KAAK,SAAS,OAClD,MAAK,IAAI,IAAI,KAAK,SAAS,SAAS,GAAG,KAAK,GAAG,IAC7C,OAAM,KAAK,KAAK,SAAS,GAAI;;AAKnC,QAAM,QAAQ;;CAGhB,SAAS,eAAqB;AAC5B,aAAW,MAAM;;AAGnB,OACE;QACQ,MAAM;QACN,MAAM;QACN,MAAM;QACN,MAAM;QACN,MAAM;QACN,MAAM;EACb,QACK;AACJ,iBAAe;IAEjB,EAAE,WAAW,MAAM,CACpB;AAKD,QAAO;EAAE;EAAO,QAHD,eAAe,UAAU,MAGlB;EAAE;EAAiB,UAFxB,eAAe,YAAY,MAEK;EAAE;EAAc"}
|
|
@@ -19,20 +19,20 @@ declare const __VLS_base: _$vue.DefineComponent<__VLS_PublicProps, {}, {}, {}, {
|
|
|
19
19
|
change: (value?: string | number | undefined, selectedData?: Record<string, any> | undefined) => any;
|
|
20
20
|
"update:text": (text?: string | undefined) => any;
|
|
21
21
|
}, string, _$vue.PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
22
|
-
"onUpdate:modelValue"?: ((value: string | number | undefined) => any) | undefined;
|
|
23
22
|
onClear?: (() => any) | undefined;
|
|
23
|
+
"onUpdate:modelValue"?: ((value: string | number | undefined) => any) | undefined;
|
|
24
24
|
onChange?: ((value?: string | number | undefined, selectedData?: Record<string, any> | undefined) => any) | undefined;
|
|
25
25
|
"onUpdate:text"?: ((text?: string | undefined) => any) | undefined;
|
|
26
26
|
}>, {
|
|
27
27
|
disabled: boolean;
|
|
28
|
+
placeholder: string;
|
|
29
|
+
clearable: boolean;
|
|
28
30
|
readonly: boolean;
|
|
29
31
|
labelKey: string;
|
|
30
32
|
valueKey: string;
|
|
31
|
-
|
|
32
|
-
clearable: boolean;
|
|
33
|
+
filterable: boolean;
|
|
33
34
|
minWidth: string;
|
|
34
35
|
expandAll: boolean;
|
|
35
|
-
filterable: boolean;
|
|
36
36
|
}, {}, {}, {}, string, _$vue.ComponentProvideOptions, false, {}, any>;
|
|
37
37
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
38
38
|
declare const _default: typeof __VLS_export;
|
|
@@ -7,8 +7,8 @@ type __VLS_Slots = {} & {
|
|
|
7
7
|
default?: (props: typeof __VLS_7) => any;
|
|
8
8
|
};
|
|
9
9
|
declare const __VLS_base: _$vue.DefineComponent<WatermarkProps, {}, {}, {}, {}, _$vue.ComponentOptionsMixin, _$vue.ComponentOptionsMixin, {}, string, _$vue.PublicProps, Readonly<WatermarkProps> & Readonly<{}>, {
|
|
10
|
-
route: number;
|
|
11
10
|
fontSize: number;
|
|
11
|
+
route: number;
|
|
12
12
|
}, {}, {}, {}, string, _$vue.ComponentProvideOptions, false, {}, any>;
|
|
13
13
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
14
14
|
declare const _default: typeof __VLS_export;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veltra/desktop",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist",
|
|
6
6
|
"src"
|
|
@@ -25,13 +25,14 @@
|
|
|
25
25
|
"check-types": "tsc -p tsconfig.json --noEmit"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@cat-kit/core": "^1.1.
|
|
28
|
+
"@cat-kit/core": "^1.1.3",
|
|
29
29
|
"@cat-kit/excel": "^1.0.1",
|
|
30
30
|
"@codemirror/lang-java": "^6.0.2",
|
|
31
31
|
"@codemirror/lang-javascript": "^6.2.5",
|
|
32
32
|
"@codemirror/lang-json": "^6.0.2",
|
|
33
33
|
"@codemirror/lang-sql": "^6.10.0",
|
|
34
34
|
"@codemirror/state": "^6.6.0",
|
|
35
|
+
"@codemirror/theme-one-dark": "^6.1.3",
|
|
35
36
|
"@codemirror/view": "^6.41.1",
|
|
36
37
|
"@embedpdf/core": "^2.14.1",
|
|
37
38
|
"@embedpdf/engines": "^2.14.1",
|
|
@@ -47,22 +48,22 @@
|
|
|
47
48
|
"@lexical/rich-text": "^0.43.0",
|
|
48
49
|
"@lexical/selection": "^0.43.0",
|
|
49
50
|
"@lexical/utils": "^0.43.0",
|
|
50
|
-
"@veltra/compositions": "1.0.
|
|
51
|
-
"@veltra/directives": "1.0.
|
|
52
|
-
"@veltra/icons": "1.0.
|
|
53
|
-
"@veltra/styles": "1.0.
|
|
54
|
-
"@veltra/utils": "1.0.
|
|
51
|
+
"@veltra/compositions": "1.0.11",
|
|
52
|
+
"@veltra/directives": "1.0.11",
|
|
53
|
+
"@veltra/icons": "1.0.11",
|
|
54
|
+
"@veltra/styles": "1.0.11",
|
|
55
|
+
"@veltra/utils": "1.0.11",
|
|
55
56
|
"@visactor/vtable": "^1.26.0",
|
|
56
57
|
"codemirror": "^6.0.2",
|
|
57
58
|
"docx-preview": "^0.3.7",
|
|
58
59
|
"lexical": "^0.43.0"
|
|
59
60
|
},
|
|
60
61
|
"peerDependencies": {
|
|
61
|
-
"@veltra/compositions": "1.0.
|
|
62
|
-
"@veltra/directives": "1.0.
|
|
63
|
-
"@veltra/icons": "1.0.
|
|
64
|
-
"@veltra/styles": "1.0.
|
|
65
|
-
"@veltra/utils": "1.0.
|
|
62
|
+
"@veltra/compositions": "1.0.11",
|
|
63
|
+
"@veltra/directives": "1.0.11",
|
|
64
|
+
"@veltra/icons": "1.0.11",
|
|
65
|
+
"@veltra/styles": "1.0.11",
|
|
66
|
+
"@veltra/utils": "1.0.11",
|
|
66
67
|
"vue": "^3.5.33"
|
|
67
68
|
}
|
|
68
69
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<script lang="ts" setup>
|
|
8
8
|
import { EditorState } from '@codemirror/state'
|
|
9
|
+
import { oneDark } from '@codemirror/theme-one-dark'
|
|
9
10
|
import { tooltips } from '@codemirror/view'
|
|
10
11
|
import { useFormComponent, useFormFallbackProps } from '@veltra/compositions'
|
|
11
12
|
import { bem, zIndex } from '@veltra/utils'
|
|
@@ -56,6 +57,7 @@ async function renderEditor() {
|
|
|
56
57
|
|
|
57
58
|
const extensions = [
|
|
58
59
|
basicSetup,
|
|
60
|
+
oneDark,
|
|
59
61
|
tooltips({
|
|
60
62
|
parent: document.body
|
|
61
63
|
}),
|
|
@@ -20,15 +20,14 @@
|
|
|
20
20
|
v-for="f in normalizedFiles"
|
|
21
21
|
:key="f.id"
|
|
22
22
|
:class="[cls.e('item'), bem.is('active', f.id === activeId)]"
|
|
23
|
+
:title="f.name"
|
|
23
24
|
@click="activate(f.id)"
|
|
24
25
|
>
|
|
25
|
-
<span :class="[cls.e('badge'), cls.em('badge', f.kind)]">
|
|
26
|
-
{{ label(f.kind) }}
|
|
27
|
-
</span>
|
|
28
26
|
<span :class="cls.e('item-meta')">
|
|
29
27
|
<span :class="cls.e('item-name')" :title="f.name">{{ f.name }}</span>
|
|
30
28
|
<span :class="cls.e('item-size')">{{ formatBytes(f.size) }}</span>
|
|
31
29
|
</span>
|
|
30
|
+
<span :class="cls.e('item-kind')">{{ label(f.kind) }}</span>
|
|
32
31
|
</li>
|
|
33
32
|
<li v-if="!normalizedFiles.length" :class="cls.e('list-empty')">
|
|
34
33
|
<u-empty text="暂无文件" :size="32" />
|
|
@@ -42,27 +41,93 @@
|
|
|
42
41
|
<span v-if="activeFile" :class="[cls.e('badge'), cls.em('badge', activeFile.kind)]">
|
|
43
42
|
{{ label(activeFile.kind) }}
|
|
44
43
|
</span>
|
|
45
|
-
<span :class="cls.e('stage-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
<span :class="cls.e('stage-copy')">
|
|
45
|
+
<span :class="cls.e('stage-name')" :title="activeFile?.name">
|
|
46
|
+
{{ activeFile?.name ?? '—' }}
|
|
47
|
+
</span>
|
|
48
|
+
<span v-if="activeFile" :class="cls.e('stage-sub')">
|
|
49
|
+
<span>{{ activeIndexLabel }}</span>
|
|
50
|
+
<span v-if="activeFile.size">{{ formatBytes(activeFile.size) }}</span>
|
|
51
|
+
</span>
|
|
50
52
|
</span>
|
|
51
53
|
</div>
|
|
52
54
|
<div :class="cls.e('stage-actions')">
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
<span :class="cls.e('action-group')">
|
|
56
|
+
<button
|
|
57
|
+
:class="[cls.e('action'), cls.em('action', 'icon')]"
|
|
58
|
+
:disabled="!hasPrev"
|
|
59
|
+
type="button"
|
|
60
|
+
aria-label="上一个"
|
|
61
|
+
title="上一个"
|
|
62
|
+
@click="prev"
|
|
63
|
+
>
|
|
64
|
+
<u-icon :size="15">
|
|
65
|
+
<ArrowLeft />
|
|
66
|
+
</u-icon>
|
|
67
|
+
</button>
|
|
68
|
+
<button
|
|
69
|
+
:class="[cls.e('action'), cls.em('action', 'icon')]"
|
|
70
|
+
:disabled="!hasNext"
|
|
71
|
+
type="button"
|
|
72
|
+
aria-label="下一个"
|
|
73
|
+
title="下一个"
|
|
74
|
+
@click="next"
|
|
75
|
+
>
|
|
76
|
+
<u-icon :size="15">
|
|
77
|
+
<ArrowRight />
|
|
78
|
+
</u-icon>
|
|
79
|
+
</button>
|
|
80
|
+
</span>
|
|
81
|
+
<span v-if="isTransformable" :class="cls.e('action-group')">
|
|
82
|
+
<button
|
|
83
|
+
:class="[cls.e('action'), cls.em('action', 'icon')]"
|
|
84
|
+
:disabled="zoomOutDisabled"
|
|
85
|
+
type="button"
|
|
86
|
+
aria-label="缩小"
|
|
87
|
+
title="缩小"
|
|
88
|
+
@click="zoomOut"
|
|
89
|
+
>
|
|
90
|
+
<u-icon :size="15">
|
|
91
|
+
<ZoomOut />
|
|
92
|
+
</u-icon>
|
|
93
|
+
</button>
|
|
94
|
+
<span :class="cls.e('zoom-value')">{{ zoomPercent }}</span>
|
|
95
|
+
<button
|
|
96
|
+
:class="[cls.e('action'), cls.em('action', 'icon')]"
|
|
97
|
+
:disabled="zoomInDisabled"
|
|
98
|
+
type="button"
|
|
99
|
+
aria-label="放大"
|
|
100
|
+
title="放大"
|
|
101
|
+
@click="zoomIn"
|
|
102
|
+
>
|
|
103
|
+
<u-icon :size="15">
|
|
104
|
+
<ZoomIn />
|
|
105
|
+
</u-icon>
|
|
106
|
+
</button>
|
|
107
|
+
<button
|
|
108
|
+
:class="[cls.e('action'), cls.em('action', 'icon')]"
|
|
109
|
+
:disabled="isTransformReset"
|
|
110
|
+
type="button"
|
|
111
|
+
aria-label="重置视图"
|
|
112
|
+
title="重置视图"
|
|
113
|
+
@click="resetTransform"
|
|
114
|
+
>
|
|
115
|
+
<u-icon :size="15">
|
|
116
|
+
<Refresh />
|
|
117
|
+
</u-icon>
|
|
118
|
+
</button>
|
|
119
|
+
</span>
|
|
59
120
|
<button
|
|
60
121
|
v-if="downloadable && activeFile"
|
|
61
|
-
:class="[cls.e('action'), cls.em('action', 'primary')]"
|
|
122
|
+
:class="[cls.e('action'), cls.em('action', 'primary'), cls.em('action', 'icon')]"
|
|
62
123
|
type="button"
|
|
124
|
+
aria-label="下载"
|
|
125
|
+
title="下载"
|
|
63
126
|
@click="download"
|
|
64
127
|
>
|
|
65
|
-
|
|
128
|
+
<u-icon :size="15">
|
|
129
|
+
<Download />
|
|
130
|
+
</u-icon>
|
|
66
131
|
</button>
|
|
67
132
|
<button
|
|
68
133
|
v-if="isModal"
|
|
@@ -80,14 +145,30 @@
|
|
|
80
145
|
</header>
|
|
81
146
|
<div :class="cls.e('body')">
|
|
82
147
|
<transition name="u-file-viewer-fade" mode="out-in">
|
|
83
|
-
<
|
|
84
|
-
:is="PreviewerMap[activeFile.kind]"
|
|
148
|
+
<div
|
|
85
149
|
v-if="activeFile"
|
|
86
150
|
:key="activeFile.id"
|
|
87
|
-
:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
151
|
+
:class="[
|
|
152
|
+
cls.e('viewport'),
|
|
153
|
+
bem.is('transformable', isTransformable),
|
|
154
|
+
bem.is('pannable', canPan),
|
|
155
|
+
bem.is('dragging', isDragging)
|
|
156
|
+
]"
|
|
157
|
+
@pointerdown="handleViewportPointerDown"
|
|
158
|
+
@pointermove="handleViewportPointerMove"
|
|
159
|
+
@pointerup="handleViewportPointerEnd"
|
|
160
|
+
@pointercancel="handleViewportPointerEnd"
|
|
161
|
+
@dblclick="handleViewportDblclick"
|
|
162
|
+
>
|
|
163
|
+
<component
|
|
164
|
+
:is="PreviewerMap[activeFile.kind]"
|
|
165
|
+
:file="activeFile"
|
|
166
|
+
:max-rows="sheetMaxRows"
|
|
167
|
+
:class="isTransformable ? cls.e('previewer') : undefined"
|
|
168
|
+
:style="previewerStyle"
|
|
169
|
+
@error="handleChildError"
|
|
170
|
+
/>
|
|
171
|
+
</div>
|
|
91
172
|
<div v-else :class="cls.e('empty')">
|
|
92
173
|
<u-empty text="暂无可预览文件" />
|
|
93
174
|
</div>
|
|
@@ -101,9 +182,26 @@
|
|
|
101
182
|
</template>
|
|
102
183
|
|
|
103
184
|
<script lang="ts" setup>
|
|
104
|
-
import {
|
|
185
|
+
import {
|
|
186
|
+
ArrowLeft,
|
|
187
|
+
ArrowRight,
|
|
188
|
+
Close,
|
|
189
|
+
Download,
|
|
190
|
+
Refresh,
|
|
191
|
+
ZoomIn,
|
|
192
|
+
ZoomOut
|
|
193
|
+
} from '@veltra/icons/normal'
|
|
105
194
|
import { bem, withUnit } from '@veltra/utils'
|
|
106
|
-
import {
|
|
195
|
+
import {
|
|
196
|
+
computed,
|
|
197
|
+
defineAsyncComponent,
|
|
198
|
+
nextTick,
|
|
199
|
+
onBeforeUnmount,
|
|
200
|
+
ref,
|
|
201
|
+
shallowRef,
|
|
202
|
+
watch
|
|
203
|
+
} from 'vue'
|
|
204
|
+
import type { CSSProperties } from 'vue'
|
|
107
205
|
|
|
108
206
|
import type {
|
|
109
207
|
_FileViewerExposed,
|
|
@@ -136,10 +234,29 @@ const emit = defineEmits<FileViewerEmits>()
|
|
|
136
234
|
|
|
137
235
|
const cls = bem('file-viewer')
|
|
138
236
|
|
|
237
|
+
const MIN_SCALE = 0.5
|
|
238
|
+
const MAX_SCALE = 3
|
|
239
|
+
const SCALE_STEP = 0.25
|
|
240
|
+
const TRANSFORMABLE_KINDS = new Set<FileViewerKind>(['image', 'pdf', 'docx'])
|
|
241
|
+
|
|
139
242
|
const activeId = defineModel<string | undefined>('modelValue', { default: undefined })
|
|
140
243
|
const openModel = defineModel<boolean | undefined>('open', { default: undefined })
|
|
141
244
|
|
|
142
245
|
const rootRef = shallowRef<HTMLDivElement>()
|
|
246
|
+
const scale = ref(1)
|
|
247
|
+
const offsetX = ref(0)
|
|
248
|
+
const offsetY = ref(0)
|
|
249
|
+
const isDragging = ref(false)
|
|
250
|
+
|
|
251
|
+
let dragState:
|
|
252
|
+
| {
|
|
253
|
+
pointerId: number
|
|
254
|
+
startX: number
|
|
255
|
+
startY: number
|
|
256
|
+
originX: number
|
|
257
|
+
originY: number
|
|
258
|
+
}
|
|
259
|
+
| undefined
|
|
143
260
|
|
|
144
261
|
const PreviewerMap: Record<FileViewerKind, ReturnType<typeof defineAsyncComponent>> = {
|
|
145
262
|
image: defineAsyncComponent(() => import('./previewers/image-previewer.vue')),
|
|
@@ -185,6 +302,33 @@ const sidebarWidthCss = computed(() => {
|
|
|
185
302
|
/** 是否启用模态模式:只要父组件显式传入 open(含 v-model:open),即进入模态 */
|
|
186
303
|
const isModal = computed(() => openModel.value !== undefined)
|
|
187
304
|
|
|
305
|
+
const activeIndexLabel = computed(() =>
|
|
306
|
+
activeIndex.value >= 0 ? `${activeIndex.value + 1} / ${normalizedFiles.value.length}` : ''
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
const isTransformable = computed(
|
|
310
|
+
() => !!activeFile.value && TRANSFORMABLE_KINDS.has(activeFile.value.kind)
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
const canPan = computed(() => isTransformable.value && scale.value > 1)
|
|
314
|
+
|
|
315
|
+
const zoomPercent = computed(() => `${Math.round(scale.value * 100)}%`)
|
|
316
|
+
|
|
317
|
+
const zoomInDisabled = computed(() => !isTransformable.value || scale.value >= MAX_SCALE)
|
|
318
|
+
|
|
319
|
+
const zoomOutDisabled = computed(() => !isTransformable.value || scale.value <= MIN_SCALE)
|
|
320
|
+
|
|
321
|
+
const isTransformReset = computed(
|
|
322
|
+
() => scale.value === 1 && offsetX.value === 0 && offsetY.value === 0
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
const previewerStyle = computed<CSSProperties | undefined>(() => {
|
|
326
|
+
if (!isTransformable.value) return undefined
|
|
327
|
+
return {
|
|
328
|
+
transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value})`
|
|
329
|
+
}
|
|
330
|
+
})
|
|
331
|
+
|
|
188
332
|
function label(kind: FileViewerKind): string {
|
|
189
333
|
return FILE_VIEWER_KIND_LABEL[kind]
|
|
190
334
|
}
|
|
@@ -210,6 +354,83 @@ function next() {
|
|
|
210
354
|
if (target) activate(target.id)
|
|
211
355
|
}
|
|
212
356
|
|
|
357
|
+
function normalizeScale(value: number): number {
|
|
358
|
+
const clamped = Math.min(MAX_SCALE, Math.max(MIN_SCALE, value))
|
|
359
|
+
return Math.round(clamped * 100) / 100
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function setScale(value: number) {
|
|
363
|
+
scale.value = normalizeScale(value)
|
|
364
|
+
if (scale.value <= 1) {
|
|
365
|
+
offsetX.value = 0
|
|
366
|
+
offsetY.value = 0
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function zoomIn() {
|
|
371
|
+
if (!isTransformable.value) return
|
|
372
|
+
setScale(scale.value + SCALE_STEP)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function zoomOut() {
|
|
376
|
+
if (!isTransformable.value) return
|
|
377
|
+
setScale(scale.value - SCALE_STEP)
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function resetTransform() {
|
|
381
|
+
scale.value = 1
|
|
382
|
+
offsetX.value = 0
|
|
383
|
+
offsetY.value = 0
|
|
384
|
+
dragState = undefined
|
|
385
|
+
isDragging.value = false
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function isInteractiveTarget(target: EventTarget | null): boolean {
|
|
389
|
+
if (!(target instanceof HTMLElement)) return false
|
|
390
|
+
return !!target.closest('button, a, input, textarea, select, video, [contenteditable="true"]')
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function handleViewportPointerDown(e: PointerEvent) {
|
|
394
|
+
if (!canPan.value || e.button !== 0 || isInteractiveTarget(e.target)) return
|
|
395
|
+
|
|
396
|
+
dragState = {
|
|
397
|
+
pointerId: e.pointerId,
|
|
398
|
+
startX: e.clientX,
|
|
399
|
+
startY: e.clientY,
|
|
400
|
+
originX: offsetX.value,
|
|
401
|
+
originY: offsetY.value
|
|
402
|
+
}
|
|
403
|
+
isDragging.value = true
|
|
404
|
+
const el = e.currentTarget as HTMLElement
|
|
405
|
+
el.setPointerCapture(e.pointerId)
|
|
406
|
+
e.preventDefault()
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function handleViewportPointerMove(e: PointerEvent) {
|
|
410
|
+
if (!dragState || dragState.pointerId !== e.pointerId) return
|
|
411
|
+
offsetX.value = dragState.originX + e.clientX - dragState.startX
|
|
412
|
+
offsetY.value = dragState.originY + e.clientY - dragState.startY
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function handleViewportPointerEnd(e: PointerEvent) {
|
|
416
|
+
if (!dragState || dragState.pointerId !== e.pointerId) return
|
|
417
|
+
const el = e.currentTarget as HTMLElement
|
|
418
|
+
if (el.hasPointerCapture(e.pointerId)) {
|
|
419
|
+
el.releasePointerCapture(e.pointerId)
|
|
420
|
+
}
|
|
421
|
+
dragState = undefined
|
|
422
|
+
isDragging.value = false
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function handleViewportDblclick() {
|
|
426
|
+
if (!isTransformable.value) return
|
|
427
|
+
if (scale.value === 1) {
|
|
428
|
+
setScale(2)
|
|
429
|
+
} else {
|
|
430
|
+
resetTransform()
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
213
434
|
async function download() {
|
|
214
435
|
if (!activeFile.value) return
|
|
215
436
|
try {
|
|
@@ -257,6 +478,11 @@ watch(
|
|
|
257
478
|
{ immediate: true }
|
|
258
479
|
)
|
|
259
480
|
|
|
481
|
+
watch(
|
|
482
|
+
() => activeFile.value?.id,
|
|
483
|
+
() => resetTransform()
|
|
484
|
+
)
|
|
485
|
+
|
|
260
486
|
// 模态打开时:锁定 body 滚动 + 让容器获得焦点以便接收 ESC
|
|
261
487
|
let previousBodyOverflow = ''
|
|
262
488
|
let isBodyLocked = false
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<u-scroll tag="div" :class="cls.e('docx')">
|
|
2
|
+
<u-scroll tag="div" :class="cls.e('docx')" v-bind="attrs">
|
|
3
3
|
<div ref="container" :class="cls.e('docx-body')" />
|
|
4
4
|
<div v-if="loading" :class="cls.e('loading')">加载中…</div>
|
|
5
5
|
</u-scroll>
|
|
@@ -7,18 +7,19 @@
|
|
|
7
7
|
|
|
8
8
|
<script lang="ts" setup>
|
|
9
9
|
import { bem } from '@veltra/utils'
|
|
10
|
-
import { onBeforeUnmount, ref, useTemplateRef, watch } from 'vue'
|
|
10
|
+
import { onBeforeUnmount, ref, useAttrs, useTemplateRef, watch } from 'vue'
|
|
11
11
|
|
|
12
12
|
import type { FileViewerItem } from '../../../types/file-viewer'
|
|
13
13
|
import { UScroll } from '../../scroll'
|
|
14
14
|
|
|
15
|
-
defineOptions({ name: 'FileViewerDocxPreviewer' })
|
|
15
|
+
defineOptions({ name: 'FileViewerDocxPreviewer', inheritAttrs: false })
|
|
16
16
|
|
|
17
17
|
const props = defineProps<{ file: FileViewerItem }>()
|
|
18
18
|
|
|
19
19
|
const emit = defineEmits<{ (e: 'error', err: unknown): void }>()
|
|
20
20
|
|
|
21
21
|
const cls = bem('file-viewer')
|
|
22
|
+
const attrs = useAttrs()
|
|
22
23
|
|
|
23
24
|
const container = useTemplateRef<HTMLDivElement>('container')
|
|
24
25
|
const loading = ref(true)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="
|
|
2
|
+
<div :class="cls.e('image')" v-bind="attrs">
|
|
3
3
|
<img
|
|
4
4
|
v-if="url"
|
|
5
5
|
:src="url"
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
draggable="false"
|
|
8
8
|
@load="loading = false"
|
|
9
9
|
@error="onImgError"
|
|
10
|
-
@dblclick="actual = !actual"
|
|
11
10
|
/>
|
|
12
11
|
<div v-if="loading" :class="cls.e('loading')">加载中…</div>
|
|
13
12
|
<div v-if="failed" :class="cls.e('loading')">图片加载失败</div>
|
|
@@ -16,22 +15,22 @@
|
|
|
16
15
|
|
|
17
16
|
<script lang="ts" setup>
|
|
18
17
|
import { bem } from '@veltra/utils'
|
|
19
|
-
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
|
|
18
|
+
import { onBeforeUnmount, ref, shallowRef, useAttrs, watch } from 'vue'
|
|
20
19
|
|
|
21
20
|
import type { FileViewerItem } from '../../../types/file-viewer'
|
|
22
21
|
|
|
23
|
-
defineOptions({ name: 'FileViewerImagePreviewer' })
|
|
22
|
+
defineOptions({ name: 'FileViewerImagePreviewer', inheritAttrs: false })
|
|
24
23
|
|
|
25
24
|
const props = defineProps<{ file: FileViewerItem }>()
|
|
26
25
|
|
|
27
26
|
const emit = defineEmits<{ (e: 'error', err: unknown): void }>()
|
|
28
27
|
|
|
29
28
|
const cls = bem('file-viewer')
|
|
29
|
+
const attrs = useAttrs()
|
|
30
30
|
|
|
31
31
|
const url = shallowRef<string>('')
|
|
32
32
|
const loading = ref(true)
|
|
33
33
|
const failed = ref(false)
|
|
34
|
-
const actual = ref(false)
|
|
35
34
|
|
|
36
35
|
let revoke: (() => void) | undefined
|
|
37
36
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="cls.e('pdf')">
|
|
2
|
+
<div :class="cls.e('pdf')" v-bind="attrs">
|
|
3
3
|
<div v-if="!engine || isLoading" :class="cls.e('loading')">正在加载 PDF 引擎…</div>
|
|
4
4
|
<EmbedPDF v-else-if="pdfUrl" :engine="engine" :plugins="plugins" v-slot="{ activeDocumentId }">
|
|
5
5
|
<DocumentContent
|
|
@@ -36,17 +36,18 @@ import { RenderLayer, RenderPluginPackage } from '@embedpdf/plugin-render/vue'
|
|
|
36
36
|
import { ScrollPluginPackage, Scroller } from '@embedpdf/plugin-scroll/vue'
|
|
37
37
|
import { ViewportPluginPackage, Viewport } from '@embedpdf/plugin-viewport/vue'
|
|
38
38
|
import { bem } from '@veltra/utils'
|
|
39
|
-
import { computed, onBeforeUnmount, shallowRef, watch } from 'vue'
|
|
39
|
+
import { computed, onBeforeUnmount, shallowRef, useAttrs, watch } from 'vue'
|
|
40
40
|
|
|
41
41
|
import type { FileViewerItem } from '../../../types/file-viewer'
|
|
42
42
|
|
|
43
|
-
defineOptions({ name: 'FileViewerPdfPreviewer' })
|
|
43
|
+
defineOptions({ name: 'FileViewerPdfPreviewer', inheritAttrs: false })
|
|
44
44
|
|
|
45
45
|
const props = defineProps<{ file: FileViewerItem }>()
|
|
46
46
|
|
|
47
47
|
const emit = defineEmits<{ (e: 'error', err: unknown): void }>()
|
|
48
48
|
|
|
49
49
|
const cls = bem('file-viewer')
|
|
50
|
+
const attrs = useAttrs()
|
|
50
51
|
|
|
51
52
|
const { engine, isLoading, error } = usePdfiumEngine()
|
|
52
53
|
|