├── LICENSE
├── README.md
├── app
├── .gitignore
├── go.mod
├── go.sum
├── internal
│ ├── plugin
│ │ ├── core.go
│ │ ├── core_test.go
│ │ ├── model.go
│ │ ├── moudle
│ │ │ ├── data.go
│ │ │ ├── factory.go
│ │ │ ├── gin.go
│ │ │ ├── mq.go
│ │ │ ├── relation.go
│ │ │ └── tools.go
│ │ └── scan.go
│ ├── rpc
│ │ └── rpc.go
│ ├── server
│ │ ├── data.go
│ │ ├── data_test.go
│ │ ├── model.go
│ │ ├── plugin.go
│ │ ├── relation.go
│ │ ├── relation_test.go
│ │ ├── server.go
│ │ ├── view.go
│ │ └── view_test.go
│ ├── util
│ │ └── zip.go
│ └── web
│ │ ├── handle.go
│ │ ├── model.go
│ │ └── router.go
├── main.go
└── plugins
│ └── core.d.ts
├── common
├── .gitignore
├── common
│ └── model.go
├── go.mod
├── go.sum
├── openapi.yaml
├── proto
│ ├── app
│ │ ├── app.pb.go
│ │ ├── app.proto
│ │ ├── app_grpc.pb.go
│ │ └── server
│ │ │ └── app.go
│ ├── data
│ │ ├── data.pb.go
│ │ ├── data.proto
│ │ └── data_grpc.pb.go
│ └── relation
│ │ ├── relation.pb.go
│ │ ├── relation.proto
│ │ └── relation_grpc.pb.go
├── readme.md
├── script
│ ├── gen_app.sh
│ ├── gen_data.sh
│ └── gen_relation.sh
├── service
│ ├── common.go
│ ├── common_test.go
│ ├── data.go
│ ├── data_test.go
│ ├── model.go
│ ├── relation.go
│ └── relation_test.go
├── tool
│ ├── log
│ │ └── log.go
│ ├── mq
│ │ ├── consumer.go
│ │ ├── produce.go
│ │ └── produce_test.go
│ └── tools
│ │ ├── err.go
│ │ ├── gin.go
│ │ ├── http.go
│ │ ├── service.go
│ │ └── string.go
└── web
│ └── common.go
├── data
├── .drone.yml
├── .gitignore
├── Dockerfile
├── ent
│ ├── client.go
│ ├── config.go
│ ├── context.go
│ ├── ent.go
│ ├── enttest
│ │ └── enttest.go
│ ├── generate.go
│ ├── hook
│ │ └── hook.go
│ ├── migrate
│ │ ├── migrate.go
│ │ └── schema.go
│ ├── mutation.go
│ ├── object.go
│ ├── object
│ │ ├── object.go
│ │ └── where.go
│ ├── object_create.go
│ ├── object_delete.go
│ ├── object_query.go
│ ├── object_update.go
│ ├── predicate
│ │ └── predicate.go
│ ├── runtime.go
│ ├── runtime
│ │ └── runtime.go
│ ├── schema
│ │ └── object.go
│ └── tx.go
├── go.mod
├── go.sum
├── internal
│ ├── rpc
│ │ ├── handle.go
│ │ └── rpc_test.go
│ ├── service
│ │ ├── common.go
│ │ ├── database.go
│ │ ├── kvrocks.go
│ │ ├── kvrocks_test.go
│ │ ├── object.go
│ │ └── redis.go
│ ├── tools
│ │ ├── content_type.go
│ │ └── content_type_test.go
│ └── web
│ │ ├── common.go
│ │ ├── handler.go
│ │ ├── model.go
│ │ └── router.go
├── main.go
├── openapi.yaml
├── pkg
│ └── storage
│ │ ├── api.go
│ │ ├── s3.go
│ │ └── s3_test.go
├── script
│ └── generate_service.sh
└── test
│ ├── ent
│ └── database_test.go
│ └── m5d_test.go
├── file-front
├── .babelrc
├── .drone.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│ └── settings.json
├── .workflow
│ └── pipeline-20220519.yml
├── Dockerfile
├── LICENSE
├── README.md
├── babel.config.js
├── default.conf
├── jsconfig.json
├── package-lock.json
├── package.json
├── public
│ ├── codemirror
│ │ └── css
│ │ │ └── tomorrow-night.css
│ ├── favicon.ico
│ ├── index.html
│ └── mavonEditor
│ │ ├── css
│ │ ├── github-markdown.css
│ │ ├── katex.min.css
│ │ └── tomorrow-night.css
│ │ └── js
│ │ ├── highlight.min.js
│ │ ├── katex.min.js
│ │ └── lang.hljs.js
├── src
│ ├── App.vue
│ ├── assets
│ │ ├── images
│ │ │ ├── audio
│ │ │ │ └── wave.gif
│ │ │ ├── common
│ │ │ │ ├── logo_footer.png
│ │ │ │ ├── logo_header.png
│ │ │ │ └── logo_header_xs.png
│ │ │ ├── error
│ │ │ │ └── 404.png
│ │ │ ├── file
│ │ │ │ ├── dir.png
│ │ │ │ ├── file_7z.svg
│ │ │ │ ├── file_avi.png
│ │ │ │ ├── file_c#.png
│ │ │ │ ├── file_c++.png
│ │ │ │ ├── file_c.png
│ │ │ │ ├── file_chm.png
│ │ │ │ ├── file_css.png
│ │ │ │ ├── file_csv.png
│ │ │ │ ├── file_dmg.png
│ │ │ │ ├── file_excel.svg
│ │ │ │ ├── file_exe.png
│ │ │ │ ├── file_flac.svg
│ │ │ │ ├── file_gif.png
│ │ │ │ ├── file_go.png
│ │ │ │ ├── file_html.png
│ │ │ │ ├── file_jar.png
│ │ │ │ ├── file_java.png
│ │ │ │ ├── file_js.png
│ │ │ │ ├── file_json.png
│ │ │ │ ├── file_jsp.png
│ │ │ │ ├── file_kotlin.png
│ │ │ │ ├── file_less.png
│ │ │ │ ├── file_lua.png
│ │ │ │ ├── file_markdown.png
│ │ │ │ ├── file_music.png
│ │ │ │ ├── file_nginx.png
│ │ │ │ ├── file_oa.png
│ │ │ │ ├── file_objective_c.png
│ │ │ │ ├── file_open.png
│ │ │ │ ├── file_pdf.png
│ │ │ │ ├── file_php.png
│ │ │ │ ├── file_powershell.png
│ │ │ │ ├── file_ppt.svg
│ │ │ │ ├── file_properties.png
│ │ │ │ ├── file_python.png
│ │ │ │ ├── file_r.png
│ │ │ │ ├── file_rar.png
│ │ │ │ ├── file_rtf.png
│ │ │ │ ├── file_rust.png
│ │ │ │ ├── file_sass.png
│ │ │ │ ├── file_scss.png
│ │ │ │ ├── file_shell.png
│ │ │ │ ├── file_sql.png
│ │ │ │ ├── file_stylus.png
│ │ │ │ ├── file_svg.png
│ │ │ │ ├── file_swift.png
│ │ │ │ ├── file_tar.svg
│ │ │ │ ├── file_txt.png
│ │ │ │ ├── file_typescript.png
│ │ │ │ ├── file_unknown.png
│ │ │ │ ├── file_vue.png
│ │ │ │ ├── file_word.svg
│ │ │ │ ├── file_xml.png
│ │ │ │ ├── file_yaml.png
│ │ │ │ └── file_zip.png
│ │ │ ├── footer
│ │ │ │ ├── QQImg.png
│ │ │ │ ├── QQLogo.png
│ │ │ │ ├── giteeImg.png
│ │ │ │ ├── wechatImg.png
│ │ │ │ └── wechatLogo.png
│ │ │ └── home
│ │ │ │ ├── banner
│ │ │ │ └── banner1.png
│ │ │ │ ├── function
│ │ │ │ ├── delete.png
│ │ │ │ ├── edit.png
│ │ │ │ ├── operation.png
│ │ │ │ ├── preview.png
│ │ │ │ ├── search.png
│ │ │ │ ├── shard.png
│ │ │ │ ├── share.png
│ │ │ │ ├── store.png
│ │ │ │ └── type.png
│ │ │ │ └── notice
│ │ │ │ └── noticeTip.png
│ │ └── styles
│ │ │ ├── base.styl
│ │ │ ├── elementCover.styl
│ │ │ ├── iconfont
│ │ │ ├── iconfont.css
│ │ │ ├── iconfont.eot
│ │ │ ├── iconfont.svg
│ │ │ ├── iconfont.ttf
│ │ │ └── iconfont.woff
│ │ │ ├── iconfontCover.styl
│ │ │ ├── mediaScreenXs.styl
│ │ │ ├── mixins.styl
│ │ │ └── varibles.styl
│ ├── components
│ │ ├── Header.vue
│ │ ├── common
│ │ │ ├── BreadCrumb.vue
│ │ │ ├── DragVerify.vue
│ │ │ ├── FileTable.vue
│ │ │ └── MarkdownPreview.vue
│ │ └── file
│ │ │ ├── AsideMenu.vue
│ │ │ ├── FileList.vue
│ │ │ ├── box
│ │ │ ├── audioPreview
│ │ │ │ ├── BoxMask.vue
│ │ │ │ └── index.js
│ │ │ ├── codePreview
│ │ │ │ ├── BoxMask.vue
│ │ │ │ ├── fold.js
│ │ │ │ ├── index.js
│ │ │ │ ├── mode.js
│ │ │ │ └── theme.js
│ │ │ ├── contextMenu
│ │ │ │ ├── Box.vue
│ │ │ │ └── index.js
│ │ │ ├── imgPreview
│ │ │ │ ├── BoxMask.vue
│ │ │ │ └── index.js
│ │ │ ├── markdownPreview
│ │ │ │ ├── BoxMask.vue
│ │ │ │ └── index.js
│ │ │ ├── uploadFile
│ │ │ │ ├── Box.vue
│ │ │ │ └── index.js
│ │ │ └── videoPreview
│ │ │ │ ├── BoxMask.vue
│ │ │ │ ├── VideoPlayer.vue
│ │ │ │ └── index.js
│ │ │ ├── components
│ │ │ ├── FileGrid.vue
│ │ │ ├── FileTimeLine.vue
│ │ │ ├── OperationMenu.vue
│ │ │ └── SelectColumn.vue
│ │ │ └── dialog
│ │ │ ├── addFile
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ ├── addFolder
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ ├── copyFile
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ ├── deleteFile
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ ├── moveFile
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ ├── renameFile
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ ├── restoreFile
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ ├── saveShareFile
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ ├── shareFile
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ ├── showFileDetail
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ │ │ └── unzipFile
│ │ │ ├── Dialog.vue
│ │ │ └── index.js
│ ├── config
│ │ └── index.js
│ ├── libs
│ │ ├── globalFunction
│ │ │ ├── common.js
│ │ │ ├── file.js
│ │ │ └── index.js
│ │ └── map.js
│ ├── main.js
│ ├── plugins
│ │ ├── element.js
│ │ └── fileOperationPlugins.js
│ ├── request
│ │ ├── file.js
│ │ ├── http.js
│ │ ├── onlyoffice.js
│ │ └── user.js
│ ├── router
│ │ └── router.js
│ ├── store
│ │ ├── index.js
│ │ └── module
│ │ │ ├── common.js
│ │ │ ├── fileList.js
│ │ │ ├── sideMenu.js
│ │ │ └── user.js
│ └── views
│ │ ├── ErrorPage
│ │ └── 404.vue
│ │ ├── File.vue
│ │ ├── OnlyOffice.vue
│ │ └── Share.vue
└── vue.config.js
├── images
├── 2022-09-05-09-51-49.png
├── 2022-09-05-09-52-18.png
├── 2022-09-05-09-53-03.png
├── 2022-09-05-09-53-26.png
├── 2022-09-05-09-53-48.png
├── 2022-09-05-09-54-04.png
├── 2022-09-05-09-54-37.png
├── 2022-09-05-09-55-00.png
├── 2022-09-05-09-55-24.png
├── 2022-09-05-09-56-00.png
└── logo.png
├── index-desktop-amis
├── .editorconfig
├── .gitignore
├── .vscode
│ ├── .debug.script.mjs
│ ├── extensions.json
│ ├── launch.json
│ └── tasks.json
├── LICENSE
├── README.md
├── README.zh-CN.md
├── electron-builder.json5
├── electron
│ ├── electron-env.d.ts
│ ├── main
│ │ ├── common.ts
│ │ ├── index.ts
│ │ ├── menu.ts
│ │ └── window.ts
│ ├── preload
│ │ └── index.ts
│ └── resources
│ │ ├── icon.ico
│ │ ├── installerIcon.ico
│ │ └── uninstallerIcon.ico
├── index.html
├── package.json
├── public
│ └── static
│ │ ├── icon
│ │ ├── admin.png
│ │ ├── blog.png
│ │ ├── cloud.png
│ │ ├── music.png
│ │ └── video.png
│ │ └── image
│ │ └── logo.png
├── src
│ ├── App.tsx
│ ├── amis
│ │ ├── action
│ │ │ └── index.tsx
│ │ ├── component
│ │ │ ├── content.tsx
│ │ │ ├── icon.tsx
│ │ │ ├── index.ts
│ │ │ └── media.tsx
│ │ └── index.tsx
│ ├── api
│ │ ├── api.ts
│ │ └── request.ts
│ ├── index.css
│ ├── main.tsx
│ ├── types
│ │ └── global.d.ts
│ ├── views
│ │ ├── index.tsx
│ │ ├── page.tsx
│ │ ├── search.css
│ │ └── search.tsx
│ └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
├── index-front-amis
├── .drone.yml
├── .gitignore
├── Dockerfile
├── default.conf
├── index.html
├── package-lock.json
├── package.json
├── public
│ └── vite.svg
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── amis
│ │ ├── action
│ │ │ └── index.tsx
│ │ ├── component
│ │ │ ├── content.tsx
│ │ │ ├── icon.tsx
│ │ │ ├── index.ts
│ │ │ └── media.tsx
│ │ └── index.tsx
│ ├── api
│ │ ├── api.ts
│ │ └── request.ts
│ ├── assets
│ │ └── react.svg
│ ├── main.tsx
│ ├── views
│ │ ├── code.tsx
│ │ ├── index.tsx
│ │ ├── manage.tsx
│ │ └── view.tsx
│ └── vite-env.d.ts
├── tmp.md
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── vite.config.ts.js
├── music-front
├── .browserslistrc
├── .drone.yml
├── .editorconfig
├── .env
├── .eslintrc.js
├── .gitignore
├── .npmrc
├── .prettierrc
├── .yarnrc
├── Dockerfile
├── LICENSE
├── README.md
├── babel.config.js
├── default.conf
├── package.json
├── postcss.config.js
├── public
│ ├── favicon.ico
│ ├── img
│ │ └── warn.png
│ ├── index.html
│ └── prompt.html
├── src
│ ├── App.vue
│ ├── api
│ │ └── index.js
│ ├── assets
│ │ ├── background
│ │ │ ├── bg-1.jpg
│ │ │ └── bg-2.jpg
│ │ └── img
│ │ │ ├── album_cover_player.png
│ │ │ ├── default.png
│ │ │ ├── player_cover.png
│ │ │ └── wave.gif
│ ├── base
│ │ ├── mm-dialog
│ │ │ └── mm-dialog.vue
│ │ ├── mm-icon
│ │ │ └── mm-icon.vue
│ │ ├── mm-loading
│ │ │ └── mm-loading.vue
│ │ ├── mm-no-result
│ │ │ └── mm-no-result.vue
│ │ ├── mm-progress
│ │ │ └── mm-progress.vue
│ │ └── mm-toast
│ │ │ ├── index.js
│ │ │ └── mm-toast.vue
│ ├── components
│ │ ├── lyric
│ │ │ └── lyric.vue
│ │ ├── mm-header
│ │ │ └── mm-header.vue
│ │ ├── music-btn
│ │ │ └── music-btn.vue
│ │ ├── music-list
│ │ │ └── music-list.vue
│ │ └── volume
│ │ │ └── volume.vue
│ ├── config.js
│ ├── main.js
│ ├── pages
│ │ ├── details
│ │ │ └── details.vue
│ │ ├── historyList
│ │ │ └── historyList.vue
│ │ ├── mmPlayer.js
│ │ ├── music.vue
│ │ ├── playList
│ │ │ └── playList.vue
│ │ ├── search
│ │ │ └── search.vue
│ │ ├── topList
│ │ │ └── topList.vue
│ │ └── userList
│ │ │ └── userList.vue
│ ├── router
│ │ └── index.js
│ ├── store
│ │ ├── actions.js
│ │ ├── getters.js
│ │ ├── index.js
│ │ ├── mutation-types.js
│ │ ├── mutations.js
│ │ └── state.js
│ ├── styles
│ │ ├── index.less
│ │ ├── mixin.less
│ │ ├── reset.less
│ │ └── var.less
│ └── utils
│ │ ├── axios.js
│ │ ├── hack.js
│ │ ├── mixin.js
│ │ ├── song.js
│ │ ├── storage.js
│ │ └── util.js
└── vue.config.js
├── plugins
├── B站服务.js
├── 文件服务.js
├── 文章服务.js
├── 智能家居.js
├── 视频服务.js
└── 音乐服务.js
├── relation
├── .drone.yaml
├── .gitignore
├── go.mod
├── go.sum
├── internal
│ └── neo4j
│ │ ├── neo4j.go
│ │ ├── neo4j_test.go
│ │ ├── node.go
│ │ └── tool.go
├── main.go
├── openapi.yaml
└── script
│ └── generate_service.sh
├── search
├── .drone.yml
├── .gitignore
├── Dockerfile
├── doc
│ └── index.md
├── go.mod
├── go.sum
├── internal
│ ├── object
│ │ ├── mq.go
│ │ ├── mq_test.go
│ │ └── search.go
│ ├── server
│ │ ├── model.go
│ │ └── server.go
│ └── web
│ │ ├── handler.go
│ │ └── router.go
├── main.go
└── pkg
│ └── es
│ ├── es.go
│ ├── es_test.go
│ └── model.go
└── views
├── B站卡片.json
├── 专辑管理.json
├── 博客管理.json
├── 文件管理.json
├── 文章显示.json
├── 文章编辑.json
├── 视频播放器.json
└── 音乐管理.json
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 个人项目
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |

