├── 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 |

logo

2 | 3 |

4 | GitHub stars 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 | ![](./images/2022-09-05-09-51-49.png) 31 | 32 | ![](./images/2022-09-05-09-56-00.png) 33 | 34 | ![](./images/2022-09-05-09-52-18.png) 35 | 36 | ![](./images/2022-09-05-09-53-03.png) 37 | 38 | ![](./images/2022-09-05-09-53-26.png) 39 | 40 | ![](./images/2022-09-05-09-53-48.png) 41 | 42 | ![](./images/2022-09-05-09-54-04.png) 43 | 44 | ![](./images/2022-09-05-09-54-37.png) 45 | 46 | ![](./images/2022-09-05-09-55-00.png) 47 | 48 | ![](./images/2022-09-05-09-55-24.png) -------------------------------------------------------------------------------- /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 | 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 | 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 | 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 | 7 | 8 | 18 | 19 | 30 | -------------------------------------------------------------------------------- /file-front/src/views/File.vue: -------------------------------------------------------------------------------- 1 | 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 | 27 | 28 |
mmPlayer | 温馨提示
很抱歉!为了更好的体验,本站限制以下浏览器访问:
IE浏览器和使用IE内核的浏览器
解决办法:下载其他主流浏览器或者切换浏览器内核为极速内核
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 | 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 | } --------------------------------------------------------------------------------