├── pnpm-workspace.yaml ├── src ├── http.ts ├── assets │ └── logo.png ├── lib │ └── stringUtil.ts ├── components │ ├── interface.ts │ ├── hooks.ts │ ├── check.vue │ ├── config.vue │ ├── converter.ts │ ├── backup.vue │ ├── convert_docx.ts │ └── api.ts ├── env.d.ts ├── App.vue └── main.ts ├── assets ├── 1.png └── 2.png ├── .vscode └── extensions.json ├── public └── favicon.ico ├── .env ├── .gitignore ├── .env.github ├── dist.bat ├── index.html ├── vite.config.ts ├── tsconfig.json ├── dist.sh ├── package.json ├── go.mod ├── main.go ├── README.md ├── go.sum └── pnpm-lock.yaml /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | onlyBuiltDependencies: 2 | - esbuild 3 | -------------------------------------------------------------------------------- /src/http.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | axios.create({ 4 | 5 | }) -------------------------------------------------------------------------------- /assets/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicarne/feishu-backup/HEAD/assets/1.png -------------------------------------------------------------------------------- /assets/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicarne/feishu-backup/HEAD/assets/2.png -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["johnsoncodehk.volar"] 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicarne/feishu-backup/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dicarne/feishu-backup/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | NODE_ENV="production" 2 | VITE_SERVER_BASEURL="/feishu-backup/" 3 | VITE_SERVER="" 4 | VITE_API_URL="/api/feishu" 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | /secret.js 7 | /secret.ts 8 | /deploy.sh 9 | feishu-backup 10 | feishu-backup-mac 11 | feishu-backup.exe 12 | publish/* -------------------------------------------------------------------------------- /.env.github: -------------------------------------------------------------------------------- 1 | NODE_ENV="production" 2 | VITE_PAGE_BASEURL="/feishu-backup/" 3 | VITE_SERVER_BASEURL="/feishu-backup/" 4 | VITE_SERVER="" 5 | VITE_API_URL="/api/feishu" 6 | 7 | VITE_DOMAIN="https://dicarne.github.io" -------------------------------------------------------------------------------- /src/lib/stringUtil.ts: -------------------------------------------------------------------------------- 1 | export function stringNullIsDefault(str:string, defaultString: string) { 2 | if(str === null || str === undefined || str === '') 3 | return defaultString 4 | return str 5 | } -------------------------------------------------------------------------------- /src/components/interface.ts: -------------------------------------------------------------------------------- 1 | import {CascaderOption} from 'naive-ui' 2 | export interface MyTreeSelectOption extends CascaderOption{ 3 | label: string 4 | value: string 5 | depth: number 6 | isLeaf: boolean 7 | } -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import { DefineComponent } from 'vue' 5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 6 | const component: DefineComponent<{}, {}, any> 7 | export default component 8 | } 9 | -------------------------------------------------------------------------------- /dist.bat: -------------------------------------------------------------------------------- 1 | CALL pnpm i 2 | CALL pnpm run build 3 | 4 | SET CGO_ENABLED=0 5 | SET GOOS=windows 6 | SET GOARCH=amd64 7 | CALL go build -o feishu-backup.exe 8 | 9 | SET CGO_ENABLED=0 10 | SET GOOS=darwin 11 | SET GOARCH=amd64 12 | CALL go build -o feishu-backup-mac 13 | 14 | SET CGO_ENABLED=0 15 | SET GOOS=linux 16 | SET GOARCH=amd64 17 | CALL go build -o feishu-backup 18 | 19 | mkdir publish -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 飞书备份 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/components/hooks.ts: -------------------------------------------------------------------------------- 1 | import { ref } from "vue"; 2 | 3 | export function useLocalStorage(name: string, default_value: T) { 4 | const old = window.localStorage.getItem(name) 5 | const v = ref(old ? (JSON.parse(old) as T) : default_value) 6 | return { 7 | value: v, 8 | setValue: (newv: T) => { 9 | v.value = newv as any 10 | window.localStorage.setItem(name, JSON.stringify(newv)) 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import { loadEnv } from 'vite' 4 | 5 | export default ({ mode }) => { 6 | const env = loadEnv(mode, process.cwd()) 7 | let url = env.VITE_PAGE_BASEURL ? env.VITE_PAGE_BASEURL : env.VITE_SERVER_BASEURL 8 | return defineConfig({ 9 | server: { 10 | port: 3800, 11 | //proxy: proxy 12 | }, 13 | base: url, 14 | plugins: [vue()] 15 | }) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true, 4 | "target": "esnext", 5 | "useDefineForClassFields": true, 6 | "module": "esnext", 7 | "moduleResolution": "node", 8 | "strict": true, 9 | "jsx": "preserve", 10 | "sourceMap": true, 11 | "resolveJsonModule": true, 12 | "esModuleInterop": true, 13 | "lib": ["esnext", "dom"] 14 | }, 15 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] 16 | } 17 | -------------------------------------------------------------------------------- /dist.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | pnpm i 4 | pnpm run build 5 | 6 | CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o feishu-backup.exe 7 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o feishu-backup 8 | CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o feishu-backup-mac 9 | 10 | 11 | mkdir publish 12 | rm publish/windows.zip 13 | rm publish/linux.zip 14 | rm publish/mac.zip 15 | zip -r publish/windows.zip feishu-backup.exe dist 16 | zip -r publish/linux.zip feishu-backup dist 17 | zip -r publish/mac.zip feishu-backup-mac dist -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { createRouter, createWebHashHistory } from 'vue-router' 3 | import App from './App.vue' 4 | const routes = [ 5 | { path: '/', component: () => import('./components/check.vue') }, 6 | { path: '/backup/:app_id/:app_secret', component: () => import('./components/backup.vue') }, 7 | { path: '/config', component: () => import('./components/config.vue') } 8 | ] 9 | 10 | const router = createRouter({ 11 | history: createWebHashHistory('/tool/feishu-backup/'), 12 | routes, 13 | }) 14 | 15 | createApp(App).use(router).mount('#app') 16 | -------------------------------------------------------------------------------- /src/components/check.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feihu-backup-web", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "dev": "vite", 6 | "build": "vue-tsc --noEmit && vite build", 7 | "github": "vue-tsc --noEmit && vite build --mode github", 8 | "serve": "vite preview" 9 | }, 10 | "dependencies": { 11 | "axios": "^1.13.2", 12 | "file-saver": "^2.0.5", 13 | "jszip": "^3.10.1", 14 | "localforage": "^1.10.0", 15 | "vue": "^3.5.25", 16 | "vue-router": "^4.6.3" 17 | }, 18 | "devDependencies": { 19 | "@types/file-saver": "^2.0.7", 20 | "@types/node": "^24.10.1", 21 | "@vitejs/plugin-vue": "^6.0.2", 22 | "naive-ui": "^2.43.2", 23 | "pnpm": "^10.23.0", 24 | "typescript": "^5.9.3", 25 | "vfonts": "^0.1.0", 26 | "vite": "^7.2.4", 27 | "vue-tsc": "^3.1.5" 28 | } 29 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module feishu-backup 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/bytedance/sonic v1.10.2 // indirect 7 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect 8 | github.com/chenzhuoyu/iasm v0.9.1 // indirect 9 | github.com/gabriel-vasile/mimetype v1.4.3 // indirect 10 | github.com/gin-contrib/cors v1.4.0 // indirect 11 | github.com/gin-contrib/sse v0.1.0 // indirect 12 | github.com/gin-gonic/gin v1.9.1 // indirect 13 | github.com/go-playground/locales v0.14.1 // indirect 14 | github.com/go-playground/universal-translator v0.18.1 // indirect 15 | github.com/go-playground/validator/v10 v10.16.0 // indirect 16 | github.com/goccy/go-json v0.10.2 // indirect 17 | github.com/json-iterator/go v1.1.12 // indirect 18 | github.com/klauspost/cpuid/v2 v2.2.6 // indirect 19 | github.com/leodido/go-urn v1.2.4 // indirect 20 | github.com/mattn/go-isatty v0.0.20 // indirect 21 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 22 | github.com/modern-go/reflect2 v1.0.2 // indirect 23 | github.com/pelletier/go-toml/v2 v2.1.0 // indirect 24 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 25 | github.com/ugorji/go/codec v1.2.11 // indirect 26 | golang.org/x/arch v0.6.0 // indirect 27 | golang.org/x/crypto v0.14.0 // indirect 28 | golang.org/x/net v0.17.0 // indirect 29 | golang.org/x/sys v0.14.0 // indirect 30 | golang.org/x/text v0.14.0 // indirect 31 | google.golang.org/protobuf v1.31.0 // indirect 32 | gopkg.in/yaml.v3 v3.0.1 // indirect 33 | ) 34 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "embed" 5 | "flag" 6 | "fmt" 7 | "io/fs" 8 | "net/http" 9 | "net/http/httputil" 10 | "net/url" 11 | "os/exec" 12 | "runtime" 13 | 14 | "github.com/gin-contrib/cors" 15 | "github.com/gin-gonic/gin" 16 | ) 17 | 18 | //go:embed dist/* 19 | var webDir embed.FS 20 | 21 | func main() { 22 | r := gin.Default() 23 | 24 | config := cors.DefaultConfig() 25 | config.AllowAllOrigins = true 26 | config.AllowCredentials = true 27 | config.AllowHeaders = []string{"Authorization"} 28 | r.Use(cors.New(config)) 29 | 30 | staticFp, _ := fs.Sub(webDir, "dist") 31 | 32 | debug := flag.Bool("debug", false, "用于本地Web开发") 33 | flag.Parse() 34 | 35 | if *debug { 36 | r.Any("/feishu-backup/*proxyPath", proxydev) 37 | } else { 38 | r.StaticFS("/feishu-backup", http.FS(staticFp)) 39 | } 40 | r.Any("/api/feishu/*proxyPath", proxy) 41 | r.GET("/ping", func(ctx *gin.Context) { 42 | ctx.JSON(http.StatusOK, gin.H{"code": 0}) 43 | }) 44 | Open(`http://127.0.0.1:18900/feishu-backup`) 45 | r.Run("0.0.0.0:18900") 46 | } 47 | 48 | func proxy(c *gin.Context) { 49 | remote, err := url.Parse("https://open.feishu.cn") 50 | if err != nil { 51 | panic(err) 52 | } 53 | 54 | proxy := httputil.NewSingleHostReverseProxy(remote) 55 | proxy.Director = func(req *http.Request) { 56 | req.Header = c.Request.Header 57 | req.Host = remote.Host 58 | req.URL.Scheme = remote.Scheme 59 | req.URL.Host = remote.Host 60 | req.URL.Path = "/open-apis" + c.Param("proxyPath") 61 | } 62 | 63 | proxy.ServeHTTP(c.Writer, c.Request) 64 | } 65 | 66 | func proxydev(c *gin.Context) { 67 | remote, err := url.Parse("http://localhost:3800") 68 | if err != nil { 69 | panic(err) 70 | } 71 | 72 | proxy := httputil.NewSingleHostReverseProxy(remote) 73 | proxy.Director = func(req *http.Request) { 74 | req.Header = c.Request.Header 75 | req.Host = remote.Host 76 | req.URL.Scheme = remote.Scheme 77 | req.URL.Host = remote.Host 78 | req.URL.Path = "/feishu-backup" + c.Param("proxyPath") 79 | } 80 | 81 | proxy.ServeHTTP(c.Writer, c.Request) 82 | } 83 | 84 | var commands = map[string]string{ 85 | "windows": "start", 86 | "darwin": "open", 87 | "linux": "xdg-open", 88 | } 89 | 90 | func Open(uri string) error { 91 | run, ok := commands[runtime.GOOS] 92 | if !ok { 93 | return fmt.Errorf("don't know how to open things on %s platform", runtime.GOOS) 94 | } 95 | 96 | if runtime.GOOS == "windows" { 97 | cmd := exec.Command("cmd", "/C", "start", uri) 98 | return cmd.Start() 99 | 100 | } else { 101 | cmd := exec.Command(run, uri) 102 | return cmd.Start() 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/components/config.vue: -------------------------------------------------------------------------------- 1 | 56 | 78 | 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 飞书云文档备份 2 | 3 | 用于备份下载所有飞书云文档。文档将被转换成markdown。 4 | 5 | 6 | ## 快速使用 7 | > 本应用为了简单化、不搞后端服务,因此直接利用APP ID和Secret进行授权,这是明文的,因此有安全风险,请不要让无关人员知道你的备份URL! 8 | > 另外,本应用针对个人用户设计,因为你需要创建飞书应用并申请权限,如果想把公司离职前写的文档搬走恐怕不太可行! 9 | 10 | ### 零、创建应用 11 | 在[飞书开放平台](https://open.feishu.cn)创建一个企业应用,名字随便写。在应用后台的权限管理中找到云文档相关的权限,都点上。然后发布版本,通过,应用上线。(注意,权限是需要审批的!!想偷偷摸摸搬走文档恐怕不太可行!!除非你是个人用户,自己就是自己企业的领导!!) 12 | 13 | ### 一、配置 14 | 从Release下载最新版本,解压到你喜欢的地方。打开里面的可执行文件,会自动打开网页。首次打开时,需要填写`App ID`和`App Secret`(这些能在应用的凭证管理中找到),然后点击计算按钮。 15 | 16 | 将生成的`重定向URL`复制粘贴到你创建的应用的`安全设置-重定向URL`中。 17 | 18 | > 计算成功后,下次将自动进入授权页面,如果需要再次生成URL,请手动访问[配置页面](http://127.0.0.1:18900/feishu-backup/#/config) 19 | > 如果需要访问多个不同账号,请手动保存生成的备份URL,可以通过访问这些URL进行备份。 20 | > 如果出现配置错误,也请直接访问[配置页面](http://127.0.0.1:18900/feishu-backup/#/config)重新生成配置即可。 21 | 22 | ### 二、完成! 23 | 在计算完成后,并且配置好重定向URL后,点击完成按钮,会自动使用生成的URL进行授权,如果没有错误,就可以成功进入备份页面。(也可以手动保存下面的`备份URL`,以后你直接访问这个链接即可打开并授权备份应用。需要在此之前打开程序!) 24 | 25 | ### 三、简单使用说明 26 | 配置好以后,打开备份URL,有两个按钮:备份`下载云空间文档`和`下载知识库文档`,分别是针对云空间和知识空间的备份。 27 | 28 | #### 下载云空间文档 29 | 点击`选择文件`,选择你需要的文件,再点击`下载选中文件`即可。 30 | 或者`下载所有文件`,会遍历整个云空间下载。 31 | 32 | #### 下载知识库文档 33 | 将会出现知识库列表,可以通过多选下载多个知识库,也可以在单个知识库中选择一些一级页面下载。 34 | 35 | ### QA 36 | #### 为什么只能下载一部分云文档 37 | 目前只支持`doc`和`docx`和文件的下载。其他的表格、多维表格都不支持,请考虑手动导出。云文档下载后将会被转换成markdown,图片将被放在文档同级目录。 38 | 39 | #### 为什么文档中只有一部分内容 40 | 文档内不支持转换成markdown的块不会被导出,它们会消失。有些是我没有实现转换的功能,有些是飞书不支持导出。 41 | 42 | 在导出markdown时将会顺便导出一份JSON,这是飞书返回的原始数据,你可以自己写脚本处理它。 43 | 44 | #### 为什么排版与格式感觉不对 45 | markdown不能很好的支持所有富文本元素,例如多列布局等。虽然也有奇淫技巧可以在markdown中实现,但鉴于通用性,暂时不考虑(或者等研究出一个漂亮的方案)。 46 | 47 | 很多文本样式在markdown中不能很好的支持。 48 | 49 | ## 预览 50 | 51 | 左侧是飞书文档,中间是导出的markdown,右侧是渲染后的markdown。 52 | 53 | ![](assets/1.png) 54 | 55 | ![](assets/2.png) 56 | 57 | ## 高级 58 | > 下面是部署原理,自己部署的话需要看懂,如果你只是想简单的使用,就跳过本节 59 | 60 | ### 计算飞书URL 61 | 记住`app_id`和`app_secret`,构造url: `https://{{your_server}}/tool/feishu-backup/#/backup/{{app_id}}/{{app_secret}}`。在飞书应用后台的安全设置中的重定向中写入这个url。 62 | 63 | 把这个url encode后,作为`{{your_direct_url}}`。 64 | 65 | 启动备份的URL:中间需要替换你自己的重定向URL和APP_ID 66 | `https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri={{your_direct_url}}&app_id={{app_id}}` 67 | 68 | 打开这个链接,然后授权,点击按钮,等待下载。 69 | 70 | ### 部署 71 | 现在只需要下载并执行可执行文件,就可以在不需求第三方服务的情况下下载文件。但是如果你还想将其部署在服务器上,只通过网页来访问的话…… 72 | 73 | #### 方法一、静态网页部署 74 | 75 | 部署复杂,但稳定性强,毕竟只是个静态网页。 76 | 77 | ##### 1. 准备 78 | ``` 79 | git clone https://github.com/dicarne/feishu-backup.git 80 | pnpm i 81 | ``` 82 | 83 | ##### 2. 修改base url 84 | 参考`.env.github`,新建一个环境变量文件,如`.env.my` 85 | 修改`.env.my`中的`VITE_BASEURL`,改成你需要的路径。这跟你的Nginx之类的网页服务器的配置有关。形如`https://your.domain/AAA/BBB/CCC/#/...`中的`/AAA/BBB/CCC`就是base url。如果不需要的话,简单改成`/`应该就行了。将`VITE_API_URL`修改为你的转发服务器的URL。 86 | 87 | ##### 3. 打包 88 | `pnpm run build my`,打包文件在`/dist`目录下,复制到你的静态网页文件夹中。 89 | 90 | 别忘了配置你的Nginx!Nginx需要为你的静态网页提供服务,也需要配置`proxy_pass`来转发请求! 91 | 92 | 配置网页的Nginx例子: 93 | ``` 94 | location /your_base_url/ { 95 | alias /web/feishu-backup/; # 你的静态网页路径 96 | index index.html; 97 | } 98 | ``` 99 | 100 | 配置转发的Nginx例子: 101 | ``` 102 | location /your_url { 103 | add_header Access-Control-Allow-Origin *; 104 | add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; 105 | add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; 106 | if ($request_method = 'OPTIONS') { 107 | return 204; 108 | } 109 | proxy_pass https://open.feishu.cn/open-apis; 110 | } 111 | ``` 112 | 113 | ##### 4. 使用 114 | 通过你计算出来的备份URL授权并访问备份网页,注意请确保回调能正确跳转到你部署的网页上! 115 | 116 | #### 方法二、直接运行 117 | 也可以在服务器上直接运行linux版的可执行文件,并用你自己的方式让它持续运行。如果可以访问到`18900`这个端口,理论上能正常运行。但暂时没有经过完整测试,如有问题试试反馈一下! 118 | 119 | ## TODO 120 | 暂时只支持部分我需要的格式转换,所以很多格式都是跳过的。 121 | 可以修改`src/components/converter.ts`(飞书1.0doc)和`src/components/convert_docx.ts`(飞书2.0docx)支持你想要的块。 122 | 123 | ## 试用 124 | 访问[试用](https://dicarne.github.io/feishu-backup/#/)直接尝试使用!但是由于转发服务器的原因,下载速度会更慢且不稳定。推荐从Release下载运行本地版。 125 | 126 | ## 注意 127 | 这是为个人用户设计,你必须要有飞书的管理员权限才行。否则API无法获取你的文档。 128 | 注意,URL可能泄露你的app secret,请在可信的环境使用。 129 | 130 | ## 更新 131 | - 支持本地使用,不再需要第三方服务器转发! 132 | - 支持仅下载知识库的单个一级页面,以改善性能问题。 133 | - 支持导出云空间中的文件,如pdf,zip,exe等。 134 | - 支持飞书2.0 docx(不完全) 135 | - 多级标题 136 | - 加粗、斜体 137 | - 代码块 138 | - 公式块 139 | - 引用 140 | - 图片 141 | - 增加一个看得过去的ui界面。 142 | - 知识库已支持。 143 | 144 | ## 支持内容 145 | ### docx 146 | | 类型 | 描述 | 支持 | 147 | | ----------- | ----------------------------------- | -------- | 148 | | page | 文档 Block,是整个文档树的根节点 | 支持 | 149 | | text | 文本 Block | 支持 | 150 | | headingN | 标题 Block,headingN,N 取值范围1~9 | 支持 | 151 | | bullet | 无序列表 Block | 支持 | 152 | | ordered | 有序列表 Block | 支持 | 153 | | code | 代码块 Block | 支持 | 154 | | quote | 引用 Block | 支持 | 155 | | equation | 公式 Block | 支持 | 156 | | todo | 任务 Block | 支持 | 157 | | bitable | 多维表格 Block | 158 | | callout | 高亮块 Block | 159 | | chat_card | 会话卡片 Block | 160 | | diagram | UML 图 Block | 161 | | divider | 分割线 Block | 支持 | 162 | | file | 文件 Block | 支持 | 163 | | grid | 分栏 Block | 部分支持 | 164 | | grid_column | 分栏列 Block | 部分支持 | 165 | | iframe | 内嵌 Block | 166 | | image | 图片 Block | 支持 | 167 | | isv | 三方 Block | 168 | | mindnote | 思维笔记 Block | 169 | | sheet | 电子表格 Block | 170 | | table | 表格 Block | 支持,但不能合并 171 | | table_cell | 单元格 Block | 支持 172 | | view | 视图 Block | 173 | | | 网页卡片 | 不支持 174 | -------------------------------------------------------------------------------- /src/components/converter.ts: -------------------------------------------------------------------------------- 1 | 2 | import JSZip from "jszip"; 3 | import localforage from 'localforage' 4 | import axios from "axios"; 5 | import { feishu_api } from "./api"; 6 | 7 | class StringFile { 8 | file = "" 9 | constructor() { 10 | } 11 | write(text: string) { 12 | this.file += text 13 | } 14 | } 15 | 16 | export interface TmpFile { 17 | mime: string 18 | data: any 19 | } 20 | export function decorate(tag: string, style: any, dec: string, file: StringFile) { 21 | if (!!style[tag]) { file.write(dec) } 22 | } 23 | export class Converter { 24 | tmp: LocalForage; 25 | docLinks: Map 26 | constructor() { 27 | this.tmp = localforage.createInstance({ 28 | name: 'file_cache' 29 | }) 30 | this.docLinks = new Map() 31 | } 32 | stringMul(str: string, times: number) { 33 | let ret = str 34 | for (let index = 0; index < times - 1; index++) { 35 | ret += str 36 | } 37 | return ret 38 | } 39 | 40 | 41 | 42 | convertele(ele: any, file: StringFile) { 43 | if (ele['type'] == 'textRun') { 44 | let t = ele['textRun'] 45 | if (t['style']) { 46 | let style = t['style'] 47 | decorate('link', style, '[', file) 48 | decorate('codeInline', style, '`', file) 49 | decorate('bold', style, '**', file) 50 | decorate('italic', style, '*', file) 51 | file.write(t['text']) 52 | decorate('codeInline', style, '`', file) 53 | decorate('bold', style, '**', file) 54 | decorate('italic', style, '*', file) 55 | decorate('link', style, '](', file) 56 | if (style['link']) { 57 | let url = decodeURIComponent(style['link']['url']) 58 | decorate('link', style, url, file) 59 | } 60 | decorate('link', style, ')', file) 61 | } 62 | else { 63 | file.write(t['text']) 64 | } 65 | } 66 | else if (ele['type'] == 'equation') { 67 | file.write("$") 68 | file.write(ele['equation']['equation']) 69 | file.write("$") 70 | } else if (ele['type'] == 'docsLink') { 71 | let inline = new RegExp('https://\\w*.feishu.cn/((wiki)|(docs))/\\w+(?#\\w+)') 72 | let url = ele['docsLink']['url'] 73 | if (inline.test(url)) { 74 | let g = inline.exec(url)?.groups?.['id'] ?? "" 75 | file.write(`[${g}](${g})`) 76 | } 77 | } 78 | } 79 | 80 | async convertPara(fobj: any, out: StringFile, user_token: string, zip: JSZip) { 81 | let blocks = fobj['body']['blocks'] 82 | for (let p of blocks) { 83 | if (p['type'] == 'paragraph') { 84 | let pg = p['paragraph'] 85 | let lineId = pg['lineId'] 86 | let els = pg['elements'] 87 | if (pg['style']) { 88 | const style = pg['style'] 89 | if (style['headingLevel']) { 90 | out.write(this.stringMul('#', style['headingLevel'])) 91 | out.write(' ') 92 | } else { 93 | lineId = null 94 | } 95 | if (style['list'] && style['list']['type'] === 'checkbox') out.write('- [ ] ') 96 | if (style['list'] && style['list']['type'] === 'bullet') out.write('- ') 97 | if (style['list'] && style['list']['type'] === 'number') out.write(JSON.stringify(style['list']['number']) + '. ') 98 | if (style['quote']) out.write('> ') 99 | } else { 100 | lineId = null 101 | } 102 | for (let e of els) { 103 | if (lineId) { 104 | out.write(``) 105 | } 106 | let innerText = new StringFile() 107 | this.convertele(e, innerText) 108 | out.write(innerText.file) 109 | if (lineId) { 110 | this.docLinks.set(lineId, innerText.file) 111 | out.write("") 112 | } 113 | } 114 | out.write('\n\n') 115 | } 116 | else if (p['type'] == 'code') { 117 | let code = p['code'] 118 | out.write("```") 119 | out.write(code['language']) 120 | out.write('\n') 121 | await this.convertPara(code, out, user_token, zip) 122 | out.write("```\n\n") 123 | } 124 | else if (p['type'] == 'gallery') { 125 | let imgs = p['gallery']['imageList'] 126 | for (let im of imgs) { 127 | let token = im['fileToken'] 128 | let filename = await this.downloadAsset(token, user_token, zip) 129 | out.write(`![](assets/${filename})\n\n`) 130 | } 131 | } else if (p['type'] == 'horizontalLine') { 132 | out.write('\n---\n\n') 133 | } else if (p['type'] == 'callout') { 134 | this.convertPara(p['callout'], out, user_token, zip) 135 | } 136 | } 137 | 138 | } 139 | async convert(user_token: string, zip: JSZip, fobj: any) { 140 | let out = new StringFile() 141 | await this.convertPara(fobj, out, user_token, zip) 142 | for (const it of this.docLinks) { 143 | let [key, title] = it 144 | out.file = replaceAll(out.file, `\\[#${key}\\]\\(#${key}\\)`, `[${title}](#${key})`) 145 | } 146 | return out 147 | } 148 | 149 | 150 | async downloadAsset(id: string, token: string, zip: JSZip) { 151 | let c = await this.tmp.getItem(id) 152 | let ext = "" 153 | if (c) { 154 | let mime = c.mime 155 | if (mime == 'image/png') 156 | ext = ".png" 157 | else if (mime == 'image/jpeg' || mime == 'image/jpg') 158 | ext = ".jpg" 159 | zip.folder("assets")?.file(id + ext, c.data) 160 | } else { 161 | try { 162 | let r = await axios.get(feishu_api(`/drive/v1/medias/${id}/download`), 163 | { 164 | headers: { 'Authorization': 'Bearer ' + token }, 165 | responseType: 'arraybuffer' 166 | }) 167 | let mime = r.headers['content-type'] 168 | 169 | if (mime == 'image/png') 170 | ext = ".png" 171 | else if (mime == 'image/jpeg' || mime == 'image/jpg') 172 | ext = ".jpg" 173 | const data = new Uint8Array(r.data) 174 | zip.folder("assets")?.file(id + ext, data) 175 | await this.tmp.setItem(id, { 176 | mime: mime, 177 | data: data 178 | }) 179 | } catch (error) { 180 | console.error(error) 181 | console.log(`下载云空间文件 /drive/v1/medias/${token}/download 失败!`) 182 | } 183 | 184 | } 185 | 186 | return id + ext 187 | } 188 | } 189 | 190 | function replaceAll(str: string, f: string, e: string) {//吧f替换成e 191 | var reg = new RegExp(f, "g"); //创建正则RegExp对象 192 | return str.replace(reg, e); 193 | } 194 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= 2 | github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= 3 | github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= 4 | github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= 5 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= 6 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 7 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= 8 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= 9 | github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= 10 | github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= 11 | github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= 12 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 13 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 15 | github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= 16 | github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= 17 | github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= 18 | github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= 19 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 20 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 21 | github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= 22 | github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= 23 | github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= 24 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 25 | github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= 26 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 27 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 28 | github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= 29 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 30 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 31 | github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= 32 | github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE= 33 | github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= 34 | github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 35 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 36 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 37 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 38 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 39 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 40 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 41 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 42 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 43 | github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= 44 | github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 45 | github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= 46 | github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 47 | github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= 48 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 49 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 50 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 51 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 52 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 53 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 54 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 55 | github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= 56 | github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= 57 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 58 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 59 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 60 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 61 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 62 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 63 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 64 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 65 | github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= 66 | github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= 67 | github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= 68 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 69 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 70 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 71 | github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= 72 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 73 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 74 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 75 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 76 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 77 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 78 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 79 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 80 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 81 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 82 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 83 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 84 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 85 | github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= 86 | github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= 87 | github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= 88 | github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 89 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 90 | golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= 91 | golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 92 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 93 | golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= 94 | golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 95 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 96 | golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= 97 | golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 98 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 99 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 100 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 101 | golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 102 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 103 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 104 | golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= 105 | golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 106 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 107 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 108 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 109 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 110 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 111 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 112 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 113 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 114 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 115 | google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= 116 | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 117 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 118 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 119 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 120 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 121 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 122 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 123 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 124 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 125 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 126 | nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= 127 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 128 | -------------------------------------------------------------------------------- /src/components/backup.vue: -------------------------------------------------------------------------------- 1 | 243 | 244 | 333 | -------------------------------------------------------------------------------- /src/components/convert_docx.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosResponse } from "axios" 2 | import JSZip from "jszip" 3 | import localforage from "localforage" 4 | import { feishu_api } from "./api" 5 | import { TmpFile } from "./converter" 6 | interface ConvertContextArg { 7 | output_raw?: boolean 8 | async_tasks?: Promise[] 9 | } 10 | interface ConvertContext { 11 | output_raw: boolean 12 | async_tasks: Promise[] 13 | } 14 | 15 | export interface DocxBlock { 16 | block_id: string 17 | parent_id: string 18 | children: string[] 19 | block_type: BlockType 20 | } 21 | interface DocxPage extends DocxBlock { 22 | page: { 23 | elements: element[] 24 | } 25 | } 26 | interface DocxCode extends DocxBlock { 27 | code: BlockContent 28 | } 29 | interface DocxFile extends DocxBlock { 30 | file: { 31 | name: string 32 | token: string 33 | } 34 | } 35 | interface DocxImage extends DocxBlock { 36 | image: { 37 | width: number, 38 | height: number, 39 | token: string 40 | } 41 | } 42 | interface DocxTable extends DocxBlock { 43 | table: { 44 | cells: string[] 45 | property: { 46 | column_size: number 47 | column_width: number[] 48 | merge_info: { col_span: number, row_span: number }[] 49 | row_size: number 50 | } 51 | } 52 | } 53 | interface element { 54 | text_run?: { 55 | content: string 56 | text_element_style: { 57 | "bold": boolean, 58 | "inline_code": boolean, 59 | "italic": boolean, 60 | "strikethrough": boolean, 61 | "underline": boolean, 62 | link?: { 63 | url: string 64 | }, 65 | background_color?: number, 66 | text_color?: number 67 | } 68 | } 69 | equation?: { 70 | content: string 71 | } 72 | mention_doc?: { 73 | obj_type: number 74 | title: string 75 | token: string 76 | url: string 77 | } 78 | } 79 | enum textStyle { 80 | left = 1, 81 | center = 2, 82 | right = 3 83 | } 84 | interface BlockStyle { 85 | 86 | align?: textStyle, 87 | done: boolean, 88 | folded: boolean, 89 | language: number, 90 | wrap: boolean 91 | 92 | } 93 | interface BlockContent { 94 | elements: element[] 95 | style: BlockStyle 96 | } 97 | interface DocxText extends DocxBlock { 98 | text: BlockContent 99 | } 100 | 101 | const _mark_color: any = { 102 | 15: "#F2F3F5", 103 | 1: "#FBBFBC", 104 | 2: "#F9D8B1", 105 | 3: "#FAF390", 106 | 4: "#C0ECBC", 107 | 5: "#C7D5F6", 108 | 6: "#D4C1F3", 109 | 7: "#E0E1E4", 110 | 14: "#BBBFC4", 111 | 8: "#F76964", 112 | 9: "#FFA53D", 113 | 10: "#FFE928", 114 | 11: "#62D256", 115 | 12: "#92AFF2", 116 | 13: "#B898EE" 117 | } 118 | 119 | function convertElements(ele: element[]) { 120 | let md = "" 121 | for (const e of ele) { 122 | if (e.text_run) { 123 | let ct = e.text_run.content 124 | let sty = e.text_run.text_element_style 125 | if (sty.link) { 126 | ct = `[${ct}](${decodeURIComponent(sty.link.url)})` 127 | } 128 | if (ct.trim() == "") { 129 | continue 130 | } 131 | if (sty.strikethrough) ct = "~~" + ct.trim() + "~~" 132 | if (sty.bold) ct = "**" + ct.trim() + "**" 133 | if (sty.italic) ct = "*" + ct.trim() + "*" 134 | if (sty.inline_code) ct = "`" + ct + "`" 135 | if (sty.background_color != undefined) { 136 | ct = `` + ct + "" 137 | } 138 | if (sty.text_color != undefined) { 139 | ct = `${ct}` 140 | } 141 | if (sty.underline) { 142 | ct = `${ct}` 143 | } 144 | md += ct 145 | } else if (e.equation) { 146 | md += "$" + e.equation.content.trim() + "$" 147 | } else if (e.mention_doc) { 148 | const mc = e.mention_doc! 149 | md += `[${mc.title}](${decodeURIComponent(mc.url)})` 150 | } 151 | } 152 | return md 153 | } 154 | 155 | export async function ConvertDocxToMD(ctx0: ConvertContextArg, parent: string, blocks: DocxBlock[], zip: JSZip, access: string, args?: { parent_prefix?: string, nonewline?: boolean }) { 156 | const r = await convertDocxToMD(ctx0, parent, blocks, zip, access, args ?? {}) 157 | await Promise.all(ctx0.async_tasks || []) 158 | return r 159 | } 160 | 161 | interface CvtArg { 162 | parent_prefix?: string, 163 | nonewline?: boolean, 164 | parentIsTarget?: boolean, 165 | orderListIndex?: number, 166 | } 167 | 168 | async function convertDocxToMD(ctx0: ConvertContextArg, parent: string, blocks: DocxBlock[], zip: JSZip, access: string, args: CvtArg) { 169 | let tmd = "" 170 | let continue_block_type = 0 171 | const ctx: ConvertContext = { 172 | output_raw: ctx0.output_raw ?? false, 173 | async_tasks: ctx0.async_tasks ?? [] 174 | } 175 | ctx0.async_tasks = ctx.async_tasks 176 | for (const ele of blocks) { 177 | if (!args?.parentIsTarget) { 178 | if (ele.parent_id != parent) { 179 | continue 180 | } 181 | } else { 182 | if (ele.block_id != parent) { 183 | continue 184 | } 185 | } 186 | if (continue_block_type != ele.block_type) { 187 | if (continue_block_type != 0) tmd += "\n" 188 | continue_block_type = 0 189 | } 190 | let block_next_line = "\n\n" 191 | let md = "" 192 | if (args.parent_prefix) { 193 | md = args.parent_prefix + md 194 | block_next_line = "\n" 195 | } 196 | if (args.nonewline) { 197 | block_next_line = "" 198 | } 199 | if (args.orderListIndex != undefined) { 200 | if (ele.block_type != BlockType.orderList) { 201 | args.orderListIndex = undefined 202 | } 203 | } 204 | const simpleChildrenRender = async () => { 205 | if (ele.children && ele.children.length > 0) { 206 | for (const c of ele.children) { 207 | let content = await convertDocxToMD(ctx, c, blocks, zip, access, { 208 | parent_prefix: "" + (args?.parent_prefix ?? ""), 209 | parentIsTarget: true 210 | }) 211 | md += content 212 | } 213 | } 214 | } 215 | switch (ele.block_type) { 216 | case BlockType.page: { 217 | const e = ele as DocxPage 218 | md += "# " + convertElements(e.page.elements) + "\n\n" 219 | md += await convertDocxToMD(ctx, e.block_id, blocks, zip, access, {}) 220 | } 221 | break; 222 | case BlockType.text: { 223 | const e = ele as DocxText 224 | md += convertElements(e.text.elements) + block_next_line 225 | await simpleChildrenRender() 226 | break 227 | } 228 | case BlockType.code: { 229 | const e = ele as DocxCode 230 | const strLang = e.code.style.language <= code_language.length ? code_language[e.code.style.language - 1] : "" 231 | // 防止代码块出现缩进,可能会有问题,OD会识别错误,导致下文全变成了代码块 232 | md += "\n```" + strLang + "\n" + convertElements(e.code.elements) + "\n```\n\n" 233 | await simpleChildrenRender() 234 | break 235 | } 236 | case BlockType.h1: { 237 | const e = ele as DocxHeading 238 | md += "# " + convertElements(e.heading1.elements) + "\n\n" 239 | await simpleChildrenRender() 240 | break 241 | } 242 | case BlockType.h2: { 243 | const e = ele as DocxHeading 244 | md += "## " + convertElements(e.heading2.elements) + "\n\n" 245 | await simpleChildrenRender() 246 | break 247 | } 248 | case BlockType.h3: { 249 | const e = ele as DocxHeading 250 | md += "### " + convertElements(e.heading3.elements) + "\n\n" 251 | await simpleChildrenRender() 252 | break 253 | } 254 | case BlockType.h4: { 255 | const e = ele as DocxHeading 256 | md += "#### " + convertElements(e.heading4.elements) + "\n\n" 257 | await simpleChildrenRender() 258 | break 259 | } 260 | case BlockType.h5: { 261 | const e = ele as DocxHeading 262 | md += "##### " + convertElements(e.heading5.elements) + "\n\n" 263 | await simpleChildrenRender() 264 | break 265 | } 266 | case BlockType.h6: { 267 | const e = ele as DocxHeading 268 | md += "###### " + convertElements(e.heading6.elements) + "\n\n" 269 | await simpleChildrenRender() 270 | break 271 | } 272 | case BlockType.h7: { 273 | const e = ele as DocxHeading 274 | md += "####### " + convertElements(e.heading7.elements) + "\n\n" 275 | await simpleChildrenRender() 276 | break 277 | } 278 | case BlockType.h8: { 279 | const e = ele as DocxHeading 280 | md += "######## " + convertElements(e.heading8.elements) + "\n\n" 281 | await simpleChildrenRender() 282 | break 283 | } 284 | case BlockType.h9: { 285 | const e = ele as DocxHeading 286 | md += "######### " + convertElements(e.heading9.elements) + "\n\n" 287 | await simpleChildrenRender() 288 | break 289 | } 290 | case BlockType.todo: { 291 | continue_block_type = BlockType.todo 292 | const e = (ele as any).todo as BlockContent 293 | if (e.style.done) { 294 | md += "- [x] " + convertElements(e.elements) + "\n" 295 | } else { 296 | md += "- [ ] " + convertElements(e.elements) + "\n" 297 | } 298 | if (ele.children && ele.children.length > 0) { 299 | for (const c of ele.children) { 300 | let content = await convertDocxToMD(ctx, c, blocks, zip, access, { 301 | parent_prefix: " " + (args?.parent_prefix ?? ""), 302 | parentIsTarget: true 303 | }) 304 | md += content 305 | } 306 | } 307 | break 308 | } 309 | case BlockType.orderList: { 310 | continue_block_type = BlockType.orderList 311 | const e = (ele as any).ordered as BlockContent 312 | md += `${args.orderListIndex ?? 1}. ` + convertElements(e.elements) + "\n" 313 | args.orderListIndex = (args.orderListIndex ?? 1) + 1 314 | if (ele.children && ele.children.length > 0) { 315 | let index = 1 316 | for (const c of ele.children) { 317 | let content = await convertDocxToMD(ctx, c, blocks, zip, access, { 318 | parent_prefix: " " + (args.parent_prefix ?? ""), 319 | parentIsTarget: true, 320 | orderListIndex: index 321 | }) 322 | index += 1 323 | md += content 324 | } 325 | } 326 | break 327 | } 328 | case BlockType.bullet: { 329 | continue_block_type = BlockType.bullet 330 | const e = (ele as any).bullet as BlockContent 331 | md += "* " + convertElements(e.elements) + "\n" 332 | if (ele.children && ele.children.length > 0) { 333 | for (const c of ele.children) { 334 | let content = await convertDocxToMD(ctx, c, blocks, zip, access, { 335 | parent_prefix: " " + (args?.parent_prefix ?? ""), 336 | parentIsTarget: true 337 | }) 338 | md += content 339 | } 340 | } 341 | break 342 | } 343 | case BlockType.quote: { 344 | continue_block_type = BlockType.quote 345 | const e = ele.children 346 | md += await convertDocxToMD(ctx, ele.block_id, blocks, zip, access, { parent_prefix: "> " }) + "\n" 347 | break 348 | } 349 | case BlockType.callout: { 350 | continue_block_type = BlockType.callout 351 | const e = ele 352 | md += "\n> [!note]\n" 353 | md += await convertDocxToMD(ctx, ele.block_id, blocks, zip, access, { parent_prefix: "> " }) + "\n" 354 | break 355 | } 356 | case BlockType.image: { 357 | const e = ele as DocxImage 358 | const filename = await downloadAsset(ctx, e.image.token, access, zip) 359 | md += `![](assets/${filename})\n\n` 360 | break 361 | } 362 | case BlockType.grid: { 363 | md += await convertDocxToMD(ctx, ele.block_id, blocks, zip, access, {}) 364 | break 365 | } 366 | case BlockType.grid_column: { 367 | md += await convertDocxToMD(ctx, ele.block_id, blocks, zip, access, {}) 368 | break; 369 | } 370 | case BlockType.divider: { 371 | md += "---\n\n" 372 | await simpleChildrenRender() 373 | break 374 | } 375 | case BlockType.view: { 376 | md += await convertDocxToMD(ctx, ele.block_id, blocks, zip, access, {}) 377 | break 378 | } 379 | case BlockType.file: { 380 | const e = ele as DocxFile 381 | const name = e.file.name 382 | const token = e.file.token 383 | const path = await downloadAsset(ctx, token, access, zip, name) 384 | md += `[${name}](assets/${path})` 385 | break 386 | } 387 | case BlockType.table: { 388 | const e = ele as DocxTable 389 | const cols = e.table.property.column_size 390 | const rows = e.table.property.row_size 391 | const children = e.children 392 | const cells = blocks.filter(b => b.parent_id === e.block_id) 393 | //.map(b => blocks.find(a => a.block_id == b.children[0])) 394 | for (let i = 0; i < rows; i++) { 395 | md += "|" 396 | for (let j = 0; j < cols; j++) { 397 | const index = i * cols + j 398 | const it = cells[index] 399 | if (!it) { 400 | md += " |" 401 | } else { 402 | md += await convertDocxToMD(ctx, it.block_id, blocks, zip, access, { 403 | nonewline: true 404 | }) + " |" 405 | } 406 | } 407 | md += "\n" 408 | if (i === 0) { 409 | md += "|" 410 | for (let j = 0; j < cols; j++) { 411 | md += "---|" 412 | } 413 | md += "\n" 414 | } 415 | } 416 | break 417 | } 418 | case BlockType.tabel_cell: { 419 | const e = ele as DocxBlock 420 | console.log(e) 421 | const cells = blocks.filter(b => b.parent_id === e.block_id) 422 | for (let i = 0; i < cells.length; i++) { 423 | const c = cells[i]; 424 | md += await convertDocxToMD(ctx, c.block_id, blocks, zip, access, { 425 | nonewline: true 426 | }) 427 | } 428 | break; 429 | } 430 | default: 431 | break; 432 | } 433 | tmd += md 434 | } 435 | return tmd 436 | } 437 | const tmp = localforage.createInstance({ 438 | name: 'file_cache' 439 | }) 440 | async function downloadAsset(ctx: ConvertContext, token: string, user_access: string, zip: JSZip, name?: string) { 441 | let c = await tmp.getItem(token) 442 | let ext = { value: "" } 443 | function get_ext(mim: string) { 444 | const mtype = mim.split("/") 445 | if (mtype.length === 2) { 446 | ext.value = "." + mtype[1] 447 | } else { 448 | console.log(mtype) 449 | } 450 | } 451 | if (c) { 452 | let mime = c.mime 453 | get_ext(mime) 454 | zip.folder("assets")?.file(name ? (token + "_" + name) : (token + ext.value), c.data) 455 | } else { 456 | try { 457 | let r = await axios.get(feishu_api(`/drive/v1/medias/${token}/download`), 458 | { 459 | headers: { 'Authorization': 'Bearer ' + user_access }, 460 | responseType: 'arraybuffer' 461 | }) 462 | let mime = r.headers['content-type'] 463 | get_ext(mime) 464 | const data = new Uint8Array(r.data) 465 | zip.folder("assets")?.file(name ? (token + "_" + name) : (token + ext.value), data) 466 | await tmp.setItem(token, { 467 | mime: mime, 468 | data: data 469 | }) 470 | } catch (error) { 471 | console.error(error) 472 | console.log(`下载云空间文件 /drive/v1/medias/${token}/download 失败!`) 473 | } 474 | 475 | } 476 | return name ? (token + "_" + name) : (token + ext.value) 477 | } 478 | 479 | async function makeQPScall(qps: number, ctx: ConvertContext, func: () => Promise>) { 480 | if (ctx.async_tasks.length >= qps) { 481 | await Promise.allSettled(ctx.async_tasks) 482 | ctx.async_tasks = [] 483 | } 484 | const callf = async () => { 485 | try { 486 | const p = await func() 487 | } catch (error) { 488 | makeQPScall(qps, ctx, func) 489 | } 490 | 491 | } 492 | ctx.async_tasks.push(callf()) 493 | } 494 | 495 | enum BlockType { 496 | page = 1, // 497 | text = 2, // 498 | h1 = 3, // 499 | h2 = 4, // 500 | h3 = 5, // 501 | h4 = 6, // 502 | h5, // 503 | h6, // 504 | h7, // 505 | h8, // 506 | h9, // 507 | bullet, // 508 | orderList, // 509 | code, // 510 | ref = 15, // 511 | equation, 512 | todo, // 513 | bitable, 514 | callout = 19, 515 | chat_card, 516 | diagram, 517 | divider, // 518 | file = 23, 519 | grid, // 520 | grid_column, // 521 | iframe, 522 | image, // 523 | widget, 524 | mindnote, 525 | sheet, 526 | table, 527 | tabel_cell, 528 | view, 529 | // ---- 530 | quote = 34, // 531 | unsupport = 999 532 | } 533 | 534 | 535 | interface DocxHeading extends DocxBlock { 536 | heading1: { 537 | elements: element[] 538 | style: BlockStyle 539 | } 540 | heading2: { 541 | elements: element[] 542 | style: BlockStyle 543 | } 544 | heading3: { 545 | elements: element[] 546 | style: BlockStyle 547 | } 548 | heading4: { 549 | elements: element[] 550 | style: BlockStyle 551 | } 552 | heading5: { 553 | elements: element[] 554 | style: BlockStyle 555 | } 556 | heading6: { 557 | elements: element[] 558 | style: BlockStyle 559 | } 560 | heading7: { 561 | elements: element[] 562 | style: BlockStyle 563 | } 564 | heading8: { 565 | elements: element[] 566 | style: BlockStyle 567 | } 568 | heading9: { 569 | elements: element[] 570 | style: BlockStyle 571 | } 572 | } 573 | 574 | const code_language = [ 575 | "PlainText", 576 | "ABAP", 577 | "Ada", 578 | "Apache", 579 | "Apex", 580 | "Assembly", 581 | "Bash", 582 | "CSharp", 583 | "C++", 584 | "C", 585 | "COBOL", 586 | "CSS", 587 | "CoffeeScript", 588 | "D", 589 | "Dart", 590 | "Delphi", 591 | "Django", 592 | "Dockerfile", 593 | "Erlang", 594 | "Fortran", 595 | "FoxPro", 596 | "Go", 597 | "Groovy", 598 | "HTML", 599 | "HTMLBars", 600 | "HTTP", 601 | "Haskell", 602 | "JSON", 603 | "Java", 604 | "JavaScript", 605 | "Julia", 606 | "Kotlin", 607 | "LateX", 608 | "Lisp", 609 | "Logo", 610 | "Lua", 611 | "MATLAB", 612 | "Makefile", 613 | "Markdown", 614 | "Nginx", 615 | "Objective", 616 | "OpenEdgeABL", 617 | "PHP", 618 | "Perl", 619 | "PostScript", 620 | "Power", 621 | "Prolog", 622 | "ProtoBuf", 623 | "Python", 624 | "R", 625 | "RPG", 626 | "Ruby", 627 | "Rust", 628 | "SAS", 629 | "SCSS", 630 | "SQL", 631 | "Scala", 632 | "Scheme", 633 | "Scratch", 634 | "Shell", 635 | "Swift", 636 | "Thrift", 637 | "TypeScript", 638 | "VBScript", 639 | "Visual", 640 | "XML", 641 | "YAML", 642 | "CMake", 643 | "Diff", 644 | "Gherkin", 645 | "GraphQL", 646 | "OpenGL Shading Language", 647 | "Properties", 648 | "Solidity", 649 | "TOML", 650 | ] -------------------------------------------------------------------------------- /src/components/api.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import JSZip from "jszip"; 3 | import { Converter, TmpFile } from "./converter"; 4 | import { MyTreeSelectOption } from "./interface"; 5 | import { stringNullIsDefault } from "../lib/stringUtil"; 6 | import { ConvertDocxToMD } from "./convert_docx"; 7 | import localforage from "localforage"; 8 | import { DialogApiInjection } from "naive-ui/es/dialog/src/DialogProvider"; 9 | import { MessageApiInjection } from "naive-ui/es/message/src/MessageProvider"; 10 | 11 | export const config = { ProxyAPI: false } 12 | 13 | const proxy_url = import.meta.env.VITE_PROXY_API_URL 14 | 15 | export async function testLocalServer() { 16 | if (import.meta.env.VITE_SERVER === undefined) { 17 | config.ProxyAPI = true 18 | return false 19 | } 20 | try { 21 | const r = await fetch(`${import.meta.env.VITE_SERVER}/ping`) 22 | const rj = await r.json() 23 | return rj.code === 0 24 | } catch (error) { 25 | config.ProxyAPI = true 26 | return false 27 | } 28 | 29 | } 30 | 31 | export function feishu_api(url: string) { 32 | if (config.ProxyAPI && !!proxy_url) { 33 | return proxy_url + url 34 | } 35 | return import.meta.env.VITE_API_URL + url 36 | } 37 | 38 | export interface UserLogin { 39 | access_token: string 40 | refresh_token: string 41 | expires_in: number 42 | } 43 | 44 | export interface RootFolder { 45 | token: string 46 | id: string 47 | user_id: string 48 | } 49 | 50 | export interface FoldFileMeta { 51 | name: string 52 | token: string 53 | type: string 54 | } 55 | 56 | export interface FolderFile { 57 | [key: string]: FoldFileMeta 58 | } 59 | 60 | export interface FolderData { 61 | children: FolderFile 62 | parentToken: string 63 | } 64 | 65 | export interface FolderMeta { 66 | id: string 67 | token: string 68 | name: string 69 | parentId: string 70 | } 71 | 72 | export interface DocContentWrapper { 73 | content: string 74 | revision: number 75 | } 76 | 77 | export interface WikiRecord { 78 | space_id: string 79 | name: string 80 | description: string 81 | } 82 | 83 | export interface WikiList { 84 | items: WikiRecord[] 85 | has_more: boolean 86 | page_token: string 87 | } 88 | 89 | export interface NodeRecord { 90 | has_child: boolean 91 | node_token: string 92 | node_type: string 93 | obj_token: string 94 | obj_type: string 95 | origin_node_token: string 96 | origin_space_id: string 97 | parent_node_token: string 98 | space_id: string 99 | title: string 100 | } 101 | 102 | export interface WikiNodeList { 103 | has_more: boolean 104 | page_token: string 105 | items: NodeRecord[] 106 | } 107 | 108 | export interface FolderTokenJson { 109 | token: string 110 | name: string 111 | path: string[] 112 | type: string 113 | } 114 | 115 | export class DocTree { 116 | type: 'doc' | 'dir' | 'root' 117 | token: string 118 | children: DocTree[] 119 | name: string 120 | constructor(type: 'doc' | 'dir' | 'root', token: string, name: string) { 121 | this.type = type 122 | this.token = token 123 | this.children = [] 124 | this.name = name 125 | } 126 | } 127 | 128 | const tmp = localforage.createInstance({ 129 | name: 'file_cache' 130 | }) 131 | 132 | export class FeishuService { 133 | convert = true 134 | message: MessageApiInjection 135 | downloadingCallback?: (file: string) => void 136 | constructor(message: MessageApiInjection, downloadingCallback?: (file: string) => void) { 137 | this.downloadingCallback = downloadingCallback 138 | this.message = message 139 | this.user_expires_in = JSON.parse(window.localStorage.getItem("user_expires_in") ?? "0") 140 | } 141 | dialog?: DialogApiInjection 142 | tenant_access_token?: string 143 | user_access_token?: string 144 | tenant_expires_in?: number 145 | user_expires_in?: number 146 | refresh_token?: string 147 | app_id?: string 148 | app_secret?: string 149 | async userAccess(): Promise { 150 | if (!this.tenant_expires_in || this.tenant_expires_in < Date.now()) { 151 | await this.app_login() 152 | } 153 | try { 154 | if (!this.user_expires_in || this.user_expires_in < Date.now()) { 155 | await this.refresh_user_access(this.refresh_token!, this.tenant_access_token!) 156 | } 157 | } catch (error) { 158 | if (this.dialog) { 159 | this.dialog.error({ 160 | title: "错误", 161 | content: "刷新用户token失败,请重新认证!" 162 | }) 163 | } 164 | } 165 | 166 | return this.user_access_token! 167 | } 168 | 169 | async get_root_folder(): Promise { 170 | let r = await axios.get(feishu_api("/drive/explorer/v2/root_folder/meta"), { 171 | headers: { 172 | "Authorization": `Bearer ${await this.userAccess()}` 173 | } 174 | }) 175 | return r.data.data 176 | } 177 | 178 | async app_login(app_id?: string, app_secret?: string): Promise { 179 | if (!app_id) { 180 | app_id = this.app_id 181 | app_secret = this.app_secret 182 | } 183 | let r = await axios.post(feishu_api("/auth/v3/tenant_access_token/internal/"), { 184 | app_id: app_id, 185 | app_secret: app_secret 186 | }) 187 | let token = r.data 188 | this.tenant_expires_in = Date.now() + (token.expire - 20 * 60) * 1000 189 | this.app_id = app_id 190 | this.app_secret = app_secret 191 | this.tenant_access_token = token.tenant_access_token 192 | return token.tenant_access_token 193 | } 194 | 195 | async user_login(user_temp_code: string, server_token: string): Promise { 196 | let r = await axios.post(feishu_api("/authen/v1/access_token"), { 197 | "grant_type": "authorization_code", 198 | "code": user_temp_code 199 | }, { 200 | headers: { 201 | "Authorization": `Bearer ${server_token}` 202 | } 203 | }) 204 | if (r.data?.code) { 205 | throw new Error(JSON.stringify(r.data)) 206 | } 207 | const user = r.data.data as UserLogin 208 | this.user_expires_in = Date.now() + (user.expires_in - 20 * 60) * 1000 209 | this.user_access_token = user.access_token 210 | this.refresh_token = user.refresh_token 211 | 212 | 213 | window.localStorage.setItem("user_access_token", user.access_token) 214 | window.localStorage.setItem("refresh_token", user.refresh_token) 215 | return user 216 | } 217 | 218 | async refresh_user_access(user_refreash_code: string, server_token: string): Promise { 219 | let r = await axios.post(feishu_api("/authen/v1/refresh_access_token"), { 220 | "grant_type": "refresh_token", 221 | "refresh_token": user_refreash_code 222 | }, { 223 | headers: { 224 | "Authorization": `Bearer ${server_token}` 225 | } 226 | }) 227 | if (r.data?.code) console.log(r.data) 228 | const user = r.data.data as UserLogin 229 | this.user_expires_in = Date.now() + (user.expires_in - 20 * 60) * 1000 230 | this.user_access_token = user.access_token 231 | this.refresh_token = user.refresh_token 232 | 233 | window.localStorage.setItem("user_access_token", user.access_token) 234 | window.localStorage.setItem("refresh_token", user.refresh_token) 235 | window.localStorage.setItem("user_expires_in", JSON.stringify(this.user_expires_in)) 236 | return user 237 | } 238 | 239 | async get_folder_meta(folder_token: string): Promise { 240 | let r = await axios.get(feishu_api(`/drive/explorer/v2/folder/${folder_token}/meta`), { 241 | headers: { 242 | "Authorization": `Bearer ${await this.userAccess()}` 243 | } 244 | }) 245 | return r.data.data 246 | } 247 | 248 | async get_files_in_folder(folder_token: string): Promise { 249 | let r = await axios.get(feishu_api(`/drive/explorer/v2/folder/${folder_token}/children`), { 250 | headers: { 251 | "Authorization": `Bearer ${await this.userAccess()}` 252 | } 253 | }) 254 | return r.data.data 255 | } 256 | 257 | async get_doc(doc_token: string): Promise { 258 | let r = await axios.get(feishu_api(`/doc/v2/${doc_token}/content`), { 259 | headers: { 260 | "Authorization": `Bearer ${await this.userAccess()}` 261 | } 262 | }) 263 | return r.data.data 264 | } 265 | async get_docx_next(doc_token: string, page_token: string): Promise { 266 | let r = await axios.get(feishu_api(`/docx/v1/documents/${doc_token}/blocks?page_token=${page_token}`), { 267 | headers: { 268 | "Authorization": `Bearer ${await this.userAccess()}` 269 | } 270 | }) 271 | 272 | const d = r.data.data 273 | let blocks = d.items 274 | if (d.has_more) { 275 | const page_token = d.page_token 276 | const next = await this.get_docx_next(doc_token, page_token) 277 | blocks = [...blocks, ...next] 278 | } 279 | return blocks 280 | } 281 | async get_docx(doc_token: string): Promise { 282 | if (!doc_token) return null 283 | 284 | try { 285 | let r = await axios.get(feishu_api(`/docx/v1/documents/${doc_token}/blocks`), { 286 | headers: { 287 | "Authorization": `Bearer ${await this.userAccess()}` 288 | } 289 | }) 290 | 291 | const d = r.data.data 292 | let blocks = d.items 293 | if (d.has_more) { 294 | const page_token = d.page_token 295 | const next = await this.get_docx_next(doc_token, page_token) 296 | blocks = [...blocks, ...next] 297 | } 298 | return blocks 299 | } catch (error) { 300 | console.error(error) 301 | console.log(`获取文档 ${doc_token} 失败!`) 302 | this.message.error(`获取文档 ${doc_token} 失败!该文档可能已被删除或者出现网络错误。`) 303 | return null 304 | } 305 | 306 | } 307 | 308 | async get_file(token: string, zip: JSZip, name?: string) { 309 | let c = await tmp.getItem(token) 310 | let ext = "" 311 | if (c) { 312 | let mime = c.mime 313 | const mtype = mime.split("/") 314 | if (mtype.length === 2) { 315 | ext = "." + mtype[1] 316 | } else { 317 | console.log(mtype) 318 | } 319 | zip.file(name ? name : (token + ext), c.data) 320 | } else { 321 | const task = async () => { 322 | let r = await axios.get(feishu_api(`/drive/v1/files/${token}/download`), 323 | { 324 | headers: { 'Authorization': 'Bearer ' + await this.userAccess() }, 325 | responseType: 'arraybuffer' 326 | }) 327 | let mime = r.headers['content-type'] 328 | 329 | if (mime == 'image/png') 330 | ext = ".png" 331 | else if (mime == 'image/jpeg' || mime == 'image/jpg') 332 | ext = ".jpg" 333 | const data = new Uint8Array(r.data) 334 | zip.file(name ? name : (token + ext), data) 335 | await tmp.setItem(token, { 336 | mime: mime, 337 | data: data 338 | }) 339 | return r 340 | } 341 | try { 342 | await task(); 343 | } catch (error) { 344 | console.error(error) 345 | console.log(`下载文件 ${token} 失败!`) 346 | } 347 | } 348 | 349 | return name ? (token + "_" + name) : (token + ext) 350 | } 351 | 352 | async get_all_docs(convert_md: boolean): Promise { 353 | const zipfile = new JSZip() 354 | const convert = new Converter() 355 | this.convert = convert_md 356 | const root = await this.get_root_folder() 357 | await this._r_docs_in_folder(root.token, zipfile, convert) 358 | return await zipfile.generateAsync({ type: 'blob' }) 359 | } 360 | 361 | zipfileName(rawname: string, zip: JSZip, ext: string) { 362 | let name = stringNullIsDefault(rawname, "未命名文档") 363 | let ind = 1 364 | let rename = '' 365 | while (zip.file(name + rename + ext)) { 366 | rename = String(ind) 367 | ind += 1 368 | } 369 | name = name + rename + ext 370 | return name 371 | } 372 | async save_doc(file: FolderTokenJson, zip: JSZip, convert: Converter) { 373 | await this._save_doc(file.token, file.name, zip, convert) 374 | } 375 | async save_docx(file: FolderTokenJson, zip: JSZip) { 376 | await this._save_docx(file.token, file.name, zip) 377 | } 378 | async save_doc_wiki(file: NodeRecord, zip: JSZip, convert: Converter) { 379 | await this._save_doc(file.obj_token, file.title, zip, convert) 380 | } 381 | async save_docx_wiki(file: NodeRecord, zip: JSZip) { 382 | await this._save_docx(file.obj_token, file.title, zip) 383 | } 384 | async _save_doc(token: string, filename: string, zip: JSZip, convert: Converter) { 385 | const file_content = (await this.get_doc(token)).content 386 | let fileobj = JSON.parse(file_content) 387 | 388 | let name = this.zipfileName(filename, zip, ".json") 389 | let mdname = this.zipfileName(filename, zip, ".md") 390 | zip.file(name, JSON.stringify({ node: fileobj, type: "doc" })) 391 | try { 392 | zip.file(mdname, (await convert.convert(await this.userAccess(), zip, fileobj)).file) 393 | } catch (error) { 394 | console.log(error) 395 | zip.file(mdname, JSON.stringify({ error: error, msg: "convert error" })) 396 | } 397 | this.downloadingCallback?.(filename) 398 | } 399 | 400 | async _save_docx(token: string, filename: string, zip: JSZip) { 401 | const content = await this.get_docx(token) 402 | if (!content) return 403 | let name = this.zipfileName(filename, zip, ".json") 404 | let mdname = this.zipfileName(filename, zip, ".md") 405 | zip.file(name, JSON.stringify({ nodes: content, type: "docx" })) 406 | try { 407 | zip.file(mdname, await ConvertDocxToMD({}, "", content, zip, await this.userAccess())) 408 | } 409 | catch (e) { 410 | zip.file(mdname, JSON.stringify({ error: e, msg: "convert error" })) 411 | console.error(e) 412 | } 413 | this.downloadingCallback?.(filename) 414 | } 415 | 416 | async get_some_docs(docs: string[], convert_md: boolean = true): Promise { 417 | const zipfile = new JSZip() 418 | const convert = new Converter() 419 | this.convert = convert_md 420 | for (const it of docs) { 421 | let j: FolderTokenJson = JSON.parse(it) 422 | let zip = zipfile 423 | for (const p of j.path) { 424 | zip = zip.folder(p)! 425 | } 426 | if (j.type === "doc") { 427 | await this.save_doc(j, zip, convert) 428 | } else if (j.type === "docx") { 429 | await this.save_docx(j, zip) 430 | } else if (j.type === "folder") { 431 | await this._r_docs_in_folder(j.token, zip, convert) 432 | } else if (j.type === "file") { 433 | await this.get_file(j.token, zip, j.name) 434 | } 435 | } 436 | 437 | return await zipfile.generateAsync({ type: 'blob' }) 438 | } 439 | 440 | async _r_docs_in_folder(folder_token: string, zipfile: JSZip, convert: Converter) { 441 | const root_folder = await this.get_files_in_folder(folder_token) 442 | for (let f_token in root_folder.children) { 443 | const file = root_folder.children[f_token] 444 | const fd: FolderTokenJson = { 445 | token: file.token, 446 | name: file.name, 447 | path: [""], 448 | type: file.type 449 | } 450 | if (file.type === 'doc') { 451 | await this.save_doc(fd, zipfile, convert) 452 | } else if (file.type === 'folder') { 453 | const fzip = zipfile.folder(file.name) 454 | await this._r_docs_in_folder(file.token, fzip!, convert) 455 | } else if (file.type === 'docx') { 456 | await this.save_docx(fd, zipfile) 457 | } else if (file.type === "file") { 458 | await this.get_file(file.token, zipfile, file.name) 459 | } 460 | } 461 | } 462 | 463 | 464 | async get_all_docs_under_folder(folder_token_json: string, depth: number): Promise { 465 | let options: MyTreeSelectOption[] = [] 466 | let j: FolderTokenJson = JSON.parse(folder_token_json) 467 | const root_folder = await this.get_files_in_folder(j.token) 468 | 469 | const folder_promise = [] 470 | for (let f_token in root_folder.children) { 471 | const file = root_folder.children[f_token] 472 | if (file.type === 'doc' || file.type === "docx") { 473 | let mj: FolderTokenJson = { 474 | token: file.token, 475 | path: [...j.path], 476 | name: file.name, 477 | type: file.type 478 | } 479 | options.push({ 480 | label: stringNullIsDefault(file.name, "未命名文档"), 481 | value: JSON.stringify(mj), 482 | isLeaf: true, 483 | depth: depth + 1 484 | }) 485 | } else if (file.type === 'folder') { 486 | const f = async () => { 487 | let name = (await this.get_folder_meta(file.token)).name 488 | let mj: FolderTokenJson = { 489 | token: file.token, 490 | path: [...j.path, name], 491 | name: '', 492 | type: file.type 493 | } 494 | options.push({ 495 | label: name, 496 | value: JSON.stringify(mj), 497 | isLeaf: false, 498 | depth: depth + 1 499 | }) 500 | } 501 | folder_promise.push(f()) 502 | } else if (file.type === "file") { 503 | let mj: FolderTokenJson = { 504 | token: file.token, 505 | path: [...j.path], 506 | name: file.name, 507 | type: file.type 508 | } 509 | options.push({ 510 | label: stringNullIsDefault(file.name, "未命名文件"), 511 | value: JSON.stringify(mj), 512 | isLeaf: true, 513 | depth: depth + 1 514 | }) 515 | } 516 | } 517 | await Promise.all(folder_promise) 518 | return options 519 | } 520 | 521 | async get_all_docs_list(): Promise { 522 | const root = await this.get_root_folder() 523 | let mj: FolderTokenJson = { 524 | token: root.token, 525 | path: [], 526 | name: '', 527 | type: 'root' 528 | } 529 | return await this.get_all_docs_under_folder(JSON.stringify(mj), 0) 530 | } 531 | 532 | async get_wiki_list(page_token?: string): Promise { 533 | let r = await axios.get(feishu_api(`/wiki/v2/spaces?page_size=10${page_token ? '&page_token=' + page_token : ''}`), { 534 | headers: { 535 | "Authorization": `Bearer ${await this.userAccess()}` 536 | } 537 | }) 538 | const d = r.data.data as WikiList 539 | let list = d.items 540 | if (d.has_more) { 541 | list = [...list, ...await this.get_wiki_list(d.page_token)] 542 | } 543 | return list 544 | } 545 | 546 | async get_wiki_nodes_root(space_id: string, page_token?: string): Promise { 547 | let r = await axios.get(feishu_api(`/wiki/v2/spaces/${space_id}/nodes?page_size=10${page_token ? '&page_token=' + page_token : ''}`), { 548 | headers: { 549 | "Authorization": `Bearer ${await this.userAccess()}` 550 | } 551 | }) 552 | const d = r.data.data as WikiNodeList 553 | let list = d.items 554 | if (d.has_more) { 555 | list = [...list, ...await this.get_wiki_nodes_root(space_id, d.page_token)] 556 | } 557 | return list 558 | } 559 | 560 | async get_wiki_nodes(space_id: string, parent_node: string, page_token?: string): Promise { 561 | let r = await axios.get(feishu_api(`/wiki/v2/spaces/${space_id}/nodes?page_size=10&parent_node_token=${parent_node}${page_token ? '&page_token=' + page_token : ''}`), { 562 | headers: { 563 | "Authorization": `Bearer ${await this.userAccess()}` 564 | } 565 | }) 566 | const d = r.data.data as WikiNodeList 567 | let list = d.items 568 | if (d.has_more) { 569 | list = [...list, ...await this.get_wiki_nodes(space_id, parent_node, d.page_token)] 570 | } 571 | return list 572 | } 573 | 574 | async get_all_wiki_in_space(space_id: string, convert_md: boolean) { 575 | const zipfile = new JSZip() 576 | const convert = new Converter() 577 | this.convert = convert_md 578 | const root = await this.get_wiki_nodes_root(space_id) 579 | await this._r_get_all_wiki_in_space(space_id, root, zipfile, convert) 580 | return await zipfile.generateAsync({ type: 'blob' }) 581 | } 582 | 583 | async get_one_wiki_in_sapce(space_id: string, convert_md: boolean, node: NodeRecord) { 584 | const zipfile = new JSZip() 585 | const convert = new Converter() 586 | this.convert = convert_md 587 | await this._r_get_all_wiki_in_space(space_id, [node], zipfile, convert) 588 | return await zipfile.generateAsync({ type: 'blob' }) 589 | } 590 | 591 | async _r_get_all_wiki_in_space(space_id: string, nodes: NodeRecord[], zipfile: JSZip, convert: Converter) { 592 | for (let node of nodes) { 593 | if (node.has_child) { 594 | let subzip = zipfile.folder(node.title) 595 | let nodes = await this.get_wiki_nodes(space_id, node.node_token) 596 | await this._r_get_all_wiki_in_space(space_id, nodes, subzip!, convert) 597 | } 598 | if (node.obj_type === 'doc') { 599 | await this.save_doc_wiki(node, zipfile, convert) 600 | } else if (node.obj_type === 'docx') { 601 | await this.save_docx_wiki(node, zipfile) 602 | } else { 603 | console.warn("Not Impl doc type: " + node.obj_type) 604 | } 605 | } 606 | } 607 | } 608 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | axios: 12 | specifier: ^1.13.2 13 | version: 1.13.2 14 | file-saver: 15 | specifier: ^2.0.5 16 | version: 2.0.5 17 | jszip: 18 | specifier: ^3.10.1 19 | version: 3.10.1 20 | localforage: 21 | specifier: ^1.10.0 22 | version: 1.10.0 23 | vue: 24 | specifier: ^3.5.25 25 | version: 3.5.25(typescript@5.9.3) 26 | vue-router: 27 | specifier: ^4.6.3 28 | version: 4.6.3(vue@3.5.25(typescript@5.9.3)) 29 | devDependencies: 30 | '@types/file-saver': 31 | specifier: ^2.0.7 32 | version: 2.0.7 33 | '@types/node': 34 | specifier: ^24.10.1 35 | version: 24.10.1 36 | '@vitejs/plugin-vue': 37 | specifier: ^6.0.2 38 | version: 6.0.2(vite@7.2.4(@types/node@24.10.1))(vue@3.5.25(typescript@5.9.3)) 39 | naive-ui: 40 | specifier: ^2.43.2 41 | version: 2.43.2(vue@3.5.25(typescript@5.9.3)) 42 | pnpm: 43 | specifier: ^10.23.0 44 | version: 10.23.0 45 | typescript: 46 | specifier: ^5.9.3 47 | version: 5.9.3 48 | vfonts: 49 | specifier: ^0.1.0 50 | version: 0.1.0 51 | vite: 52 | specifier: ^7.2.4 53 | version: 7.2.4(@types/node@24.10.1) 54 | vue-tsc: 55 | specifier: ^3.1.5 56 | version: 3.1.5(typescript@5.9.3) 57 | 58 | packages: 59 | 60 | '@babel/helper-string-parser@7.27.1': 61 | resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} 62 | engines: {node: '>=6.9.0'} 63 | 64 | '@babel/helper-validator-identifier@7.28.5': 65 | resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} 66 | engines: {node: '>=6.9.0'} 67 | 68 | '@babel/parser@7.28.5': 69 | resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} 70 | engines: {node: '>=6.0.0'} 71 | hasBin: true 72 | 73 | '@babel/types@7.28.5': 74 | resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} 75 | engines: {node: '>=6.9.0'} 76 | 77 | '@css-render/plugin-bem@0.15.14': 78 | resolution: {integrity: sha512-QK513CJ7yEQxm/P3EwsI+d+ha8kSOcjGvD6SevM41neEMxdULE+18iuQK6tEChAWMOQNQPLG/Rw3Khb69r5neg==} 79 | peerDependencies: 80 | css-render: ~0.15.14 81 | 82 | '@css-render/vue3-ssr@0.15.14': 83 | resolution: {integrity: sha512-//8027GSbxE9n3QlD73xFY6z4ZbHbvrOVB7AO6hsmrEzGbg+h2A09HboUyDgu+xsmj7JnvJD39Irt+2D0+iV8g==} 84 | peerDependencies: 85 | vue: ^3.0.11 86 | 87 | '@emotion/hash@0.8.0': 88 | resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} 89 | 90 | '@esbuild/aix-ppc64@0.25.12': 91 | resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} 92 | engines: {node: '>=18'} 93 | cpu: [ppc64] 94 | os: [aix] 95 | 96 | '@esbuild/android-arm64@0.25.12': 97 | resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} 98 | engines: {node: '>=18'} 99 | cpu: [arm64] 100 | os: [android] 101 | 102 | '@esbuild/android-arm@0.25.12': 103 | resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} 104 | engines: {node: '>=18'} 105 | cpu: [arm] 106 | os: [android] 107 | 108 | '@esbuild/android-x64@0.25.12': 109 | resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} 110 | engines: {node: '>=18'} 111 | cpu: [x64] 112 | os: [android] 113 | 114 | '@esbuild/darwin-arm64@0.25.12': 115 | resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} 116 | engines: {node: '>=18'} 117 | cpu: [arm64] 118 | os: [darwin] 119 | 120 | '@esbuild/darwin-x64@0.25.12': 121 | resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} 122 | engines: {node: '>=18'} 123 | cpu: [x64] 124 | os: [darwin] 125 | 126 | '@esbuild/freebsd-arm64@0.25.12': 127 | resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} 128 | engines: {node: '>=18'} 129 | cpu: [arm64] 130 | os: [freebsd] 131 | 132 | '@esbuild/freebsd-x64@0.25.12': 133 | resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} 134 | engines: {node: '>=18'} 135 | cpu: [x64] 136 | os: [freebsd] 137 | 138 | '@esbuild/linux-arm64@0.25.12': 139 | resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} 140 | engines: {node: '>=18'} 141 | cpu: [arm64] 142 | os: [linux] 143 | 144 | '@esbuild/linux-arm@0.25.12': 145 | resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} 146 | engines: {node: '>=18'} 147 | cpu: [arm] 148 | os: [linux] 149 | 150 | '@esbuild/linux-ia32@0.25.12': 151 | resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} 152 | engines: {node: '>=18'} 153 | cpu: [ia32] 154 | os: [linux] 155 | 156 | '@esbuild/linux-loong64@0.25.12': 157 | resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} 158 | engines: {node: '>=18'} 159 | cpu: [loong64] 160 | os: [linux] 161 | 162 | '@esbuild/linux-mips64el@0.25.12': 163 | resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} 164 | engines: {node: '>=18'} 165 | cpu: [mips64el] 166 | os: [linux] 167 | 168 | '@esbuild/linux-ppc64@0.25.12': 169 | resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} 170 | engines: {node: '>=18'} 171 | cpu: [ppc64] 172 | os: [linux] 173 | 174 | '@esbuild/linux-riscv64@0.25.12': 175 | resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} 176 | engines: {node: '>=18'} 177 | cpu: [riscv64] 178 | os: [linux] 179 | 180 | '@esbuild/linux-s390x@0.25.12': 181 | resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} 182 | engines: {node: '>=18'} 183 | cpu: [s390x] 184 | os: [linux] 185 | 186 | '@esbuild/linux-x64@0.25.12': 187 | resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} 188 | engines: {node: '>=18'} 189 | cpu: [x64] 190 | os: [linux] 191 | 192 | '@esbuild/netbsd-arm64@0.25.12': 193 | resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} 194 | engines: {node: '>=18'} 195 | cpu: [arm64] 196 | os: [netbsd] 197 | 198 | '@esbuild/netbsd-x64@0.25.12': 199 | resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} 200 | engines: {node: '>=18'} 201 | cpu: [x64] 202 | os: [netbsd] 203 | 204 | '@esbuild/openbsd-arm64@0.25.12': 205 | resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} 206 | engines: {node: '>=18'} 207 | cpu: [arm64] 208 | os: [openbsd] 209 | 210 | '@esbuild/openbsd-x64@0.25.12': 211 | resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} 212 | engines: {node: '>=18'} 213 | cpu: [x64] 214 | os: [openbsd] 215 | 216 | '@esbuild/openharmony-arm64@0.25.12': 217 | resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} 218 | engines: {node: '>=18'} 219 | cpu: [arm64] 220 | os: [openharmony] 221 | 222 | '@esbuild/sunos-x64@0.25.12': 223 | resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} 224 | engines: {node: '>=18'} 225 | cpu: [x64] 226 | os: [sunos] 227 | 228 | '@esbuild/win32-arm64@0.25.12': 229 | resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} 230 | engines: {node: '>=18'} 231 | cpu: [arm64] 232 | os: [win32] 233 | 234 | '@esbuild/win32-ia32@0.25.12': 235 | resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} 236 | engines: {node: '>=18'} 237 | cpu: [ia32] 238 | os: [win32] 239 | 240 | '@esbuild/win32-x64@0.25.12': 241 | resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} 242 | engines: {node: '>=18'} 243 | cpu: [x64] 244 | os: [win32] 245 | 246 | '@jridgewell/sourcemap-codec@1.5.5': 247 | resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} 248 | 249 | '@juggle/resize-observer@3.4.0': 250 | resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} 251 | 252 | '@rolldown/pluginutils@1.0.0-beta.50': 253 | resolution: {integrity: sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==} 254 | 255 | '@rollup/rollup-android-arm-eabi@4.53.3': 256 | resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} 257 | cpu: [arm] 258 | os: [android] 259 | 260 | '@rollup/rollup-android-arm64@4.53.3': 261 | resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} 262 | cpu: [arm64] 263 | os: [android] 264 | 265 | '@rollup/rollup-darwin-arm64@4.53.3': 266 | resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} 267 | cpu: [arm64] 268 | os: [darwin] 269 | 270 | '@rollup/rollup-darwin-x64@4.53.3': 271 | resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} 272 | cpu: [x64] 273 | os: [darwin] 274 | 275 | '@rollup/rollup-freebsd-arm64@4.53.3': 276 | resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} 277 | cpu: [arm64] 278 | os: [freebsd] 279 | 280 | '@rollup/rollup-freebsd-x64@4.53.3': 281 | resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} 282 | cpu: [x64] 283 | os: [freebsd] 284 | 285 | '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 286 | resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} 287 | cpu: [arm] 288 | os: [linux] 289 | 290 | '@rollup/rollup-linux-arm-musleabihf@4.53.3': 291 | resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} 292 | cpu: [arm] 293 | os: [linux] 294 | 295 | '@rollup/rollup-linux-arm64-gnu@4.53.3': 296 | resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} 297 | cpu: [arm64] 298 | os: [linux] 299 | 300 | '@rollup/rollup-linux-arm64-musl@4.53.3': 301 | resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} 302 | cpu: [arm64] 303 | os: [linux] 304 | 305 | '@rollup/rollup-linux-loong64-gnu@4.53.3': 306 | resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} 307 | cpu: [loong64] 308 | os: [linux] 309 | 310 | '@rollup/rollup-linux-ppc64-gnu@4.53.3': 311 | resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} 312 | cpu: [ppc64] 313 | os: [linux] 314 | 315 | '@rollup/rollup-linux-riscv64-gnu@4.53.3': 316 | resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} 317 | cpu: [riscv64] 318 | os: [linux] 319 | 320 | '@rollup/rollup-linux-riscv64-musl@4.53.3': 321 | resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} 322 | cpu: [riscv64] 323 | os: [linux] 324 | 325 | '@rollup/rollup-linux-s390x-gnu@4.53.3': 326 | resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} 327 | cpu: [s390x] 328 | os: [linux] 329 | 330 | '@rollup/rollup-linux-x64-gnu@4.53.3': 331 | resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} 332 | cpu: [x64] 333 | os: [linux] 334 | 335 | '@rollup/rollup-linux-x64-musl@4.53.3': 336 | resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} 337 | cpu: [x64] 338 | os: [linux] 339 | 340 | '@rollup/rollup-openharmony-arm64@4.53.3': 341 | resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} 342 | cpu: [arm64] 343 | os: [openharmony] 344 | 345 | '@rollup/rollup-win32-arm64-msvc@4.53.3': 346 | resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} 347 | cpu: [arm64] 348 | os: [win32] 349 | 350 | '@rollup/rollup-win32-ia32-msvc@4.53.3': 351 | resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} 352 | cpu: [ia32] 353 | os: [win32] 354 | 355 | '@rollup/rollup-win32-x64-gnu@4.53.3': 356 | resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} 357 | cpu: [x64] 358 | os: [win32] 359 | 360 | '@rollup/rollup-win32-x64-msvc@4.53.3': 361 | resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} 362 | cpu: [x64] 363 | os: [win32] 364 | 365 | '@types/estree@1.0.8': 366 | resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 367 | 368 | '@types/file-saver@2.0.7': 369 | resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==} 370 | 371 | '@types/katex@0.16.7': 372 | resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} 373 | 374 | '@types/lodash-es@4.17.12': 375 | resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} 376 | 377 | '@types/lodash@4.17.21': 378 | resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} 379 | 380 | '@types/node@24.10.1': 381 | resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} 382 | 383 | '@vitejs/plugin-vue@6.0.2': 384 | resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==} 385 | engines: {node: ^20.19.0 || >=22.12.0} 386 | peerDependencies: 387 | vite: ^5.0.0 || ^6.0.0 || ^7.0.0 388 | vue: ^3.2.25 389 | 390 | '@volar/language-core@2.4.23': 391 | resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==} 392 | 393 | '@volar/source-map@2.4.23': 394 | resolution: {integrity: sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==} 395 | 396 | '@volar/typescript@2.4.23': 397 | resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==} 398 | 399 | '@vue/compiler-core@3.5.25': 400 | resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} 401 | 402 | '@vue/compiler-dom@3.5.25': 403 | resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} 404 | 405 | '@vue/compiler-sfc@3.5.25': 406 | resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} 407 | 408 | '@vue/compiler-ssr@3.5.25': 409 | resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} 410 | 411 | '@vue/devtools-api@6.6.4': 412 | resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} 413 | 414 | '@vue/language-core@3.1.5': 415 | resolution: {integrity: sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w==} 416 | peerDependencies: 417 | typescript: '*' 418 | peerDependenciesMeta: 419 | typescript: 420 | optional: true 421 | 422 | '@vue/reactivity@3.5.25': 423 | resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==} 424 | 425 | '@vue/runtime-core@3.5.25': 426 | resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==} 427 | 428 | '@vue/runtime-dom@3.5.25': 429 | resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==} 430 | 431 | '@vue/server-renderer@3.5.25': 432 | resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==} 433 | peerDependencies: 434 | vue: 3.5.25 435 | 436 | '@vue/shared@3.5.25': 437 | resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} 438 | 439 | alien-signals@3.1.1: 440 | resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==} 441 | 442 | async-validator@4.2.5: 443 | resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} 444 | 445 | asynckit@0.4.0: 446 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 447 | 448 | axios@1.13.2: 449 | resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} 450 | 451 | call-bind-apply-helpers@1.0.2: 452 | resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} 453 | engines: {node: '>= 0.4'} 454 | 455 | combined-stream@1.0.8: 456 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 457 | engines: {node: '>= 0.8'} 458 | 459 | core-util-is@1.0.3: 460 | resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} 461 | 462 | css-render@0.15.14: 463 | resolution: {integrity: sha512-9nF4PdUle+5ta4W5SyZdLCCmFd37uVimSjg1evcTqKJCyvCEEj12WKzOSBNak6r4im4J4iYXKH1OWpUV5LBYFg==} 464 | 465 | csstype@3.0.11: 466 | resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==} 467 | 468 | csstype@3.2.3: 469 | resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} 470 | 471 | date-fns-tz@3.2.0: 472 | resolution: {integrity: sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==} 473 | peerDependencies: 474 | date-fns: ^3.0.0 || ^4.0.0 475 | 476 | date-fns@4.1.0: 477 | resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} 478 | 479 | delayed-stream@1.0.0: 480 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 481 | engines: {node: '>=0.4.0'} 482 | 483 | dunder-proto@1.0.1: 484 | resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} 485 | engines: {node: '>= 0.4'} 486 | 487 | entities@4.5.0: 488 | resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} 489 | engines: {node: '>=0.12'} 490 | 491 | es-define-property@1.0.1: 492 | resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} 493 | engines: {node: '>= 0.4'} 494 | 495 | es-errors@1.3.0: 496 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 497 | engines: {node: '>= 0.4'} 498 | 499 | es-object-atoms@1.1.1: 500 | resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} 501 | engines: {node: '>= 0.4'} 502 | 503 | es-set-tostringtag@2.1.0: 504 | resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} 505 | engines: {node: '>= 0.4'} 506 | 507 | esbuild@0.25.12: 508 | resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} 509 | engines: {node: '>=18'} 510 | hasBin: true 511 | 512 | estree-walker@2.0.2: 513 | resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 514 | 515 | evtd@0.2.4: 516 | resolution: {integrity: sha512-qaeGN5bx63s/AXgQo8gj6fBkxge+OoLddLniox5qtLAEY5HSnuSlISXVPxnSae1dWblvTh4/HoMIB+mbMsvZzw==} 517 | 518 | fdir@6.5.0: 519 | resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 520 | engines: {node: '>=12.0.0'} 521 | peerDependencies: 522 | picomatch: ^3 || ^4 523 | peerDependenciesMeta: 524 | picomatch: 525 | optional: true 526 | 527 | file-saver@2.0.5: 528 | resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==} 529 | 530 | follow-redirects@1.15.11: 531 | resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} 532 | engines: {node: '>=4.0'} 533 | peerDependencies: 534 | debug: '*' 535 | peerDependenciesMeta: 536 | debug: 537 | optional: true 538 | 539 | form-data@4.0.5: 540 | resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} 541 | engines: {node: '>= 6'} 542 | 543 | fsevents@2.3.3: 544 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 545 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 546 | os: [darwin] 547 | 548 | function-bind@1.1.2: 549 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 550 | 551 | get-intrinsic@1.3.0: 552 | resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} 553 | engines: {node: '>= 0.4'} 554 | 555 | get-proto@1.0.1: 556 | resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} 557 | engines: {node: '>= 0.4'} 558 | 559 | gopd@1.2.0: 560 | resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} 561 | engines: {node: '>= 0.4'} 562 | 563 | has-symbols@1.1.0: 564 | resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} 565 | engines: {node: '>= 0.4'} 566 | 567 | has-tostringtag@1.0.2: 568 | resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} 569 | engines: {node: '>= 0.4'} 570 | 571 | hasown@2.0.2: 572 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 573 | engines: {node: '>= 0.4'} 574 | 575 | highlight.js@11.11.1: 576 | resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} 577 | engines: {node: '>=12.0.0'} 578 | 579 | immediate@3.0.6: 580 | resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} 581 | 582 | inherits@2.0.4: 583 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 584 | 585 | isarray@1.0.0: 586 | resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} 587 | 588 | jszip@3.10.1: 589 | resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} 590 | 591 | lie@3.1.1: 592 | resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==} 593 | 594 | lie@3.3.0: 595 | resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} 596 | 597 | localforage@1.10.0: 598 | resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} 599 | 600 | lodash-es@4.17.21: 601 | resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} 602 | 603 | lodash@4.17.21: 604 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 605 | 606 | magic-string@0.30.21: 607 | resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} 608 | 609 | math-intrinsics@1.1.0: 610 | resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} 611 | engines: {node: '>= 0.4'} 612 | 613 | mime-db@1.52.0: 614 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 615 | engines: {node: '>= 0.6'} 616 | 617 | mime-types@2.1.35: 618 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 619 | engines: {node: '>= 0.6'} 620 | 621 | muggle-string@0.4.1: 622 | resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} 623 | 624 | naive-ui@2.43.2: 625 | resolution: {integrity: sha512-YlLMnGrwGTOc+zMj90sG3ubaH5/7czsgLgGcjTLA981IUaz8r6t4WIujNt8r9PNr+dqv6XNEr0vxkARgPPjfBQ==} 626 | peerDependencies: 627 | vue: ^3.0.0 628 | 629 | nanoid@3.3.11: 630 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 631 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 632 | hasBin: true 633 | 634 | pako@1.0.11: 635 | resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} 636 | 637 | path-browserify@1.0.1: 638 | resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} 639 | 640 | picocolors@1.1.1: 641 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 642 | 643 | picomatch@4.0.3: 644 | resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} 645 | engines: {node: '>=12'} 646 | 647 | pnpm@10.23.0: 648 | resolution: {integrity: sha512-IcTlaYACrel+Tv6Li0qJqN48haN5GflX56DzDzj7xbvdBZgP/ikXmy+25uaRJC4JjZRdFgF3LK0P71+2QR4qSw==} 649 | engines: {node: '>=18.12'} 650 | hasBin: true 651 | 652 | postcss@8.5.6: 653 | resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 654 | engines: {node: ^10 || ^12 || >=14} 655 | 656 | process-nextick-args@2.0.1: 657 | resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} 658 | 659 | proxy-from-env@1.1.0: 660 | resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} 661 | 662 | readable-stream@2.3.8: 663 | resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} 664 | 665 | rollup@4.53.3: 666 | resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} 667 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 668 | hasBin: true 669 | 670 | safe-buffer@5.1.2: 671 | resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} 672 | 673 | seemly@0.3.10: 674 | resolution: {integrity: sha512-2+SMxtG1PcsL0uyhkumlOU6Qo9TAQ/WyH7tthnPIOQB05/12jz9naq6GZ6iZ6ApVsO3rr2gsnTf3++OV63kE1Q==} 675 | 676 | setimmediate@1.0.5: 677 | resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} 678 | 679 | source-map-js@1.2.1: 680 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 681 | engines: {node: '>=0.10.0'} 682 | 683 | string_decoder@1.1.1: 684 | resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} 685 | 686 | tinyglobby@0.2.15: 687 | resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} 688 | engines: {node: '>=12.0.0'} 689 | 690 | treemate@0.3.11: 691 | resolution: {integrity: sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==} 692 | 693 | typescript@5.9.3: 694 | resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} 695 | engines: {node: '>=14.17'} 696 | hasBin: true 697 | 698 | undici-types@7.16.0: 699 | resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} 700 | 701 | util-deprecate@1.0.2: 702 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 703 | 704 | vdirs@0.1.8: 705 | resolution: {integrity: sha512-H9V1zGRLQZg9b+GdMk8MXDN2Lva0zx72MPahDKc30v+DtwKjfyOSXWRIX4t2mhDubM1H09gPhWeth/BJWPHGUw==} 706 | peerDependencies: 707 | vue: ^3.0.11 708 | 709 | vfonts@0.1.0: 710 | resolution: {integrity: sha512-vQBcvntBlnAPonAkGNM8iJ9NxE3PucA+V2W95xiN75YJKxirLJvOws2kEyOEO45T4N+YTbQOCR2m77Y05pfVhQ==} 711 | 712 | vite@7.2.4: 713 | resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} 714 | engines: {node: ^20.19.0 || >=22.12.0} 715 | hasBin: true 716 | peerDependencies: 717 | '@types/node': ^20.19.0 || >=22.12.0 718 | jiti: '>=1.21.0' 719 | less: ^4.0.0 720 | lightningcss: ^1.21.0 721 | sass: ^1.70.0 722 | sass-embedded: ^1.70.0 723 | stylus: '>=0.54.8' 724 | sugarss: ^5.0.0 725 | terser: ^5.16.0 726 | tsx: ^4.8.1 727 | yaml: ^2.4.2 728 | peerDependenciesMeta: 729 | '@types/node': 730 | optional: true 731 | jiti: 732 | optional: true 733 | less: 734 | optional: true 735 | lightningcss: 736 | optional: true 737 | sass: 738 | optional: true 739 | sass-embedded: 740 | optional: true 741 | stylus: 742 | optional: true 743 | sugarss: 744 | optional: true 745 | terser: 746 | optional: true 747 | tsx: 748 | optional: true 749 | yaml: 750 | optional: true 751 | 752 | vooks@0.2.12: 753 | resolution: {integrity: sha512-iox0I3RZzxtKlcgYaStQYKEzWWGAduMmq+jS7OrNdQo1FgGfPMubGL3uGHOU9n97NIvfFDBGnpSvkWyb/NSn/Q==} 754 | peerDependencies: 755 | vue: ^3.0.0 756 | 757 | vscode-uri@3.1.0: 758 | resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} 759 | 760 | vue-router@4.6.3: 761 | resolution: {integrity: sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==} 762 | peerDependencies: 763 | vue: ^3.5.0 764 | 765 | vue-tsc@3.1.5: 766 | resolution: {integrity: sha512-L/G9IUjOWhBU0yun89rv8fKqmKC+T0HfhrFjlIml71WpfBv9eb4E9Bev8FMbyueBIU9vxQqbd+oOsVcDa5amGw==} 767 | hasBin: true 768 | peerDependencies: 769 | typescript: '>=5.0.0' 770 | 771 | vue@3.5.25: 772 | resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} 773 | peerDependencies: 774 | typescript: '*' 775 | peerDependenciesMeta: 776 | typescript: 777 | optional: true 778 | 779 | vueuc@0.4.65: 780 | resolution: {integrity: sha512-lXuMl+8gsBmruudfxnMF9HW4be8rFziylXFu1VHVNbLVhRTXXV4njvpRuJapD/8q+oFEMSfQMH16E/85VoWRyQ==} 781 | peerDependencies: 782 | vue: ^3.0.11 783 | 784 | snapshots: 785 | 786 | '@babel/helper-string-parser@7.27.1': {} 787 | 788 | '@babel/helper-validator-identifier@7.28.5': {} 789 | 790 | '@babel/parser@7.28.5': 791 | dependencies: 792 | '@babel/types': 7.28.5 793 | 794 | '@babel/types@7.28.5': 795 | dependencies: 796 | '@babel/helper-string-parser': 7.27.1 797 | '@babel/helper-validator-identifier': 7.28.5 798 | 799 | '@css-render/plugin-bem@0.15.14(css-render@0.15.14)': 800 | dependencies: 801 | css-render: 0.15.14 802 | 803 | '@css-render/vue3-ssr@0.15.14(vue@3.5.25(typescript@5.9.3))': 804 | dependencies: 805 | vue: 3.5.25(typescript@5.9.3) 806 | 807 | '@emotion/hash@0.8.0': {} 808 | 809 | '@esbuild/aix-ppc64@0.25.12': 810 | optional: true 811 | 812 | '@esbuild/android-arm64@0.25.12': 813 | optional: true 814 | 815 | '@esbuild/android-arm@0.25.12': 816 | optional: true 817 | 818 | '@esbuild/android-x64@0.25.12': 819 | optional: true 820 | 821 | '@esbuild/darwin-arm64@0.25.12': 822 | optional: true 823 | 824 | '@esbuild/darwin-x64@0.25.12': 825 | optional: true 826 | 827 | '@esbuild/freebsd-arm64@0.25.12': 828 | optional: true 829 | 830 | '@esbuild/freebsd-x64@0.25.12': 831 | optional: true 832 | 833 | '@esbuild/linux-arm64@0.25.12': 834 | optional: true 835 | 836 | '@esbuild/linux-arm@0.25.12': 837 | optional: true 838 | 839 | '@esbuild/linux-ia32@0.25.12': 840 | optional: true 841 | 842 | '@esbuild/linux-loong64@0.25.12': 843 | optional: true 844 | 845 | '@esbuild/linux-mips64el@0.25.12': 846 | optional: true 847 | 848 | '@esbuild/linux-ppc64@0.25.12': 849 | optional: true 850 | 851 | '@esbuild/linux-riscv64@0.25.12': 852 | optional: true 853 | 854 | '@esbuild/linux-s390x@0.25.12': 855 | optional: true 856 | 857 | '@esbuild/linux-x64@0.25.12': 858 | optional: true 859 | 860 | '@esbuild/netbsd-arm64@0.25.12': 861 | optional: true 862 | 863 | '@esbuild/netbsd-x64@0.25.12': 864 | optional: true 865 | 866 | '@esbuild/openbsd-arm64@0.25.12': 867 | optional: true 868 | 869 | '@esbuild/openbsd-x64@0.25.12': 870 | optional: true 871 | 872 | '@esbuild/openharmony-arm64@0.25.12': 873 | optional: true 874 | 875 | '@esbuild/sunos-x64@0.25.12': 876 | optional: true 877 | 878 | '@esbuild/win32-arm64@0.25.12': 879 | optional: true 880 | 881 | '@esbuild/win32-ia32@0.25.12': 882 | optional: true 883 | 884 | '@esbuild/win32-x64@0.25.12': 885 | optional: true 886 | 887 | '@jridgewell/sourcemap-codec@1.5.5': {} 888 | 889 | '@juggle/resize-observer@3.4.0': {} 890 | 891 | '@rolldown/pluginutils@1.0.0-beta.50': {} 892 | 893 | '@rollup/rollup-android-arm-eabi@4.53.3': 894 | optional: true 895 | 896 | '@rollup/rollup-android-arm64@4.53.3': 897 | optional: true 898 | 899 | '@rollup/rollup-darwin-arm64@4.53.3': 900 | optional: true 901 | 902 | '@rollup/rollup-darwin-x64@4.53.3': 903 | optional: true 904 | 905 | '@rollup/rollup-freebsd-arm64@4.53.3': 906 | optional: true 907 | 908 | '@rollup/rollup-freebsd-x64@4.53.3': 909 | optional: true 910 | 911 | '@rollup/rollup-linux-arm-gnueabihf@4.53.3': 912 | optional: true 913 | 914 | '@rollup/rollup-linux-arm-musleabihf@4.53.3': 915 | optional: true 916 | 917 | '@rollup/rollup-linux-arm64-gnu@4.53.3': 918 | optional: true 919 | 920 | '@rollup/rollup-linux-arm64-musl@4.53.3': 921 | optional: true 922 | 923 | '@rollup/rollup-linux-loong64-gnu@4.53.3': 924 | optional: true 925 | 926 | '@rollup/rollup-linux-ppc64-gnu@4.53.3': 927 | optional: true 928 | 929 | '@rollup/rollup-linux-riscv64-gnu@4.53.3': 930 | optional: true 931 | 932 | '@rollup/rollup-linux-riscv64-musl@4.53.3': 933 | optional: true 934 | 935 | '@rollup/rollup-linux-s390x-gnu@4.53.3': 936 | optional: true 937 | 938 | '@rollup/rollup-linux-x64-gnu@4.53.3': 939 | optional: true 940 | 941 | '@rollup/rollup-linux-x64-musl@4.53.3': 942 | optional: true 943 | 944 | '@rollup/rollup-openharmony-arm64@4.53.3': 945 | optional: true 946 | 947 | '@rollup/rollup-win32-arm64-msvc@4.53.3': 948 | optional: true 949 | 950 | '@rollup/rollup-win32-ia32-msvc@4.53.3': 951 | optional: true 952 | 953 | '@rollup/rollup-win32-x64-gnu@4.53.3': 954 | optional: true 955 | 956 | '@rollup/rollup-win32-x64-msvc@4.53.3': 957 | optional: true 958 | 959 | '@types/estree@1.0.8': {} 960 | 961 | '@types/file-saver@2.0.7': {} 962 | 963 | '@types/katex@0.16.7': {} 964 | 965 | '@types/lodash-es@4.17.12': 966 | dependencies: 967 | '@types/lodash': 4.17.21 968 | 969 | '@types/lodash@4.17.21': {} 970 | 971 | '@types/node@24.10.1': 972 | dependencies: 973 | undici-types: 7.16.0 974 | 975 | '@vitejs/plugin-vue@6.0.2(vite@7.2.4(@types/node@24.10.1))(vue@3.5.25(typescript@5.9.3))': 976 | dependencies: 977 | '@rolldown/pluginutils': 1.0.0-beta.50 978 | vite: 7.2.4(@types/node@24.10.1) 979 | vue: 3.5.25(typescript@5.9.3) 980 | 981 | '@volar/language-core@2.4.23': 982 | dependencies: 983 | '@volar/source-map': 2.4.23 984 | 985 | '@volar/source-map@2.4.23': {} 986 | 987 | '@volar/typescript@2.4.23': 988 | dependencies: 989 | '@volar/language-core': 2.4.23 990 | path-browserify: 1.0.1 991 | vscode-uri: 3.1.0 992 | 993 | '@vue/compiler-core@3.5.25': 994 | dependencies: 995 | '@babel/parser': 7.28.5 996 | '@vue/shared': 3.5.25 997 | entities: 4.5.0 998 | estree-walker: 2.0.2 999 | source-map-js: 1.2.1 1000 | 1001 | '@vue/compiler-dom@3.5.25': 1002 | dependencies: 1003 | '@vue/compiler-core': 3.5.25 1004 | '@vue/shared': 3.5.25 1005 | 1006 | '@vue/compiler-sfc@3.5.25': 1007 | dependencies: 1008 | '@babel/parser': 7.28.5 1009 | '@vue/compiler-core': 3.5.25 1010 | '@vue/compiler-dom': 3.5.25 1011 | '@vue/compiler-ssr': 3.5.25 1012 | '@vue/shared': 3.5.25 1013 | estree-walker: 2.0.2 1014 | magic-string: 0.30.21 1015 | postcss: 8.5.6 1016 | source-map-js: 1.2.1 1017 | 1018 | '@vue/compiler-ssr@3.5.25': 1019 | dependencies: 1020 | '@vue/compiler-dom': 3.5.25 1021 | '@vue/shared': 3.5.25 1022 | 1023 | '@vue/devtools-api@6.6.4': {} 1024 | 1025 | '@vue/language-core@3.1.5(typescript@5.9.3)': 1026 | dependencies: 1027 | '@volar/language-core': 2.4.23 1028 | '@vue/compiler-dom': 3.5.25 1029 | '@vue/shared': 3.5.25 1030 | alien-signals: 3.1.1 1031 | muggle-string: 0.4.1 1032 | path-browserify: 1.0.1 1033 | picomatch: 4.0.3 1034 | optionalDependencies: 1035 | typescript: 5.9.3 1036 | 1037 | '@vue/reactivity@3.5.25': 1038 | dependencies: 1039 | '@vue/shared': 3.5.25 1040 | 1041 | '@vue/runtime-core@3.5.25': 1042 | dependencies: 1043 | '@vue/reactivity': 3.5.25 1044 | '@vue/shared': 3.5.25 1045 | 1046 | '@vue/runtime-dom@3.5.25': 1047 | dependencies: 1048 | '@vue/reactivity': 3.5.25 1049 | '@vue/runtime-core': 3.5.25 1050 | '@vue/shared': 3.5.25 1051 | csstype: 3.2.3 1052 | 1053 | '@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))': 1054 | dependencies: 1055 | '@vue/compiler-ssr': 3.5.25 1056 | '@vue/shared': 3.5.25 1057 | vue: 3.5.25(typescript@5.9.3) 1058 | 1059 | '@vue/shared@3.5.25': {} 1060 | 1061 | alien-signals@3.1.1: {} 1062 | 1063 | async-validator@4.2.5: {} 1064 | 1065 | asynckit@0.4.0: {} 1066 | 1067 | axios@1.13.2: 1068 | dependencies: 1069 | follow-redirects: 1.15.11 1070 | form-data: 4.0.5 1071 | proxy-from-env: 1.1.0 1072 | transitivePeerDependencies: 1073 | - debug 1074 | 1075 | call-bind-apply-helpers@1.0.2: 1076 | dependencies: 1077 | es-errors: 1.3.0 1078 | function-bind: 1.1.2 1079 | 1080 | combined-stream@1.0.8: 1081 | dependencies: 1082 | delayed-stream: 1.0.0 1083 | 1084 | core-util-is@1.0.3: {} 1085 | 1086 | css-render@0.15.14: 1087 | dependencies: 1088 | '@emotion/hash': 0.8.0 1089 | csstype: 3.0.11 1090 | 1091 | csstype@3.0.11: {} 1092 | 1093 | csstype@3.2.3: {} 1094 | 1095 | date-fns-tz@3.2.0(date-fns@4.1.0): 1096 | dependencies: 1097 | date-fns: 4.1.0 1098 | 1099 | date-fns@4.1.0: {} 1100 | 1101 | delayed-stream@1.0.0: {} 1102 | 1103 | dunder-proto@1.0.1: 1104 | dependencies: 1105 | call-bind-apply-helpers: 1.0.2 1106 | es-errors: 1.3.0 1107 | gopd: 1.2.0 1108 | 1109 | entities@4.5.0: {} 1110 | 1111 | es-define-property@1.0.1: {} 1112 | 1113 | es-errors@1.3.0: {} 1114 | 1115 | es-object-atoms@1.1.1: 1116 | dependencies: 1117 | es-errors: 1.3.0 1118 | 1119 | es-set-tostringtag@2.1.0: 1120 | dependencies: 1121 | es-errors: 1.3.0 1122 | get-intrinsic: 1.3.0 1123 | has-tostringtag: 1.0.2 1124 | hasown: 2.0.2 1125 | 1126 | esbuild@0.25.12: 1127 | optionalDependencies: 1128 | '@esbuild/aix-ppc64': 0.25.12 1129 | '@esbuild/android-arm': 0.25.12 1130 | '@esbuild/android-arm64': 0.25.12 1131 | '@esbuild/android-x64': 0.25.12 1132 | '@esbuild/darwin-arm64': 0.25.12 1133 | '@esbuild/darwin-x64': 0.25.12 1134 | '@esbuild/freebsd-arm64': 0.25.12 1135 | '@esbuild/freebsd-x64': 0.25.12 1136 | '@esbuild/linux-arm': 0.25.12 1137 | '@esbuild/linux-arm64': 0.25.12 1138 | '@esbuild/linux-ia32': 0.25.12 1139 | '@esbuild/linux-loong64': 0.25.12 1140 | '@esbuild/linux-mips64el': 0.25.12 1141 | '@esbuild/linux-ppc64': 0.25.12 1142 | '@esbuild/linux-riscv64': 0.25.12 1143 | '@esbuild/linux-s390x': 0.25.12 1144 | '@esbuild/linux-x64': 0.25.12 1145 | '@esbuild/netbsd-arm64': 0.25.12 1146 | '@esbuild/netbsd-x64': 0.25.12 1147 | '@esbuild/openbsd-arm64': 0.25.12 1148 | '@esbuild/openbsd-x64': 0.25.12 1149 | '@esbuild/openharmony-arm64': 0.25.12 1150 | '@esbuild/sunos-x64': 0.25.12 1151 | '@esbuild/win32-arm64': 0.25.12 1152 | '@esbuild/win32-ia32': 0.25.12 1153 | '@esbuild/win32-x64': 0.25.12 1154 | 1155 | estree-walker@2.0.2: {} 1156 | 1157 | evtd@0.2.4: {} 1158 | 1159 | fdir@6.5.0(picomatch@4.0.3): 1160 | optionalDependencies: 1161 | picomatch: 4.0.3 1162 | 1163 | file-saver@2.0.5: {} 1164 | 1165 | follow-redirects@1.15.11: {} 1166 | 1167 | form-data@4.0.5: 1168 | dependencies: 1169 | asynckit: 0.4.0 1170 | combined-stream: 1.0.8 1171 | es-set-tostringtag: 2.1.0 1172 | hasown: 2.0.2 1173 | mime-types: 2.1.35 1174 | 1175 | fsevents@2.3.3: 1176 | optional: true 1177 | 1178 | function-bind@1.1.2: {} 1179 | 1180 | get-intrinsic@1.3.0: 1181 | dependencies: 1182 | call-bind-apply-helpers: 1.0.2 1183 | es-define-property: 1.0.1 1184 | es-errors: 1.3.0 1185 | es-object-atoms: 1.1.1 1186 | function-bind: 1.1.2 1187 | get-proto: 1.0.1 1188 | gopd: 1.2.0 1189 | has-symbols: 1.1.0 1190 | hasown: 2.0.2 1191 | math-intrinsics: 1.1.0 1192 | 1193 | get-proto@1.0.1: 1194 | dependencies: 1195 | dunder-proto: 1.0.1 1196 | es-object-atoms: 1.1.1 1197 | 1198 | gopd@1.2.0: {} 1199 | 1200 | has-symbols@1.1.0: {} 1201 | 1202 | has-tostringtag@1.0.2: 1203 | dependencies: 1204 | has-symbols: 1.1.0 1205 | 1206 | hasown@2.0.2: 1207 | dependencies: 1208 | function-bind: 1.1.2 1209 | 1210 | highlight.js@11.11.1: {} 1211 | 1212 | immediate@3.0.6: {} 1213 | 1214 | inherits@2.0.4: {} 1215 | 1216 | isarray@1.0.0: {} 1217 | 1218 | jszip@3.10.1: 1219 | dependencies: 1220 | lie: 3.3.0 1221 | pako: 1.0.11 1222 | readable-stream: 2.3.8 1223 | setimmediate: 1.0.5 1224 | 1225 | lie@3.1.1: 1226 | dependencies: 1227 | immediate: 3.0.6 1228 | 1229 | lie@3.3.0: 1230 | dependencies: 1231 | immediate: 3.0.6 1232 | 1233 | localforage@1.10.0: 1234 | dependencies: 1235 | lie: 3.1.1 1236 | 1237 | lodash-es@4.17.21: {} 1238 | 1239 | lodash@4.17.21: {} 1240 | 1241 | magic-string@0.30.21: 1242 | dependencies: 1243 | '@jridgewell/sourcemap-codec': 1.5.5 1244 | 1245 | math-intrinsics@1.1.0: {} 1246 | 1247 | mime-db@1.52.0: {} 1248 | 1249 | mime-types@2.1.35: 1250 | dependencies: 1251 | mime-db: 1.52.0 1252 | 1253 | muggle-string@0.4.1: {} 1254 | 1255 | naive-ui@2.43.2(vue@3.5.25(typescript@5.9.3)): 1256 | dependencies: 1257 | '@css-render/plugin-bem': 0.15.14(css-render@0.15.14) 1258 | '@css-render/vue3-ssr': 0.15.14(vue@3.5.25(typescript@5.9.3)) 1259 | '@types/katex': 0.16.7 1260 | '@types/lodash': 4.17.21 1261 | '@types/lodash-es': 4.17.12 1262 | async-validator: 4.2.5 1263 | css-render: 0.15.14 1264 | csstype: 3.2.3 1265 | date-fns: 4.1.0 1266 | date-fns-tz: 3.2.0(date-fns@4.1.0) 1267 | evtd: 0.2.4 1268 | highlight.js: 11.11.1 1269 | lodash: 4.17.21 1270 | lodash-es: 4.17.21 1271 | seemly: 0.3.10 1272 | treemate: 0.3.11 1273 | vdirs: 0.1.8(vue@3.5.25(typescript@5.9.3)) 1274 | vooks: 0.2.12(vue@3.5.25(typescript@5.9.3)) 1275 | vue: 3.5.25(typescript@5.9.3) 1276 | vueuc: 0.4.65(vue@3.5.25(typescript@5.9.3)) 1277 | 1278 | nanoid@3.3.11: {} 1279 | 1280 | pako@1.0.11: {} 1281 | 1282 | path-browserify@1.0.1: {} 1283 | 1284 | picocolors@1.1.1: {} 1285 | 1286 | picomatch@4.0.3: {} 1287 | 1288 | pnpm@10.23.0: {} 1289 | 1290 | postcss@8.5.6: 1291 | dependencies: 1292 | nanoid: 3.3.11 1293 | picocolors: 1.1.1 1294 | source-map-js: 1.2.1 1295 | 1296 | process-nextick-args@2.0.1: {} 1297 | 1298 | proxy-from-env@1.1.0: {} 1299 | 1300 | readable-stream@2.3.8: 1301 | dependencies: 1302 | core-util-is: 1.0.3 1303 | inherits: 2.0.4 1304 | isarray: 1.0.0 1305 | process-nextick-args: 2.0.1 1306 | safe-buffer: 5.1.2 1307 | string_decoder: 1.1.1 1308 | util-deprecate: 1.0.2 1309 | 1310 | rollup@4.53.3: 1311 | dependencies: 1312 | '@types/estree': 1.0.8 1313 | optionalDependencies: 1314 | '@rollup/rollup-android-arm-eabi': 4.53.3 1315 | '@rollup/rollup-android-arm64': 4.53.3 1316 | '@rollup/rollup-darwin-arm64': 4.53.3 1317 | '@rollup/rollup-darwin-x64': 4.53.3 1318 | '@rollup/rollup-freebsd-arm64': 4.53.3 1319 | '@rollup/rollup-freebsd-x64': 4.53.3 1320 | '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 1321 | '@rollup/rollup-linux-arm-musleabihf': 4.53.3 1322 | '@rollup/rollup-linux-arm64-gnu': 4.53.3 1323 | '@rollup/rollup-linux-arm64-musl': 4.53.3 1324 | '@rollup/rollup-linux-loong64-gnu': 4.53.3 1325 | '@rollup/rollup-linux-ppc64-gnu': 4.53.3 1326 | '@rollup/rollup-linux-riscv64-gnu': 4.53.3 1327 | '@rollup/rollup-linux-riscv64-musl': 4.53.3 1328 | '@rollup/rollup-linux-s390x-gnu': 4.53.3 1329 | '@rollup/rollup-linux-x64-gnu': 4.53.3 1330 | '@rollup/rollup-linux-x64-musl': 4.53.3 1331 | '@rollup/rollup-openharmony-arm64': 4.53.3 1332 | '@rollup/rollup-win32-arm64-msvc': 4.53.3 1333 | '@rollup/rollup-win32-ia32-msvc': 4.53.3 1334 | '@rollup/rollup-win32-x64-gnu': 4.53.3 1335 | '@rollup/rollup-win32-x64-msvc': 4.53.3 1336 | fsevents: 2.3.3 1337 | 1338 | safe-buffer@5.1.2: {} 1339 | 1340 | seemly@0.3.10: {} 1341 | 1342 | setimmediate@1.0.5: {} 1343 | 1344 | source-map-js@1.2.1: {} 1345 | 1346 | string_decoder@1.1.1: 1347 | dependencies: 1348 | safe-buffer: 5.1.2 1349 | 1350 | tinyglobby@0.2.15: 1351 | dependencies: 1352 | fdir: 6.5.0(picomatch@4.0.3) 1353 | picomatch: 4.0.3 1354 | 1355 | treemate@0.3.11: {} 1356 | 1357 | typescript@5.9.3: {} 1358 | 1359 | undici-types@7.16.0: {} 1360 | 1361 | util-deprecate@1.0.2: {} 1362 | 1363 | vdirs@0.1.8(vue@3.5.25(typescript@5.9.3)): 1364 | dependencies: 1365 | evtd: 0.2.4 1366 | vue: 3.5.25(typescript@5.9.3) 1367 | 1368 | vfonts@0.1.0: {} 1369 | 1370 | vite@7.2.4(@types/node@24.10.1): 1371 | dependencies: 1372 | esbuild: 0.25.12 1373 | fdir: 6.5.0(picomatch@4.0.3) 1374 | picomatch: 4.0.3 1375 | postcss: 8.5.6 1376 | rollup: 4.53.3 1377 | tinyglobby: 0.2.15 1378 | optionalDependencies: 1379 | '@types/node': 24.10.1 1380 | fsevents: 2.3.3 1381 | 1382 | vooks@0.2.12(vue@3.5.25(typescript@5.9.3)): 1383 | dependencies: 1384 | evtd: 0.2.4 1385 | vue: 3.5.25(typescript@5.9.3) 1386 | 1387 | vscode-uri@3.1.0: {} 1388 | 1389 | vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)): 1390 | dependencies: 1391 | '@vue/devtools-api': 6.6.4 1392 | vue: 3.5.25(typescript@5.9.3) 1393 | 1394 | vue-tsc@3.1.5(typescript@5.9.3): 1395 | dependencies: 1396 | '@volar/typescript': 2.4.23 1397 | '@vue/language-core': 3.1.5(typescript@5.9.3) 1398 | typescript: 5.9.3 1399 | 1400 | vue@3.5.25(typescript@5.9.3): 1401 | dependencies: 1402 | '@vue/compiler-dom': 3.5.25 1403 | '@vue/compiler-sfc': 3.5.25 1404 | '@vue/runtime-dom': 3.5.25 1405 | '@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3)) 1406 | '@vue/shared': 3.5.25 1407 | optionalDependencies: 1408 | typescript: 5.9.3 1409 | 1410 | vueuc@0.4.65(vue@3.5.25(typescript@5.9.3)): 1411 | dependencies: 1412 | '@css-render/vue3-ssr': 0.15.14(vue@3.5.25(typescript@5.9.3)) 1413 | '@juggle/resize-observer': 3.4.0 1414 | css-render: 0.15.14 1415 | evtd: 0.2.4 1416 | seemly: 0.3.10 1417 | vdirs: 0.1.8(vue@3.5.25(typescript@5.9.3)) 1418 | vooks: 0.2.12(vue@3.5.25(typescript@5.9.3)) 1419 | vue: 3.5.25(typescript@5.9.3) 1420 | --------------------------------------------------------------------------------