Lee 3 тижнів тому
батько
коміт
4f5818e618

+ 0 - 6
components.d.ts

@@ -9,12 +9,6 @@ export {}
 declare module 'vue' {
   export interface GlobalComponents {
     CodeViewer: typeof import('./src/components/view_file/vendors/text/CodeViewer.vue')['default']
-    ElButton: typeof import('element-plus/es')['ElButton']
-    ElIcon: typeof import('element-plus/es')['ElIcon']
-    ElImage: typeof import('element-plus/es')['ElImage']
-    ElOption: typeof import('element-plus/es')['ElOption']
-    ElSelect: typeof import('element-plus/es')['ElSelect']
-    ElUpload: typeof import('element-plus/es')['ElUpload']
     ImageViewer: typeof import('./src/components/view_file/vendors/image/ImageViewer.vue')['default']
     Other: typeof import('./src/components/view_file/vendors/other/index.vue')['default']
     PdfView: typeof import('./src/components/view_file/vendors/pdf/PdfView.vue')['default']

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
dist-lib/huijia-viewfile.css


Різницю між файлами не показано, бо вона завелика
+ 10 - 0
dist-lib/index.cjs


+ 50 - 0
dist-lib/index.d.ts

@@ -0,0 +1,50 @@
+import type { DefineComponent, Plugin } from "vue"
+
+export type ViewFileType =
+  | "docx"
+  | "xlsx"
+  | "pdf"
+  | "pptx"
+  | "gif"
+  | "jpg"
+  | "jpeg"
+  | "bmp"
+  | "tiff"
+  | "tif"
+  | "png"
+  | "svg"
+  | "txt"
+  | "json"
+  | "js"
+  | "css"
+  | "java"
+  | "py"
+  | "html"
+  | "jsx"
+  | "ts"
+  | "tsx"
+  | "xml"
+  | "md"
+  | "log"
+  | string
+
+export interface ViewFileInput {
+  filename?: string
+  type?: ViewFileType
+  fileBuffer?: ArrayBuffer | null
+  size?: number
+  name?: string
+}
+
+export const ViewFile: DefineComponent<{
+  file?: ViewFileInput
+}>
+
+export function getExtend(name: string): string
+export function readBuffer(file: File): Promise<ArrayBuffer>
+export function readDataURL(buffer: ArrayBuffer): Promise<string>
+export function readText(buffer: ArrayBuffer): Promise<string>
+export function render(buffer: ArrayBuffer, type: string, target: HTMLElement): Promise<any>
+
+declare const plugin: Plugin
+export default plugin

Різницю між файлами не показано, бо вона завелика
+ 20899 - 0
dist-lib/index.js


+ 30 - 8
package.json

@@ -1,35 +1,57 @@
 {
-    "name": "wisdomcity-office",
-    "private": true,
-    "version": "0.0.0",
+    "name": "huijia-viewfile",
+    "private": false,
+    "version": "0.1.2",
     "type": "module",
     "scripts": {
         "dev": "vite",
         "build": "vue-tsc -b && vite build",
+        "build:lib": "vite build --mode lib && node --input-type=module -e \"import { copyFileSync } from 'node:fs'; copyFileSync('src/components/view_file/lib.d.ts','dist-lib/index.d.ts');\"",
+        "prepublishOnly": "npm run build:lib",
         "preview": "vite preview"
     },
+    "main": "./dist-lib/index.cjs",
+    "module": "./dist-lib/index.js",
+    "types": "./dist-lib/index.d.ts",
+    "exports": {
+        ".": {
+            "types": "./dist-lib/index.d.ts",
+            "import": "./dist-lib/index.js",
+            "require": "./dist-lib/index.cjs"
+        },
+        "./style.css": "./dist-lib/huijia-viewfile.css"
+    },
+    "files": [
+        "dist-lib"
+    ],
+    "publishConfig": {
+        "access": "public"
+    },
+    "peerDependencies": {
+        "vue": "^3.5.0"
+    },
     "dependencies": {
         "docx-preview": "0.3.5",
-        "element-plus": "^2.9.8",
         "exceljs": "4.4.0",
         "html2canvas": "1.4.1",
         "lodash-es": "^4.17.21",
         "pdfjs-dist": "^5.1.91",
-        "tinycolor2": "1.6.0",
-        "vue": "^3.5.13",
-        "vue-router": "4",
         "pptxtojson": "^1.5.0",
-        "wisdom-pptxtojson": "^1.0.0",
+        "tinycolor2": "1.6.0",
+        "huijia-pptxtojson": "^1.0.0",
         "x-data-spreadsheet": "^1.1.9"
     },
     "devDependencies": {
         "@vitejs/plugin-vue": "^5.2.2",
         "@vue/tsconfig": "^0.7.0",
+        "element-plus": "^2.9.8",
         "less": "^4.3.0",
         "typescript": "~5.7.2",
         "unplugin-auto-import": "^19.1.2",
         "unplugin-vue-components": "^28.5.0",
         "vite": "^6.3.1",
+        "vue": "^3.5.13",
+        "vue-router": "4",
         "vue-tsc": "^2.2.8"
     }
 }

+ 12 - 12
pnpm-lock.yaml

@@ -20,6 +20,9 @@ importers:
       html2canvas:
         specifier: 1.4.1
         version: 1.4.1
+      huijia-pptxtojson:
+        specifier: ^1.0.0
+        version: 1.0.0
       lodash-es:
         specifier: ^4.17.21
         version: 4.17.21
@@ -38,9 +41,6 @@ importers:
       vue-router:
         specifier: '4'
         version: 4.5.0(vue@3.5.13(typescript@5.7.3))
-      wisdom-pptxtojson:
-        specifier: ^1.0.0
-        version: 1.0.0
       x-data-spreadsheet:
         specifier: ^1.1.9
         version: 1.1.9
@@ -821,6 +821,9 @@ packages:
     resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
     engines: {node: '>=8.0.0'}
 
+  huijia-pptxtojson@1.0.0:
+    resolution: {integrity: sha512-j4F0ueGJNLCY2wieGYBI0cHBu8ulfkDNkJLXLCDmFYX0qhW3HKF9DeVVBBstMo0mONfS8lJpdIAeNjlXAv4tdw==}
+
   iconv-lite@0.4.24:
     resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
     engines: {node: '>=0.10.0'}
@@ -1401,9 +1404,6 @@ packages:
   webpack-virtual-modules@0.6.2:
     resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
 
-  wisdom-pptxtojson@1.0.0:
-    resolution: {integrity: sha512-fKtOHCaLASVBTe6Qu8oCjD1cvUjkB+wO/VryRo37xNMa2Ym9Afi7uS/ukbkUEFrNYxRHrSfg/PqUp/XUpLXjGg==}
-
   wrappy@1.0.2:
     resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
 
@@ -2128,6 +2128,12 @@ snapshots:
       css-line-break: 2.1.0
       text-segmentation: 1.0.3
 
+  huijia-pptxtojson@1.0.0:
+    dependencies:
+      jszip: 3.10.1
+      tinycolor2: 1.6.0
+      txml: 5.1.1
+
   iconv-lite@0.4.24:
     dependencies:
       safer-buffer: 2.1.2
@@ -2702,12 +2708,6 @@ snapshots:
 
   webpack-virtual-modules@0.6.2: {}
 
-  wisdom-pptxtojson@1.0.0:
-    dependencies:
-      jszip: 3.10.1
-      tinycolor2: 1.6.0
-      txml: 5.1.1
-
   wrappy@1.0.2: {}
 
   x-data-spreadsheet@1.1.9:

+ 190 - 5
src/components/view_file/index.vue

@@ -14,7 +14,45 @@
                   </svg>
                 </div>
               </div>
-              <div class="output" v-show="!renderLoading" ref="output"></div>
+              <div v-if="isImageType" class="viewfile-image" v-show="!renderLoading">
+                <slot
+                  name="image"
+                  :src="imageUrl"
+                  :src-list="imageSrcList"
+                  :index="previewIndex"
+                  :file="file"
+                  :preview="previewApi"
+                >
+                  <img
+                    class="viewfile-image-inner"
+                    :src="imageUrl"
+                    :alt="file.filename || ''"
+                    @click="openImagePreview(0)"
+                  />
+                </slot>
+
+                <div v-if="previewVisible" class="viewfile-image-preview" @click.self="closeImagePreview">
+                  <button class="viewfile-image-preview-close" type="button" @click="closeImagePreview">×</button>
+                  <button
+                    v-if="imageSrcList.length > 1"
+                    class="viewfile-image-preview-prev"
+                    type="button"
+                    @click.stop="prevImage"
+                  >
+                    ‹
+                  </button>
+                  <img class="viewfile-image-preview-img" :src="imageSrcList[previewIndex]" alt="" />
+                  <button
+                    v-if="imageSrcList.length > 1"
+                    class="viewfile-image-preview-next"
+                    type="button"
+                    @click.stop="nextImage"
+                  >
+                    ›
+                  </button>
+                </div>
+              </div>
+              <div v-else class="output" v-show="!renderLoading" ref="output"></div>
             </div>
           </div>
           <view-other-component
@@ -28,10 +66,9 @@
 </template>
 
 <script setup>
-import { ref, computed, watch, nextTick } from "vue"
-import commJs from "@/comm_js"
-import { render } from "@/components/view_file/util"
-import ViewOtherComponent from "@/components/view_file/vendors/other/index.vue"
+import { ref, computed, watch, nextTick, onBeforeUnmount, onMounted } from "vue"
+import { readDataURL, render } from "./util"
+import ViewOtherComponent from "./vendors/other/index.vue"
 
 
 const props = defineProps({
@@ -45,6 +82,9 @@ const props = defineProps({
 
 const renderLoading = ref(false)
 const output = ref(null)
+const imageUrl = ref("")
+const previewVisible = ref(false)
+const previewIndex = ref(0)
 
 // 可在在线预览文件类型
 const isAbleView = computed(() => {
@@ -75,6 +115,63 @@ const isAbleView = computed(() => {
   return ablePreviewTypes.includes(lowType)
 })
 
+const isImageType = computed(() => {
+  const lowType = (props.file.type || "").toLowerCase()
+  return ["gif", "jpg", "jpeg", "bmp", "tiff", "tif", "png", "svg"].includes(lowType)
+})
+
+const imageSrcList = computed(() => {
+  const src = String(imageUrl.value || "")
+  return src ? [src] : []
+})
+
+const previewApi = computed(() => {
+  return {
+    visible: previewVisible.value,
+    open: openImagePreview,
+    close: closeImagePreview,
+    next: nextImage,
+    prev: prevImage,
+  }
+})
+
+function openImagePreview(index = 0) {
+  if (!imageSrcList.value.length) return
+  previewIndex.value = Math.max(0, Math.min(imageSrcList.value.length - 1, Number(index) || 0))
+  previewVisible.value = true
+}
+
+function closeImagePreview() {
+  previewVisible.value = false
+}
+
+function nextImage() {
+  const list = imageSrcList.value
+  if (list.length <= 1) return
+  previewIndex.value = (previewIndex.value + 1) % list.length
+}
+
+function prevImage() {
+  const list = imageSrcList.value
+  if (list.length <= 1) return
+  previewIndex.value = (previewIndex.value - 1 + list.length) % list.length
+}
+
+function onKeydown(e) {
+  if (!previewVisible.value) return
+  if (e.key === "Escape") closeImagePreview()
+  if (e.key === "ArrowRight") nextImage()
+  if (e.key === "ArrowLeft") prevImage()
+}
+
+onMounted(() => {
+  window.addEventListener("keydown", onKeydown)
+})
+
+onBeforeUnmount(() => {
+  window.removeEventListener("keydown", onKeydown)
+})
+
 /**
  * @{params} buffer 文件字节流
  * @{params} extend 文件扩展名
@@ -98,6 +195,24 @@ watch(
       try {
         renderLoading.value = true
         nextTick(() => {
+          if (isImageType.value) {
+            imageUrl.value = ""
+            previewVisible.value = false
+            previewIndex.value = 0
+            if (output.value) output.value.innerHTML = ""
+            readDataURL(newFile.fileBuffer)
+              .then((url) => {
+                imageUrl.value = String(url || "")
+              })
+              .finally(() => {
+                renderLoading.value = false
+              })
+            return
+          }
+
+          imageUrl.value = ""
+          previewVisible.value = false
+          previewIndex.value = 0
           renderResult(newFile.fileBuffer, newFile.type).finally(() => {
             renderLoading.value = false
           })
@@ -124,6 +239,76 @@ watch(
     }
   }
 }
+
+.viewfile-image {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.viewfile-image-inner {
+  max-width: 100%;
+  max-height: 100%;
+  display: block;
+  object-fit: contain;
+}
+
+.viewfile-image-preview {
+  position: fixed;
+  inset: 0;
+  background: rgba(0, 0, 0, 0.72);
+  z-index: 9999;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.viewfile-image-preview-img {
+  max-width: calc(100vw - 120px);
+  max-height: calc(100vh - 120px);
+  object-fit: contain;
+  display: block;
+}
+
+.viewfile-image-preview-close,
+.viewfile-image-preview-prev,
+.viewfile-image-preview-next {
+  position: absolute;
+  border: 0;
+  background: rgba(0, 0, 0, 0.36);
+  color: #fff;
+  cursor: pointer;
+  line-height: 1;
+}
+
+.viewfile-image-preview-close {
+  right: 16px;
+  top: 16px;
+  width: 40px;
+  height: 40px;
+  border-radius: 20px;
+  font-size: 28px;
+}
+
+.viewfile-image-preview-prev,
+.viewfile-image-preview-next {
+  top: 50%;
+  transform: translateY(-50%);
+  width: 44px;
+  height: 44px;
+  border-radius: 22px;
+  font-size: 28px;
+}
+
+.viewfile-image-preview-prev {
+  left: 16px;
+}
+
+.viewfile-image-preview-next {
+  right: 16px;
+}
 </style>
 <style lang="less" scoped>
 @import url("./index.less");

+ 50 - 0
src/components/view_file/lib.d.ts

@@ -0,0 +1,50 @@
+import type { DefineComponent, Plugin } from "vue"
+
+export type ViewFileType =
+  | "docx"
+  | "xlsx"
+  | "pdf"
+  | "pptx"
+  | "gif"
+  | "jpg"
+  | "jpeg"
+  | "bmp"
+  | "tiff"
+  | "tif"
+  | "png"
+  | "svg"
+  | "txt"
+  | "json"
+  | "js"
+  | "css"
+  | "java"
+  | "py"
+  | "html"
+  | "jsx"
+  | "ts"
+  | "tsx"
+  | "xml"
+  | "md"
+  | "log"
+  | string
+
+export interface ViewFileInput {
+  filename?: string
+  type?: ViewFileType
+  fileBuffer?: ArrayBuffer | null
+  size?: number
+  name?: string
+}
+
+export const ViewFile: DefineComponent<{
+  file?: ViewFileInput
+}>
+
+export function getExtend(name: string): string
+export function readBuffer(file: File): Promise<ArrayBuffer>
+export function readDataURL(buffer: ArrayBuffer): Promise<string>
+export function readText(buffer: ArrayBuffer): Promise<string>
+export function render(buffer: ArrayBuffer, type: string, target: HTMLElement): Promise<any>
+
+declare const plugin: Plugin
+export default plugin

+ 10 - 0
src/components/view_file/lib.js

@@ -0,0 +1,10 @@
+import ViewFile from "./index.vue"
+import { getExtend, readBuffer, readDataURL, readText, render } from "./util"
+
+export { ViewFile, getExtend, readBuffer, readDataURL, readText, render }
+
+export default {
+  install(app) {
+    app.component("ViewFile", ViewFile)
+  },
+}

+ 128 - 12
src/components/view_file/vendors/image/ImageViewer.vue

@@ -2,30 +2,91 @@
  * @Author: LiZhiWei
  * @Date: 2025-04-24 15:29:17
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2025-04-24 16:24:34
+ * @LastEditTime: 2025-12-30 12:45:42
  * @Description: 
 -->
 <template>
   <div>
-    <!-- <img v-for="item in images" alt="图片" :src="item.src" :key="item.index" class="image" /> -->
-    <el-image
-      :src="images[0]"
-      :preview-src-list="images"
-      width="100%"
-      height="100%"
-      :preview="true"
-    />
+    <slot
+      name="image"
+      :src="srcList[0]"
+      :src-list="srcList"
+      :index="index"
+      :preview="previewApi"
+    >
+      <img v-if="srcList[0]" class="image" :src="srcList[0]" alt="" @click="open(0)" />
+    </slot>
+
+    <div v-if="visible" class="viewfile-image-preview" @click.self="close">
+      <button class="viewfile-image-preview-close" type="button" @click="close">×</button>
+      <button v-if="srcList.length > 1" class="viewfile-image-preview-prev" type="button" @click.stop="prev">‹</button>
+      <img class="viewfile-image-preview-img" :src="srcList[index]" alt="" />
+      <button v-if="srcList.length > 1" class="viewfile-image-preview-next" type="button" @click.stop="next">›</button>
+    </div>
   </div>
 </template>
 
 <script setup>
-import { computed } from "vue"
+import { computed, onBeforeUnmount, onMounted, ref } from "vue"
+
 const props = defineProps({
   image: String,
+  srcList: Array,
+})
+
+const visible = ref(false)
+const index = ref(0)
+
+const srcList = computed(() => {
+  const list = Array.isArray(props.srcList) ? props.srcList : []
+  if (list.length) return list.map((v) => String(v || "")).filter(Boolean)
+  const src = String(props.image || "")
+  return src ? [src] : []
+})
+
+const previewApi = computed(() => {
+  return {
+    visible: visible.value,
+    open,
+    close,
+    next,
+    prev,
+  }
+})
+
+function open(i = 0) {
+  if (!srcList.value.length) return
+  index.value = Math.max(0, Math.min(srcList.value.length - 1, Number(i) || 0))
+  visible.value = true
+}
+
+function close() {
+  visible.value = false
+}
+
+function next() {
+  if (srcList.value.length <= 1) return
+  index.value = (index.value + 1) % srcList.value.length
+}
+
+function prev() {
+  if (srcList.value.length <= 1) return
+  index.value = (index.value - 1 + srcList.value.length) % srcList.value.length
+}
+
+function onKeydown(e) {
+  if (!visible.value) return
+  if (e.key === "Escape") close()
+  if (e.key === "ArrowRight") next()
+  if (e.key === "ArrowLeft") prev()
+}
+
+onMounted(() => {
+  window.addEventListener("keydown", onKeydown)
 })
 
-const images = computed(() => {
-  return props.image ? [props.image] : []
+onBeforeUnmount(() => {
+  window.removeEventListener("keydown", onKeydown)
 })
 </script>
 
@@ -36,4 +97,59 @@ const images = computed(() => {
   height: 100%;
   margin: 0 auto;
 }
+
+.viewfile-image-preview {
+  position: fixed;
+  inset: 0;
+  background: rgba(0, 0, 0, 0.72);
+  z-index: 9999;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.viewfile-image-preview-img {
+  max-width: calc(100vw - 120px);
+  max-height: calc(100vh - 120px);
+  object-fit: contain;
+  display: block;
+}
+
+.viewfile-image-preview-close,
+.viewfile-image-preview-prev,
+.viewfile-image-preview-next {
+  position: absolute;
+  border: 0;
+  background: rgba(0, 0, 0, 0.36);
+  color: #fff;
+  cursor: pointer;
+  line-height: 1;
+}
+
+.viewfile-image-preview-close {
+  right: 16px;
+  top: 16px;
+  width: 40px;
+  height: 40px;
+  border-radius: 20px;
+  font-size: 28px;
+}
+
+.viewfile-image-preview-prev,
+.viewfile-image-preview-next {
+  top: 50%;
+  transform: translateY(-50%);
+  width: 44px;
+  height: 44px;
+  border-radius: 22px;
+  font-size: 28px;
+}
+
+.viewfile-image-preview-prev {
+  left: 16px;
+}
+
+.viewfile-image-preview-next {
+  right: 16px;
+}
 </style>

+ 16 - 7
src/components/view_file/vendors/other/index.vue

@@ -1,10 +1,6 @@
 <template>
   <div class="view-other">
-    <el-image :src="viewOffImage" class="view-off-icon">
-      <div slot="error" class="image-slot">
-        <i class="el-icon-picture-outline"></i>
-      </div>
-    </el-image>
+    <img class="view-off-icon" :src="viewOffImage" alt="" />
     <p>
       {{ file.name }}.{{ file.type
       }}<span class="size-item">{{ getFileSize }}</span>
@@ -17,7 +13,6 @@
 
 <script setup>
 import { computed } from 'vue'
-import commJs from "@/comm_js/index"
 import viewOffImage from "../../assets/view_off.svg"
 
 const props = defineProps({
@@ -30,7 +25,15 @@ const props = defineProps({
 })
 
 const getFileSize = computed(() => {
-  return commJs.fileSizeFormat(props.file.size, "KB")
+  const size = Number(props.file.size)
+  if (!Number.isFinite(size) || !size) return "0KB"
+  const kbToMb = 1024
+  const kbToGb = 1048576
+  const abs = Math.abs(size)
+  const sign = size < 0 ? "-" : ""
+  if (abs >= kbToGb) return `${sign}${Math.floor((abs / kbToGb) * 100) / 100} GB`
+  if (abs >= kbToMb) return `${sign}${Math.floor((abs / kbToMb) * 100) / 100} MB`
+  return `${sign}${abs} KB`
 })
 </script>
 
@@ -44,5 +47,11 @@ const getFileSize = computed(() => {
   .size-item {
     margin-left: 10px;
   }
+
+  .view-off-icon {
+    width: 120px;
+    height: 120px;
+    object-fit: contain;
+  }
 }
 </style>

+ 8 - 2
src/components/view_file/vendors/pptx/elements/pptxText.ts

@@ -1,8 +1,15 @@
+/*
+ * @Author: LiZhiWei
+ * @Date: 2025-12-29 11:59:39
+ * @LastEditors: LiZhiWei
+ * @LastEditTime: 2025-12-30 11:58:04
+ * @Description: 
+ */
 import type { CSSProperties } from "vue"
 import type { PptxElement } from "./pptxTypes"
 import { getNumber } from "./pptxUtils"
 
-export function getHtmlBoxStyle(el: PptxElement) {
+export function getHtmlBoxStyle(_el: PptxElement) {
   return {
     position: "absolute",
     left: 0,
@@ -36,7 +43,6 @@ export function getHtmlInnerStyle(el: PptxElement) {
     } as CSSProperties
   }
 
-  const inv = 100 / fontScale
   return {
     display: "table-cell" as const,
     // width: `${inv}%`,

+ 2 - 2
src/components/view_file/vendors/pptx/index.js

@@ -2,12 +2,12 @@
  * @Author: LiZhiWei
  * @Date: 2025-12-26 14:35:12
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2025-12-29 13:09:44
+ * @LastEditTime: 2025-12-30 11:55:29
  * @Description: 
  */
 import { createApp } from "vue"
 import PPT from "./PPT.vue"
-import { parse } from "hj-pptxtojson"
+import { parse } from "huijia-pptxtojson"
 
 /**
  * 渲染ppt

+ 5 - 2
src/main.ts

@@ -2,16 +2,19 @@
  * @Author: LiZhiWei
  * @Date: 2025-04-24 15:20:36
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2025-04-24 15:33:21
+ * @LastEditTime: 2025-12-30 12:57:20
  * @Description: 
  */
 import { createApp } from 'vue'
 import App from './App.vue'
 import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
+import ViewFilePlugin from 'huijia-viewfile'
+// import 'huijia-viewfile/style.css'
 import router from './router'
 
 const app = createApp(App)
 app.use(router)
 app.use(ElementPlus)
-app.mount('#app')
+app.use(ViewFilePlugin)
+app.mount('#app')

+ 1 - 2
src/views/index.vue

@@ -2,7 +2,7 @@
  * @Author: LiZhiWei
  * @Date: 2025-04-24 15:23:24
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2025-04-25 09:48:50
+ * @LastEditTime: 2025-12-30 12:56:38
  * @Description: 
 -->
 <template>
@@ -53,7 +53,6 @@
 
 <script setup lang="ts">
 import { ref } from "vue"
-import ViewFile from "@/components/view_file/index.vue"
 
 type file = {
   filename: string 

+ 46 - 6
vite.config.ts

@@ -2,7 +2,7 @@
  * @Author: LiZhiWei
  * @Date: 2025-04-24 15:29:01
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2025-04-24 17:14:31
+ * @LastEditTime: 2025-12-30 12:19:24
  * @Description:
  */
 import { defineConfig } from "vite"
@@ -10,8 +10,9 @@ import vue from "@vitejs/plugin-vue"
 import AutoImport from "unplugin-auto-import/vite"
 import Components from "unplugin-vue-components/vite"
 import { ElementPlusResolver } from "unplugin-vue-components/resolvers"
-export default defineConfig({
-  plugins: [
+
+export default defineConfig(({ mode }) => {
+  const plugins = [
     vue(),
     AutoImport({
       resolvers: [ElementPlusResolver()],
@@ -19,10 +20,49 @@ export default defineConfig({
     Components({
       resolvers: [ElementPlusResolver()],
     }),
-  ],
-  resolve: {
+  ]
+
+  const resolve = {
     alias: {
       "@": "/src",
+      ...(mode === "lib"
+        ? {}
+        : {
+            "huijia-viewfile": "/src/components/view_file/lib.js",
+            "huijia-viewfile/style.css": "/src/components/view_file/index.less",
+          }),
     },
-  },
+  }
+
+  if (mode === "lib") {
+    return {
+      plugins,
+      resolve,
+      publicDir: false,
+      build: {
+        outDir: "dist-lib",
+        emptyOutDir: true,
+        lib: {
+          entry: "src/components/view_file/lib.js",
+          name: "ViewFile",
+          formats: ["es", "cjs"],
+          fileName: (format) => (format === "cjs" ? "index.cjs" : "index.js"),
+        },
+        rollupOptions: {
+          external: ["vue"],
+          output: {
+            exports: "named",
+            globals: {
+              vue: "Vue",
+            },
+          },
+        },
+      },
+    }
+  }
+
+  return {
+    plugins,
+    resolve,
+  }
 })

Деякі файли не було показано, через те що забагато файлів було змінено