2 |
3 |
4 |
5 |
6 |
😍index
7 | 一款可扩展的资源管理软件
8 |
9 | ## 项目结构
10 | - app 应用服务
11 | - common 公共基础库
12 | - data 存储服务
13 | - file-front 网盘前端
14 | - index-desktop-amis index桌面版
15 | - index-front-amis index后台管理系统
16 | - music-front 音乐播放器
17 | - relation 关系服务
18 | - search 搜索服务
19 | - views 所有界面的json
20 | - plugins 所有插件代码
21 |
22 | ## 功能特点
23 | - 采用微服务架构
24 | - 提供资源搜索功能,可以搜索所有资源
25 | - 所有服务都采用插件来实现
26 | - 前端低代码,可以使用JSON来配置前端
27 |
28 | ## 界面展示
29 |
30 | 
31 |
32 | 
33 |
34 | 
35 |
36 | 
37 |
38 | 
39 |
40 | 
41 |
42 | 
43 |
44 | 
45 |
46 | 
47 |
48 | 
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | tmp
--------------------------------------------------------------------------------
/app/internal/plugin/core_test.go:
--------------------------------------------------------------------------------
1 | package plugin
2 |
3 | import "testing"
4 |
5 | func TestCreateContainer(t *testing.T) {
6 | //CreateContainer("../../plugins/music", nil)
7 | }
8 |
--------------------------------------------------------------------------------
/app/internal/plugin/model.go:
--------------------------------------------------------------------------------
1 | package plugin
2 |
3 | // ManegeView 管理界面
4 | type ManegeView struct {
5 | ID int64 `json:"id"` // 页面ID
6 | Name string `json:"name"` // 页面名字
7 | Data func() map[string]string `json:"data"` // 待映射的数据
8 | }
9 |
--------------------------------------------------------------------------------
/app/internal/plugin/moudle/factory.go:
--------------------------------------------------------------------------------
1 | package moudle
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "index.app/internal/server"
6 | )
7 |
8 | func CreateToolsServer() *ToolsServer {
9 | return &ToolsServer{}
10 | }
11 |
12 | func CreateGinServer(engine *gin.Engine, name string) *GinServer {
13 | return &GinServer{engine: engine, name: name}
14 | }
15 |
16 | func CreateDataServer() *DataServer {
17 | return &DataServer{server: server.DataServer}
18 | }
19 |
20 | func CreateRelationServer() *RelationServer {
21 | return &RelationServer{server: server.RelationServer}
22 | }
23 |
24 | func CreateMqServer() *MqServer {
25 | return &MqServer{server: server.MqServer, topic: "object"}
26 | }
27 |
--------------------------------------------------------------------------------
/app/internal/rpc/rpc.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 | import (
4 | "context"
5 | pb "git.xiaoyou.host/index/common/proto/app"
6 | "index.app/internal/plugin"
7 | )
8 |
9 | type AppService struct {
10 | pb.UnimplementedAppServer
11 | }
12 |
13 | func NewAppService() *AppService {
14 | return &AppService{}
15 | }
16 |
17 | func (s *AppService) DeleteNode(ctx context.Context, req *pb.NoeMeta) (*pb.DeleteNodeResp, error) {
18 | return &pb.DeleteNodeResp{}, nil
19 | }
20 | func (s *AppService) GetNodeInfo(ctx context.Context, req *pb.GetNodeInfoReq) (*pb.GetNodeInfoResp, error) {
21 | res := make([]*pb.CardInfo, 0, len(req.Infos))
22 | // 遍历所有的卡片
23 | for _, card := range req.Infos {
24 | // 判断卡片是否存在
25 | if container := plugin.GetPluginInfo(card.App); container != nil {
26 | // 调用搜索接口
27 | if info := container.GetSearchCard(ctx, card.NodeId); info != "" {
28 | res = append(res, &pb.CardInfo{
29 | NodeId: card.NodeId,
30 | App: card.App,
31 | Info: info,
32 | })
33 | }
34 | }
35 | }
36 | return &pb.GetNodeInfoResp{
37 | Cards: res,
38 | }, nil
39 | }
40 |
--------------------------------------------------------------------------------
/app/internal/server/data_test.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "fmt"
7 | "testing"
8 | )
9 |
10 | func TestDataService_GetDownloadLink(t *testing.T) {
11 | fmt.Println(data1.GetDownloadLink(context.Background(), "62caa90f45355445b731a6bd"))
12 | }
13 |
14 | func TestDataService_UploadObjectFromFile(t *testing.T) {
15 | data := []byte("hello word")
16 | id, err := data1.UploadFromReader(context.Background(), bytes.NewReader(data), "hello.txt", int64(len(data)))
17 | fmt.Println(id)
18 | fmt.Println(err)
19 | }
20 |
--------------------------------------------------------------------------------
/app/internal/server/plugin.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | const NodePlugin = "plugin"
4 |
--------------------------------------------------------------------------------
/app/internal/server/relation_test.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 | )
8 |
9 | var relation1 *RelationService
10 | var data1 *DataService
11 |
12 | func TestMain(t *testing.M) {
13 | //InitConsul()
14 | relation1 = CreateRelationService()
15 | data1 = CreateDataService()
16 | t.Run()
17 | }
18 |
19 | func TestGetAttribute(t *testing.T) {
20 | //var relation = CreateRelationService()
21 | //relation.AddN
22 | //ode("people", PeopleInfo{
23 | // Name: "小游",
24 | // Pic: "123456",
25 | // Desc: "描述信息",
26 | // Birth: "生日",
27 | //})
28 | }
29 |
30 | func TestGetNode(t *testing.T) {
31 | //var music MusicInfo
32 | //err := relation1.GetNode(context.Background(), 7, &music)
33 | //fmt.Println(err)
34 | //fmt.Println(music)
35 | }
36 |
37 | func TestRelationService_UpdateNode(t *testing.T) {
38 | err := relation1.UpdateNode(context.Background(), 901, map[string]string{"name": "666"})
39 | fmt.Println(err)
40 | }
41 |
--------------------------------------------------------------------------------
/app/internal/server/server.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "git.xiaoyou.host/index/common/service"
5 | "git.xiaoyou.host/index/common/tool/mq"
6 | )
7 |
8 | var (
9 | DataServer *DataService
10 | RelationServer *RelationService
11 | MqServer *mq.ProduceService
12 | )
13 |
14 | func InitRpc() {
15 | service.InitConsul()
16 | // 初始化服务发现
17 | DataServer = CreateDataService()
18 | RelationServer = CreateRelationService()
19 | MqServer = mq.CreateProduceService("index")
20 | }
21 |
--------------------------------------------------------------------------------
/app/internal/server/view.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "git.xiaoyou.host/index/common/tool/log"
7 | "git.xiaoyou.host/index/common/tool/tools"
8 | "index.app/internal/util"
9 | "io/ioutil"
10 | )
11 |
12 | const NodeView = "view"
13 |
14 | func ExportNode(ctx context.Context, name string, content string, ext string) ([]byte, error) {
15 | // 获取所有的页面
16 | views, _, err := RelationServer.FindNode(ctx, name, "name", ".*", 0, 0)
17 | if err != nil {
18 | return nil, tools.ReturnError("get node err %v", err)
19 | }
20 | var fileList []string
21 | // 写入文件tmp
22 | for _, v := range views {
23 | attribute := v.Info.Attribute
24 | // 获取原始视图信息
25 | _, content, err := DataServer.GetText(ctx, attribute[content])
26 | if err != nil || content == "" {
27 | return nil, tools.ReturnError("const is nil err %v", err)
28 | }
29 | fmt.Println(attribute["name"], attribute[content])
30 | filename := fmt.Sprintf("%s.%s", attribute["name"], ext)
31 | fileList = append(fileList, filename)
32 | err = ioutil.WriteFile(filename, []byte(content), 0775)
33 | if err != nil {
34 | log.CtxLogError(ctx, "write file err %v", err)
35 | }
36 | }
37 | // 压缩文件
38 | err = util.ZipFiles("tmp.zip", fileList)
39 | if err != nil {
40 | return nil, tools.ReturnError("zip file err %v", err)
41 | }
42 | data, err := ioutil.ReadFile("tmp.zip")
43 | if err != nil {
44 | return nil, tools.ReturnError("open file err %v", err)
45 | }
46 | return data, nil
47 | }
48 |
--------------------------------------------------------------------------------
/app/internal/server/view_test.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestExportView(t *testing.T) {
8 | InitRpc()
9 | //err := ExportView(context.Background())
10 | //fmt.Println(err)
11 | }
12 |
--------------------------------------------------------------------------------
/app/internal/util/zip.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "archive/zip"
5 | "io"
6 | "os"
7 | )
8 |
9 | func ZipFiles(filename string, files []string) error {
10 |
11 | newZipFile, err := os.Create(filename)
12 | if err != nil {
13 | return err
14 | }
15 | defer newZipFile.Close()
16 |
17 | zipWriter := zip.NewWriter(newZipFile)
18 | defer zipWriter.Close()
19 |
20 | // Add files to zip
21 | for _, file := range files {
22 | if err = AddFileToZip(zipWriter, file); err != nil {
23 | return err
24 | }
25 | }
26 | return nil
27 | }
28 |
29 | func AddFileToZip(zipWriter *zip.Writer, filename string) error {
30 |
31 | fileToZip, err := os.Open(filename)
32 | if err != nil {
33 | return err
34 | }
35 | defer fileToZip.Close()
36 |
37 | // Get the file information
38 | info, err := fileToZip.Stat()
39 | if err != nil {
40 | return err
41 | }
42 |
43 | header, err := zip.FileInfoHeader(info)
44 | if err != nil {
45 | return err
46 | }
47 |
48 | // Using FileInfoHeader() above only uses the basename of the file. If we want
49 | // to preserve the folder structure we can overwrite this with the full path.
50 | header.Name = filename
51 |
52 | // Change to deflate to gain better compression
53 | // see http://golang.org/pkg/archive/zip/#pkg-constants
54 | header.Method = zip.Deflate
55 |
56 | writer, err := zipWriter.CreateHeader(header)
57 | if err != nil {
58 | return err
59 | }
60 | _, err = io.Copy(writer, fileToZip)
61 | return err
62 | }
63 |
--------------------------------------------------------------------------------
/app/internal/web/model.go:
--------------------------------------------------------------------------------
1 | package web
2 |
3 | type View struct {
4 | Id int64 `json:"id"` // 视图ID
5 | ViewInfo
6 | }
7 |
8 | // ViewInfo 视图信息
9 | type ViewInfo struct {
10 | Name string `json:"name"` // 视图名称
11 | View string `json:"view"` // 视图代码
12 | }
13 |
--------------------------------------------------------------------------------
/app/internal/web/router.go:
--------------------------------------------------------------------------------
1 | package web
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | // RegisterRouter 注册http路由
8 | func RegisterRouter(r *gin.Engine) {
9 | plugin := r.Group("/app/core")
10 | // 获取语法定义
11 | plugin.GET("/interface/plugin", GetPluginInterface)
12 | // 获取插件列表
13 | plugin.GET("/plugins", GetPluginList)
14 | // 新建插件
15 | plugin.POST("/plugin", AddPlugin)
16 | // 获取插件内容
17 | plugin.GET("/plugin/:name", GetPluginInfo)
18 | // 更新插件内容
19 | plugin.PUT("/plugin/:name", UpdatePlugin)
20 | // 插件重载
21 | plugin.GET("/plugin/:name/reload", PluginReload)
22 | // 删除插件
23 | plugin.DELETE("/plugin/:name", PluginDelete)
24 | // 插件导出
25 | plugin.GET("/plugin/export", ExportPlugin)
26 |
27 | // 获取所有管理页面
28 | plugin.GET("/view/manage", GetManageViews)
29 | // 获取自定义页面
30 | plugin.GET("/view/app/:name/:id/:view", GetCustomView)
31 | // 视图导出功能
32 | plugin.GET("/view/export", ExportView)
33 |
34 | // 新建页面
35 | plugin.POST("/views", AddView)
36 | // 获取所有页面
37 | plugin.GET("/views", GetViews)
38 | // 修改页面
39 | plugin.PUT("/views/:id", UpdateView)
40 | // 删除页面
41 | plugin.DELETE("/views/:id", DeleteView)
42 | // 获取某个页面
43 | plugin.GET("/views/:id", GetView)
44 | }
45 |
--------------------------------------------------------------------------------
/app/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | app2 "git.xiaoyou.host/index/common/proto/app"
5 | "git.xiaoyou.host/index/common/service"
6 | "github.com/gin-gonic/gin"
7 | "github.com/go-kratos/kratos/v2"
8 | "github.com/go-kratos/kratos/v2/middleware/recovery"
9 | "github.com/go-kratos/kratos/v2/transport/grpc"
10 | "github.com/go-kratos/kratos/v2/transport/http"
11 | "index.app/internal/plugin"
12 | "index.app/internal/rpc"
13 | "index.app/internal/server"
14 | "index.app/internal/web"
15 | )
16 |
17 | func main() {
18 | server.InitRpc()
19 | // http
20 | router := gin.Default()
21 | web.RegisterRouter(router)
22 | httpSrv := http.NewServer(http.Address(":8006"))
23 | httpSrv.HandlePrefix("/", router)
24 | // 加载插件
25 | plugin.InitPlugin(router)
26 | // rpc
27 | s := rpc.NewAppService()
28 | grpcSrv := grpc.NewServer(grpc.Address(":9006"), grpc.Middleware(recovery.Recovery()))
29 | app2.RegisterAppServer(grpcSrv, s)
30 | app := kratos.New(
31 | kratos.Name("index.app"),
32 | kratos.Server(httpSrv, grpcSrv),
33 | kratos.Registrar(service.GetRegistry()))
34 | if err := app.Run(); err != nil {
35 | panic(any(err))
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/common/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
--------------------------------------------------------------------------------
/common/common/model.go:
--------------------------------------------------------------------------------
1 | package common
2 |
3 | // PageInfo 分页信息
4 | type PageInfo struct {
5 | Current int `json:"current"` // 当前第几页
6 | Total int64 `json:"total"` // 总页数
7 | List interface{} `json:"list"` // 列表
8 | }
9 |
--------------------------------------------------------------------------------
/common/openapi.yaml:
--------------------------------------------------------------------------------
1 | # Generated with protoc-gen-openapi
2 | # https://github.com/google/gnostic/tree/master/cmd/protoc-gen-openapi
3 |
4 | openapi: 3.0.3
5 | info:
6 | title: ""
7 | version: 0.0.1
8 | paths: {}
9 | components:
10 | schemas: {}
11 |
--------------------------------------------------------------------------------
/common/proto/app/app.proto:
--------------------------------------------------------------------------------
1 | // 定义我们接口的版本
2 | syntax = "proto3";
3 | // 定义包名称
4 | package api;
5 | // 定义go安装包名称
6 | option go_package = "index.app/api;app";
7 | // 定义我们的服务
8 | service App {
9 | // 删除某个节点
10 | rpc DeleteNode (NoeMeta) returns (DeleteNodeResp);
11 | // 获取节点的原信息(用于前端界面展示)
12 | rpc GetNodeInfo (GetNodeInfoReq) returns (GetNodeInfoResp);
13 | }
14 |
15 | // 对象元信息
16 | message NoeMeta {
17 | int64 id = 1; // 节点ID
18 | }
19 | // 删除响应事件
20 | message DeleteNodeResp {
21 | bool id = 1; // 对象ID
22 | }
23 |
24 | message GetNodeInfoReq {
25 | repeated CardInfo infos = 1; // 对象ID和所属应用
26 | }
27 | // 获取节点信息
28 | message GetNodeInfoResp {
29 | repeated CardInfo cards = 1; // 卡片信息列表
30 | }
31 | // 卡片信息
32 | message CardInfo {
33 | int64 NodeId = 1; // 节点ID
34 | string App = 2; // 卡片所属应用
35 | string Info = 3; // 卡片信息
36 | }
--------------------------------------------------------------------------------
/common/proto/app/server/app.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 |
6 | pb "git.xiaoyou.host/index/common/proto/app"
7 | )
8 |
9 | type AppService struct {
10 | pb.UnimplementedAppServer
11 | }
12 |
13 | func NewAppService() *AppService {
14 | return &AppService{}
15 | }
16 |
17 | func (s *AppService) DeleteNode(ctx context.Context, req *pb.NoeMeta) (*pb.DeleteNodeResp, error) {
18 | return &pb.DeleteNodeResp{}, nil
19 | }
20 | func (s *AppService) GetNodeInfo(ctx context.Context, req *pb.GetNodeInfoReq) (*pb.GetNodeInfoResp, error) {
21 | return &pb.GetNodeInfoResp{}, nil
22 | }
23 |
--------------------------------------------------------------------------------
/common/readme.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/common/readme.md
--------------------------------------------------------------------------------
/common/script/gen_app.sh:
--------------------------------------------------------------------------------
1 | # 自动生成服务端和客户端代码
2 | export export PATH=$PATH:/home/projector-user/sdk/go/bin
3 | export GOPROXY="https://goproxy.cn"
4 | cd ..
5 | kratos proto client proto/app/app.proto
6 | kratos proto server proto/app/app.proto -t ./proto/app/server
--------------------------------------------------------------------------------
/common/script/gen_data.sh:
--------------------------------------------------------------------------------
1 | # 自动生成服务端和客户端代码
2 | export export PATH=$PATH:/home/projector-user/sdk/go/bin
3 | export GOPROXY="https://goproxy.cn"
4 | cd ..
5 | kratos proto client proto/data/data.proto
6 | kratos proto server proto/data/data.proto -t ../data
--------------------------------------------------------------------------------
/common/script/gen_relation.sh:
--------------------------------------------------------------------------------
1 | # 自动生成服务端和客户端代码
2 | export export PATH=$PATH:/home/projector-user/sdk/go/bin
3 | export GOPROXY="https://goproxy.cn"
4 | cd ..
5 | kratos proto client proto/relation/relation.proto
6 | kratos proto server proto/relation/relation.proto -t ../relation
--------------------------------------------------------------------------------
/common/service/common.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "git.xiaoyou.host/index/common/tool/log"
6 | "github.com/go-kratos/kratos/contrib/registry/consul/v2"
7 | "github.com/hashicorp/consul/api"
8 | )
9 |
10 | var registry *consul.Registry
11 | var client *api.Client
12 |
13 | // InitConsul 初始化consul服务
14 | func InitConsul() {
15 | config := api.DefaultConfig()
16 | config.Address = "consul-1.consul.xiaoyou-index.svc.cluster.local:8500"
17 | consulClient, err := api.NewClient(config)
18 | if err != nil {
19 | panic(any(err))
20 | }
21 | client = consulClient
22 | // 注册consul服务
23 | registry = consul.New(consulClient)
24 | }
25 |
26 | func GetRegistry() *consul.Registry {
27 | return registry
28 | }
29 |
30 | func GetClient() *api.Client {
31 | return client
32 | }
33 |
34 | func GetStringValue(ctx context.Context, key string) string {
35 | if client == nil {
36 | return ""
37 | }
38 | conf, _, err := client.KV().Get(key, nil)
39 | if err != nil || conf == nil {
40 | log.CtxLogError(ctx, "get config error %v", err)
41 | return ""
42 | }
43 | return string(conf.Value)
44 | }
45 |
--------------------------------------------------------------------------------
/common/service/common_test.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 | )
8 |
9 | func TestGetStringValue(t *testing.T) {
10 | InitConsul()
11 | fmt.Println(GetStringValue(context.Background(), "index/music/qq_api_cookie"))
12 | }
13 |
--------------------------------------------------------------------------------
/common/service/data_test.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "fmt"
7 | "testing"
8 | )
9 |
10 | func TestDataService_GetDownloadLink(t *testing.T) {
11 | fmt.Println(data1.GetDownloadLink(context.Background(), "62caa90f45355445b731a6bd"))
12 | }
13 |
14 | func TestDataService_UploadObjectFromFile(t *testing.T) {
15 | data := []byte("hello word")
16 | id, err := data1.UploadFromReader(context.Background(), bytes.NewReader(data), "hello.txt", int64(len(data)))
17 | fmt.Println(id)
18 | fmt.Println(err)
19 | }
20 |
--------------------------------------------------------------------------------
/common/service/model.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | // Music 音乐
4 | type Music struct {
5 | ID int64 `json:"id"` // 音乐ID
6 | MusicInfo
7 | }
8 |
9 | // MusicInfo 音乐信息
10 | type MusicInfo struct {
11 | Name string `json:"name"` // 音乐名字
12 | Pic string `json:"pic"` // 音乐图片
13 | Audio string `json:"audio"` // 播放路径
14 | Lrc string `json:"lrc"` // 歌词路径
15 | Singer string `json:"singer"` // 歌手
16 | QQMid string `json:"qq_mid"` // QQ音乐ID
17 | }
18 |
19 | // People 人物
20 | type People struct {
21 | ID int64 `json:"id"`
22 | PeopleInfo
23 | }
24 |
25 | // PeopleInfo 人物信息
26 | type PeopleInfo struct {
27 | Name string `json:"name"` // 名字
28 | Pic string `json:"pic"` // 人物图片
29 | Desc string `json:"desc"` // 人物描述
30 | Birth string `json:"birth"` // 出生日期
31 | QQMid string `json:"qq_mid"` // QQ音乐歌手ID
32 | }
33 |
34 | // Album 专辑信息
35 | type Album struct {
36 | ID int64 `json:"id"` // 专辑ID
37 | AlbumInfo
38 | }
39 |
40 | // AlbumInfo 专辑
41 | type AlbumInfo struct {
42 | Name string `json:"name"` // 专辑名字
43 | Pic string `json:"pic"` // 封面
44 | Desc string `json:"desc"` // 专辑描述
45 | }
46 |
47 | // EsObject 对象信息
48 | type EsObject struct {
49 | NodeID int64 `json:"node_id"` // 节点ID
50 | Name string `json:"name"` // 节点名字
51 | App string `json:"app"` // 节点所属应用
52 | Tags []string `json:"tags"` // 节点标签
53 | Content string `json:"content"` // 节点内容
54 |
55 | }
56 |
57 | // EsObjectOption ES消息队列模型
58 | type EsObjectOption struct {
59 | Option int32 `json:"option"` // 操作类型 1 新增 2 删除 3 更新
60 | EsObject
61 | }
62 |
--------------------------------------------------------------------------------
/common/service/relation_test.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 | )
8 |
9 | var relation1 *RelationService
10 | var data1 *DataService
11 |
12 | func TestMain(t *testing.M) {
13 | InitConsul()
14 | relation1 = CreateRelationService()
15 | data1 = CreateDataService()
16 | t.Run()
17 | }
18 |
19 | func TestGetAttribute(t *testing.T) {
20 | //var relation = CreateRelationService()
21 | //relation.AddN
22 | //ode("people", PeopleInfo{
23 | // Name: "小游",
24 | // Pic: "123456",
25 | // Desc: "描述信息",
26 | // Birth: "生日",
27 | //})
28 | }
29 |
30 | func TestGetNode(t *testing.T) {
31 | var music MusicInfo
32 | err := relation1.GetNode(context.Background(), 7, &music)
33 | fmt.Println(err)
34 | fmt.Println(music)
35 | }
36 |
37 | func TestRelationService_UpdateNode(t *testing.T) {
38 | err := relation1.UpdateNode(context.Background(), 901, map[string]string{"name": "666"})
39 | fmt.Println(err)
40 | }
41 |
--------------------------------------------------------------------------------
/common/tool/log/log.go:
--------------------------------------------------------------------------------
1 | package log
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 | )
8 |
9 | func CtxLogInfo(ctx context.Context, format string, data ...interface{}) {
10 | fmt.Printf(format+"\n", data...)
11 | }
12 |
13 | func CtxLogWarn(ctx context.Context, format string, data ...interface{}) {
14 | fmt.Printf(format+"\n", data...)
15 | }
16 |
17 | func CtxLogError(ctx context.Context, format string, data ...interface{}) {
18 | fmt.Printf(format+"\n", data...)
19 | }
20 |
21 | func Info(format string, data ...interface{}) {
22 | fmt.Printf(format+"\n", data...)
23 | }
24 |
25 | func Warn(format string, data ...interface{}) {
26 | fmt.Printf(format+"\n", data...)
27 | }
28 |
29 | func Error(format string, data ...interface{}) {
30 | fmt.Printf(format+"\n", data...)
31 | }
32 |
33 | func Json(format string, data interface{}) {
34 | res, err := json.Marshal(data)
35 | if err != nil {
36 | return
37 | }
38 | fmt.Printf(format+"\n", string(res))
39 | }
40 |
--------------------------------------------------------------------------------
/common/tool/mq/consumer.go:
--------------------------------------------------------------------------------
1 | package mq
2 |
3 | import (
4 | "context"
5 | "github.com/apache/rocketmq-client-go/v2"
6 | "github.com/apache/rocketmq-client-go/v2/consumer"
7 | "github.com/apache/rocketmq-client-go/v2/primitive"
8 | )
9 |
10 | func CreateConsumerService(group string) *ConsumerService {
11 | c, err := rocketmq.NewPushConsumer(
12 | consumer.WithNameServer(primitive.NamesrvAddr{rocketmqAddr}),
13 | consumer.WithConsumerModel(consumer.Clustering),
14 | consumer.WithGroupName(group),
15 | )
16 | if err != nil {
17 | panic(any(err))
18 | }
19 | return &ConsumerService{consumer: &c}
20 | }
21 |
22 | type ConsumerService struct {
23 | consumer *rocketmq.PushConsumer
24 | }
25 |
26 | func (s ConsumerService) Subscribe(topic string, handle func(ctx context.Context, ext ...*primitive.MessageExt) (consumer.ConsumeResult, error)) error {
27 | err := (*s.consumer).Subscribe(topic, consumer.MessageSelector{}, handle)
28 | if err != nil {
29 | return err
30 | }
31 | // 启动服务
32 | err = (*s.consumer).Start()
33 | if err != nil {
34 | return err
35 | }
36 | return nil
37 | }
38 |
--------------------------------------------------------------------------------
/common/tool/mq/produce.go:
--------------------------------------------------------------------------------
1 | package mq
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "errors"
7 | "fmt"
8 | "github.com/apache/rocketmq-client-go/v2"
9 | "github.com/apache/rocketmq-client-go/v2/primitive"
10 | "github.com/apache/rocketmq-client-go/v2/producer"
11 | )
12 |
13 | const rocketmqAddr = "http://rocketmq-0.rocketmq.xiaoyou-index.svc.cluster.local:9876"
14 |
15 | func CreateProduceService(group string) *ProduceService {
16 | p, err := rocketmq.NewProducer(
17 | producer.WithNameServer(primitive.NamesrvAddr{rocketmqAddr}),
18 | producer.WithRetry(2),
19 | producer.WithGroupName("index"),
20 | )
21 | if err != nil {
22 | panic(any(err))
23 | }
24 | // 启动服务
25 | err = p.Start()
26 | if err != nil {
27 | panic(any(err))
28 | }
29 | return &ProduceService{produce: &p}
30 | }
31 |
32 | type ProduceService struct {
33 | produce *rocketmq.Producer
34 | }
35 |
36 | func (s ProduceService) SendSync(ctx context.Context, topic string, data interface{}) error {
37 | // 解析为json数据
38 | row, err := json.Marshal(data)
39 | if err != nil {
40 | return err
41 | }
42 | res, err := (*s.produce).SendSync(context.Background(), &primitive.Message{
43 | Topic: topic,
44 | Body: row,
45 | })
46 | if res.Status != primitive.SendOK {
47 | return errors.New(fmt.Sprintf("send message erorr %v", err))
48 | }
49 | return nil
50 | }
51 |
--------------------------------------------------------------------------------
/common/tool/mq/produce_test.go:
--------------------------------------------------------------------------------
1 | package mq
2 |
--------------------------------------------------------------------------------
/common/tool/tools/err.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | )
7 |
8 | // ReturnError 返回错误信息
9 | func ReturnError(format string, a ...any) error {
10 | return errors.New(fmt.Sprintf(format, a...))
11 | }
12 |
--------------------------------------------------------------------------------
/common/tool/tools/gin.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "git.xiaoyou.host/index/common/web"
5 | "github.com/gin-gonic/gin"
6 | "strconv"
7 | "strings"
8 | )
9 |
10 | // GinGetFiledInt 快速获取某一个字段的int类型
11 | func GinGetFiledInt(ctx *gin.Context, filed string) (int, bool) {
12 | // 获取id参数
13 | p := ctx.Param(filed)
14 | id, err := strconv.Atoi(p)
15 | if id == 0 || err != nil {
16 | web.Fail(ctx, "参数错误")
17 | return 0, false
18 | }
19 | return id, true
20 | }
21 |
22 | // GinGetQueryFiledInt 获取query字段
23 | func GinGetQueryFiledInt(ctx *gin.Context, filed string) int {
24 | id, _ := strconv.Atoi(ctx.Query(filed))
25 | return id
26 | }
27 |
28 | // GinGetFiledIntList 快速获取某一个字段列表
29 | func GinGetFiledIntList(ctx *gin.Context, filed string) []int64 {
30 | // 获取id参数
31 | strs := strings.Split(ctx.Param(filed), ",")
32 | res := make([]int64, 0, len(strs))
33 | for _, str := range strs {
34 | id, _ := strconv.Atoi(str)
35 | if id > 0 {
36 | res = append(res, int64(id))
37 | }
38 | }
39 |
40 | return res
41 | }
42 |
43 | // GinBindData 绑定数据
44 | func GinBindData(ctx *gin.Context, req interface{}) bool {
45 | if err := ctx.BindJSON(req); err != nil {
46 | web.Fail(ctx, "参数错误")
47 | return false
48 | }
49 | return true
50 | }
51 |
--------------------------------------------------------------------------------
/common/tool/tools/http.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "encoding/json"
7 | "git.xiaoyou.host/index/common/tool/log"
8 | "io"
9 | "io/ioutil"
10 | "net/http"
11 | )
12 |
13 | // HttpSendRequest 发送HTTP请求
14 | func HttpSendRequest(ctx context.Context, url string, method string, header map[string]string, data interface{}, resp interface{}) {
15 | var b io.Reader
16 | if data != nil {
17 | // 解析data数据
18 | row, _ := json.Marshal(data)
19 | b = bytes.NewReader(row)
20 | } else {
21 | b = nil
22 | }
23 |
24 | // 初始化request
25 | req, err := http.NewRequest(method, url, b)
26 | req.Header.Set("Content-Type", "application/json")
27 | for k, v := range header {
28 | req.Header.Set(k, v)
29 | }
30 | // 构建并发送请求
31 | client := &http.Client{}
32 | res, err := client.Do(req)
33 | if err != nil {
34 | log.CtxLogError(ctx, "send data error %v", err)
35 | return
36 | }
37 | defer res.Body.Close()
38 | body, _ := ioutil.ReadAll(res.Body)
39 | // 解析json数据
40 | err = json.Unmarshal(body, resp)
41 | if err != nil {
42 | log.CtxLogError(ctx, "unmarshal data err %v, body %s", err, string(body))
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/common/tool/tools/service.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | // GetObjectLink 获取节点直链
8 | func GetObjectLink(id string) string {
9 | return fmt.Sprintf("https://index.xiaoyou.host/data/object/%s", id)
10 | }
11 |
--------------------------------------------------------------------------------
/common/tool/tools/string.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import "time"
4 |
5 | // Time2String 时间转string
6 | func Time2String(times time.Time, showHour bool) string {
7 | var cstZone = time.FixedZone("CST", 8*3600)
8 | if showHour {
9 | return times.In(cstZone).Format("2006-01-02 15:04:05")
10 | }
11 | return times.In(cstZone).Format("2006-01-02")
12 | }
13 |
14 | // Str2Time string转时间
15 | func Str2Time(times string, hour bool) time.Time {
16 | if loc, err := time.LoadLocation("Local"); err == nil {
17 | var theTime time.Time
18 | // 是否为带时间的转换
19 | if hour {
20 | theTime, err = time.ParseInLocation("2006-01-02 15:04:05", times, loc)
21 | } else {
22 | theTime, err = time.ParseInLocation("2006-01-02", times, loc)
23 | }
24 | // 判断是否转换成功
25 | if err == nil {
26 | return theTime
27 | }
28 | }
29 | return time.Now()
30 | }
31 |
--------------------------------------------------------------------------------
/common/web/common.go:
--------------------------------------------------------------------------------
1 | package web
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type returnData struct {
9 | Code int `json:"code"`
10 | Msg string `json:"msg"`
11 | Data interface{} `json:"data"`
12 | }
13 |
14 | func Success(ctx *gin.Context, data interface{}) {
15 | ctx.JSON(200, returnData{
16 | Code: 200,
17 | Msg: "success",
18 | Data: data,
19 | })
20 | }
21 |
22 | func Fail(ctx *gin.Context, format string, a ...any) {
23 | ctx.JSON(200, returnData{
24 | Code: 500,
25 | Msg: fmt.Sprintf(format, a...),
26 | Data: nil,
27 | })
28 | }
29 |
--------------------------------------------------------------------------------
/data/.drone.yml:
--------------------------------------------------------------------------------
1 | kind: pipeline
2 | type: docker
3 | name: build
4 | steps:
5 | - name: build # 构建阶段
6 | image: golang:1.18.3
7 | pull: if-not-exists # 镜像拉取策略
8 | commands: # 下面这里是我们执行的命令。这里我们是使用go去编译项目
9 | - export GOPROXY="https://goproxy.cn"
10 | - go env -w GOPRIVATE=git.xiaoyou.host
11 | - go mod download
12 | - CGO_ENABLED=0 GOOS=linux go build -o app .
13 | - name: push # 自动推送到私有仓库update
14 | image: plugins/docker
15 | pull: if-not-exists # 镜像拉取策略
16 | settings:
17 | registry: registry.xiaoyou66.com # 私有仓库地址
18 | repo: registry.xiaoyou66.com/index/data # 仓库全称
19 | use_cache: true
20 | username: admin # 设置私有仓库的账号密码
21 | password: xiaoyou
22 | tags: # 设置我们的标签
23 | - latest
24 | - 0.0.3
25 | #trigger: # 这里设置使用master分支来触发
26 | # branch:
27 | # - master
--------------------------------------------------------------------------------
/data/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | data.go
3 | tmp
--------------------------------------------------------------------------------
/data/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM registry.xiaoyou66.com/library/alpine
2 | #WORKDIR /app
3 | # 拷贝我们编译好的文件
4 | COPY app /
5 | # 声明暴露的端口
6 | EXPOSE 8000
7 | EXPOSE 9000
8 | # 启动时直接运行app
9 | ENTRYPOINT chmod +x /app && /app
--------------------------------------------------------------------------------
/data/ent/config.go:
--------------------------------------------------------------------------------
1 | // Code generated by entc, DO NOT EDIT.
2 |
3 | package ent
4 |
5 | import (
6 | "entgo.io/ent"
7 | "entgo.io/ent/dialect"
8 | )
9 |
10 | // Option function to configure the client.
11 | type Option func(*config)
12 |
13 | // Config is the configuration for the client and its builder.
14 | type config struct {
15 | // driver used for executing database requests.
16 | driver dialect.Driver
17 | // debug enable a debug logging.
18 | debug bool
19 | // log used for logging on debug mode.
20 | log func(...interface{})
21 | // hooks to execute on mutations.
22 | hooks *hooks
23 | }
24 |
25 | // hooks per client, for fast access.
26 | type hooks struct {
27 | Object []ent.Hook
28 | }
29 |
30 | // Options applies the options on the config object.
31 | func (c *config) options(opts ...Option) {
32 | for _, opt := range opts {
33 | opt(c)
34 | }
35 | if c.debug {
36 | c.driver = dialect.Debug(c.driver, c.log)
37 | }
38 | }
39 |
40 | // Debug enables debug logging on the ent.Driver.
41 | func Debug() Option {
42 | return func(c *config) {
43 | c.debug = true
44 | }
45 | }
46 |
47 | // Log sets the logging function for debug mode.
48 | func Log(fn func(...interface{})) Option {
49 | return func(c *config) {
50 | c.log = fn
51 | }
52 | }
53 |
54 | // Driver configures the client driver.
55 | func Driver(driver dialect.Driver) Option {
56 | return func(c *config) {
57 | c.driver = driver
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/data/ent/context.go:
--------------------------------------------------------------------------------
1 | // Code generated by entc, DO NOT EDIT.
2 |
3 | package ent
4 |
5 | import (
6 | "context"
7 | )
8 |
9 | type clientCtxKey struct{}
10 |
11 | // FromContext returns a Client stored inside a context, or nil if there isn't one.
12 | func FromContext(ctx context.Context) *Client {
13 | c, _ := ctx.Value(clientCtxKey{}).(*Client)
14 | return c
15 | }
16 |
17 | // NewContext returns a new context with the given Client attached.
18 | func NewContext(parent context.Context, c *Client) context.Context {
19 | return context.WithValue(parent, clientCtxKey{}, c)
20 | }
21 |
22 | type txCtxKey struct{}
23 |
24 | // TxFromContext returns a Tx stored inside a context, or nil if there isn't one.
25 | func TxFromContext(ctx context.Context) *Tx {
26 | tx, _ := ctx.Value(txCtxKey{}).(*Tx)
27 | return tx
28 | }
29 |
30 | // NewTxContext returns a new context with the given Tx attached.
31 | func NewTxContext(parent context.Context, tx *Tx) context.Context {
32 | return context.WithValue(parent, txCtxKey{}, tx)
33 | }
34 |
--------------------------------------------------------------------------------
/data/ent/generate.go:
--------------------------------------------------------------------------------
1 | package ent
2 |
3 | //go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema
4 |
--------------------------------------------------------------------------------
/data/ent/migrate/schema.go:
--------------------------------------------------------------------------------
1 | // Code generated by entc, DO NOT EDIT.
2 |
3 | package migrate
4 |
5 | import (
6 | "entgo.io/ent/dialect/sql/schema"
7 | "entgo.io/ent/schema/field"
8 | )
9 |
10 | var (
11 | // ObjectsColumns holds the columns for the "objects" table.
12 | ObjectsColumns = []*schema.Column{
13 | {Name: "id", Type: field.TypeString, Unique: true},
14 | {Name: "object_name", Type: field.TypeString},
15 | {Name: "content_type", Type: field.TypeString},
16 | {Name: "object_location", Type: field.TypeUint8},
17 | {Name: "object_size", Type: field.TypeInt64},
18 | {Name: "object_sha256", Type: field.TypeString},
19 | {Name: "created_at", Type: field.TypeTime},
20 | {Name: "updated_at", Type: field.TypeTime},
21 | }
22 | // ObjectsTable holds the schema information for the "objects" table.
23 | ObjectsTable = &schema.Table{
24 | Name: "objects",
25 | Columns: ObjectsColumns,
26 | PrimaryKey: []*schema.Column{ObjectsColumns[0]},
27 | Indexes: []*schema.Index{
28 | {
29 | Name: "object_id",
30 | Unique: false,
31 | Columns: []*schema.Column{ObjectsColumns[0]},
32 | },
33 | },
34 | }
35 | // Tables holds all the tables in the schema.
36 | Tables = []*schema.Table{
37 | ObjectsTable,
38 | }
39 | )
40 |
41 | func init() {
42 | }
43 |
--------------------------------------------------------------------------------
/data/ent/predicate/predicate.go:
--------------------------------------------------------------------------------
1 | // Code generated by entc, DO NOT EDIT.
2 |
3 | package predicate
4 |
5 | import (
6 | "entgo.io/ent/dialect/sql"
7 | )
8 |
9 | // Object is the predicate function for object builders.
10 | type Object func(*sql.Selector)
11 |
--------------------------------------------------------------------------------
/data/ent/runtime.go:
--------------------------------------------------------------------------------
1 | // Code generated by entc, DO NOT EDIT.
2 |
3 | package ent
4 |
5 | import (
6 | "time"
7 |
8 | "index.data/ent/object"
9 | "index.data/ent/schema"
10 | )
11 |
12 | // The init function reads all schema descriptors with runtime code
13 | // (default values, validators, hooks and policies) and stitches it
14 | // to their package variables.
15 | func init() {
16 | objectFields := schema.Object{}.Fields()
17 | _ = objectFields
18 | // objectDescCreatedAt is the schema descriptor for created_at field.
19 | objectDescCreatedAt := objectFields[6].Descriptor()
20 | // object.DefaultCreatedAt holds the default value on creation for the created_at field.
21 | object.DefaultCreatedAt = objectDescCreatedAt.Default.(func() time.Time)
22 | // objectDescUpdatedAt is the schema descriptor for updated_at field.
23 | objectDescUpdatedAt := objectFields[7].Descriptor()
24 | // object.DefaultUpdatedAt holds the default value on creation for the updated_at field.
25 | object.DefaultUpdatedAt = objectDescUpdatedAt.Default.(time.Time)
26 | // object.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
27 | object.UpdateDefaultUpdatedAt = objectDescUpdatedAt.UpdateDefault.(func() time.Time)
28 | }
29 |
--------------------------------------------------------------------------------
/data/ent/runtime/runtime.go:
--------------------------------------------------------------------------------
1 | // Code generated by entc, DO NOT EDIT.
2 |
3 | package runtime
4 |
5 | // The schema-stitching logic is generated in index.data/ent/runtime.go
6 |
7 | const (
8 | Version = "v0.10.1" // Version of ent codegen.
9 | Sum = "h1:dM5h4Zk6yHGIgw4dCqVzGw3nWgpGYJiV4/kyHEF6PFo=" // Sum of ent codegen.
10 | )
11 |
--------------------------------------------------------------------------------
/data/ent/schema/object.go:
--------------------------------------------------------------------------------
1 | package schema
2 |
3 | import (
4 | "entgo.io/ent"
5 | "entgo.io/ent/schema/field"
6 | "entgo.io/ent/schema/index"
7 | "time"
8 | )
9 |
10 | // Object holds the schema definition for the Object entity.
11 | type Object struct {
12 | ent.Schema
13 | }
14 |
15 | // Fields of the Object.
16 | func (Object) Fields() []ent.Field {
17 | return []ent.Field{
18 | field.String("id").Unique(), // 对象ID
19 | field.String("object_name"), // 对象名称(对应原始文件名)
20 | field.String("content_type"), // 对象类型
21 | field.Uint8("object_location"), // 存储位置 1 对象存储 2 文本存储
22 | field.Int64("object_size"), // 对象大小
23 | field.String("object_sha256"), // 对象Sha256的值
24 | field.Time("created_at").Default(time.Now), // 对象创建时间
25 | field.Time("updated_at").Default(time.Now()).UpdateDefault(time.Now), // 对象更新时间
26 | }
27 | }
28 |
29 | // Edges of the Object.
30 | func (Object) Edges() []ent.Edge {
31 | return nil
32 | }
33 |
34 | func (Object) Indexes() []ent.Index {
35 | return []ent.Index{index.Fields("id")} // 给对象ID创建一个索引
36 | }
37 |
--------------------------------------------------------------------------------
/data/internal/rpc/rpc_test.go:
--------------------------------------------------------------------------------
1 | package rpc
2 |
3 |
4 |
--------------------------------------------------------------------------------
/data/internal/service/common.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "crypto/sha256"
6 | "fmt"
7 | "index.data/internal/tools"
8 | "io"
9 | )
10 |
11 | func getObjectSha256(ctx context.Context, id string, contentType string, location int) (string, int64) {
12 | if location == 2 {
13 | object, err := kvRock.GetTextByte(ctx, id)
14 | if err != nil {
15 | return "", 0
16 | }
17 | h := sha256.New()
18 | h.Write(object)
19 | return fmt.Sprintf("%X", h.Sum(nil)), int64(len(object))
20 | }
21 | // 先获取对象
22 | object, err := fileObject.GetObjet(ctx, tools.GetBucketFromContentType(contentType), id)
23 | if err != nil {
24 | fmt.Println(err)
25 | return "", 0
26 | }
27 | ha := sha256.New()
28 | if _, err := io.Copy(ha, object.Data); err != nil {
29 | fmt.Println(err)
30 | return "", 0
31 | }
32 | return fmt.Sprintf("%X", ha.Sum(nil)), object.Size
33 | }
34 |
35 | func GetReaderSha256(data io.Reader) string {
36 | ha := sha256.New()
37 | if _, err := io.Copy(ha, data); err != nil {
38 | return ""
39 | }
40 | return fmt.Sprintf("%X", ha.Sum(nil))
41 | }
42 |
43 | func getByteSha256(data []byte) (string, int64) {
44 | h := sha256.New()
45 | h.Write(data)
46 | return fmt.Sprintf("%X", h.Sum(nil)), int64(len(data))
47 | }
48 |
--------------------------------------------------------------------------------
/data/internal/service/kvrocks.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "github.com/go-redis/redis/v8"
6 | )
7 |
8 | // CreateKvRocksService 文本存储服务
9 | func CreateKvRocksService(addr string) *KvRocksService {
10 | rdb := redis.NewClient(&redis.Options{
11 | Addr: addr,
12 | Password: "", // no password set
13 | DB: 0, // use default DB
14 | })
15 | if rdb.Ping(context.Background()).Val() != "PONG" {
16 | panic(any("redis client error"))
17 | }
18 | return &KvRocksService{client: rdb}
19 | }
20 |
21 | type KvRocksService struct {
22 | client *redis.Client
23 | }
24 |
25 | // SetText 设置文本信息
26 | func (s KvRocksService) SetText(ctx context.Context, key string, value interface{}) error {
27 | // 需要对文本进行base4编码
28 | return s.client.Set(ctx, key, value, 0).Err()
29 | }
30 |
31 | // GetTextByte 获取文本信息
32 | func (s KvRocksService) GetTextByte(ctx context.Context, key string) ([]byte, error) {
33 | return s.client.Get(ctx, key).Bytes()
34 | }
35 |
36 | // GetText 获取文本信息
37 | func (s KvRocksService) GetText(ctx context.Context, key string) (string, error) {
38 | cmd := s.client.Get(ctx, key)
39 | return cmd.Val(), cmd.Err()
40 | }
41 |
42 | // DeleteText 删除文本
43 | func (s KvRocksService) DeleteText(ctx context.Context, key string) error {
44 | return s.client.Del(ctx, key).Err()
45 | }
46 |
--------------------------------------------------------------------------------
/data/internal/service/kvrocks_test.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 | )
8 |
9 | func TestClient(t *testing.T) {
10 | s := CreateKvRocksService()
11 | err := s.SetText(context.Background(), "123", []byte("hello word"))
12 | fmt.Println(err)
13 | a, err := s.GetTextByte(context.Background(), "123")
14 | fmt.Println(err)
15 | fmt.Println(string(a))
16 | }
17 |
--------------------------------------------------------------------------------
/data/internal/service/redis.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/go-redis/redis/v8"
7 | "time"
8 | )
9 |
10 | func CreateRedisService(addr string) *RedisService {
11 | rdb := redis.NewClient(&redis.Options{
12 | Addr: addr,
13 | Password: "", // no password set
14 | DB: 0, // use default DB
15 | })
16 | if rdb.Ping(context.Background()).Val() != "PONG" {
17 | panic(any("redis client error"))
18 | }
19 | return &RedisService{client: rdb}
20 | }
21 |
22 | type RedisService struct {
23 | client *redis.Client
24 | }
25 |
26 | // SetByte 设置字节
27 | func (r RedisService) SetByte(ctx context.Context, key string, current int32, value []byte) error {
28 | return r.client.Set(ctx, fmt.Sprintf("%s:%d", key, current), value, time.Hour).Err()
29 | }
30 |
31 | // GetByte 获取字节数据
32 | func (r RedisService) GetByte(ctx context.Context, key string, current int32) ([]byte, error) {
33 | return r.client.Get(ctx, fmt.Sprintf("%s:%d", key, current)).Bytes()
34 | }
35 |
36 | // DeleteByte 删除key
37 | func (r RedisService) DeleteByte(ctx context.Context, key string, current int32) error {
38 | return r.client.Del(ctx, fmt.Sprintf("%s:%d", key, current)).Err()
39 | }
40 |
--------------------------------------------------------------------------------
/data/internal/tools/content_type.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import "strings"
4 |
5 | const (
6 | TypeJPG = "image/jpeg"
7 | TypePNG = "image/png"
8 | TypeGIF = "image/gif"
9 | TypeText = "text/plain"
10 | TypeMp3 = "audio/mpeg"
11 | TypeMp4 = "video/mp4"
12 | TypeOther = "application/octet-stream"
13 | )
14 |
15 | // GetContentType 获取文件的contentType类型
16 | func GetContentType(filename string) string {
17 | index := strings.LastIndex(filename, ".")
18 | if index == -1 {
19 | return TypeOther
20 | }
21 | switch filename[index+1:] {
22 | case "png":
23 | return TypePNG
24 | case "jpg", "jpeg":
25 | return TypeJPG
26 | case "mp3":
27 | return TypeMp3
28 | case "mp4", "mkv":
29 | return TypeMp4
30 | case "txt", "lrc", "ass", "nfo":
31 | return TypeText
32 | default:
33 | return TypeOther
34 | }
35 | }
36 |
37 | // GetBucketFromContentType 获取存储的bucket
38 | func GetBucketFromContentType(contentType string) string {
39 | switch contentType {
40 | case TypeJPG, TypePNG, TypeGIF:
41 | return "image"
42 | case TypeMp4:
43 | return "video"
44 | case TypeMp3:
45 | return "music"
46 | case TypeText:
47 | return "text"
48 | default:
49 | return "other"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/data/internal/tools/content_type_test.go:
--------------------------------------------------------------------------------
1 | package tools
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | "testing"
7 | )
8 |
9 | func TestGetContentType(t *testing.T) {
10 | //assert.Same(t, TypeJPG, GetContentType("21323.jpg"))
11 | }
12 |
13 | func TestName(t *testing.T) {
14 | file := "q.aaa.222"
15 | index := strings.LastIndex(file, ".")
16 | fmt.Println(file[:index])
17 | }
18 |
--------------------------------------------------------------------------------
/data/internal/web/common.go:
--------------------------------------------------------------------------------
1 | package web
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | )
7 |
8 | type returnData struct {
9 | Code int `json:"code"`
10 | Msg string `json:"msg"`
11 | Data interface{} `json:"data"`
12 | }
13 |
14 | func success(ctx *gin.Context, data interface{}) {
15 | ctx.JSON(200, returnData{
16 | Code: 200,
17 | Msg: "success",
18 | Data: data,
19 | })
20 | }
21 |
22 | func fail(ctx *gin.Context, format string, a ...any) {
23 | ctx.JSON(200, returnData{
24 | Code: 500,
25 | Msg: fmt.Sprintf(format, a...),
26 | Data: nil,
27 | })
28 | }
29 |
--------------------------------------------------------------------------------
/data/internal/web/model.go:
--------------------------------------------------------------------------------
1 | package web
2 |
3 | type addObjectResp struct {
4 | ObjectID string `json:"object_id"` // 对象ID
5 | }
6 |
7 | type getTextResp struct {
8 | Name string `json:"name"`
9 | Content string `json:"content"`
10 | }
11 |
12 | // FileUploadReq 文件上传携带的值
13 | type FileUploadReq struct {
14 | TotalChunk int32 `json:"totalChunk" form:"totalChunks"` // 总分片大小
15 | Current int32 `json:"current" form:"chunkNumber"` // 当前几个分片
16 | TotalSize int64 `json:"totalSize" form:"totalSize"` // 总大小
17 | Name string `json:"name" form:"filename"` // 文件名
18 | Data string `json:"data" form:"data"` // 文件数据(使用base4)
19 | }
20 |
--------------------------------------------------------------------------------
/data/internal/web/router.go:
--------------------------------------------------------------------------------
1 | package web
2 |
3 | import "github.com/gin-gonic/gin"
4 |
5 | // RegisterRouter 注册http路由
6 | func RegisterRouter(r *gin.Engine) {
7 | // 获取对象
8 | r.GET("/data/object/:id", getObject)
9 | // 获取对象信息
10 | r.GET("/data/object/:id/info", getObjectInfo)
11 | // 上传对象
12 | r.POST("/data/object", addObject)
13 | // 删除对象
14 | r.DELETE("/data/object/:id", deleteObject)
15 | // 获取文本对象
16 | r.GET("/data/text/:id", getObjectText)
17 | // 添加文本对象
18 | r.POST("/data/text", addObjectText)
19 | // 更新文本对象
20 | r.PUT("/data/text/:id", updateObjectText)
21 |
22 | // 上传大文件
23 | r.POST("/data/object/big", uploadBigObject)
24 | // 根据sha256返回文件内容
25 | r.GET("/data/object/sha256", FindFileBySha256)
26 | }
27 |
--------------------------------------------------------------------------------
/data/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "git.xiaoyou.host/index/common/proto/data"
5 | "github.com/gin-gonic/gin"
6 | "github.com/go-kratos/kratos/contrib/registry/consul/v2"
7 | "github.com/go-kratos/kratos/v2"
8 | "github.com/go-kratos/kratos/v2/middleware/recovery"
9 | "github.com/go-kratos/kratos/v2/transport/grpc"
10 | "github.com/go-kratos/kratos/v2/transport/http"
11 | "github.com/hashicorp/consul/api"
12 | "index.data/internal/rpc"
13 | "index.data/internal/web"
14 | )
15 |
16 | func main() {
17 | // 服务发现
18 | config := api.DefaultConfig()
19 | // 这里配置成我们的consul的agent地址
20 | config.Address = "consul-0.consul.xiaoyou-index.svc.cluster.local:8500"
21 | consulClient, err := api.NewClient(config)
22 | if err != nil {
23 | panic(any(err))
24 | }
25 | r := consul.New(consulClient)
26 | // 路由注册
27 | router := gin.Default()
28 | web.RegisterRouter(router)
29 | // 启动web服务
30 | httpSrv := http.NewServer(http.Address(":8001"))
31 | httpSrv.HandlePrefix("/", router)
32 | // 启动rpc服务
33 | s := rpc.NewDataService()
34 | grpcSrv := grpc.NewServer(
35 | grpc.Address(":9001"),
36 | grpc.Middleware(recovery.Recovery()))
37 | data.RegisterDataServer(grpcSrv, s)
38 | // 启动总服务
39 | app := kratos.New(
40 | kratos.Name("index.data"),
41 | kratos.Server(httpSrv, grpcSrv),
42 | kratos.Registrar(r))
43 | if err := app.Run(); err != nil {
44 | panic(any(err))
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/data/openapi.yaml:
--------------------------------------------------------------------------------
1 | # Generated with protoc-gen-openapi
2 | # https://github.com/google/gnostic/tree/master/cmd/protoc-gen-openapi
3 |
4 | openapi: 3.0.3
5 | info:
6 | title: ""
7 | version: 0.0.1
8 | paths: {}
9 | components:
10 | schemas: {}
11 |
--------------------------------------------------------------------------------
/data/pkg/storage/api.go:
--------------------------------------------------------------------------------
1 | package storage
2 |
3 | import (
4 | "context"
5 | "io"
6 | )
7 |
8 | // Storage 标准存储接口
9 | type Storage interface {
10 | PutObjet(ctx context.Context, bucket string, obj Object) error // 存储对象
11 | GetObjet(ctx context.Context, bucket string, objectID string) (Object, error) // 获取对象
12 | DeleteObject(ctx context.Context, bucket string, objectID string) error // 删除对象
13 | GetDownloadLink(ctx context.Context, bucket string, objectID string, filename string) (string, error) // 获取对象的临时下载链接
14 | PutLargeObject(ctx context.Context, bucket string, obj Object, filepath string) error
15 | }
16 |
17 | // Object 对象内容
18 | type Object struct {
19 | ObjectID string `json:"object_id"` // 对象ID
20 | ContentType string `json:"content_type"` // 对象类型
21 | Data io.Reader `json:"data"` // 对象内容
22 | Size int64 `json:"size"` // 文件
23 | }
24 |
--------------------------------------------------------------------------------
/data/script/generate_service.sh:
--------------------------------------------------------------------------------
1 | # 自动生成服务端和客户端代码
2 | export GOPROXY="https://goproxy.cn"
3 | cd ..
4 | kratos proto client api/data.proto
5 | kratos proto server api/data.proto -t internal/rpc
--------------------------------------------------------------------------------
/file-front/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [["@babel/preset-env", { "modules": false }]],
3 | "plugins": [
4 | [
5 | "component",
6 | {
7 | "libraryName": "element-ui",
8 | "styleLibraryName": "theme-chalk"
9 | }
10 | ]
11 | ]
12 | }
--------------------------------------------------------------------------------
/file-front/.drone.yml:
--------------------------------------------------------------------------------
1 | kind: pipeline
2 | type: docker
3 | name: build
4 | steps:
5 | - name: build # 构建阶段
6 | image: node:16.13.0
7 | pull: if-not-exists # 镜像拉取策略
8 | commands: # 下面这里是我们执行的命令
9 | - yarn install # 安装依赖
10 | - yarn run build # 构建应用
11 | - name: push # 自动推送到私有仓库update
12 | image: plugins/docker
13 | pull: if-not-exists # 镜像拉取策略
14 | settings:
15 | registry: registry.xiaoyou66.com # 私有仓库地址
16 | repo: registry.xiaoyou66.com/index/web-file # 仓库全称
17 | use_cache: true
18 | username: admin # 设置私有仓库的账号密码
19 | password: xiaoyou
20 | tags: # 设置我们的标签
21 | - latest
22 | - 0.0.3
23 | #trigger: # 这里设置使用master分支来触发
24 | # branch:
25 | # - master
26 |
--------------------------------------------------------------------------------
/file-front/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | # .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/file-front/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 80, // 每行最大字符数为 80, 如果超出则换行
3 | tabWidth: 2, // 一个制表符等于的空格数
4 | useTabs: true, // 使用 tab 缩进
5 | singleQuote: true, // 使用单引号
6 | semi: false, // 代码结尾不加分号
7 | trailingComma: 'none', // 不自动添加逗号
8 | bracketSpacing: true, // 控制对象字面量的空格输出
9 | jsxBracketSameLine: false, // 将多行jsx的>放到下一行
10 | endOfLine: 'auto'
11 | }
12 |
--------------------------------------------------------------------------------
/file-front/.workflow/pipeline-20220519.yml:
--------------------------------------------------------------------------------
1 | version: '1.0'
2 | name: pipeline-20220519
3 | displayName: pipeline-20220519
4 | triggers:
5 | trigger: manual
6 | push:
7 | branches:
8 | prefix:
9 | - ''
10 | stages:
11 | - name: stage-f911a4d4
12 | displayName: 编译
13 | strategy: naturally
14 | trigger: auto
15 | executor: []
16 | steps:
17 | - step: build@nodejs
18 | name: build_nodejs
19 | displayName: Nodejs 构建
20 | nodeVersion: 14.16.0
21 | commands:
22 | - npm install && rm -rf ./dist && npm run build
23 | artifacts:
24 | - name: BUILD_ARTIFACT
25 | path:
26 | - ./dist
27 | - name: stage-dbe565b9
28 | displayName: 部署
29 | strategy: naturally
30 | trigger: auto
31 | executor: []
32 | steps:
33 | - step: deploy@agent
34 | name: deploy_agent
35 | displayName: 主机部署
36 | hostGroupID: qiwen
37 | deployArtifact:
38 | - source: build
39 | name: qiwen-file-web
40 | target: ~/gitee_go/deploy/qiwen-file-web
41 | dependArtifact: BUILD_ARTIFACT
42 | script: |-
43 | # 请在此输入部署脚本,如启动Java应用如下
44 | # nohup java -jar test.jar > nohup.out &
45 | cd ~/gitee_go/deploy/qiwen-file-web
46 | tar -zxvf qiwen-file-web.tar.gz
47 | rm -r /home/html/opensoftware/file
48 | cp -r dist /home/html/opensoftware/file
49 | echo 'Hello Gitee!'
50 | strategy:
51 | retry: '0'
52 | permissions:
53 | - role: admin
54 | members: []
55 |
--------------------------------------------------------------------------------
/file-front/Dockerfile:
--------------------------------------------------------------------------------
1 | #拉取nginx镜像
2 | FROM registry.xiaoyou66.com/library/nginx:latest
3 | # 拷贝编译好的应用
4 | COPY dist/ /usr/share/nginx/html/
5 | # 拷贝配置文件
6 | COPY default.conf /etc/nginx/conf.d/default.conf
7 |
--------------------------------------------------------------------------------
/file-front/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 MAC
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/file-front/README.md:
--------------------------------------------------------------------------------
1 | ## 个人网盘
2 |
--------------------------------------------------------------------------------
/file-front/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/file-front/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name localhost;
4 |
5 | #charset koi8-r;
6 | access_log /var/log/nginx/host.access.log main;
7 | error_log /var/log/nginx/error.log error;
8 |
9 | location / {
10 | root /usr/share/nginx/html;
11 | index index.html index.htm;
12 | }
13 |
14 | #error_page 404 /404.html;
15 |
16 | # redirect server error pages to the static page /50x.html
17 | #
18 | error_page 500 502 503 504 /50x.html;
19 | location = /50x.html {
20 | root /usr/share/nginx/html;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/file-front/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "@/*": ["src/*"],
6 | "_v/*": ["src/views/*"],
7 | "_c/*": ["src/components/*"],
8 | "_a/*": ["src/assets/*"],
9 | "_r": ["src/request/*"],
10 | "_public": ["public/*"]
11 | }
12 | },
13 | "exclude": ["node_modules", "dist"]
14 | }
15 |
--------------------------------------------------------------------------------
/file-front/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/public/favicon.ico
--------------------------------------------------------------------------------
/file-front/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/file-front/public/mavonEditor/css/tomorrow-night.css:
--------------------------------------------------------------------------------
1 | /* Tomorrow Night Theme */
2 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
3 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */
4 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
5 |
6 | /* Tomorrow Comment */
7 | .hljs-comment,
8 | .hljs-quote {
9 | color: #969896;
10 | }
11 |
12 | /* Tomorrow Red */
13 | .hljs-variable,
14 | .hljs-template-variable,
15 | .hljs-tag,
16 | .hljs-name,
17 | .hljs-selector-id,
18 | .hljs-selector-class,
19 | .hljs-regexp,
20 | .hljs-deletion {
21 | color: #cc6666;
22 | }
23 |
24 | /* Tomorrow Orange */
25 | .hljs-number,
26 | .hljs-built_in,
27 | .hljs-builtin-name,
28 | .hljs-literal,
29 | .hljs-type,
30 | .hljs-params,
31 | .hljs-meta,
32 | .hljs-link {
33 | color: #de935f;
34 | }
35 |
36 | /* Tomorrow Yellow */
37 | .hljs-attribute {
38 | color: #f0c674;
39 | }
40 |
41 | /* Tomorrow Green */
42 | .hljs-string,
43 | .hljs-symbol,
44 | .hljs-bullet,
45 | .hljs-addition {
46 | color: #b5bd68;
47 | }
48 |
49 | /* Tomorrow Blue */
50 | .hljs-title,
51 | .hljs-section {
52 | color: #81a2be;
53 | }
54 |
55 | /* Tomorrow Purple */
56 | .hljs-keyword,
57 | .hljs-selector-tag {
58 | color: #b294bb;
59 | }
60 |
61 | .hljs {
62 | display: block;
63 | overflow-x: auto;
64 | background: #1d1f21;
65 | color: #c5c8c6;
66 | padding: 16px;
67 | }
68 |
69 | .hljs-emphasis {
70 | font-style: italic;
71 | }
72 |
73 | .hljs-strong {
74 | font-weight: bold;
75 | }
76 |
--------------------------------------------------------------------------------
/file-front/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
21 |
43 |
--------------------------------------------------------------------------------
/file-front/src/assets/images/audio/wave.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/audio/wave.gif
--------------------------------------------------------------------------------
/file-front/src/assets/images/common/logo_footer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/common/logo_footer.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/common/logo_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/common/logo_header.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/common/logo_header_xs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/common/logo_header_xs.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/error/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/error/404.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/dir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/dir.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_avi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_avi.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_c#.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_c#.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_c++.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_c++.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_c.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_c.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_chm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_chm.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_css.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_css.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_csv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_csv.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_dmg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_dmg.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_exe.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_gif.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_gif.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_go.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_go.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_html.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_html.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_jar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_jar.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_java.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_java.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_js.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_json.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_json.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_jsp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_jsp.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_kotlin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_kotlin.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_less.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_less.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_lua.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_lua.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_markdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_markdown.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_music.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_music.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_nginx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_nginx.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_oa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_oa.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_objective_c.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_objective_c.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_open.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_pdf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_pdf.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_php.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_php.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_powershell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_powershell.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_properties.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_properties.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_python.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_python.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_r.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_rar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_rar.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_rtf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_rtf.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_rust.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_rust.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_sass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_sass.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_scss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_scss.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_shell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_shell.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_sql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_sql.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_stylus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_stylus.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_svg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_svg.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_swift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_swift.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_txt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_txt.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_typescript.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_typescript.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_unknown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_unknown.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_vue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_vue.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_xml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_xml.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_yaml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_yaml.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/file/file_zip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/file/file_zip.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/footer/QQImg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/footer/QQImg.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/footer/QQLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/footer/QQLogo.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/footer/giteeImg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/footer/giteeImg.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/footer/wechatImg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/footer/wechatImg.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/footer/wechatLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/footer/wechatLogo.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/banner/banner1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/banner/banner1.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/function/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/function/delete.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/function/edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/function/edit.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/function/operation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/function/operation.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/function/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/function/preview.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/function/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/function/search.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/function/shard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/function/shard.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/function/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/function/share.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/function/store.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/function/store.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/function/type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/function/type.png
--------------------------------------------------------------------------------
/file-front/src/assets/images/home/notice/noticeTip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/images/home/notice/noticeTip.png
--------------------------------------------------------------------------------
/file-front/src/assets/styles/base.styl:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | outline: 0;
6 | font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
7 | 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
8 | }
9 | html {
10 | height: 100%;
11 | }
12 | body {
13 | height: 100%;
14 | font-size: 16px;
15 | overflow-x: hidden;
16 | }
17 | a {
18 | text-decoration: none;
19 | }
20 | img {
21 | vertical-align: middle;
22 | }
23 | p {
24 | line-height: 24px;
25 | }
26 |
--------------------------------------------------------------------------------
/file-front/src/assets/styles/elementCover.styl:
--------------------------------------------------------------------------------
1 | // element UI 样式覆盖
2 | .el-dialog__wrapper {
3 | .el-dialog {
4 | margin-top: 9vh !important;
5 | }
6 | }
7 | .el-avatar > img {
8 | width: 100%;
9 | }
10 | .el-textarea__inner {
11 | font-family: inherit;
12 | }
13 | .el-input__count {
14 | line-height: 100%;
15 | }
16 |
--------------------------------------------------------------------------------
/file-front/src/assets/styles/iconfont/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "iconfont"; /* Project id 2613341 */
3 | src: url('iconfont.eot?t=1651979043996'); /* IE9 */
4 | src: url('iconfont.eot?t=1651979043996#iefix') format('embedded-opentype'), /* IE6-IE8 */
5 | url('iconfont.woff?t=1651979043996') format('woff'),
6 | url('iconfont.ttf?t=1651979043996') format('truetype'),
7 | url('iconfont.svg?t=1651979043996#iconfont') format('svg');
8 | }
9 |
10 | .iconfont {
11 | font-family: "iconfont" !important;
12 | font-size: 16px;
13 | font-style: normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .icon-jingyin01:before {
19 | content: "\e692";
20 | }
21 |
22 | .icon-yinliang101:before {
23 | content: "\e72a";
24 | }
25 |
26 | .icon-icon-3:before {
27 | content: "\e64b";
28 | }
29 |
30 | .icon-icon-7:before {
31 | content: "\e64f";
32 | }
33 |
34 | .icon-suijibofang1:before {
35 | content: "\e66b";
36 | }
37 |
38 | .icon-xunhuanbofang:before {
39 | content: "\e66c";
40 | }
41 |
42 | .icon-danquxunhuan1:before {
43 | content: "\e66d";
44 | }
45 |
46 | .icon-shangyishou:before {
47 | content: "\e718";
48 | }
49 |
50 | .icon-xiayishou:before {
51 | content: "\e719";
52 | }
53 |
54 | .icon-liebiao1:before {
55 | content: "\e608";
56 | }
57 |
58 | .icon-baocun:before {
59 | content: "\e605";
60 | }
61 |
62 | .icon-qq:before {
63 | content: "\e600";
64 | }
65 |
66 | .icon-mayun:before {
67 | content: "\e6d0";
68 | }
69 |
70 | .icon-weixin-copy:before {
71 | content: "\e601";
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/file-front/src/assets/styles/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/styles/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/file-front/src/assets/styles/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/styles/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/file-front/src/assets/styles/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/file-front/src/assets/styles/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/file-front/src/assets/styles/iconfontCover.styl:
--------------------------------------------------------------------------------
1 | .iconfont {
2 | font-size: inherit;
3 | }
--------------------------------------------------------------------------------
/file-front/src/assets/styles/mixins.styl:
--------------------------------------------------------------------------------
1 | // 设置滚动条样式
2 | // scrollbarWidth:滚动条宽度
3 | // trackColor:轨道颜色
4 | // thumbColor:滑块颜色
5 | setScrollbar(scrollbarWidth, trackColor = #EBEEF5, thumbColor = #909399) {
6 | // 修改滚动条下面的宽度
7 | &::-webkit-scrollbar {
8 | width: scrollbarWidth;
9 | }
10 | // 修改滚动条的下面的样式
11 | &::-webkit-scrollbar-track {
12 | background-color: trackColor;
13 | -webkit-border-radius: 2em;
14 | -moz-border-radius: 2em;
15 | border-radius: 2em;
16 | }
17 | // 修改滑块
18 | &::-webkit-scrollbar-thumb {
19 | background-color: thumbColor;
20 | -webkit-border-radius: 2em;
21 | -moz-border-radius: 2em;
22 | border-radius: 2em;
23 | }
24 | }
25 | // 设置文字过长显示省略号
26 | // line:在当前行显示省略号
27 | setEllipsis(line) {
28 | display: -webkit-box;
29 | overflow: hidden;
30 | white-space: wrap;
31 | text-overflow: ellipsis;
32 | -webkit-box-orient: vertical; /* -webkit-box-orient 必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式 */
33 | -webkit-line-clamp: line; /* -webkit-line-clamp用来限制在一个块元素显示的文本的行数 */
34 | }
--------------------------------------------------------------------------------
/file-front/src/assets/styles/varibles.styl:
--------------------------------------------------------------------------------
1 | // 主题色
2 | $Primary = #409EFF;
3 | $Success = #67C23A;
4 | $Warning = #E6A23C;
5 | $Danger = #F56C6C;
6 | $Info = #909399;
7 | // 主题色的 Hover 颜色
8 | $PrimaryHover = #ecf5ff;
9 | $SuccessHover = #f0f9eb;
10 | $WarningHover = #fdf6ec;
11 | $DangerHover = #fdf6ec;
12 | $InfoHover = #e9e9eb;
13 | // 文字颜色
14 | $PrimaryText = #303133;
15 | $RegularText = #606266;
16 | $SecondaryText = #909399;
17 | $Placeholder = #C0C4CC;
18 | // 边框颜色
19 | $BorderBase = #DCDFE6;
20 | $BorderLight = #E4E7ED;
21 | $BorderLighter = #EBEEF5;
22 | $BorderExtralight = #F2F6FC;
23 | // 背景色
24 | $tabBackColor = #F5F7FA;
25 | // 阴影颜色
26 | $tabBoxShadow = 0 2px 12px 0 rgba(0, 0, 0, 0.1);
27 | $tabBoxShadowMin = 0 2px 4px 0 rgba(0, 0, 0, 0.1);
--------------------------------------------------------------------------------
/file-front/src/components/common/MarkdownPreview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
22 |
--------------------------------------------------------------------------------
/file-front/src/components/file/box/audioPreview/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import AudioPreview from './BoxMask.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const AudioPreviewConstructor = Vue.extend(AudioPreview)
6 |
7 | let audioPreviewInstance = null
8 | /**
9 | * 初始化音频预览实例
10 | * @param {string} audioList 音频列表
11 | * @param {object} defaultIndex 当前查看的音频索引
12 | */
13 | const initInstanceAudioPreview = (audioList, defaultIndex) => {
14 | audioPreviewInstance = new AudioPreviewConstructor({
15 | el: document.createElement('div'),
16 | data() {
17 | return {
18 | audioList,
19 | defaultIndex
20 | }
21 | }
22 | })
23 | }
24 | /**
25 | * 音频预览 Promise 函数
26 | * @returns {Promise} 抛出确认和取消回调函数
27 | */
28 | const showAudioPreviewBox = (obj) => {
29 | // 非首次调用服务时,在 DOM 中移除上个实例
30 | if (audioPreviewInstance !== null) {
31 | document.body.removeChild(audioPreviewInstance.$el)
32 | }
33 | let { audioList, defaultIndex } = obj
34 | return new Promise((reslove) => {
35 | initInstanceAudioPreview(audioList, defaultIndex)
36 | audioPreviewInstance.callback = (res) => {
37 | reslove(res)
38 | // 服务取消时卸载 DOM
39 | if (res === 'cancel' && audioPreviewInstance !== null) {
40 | document.body.removeChild(audioPreviewInstance.$el)
41 | audioPreviewInstance = null
42 | }
43 | }
44 | document.body.appendChild(audioPreviewInstance.$el) // 挂载 DOM
45 | Vue.nextTick(() => {
46 | audioPreviewInstance.visible = true // 打开音频预览遮罩层
47 | })
48 | })
49 | }
50 |
51 | export default showAudioPreviewBox
52 |
--------------------------------------------------------------------------------
/file-front/src/components/file/box/codePreview/fold.js:
--------------------------------------------------------------------------------
1 | // 折叠
2 | import 'codemirror/addon/fold/foldgutter.css'
3 | import 'codemirror/addon/fold/foldcode'
4 | import 'codemirror/addon/fold/foldgutter'
5 | import 'codemirror/addon/fold/brace-fold'
6 | import 'codemirror/addon/fold/comment-fold'
7 | import 'codemirror/addon/fold/indent-fold'
8 |
--------------------------------------------------------------------------------
/file-front/src/components/file/box/codePreview/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import CodePreview from './BoxMask.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const CodePreviewConstructor = Vue.extend(CodePreview)
6 |
7 | let codePreviewInstance = null
8 | /**
9 | * 初始化代码预览实例
10 | * @param {string} fileInfo 文件信息
11 | * @param {boolean} isEdit 是否可编辑
12 | */
13 | const initInstanceCodePreview = (fileInfo, isEdit) => {
14 | codePreviewInstance = new CodePreviewConstructor({
15 | el: document.createElement('div'),
16 | data() {
17 | return {
18 | fileInfo,
19 | isEdit
20 | }
21 | }
22 | })
23 | }
24 | /**
25 | * 代码预览 Promise 函数
26 | * @returns {Promise} 抛出确认和取消回调函数
27 | */
28 | const showCodePreviewBox = (obj) => {
29 | // 非首次调用服务时,在 DOM 中移除上个实例
30 | if (codePreviewInstance !== null) {
31 | document.body.removeChild(codePreviewInstance.$el)
32 | }
33 | let { fileInfo, isEdit } = obj
34 | return new Promise((reslove) => {
35 | initInstanceCodePreview(fileInfo, isEdit)
36 | codePreviewInstance.callback = (res) => {
37 | reslove(res)
38 | // 服务取消时卸载 DOM
39 | if (res === 'cancel' && codePreviewInstance !== null) {
40 | document.body.removeChild(codePreviewInstance.$el)
41 | codePreviewInstance = null
42 | }
43 | }
44 | document.body.appendChild(codePreviewInstance.$el) // 挂载 DOM
45 | Vue.nextTick(() => {
46 | codePreviewInstance.visible = true // 打开代码预览遮罩层
47 | })
48 | })
49 | }
50 |
51 | export default showCodePreviewBox
52 |
--------------------------------------------------------------------------------
/file-front/src/components/file/box/codePreview/mode.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 这里引入几个常用的语言解析模式
3 | * 全量语言模式参考,https://codemirror.net/mode/
4 | */
5 | import 'codemirror/mode/clike/clike.js' // C | C++ | Objective-C | Scala | Ceylon | Java 语言
6 | import 'codemirror/mode/javascript/javascript.js' // JavaScript 语言
7 | import 'codemirror/mode/css/css.js' // css 语言 | less 预编译器 | scss 预编译器
8 | import 'codemirror/mode/go/go.js' // Go 语言
9 | import 'codemirror/mode/nginx/nginx.js' // Nginx 语言
10 | import 'codemirror/mode/php/php.js' // PHP 语言
11 | import 'codemirror/mode/powershell/powershell.js' // Bat 文件
12 | import 'codemirror/mode/properties/properties.js' // properties 文件
13 | import 'codemirror/mode/python/python.js' // Python 语言
14 | import 'codemirror/mode/r/r.js' // R 语言
15 | import 'codemirror/mode/rust/rust.js' // R 语言
16 | import 'codemirror/mode/sass/sass.js' // sass 预编译器
17 | import 'codemirror/mode/shell/shell.js' // sass 预编译器
18 | import 'codemirror/mode/stylus/stylus.js' // stylus 预编译器
19 | import 'codemirror/mode/swift/swift.js' // Swift 语言
20 | import 'codemirror/mode/vue/vue.js' // vue.js 框架
21 | import 'codemirror/mode/sql/sql.js' // SQL 语言
22 | import 'codemirror/mode/xml/xml.js' // xml 语言
23 | import 'codemirror/mode/yaml/yaml' // YAML 语言
24 | import 'codemirror/mode/htmlmixed/htmlmixed.js' // html 标记语言
25 |
--------------------------------------------------------------------------------
/file-front/src/components/file/box/imgPreview/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import ImgPreview from './BoxMask.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const ImgPreviewConstructor = Vue.extend(ImgPreview)
6 |
7 | let imgPreviewInstance = null
8 | /**
9 | * 初始化图片预览实例
10 | * @param {string} imgList 图片列表
11 | * @param {object} defaultIndex 当前查看的图片索引
12 | */
13 | const initInstanceImgPreview = (imgList, defaultIndex) => {
14 | imgPreviewInstance = new ImgPreviewConstructor({
15 | el: document.createElement('div'),
16 | data() {
17 | return {
18 | imgList,
19 | defaultIndex
20 | }
21 | }
22 | })
23 | }
24 | /**
25 | * 图片预览 Promise 函数
26 | * @returns {Promise} 抛出确认和取消回调函数
27 | */
28 | const showImgPreviewBox = (obj) => {
29 | // 非首次调用服务时,在 DOM 中移除上个实例
30 | if (imgPreviewInstance !== null) {
31 | document.body.removeChild(imgPreviewInstance.$el)
32 | }
33 | let { imgList, defaultIndex } = obj
34 | return new Promise((reslove) => {
35 | initInstanceImgPreview(imgList, defaultIndex)
36 | imgPreviewInstance.callback = (res) => {
37 | reslove(res)
38 | // 服务取消时卸载 DOM
39 | if (res === 'cancel' && imgPreviewInstance !== null) {
40 | document.body.removeChild(imgPreviewInstance.$el)
41 | imgPreviewInstance = null
42 | }
43 | }
44 | document.body.appendChild(imgPreviewInstance.$el) // 挂载 DOM
45 | Vue.nextTick(() => {
46 | imgPreviewInstance.visible = true // 打开图片预览遮罩层
47 | })
48 | })
49 | }
50 |
51 | export default showImgPreviewBox
52 |
--------------------------------------------------------------------------------
/file-front/src/components/file/box/markdownPreview/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import MarkdownPreview from './BoxMask.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const MarkdownPreviewConstructor = Vue.extend(MarkdownPreview)
6 |
7 | let markdownPreviewInstance = null
8 | /**
9 | * 初始化 markdown 预览实例
10 | * @param {string} fileInfo 文件信息
11 | * @param {boolean} editable 是否可编辑
12 | */
13 | const initInstanceMarkdownPreview = (fileInfo, editable) => {
14 | markdownPreviewInstance = new MarkdownPreviewConstructor({
15 | el: document.createElement('div'),
16 | data() {
17 | return {
18 | fileInfo,
19 | editable
20 | }
21 | }
22 | })
23 | }
24 | /**
25 | * markdown 预览 Promise 函数
26 | * @returns {Promise} 抛出确认和取消回调函数
27 | */
28 | const showMarkdownPreviewBox = (obj) => {
29 | // 非首次调用服务时,在 DOM 中移除上个实例
30 | if (markdownPreviewInstance !== null) {
31 | document.body.removeChild(markdownPreviewInstance.$el)
32 | }
33 | let { fileInfo, editable } = obj
34 | return new Promise((reslove) => {
35 | initInstanceMarkdownPreview(fileInfo, editable)
36 | markdownPreviewInstance.callback = (res) => {
37 | reslove(res)
38 | // 服务取消时卸载 DOM
39 | if (res === 'cancel' && markdownPreviewInstance !== null) {
40 | document.body.removeChild(markdownPreviewInstance.$el)
41 | markdownPreviewInstance = null
42 | }
43 | }
44 | document.body.appendChild(markdownPreviewInstance.$el) // 挂载 DOM
45 | Vue.nextTick(() => {
46 | markdownPreviewInstance.visible = true // 打开 markdown 预览遮罩层
47 | })
48 | })
49 | }
50 |
51 | export default showMarkdownPreviewBox
52 |
--------------------------------------------------------------------------------
/file-front/src/components/file/box/videoPreview/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import VideoPreview from './BoxMask.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const VideoPreviewConstructor = Vue.extend(VideoPreview)
6 |
7 | let videoPreviewInstance = null
8 | /**
9 | * 初始化视频预览实例
10 | * @param {string} videoList 视频列表
11 | * @param {object} defaultIndex 当前查看的视频索引
12 | */
13 | const initInstanceVideoPreview = (videoList, defaultIndex) => {
14 | videoPreviewInstance = new VideoPreviewConstructor({
15 | el: document.createElement('div'),
16 | data() {
17 | return {
18 | videoList,
19 | defaultIndex
20 | }
21 | }
22 | })
23 | }
24 | /**
25 | * 视频预览 Promise 函数
26 | * @returns {Promise} 抛出确认和取消回调函数
27 | */
28 | const showVideoPreviewBox = (obj) => {
29 | // 非首次调用服务时,在 DOM 中移除上个实例
30 | if (videoPreviewInstance !== null) {
31 | document.body.removeChild(videoPreviewInstance.$el)
32 | }
33 | let { videoList, defaultIndex } = obj
34 | return new Promise((reslove) => {
35 | initInstanceVideoPreview(videoList, defaultIndex)
36 | videoPreviewInstance.callback = (res) => {
37 | reslove(res)
38 | // 服务取消时卸载 DOM
39 | if (res === 'cancel' && videoPreviewInstance !== null) {
40 | document.body.removeChild(videoPreviewInstance.$el)
41 | videoPreviewInstance = null
42 | }
43 | }
44 | document.body.appendChild(videoPreviewInstance.$el) // 挂载 DOM
45 | Vue.nextTick(() => {
46 | videoPreviewInstance.visible = true // 打开视频预览遮罩层
47 | })
48 | })
49 | }
50 |
51 | export default showVideoPreviewBox
52 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/addFile/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import router from '@/router/router.js'
3 | // 导入组件
4 | import AddFileDialog from './Dialog.vue'
5 | // 使用基础 Vue 构造器,创建一个“子类”
6 | const AddFileConstructor = Vue.extend(AddFileDialog)
7 |
8 | let addFileInstance = null
9 | /**
10 | * 初始化新建文件实例
11 | * @param {string} extendName office 文件扩展名
12 | * @param {string} filePath 新建文件夹的父路径
13 | */
14 | const initInstanceAddFile = (
15 | extendName,
16 | filePath = router.currentRoute.query.filePath || '/'
17 | ) => {
18 | addFileInstance = new AddFileConstructor({
19 | el: document.createElement('div'),
20 | data() {
21 | return {
22 | extendName,
23 | filePath
24 | }
25 | }
26 | })
27 | }
28 | /**
29 | * 新建文件 Promise 函数
30 | * @returns {Promise} 抛出确认和取消回调函数
31 | */
32 | const showAddFileDialog = (obj) => {
33 | // 非首次调用服务时,在 DOM 中移除上个实例
34 | if (addFileInstance !== null) {
35 | document.body.removeChild(addFileInstance.$el)
36 | }
37 | let { extendName, filePath } = obj
38 | return new Promise((reslove) => {
39 | initInstanceAddFile(extendName, filePath)
40 | addFileInstance.callback = (res) => {
41 | reslove(res)
42 | // 服务取消时卸载 DOM
43 | if (res === 'cancel' && addFileInstance !== null) {
44 | document.body.removeChild(addFileInstance.$el)
45 | addFileInstance = null
46 | }
47 | }
48 | document.body.appendChild(addFileInstance.$el) // 挂载 DOM
49 | Vue.nextTick(() => {
50 | addFileInstance.visible = true // 打开对话框
51 | })
52 | })
53 | }
54 |
55 | export default showAddFileDialog
56 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/addFolder/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import AddFolderDialog from './Dialog.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const AddFolderConstructor = Vue.extend(AddFolderDialog)
6 |
7 | let addFolderInstance = null
8 | /**
9 | * 初始化新建文件夹实例
10 | * @param {string} filePath 新建文件的父路径
11 | */
12 | const initInstanceAddFolder = (parent) => {
13 | addFolderInstance = new AddFolderConstructor({
14 | el: document.createElement('div'),
15 | data() {
16 | return {
17 | parent
18 | }
19 | }
20 | })
21 | }
22 | /**
23 | * 新建文件夹 Promise 函数
24 | * @returns {Promise} 抛出确认和取消回调函数
25 | */
26 | const showAddFolderDialog = ({ parent }) => {
27 | // 非首次调用服务时,在 DOM 中移除上个实例
28 | if (addFolderInstance !== null) {
29 | document.body.removeChild(addFolderInstance.$el)
30 | }
31 | return new Promise((reslove) => {
32 | initInstanceAddFolder(parent)
33 | addFolderInstance.callback = (res) => {
34 | reslove(res)
35 | // 服务取消时卸载 DOM
36 | if (res === 'cancel' && addFolderInstance !== null) {
37 | document.body.removeChild(addFolderInstance.$el)
38 | addFolderInstance = null
39 | }
40 | }
41 | document.body.appendChild(addFolderInstance.$el) // 挂载 DOM
42 | Vue.nextTick(() => {
43 | addFolderInstance.visible = true // 打开对话框
44 | })
45 | })
46 | }
47 |
48 | export default showAddFolderDialog
49 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/copyFile/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import CopyFileDialog from './Dialog.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const CopyFileConstructor = Vue.extend(CopyFileDialog)
6 |
7 | let copyFileInstance = null
8 | /**
9 | * 初始化复制文件实例
10 | * @param {object | array} fileInfo 要复制的文件信息
11 | */
12 | const initInstanceCopyFile = (fileInfo) => {
13 | copyFileInstance = new CopyFileConstructor({
14 | el: document.createElement('div'),
15 | data() {
16 | return {
17 | fileInfo
18 | }
19 | }
20 | })
21 | }
22 | /**
23 | * 复制文件 Promise 函数
24 | * @returns {Promise} 抛出确认和取消回调函数
25 | */
26 | const showCopyFileDialog = (obj) => {
27 | // 非首次调用服务时,在 DOM 中移除上个实例
28 | if (copyFileInstance !== null) {
29 | document.body.removeChild(copyFileInstance.$el)
30 | }
31 | let { fileInfo } = obj
32 | return new Promise((reslove) => {
33 | initInstanceCopyFile(fileInfo)
34 | copyFileInstance.callback = (res) => {
35 | reslove(res)
36 | // 服务取消时卸载 DOM
37 | if (res === 'cancel' && copyFileInstance !== null) {
38 | document.body.removeChild(copyFileInstance.$el)
39 | copyFileInstance = null
40 | }
41 | }
42 | document.body.appendChild(copyFileInstance.$el) // 挂载 DOM
43 | Vue.nextTick(() => {
44 | copyFileInstance.visible = true // 打开对话框
45 | })
46 | })
47 | }
48 |
49 | export default showCopyFileDialog
50 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/moveFile/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import MoveFileDialog from './Dialog.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const MoveFileConstructor = Vue.extend(MoveFileDialog)
6 |
7 | let moveFileInstance = null
8 | /**
9 | * 初始化移动文件实例
10 | * @param {boolean} isBatchOperation 是否为批量移动:true - 批量移动,false - 单文件移动
11 | * @param {object | array} fileInfo 文件信息,单文件移动时,为单个文件对象;批量移动时,为文件数组
12 | */
13 | const initInstanceMoveFile = (isBatchOperation, fileInfo) => {
14 | moveFileInstance = new MoveFileConstructor({
15 | el: document.createElement('div'),
16 | data() {
17 | return {
18 | isBatchOperation,
19 | fileInfo
20 | }
21 | }
22 | })
23 | }
24 | /**
25 | * 移动文件 Promise 函数
26 | * @returns {Promise} 抛出确认和取消回调函数
27 | */
28 | const showMoveFileDialog = (obj) => {
29 | // 非首次调用服务时,在 DOM 中移除上个实例
30 | if (moveFileInstance !== null) {
31 | document.body.removeChild(moveFileInstance.$el)
32 | }
33 | let { isBatchOperation, fileInfo } = obj
34 | return new Promise((reslove) => {
35 | initInstanceMoveFile(isBatchOperation, fileInfo)
36 | moveFileInstance.callback = (res) => {
37 | reslove(res)
38 | // 服务取消时卸载 DOM
39 | if (res === 'cancel' && moveFileInstance !== null) {
40 | document.body.removeChild(moveFileInstance.$el)
41 | moveFileInstance = null
42 | }
43 | }
44 | document.body.appendChild(moveFileInstance.$el) // 挂载 DOM
45 | Vue.nextTick(() => {
46 | moveFileInstance.visible = true // 打开对话框
47 | })
48 | })
49 | }
50 |
51 | export default showMoveFileDialog
52 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/renameFile/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import RenameFileDialog from './Dialog.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const RenameFileConstructor = Vue.extend(RenameFileDialog)
6 |
7 | let renameFileInstance = null
8 | /**
9 | * 初始化重命名文件实例
10 | * @param {string} oldFileName 文件原本的名称
11 | * @param {string} userFileId 文件 ID
12 | */
13 | const initInstanceRenameFile = (oldFileName, userFileId) => {
14 | renameFileInstance = new RenameFileConstructor({
15 | el: document.createElement('div'),
16 | data() {
17 | return {
18 | oldFileName,
19 | userFileId
20 | }
21 | }
22 | })
23 | }
24 | /**
25 | * 重命名文件 Promise 函数
26 | * @returns {Promise} 抛出确认和取消回调函数
27 | */
28 | const showRenameFileDialog = (obj) => {
29 | // 非首次调用服务时,在 DOM 中移除上个实例
30 | if (renameFileInstance !== null) {
31 | document.body.removeChild(renameFileInstance.$el)
32 | }
33 | let { oldFileName, userFileId } = obj
34 | return new Promise((reslove) => {
35 | initInstanceRenameFile(oldFileName, userFileId)
36 | renameFileInstance.callback = (res) => {
37 | reslove(res)
38 | // 服务取消时卸载 DOM
39 | if (res === 'cancel' && renameFileInstance !== null) {
40 | document.body.removeChild(renameFileInstance.$el)
41 | renameFileInstance = null
42 | }
43 | }
44 | document.body.appendChild(renameFileInstance.$el) // 挂载 DOM
45 | Vue.nextTick(() => {
46 | renameFileInstance.visible = true // 打开对话框
47 | })
48 | })
49 | }
50 |
51 | export default showRenameFileDialog
52 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/restoreFile/Dialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 | 正在还原文件,请稍等片刻...
13 |
14 |
15 |
16 |
17 |
57 |
58 |
64 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/restoreFile/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import RestoreFileDialog from './Dialog.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const RestoreFileConstructor = Vue.extend(RestoreFileDialog)
6 |
7 | let restoreFileInstance = null
8 | /**
9 | * 初始化还原文件实例
10 | * @param {string} deleteBatchNum 删除批次号
11 | * @param {number} filePath 文件路径
12 | */
13 | const initInstanceRestoreFile = (deleteBatchNum, filePath) => {
14 | restoreFileInstance = new RestoreFileConstructor({
15 | el: document.createElement('div'),
16 | data() {
17 | return {
18 | deleteBatchNum,
19 | filePath
20 | }
21 | }
22 | })
23 | }
24 | /**
25 | * 还原文件 Promise 函数
26 | * @returns {Promise} 抛出确认和取消回调函数
27 | */
28 | const showRestoreFileDialog = (obj) => {
29 | // 非首次调用服务时,在 DOM 中移除上个实例
30 | if (restoreFileInstance !== null) {
31 | document.body.removeChild(restoreFileInstance.$el)
32 | }
33 | let { deleteBatchNum, filePath } = obj
34 | return new Promise((reslove) => {
35 | initInstanceRestoreFile(deleteBatchNum, filePath)
36 | restoreFileInstance.callback = (res) => {
37 | reslove(res)
38 | // 服务取消时卸载 DOM
39 | if (res === 'cancel' && restoreFileInstance !== null) {
40 | document.body.removeChild(restoreFileInstance.$el)
41 | restoreFileInstance = null
42 | }
43 | }
44 | document.body.appendChild(restoreFileInstance.$el) // 挂载 DOM
45 | Vue.nextTick(() => {
46 | restoreFileInstance.visible = true // 打开对话框
47 | })
48 | })
49 | }
50 |
51 | export default showRestoreFileDialog
52 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/saveShareFile/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import SaveShareFileDialog from './Dialog.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const SaveShareFileConstructor = Vue.extend(SaveShareFileDialog)
6 |
7 | let saveShareFileInstance = null
8 | /**
9 | * 初始化保存分享文件实例
10 | * @param {array} fileInfo 要保存的文件数组
11 | */
12 | const initInstanceSaveShareFile = (fileInfo) => {
13 | saveShareFileInstance = new SaveShareFileConstructor({
14 | el: document.createElement('div'),
15 | data() {
16 | return {
17 | fileInfo
18 | }
19 | }
20 | })
21 | }
22 | /**
23 | * 保存分享文件 Promise 函数
24 | * @returns {Promise} 抛出确认和取消回调函数
25 | */
26 | const showSaveShareFileDialog = (obj) => {
27 | // 非首次调用服务时,在 DOM 中移除上个实例
28 | if (saveShareFileInstance !== null) {
29 | document.body.removeChild(saveShareFileInstance.$el)
30 | }
31 | let { fileInfo } = obj
32 | return new Promise((reslove) => {
33 | initInstanceSaveShareFile(fileInfo)
34 | saveShareFileInstance.callback = (res) => {
35 | reslove(res)
36 | // 服务取消时卸载 DOM
37 | if (res === 'cancel' && saveShareFileInstance !== null) {
38 | document.body.removeChild(saveShareFileInstance.$el)
39 | saveShareFileInstance = null
40 | }
41 | }
42 | document.body.appendChild(saveShareFileInstance.$el) // 挂载 DOM
43 | Vue.nextTick(() => {
44 | saveShareFileInstance.visible = true // 打开对话框
45 | })
46 | })
47 | }
48 |
49 | export default showSaveShareFileDialog
50 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/shareFile/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import ShareFileDialog from './Dialog.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const ShareFileConstructor = Vue.extend(ShareFileDialog)
6 |
7 | let shareFileInstance = null
8 | /**
9 | * 初始化分享文件实例
10 | * @param {array} fileInfo 要分享的文件数组
11 | */
12 | const initInstanceShareFile = (fileInfo) => {
13 | shareFileInstance = new ShareFileConstructor({
14 | el: document.createElement('div'),
15 | data() {
16 | return {
17 | fileInfo
18 | }
19 | }
20 | })
21 | }
22 | /**
23 | * 分享文件 Promise 函数
24 | * @returns {Promise} 抛出确认和取消回调函数
25 | */
26 | const showShareFileDialog = (obj) => {
27 | // 非首次调用服务时,在 DOM 中移除上个实例
28 | if (shareFileInstance !== null) {
29 | document.body.removeChild(shareFileInstance.$el)
30 | }
31 | let { fileInfo } = obj
32 | return new Promise((reslove) => {
33 | initInstanceShareFile(fileInfo)
34 | shareFileInstance.callback = (res) => {
35 | reslove(res)
36 | // 服务取消时卸载 DOM
37 | if (res === 'cancel' && shareFileInstance !== null) {
38 | document.body.removeChild(shareFileInstance.$el)
39 | shareFileInstance = null
40 | }
41 | }
42 | document.body.appendChild(shareFileInstance.$el) // 挂载 DOM
43 | Vue.nextTick(() => {
44 | shareFileInstance.visible = true // 打开对话框
45 | })
46 | })
47 | }
48 |
49 | export default showShareFileDialog
50 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/showFileDetail/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import FileDetailDialog from './Dialog.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const FileDetailConstructor = Vue.extend(FileDetailDialog)
6 |
7 | let fileDetailInstance = null
8 | /**
9 | * 初始化文件详情文件实例
10 | * @param {object | array} fileInfo 文件信息,批量时为数组、单文件时为对象
11 | */
12 | const initInstanceFileDetail = (fileInfo) => {
13 | fileDetailInstance = new FileDetailConstructor({
14 | el: document.createElement('div'),
15 | data() {
16 | return {
17 | fileInfo
18 | }
19 | }
20 | })
21 | }
22 | /**
23 | * 文件详情文件 Promise 函数
24 | * @returns {Promise} 抛出确认和取消回调函数
25 | */
26 | const showFileDetailDialog = (obj) => {
27 | // 非首次调用服务时,在 DOM 中移除上个实例
28 | if (fileDetailInstance !== null) {
29 | document.body.removeChild(fileDetailInstance.$el)
30 | }
31 | let { fileInfo } = obj
32 | return new Promise((reslove) => {
33 | initInstanceFileDetail(fileInfo)
34 | fileDetailInstance.callback = (res) => {
35 | reslove(res)
36 | // 服务取消时卸载 DOM
37 | if (res === 'cancel' && fileDetailInstance !== null) {
38 | document.body.removeChild(fileDetailInstance.$el)
39 | fileDetailInstance = null
40 | }
41 | }
42 | document.body.appendChild(fileDetailInstance.$el) // 挂载 DOM
43 | Vue.nextTick(() => {
44 | fileDetailInstance.visible = true // 打开对话框
45 | })
46 | })
47 | }
48 |
49 | export default showFileDetailDialog
50 |
--------------------------------------------------------------------------------
/file-front/src/components/file/dialog/unzipFile/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | // 导入组件
3 | import UnzipFileDialog from './Dialog.vue'
4 | // 使用基础 Vue 构造器,创建一个“子类”
5 | const UnzipFileConstructor = Vue.extend(UnzipFileDialog)
6 |
7 | let unzipFileInstance = null
8 | /**
9 | * 初始化解压缩文件实例
10 | * @param {string} unzipMode 解压模式 0-解压到当前文件夹, 1-自动创建该文件名目录,并解压到目录里, 2-手动选择解压目录
11 | * @param {string} userFileId 文件用户 ID
12 | */
13 | const initInstanceUnzipFile = (unzipMode, userFileId) => {
14 | unzipFileInstance = new UnzipFileConstructor({
15 | el: document.createElement('div'),
16 | data() {
17 | return {
18 | unzipMode,
19 | userFileId
20 | }
21 | }
22 | })
23 | }
24 | /**
25 | * 解压缩文件 Promise 函数
26 | * @returns {Promise} 抛出确认和取消回调函数
27 | */
28 | const showUnzipFileDialog = (obj) => {
29 | // 非首次调用服务时,在 DOM 中移除上个实例
30 | if (unzipFileInstance !== null) {
31 | document.body.removeChild(unzipFileInstance.$el)
32 | }
33 | let { unzipMode, userFileId } = obj
34 | return new Promise((reslove) => {
35 | initInstanceUnzipFile(unzipMode, userFileId)
36 | unzipFileInstance.callback = (res) => {
37 | reslove(res)
38 | // 服务取消时卸载 DOM
39 | if (res === 'cancel' && unzipFileInstance !== null) {
40 | document.body.removeChild(unzipFileInstance.$el)
41 | unzipFileInstance = null
42 | }
43 | }
44 | document.body.appendChild(unzipFileInstance.$el) // 挂载 DOM
45 | Vue.nextTick(() => {
46 | unzipFileInstance.visible = true // 打开对话框
47 | })
48 | })
49 | }
50 |
51 | export default showUnzipFileDialog
52 |
--------------------------------------------------------------------------------
/file-front/src/config/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 存放工程配置项
3 | * @author 李雅婷
4 | */
5 | const config = {
6 | /**
7 | * @description 域名
8 | * 区分生产环境和开发环境,用来存放session及一些用户配置信息(左侧菜单栏是否收缩等)
9 | * 冒号之前配置生产环境域名
10 | * 冒号之后配置开发环境域名,开发环境域名默认使用主机名
11 | */
12 | domain: '',
13 | /**
14 | * 网站名称
15 | */
16 | siteName: '个人网盘',
17 | /**
18 | * 请求后台接口 URL 代理时的上下文
19 | * @description 仅适用于本地开发环境代理时使用
20 | * 生产环境需要在 nginx 配置中将 /api/ 代理到生产环境后台地址
21 | * 对应 vue.config.js 中配置的 devServer.proxy 中的代理之一
22 | * 若修改了此值,请同步修改 vue.config.js 中 devServer.proxy 对应的值
23 | */
24 | baseContext: 'https://index.xiaoyou.host',
25 | /**
26 | * 存放 token 时的命名方式
27 | */
28 | tokenKeyName: 'token'
29 | }
30 |
31 | export default config
32 |
--------------------------------------------------------------------------------
/file-front/src/libs/globalFunction/common.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 | import config from '@/config/index.js'
3 |
4 | // 全局函数 - 公共操作相关
5 | const commonFunction = {
6 | // 跳转到奇文账户域名下的某个路径,默认在当前标签页打开
7 | goAccount(path, target = '_self') {
8 | open(`https://account.qiwenshare.com${path}?Rurl=${location.href}`, target)
9 | },
10 | /**
11 | * 设置 Cookies
12 | * @param {string} name 名称
13 | * @param {string} value 值
14 | * @param {object} others 域名、路径、有效期等,封装到对象中
15 | */
16 | setCookies(name, value, others = null) {
17 | Cookies.set(name, value, { domain: config.domain, ...others })
18 | },
19 | /**
20 | * 获取 Cookies
21 | * @param {string} name 名称
22 | * @param {object} others 域名、路径等,封装到对象中
23 | * @returns {string} Cookies 值
24 | */
25 | getCookies(name, others = null) {
26 | return Cookies.get(name, { domain: config.domain, ...others })
27 | },
28 | /**
29 | * 移除 Cookies
30 | * @param {string} name 名称
31 | * @param {object} others 域名、路径等,封装到对象中
32 | */
33 | removeCookies(name, others = null) {
34 | Cookies.remove(name, { domain: config.domain, ...others })
35 | }
36 | }
37 | export default commonFunction
38 |
--------------------------------------------------------------------------------
/file-front/src/libs/globalFunction/index.js:
--------------------------------------------------------------------------------
1 | import common from './common.js'
2 | import file from './file.js'
3 |
4 | export default { common, file }
5 |
--------------------------------------------------------------------------------
/file-front/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router/router'
4 | import store from '@/store/index.js'
5 | import '_a/styles/base.styl'
6 | import '_a/styles/iconfont/iconfont.css'
7 | import '_a/styles/iconfontCover.styl'
8 | import '_a/styles/elementCover.styl'
9 | import '_a/styles/mediaScreenXs.styl'
10 | import 'element-ui/lib/theme-chalk/index.css'
11 | // 引入全局函数
12 | import globalFunction from '@/libs/globalFunction/index.js'
13 | // 引入文件操作相关插件
14 | import fileOperationPlugins from '@/plugins/fileOperationPlugins.js'
15 | // 引入 Element UI 组件
16 | import element from '@/plugins/element.js'
17 | // 引入自定义的全局配置
18 | import config from '@/config/index.js'
19 | /**
20 | * vue-simple-uploader 中文官方文档 https://github.com/simple-uploader/vue-uploader/blob/master/README_zh-CN.md
21 | * simple-uploader.js 中文官方文档 https://github.com/simple-uploader/Uploader/blob/develop/README_zh-CN.md
22 | */
23 | import uploader from 'vue-simple-uploader'
24 | // collapse 展开折叠
25 | import CollapseTransition from 'element-ui/lib/transitions/collapse-transition'
26 |
27 | Vue.component(CollapseTransition.name, CollapseTransition)
28 |
29 | Vue.config.productionTip = false
30 |
31 | for (let key in globalFunction) {
32 | Vue.prototype[`$${key}`] = globalFunction[key]
33 | }
34 | for (let key in fileOperationPlugins) {
35 | Vue.prototype[`$${key}`] = fileOperationPlugins[key]
36 | }
37 |
38 | Vue.use(element)
39 | Vue.prototype.$config = config
40 | Vue.use(uploader)
41 |
42 | new Vue({
43 | router,
44 | store,
45 | render: (h) => h(App)
46 | }).$mount('#app')
47 |
--------------------------------------------------------------------------------
/file-front/src/plugins/fileOperationPlugins.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 以服务的方式,将对文件的一些操作挂载到 Vue 上
3 | * @description 各个服务的参数传递查看服务封装对应目录下的 index.js 文件,里面注明了需要传递的参数
4 | * @author 小鲤鱼听听
5 | */
6 |
7 | /**
8 | * 动态引入操作文件的弹窗组件
9 | */
10 | const fileOperateDialog = require.context(
11 | '_c/file/dialog',
12 | true,
13 | /\.\/(.*)\/index.js$/
14 | )
15 | /**
16 | * 服务挂载到 Vue - $openDialog,各个服务的名称为其对应的文件夹的名称
17 | * @description 例如,创建文件夹功能:服务封装路径 '_c/file/dialog/addFolder' ,则如下:
18 | * 在 *.vue 文件中,使用 this.$openDialog.addFolder 调用创建文件夹服务
19 | * 在 *.js 文件中,需要先在文件顶部引入 Vue ,即 import Vue from 'vue' ,然后使用 Vue.property.$openDialog.addFolder 调用创建文件夹服务
20 | */
21 | const openDialog = fileOperateDialog
22 | .keys()
23 | .map((key) => {
24 | return { [key.split('/')[1]]: fileOperateDialog(key).default }
25 | })
26 | .reduce((pre, next) => {
27 | return { ...pre, ...next }
28 | }, {})
29 |
30 | /**
31 | * 动态添加操作文件的遮罩或浮层组件
32 | */
33 | const fileOperateBox = require.context(
34 | '_c/file/box',
35 | true,
36 | /\.\/(.*)\/index.js$/
37 | )
38 | /**
39 | * 服务挂载到 Vue - $openBox,各个服务的名称为其对应的文件夹的名称
40 | * @description 例如,图片预览功能:服务封装路径 '_c/file/box/imgPreview' ,则如下:
41 | * 在 *.vue 文件中,使用 this.$openDialog.imgPreview 调用图片预览服务
42 | * 在 *.js 文件中,需要先在文件顶部引入 Vue ,即 import Vue from 'vue' ,然后使用 Vue.property.$openDialog.imgPreview 调用图片预览服务
43 | */
44 | const openBox = fileOperateBox
45 | .keys()
46 | .map((key) => {
47 | return { [key.split('/')[1]]: fileOperateBox(key).default }
48 | })
49 | .reduce((pre, next) => {
50 | return { ...pre, ...next }
51 | }, {})
52 |
53 | export default { openDialog, openBox }
54 |
--------------------------------------------------------------------------------
/file-front/src/request/onlyoffice.js:
--------------------------------------------------------------------------------
1 | // onlyoffice 相关接口
2 | import { post } from './http'
3 |
4 | // 创建文档
5 | export const createOfficeFile = (p) => post('/office/createofficefile', p)
6 | // 编辑文档
7 | export const editOfficeFile = (p) => post('/office/editofficefile', p)
8 | // 查看文档
9 | export const previewOfficeFile = (p) => post('/office/previewofficefile', p)
10 |
--------------------------------------------------------------------------------
/file-front/src/request/user.js:
--------------------------------------------------------------------------------
1 | // 用户信息相关接口
2 | import { get, post } from './http'
3 |
4 | /**
5 | * 以登录接口为例
6 | * export const login = p => get('/user/login', p);
7 | *
8 | * login ---------- 接口名称
9 | * p -------------- 传参,若需要在url中拼接其他信息,传参可以改为(p, other)
10 | * get ------------ 接口调用的方法,来自 http.js 中封装好的四个axios方法 get/post/put/axiosDelete
11 | * '/user/login' -- 接口url,若需要在url中拼接其他信息:
12 | * 首先需要在传参处改为(p, other1, other2)
13 | * 然后将url改为`/user/${other1}/login/${other2}`
14 | * p -------------- 传递给 get/post/put/axiosDelete 中的查询参数/请求体
15 | *
16 | *
17 | *
18 | * 除此之外,POST 请求支持请求体格式为 FormData,那么就需要多传递一个参数,true,如下示例:
19 | * export const example = p => post('/test/example', p, true);
20 | */
21 |
22 | // 用户登录
23 | export const login = (p) => get('/user/login', p)
24 | // 获取登录状态及用户信息
25 | export const checkUserLoginInfo = (p) => get('/user/checkuserlogininfo', p)
26 | // 用户注册
27 | export const addUser = (p) => post('/user/register', p)
28 |
--------------------------------------------------------------------------------
/file-front/src/router/router.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | Vue.use(Router)
5 |
6 | export default new Router({
7 | mode: 'history',
8 | base: process.env.BASE_URL,
9 | routes: [
10 | {
11 | path: '/',
12 | name: 'File',
13 | component: () => import(/* webpackChunkName: "file" */ '_v/File.vue'),
14 | meta: {
15 | title: '网盘',
16 | content: {
17 | description: '图片 文档 视频 音乐 其他 回收站 我的分享'
18 | }
19 | }
20 | },
21 | {
22 | path: '/onlyoffice',
23 | name: 'Onlyoffice',
24 | meta: {
25 | title: '在线编辑预览',
26 | content: {
27 | description: 'onlyoffice 文档在线编辑预览,支持 Word Excel PowerPoint'
28 | }
29 | },
30 | component: () =>
31 | import(/* webpackChunkName: "onlyOffice" */ '_v/OnlyOffice.vue')
32 | },
33 | {
34 | path: '/share/:shareBatchNum',
35 | name: 'Share',
36 | component: () => import(/* webpackChunkName: "share" */ '_v/Share.vue'),
37 | meta: {
38 | title: '分享',
39 | content: {
40 | description: '查看他人分享'
41 | }
42 | },
43 | props: true
44 | },
45 | {
46 | path: '*',
47 | name: 'Error_404',
48 | component: () =>
49 | import(/* webpackChunkName: "error_404" */ '_v/ErrorPage/404.vue'),
50 | meta: { title: '链接不存在' }
51 | }
52 | ]
53 | })
54 |
55 | const originalPush = Router.prototype.push
56 | Router.prototype.push = function push(location) {
57 | return originalPush.call(this, location).catch((err) => err)
58 | }
59 |
--------------------------------------------------------------------------------
/file-front/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import user from './module/user' // 用户模块
5 | import fileList from './module/fileList' // 文件列表模块
6 | import sideMenu from './module/sideMenu' // 左侧菜单模块
7 | import common from './module/common' // 公共模块
8 |
9 | import { allColumnList } from '@/libs/map.js'
10 |
11 | Vue.use(Vuex)
12 |
13 | export default new Vuex.Store({
14 | state: {
15 | //
16 | },
17 | getters: {
18 | // 登录状态
19 | isLogin: (state) => state.user.isLogin,
20 | // 用户姓名
21 | username: (state) => state.user.userInfoObj.username,
22 | // 用户ID
23 | userId: (state) => state.user.userInfoObj.userId,
24 | // 表格显示列
25 | selectedColumnList: (state) =>
26 | state.fileList.selectedColumnList === null
27 | ? allColumnList
28 | : state.fileList.selectedColumnList.split(','),
29 | // 文件查看模式
30 | fileModel: (state) =>
31 | state.fileList.fileModel === null ? 0 : Number(state.fileList.fileModel),
32 | // 网格模式 & 时间线模式下 文件图标大小
33 | gridSize: (state) => state.fileList.gridSize,
34 | // 剩余存储空间
35 | remainderStorageValue: (state) =>
36 | state.sideMenu.totalStorageValue - state.sideMenu.storageValue
37 | },
38 | mutations: {
39 | //
40 | },
41 | actions: {
42 | //
43 | },
44 | modules: {
45 | user,
46 | fileList,
47 | sideMenu,
48 | common
49 | }
50 | })
51 |
--------------------------------------------------------------------------------
/file-front/src/store/module/common.js:
--------------------------------------------------------------------------------
1 | export default {
2 | state: {
3 | screenWidth: document.body.clientWidth // 屏幕宽度
4 | },
5 | mutations: {
6 | /**
7 | * 改变屏幕宽度
8 | * @description 表格显示列保存在 Vuex 和 cookie 中
9 | * @param {object} state Vuex 的 state 对象
10 | * @param {[]} data 屏幕宽度
11 | */
12 | changeScreenWidth(state, data) {
13 | state.screenWidth = data
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/file-front/src/store/module/sideMenu.js:
--------------------------------------------------------------------------------
1 | export default {
2 | state: {
3 | },
4 | mutations: {
5 | },
6 | actions: {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/file-front/src/store/module/user.js:
--------------------------------------------------------------------------------
1 | import { checkUserLoginInfo } from '_r/user.js' //引入axios封装
2 |
3 | export default {
4 | state: {
5 | isLogin: false, // 用户登录状态
6 | userInfoObj: {} // 用户信息
7 | },
8 | mutations: {
9 | /**
10 | * 保存登录状态
11 | * @param {object} state Vuex 的 state 对象
12 | * @param {boolean} data 登录状态
13 | */
14 | changeIsLogin(state, data) {
15 | state.isLogin = data
16 | },
17 | /**
18 | * 保存用户信息
19 | * @param {object} state Vuex 的 state 对象
20 | * @param {boolean} data 用户信息
21 | */
22 | changeUserInfoObj(state, data) {
23 | state.userInfoObj = Object.assign({}, state.userInfoObj, data)
24 | }
25 | },
26 | actions: {
27 | /**
28 | * 获取用户信息
29 | */
30 | getUserInfo(context) {
31 | return checkUserLoginInfo().then((res) => {
32 | if (res.success) {
33 | // 改变登录状态
34 | context.commit('changeIsLogin', res.success)
35 | // 保存用户信息
36 | context.commit('changeUserInfoObj', res.data)
37 | } else {
38 | context.commit('changeIsLogin', res.success)
39 | }
40 | })
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/file-front/src/views/ErrorPage/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
您的页面飞走了……
4 |
![]()
5 |
6 |
7 |
8 |
18 |
19 |
30 |
--------------------------------------------------------------------------------
/file-front/src/views/File.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
28 |
29 |
49 |
--------------------------------------------------------------------------------
/file-front/vue.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = {
4 | // 选项...
5 | publicPath: '/',
6 |
7 | // 配置项不懂的地方,请查看 Vue CLI 官方文档 https://cli.vuejs.org/zh/config/#devserver
8 | devServer: {
9 | disableHostCheck: true,
10 | host: '0.0.0.0',
11 | port: 8081, // 本地开发环境 - 前端工程启动的端口;如果不想指定端口,期望启动追加,请注释 port 属性
12 | // 配置代理,解决本地开发环境下跨域请求后台接口的问题,proxy 中的修改项修改完后需要重启项目才可生效
13 | },
14 |
15 | productionSourceMap: false,
16 |
17 | pluginOptions: {
18 | 'style-resources-loader': {
19 | preProcessor: 'stylus',
20 | patterns: []
21 | }
22 | },
23 |
24 | configureWebpack: (config) => {
25 | config.resolve.alias = {
26 | '@': path.resolve(__dirname, './src'),
27 | _v: path.resolve(__dirname, './src/views'),
28 | _c: path.resolve(__dirname, './src/components'),
29 | _a: path.resolve(__dirname, './src/assets'),
30 | _r: path.resolve(__dirname, './src/request'),
31 | _public: path.resolve(__dirname, './public')
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/images/2022-09-05-09-51-49.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-51-49.png
--------------------------------------------------------------------------------
/images/2022-09-05-09-52-18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-52-18.png
--------------------------------------------------------------------------------
/images/2022-09-05-09-53-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-53-03.png
--------------------------------------------------------------------------------
/images/2022-09-05-09-53-26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-53-26.png
--------------------------------------------------------------------------------
/images/2022-09-05-09-53-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-53-48.png
--------------------------------------------------------------------------------
/images/2022-09-05-09-54-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-54-04.png
--------------------------------------------------------------------------------
/images/2022-09-05-09-54-37.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-54-37.png
--------------------------------------------------------------------------------
/images/2022-09-05-09-55-00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-55-00.png
--------------------------------------------------------------------------------
/images/2022-09-05-09-55-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-55-24.png
--------------------------------------------------------------------------------
/images/2022-09-05-09-56-00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/2022-09-05-09-56-00.png
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/images/logo.png
--------------------------------------------------------------------------------
/index-desktop-amis/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/index-desktop-amis/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .idea
17 | .DS_Store
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw?
23 |
24 | release
25 | .vscode/.debug.env
26 | package-lock.json
27 | pnpm-lock.yaml
28 | yarn.lock
29 |
--------------------------------------------------------------------------------
/index-desktop-amis/.vscode/.debug.script.mjs:
--------------------------------------------------------------------------------
1 | import fs from 'fs'
2 | import path from 'path'
3 | import { fileURLToPath } from 'url'
4 | import { createRequire } from 'module'
5 | import { spawn } from 'child_process'
6 |
7 | const __dirname = path.dirname(fileURLToPath(import.meta.url))
8 | const require = createRequire(import.meta.url)
9 | const pkg = require('../package.json')
10 |
11 | // write .debug.env
12 | const envContent = Object.entries(pkg.env).map(([key, val]) => `${key}=${val}`)
13 | fs.writeFileSync(path.join(__dirname, '.debug.env'), envContent.join('\n'))
14 |
15 | // bootstrap
16 | spawn(
17 | // TODO: terminate `npm run dev` when Debug exits.
18 | process.platform === 'win32' ? 'npm.cmd' : 'npm',
19 | ['run', 'dev'],
20 | {
21 | stdio: 'inherit',
22 | env: Object.assign(process.env, { VSCODE_DEBUG: 'true' }),
23 | },
24 | )
25 |
--------------------------------------------------------------------------------
/index-desktop-amis/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "editorconfig.editorconfig",
6 | "mrmlnc.vscode-json5",
7 | "rbbit.typescript-hero",
8 | "syler.sass-indented",
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/index-desktop-amis/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "compounds": [
7 | {
8 | "name": "Debug App",
9 | "preLaunchTask": "start .debug.script.mjs",
10 | "configurations": [
11 | "Debug Main Process",
12 | "Debug Renderer Process"
13 | ],
14 | "presentation": {
15 | "hidden": false,
16 | "group": "",
17 | "order": 1
18 | },
19 | "stopAll": true
20 | }
21 | ],
22 | "configurations": [
23 | {
24 | "name": "Debug Main Process",
25 | "type": "pwa-node",
26 | "request": "launch",
27 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
28 | "windows": {
29 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
30 | },
31 | "runtimeArgs": [
32 | "--remote-debugging-port=9229",
33 | "${workspaceRoot}/dist/electron/main/index.js"
34 | ],
35 | "envFile": "${workspaceFolder}/.vscode/.debug.env"
36 | },
37 | {
38 | "name": "Debug Renderer Process",
39 | "port": 9229,
40 | "request": "attach",
41 | "type": "pwa-chrome",
42 | "timeout": 60000
43 | },
44 | ]
45 | }
46 |
--------------------------------------------------------------------------------
/index-desktop-amis/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "start .debug.script.mjs",
8 | "type": "shell",
9 | "command": "node .vscode/.debug.script.mjs",
10 | "isBackground": true,
11 | "problemMatcher": {
12 | "owner": "typescript",
13 | "fileLocation": "relative",
14 | "pattern": {
15 | "regexp": "^([a-zA-Z]\\:\/?([\\w\\-]\/?)+\\.\\w+):(\\d+):(\\d+): (ERROR|WARNING)\\: (.*)$",
16 | "file": 1,
17 | "line": 3,
18 | "column": 4,
19 | "code": 5,
20 | "message": 6
21 | },
22 | "background": {
23 | "activeOnStart": true,
24 | "beginsPattern": "^.*building for development.*$",
25 | "endsPattern": "built in [0-9]*ms.*$",
26 | }
27 | }
28 | }
29 | ]
30 | }
31 |
32 | // https://code.visualstudio.com/docs/editor/tasks#_operating-system-specific-properties
33 | // https://code.visualstudio.com/docs/editor/tasks#_background-watching-tasks
34 | // https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson
35 |
--------------------------------------------------------------------------------
/index-desktop-amis/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 草鞋没号
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/index-desktop-amis/electron-builder.json5:
--------------------------------------------------------------------------------
1 | /**
2 | * @see https://www.electron.build/configuration/configuration
3 | */
4 | {
5 | appId: "123456",
6 | productName: "index",
7 | copyright: "Copyright © 2022 xiaoyou",
8 | asar: true,
9 | directories: {
10 | output: "release/${version}",
11 | buildResources: "electron/resources",
12 | },
13 | files: ["dist"],
14 | win: {
15 | target: [
16 | {
17 | target: "nsis",
18 | arch: ["x64"],
19 | },
20 | ],
21 | artifactName: "${productName}-Windows-${version}-Setup.${ext}",
22 | },
23 | nsis: {
24 | oneClick: false,
25 | perMachine: false,
26 | allowToChangeInstallationDirectory: true,
27 | deleteAppDataOnUninstall: false,
28 | },
29 | mac: {
30 | target: ["dmg"],
31 | artifactName: "${productName}-Mac-${version}-Installer.${ext}",
32 | },
33 | linux: {
34 | target: ["AppImage"],
35 | artifactName: "${productName}-Linux-${version}.${ext}",
36 | },
37 | }
38 |
--------------------------------------------------------------------------------
/index-desktop-amis/electron/electron-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
--------------------------------------------------------------------------------
/index-desktop-amis/electron/main/common.ts:
--------------------------------------------------------------------------------
1 | import {join} from "path";
2 | import {app} from "electron";
3 |
4 | export const ROOT_PATH = {
5 | // /dist
6 | dist: join(__dirname, '../..'),
7 | // /dist or /public
8 | public: join(__dirname, app.isPackaged ? '../..' : '../../../public'),
9 | }
10 |
--------------------------------------------------------------------------------
/index-desktop-amis/electron/resources/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/index-desktop-amis/electron/resources/icon.ico
--------------------------------------------------------------------------------
/index-desktop-amis/electron/resources/installerIcon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/index-desktop-amis/electron/resources/installerIcon.ico
--------------------------------------------------------------------------------
/index-desktop-amis/electron/resources/uninstallerIcon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/index-desktop-amis/electron/resources/uninstallerIcon.ico
--------------------------------------------------------------------------------
/index-desktop-amis/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/index-desktop-amis/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "index-desktop-amis",
3 | "productName": "index",
4 | "private": true,
5 | "version": "2.0.0",
6 | "description": "Vite React Electron boilerplate.",
7 | "main": "dist/electron/main/index.js",
8 | "scripts": {
9 | "dev": "vite",
10 | "build": "tsc && vite build && electron-builder"
11 | },
12 | "engines": {
13 | "node": "^14.18.0 || >=16.0.0"
14 | },
15 | "dependencies": {
16 | "@fortawesome/fontawesome-svg-core": "^6.1.2",
17 | "@fortawesome/free-brands-svg-icons": "^6.1.2",
18 | "@fortawesome/free-regular-svg-icons": "^6.1.2",
19 | "@fortawesome/free-solid-svg-icons": "^6.1.2",
20 | "@fortawesome/react-fontawesome": "^0.2.0",
21 | "amis": "^2.1.1-beta.2",
22 | "antd": "^4.22.6",
23 | "axios": "^0.27.2",
24 | "dplayer": "^1.27.0",
25 | "aplayer": "^1.10.1",
26 | "react-router-dom": "^6.3.0",
27 | "highlight.js": "^11.6.0",
28 | "marked": "^4.0.19"
29 | },
30 | "devDependencies": {
31 | "@types/dplayer": "^1.25.2",
32 | "@types/marked": "^4.0.6",
33 | "@types/node": "^18.7.9",
34 | "@types/react": "^18.0.17",
35 | "@types/react-dom": "^18.0.6",
36 | "@vitejs/plugin-react": "^2.0.1",
37 | "electron": "^20.0.2",
38 | "electron-builder": "^23.3.3",
39 | "react": "^18.2.0",
40 | "react-dom": "^18.2.0",
41 | "typescript": "^4.7.4",
42 | "vite": "^3.0.7",
43 | "vite-plugin-electron": "^0.9.0",
44 | "vditor": "^3.8.17"
45 | },
46 | "env": {
47 | "VITE_DEV_SERVER_HOST": "127.0.0.1",
48 | "VITE_DEV_SERVER_PORT": 7777
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/index-desktop-amis/public/static/icon/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/index-desktop-amis/public/static/icon/admin.png
--------------------------------------------------------------------------------
/index-desktop-amis/public/static/icon/blog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/index-desktop-amis/public/static/icon/blog.png
--------------------------------------------------------------------------------
/index-desktop-amis/public/static/icon/cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/index-desktop-amis/public/static/icon/cloud.png
--------------------------------------------------------------------------------
/index-desktop-amis/public/static/icon/music.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/index-desktop-amis/public/static/icon/music.png
--------------------------------------------------------------------------------
/index-desktop-amis/public/static/icon/video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/index-desktop-amis/public/static/icon/video.png
--------------------------------------------------------------------------------
/index-desktop-amis/public/static/image/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/index-desktop-amis/public/static/image/logo.png
--------------------------------------------------------------------------------
/index-desktop-amis/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 | import { HashRouter as Router, Routes, Route } from "react-router-dom";
3 | import Index from './views';
4 | import Page from './views/page';
5 | import Search from './views/search';
6 | import {message, Progress} from "antd";
7 |
8 | const App: React.FC = () => {
9 | let [progress, setProgress] = useState(100)
10 | window.electron.onProgress((event, value)=>{
11 | setProgress(value)
12 | })
13 | return (
14 |
15 |
16 |
17 | } />
18 | } />
19 | } />
20 |
21 |
22 | );
23 | }
24 |
25 | export default App
26 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/amis/component/icon.tsx:
--------------------------------------------------------------------------------
1 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
2 | // 引入lib库
3 | import { library } from '@fortawesome/fontawesome-svg-core'
4 | // 把所有的组件都引入进来
5 | import { fas } from '@fortawesome/free-solid-svg-icons'
6 | import { far } from '@fortawesome/free-regular-svg-icons'
7 | import { fab } from '@fortawesome/free-brands-svg-icons'
8 | import React, {useState} from "react";
9 | // 添加组件
10 | library.add(fas, far, fab)
11 | //
12 | // {"type":"index-icon","icon":{"type":"fab","name":"google"}}
13 | export const Icon = React.forwardRef((props:any, ref) => {
14 | let icon = props.icon
15 | let color = icon.color || '#999'
16 | let hoverColor = icon.hoverColor || '#999'
17 | let [current, setColor]= useState(color)
18 | return {setColor(color)}}
26 | onMouseEnter={()=>{setColor(hoverColor)}}
27 | />;
28 | })
29 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/amis/component/index.ts:
--------------------------------------------------------------------------------
1 | import {Renderer} from 'amis';
2 | import {Music, Video} from "./media";
3 | import {Icon} from "./icon";
4 | import {Markdown, MarkdownEdit} from "@/amis/component/content";
5 |
6 | export default function initComponent() {
7 | Renderer({type:"index-music", autoVar: true})(Music)
8 | Renderer({type:"index-video", autoVar: true})(Video)
9 | Renderer({type:"index-icon", autoVar: true})(Icon)
10 | Renderer({type:"index-markdown", autoVar: true})(Markdown)
11 | Renderer({type:"index-markdown-editor", autoVar: true, isFormItem: true})(MarkdownEdit)
12 | }
13 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/api/api.ts:
--------------------------------------------------------------------------------
1 | import request from "./request"
2 |
3 | export const base = 'https://index.xiaoyou.host'
4 |
5 | // 搜索内容
6 | export function search(keyword:string) {return request(`${base}/search?q=${keyword}`, null, 'get')}
7 | // 获取自定义界面
8 | export function getCustomView(name:string,id:string,view:string) {return request(`${base}/app/core/view/app/${name}/${id}/${view}`, null, 'get')}
9 |
10 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/api/request.ts:
--------------------------------------------------------------------------------
1 | import axios, {AxiosResponse} from 'axios'
2 | import { message } from 'antd'
3 |
4 |
5 | // 对axios函数进行封装,用来发api请求,post使用qs进行处理,避免自己把from数据转换为json字符串
6 | export default async function request (url:string, data:any, type:string) {
7 | let req:any
8 | // 判断请求类型
9 | if (type === 'get') {
10 | req = axios.get(url, { params: data, timeout: 1000 * 60 * 10 })
11 | } else if (type === 'post') {
12 | req = axios.post(url, data)
13 | } else if (type === 'put') {
14 | req = axios.put(url, data)
15 | } else if (type === 'delete') {
16 | req = axios.delete(url, {params: data})
17 | } else if (type === 'patch') {
18 | req = axios.patch(url, data)
19 | }
20 | return new Promise((resolve, reject) => {
21 | req.then((res: AxiosResponse) => {
22 | if (res.status !== 200) {
23 | message.error('请求失败')
24 | reject('请求失败')
25 | }else if (res.data.code !== 200) {
26 | message.error(res.data.msg)
27 | reject(res.data.msg)
28 | } else {
29 | resolve(res.data.data)
30 | }
31 | })
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 | import './index.css';
5 |
6 | // antd
7 | import 'antd/dist/antd.css';
8 | import AmisRegister from "./amis";
9 | // 引入amis的css样式
10 | import 'amis/lib/themes/cxd.css';
11 | import 'amis/lib/helper.css';
12 | import 'amis/sdk/iconfont.css';
13 | // 注册自定义的组件和各种事件
14 | AmisRegister()
15 |
16 | ReactDOM.createRoot(document.getElementById('root')!).render(
17 |
18 | )
19 |
20 | postMessage({ payload: 'removeLoading' }, '*')
21 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/types/global.d.ts:
--------------------------------------------------------------------------------
1 | import {ipcRenderer} from "electron";
2 |
3 | export interface IElectronAPI {
4 | openPage(info: WindowsSendMessage),
5 | download(url:string),
6 | onProgress(handle:(event, message)=>void),
7 | }
8 | declare global {
9 | // 定义自己的window对象,封装自己的api
10 | interface Window {
11 | electron: IElectronAPI
12 | }
13 | // 定义全局的通信格式
14 | interface WindowsSendMessage {
15 | url: string // 页面url
16 | height?: number // 页面高度
17 | width?: number // 页面宽度
18 | frame?: boolean // 是否显示frame
19 | title?: string // 标题
20 | logo?: string // 页面logo
21 | dev?: boolean // 是否显示开发者工具
22 | resize?: boolean // 是否可以改变大小
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/views/index.tsx:
--------------------------------------------------------------------------------
1 |
2 | export default function Index() {
3 | return 你好,世界
;
4 | }
5 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/views/page.tsx:
--------------------------------------------------------------------------------
1 | import { render as renderAmis } from 'amis';
2 | import React, {useCallback, useEffect, useState} from 'react';
3 | import {getCustomView} from "@/api/api";
4 | import {useParams} from "react-router-dom";
5 |
6 |
7 | export default function Page() {
8 | let [view,setView] = useState({type:"page",body:{}})
9 | let param = useParams()
10 | // 初始化获取所有页面信息
11 | useEffect(() => {
12 | getCustomView(param.name as string, param.id as string, param.view as string).then((data:any) => {
13 | setView(data.page)
14 | })
15 | }, [])
16 |
17 | return {renderAmis(view)}
;
18 | }
19 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/views/search.css:
--------------------------------------------------------------------------------
1 | .index-align-item {align-items: center;}
2 | .index-text-align-center {text-align: center}
3 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/views/search.tsx:
--------------------------------------------------------------------------------
1 | import { Input } from 'antd';
2 | import React, { useState } from "react";
3 | import { search } from "@/api/api";
4 | import { render as RenderUI } from "amis-core";
5 | import './search.css'
6 |
7 | export default function Search() {
8 | // 输入框内容
9 | let [input,setInput] = useState('')
10 | // 自定义渲染
11 | let [ui,setUI] = useState({ "type": "page", "body": {}})
12 | const inputOnchange = (e: React.ChangeEvent) => {
13 | const { value } = e.target
14 | setInput(value)
15 | search(value).then((res:any) => {
16 | setUI({ "type": "page", "body": {}})
17 | // 延迟触发,避免重叠
18 | setTimeout(() => {setUI(res.view)}, 100)
19 | })
20 | }
21 | return (
22 |
23 |
24 |
{RenderUI(ui)}
25 |
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/index-desktop-amis/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/index-desktop-amis/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "target": "ESNext",
5 | "useDefineForClassFields": true,
6 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
7 | "paths": {
8 | "@/*": ["src/*"],
9 | "styles/*": ["src/assets/styles/*"]
10 | },
11 | "allowJs": false,
12 | "skipLibCheck": true,
13 | "esModuleInterop": false,
14 | "allowSyntheticDefaultImports": true,
15 | "strict": true,
16 | "forceConsistentCasingInFileNames": true,
17 | "module": "ESNext",
18 | "moduleResolution": "Node",
19 | "resolveJsonModule": true,
20 | "isolatedModules": true,
21 | "noEmit": true,
22 | "jsx": "react-jsx"
23 | },
24 | "include": ["src"],
25 | "references": [{ "path": "./tsconfig.node.json" }]
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/index-desktop-amis/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "resolveJsonModule": true,
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts", "package.json"]
10 | }
11 |
--------------------------------------------------------------------------------
/index-front-amis/.drone.yml:
--------------------------------------------------------------------------------
1 | kind: pipeline
2 | type: docker
3 | name: build
4 | steps:
5 | - name: build # 构建阶段
6 | image: node:16.13.0
7 | pull: if-not-exists # 镜像拉取策略
8 | commands: # 下面这里是我们执行的命令
9 | - export NODE_OPTIONS="--max-old-space-size=8192"
10 | - yarn install # 安装依赖
11 | - yarn run build # 构建应用
12 | - name: push # 自动推送到私有仓库update
13 | image: plugins/docker
14 | pull: if-not-exists # 镜像拉取策略
15 | settings:
16 | registry: registry.xiaoyou66.com # 私有仓库地址
17 | repo: registry.xiaoyou66.com/index/admin-front-amis # 仓库全称
18 | use_cache: true
19 | username: admin # 设置私有仓库的账号密码
20 | password: xiaoyou
21 | tags: # 设置我们的标签
22 | - latest
23 | - 0.0.1
24 | #trigger: # 这里设置使用master分支来触发
25 | # branch:
26 | # - master
27 |
--------------------------------------------------------------------------------
/index-front-amis/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/index-front-amis/Dockerfile:
--------------------------------------------------------------------------------
1 | #拉取nginx镜像
2 | FROM registry.xiaoyou66.com/library/nginx:latest
3 | # 拷贝编译好的应用
4 | COPY dist/ /usr/share/nginx/html/
5 | # 拷贝配置文件
6 | COPY default.conf /etc/nginx/conf.d/default.conf
7 |
--------------------------------------------------------------------------------
/index-front-amis/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name localhost;
4 |
5 | #charset koi8-r;
6 | access_log /var/log/nginx/host.access.log main;
7 | error_log /var/log/nginx/error.log error;
8 | root /usr/share/nginx/html;
9 |
10 | location / {
11 | try_files $uri $uri/ /index.html;
12 | }
13 |
14 | #error_page 404 /404.html;
15 |
16 | # redirect server error pages to the static page /50x.html
17 | error_page 500 502 503 504 /50x.html;
18 | location = /50x.html {
19 | root /usr/share/nginx/html;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/index-front-amis/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 后台管理系统
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/index-front-amis/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-number-conversion",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@fortawesome/fontawesome-svg-core": "^6.1.2",
13 | "@fortawesome/free-brands-svg-icons": "^6.1.2",
14 | "@fortawesome/free-regular-svg-icons": "^6.1.2",
15 | "@fortawesome/free-solid-svg-icons": "^6.1.2",
16 | "@fortawesome/react-fontawesome": "^0.2.0",
17 | "amis": "^2.1.1-beta.2",
18 | "antd": "^4.22.6",
19 | "aplayer": "^1.10.1",
20 | "axios": "^0.27.2",
21 | "dplayer": "^1.27.0",
22 | "highlight.js": "^11.6.0",
23 | "marked": "^4.0.19",
24 | "react": "^18.2.0",
25 | "react-dom": "^18.2.0",
26 | "react-router-dom": "^6.3.0",
27 | "vditor": "^3.8.17"
28 | },
29 | "devDependencies": {
30 | "@types/dplayer": "^1.25.2",
31 | "@types/marked": "^4.0.6",
32 | "@types/react": "^18.0.17",
33 | "@types/react-dom": "^18.0.6",
34 | "@vitejs/plugin-react": "^2.0.1",
35 | "typescript": "^4.6.4",
36 | "vite": "^3.0.7"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/index-front-amis/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/index-front-amis/src/amis/action/index.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | ListenerAction,
3 | ListenerContext,
4 | registerAction,
5 | RendererAction
6 | } from 'amis-core';
7 | import {RendererEvent} from 'amis-core';
8 |
9 | // 动作定义
10 | interface IMyAction extends ListenerAction {
11 | actionType: 'index-request';
12 | args: {
13 | method: string, // 请求方式
14 | url: string, // 请求地址
15 | data: any, // 请求的数据
16 | numberField: [], // 需要转换为int的字段
17 | numberListField: [] // 需要转换为intList的字段
18 | };
19 | }
20 |
21 | /**
22 | * 我的动作实现
23 | */
24 | export class RequestAction implements RendererAction {
25 | // @ts-ignore
26 | run(action: IMyAction, renderer: ListenerContext, event: RendererEvent) {
27 | const {method, url, data, numberField, numberListField} = action.args;
28 | if (numberField != undefined) {
29 | numberField.forEach(((field)=>{
30 | data[field] = Number(data[field])
31 | }))
32 | }
33 | if (numberListField != undefined) {
34 | numberListField.forEach(((field)=>{
35 | data[field] = String(data[field]).split(",").map(value => Number(value))
36 | }))
37 | }
38 |
39 | console.log(method, url, data)
40 | }
41 | }
42 |
43 | export default function initAction() {
44 | // 注册自定义动作
45 | // @ts-ignore
46 | registerAction('index-request', new RequestAction());
47 | }
48 |
--------------------------------------------------------------------------------
/index-front-amis/src/amis/component/icon.tsx:
--------------------------------------------------------------------------------
1 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
2 | // 引入lib库
3 | import { library } from '@fortawesome/fontawesome-svg-core'
4 | // 把所有的组件都引入进来
5 | import { fas } from '@fortawesome/free-solid-svg-icons'
6 | import { far } from '@fortawesome/free-regular-svg-icons'
7 | import { fab } from '@fortawesome/free-brands-svg-icons'
8 | import React, {useState} from "react";
9 | // 添加组件
10 | library.add(fas, far, fab)
11 | //
12 | // {"type":"index-icon","icon":{"type":"fab","name":"google"}}
13 | export const Icon = React.forwardRef((props:any, ref) => {
14 | let icon = props.icon
15 | let color = icon.color || '#999'
16 | let hoverColor = icon.hoverColor || '#999'
17 | let [current, setColor]= useState(color)
18 | return {setColor(color)}}
26 | onMouseEnter={()=>{setColor(hoverColor)}}
27 | />;
28 | })
29 |
--------------------------------------------------------------------------------
/index-front-amis/src/amis/component/index.ts:
--------------------------------------------------------------------------------
1 | import {Renderer} from 'amis';
2 | import {Music, Video} from "./media";
3 | import {Icon} from "./icon";
4 | import {Markdown, MarkdownEdit} from "./content";
5 |
6 | export default function initComponent() {
7 | Renderer({type:"index-music", autoVar: true})(Music)
8 | Renderer({type:"index-video", autoVar: true})(Video)
9 | Renderer({type:"index-icon", autoVar: true})(Icon)
10 | Renderer({type:"index-markdown", autoVar: true})(Markdown)
11 | Renderer({type:"index-markdown-editor", autoVar: true, isFormItem: true})(MarkdownEdit)
12 | }
13 |
--------------------------------------------------------------------------------
/index-front-amis/src/api/request.ts:
--------------------------------------------------------------------------------
1 | import axios, {AxiosResponse} from 'axios'
2 | import { message } from 'antd'
3 |
4 |
5 | // 对axios函数进行封装,用来发api请求,post使用qs进行处理,避免自己把from数据转换为json字符串
6 | export default async function request (url:string, data:any, type:string) {
7 | let req:any
8 | // 判断请求类型
9 | if (type === 'get') {
10 | req = axios.get(url, { params: data, timeout: 1000 * 60 * 10 })
11 | } else if (type === 'post') {
12 | req = axios.post(url, data)
13 | } else if (type === 'put') {
14 | req = axios.put(url, data)
15 | } else if (type === 'delete') {
16 | req = axios.delete(url, {params: data})
17 | } else if (type === 'patch') {
18 | req = axios.patch(url, data)
19 | }
20 | return new Promise((resolve, reject) => {
21 | req.then((res: AxiosResponse) => {
22 | if (res.status !== 200) {
23 | message.error('请求失败')
24 | reject('请求失败')
25 | }else if (res.data.code !== 200) {
26 | message.error(res.data.msg)
27 | reject(res.data.msg)
28 | } else {
29 | resolve(res.data.data)
30 | }
31 | })
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/index-front-amis/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 |
5 | // 引入amis的css样式
6 | import 'amis/lib/themes/cxd.css';
7 | import 'amis/lib/helper.css';
8 | import 'amis/sdk/iconfont.css';
9 | import AmisRegister from "./amis";
10 | // antd
11 | import 'antd/dist/antd.css';
12 | // 编辑器配置
13 | import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
14 | import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
15 | import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
16 | import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
17 | import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
18 | // @ts-ignore
19 | self.MonacoEnvironment = {
20 | getWorker(_: string, label: string) {
21 | if (label === 'json') {
22 | return new jsonWorker()
23 | }
24 | if (label === 'css' || label === 'scss' || label === 'less') {
25 | return new cssWorker()
26 | }
27 | if (label === 'html' || label === 'handlebars' || label === 'razor') {
28 | return new htmlWorker()
29 | }
30 | if (['typescript', 'javascript'].includes(label)) {
31 | return new tsWorker()
32 | }
33 | return new EditorWorker()
34 | },
35 | }
36 |
37 | // 注册amis
38 | AmisRegister()
39 |
40 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
41 |
42 | )
43 |
--------------------------------------------------------------------------------
/index-front-amis/src/views/manage.tsx:
--------------------------------------------------------------------------------
1 | import { useParams } from 'react-router-dom';
2 | import React, {useCallback, useEffect, useState} from "react";
3 | import {getManagesView, getView} from "../api/api";
4 | import {render as renderAmis} from "amis-core";
5 |
6 |
7 | export default function Manage(props:any) {
8 | const id = Number(useParams()["id"])
9 | let [view, setView] = useState('{}')
10 |
11 | // 我们监听路由参数变化,如果路由变更那么就重新渲染
12 | useEffect(() => {
13 | // 获取所有的子菜单
14 | getView(id).then((data:any)=>setView(data.view))
15 | }, [useParams()])
16 |
17 | const renderView = () => {return {renderAmis(JSON.parse(view))}
}
18 |
19 | return {renderView()}
20 | }
21 |
--------------------------------------------------------------------------------
/index-front-amis/src/views/view.tsx:
--------------------------------------------------------------------------------
1 |
2 | export default function View() {
3 | return
4 | }
5 |
--------------------------------------------------------------------------------
/index-front-amis/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/index-front-amis/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx"
18 | },
19 | "include": ["src"],
20 | "references": [{ "path": "./tsconfig.node.json" }]
21 | }
22 |
--------------------------------------------------------------------------------
/index-front-amis/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/index-front-amis/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 | import { resolve } from "path";
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [react()],
8 | resolve: {
9 | alias: {
10 | "@": resolve(__dirname, "src"), // 配置路径映射
11 | },
12 | },
13 | optimizeDeps: {
14 | include: [
15 | `monaco-editor/esm/vs/language/json/json.worker`,
16 | `monaco-editor/esm/vs/language/css/css.worker`,
17 | `monaco-editor/esm/vs/language/html/html.worker`,
18 | `monaco-editor/esm/vs/language/typescript/ts.worker`,
19 | `monaco-editor/esm/vs/editor/editor.worker`
20 | ],
21 | },
22 | })
23 |
--------------------------------------------------------------------------------
/index-front-amis/vite.config.ts.js:
--------------------------------------------------------------------------------
1 | // vite.config.ts
2 | import { defineConfig } from "vite";
3 | import react from "@vitejs/plugin-react";
4 | var vite_config_default = defineConfig({
5 | plugins: [react()]
6 | });
7 | export {
8 | vite_config_default as default
9 | };
10 | //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gJ3ZpdGUnXG5pbXBvcnQgcmVhY3QgZnJvbSAnQHZpdGVqcy9wbHVnaW4tcmVhY3QnXG5cbi8vIGh0dHBzOi8vdml0ZWpzLmRldi9jb25maWcvXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xuICBwbHVnaW5zOiBbcmVhY3QoKV1cbn0pXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQUE7QUFDQTtBQUdBLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzFCLFNBQVMsQ0FBQztBQUFBOyIsCiAgIm5hbWVzIjogW10KfQo=
11 |
--------------------------------------------------------------------------------
/music-front/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 8
4 |
--------------------------------------------------------------------------------
/music-front/.drone.yml:
--------------------------------------------------------------------------------
1 | kind: pipeline
2 | type: docker
3 | name: build
4 | steps:
5 | - name: build # 构建阶段
6 | image: node:16.13.0
7 | pull: if-not-exists # 镜像拉取策略
8 | commands: # 下面这里是我们执行的命令
9 | - yarn install # 安装依赖
10 | - yarn run build # 构建应用
11 | - name: push # 自动推送到私有仓库update
12 | image: plugins/docker
13 | pull: if-not-exists # 镜像拉取策略
14 | settings:
15 | registry: registry.xiaoyou66.com # 私有仓库地址
16 | repo: registry.xiaoyou66.com/index/music-front # 仓库全称
17 | use_cache: true
18 | username: admin # 设置私有仓库的账号密码
19 | password: xiaoyou
20 | tags: # 设置我们的标签
21 | - 0.0.4
22 |
--------------------------------------------------------------------------------
/music-front/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/music-front/.env:
--------------------------------------------------------------------------------
1 | VUE_APP_BASE_API_URL = https://index.xiaoyou.host
--------------------------------------------------------------------------------
/music-front/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | extends: ['plugin:vue/recommended', '@vue/standard'],
7 | rules: {
8 | 'vue/max-attributes-per-line': [
9 | 2,
10 | {
11 | singleline: 10,
12 | multiline: {
13 | max: 1,
14 | allowFirstLine: false
15 | }
16 | }
17 | ],
18 | 'vue/singleline-html-element-content-newline': 'off',
19 | 'vue/multiline-html-element-content-newline': 'off',
20 | 'vue/name-property-casing': ['error', 'PascalCase'],
21 | 'vue/html-self-closing': [
22 | 'error',
23 | {
24 | html: {
25 | void: 'any',
26 | normal: 'never',
27 | component: 'always'
28 | },
29 | svg: 'always',
30 | math: 'always'
31 | }
32 | ],
33 | 'space-before-function-paren': [2, 'never'],
34 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
35 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
36 | 'no-sequences': 2,
37 | semi: 1
38 | },
39 | parserOptions: {
40 | parser: 'babel-eslint'
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/music-front/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
23 | yarn.lock
24 | package-lock.json
25 |
--------------------------------------------------------------------------------
/music-front/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npm.taobao.org
2 | sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
3 | phantomjs_cdnurl=http://cnpmjs.org/downloads
4 | electron_mirror=https://npm.taobao.org/mirrors/electron/
5 | sqlite3_binary_host_mirror=https://foxgis.oss-cn-shanghai.aliyuncs.com/
6 | profiler_binary_host_mirror=https://npm.taobao.org/mirrors/node-inspector/
7 | chromedriver_cdnurl=https://cdn.npm.taobao.org/dist/chromedriver
8 |
--------------------------------------------------------------------------------
/music-front/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "trailingComma": "none",
5 | "printWidth": 80
6 | }
7 |
--------------------------------------------------------------------------------
/music-front/.yarnrc:
--------------------------------------------------------------------------------
1 | registry "https://registry.npm.taobao.org"
2 | sass_binary_site "https://npm.taobao.org/mirrors/node-sass/"
3 | phantomjs_cdnurl "http://cnpmjs.org/downloads"
4 | electron_mirror "https://npm.taobao.org/mirrors/electron/"
5 | sqlite3_binary_host_mirror "https://foxgis.oss-cn-shanghai.aliyuncs.com/"
6 | profiler_binary_host_mirror "https://npm.taobao.org/mirrors/node-inspector/"
7 | chromedriver_cdnurl "https://cdn.npm.taobao.org/dist/chromedriver"
8 |
--------------------------------------------------------------------------------
/music-front/Dockerfile:
--------------------------------------------------------------------------------
1 | #拉取nginx镜像
2 | FROM registry.xiaoyou66.com/library/nginx:latest
3 | # 拷贝编译好的应用
4 | COPY dist/ /usr/share/nginx/html/
5 | # 拷贝配置文件
6 | COPY default.conf /etc/nginx/conf.d/default.conf
7 |
--------------------------------------------------------------------------------
/music-front/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 maomao1996
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/music-front/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['@vue/cli-plugin-babel/preset']
3 | }
4 |
--------------------------------------------------------------------------------
/music-front/default.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name localhost;
4 |
5 | #charset koi8-r;
6 | access_log /var/log/nginx/host.access.log main;
7 | error_log /var/log/nginx/error.log error;
8 |
9 | location / {
10 | root /usr/share/nginx/html;
11 | index index.html index.htm;
12 | }
13 |
14 | #error_page 404 /404.html;
15 |
16 | # redirect server error pages to the static page /50x.html
17 | #
18 | error_page 500 502 503 504 /50x.html;
19 | location = /50x.html {
20 | root /usr/share/nginx/html;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/music-front/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-mmplayer",
3 | "version": "1.8.2",
4 | "private": true,
5 | "description": "Online music player",
6 | "author": "maomao1996 <1714487678@qq.com>",
7 | "bugs": {
8 | "url": "https://github.com/maomao1996/Vue-mmPlayer/issues"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/maomao1996/Vue-mmPlayer"
13 | },
14 | "license": "MIT",
15 | "scripts": {
16 | "serve": "vue-cli-service serve",
17 | "build": "vue-cli-service build",
18 | "lint": "vue-cli-service lint"
19 | },
20 | "dependencies": {
21 | "axios": "^0.19.0",
22 | "core-js": "^3.4.1",
23 | "fastclick": "^1.0.6",
24 | "vue": "^2.6.10",
25 | "vue-lazyload": "^1.3.3",
26 | "vue-router": "^3.1.3",
27 | "vuex": "^3.1.2"
28 | },
29 | "devDependencies": {
30 | "@vue/cli-plugin-babel": "^4.0.5",
31 | "@vue/cli-plugin-eslint": "^4.0.5",
32 | "@vue/cli-service": "^4.0.5",
33 | "@vue/eslint-config-standard": "^4.0.0",
34 | "babel-eslint": "^10.0.3",
35 | "dayjs": "^1.8.24",
36 | "eslint": "^6.6.0",
37 | "eslint-plugin-vue": "^6.0.1",
38 | "less": "^3.10.3",
39 | "less-loader": "^5.0.0",
40 | "style-resources-loader": "^1.3.2",
41 | "vue-cli-plugin-style-resources-loader": "^0.1.3",
42 | "vue-template-compiler": "^2.6.10"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/music-front/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/music-front/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/music-front/public/favicon.ico
--------------------------------------------------------------------------------
/music-front/public/img/warn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/music-front/public/img/warn.png
--------------------------------------------------------------------------------
/music-front/public/prompt.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | mmPlayer | 温馨提示
7 |
16 |
17 |
18 |
19 |
20 |
21 |  |
22 |
23 |
24 | |
25 | 很抱歉!为了更好的体验,本站限制以下浏览器访问: |
26 | IE浏览器和使用IE内核的浏览器 |
27 | 解决办法:下载其他主流浏览器或者切换浏览器内核为极速内核 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/music-front/src/assets/background/bg-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/music-front/src/assets/background/bg-1.jpg
--------------------------------------------------------------------------------
/music-front/src/assets/background/bg-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/music-front/src/assets/background/bg-2.jpg
--------------------------------------------------------------------------------
/music-front/src/assets/img/album_cover_player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/music-front/src/assets/img/album_cover_player.png
--------------------------------------------------------------------------------
/music-front/src/assets/img/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/music-front/src/assets/img/default.png
--------------------------------------------------------------------------------
/music-front/src/assets/img/player_cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/music-front/src/assets/img/player_cover.png
--------------------------------------------------------------------------------
/music-front/src/assets/img/wave.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-bilibili/index/0c7bdd3552778304f1b87ff31c3f9f70b39e015e/music-front/src/assets/img/wave.gif
--------------------------------------------------------------------------------
/music-front/src/base/mm-icon/mm-icon.vue:
--------------------------------------------------------------------------------
1 |
2 |
38 |
39 |
54 |
--------------------------------------------------------------------------------
/music-front/src/base/mm-no-result/mm-no-result.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
20 |
21 |
35 |
--------------------------------------------------------------------------------
/music-front/src/base/mm-toast/index.js:
--------------------------------------------------------------------------------
1 | import TempToast from './mm-toast.vue'
2 |
3 | let instance
4 | let showToast = false
5 | let time // 存储toast显示状态
6 | const mmToast = {
7 | install(Vue, options = {}) {
8 | let opt = TempToast.data() // 获取组件中的默认配置
9 | Object.assign(opt, options) // 合并配置
10 | Vue.prototype.$mmToast = (message, position) => {
11 | if (showToast) {
12 | clearTimeout(time)
13 | instance.vm.visible = showToast = false
14 | document.body.removeChild(instance.vm.$el)
15 | // return;// 如果toast还在,则不再执行
16 | }
17 | if (message) {
18 | opt.message = message // 如果有传message,则使用所传的message
19 | }
20 | if (position) {
21 | opt.position = position // 如果有传type,则使用所传的type
22 | }
23 | let TempToastConstructor = Vue.extend(TempToast)
24 | instance = new TempToastConstructor({
25 | data: opt
26 | })
27 | instance.vm = instance.$mount()
28 | document.body.appendChild(instance.vm.$el)
29 | instance.vm.visible = showToast = true
30 |
31 | time = setTimeout(function() {
32 | instance.vm.visible = showToast = false
33 | document.body.removeChild(instance.vm.$el)
34 | }, opt.duration)
35 | }
36 | }
37 | }
38 |
39 | export default mmToast
40 |
--------------------------------------------------------------------------------
/music-front/src/config.js:
--------------------------------------------------------------------------------
1 | // 版本号
2 | export const VERSION = process.env.VUE_APP_VERSION
3 |
4 | // 默认分页数量
5 | export const defaultLimit = 30
6 |
7 | // 默认背景图(可引入网络图或本地静态图)
8 | const requireAll = requireContext => requireContext.keys().map(requireContext)
9 | const req = require.context('./assets/background', false)
10 | const BG_ARR = requireAll(req)
11 | export const defaultBG = BG_ARR[Math.floor(Math.random() * BG_ARR.length)]
12 |
13 | // 默认音量
14 | export const defaultVolume = 0.8
15 |
16 | /**
17 | * 播放模式
18 | * listLoop: 列表循环
19 | * order:顺序
20 | * loop: 单曲循环
21 | * random: 随机
22 | */
23 | export const playMode = {
24 | listLoop: 0,
25 | order: 1,
26 | random: 2,
27 | loop: 3
28 | }
29 |
--------------------------------------------------------------------------------
/music-front/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | // import 'babel-polyfill'
4 | // import '@/utils/hack'
5 | import Vue from 'vue'
6 | import store from './store'
7 | import router from './router'
8 | import App from './App'
9 | import fastclick from 'fastclick'
10 | import mmToast from 'base/mm-toast'
11 | import Icon from 'base/mm-icon/mm-icon'
12 | import VueLazyload from 'vue-lazyload'
13 | import { VERSION } from './config'
14 |
15 | import '@/styles/index.less'
16 |
17 | // 优化移动端300ms点击延迟
18 | fastclick.attach(document.body)
19 |
20 | // 弹出层
21 | Vue.use(mmToast)
22 |
23 | // icon 组件
24 | Vue.component(Icon.name, Icon)
25 |
26 | // 懒加载
27 | Vue.use(VueLazyload, {
28 | preLoad: 1,
29 | loading: require('assets/img/default.png')
30 | })
31 |
32 | // 访问版本统计
33 | window._hmt && window._hmt.push(['_setCustomVar', 1, 'version', VERSION, 1])
34 |
35 | const redirectList = ['/music/details', '/music/comment']
36 | router.beforeEach((to, from, next) => {
37 | window._hmt &&
38 | to.path &&
39 | window._hmt.push(['_trackPageview', '/#' + to.fullPath])
40 | if (redirectList.includes(to.path)) {
41 | next()
42 | } else {
43 | document.title =
44 | (to.meta.title && `${to.meta.title} - 在线音乐播放器`) ||
45 | '在线音乐播放器'
46 | next()
47 | }
48 | })
49 |
50 | // eslint-disable-next-line no-new
51 | new Vue({
52 | el: '#mmPlayer',
53 | store,
54 | router,
55 | render: h => h(App)
56 | })
57 |
--------------------------------------------------------------------------------
/music-front/src/store/getters.js:
--------------------------------------------------------------------------------
1 | // audio元素
2 | export const audioEle = state => state.audioEle
3 | // 播放模式
4 | export const mode = state => state.mode
5 | // 播放状态
6 | export const playing = state => state.playing
7 | // 播放列表
8 | export const playlist = state => state.playlist
9 | // 顺序列表
10 | export const orderList = state => state.orderList
11 | // 当前音乐索引
12 | export const currentIndex = state => state.currentIndex
13 | // 当前音乐
14 | export const currentMusic = state => {
15 | return state.playlist[state.currentIndex] || {}
16 | }
17 | // 播放历史列表
18 | export const historyList = state => state.historyList
19 | // 网易云用户UID
20 | export const uid = state => state.uid
21 |
--------------------------------------------------------------------------------
/music-front/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import state from './state'
4 | import * as getters from './getters'
5 | import * as actions from './actions'
6 | import mutations from './mutations'
7 | // vuex调试
8 | import createLogger from 'vuex/dist/logger'
9 | const debug = process.env.NODE_ENV !== 'production'
10 |
11 | Vue.use(Vuex)
12 |
13 | export default new Vuex.Store({
14 | state,
15 | getters,
16 | mutations,
17 | actions,
18 | // vuex调试
19 | strict: debug,
20 | plugins: debug ? [createLogger()] : []
21 | })
22 |
--------------------------------------------------------------------------------
/music-front/src/store/mutation-types.js:
--------------------------------------------------------------------------------
1 | export const SET_AUDIOELE = 'SET_AUDIOELE' // 修改audio元素
2 | export const SET_PLAYMODE = 'SET_PLAYMODE' // 修改播放模式
3 | export const SET_PLAYING = 'SET_PLAYING' // 修改播放状态
4 | export const SET_PLAYLIST = 'SET_PLAYLIST' // 修改播放列表
5 | export const SET_ORDERLIST = 'SET_ORDERLIST' // 修改顺序列表
6 | export const SET_CURRENTINDEX = 'SET_CURRENTINDEX' // 修改当前音乐索引
7 | export const SET_HISTORYLIST = 'SET_HISTORYLIST' // 修改播放历史列表
8 | export const SET_UID = 'SET_UID' // 修改网易云用户UID
9 |
--------------------------------------------------------------------------------
/music-front/src/store/mutations.js:
--------------------------------------------------------------------------------
1 | import * as types from './mutation-types'
2 |
3 | const mutations = {
4 | // 修改audio元素
5 | [types.SET_AUDIOELE](state, audioEle) {
6 | state.audioEle = audioEle
7 | },
8 | // 修改播放模式
9 | [types.SET_PLAYMODE](state, mode) {
10 | state.mode = mode
11 | },
12 | // 修改播放状态
13 | [types.SET_PLAYING](state, playing) {
14 | state.playing = playing
15 | },
16 | // 修改播放列表
17 | [types.SET_PLAYLIST](state, playlist) {
18 | state.playlist = playlist
19 | },
20 | // 修改顺序列表
21 | [types.SET_ORDERLIST](state, orderList) {
22 | state.orderList = orderList
23 | },
24 | // 修改当前音乐索引
25 | [types.SET_CURRENTINDEX](state, currentIndex) {
26 | state.currentIndex = currentIndex
27 | },
28 | // 修改播放历史列表
29 | [types.SET_HISTORYLIST](state, historyList) {
30 | state.historyList = historyList
31 | },
32 | // 修改网易云用户UID
33 | [types.SET_UID](state, uid) {
34 | state.uid = uid
35 | }
36 | }
37 |
38 | export default mutations
39 |
--------------------------------------------------------------------------------
/music-front/src/store/state.js:
--------------------------------------------------------------------------------
1 | import { playMode } from '@/config'
2 | import { getHistoryList, getMode, getUserId } from '@/utils/storage'
3 |
4 | const state = {
5 | audioEle: null, // audio元素
6 | mode: Number(getMode()) || playMode.listLoop, // 播放模式,默认列表循环
7 | playing: false, // 播放状态
8 | playlist: [], // 播放列表
9 | orderList: [], // 顺序列表
10 | currentIndex: -1, // 当前音乐索引
11 | historyList: getHistoryList() || [], // 播放历史列表
12 | uid: getUserId() || null // 网易云用户UID
13 | }
14 |
15 | export default state
16 |
--------------------------------------------------------------------------------
/music-front/src/styles/mixin.less:
--------------------------------------------------------------------------------
1 | // 显示省略号
2 | .no-wrap() {
3 | text-overflow: ellipsis;
4 | overflow: hidden;
5 | white-space: nowrap;
6 | }
7 |
8 | .flex-center(@direction: row) {
9 | display: flex;
10 | flex-direction: @direction;
11 | justify-content: center;
12 | align-items: center;
13 | }
14 |
--------------------------------------------------------------------------------
/music-front/src/styles/var.less:
--------------------------------------------------------------------------------
1 | //字体颜色定义规范
2 | @text_color: rgba(255, 255, 255, 0.6);
3 | @text_color_active: #fff; //重点部分
4 |
5 | //active颜色
6 | @active_color: #fff;
7 |
8 | //遮罩层颜色
9 | @mask_color: rgba(0, 0, 0, 0.4);
10 |
11 | //loading背景颜色
12 | @load_bg_color: rgba(0, 0, 0, 0.2);
13 |
14 | //header背景颜色
15 | @header_bg_color: rgba(0, 0, 0, 0.3);
16 |
17 | //search-head
18 | @search_bg_coloe: rgba(0, 0, 0, 0.2);
19 |
20 | //dialog相关
21 | @dialog_bg_color: rgba(0, 0, 0, 0.5);
22 | @dialog_content_bg_color: rgba(0, 0, 0, 0.6);
23 | @dialog_text_color: rgba(255, 255, 255, 0.7);
24 | @dialog_line_color: rgba(0, 0, 0, 0.35);
25 |
26 | //btn相关
27 | @btn_color: rgba(255, 255, 255, 0.6);
28 | @btn_color_active: #fff;
29 |
30 | //歌词高亮颜色
31 | @lyric_color_active: #40ce8f;
32 |
33 | //进度条
34 | @bar_color: rgba(255, 255, 255, 0.15);
35 | @line_color: #fff;
36 | @dot_color: #fff;
37 |
38 | //列表
39 | @list_head_line_color: rgba(255, 255, 255, 0.8);
40 | @list_item_line_color: rgba(255, 255, 255, 0.1);
41 |
42 | //评论
43 | @comment_head_line_color: rgba(255, 255, 255, 0.8);
44 | @comment_item_line_color: rgba(255, 255, 255, 0.1);
45 | @comment_replied_line_color: rgba(255, 255, 255, 0.3);
46 |
47 | //字体大小定义规范
48 | @font_size_small: 12px;
49 | @font_size_medium: 14px;
50 | @font_size_medium_x: 16px;
51 | @font_size_large: 18px;
52 | @font_size_large_x: 22px;
53 |
--------------------------------------------------------------------------------
/music-front/src/utils/axios.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import Vue from 'vue'
3 |
4 | const request = axios.create({
5 | baseURL: process.env.VUE_APP_BASE_API_URL
6 | })
7 |
8 | request.interceptors.response.use(
9 | response => {
10 | window.response = response
11 |
12 | if (response.status === 200 && response.data.code === 200) {
13 | return response.data
14 | }
15 | return Promise.reject(response)
16 | },
17 | error => {
18 | Vue.prototype.$mmToast(
19 | error.response ? error.response.data.message : error.message
20 | )
21 | return error
22 | }
23 | )
24 |
25 | export default request
26 |
--------------------------------------------------------------------------------
/music-front/src/utils/hack.js:
--------------------------------------------------------------------------------
1 | // hack for global nextTick
2 |
3 | function noop() {}
4 |
5 | window.MessageChannel = noop
6 | window.setImmediate = noop
7 |
--------------------------------------------------------------------------------
/music-front/src/utils/mixin.js:
--------------------------------------------------------------------------------
1 | import { mapGetters, mapMutations, mapActions } from 'vuex'
2 |
3 | /**
4 | * 歌曲列表
5 | */
6 | export const listMixin = {
7 | computed: {
8 | ...mapGetters(['playing', 'currentMusic'])
9 | },
10 | methods: {
11 | selectItem(item, index) {
12 | if (item.id === this.currentMusic.id && this.playing) {
13 | this.setPlaying(false)
14 | } else {
15 | this.selectPlay({
16 | list: this.list,
17 | index
18 | })
19 | }
20 | },
21 | ...mapMutations({
22 | setPlaying: 'SET_PLAYING'
23 | }),
24 | ...mapActions(['selectPlay'])
25 | }
26 | }
27 |
28 | /**
29 | * loading状态
30 | * @type {{data(): *, methods: {_hideLoad(): void}}}
31 | */
32 | export const loadMixin = {
33 | data() {
34 | return {
35 | mmLoadShow: true // loading状态
36 | }
37 | },
38 | methods: {
39 | _hideLoad() {
40 | let timer
41 | clearTimeout(timer)
42 | timer = setTimeout(() => {
43 | this.mmLoadShow = false
44 | }, 200)
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/music-front/vue.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const dayjs = require('dayjs')
3 |
4 | function resolve(dir) {
5 | return path.join(__dirname, dir)
6 | }
7 |
8 | const isEnvProduction = process.env.NODE_ENV === 'production'
9 |
10 | // 注入版本信息
11 | process.env.VUE_APP_VERSION = require('./package.json').version
12 | // 注入版本更新时间
13 | process.env.VUE_APP_UPDATE_TIME = dayjs()
14 | .locale('zh-cn')
15 | .format('YYYY-MM-DD')
16 |
17 | module.exports = {
18 | publicPath: '',
19 | chainWebpack(config) {
20 | config.resolve.alias
21 | .set('api', resolve('src/api'))
22 | .set('assets', resolve('src/assets'))
23 | .set('base', resolve('src/base'))
24 | .set('components', resolve('src/components'))
25 | .set('pages', resolve('src/pages'))
26 | config.plugin('html').tap(args => {
27 | if (isEnvProduction) {
28 | args[0].minify.minifyJS = true
29 | args[0].minify.minifyCSS = true
30 | }
31 | return args
32 | })
33 | },
34 | pluginOptions: {
35 | 'style-resources-loader': {
36 | preProcessor: 'less',
37 | patterns: [
38 | resolve('src/styles/var.less'),
39 | resolve('src/styles/mixin.less')
40 | ]
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/plugins/智能家居.js:
--------------------------------------------------------------------------------
1 | const unique = "home"
2 | let token = tools.GetConsulKV(tools.ContextBackground(), "index/app/ha_token")
3 |
4 | // LED控制
5 | gin.Handle("GET", "/server/:domain/:service/:entity", ctx => {
6 | let res = tools.HttpSendRequest(ctx, `http://ha.xiaoyou.host/api/services/${ctx.Param("domain")}/${ctx.Param("service")}`, "POST", {"Authorization": `Bearer ${token}`}, {"entity_id": ctx.Param("entity")})
7 | // 添加粉丝
8 | gin.Success(ctx, res)
9 | })
10 | // 全量数据同步
11 | gin.Handle("GET", "/sync", ctx => {
12 | // 先把旧记录全部删除
13 | mqServer.DeleteAll(ctx, unique)
14 | mqServer.Add(ctx, -2, unique, "灯", "", [])
15 | // 添加粉丝
16 | gin.Success(ctx, "同步成功")
17 | })
18 | // B站粉丝数卡片
19 | view.HandleSearch((ctx,id) => {
20 | let card = {
21 | "type": "service",
22 | "data": { "host": "http://index.xiaoyou.host" },
23 | "body": {
24 | "type": "flex",
25 | "justify": "flex-start",
26 | "items": [
27 | {"type":"image","width":"40px","height":"40px","imageMode":"original","src":"${host}/data/object/6309d715e891a61a9478303a"},
28 | {"className": "m-l","type": "button-group-select", "name": "type", "options": [{"label": "打开","value": "turn_on"},{"label": "关闭","value": "turn_off"}],
29 | "onEvent": {"change": {"actions": [{"actionType": "index-request", "args": {"url":"/app/home/server/light/${event.data.value}/light.mbulb3_cloud_128410","method":"get"}}]}}
30 | }
31 | ]}
32 | }
33 | // 返回内容
34 | return JSON.stringify(card)
35 | })
36 |
--------------------------------------------------------------------------------
/relation/.drone.yaml:
--------------------------------------------------------------------------------
1 | kind: pipeline
2 | type: docker
3 | name: build
4 | steps:
5 | - name: build # 构建阶段
6 | image: golang:1.18.3
7 | pull: if-not-exists # 镜像拉取策略
8 | commands: # 下面这里是我们执行的命令。这里我们是使用go去编译项目
9 | - export GOPROXY="https://goproxy.cn"
10 | - go env -w GOPRIVATE=git.xiaoyou.host
11 | - go mod download
12 | - CGO_ENABLED=0 GOOS=linux go build -o app .
13 | - name: push # 自动推送到私有仓库update
14 | image: plugins/docker
15 | pull: if-not-exists # 镜像拉取策略
16 | settings:
17 | registry: registry.xiaoyou66.com # 私有仓库地址
18 | repo: registry.xiaoyou66.com/index/relation # 仓库全称
19 | use_cache: true
20 | username: admin # 设置私有仓库的账号密码
21 | password: xiaoyou
22 | tags: # 设置我们的标签
23 | - latest
24 | - 0.0.1
25 | #trigger: # 这里设置使用master分支来触发
26 | # branch:
27 | # - master
--------------------------------------------------------------------------------
/relation/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | relation.go
--------------------------------------------------------------------------------
/relation/internal/neo4j/neo4j.go:
--------------------------------------------------------------------------------
1 | package neo4j
2 |
3 | import (
4 | "fmt"
5 | "github.com/neo4j/neo4j-go-driver/v4/neo4j"
6 | "strings"
7 | )
8 |
9 | func CreateService() *Service {
10 | driver, err := neo4j.NewDriver("neo4j://192.168.1.40:32017", neo4j.BasicAuth("neo4j", "xiaoyou", ""))
11 | if err != nil {
12 | panic(any("client neo4j error"))
13 | }
14 | return &Service{
15 | driver: driver,
16 | session: driver.NewSession(neo4j.SessionConfig{}),
17 | }
18 | }
19 |
20 | // Service 图数据库服务
21 | type Service struct {
22 | driver neo4j.Driver
23 | session neo4j.Session
24 | }
25 |
26 | // 初始化一个session服务
27 | func (s Service) newSession() neo4j.Session {
28 | return s.session
29 | }
30 |
31 | // 构建属性关系
32 | func (s Service) buildAttribute(attribute map[string]interface{}) string {
33 | tags := make([]string, 0, len(attribute))
34 | for k := range attribute {
35 | tags = append(tags, fmt.Sprintf("%s:$%s", k, k))
36 | }
37 | return fmt.Sprintf("{%s}", strings.Join(tags, ","))
38 | }
39 |
40 | // 构建更新关系
41 | func (s Service) buildUpdate(name string, attribute map[string]interface{}) string {
42 | tags := make([]string, 0, len(attribute))
43 | for k := range attribute {
44 | tags = append(tags, fmt.Sprintf("%s.%s=$%s", name, k, k))
45 | }
46 | return strings.Join(tags, ",")
47 | }
48 |
--------------------------------------------------------------------------------
/relation/internal/neo4j/tool.go:
--------------------------------------------------------------------------------
1 | package neo4j
2 |
3 | // GetNodeCount 计算节点个数
4 | func (s Service) GetNodeCount(cypher string) int64 {
5 | session := s.newSession()
6 | // 构建标签
7 | res, err := session.Run(cypher+" as total", map[string]interface{}{})
8 | if err != nil {
9 | return 0
10 | }
11 |
12 | single, err := res.Single()
13 | if err != nil {
14 | return 0
15 | }
16 | if count, ok := single.Get("total"); ok {
17 | if total, ok := count.(int64); ok {
18 | return total
19 | }
20 | }
21 |
22 | return 0
23 | }
24 |
--------------------------------------------------------------------------------
/relation/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "git.xiaoyou.host/index/common/proto/relation"
5 | "github.com/go-kratos/kratos/contrib/registry/consul/v2"
6 | "github.com/go-kratos/kratos/v2"
7 | "github.com/go-kratos/kratos/v2/middleware/recovery"
8 | "github.com/go-kratos/kratos/v2/transport/grpc"
9 | "github.com/hashicorp/consul/api"
10 | "index.relation/internal/rpc"
11 | "log"
12 | )
13 |
14 | func main() {
15 | // 服务发现
16 | config := api.DefaultConfig()
17 | // 这里配置成我们的consul的agent地址
18 | config.Address = "consul-1.consul.xiaoyou-index.svc.cluster.local:8500"
19 | consulClient, err := api.NewClient(config)
20 | if err != nil {
21 | panic(any(err))
22 | }
23 | r := consul.New(consulClient)
24 | // RPC服务注册
25 | s := rpc.NewRelationService()
26 | grpcSrv := grpc.NewServer(grpc.Address(":9000"), grpc.Middleware(recovery.Recovery()))
27 | relation.RegisterRelationServer(grpcSrv, s)
28 | // 启动应用
29 | app := kratos.New(
30 | kratos.Name("index.relation"),
31 | kratos.Server(grpcSrv),
32 | kratos.Registrar(r),
33 | )
34 | if err := app.Run(); err != nil {
35 | log.Fatal(err)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/relation/openapi.yaml:
--------------------------------------------------------------------------------
1 | # Generated with protoc-gen-openapi
2 | # https://github.com/google/gnostic/tree/master/cmd/protoc-gen-openapi
3 |
4 | openapi: 3.0.3
5 | info:
6 | title: ""
7 | version: 0.0.1
8 | paths: {}
9 | components:
10 | schemas: {}
11 |
--------------------------------------------------------------------------------
/relation/script/generate_service.sh:
--------------------------------------------------------------------------------
1 | # 自动生成服务端和客户端代码
2 | export GOPROXY="https://goproxy.cn"export GOPROXY="https://goproxy.cn"
3 | cd ..
4 | kratos proto client api/relation.proto
5 | kratos proto server api/relation.proto -t internal/rpc
--------------------------------------------------------------------------------
/search/.drone.yml:
--------------------------------------------------------------------------------
1 | kind: pipeline
2 | type: docker
3 | name: build
4 | steps:
5 | - name: build # 构建阶段
6 | image: golang:1.18.3
7 | pull: if-not-exists # 镜像拉取策略
8 | commands: # 下面这里是我们执行的命令。这里我们是使用go去编译项目
9 | - export GOPROXY="https://goproxy.cn"
10 | - go env -w GOPRIVATE=git.xiaoyou.host
11 | - go mod tidy
12 | - CGO_ENABLED=0 GOOS=linux go build -o app .
13 | - name: push # 自动推送到私有仓库update
14 | image: plugins/docker
15 | pull: if-not-exists # 镜像拉取策略
16 | settings:
17 | registry: registry.xiaoyou66.com # 私有仓库地址
18 | repo: registry.xiaoyou66.com/index/search # 仓库全称
19 | use_cache: true
20 | username: admin # 设置私有仓库的账号密码
21 | password: xiaoyou
22 | tags: # 设置我们的标签
23 | - latest
24 | - 0.0.1
25 | trigger: # 这里设置使用master分支来触发
26 | branch:
27 | - master
--------------------------------------------------------------------------------
/search/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
--------------------------------------------------------------------------------
/search/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM registry.xiaoyou66.com/library/alpine
2 | #WORKDIR /a
3 | # 拷贝我们编译好的文件
4 | COPY app /
5 | # 声明暴露的端口
6 | EXPOSE 8005
7 | # 启动时直接运行app
8 | ENTRYPOINT chmod +x /app && /app
--------------------------------------------------------------------------------
/search/doc/index.md:
--------------------------------------------------------------------------------
1 | ## ES 索引相关
2 |
3 | ```bash
4 | put /object
5 | {
6 | "settings": {
7 | "number_of_shards":1,
8 | "number_of_replicas":2,
9 | "analysis" : {
10 | "analyzer" : {
11 | "ik" : {
12 | "tokenizer" : "ik_max_word"
13 | }
14 | }
15 | }
16 | },
17 | "mappings":{
18 | "properties":{
19 | "name": {"type": "text", "analyzer": "ik_max_word","search_analyzer": "ik_smart"},
20 | "tags": {"type": "text", "analyzer": "ik_max_word","search_analyzer": "ik_smart"},
21 | "content": {"type": "text", "analyzer": "ik_max_word","search_analyzer": "ik_smart"},
22 | "node_id": {"type": "long"},
23 | "app": {"type": "keyword"}
24 | }
25 | }
26 | }
27 | ```
28 |
29 |
30 |
--------------------------------------------------------------------------------
/search/internal/object/mq_test.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "git.xiaoyou.host/index/common/service"
7 | "git.xiaoyou.host/index/common/tool/mq"
8 | "testing"
9 | )
10 |
11 | func TestProduce(t *testing.T) {
12 | produce := mq.CreateProduceService("index")
13 | err := produce.SendSync(context.Background(), "object", service.EsObjectOption{
14 | Option: 2,
15 | EsObject: service.EsObject{
16 | NodeID: 1,
17 | Name: "22222",
18 | Content: "4522226",
19 | Tags: []string{"22222", "33333"},
20 | },
21 | })
22 | fmt.Println(err)
23 | }
24 |
--------------------------------------------------------------------------------
/search/internal/object/search.go:
--------------------------------------------------------------------------------
1 | package object
2 |
3 | import (
4 | "context"
5 | "git.xiaoyou.host/index/common/service"
6 | )
7 |
8 | func SearchKeyword(ctx context.Context, keyword string) ([]service.EsObject, error) {
9 | res, err := esService.SearchNode(ctx, "object", keyword)
10 | if err != nil {
11 | return nil, err
12 | }
13 | objects := make([]service.EsObject, 0, len(res.Hits.Hits))
14 | for _, v := range res.Hits.Hits {
15 | objects = append(objects, v.Source)
16 | }
17 | return objects, nil
18 | }
19 |
--------------------------------------------------------------------------------
/search/internal/server/model.go:
--------------------------------------------------------------------------------
1 | package server
2 |
--------------------------------------------------------------------------------
/search/internal/web/handler.go:
--------------------------------------------------------------------------------
1 | package web
2 |
3 | import (
4 | "git.xiaoyou.host/index/common/web"
5 | "github.com/gin-gonic/gin"
6 | "index.search/internal/server"
7 | )
8 |
9 | func Search(ctx *gin.Context) {
10 | // 获取关键词
11 | q := ctx.Query("q")
12 | res, err := server.SearchNode(ctx, q)
13 | if err != nil {
14 | web.Fail(ctx, "get node err %v", err)
15 | return
16 | }
17 | web.Success(ctx, res)
18 | }
19 |
--------------------------------------------------------------------------------
/search/internal/web/router.go:
--------------------------------------------------------------------------------
1 | package web
2 |
3 | import "github.com/gin-gonic/gin"
4 |
5 | // RegisterRouter 注册http路由
6 | func RegisterRouter(r *gin.Engine) {
7 | r.GET("/search", Search)
8 | }
9 |
--------------------------------------------------------------------------------
/search/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/go-kratos/kratos/v2"
6 | "github.com/go-kratos/kratos/v2/transport/http"
7 | "index.search/internal/object"
8 | "index.search/internal/server"
9 | "index.search/internal/web"
10 | //"index.file/internal/web"
11 | )
12 |
13 | func main() {
14 | server.InitRpc()
15 | object.StartHandleMessage()
16 | // 注册rpc路由
17 | router := gin.Default()
18 | // 注册静态文件路由
19 | web.RegisterRouter(router)
20 | httpSrv := http.NewServer(http.Address(":8005"))
21 | httpSrv.HandlePrefix("/", router)
22 | app := kratos.New(kratos.Name("index.search"), kratos.Server(httpSrv))
23 | if err := app.Run(); err != nil {
24 | panic(any(err))
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/search/pkg/es/es_test.go:
--------------------------------------------------------------------------------
1 | package es
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "testing"
7 | )
8 |
9 | var service = CreateEsService()
10 |
11 | // 参考 https://github.com/elastic/go-elasticsearch#go-elasticsearch
12 |
13 | func TestCreateEsService(t *testing.T) {
14 | //err := service.InsertData(context.Background(), "object", .Object{
15 | // Name: "测试",
16 | // Tags: []string{"标签1", "标签2"},
17 | // Content: "这个是测试的内容",
18 | // NodeID: 10,
19 | //})
20 | //fmt.Println(err)
21 | }
22 |
23 | func TestService_DeleteRecordByNodeId(t *testing.T) {
24 | err := service.DeleteRecordByNodeId(context.Background(), "object", 10)
25 | fmt.Println(err)
26 | }
27 |
28 | func TestService_SearchNode(t *testing.T) {
29 | res, err := service.SearchNode(context.Background(), "object", "标签")
30 | fmt.Println(res)
31 | fmt.Println(err)
32 | }
33 |
34 | func TestService_UpdateNode(t *testing.T) {
35 | err := service.UpdateNode(context.Background(), "object", 10, "名字", "内容", []string{"111", "211", "311"})
36 | fmt.Println(err)
37 | }
38 |
--------------------------------------------------------------------------------
/search/pkg/es/model.go:
--------------------------------------------------------------------------------
1 | package es
2 |
3 | import "git.xiaoyou.host/index/common/service"
4 |
5 | // HintRes es搜索的返回结果
6 | type HintRes struct {
7 | Took int `json:"took"`
8 | TimedOut bool `json:"timed_out"`
9 | Shards struct {
10 | Total int `json:"total"`
11 | Successful int `json:"successful"`
12 | Skipped int `json:"skipped"`
13 | Failed int `json:"failed"`
14 | } `json:"_shards"`
15 | Hits struct {
16 | Total struct {
17 | Value int `json:"value"`
18 | Relation string `json:"relation"`
19 | } `json:"total"`
20 | MaxScore float64 `json:"max_score"`
21 | Hits []struct {
22 | Index string `json:"_index"`
23 | Id string `json:"_id"`
24 | Score float64 `json:"_score"`
25 | Source service.EsObject `json:"_source"`
26 | } `json:"hits"`
27 | } `json:"hits"`
28 | }
29 |
--------------------------------------------------------------------------------
/views/B站卡片.json:
--------------------------------------------------------------------------------
1 | {"type":"page", "data": {}, "body":[
2 | {
3 | "type": "service",
4 | "data": {
5 | "object": "http://index.xiaoyou.host/data/object/",
6 | "server": "http://index.xiaoyou.host/app/home/server/light/turn_off/light.mbulb3_cloud_128410"
7 | },
8 | "body": {
9 | "type": "flex",
10 | "justify": "flex-start",
11 | "items": [
12 | {"type":"image","width":"40px","height":"40px","imageMode":"original","src":"${object}6309d715e891a61a9478303a"},
13 | {
14 | "className": "m-l",
15 | "type": "button-group-select",
16 | "name": "type",
17 | "options": [{"label": "打开","value": "turn_on"},{"label": "关闭","value": "turn_off"}],
18 | "onEvent": {"change": {"actions": [{"actionType": "index-request", "args": {"url":"http://index.xiaoyou.host/app/home/server/light/${event.data.value}/light.mbulb3_cloud_128410","method":"get"}}]}}
19 | }
20 | ]}
21 | }
22 | ]}
--------------------------------------------------------------------------------
/views/文章显示.json:
--------------------------------------------------------------------------------
1 | {
2 | "type":"page",
3 | "data": {
4 | "name": "测试",
5 | "content": "# title\n markdown **text**",
6 | "tags": ["测试", "测试2"]
7 | },
8 | "body":[
9 | { "className": "post-content","type": "index-markdown", "content": "${content}" },
10 | { "type": "each", "name": "tags", "items": {"type": "tag", "label": "${item}", "color": "processing"}}
11 | ]
12 | }
--------------------------------------------------------------------------------