diff --git a/Dockerfile b/Dockerfile index 387b5c6..26b3ecf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,12 +16,13 @@ COPY . /build RUN pnpm run build # build backend -FROM golang:1.19 as server_image +FROM golang:1.21-alpine as server_image WORKDIR /build COPY ./service . +RUN apk add --no-cache bash curl gcc git go musl-dev # 执行指令 关闭链接确认 RUN go env -w GO111MODULE=on \ @@ -34,7 +35,7 @@ RUN go env -w GO111MODULE=on \ # run_image -FROM ubuntu +FROM alpine WORKDIR /app @@ -42,6 +43,8 @@ COPY --from=web_image /build/dist /app/web COPY --from=server_image /build/sun-panel /app/sun-panel -RUN apt-get update && apt-get install -y ca-certificates &&./sun-panel -config +RUN apk add --no-cache bash ca-certificates su-exec tzdata \ + && chmod +x ./sun-panel \ + && ./sun-panel -config CMD ./sun-panel diff --git a/README.md b/README.md index ef978fb..82fcaf8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@
- + + + # Sun-Panel Github | Gitee | Docker Hub | B站视频 @@ -8,13 +10,13 @@
-![](./doc/images/icon-info.jpg) +![](./doc/images/icon-info-new.png) ## 😎 特点 -- 局域网内外网链接切换 - 简洁 -- docker 部署 +- 局域网内外网链接切换 +- docker部署,对arm系统支持 - 上手简单,免修改代码 - 无需连接外部数据库 - 丰富图标自由搭配(文字图标+svg图标+内置三方图标库) @@ -47,22 +49,36 @@ 先画个饼 -- [ ] 图标排序 +- [x] 分组,拖拽排序 +- [ ] 导入导出功能 +- [ ] 增加访客账号 +- [ ] 用户自定义搜索框搜索引擎 +- [ ] 搜索框样式自定义(背景颜色,文字颜色) +- [ ] 帐号解除邮箱限制 +- [ ] 对上传的文件管理(针对账户增强重复利用,节省空间) +- [ ] 多国语言支持 - [ ] 服务器监控 - [ ] docker管理器 - [ ] 计划任务 + + ## 🖼️ 预览截图 -![](./doc/images/icon-small.jpg) -![](./doc/images/full-color-info.jpg) +**各种风格,自由搭配** + +![](./doc/images/icon-small-new.png) +![](./doc/images/transparent-info.png) +![](./doc/images/transparent-small.png) +![](./doc/images/solid-color-info.png) ![](./doc/images/full-color-small.jpg) -内置小窗口 +**内置小窗口** + ![](./doc/images/window-ssh.png) ![](./doc/images/window-xunlei.png) -## 🍜 使用教程 +## 🍜 使用运行教程
@@ -78,7 +94,20 @@ |-config|生成配置文件(conf/conf.ini)| |-password-reset|重置第一个用户的密码| +### 二进制文件运行 + +去 [Releases](https://github.com/hslr-s/sun-panel/releases) 下载二进制文件 + 执行示例 + +```sh +./sun-panel +``` + +#### 重置密码 + +执行示例 + ```sh ./sun-panel -password-reset ``` @@ -115,14 +144,14 @@ hslr/sun-panel ``` -### 编译和运行 +### 自编译运行 #### 前端 ``` # 开发运行 pnpm dev -# 编译打包 +# 编译打包(打包后生成dist目录,若需要结合后端使用请改成web) pnpm build ``` diff --git a/UPDATELOG.md b/UPDATELOG.md new file mode 100644 index 0000000..496fe38 --- /dev/null +++ b/UPDATELOG.md @@ -0,0 +1,22 @@ +# 更新说明 +> 老用户版本升级需要看升级说明,并且一定提前备份好重要数据。新用户可以直接使用最新版本。 + + +## v1.1.0 +> 支持上个版本直接升级无需特殊处理 + +- [新增] 增加分组,拖拽排序 +- [新增] 搜索框 +- [新增] 应用图标支持URL外链 +- [新增] 图标支持纯透明 +- [新增] 壁纸背景增加遮罩设置 +- [新增] 右键菜单新增打开局域网或者互联网地址 +- [优化] 网址输入框增加https/http提示 +- [优化] 小图标模式,鼠标悬浮显示详情,支持隐藏图标标题 +- [优化] 详情图标样式,支持隐藏描述信息 +- [优化] 添加用户密码时限制字符 +- [其他] 新增arm版本docker支持。[DockerHub](https://hub.docker.com/r/hslr/sun-panel)直接拉取即可 +- [其他] 新增多平台二进制文件运行。[Releases](https://github.com/hslr-s/sun-panel/releases) + +## v1.0.0 +- 首个版本 \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..fd2ca21 --- /dev/null +++ b/build.sh @@ -0,0 +1,143 @@ +#!/bin/bash + +REPO=$( + cd $(dirname $0) + pwd +) +COMMIT_SHA=$(git rev-parse --short HEAD) +VERSION=$(git describe --tags) +# VERSION="0.1.1" +FRONTEND="false" +BINARY="false" +RELEASE="false" + +debugInfo() { + echo "Repo: $REPO" + echo "Build frontend: $FRONTEND" + echo "Build binary: $BINARY" + echo "Release: $RELEASE" + echo "Version: $VERSION" + echo "Commit: $COMMIT_SHA" +} + +buildFrontend() { + cd $REPO + pwd +# npm install pnpm -g + pnpm install + pnpm run build +} + +buildBackEndAssets() { + cd $REPO/service +# export PATH=$PATH:/root/go/bin + go install -a -v github.com/go-bindata/go-bindata/...@latest + go install -a -v github.com/elazarl/go-bindata-assetfs/...@latest + go-bindata-assetfs -o=assets/bindata.go -pkg=assets assets/... +} + +# buildBinary() { +# cd $REPO/service +# # mv "${REPO}/dist" "${REPO}/web" +# go build -o "sun-panel" --ldflags="-X sun-panel/global.RUNCODE=release" main.go +# } + +_build() { + cd $REPO/service + pwd + local osarch=$1 + IFS=/ read -r -a arr <<<"$osarch" + os="${arr[0]}" + arch="${arr[1]}" + gcc="${arr[2]}" + + # Go build to build the binary. + export GOOS=$os + export GOARCH=$arch + export CC=$gcc + export CGO_ENABLED=1 + + pathRelease=$REPO/release + + if [ -n "$VERSION" ]; then + outPath="sun-panel_${VERSION}_${os}_${arch}" + else + outPath="sun-panel_${COMMIT_SHA}_${os}_${arch}" + fi + outname="${pathRelease}/${outPath}/sun-panel" + go build -o "${outname}" --ldflags="-X sun-panel/global.RUNCODE=release" main.go + + cd $pathRelease + # copy front file + cp -r "${REPO}/dist" "${pathRelease}/${outPath}/web" + + echo "Release ${outPath}" + if [ "$os" = "windows" ]; then + mv $outname $outPath/sun-panel.exe + zip -r "${pathRelease}/${outPath}.zip" $outPath + else + mv $outname $outPath/sun-panel + tar -zcvf "${pathRelease}/${outPath}.tar.gz" $outPath + fi + rm -rf "${pathRelease}/${outPath}" +} + +release() { + cd $REPO/service + ## List of architectures and OS to test coss compilation. + SUPPORTED_OSARCH="linux/amd64/gcc linux/arm/arm-linux-gnueabihf-gcc windows/amd64/x86_64-w64-mingw32-gcc linux/arm64/aarch64-linux-gnu-gcc" + + echo "Release builds for OS/Arch/CC: ${SUPPORTED_OSARCH}" + for each_osarch in ${SUPPORTED_OSARCH}; do + _build "${each_osarch}" + done +} + +usage() { + # echo "Usage: $0 [-f] [-c] [-b] [-r]" 1>&2 + echo "Usage: $0 [-f] [-b] [-r]" 1>&2 + exit 1 +} + +while getopts "bfcrd" o; do + case "${o}" in + b) + FRONTEND="true" + BINARY="true" + ;; + f) + FRONTEND="true" + ;; + c) + BINARY="true" + ;; + r) + FRONTEND="true" + RELEASE="true" + ;; + d) + DEBUG="true" + ;; + *) + usage + ;; + esac +done +shift $((OPTIND - 1)) + +if [ "$DEBUG" = "true" ]; then + debugInfo +fi + +if [ "$FRONTEND" = "true" ]; then + buildFrontend +fi + +# if [ "$BINARY" = "true" ]; then +# buildBinary +# fi + +if [ "$RELEASE" = "true" ]; then + buildBackEndAssets + release +fi \ No newline at end of file diff --git a/doc/images/icon-info-new.png b/doc/images/icon-info-new.png new file mode 100644 index 0000000..c31947e Binary files /dev/null and b/doc/images/icon-info-new.png differ diff --git a/doc/images/icon-small-new.png b/doc/images/icon-small-new.png new file mode 100644 index 0000000..58d9194 Binary files /dev/null and b/doc/images/icon-small-new.png differ diff --git a/doc/images/logo.png b/doc/images/logo.png new file mode 100644 index 0000000..a3aac61 Binary files /dev/null and b/doc/images/logo.png differ diff --git a/doc/images/solid-color-info.png b/doc/images/solid-color-info.png new file mode 100644 index 0000000..2456a1b Binary files /dev/null and b/doc/images/solid-color-info.png differ diff --git a/doc/images/transparent-info.png b/doc/images/transparent-info.png new file mode 100644 index 0000000..8d22c10 Binary files /dev/null and b/doc/images/transparent-info.png differ diff --git a/doc/images/transparent-small.png b/doc/images/transparent-small.png new file mode 100644 index 0000000..a79846f Binary files /dev/null and b/doc/images/transparent-small.png differ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..22ad954 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: "3.2" + +services: + sun-panel: + image: 'hslr/sun-panel:latest' + container_name: sun-panel + volumes: + - ./conf:/app/conf + - ./uploads:/app/uploads + - ./database:/app/database + # - ./runtime:/app/runtime + ports: + - 3002:3002 + restart: always \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 47b016c..b8c261c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "chatgpt-web", + "name": "sun-panel", "version": "2.10.9", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "chatgpt-web", + "name": "sun-panel", "version": "2.10.9", "dependencies": { "@traptitech/markdown-it-katex": "^3.6.0", diff --git a/package.json b/package.json index c2781cd..b7f6618 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { - "name": "chatgpt-web", + "name": "sun-panel", "version": "2.10.9", "private": false, "description": "ChatGPT Web", "author": "ChenZhaoYu ", "keywords": [ - "chatgpt-web", + "Sun-Panel", "chatgpt", "chatbot", "vue" @@ -32,6 +32,7 @@ "naive-ui": "^2.34.3", "pinia": "^2.0.33", "vue": "^3.2.47", + "vue-draggable-plus": "^0.2.6", "vue-i18n": "^9.2.2", "vue-router": "^4.1.6", "vuedraggable": "^4.1.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5eebed..f5be7b5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,15 +11,9 @@ dependencies: '@vueuse/core': specifier: ^9.13.0 version: 9.13.0(vue@3.2.47) - echarts: - specifier: ^5.4.2 - version: 5.4.2 highlight.js: specifier: ^11.7.0 version: 11.7.0 - html2canvas: - specifier: ^1.4.1 - version: 1.4.1 katex: specifier: ^0.16.4 version: 0.16.4 @@ -38,6 +32,9 @@ dependencies: vue: specifier: ^3.2.47 version: 3.2.47 + vue-draggable-plus: + specifier: ^0.2.6 + version: 0.2.6(@types/sortablejs@1.15.5) vue-i18n: specifier: ^9.2.2 version: 9.2.2(vue@3.2.47) @@ -2174,6 +2171,10 @@ packages: resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} dev: true + /@types/sortablejs@1.15.5: + resolution: {integrity: sha512-qqqbEFbB1EZt08I1Ok2BA3Sx0zlI8oizdIguMsajk4Yo/iHgXhCb3GM6N09JOJqT9xIMYM9LTFy8vit3RNY71Q==} + dev: false + /@types/trusted-types@2.0.3: resolution: {integrity: sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==} dev: true @@ -2733,11 +2734,6 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true - /base64-arraybuffer@1.0.2: - resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==} - engines: {node: '>= 0.6.0'} - dev: false - /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -3087,12 +3083,6 @@ packages: engines: {node: '>=8'} dev: true - /css-line-break@2.1.0: - resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==} - dependencies: - utrie: 1.0.2 - dev: false - /css-render@0.15.12: resolution: {integrity: sha512-eWzS66patiGkTTik+ipO9qNGZ+uNuGyTmnz6/+EJIiFg8+3yZRpnMwgFo8YdXhQRsiePzehnusrxVvugNjXzbw==} dependencies: @@ -3279,13 +3269,6 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /echarts@5.4.2: - resolution: {integrity: sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==} - dependencies: - tslib: 2.3.0 - zrender: 5.4.3 - dev: false - /ejs@3.1.8: resolution: {integrity: sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==} engines: {node: '>=0.10.0'} @@ -4238,14 +4221,6 @@ packages: lru-cache: 6.0.0 dev: true - /html2canvas@1.4.1: - resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==} - engines: {node: '>=8.0.0'} - dependencies: - css-line-break: 2.1.0 - text-segmentation: 1.0.3 - dev: false - /htmlparser2@8.0.1: resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==} dependencies: @@ -5093,6 +5068,7 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + requiresBuild: true dev: true /muggle-string@0.2.2: @@ -6224,12 +6200,6 @@ packages: engines: {node: '>=0.10'} dev: true - /text-segmentation@1.0.3: - resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==} - dependencies: - utrie: 1.0.2 - dev: false - /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -6314,10 +6284,6 @@ packages: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true - /tslib@2.3.0: - resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} - dev: false - /tslib@2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} dev: true @@ -6462,12 +6428,6 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true - /utrie@1.0.2: - resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==} - dependencies: - base64-arraybuffer: 1.0.2 - dev: false - /v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true @@ -6566,6 +6526,18 @@ packages: vue: 3.2.47 dev: false + /vue-draggable-plus@0.2.6(@types/sortablejs@1.15.5): + resolution: {integrity: sha512-d+0omKIBIfLiJFggc6H4ePRaifbX+33+OiCMsxn8rG59yWXlJGrobexxgXetnSo/1NLTd0TkYZKNc4CA6iwJZw==} + peerDependencies: + '@types/sortablejs': ^1.15.0 + '@vue/composition-api': '*' + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + '@types/sortablejs': 1.15.5 + dev: false + /vue-eslint-parser@9.1.0(eslint@8.35.0): resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==} engines: {node: ^14.17.0 || >=16.0.0} @@ -6953,9 +6925,3 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true - - /zrender@5.4.3: - resolution: {integrity: sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==} - dependencies: - tslib: 2.3.0 - dev: false diff --git a/public/favicon-black.svg b/public/favicon-black.svg new file mode 100644 index 0000000..4f1f1e1 --- /dev/null +++ b/public/favicon-black.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico index cb154e0..3e414ed 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.svg b/public/favicon.svg index 46faab2..561e1f5 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..a3aac61 Binary files /dev/null and b/public/logo.png differ diff --git a/service/api/api_v1/common/apiData/commonApiStructs/common.go b/service/api/api_v1/common/apiData/commonApiStructs/common.go index e98847b..5643a5c 100644 --- a/service/api/api_v1/common/apiData/commonApiStructs/common.go +++ b/service/api/api_v1/common/apiData/commonApiStructs/common.go @@ -20,3 +20,12 @@ type VerificationResponse struct { Result bool `json:"result"` Message string `json:"message"` } + +type SortRequestItem struct { + Id uint `json:"id"` + Sort uint `json:"sort"` +} + +type SortRequest struct { + SortItems []SortRequestItem `json:"sortItems"` +} diff --git a/service/api/api_v1/common/apiData/panelApiStructs/itemIcon.go b/service/api/api_v1/common/apiData/panelApiStructs/itemIcon.go index 6961d1b..027a4b2 100644 --- a/service/api/api_v1/common/apiData/panelApiStructs/itemIcon.go +++ b/service/api/api_v1/common/apiData/panelApiStructs/itemIcon.go @@ -1,8 +1,16 @@ -package adminApiStructs +package panelApiStructs -import "sun-panel/models" +import ( + "sun-panel/api/api_v1/common/apiData/commonApiStructs" + "sun-panel/models" +) type ItemIconEditRequest struct { models.ItemIcon IconJson string } + +type ItemIconSaveSortRequest struct { + SortItems []commonApiStructs.SortRequestItem `json:"sortItems"` + ItemIconGroupId uint `json:"itemIconGroupId"` +} diff --git a/service/api/api_v1/panel/A_ENTER.go b/service/api/api_v1/panel/A_ENTER.go index eacd0a9..57aaf53 100644 --- a/service/api/api_v1/panel/A_ENTER.go +++ b/service/api/api_v1/panel/A_ENTER.go @@ -1,7 +1,8 @@ package panel type ApiPanel struct { - ItemIcon ItemIcon - UserConfig UserConfig - UsersApi UsersApi + ItemIcon ItemIcon + UserConfig UserConfig + UsersApi UsersApi + ItemIconGroup ItemIconGroup } diff --git a/service/api/api_v1/panel/ItemIconGroup.go b/service/api/api_v1/panel/ItemIconGroup.go new file mode 100644 index 0000000..9802062 --- /dev/null +++ b/service/api/api_v1/panel/ItemIconGroup.go @@ -0,0 +1,152 @@ +package panel + +import ( + "math" + "sun-panel/api/api_v1/common/apiData/commonApiStructs" + "sun-panel/api/api_v1/common/apiReturn" + "sun-panel/api/api_v1/common/base" + "sun-panel/global" + "sun-panel/models" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" + "gorm.io/gorm" +) + +type ItemIconGroup struct { +} + +func (a *ItemIconGroup) Edit(c *gin.Context) { + userInfo, _ := base.GetCurrentUserInfo(c) + req := models.ItemIconGroup{} + + if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { + apiReturn.ErrorParamFomat(c, err.Error()) + return + } + + req.UserId = userInfo.ID + + if req.ID != 0 { + // 修改 + updateField := []string{"IconJson", "Icon", "Title", "Url", "LanUrl", "Description", "OpenMethod", "GroupId", "UserId"} + if req.Sort != 0 { + updateField = append(updateField, "Sort") + } + global.Db.Model(&models.ItemIconGroup{}). + Select(updateField). + Where("id=?", req.ID).Updates(&req) + } else { + // 创建 + global.Db.Create(&req) + } + + apiReturn.SuccessData(c, req) +} + +func (a *ItemIconGroup) GetList(c *gin.Context) { + + userInfo, _ := base.GetCurrentUserInfo(c) + groups := []models.ItemIconGroup{} + + if err := global.Db.Order("sort ,created_at").Where("user_id=?", userInfo.ID).Find(&groups).Error; err != nil { + apiReturn.ErrorDatabase(c, err.Error()) + return + } + + // 判断分组是否为空,为空将自动创建默认分组 + if len(groups) == 0 { + defaultGroup := models.ItemIconGroup{ + Title: "APP", + UserId: userInfo.ID, + Icon: "material-symbols:ad-group-outline"} + if err := global.Db.Create(&defaultGroup).Error; err != nil { + apiReturn.ErrorDatabase(c, err.Error()) + return + } + + // 并将当前账号下所有无分组的图标更新到当前组 + if err := global.Db.Model(&models.ItemIcon{}).Where("user_id=?", userInfo.ID).Update("item_icon_group_id", defaultGroup.ID).Error; err != nil { + apiReturn.ErrorDatabase(c, err.Error()) + return + } + + groups = append(groups, defaultGroup) + } + + apiReturn.SuccessListData(c, groups, 0) +} + +func (a *ItemIconGroup) Deletes(c *gin.Context) { + req := commonApiStructs.RequestDeleteIds[uint]{} + + if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { + apiReturn.ErrorParamFomat(c, err.Error()) + return + } + userInfo, _ := base.GetCurrentUserInfo(c) + + var count int64 + if err := global.Db.Model(&models.ItemIconGroup{}).Where(" user_id=?", userInfo.ID).Count(&count).Error; err != nil { + apiReturn.ErrorDatabase(c, err.Error()) + return + } else { + if math.Abs(float64(len(req.Ids))-float64(count)) < 1 { + apiReturn.Error(c, "至少要保留一个") + return + } + + } + + txErr := global.Db.Transaction(func(tx *gorm.DB) error { + mitemIcon := models.ItemIcon{} + if err := tx.Delete(&models.ItemIconGroup{}, "id in ? AND user_id=?", req.Ids, userInfo.ID).Error; err != nil { + return err + } + + if err := mitemIcon.DeleteByItemIconGroupIds(tx, userInfo.ID, req.Ids); err != nil { + return err + } + + return nil + }) + + if txErr != nil { + apiReturn.ErrorDatabase(c, txErr.Error()) + return + } + + apiReturn.Success(c) +} + +// 保存排序 +func (a *ItemIconGroup) SaveSort(c *gin.Context) { + req := commonApiStructs.SortRequest{} + + if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { + apiReturn.ErrorParamFomat(c, err.Error()) + return + } + + userInfo, _ := base.GetCurrentUserInfo(c) + + transactionErr := global.Db.Transaction(func(tx *gorm.DB) error { + // 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db') + for _, v := range req.SortItems { + if err := tx.Model(&models.ItemIconGroup{}).Where("user_id=? AND id=?", userInfo.ID, v.Id).Update("sort", v.Sort).Error; err != nil { + // 返回任何错误都会回滚事务 + return err + } + } + + // 返回 nil 提交事务 + return nil + }) + + if transactionErr != nil { + apiReturn.ErrorDatabase(c, transactionErr.Error()) + return + } + + apiReturn.Success(c) +} diff --git a/service/api/api_v1/panel/itemIcon.go b/service/api/api_v1/panel/itemIcon.go index 67aafbb..ff9c4c6 100644 --- a/service/api/api_v1/panel/itemIcon.go +++ b/service/api/api_v1/panel/itemIcon.go @@ -3,6 +3,7 @@ package panel import ( "encoding/json" "sun-panel/api/api_v1/common/apiData/commonApiStructs" + "sun-panel/api/api_v1/common/apiData/panelApiStructs" "sun-panel/api/api_v1/common/apiReturn" "sun-panel/api/api_v1/common/base" "sun-panel/global" @@ -10,6 +11,7 @@ import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" + "gorm.io/gorm" ) type ItemIcon struct { @@ -24,9 +26,12 @@ func (a *ItemIcon) Edit(c *gin.Context) { return } + if req.ItemIconGroupId == 0 { + apiReturn.Error(c, "分组为必填项") + return + } + req.UserId = userInfo.ID - req.GroupId = 1 - req.Sort = 1 // json转字符串 if j, err := json.Marshal(req.Icon); err == nil { @@ -35,10 +40,15 @@ func (a *ItemIcon) Edit(c *gin.Context) { if req.ID != 0 { // 修改 + updateField := []string{"IconJson", "Icon", "Title", "Url", "LanUrl", "Description", "OpenMethod", "GroupId", "UserId", "ItemIconGroupId"} + if req.Sort != 0 { + updateField = append(updateField, "Sort") + } global.Db.Model(&models.ItemIcon{}). - Select("IconJson", "Icon", "Title", "Url", "LanUrl", "Description", "OpenMethod", "Sort", "GroupId", "UserId"). + Select(updateField). Where("id=?", req.ID).Updates(&req) } else { + req.Sort = 9999 // 创建 global.Db.Create(&req) } @@ -77,7 +87,7 @@ func (a *ItemIcon) Edit(c *gin.Context) { // } func (a *ItemIcon) GetListByGroupId(c *gin.Context) { - req := commonApiStructs.RequestPage{} + req := models.ItemIcon{} if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { apiReturn.ErrorParamFomat(c, err.Error()) @@ -87,7 +97,7 @@ func (a *ItemIcon) GetListByGroupId(c *gin.Context) { userInfo, _ := base.GetCurrentUserInfo(c) itemIcons := []models.ItemIcon{} - if err := global.Db.Order("sort ,created_at DESC").Where("user_id=?", userInfo.ID).Find(&itemIcons, "group_id = ? AND user_id=?", 1, userInfo.ID).Error; err != nil { + if err := global.Db.Order("sort ,created_at").Find(&itemIcons, "item_icon_group_id = ? AND user_id=?", req.ItemIconGroupId, userInfo.ID).Error; err != nil { apiReturn.ErrorDatabase(c, err.Error()) return } @@ -108,10 +118,42 @@ func (a *ItemIcon) Deletes(c *gin.Context) { } userInfo, _ := base.GetCurrentUserInfo(c) - if err := global.Db.Debug().Delete(&models.ItemIcon{}, "id in ? AND user_id=?", req.Ids, userInfo.ID).Error; err != nil { + if err := global.Db.Delete(&models.ItemIcon{}, "id in ? AND user_id=?", req.Ids, userInfo.ID).Error; err != nil { apiReturn.ErrorDatabase(c, err.Error()) return } apiReturn.Success(c) } + +// 保存排序 +func (a *ItemIcon) SaveSort(c *gin.Context) { + req := panelApiStructs.ItemIconSaveSortRequest{} + + if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { + apiReturn.ErrorParamFomat(c, err.Error()) + return + } + + userInfo, _ := base.GetCurrentUserInfo(c) + + transactionErr := global.Db.Transaction(func(tx *gorm.DB) error { + // 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db') + for _, v := range req.SortItems { + if err := tx.Model(&models.ItemIcon{}).Where("user_id=? AND id=? AND item_icon_group_id=?", userInfo.ID, v.Id, req.ItemIconGroupId).Update("sort", v.Sort).Error; err != nil { + // 返回任何错误都会回滚事务 + return err + } + } + + // 返回 nil 提交事务 + return nil + }) + + if transactionErr != nil { + apiReturn.ErrorDatabase(c, transactionErr.Error()) + return + } + + apiReturn.Success(c) +} diff --git a/service/api/api_v1/panel/users.go b/service/api/api_v1/panel/users.go index c5b23a4..ff5265f 100644 --- a/service/api/api_v1/panel/users.go +++ b/service/api/api_v1/panel/users.go @@ -1,6 +1,7 @@ package panel import ( + "math" "sun-panel/api/api_v1/common/apiReturn" "sun-panel/api/api_v1/common/base" "sun-panel/global" @@ -9,6 +10,7 @@ import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" + "gorm.io/gorm" ) // 此API 临时使用,后期带有管理功能,将废除!!! @@ -64,10 +66,55 @@ func (a UsersApi) Deletes(c *gin.Context) { return } - if err := global.Db.Delete(&models.User{}, ¶m.UserIds).Error; err != nil { + var count int64 + if err := global.Db.Model(&models.User{}).Count(&count).Error; err != nil { apiReturn.ErrorDatabase(c, err.Error()) return + } else { + if math.Abs(float64(len(param.UserIds))-float64(count)) < 1 { + apiReturn.Error(c, "至少要保留一个") + return + } } + + txErr := global.Db.Transaction(func(tx *gorm.DB) error { + mitemIconGroup := models.ItemIconGroup{} + + for _, v := range param.UserIds { + // 删除图标 + if err := tx.Delete(&models.ItemIcon{}, "user_id=?", v).Error; err != nil { + return err + } + // 删除分组 + if err := mitemIconGroup.DeleteByUserId(tx, v); err != nil { + return err + } + // 删除模块配置 + if err := tx.Delete(&models.ModuleConfig{}, "user_id=?", v).Error; err != nil { + return err + } + // 删除用户配置 + if err := tx.Delete(&models.ModuleConfig{}, "user_id=?", v).Error; err != nil { + return err + } + // // 删除文件记录(不删除资源文件) + // if err := tx.Delete(&models.File{}, "user_id=?", v).Error; err != nil { + // return err + // } + } + + if err := tx.Delete(&models.User{}, ¶m.UserIds).Error; err != nil { + apiReturn.ErrorDatabase(c, err.Error()) + return err + } + return nil + }) + + if txErr != nil { + apiReturn.ErrorDatabase(c, txErr.Error()) + return + } + apiReturn.Success(c) } diff --git a/service/api/api_v1/system/A_ENTER.go b/service/api/api_v1/system/A_ENTER.go index cd6412d..f1b8636 100644 --- a/service/api/api_v1/system/A_ENTER.go +++ b/service/api/api_v1/system/A_ENTER.go @@ -1,11 +1,12 @@ package system type ApiSystem struct { - About About - LoginApi LoginApi - UserApi UserApi - FileApi FileApi - CaptchaApi CaptchaApi - RegisterApi RegisterApi - NoticeApi NoticeApi + About About + LoginApi LoginApi + UserApi UserApi + FileApi FileApi + CaptchaApi CaptchaApi + RegisterApi RegisterApi + NoticeApi NoticeApi + ModuleConfigApi ModuleConfigApi } diff --git a/service/api/api_v1/system/ModuleConfig.go b/service/api/api_v1/system/ModuleConfig.go new file mode 100644 index 0000000..d3b490c --- /dev/null +++ b/service/api/api_v1/system/ModuleConfig.go @@ -0,0 +1,53 @@ +package system + +import ( + "sun-panel/api/api_v1/common/apiReturn" + "sun-panel/api/api_v1/common/base" + "sun-panel/global" + "sun-panel/models" + + "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" +) + +type ModuleConfigApi struct{} + +func (a *ModuleConfigApi) GetByName(c *gin.Context) { + req := models.ModuleConfig{} + + if err := c.ShouldBindWith(&req, binding.JSON); err != nil { + apiReturn.ErrorParamFomat(c, err.Error()) + return + } + + userInfo, _ := base.GetCurrentUserInfo(c) + + mCfg := models.ModuleConfig{} + if cfg, err := mCfg.GetConfigByUserIdAndName(global.Db, userInfo.ID, req.Name); err != nil { + apiReturn.ErrorDatabase(c, err.Error()) + return + } else { + apiReturn.SuccessData(c, cfg) + return + } + +} + +func (a *ModuleConfigApi) Save(c *gin.Context) { + req := models.ModuleConfig{} + if err := c.ShouldBindWith(&req, binding.JSON); err != nil { + apiReturn.ErrorParamFomat(c, err.Error()) + return + } + userInfo, _ := base.GetCurrentUserInfo(c) + mCfg := models.ModuleConfig{} + mCfg.UserId = userInfo.ID + mCfg.Value = req.Value + mCfg.Name = req.Name + + if err := mCfg.Save(global.Db); err != nil { + apiReturn.ErrorDatabase(c, err.Error()) + return + } + apiReturn.Success(c) +} diff --git a/service/api/api_v1/system/login.go b/service/api/api_v1/system/login.go index 7ec6098..9f2f442 100644 --- a/service/api/api_v1/system/login.go +++ b/service/api/api_v1/system/login.go @@ -23,8 +23,8 @@ type LoginApi struct { // 登录输入验证 type LoginLoginVerify struct { - Username string `json:"username" validate:"required,min=5"` - Password string `json:"password" validate:"required,min=5,max=20"` + Username string `json:"username" validate:"required"` + Password string `json:"password" validate:"required,max=50"` VCode string `json:"vcode" validate:"max=6"` Email string `json:"email"` } diff --git a/service/assets/conf.example.ini b/service/assets/conf.example.ini index dec7644..7d47bb0 100644 --- a/service/assets/conf.example.ini +++ b/service/assets/conf.example.ini @@ -23,7 +23,7 @@ host=127.0.0.1 port=3306 username=root password=root -db_name=chatgpt +db_name=sun_panel wait_timeout=100 # ====================== @@ -39,37 +39,4 @@ file_path=./database/database.db address=127.0.0.1:6379 password= prefix=sun_panel: -db=0 - -# ================ -# proxy -# ================ -[proxy] -url= - -# ====================== -# Automatically generated -# Prohibit modification -# ====================== -[build] -conf_version=1 -; install_time=132456 - - -# ====================== -# Initial configuration -# ====================== -# Automatically delete after successful initialization -[init] -# Administrator account (try to use email format; 6-16 digits) -admin_username=admin -# Administrator password (6-16 digits) -admin_password=123456 - -# ====================== -# 支付宝支付相关配置 -# ====================== -[alipay] -appid= -private_key= -alipay_public_key= \ No newline at end of file +db=0 \ No newline at end of file diff --git a/service/assets/version b/service/assets/version index 972893c..177cd67 100644 --- a/service/assets/version +++ b/service/assets/version @@ -1 +1 @@ -1|1.0.0 \ No newline at end of file +3|1.1.0 \ No newline at end of file diff --git a/service/initialize/A_ENTER.go b/service/initialize/A_ENTER.go index 54d6115..fd8c53a 100644 --- a/service/initialize/A_ENTER.go +++ b/service/initialize/A_ENTER.go @@ -29,6 +29,7 @@ var DB_DRIVER = database.SQLITE // var ISDOCER = "" // 是否为docker模式 func InitApp() error { + Logo() gin.SetMode(global.RUNCODE) // GIN 运行模式 // 日志 @@ -176,3 +177,17 @@ func CommandRun() { } os.Exit(0) // 务必退出 } + +func Logo() { + fmt.Println(" ____ ___ __") + fmt.Println(" / __/_ _____ / _ \\___ ____ ___ / /") + fmt.Println(" _\\ \\/ // / _ \\ / ___/ _ `/ _ \\/ -_) / ") + fmt.Println(" /___/\\_,_/_//_/ /_/ \\_,_/_//_/\\__/_/ ") + fmt.Println("") + + versionInfo := cmn.GetSysVersionInfo() + fmt.Println("Version:", versionInfo.Version) + fmt.Println("Welcome to the Sun-Panel.") + fmt.Println("Project address:", "https://github.com/hslr-s/sun-panel") + +} diff --git a/service/initialize/database/connect.go b/service/initialize/database/connect.go index f7caa4b..f0dc6a1 100644 --- a/service/initialize/database/connect.go +++ b/service/initialize/database/connect.go @@ -76,7 +76,7 @@ func (d *SQLiteConfig) Connect() (db *gorm.DB, err error) { // 创建文件夹 if !exists { - if err = os.MkdirAll(path.Dir(filePath), 0666); err != nil { + if err = os.MkdirAll(path.Dir(filePath), 0700); err != nil { return } } @@ -121,6 +121,8 @@ func CreateDatabase(driver string, db *gorm.DB) error { &models.ItemIcon{}, &models.UserConfig{}, &models.File{}, + &models.ItemIconGroup{}, + &models.ModuleConfig{}, ) return err diff --git a/service/lib/cmn/base.go b/service/lib/cmn/base.go index 1f45e7f..3472b15 100644 --- a/service/lib/cmn/base.go +++ b/service/lib/cmn/base.go @@ -5,7 +5,6 @@ import ( "crypto/md5" "encoding/hex" "fmt" - "io/ioutil" "math/rand" "os" "path" @@ -198,7 +197,7 @@ func AssetsTakeFileToPath(assetsPath, targetPath string) error { return err } } - return ioutil.WriteFile(targetPath, bytes, 0666) + return os.WriteFile(targetPath, bytes, 0666) } // 密码加密 diff --git a/service/lib/cmn/log.go b/service/lib/cmn/log.go index 2818107..a8b72ce 100644 --- a/service/lib/cmn/log.go +++ b/service/lib/cmn/log.go @@ -93,7 +93,7 @@ func NewLog(log_file_name string) *LogStruct { logDir := path.Dir(log_file_name) ok, _ := PathExists(logDir) if !ok { - if err := os.MkdirAll(logDir, 0666); err != nil { + if err := os.MkdirAll(logDir, 0700); err != nil { fmt.Println("创建日志文件错误", err.Error()) } } @@ -128,7 +128,7 @@ func RunLog() *LogStruct { runLogStatic.Writer = io.MultiWriter(f) } else { if runLogStatic.File == nil { - f, _ := os.OpenFile(log_file_name, os.O_APPEND|os.O_WRONLY, 0666) + f, _ := os.OpenFile(log_file_name, os.O_APPEND|os.O_WRONLY, 0700) runLogStatic.File = f runLogStatic.Writer = io.MultiWriter(f) } diff --git a/service/models/datatype/itemIcon.go b/service/models/datatype/itemIcon.go index f27766a..672bc6e 100644 --- a/service/models/datatype/itemIcon.go +++ b/service/models/datatype/itemIcon.go @@ -4,5 +4,6 @@ type ItemIconIconInfo struct { ItemType int `json:"itemType"` Src string `json:"src"` Text string `json:"text"` - BgColor string `json:"bgColor"` + // BgColor string `json:"bgColor"` + BackgroundColor string `json:"backgroundColor"` } diff --git a/service/models/itemIcon.go b/service/models/itemIcon.go index d306260..60471c5 100644 --- a/service/models/itemIcon.go +++ b/service/models/itemIcon.go @@ -1,18 +1,31 @@ package models -import "sun-panel/models/datatype" +import ( + "sun-panel/models/datatype" + + "gorm.io/gorm" +) type ItemIcon struct { BaseModel - IconJson string `gorm:"type:varchar(1000)" json:"-"` - Icon datatype.ItemIconIconInfo `gorm:"-" json:"icon"` - Title string `gorm:"type:varchar(50)" json:"title"` - Url string `gorm:"type:varchar(1000)" json:"url"` - LanUrl string `gorm:"type:varchar(1000)" json:"lanUrl"` - Description string `gorm:"type:varchar(1000)" json:"description"` - OpenMethod int `gorm:"type:tinyint(1)" json:"openMethod"` - Sort int `gorm:"type:int(11)" json:"sort"` - GroupId int `json:"groupId"` // 为以后分组做准备 - UserId uint `json:"userId"` - User User `json:"user"` + IconJson string `gorm:"type:varchar(1000)" json:"-"` + Icon datatype.ItemIconIconInfo `gorm:"-" json:"icon"` + Title string `gorm:"type:varchar(50)" json:"title"` + Url string `gorm:"type:varchar(1000)" json:"url"` + LanUrl string `gorm:"type:varchar(1000)" json:"lanUrl"` + Description string `gorm:"type:varchar(1000)" json:"description"` + OpenMethod int `gorm:"type:tinyint(1)" json:"openMethod"` + Sort int `gorm:"type:int(11)" json:"sort"` + ItemIconGroupId int `json:"itemIconGroupId"` + UserId uint `json:"userId"` + User User `json:"user"` +} + +func (m *ItemIcon) DeleteByItemIconGroupIds(db *gorm.DB, userId uint, itemIconGroupIds []uint) (err error) { + err = db.Delete(&ItemIcon{}, "item_icon_group_id in ? AND user_id=?", itemIconGroupIds, userId).Error + return +} + +func (m *ItemIcon) DeleteByUserId(db *gorm.DB, userId uint) (err error) { + return db.Delete(&ItemIcon{}, "user_id=?", userId).Error } diff --git a/service/models/itemIconGroup.go b/service/models/itemIconGroup.go new file mode 100644 index 0000000..0c51c65 --- /dev/null +++ b/service/models/itemIconGroup.go @@ -0,0 +1,20 @@ +package models + +import ( + "gorm.io/gorm" +) + +type ItemIconGroup struct { + BaseModel + Icon string `json:"icon"` + Title string `gorm:"type:varchar(50)" json:"title"` + Description string `gorm:"type:varchar(1000)" json:"description"` + Sort int `gorm:"type:int(11)" json:"sort"` + UserId uint `json:"userId"` + User User `json:"user"` +} + +func (m *ItemIconGroup) DeleteByUserId(db *gorm.DB, userId uint) (err error) { + err = db.Delete(&ItemIconGroup{}, "user_id = ?", userId).Error + return +} diff --git a/service/models/moduleConfig.go b/service/models/moduleConfig.go new file mode 100644 index 0000000..31f94b6 --- /dev/null +++ b/service/models/moduleConfig.go @@ -0,0 +1,61 @@ +package models + +import ( + "encoding/json" + + "gorm.io/gorm" +) + +type ModuleConfig struct { + BaseModel + UserId uint `gorm:"index" json:"userId"` + Name string `gorm:"type:varchar(255)" json:"name"` + ValueJson string `gorm:"type:text" json:"-"` + Value map[string]interface{} `gorm:"-" json:"value"` +} + +func (m *ModuleConfig) GetConfigByUserIdAndName(db *gorm.DB, userId uint, name string) (map[string]interface{}, error) { + cfg := ModuleConfig{} + if err := db.First(&cfg, "user_id=? AND name=?", userId, name).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, err + } + } + + // 处理字段 + if err := json.Unmarshal([]byte(cfg.ValueJson), &cfg.Value); err != nil { + cfg.Value = nil + } + return cfg.Value, nil +} + +func (m *ModuleConfig) Save(db *gorm.DB) error { + + // 处理字段 + if jb, err := json.Marshal(m.Value); err != nil { + m.ValueJson = "{}" + } else { + m.ValueJson = string(jb) + } + + // 保存操作 + if err := db.First(&ModuleConfig{}, "user_id=? AND name=?", m.UserId, m.Name).Error; err != nil { + if err == gorm.ErrRecordNotFound { + // 新增 + if err := db.Create(&m).Error; err != nil { + return err + } + } else { + return err + } + } else { + // 修改 + if err := db.Select("Name", "UserId", "ValueJson").Where("user_id=? AND name=?", m.UserId, m.Name).Updates(&m).Error; err != nil { + return err + } + } + + return nil +} diff --git a/service/router/panel/A_ENTER.go b/service/router/panel/A_ENTER.go index c9f14ea..7a5ac10 100644 --- a/service/router/panel/A_ENTER.go +++ b/service/router/panel/A_ENTER.go @@ -6,4 +6,5 @@ func Init(routerGroup *gin.RouterGroup) { InitItemIcon(routerGroup) InitUserConfig(routerGroup) InitUsersRouter(routerGroup) + InitItemIconGroup(routerGroup) } diff --git a/service/router/panel/itemIcon.go b/service/router/panel/itemIcon.go index 3f49c27..5dee10d 100644 --- a/service/router/panel/itemIcon.go +++ b/service/router/panel/itemIcon.go @@ -14,5 +14,6 @@ func InitItemIcon(router *gin.RouterGroup) { r.POST("/panel/itemIcon/edit", itemIcon.Edit) r.POST("/panel/itemIcon/getListByGroupId", itemIcon.GetListByGroupId) r.POST("/panel/itemIcon/deletes", itemIcon.Deletes) + r.POST("/panel/itemIcon/saveSort", itemIcon.SaveSort) } } diff --git a/service/router/panel/itemIconGroup.go b/service/router/panel/itemIconGroup.go new file mode 100644 index 0000000..ee3d534 --- /dev/null +++ b/service/router/panel/itemIconGroup.go @@ -0,0 +1,19 @@ +package panel + +import ( + "sun-panel/api/api_v1" + "sun-panel/api/api_v1/middleware" + + "github.com/gin-gonic/gin" +) + +func InitItemIconGroup(router *gin.RouterGroup) { + itemIconGroup := api_v1.ApiGroupApp.ApiPanel.ItemIconGroup + r := router.Group("", middleware.LoginInterceptor) + { + r.POST("/panel/itemIconGroup/edit", itemIconGroup.Edit) + r.POST("/panel/itemIconGroup/getList", itemIconGroup.GetList) + r.POST("/panel/itemIconGroup/deletes", itemIconGroup.Deletes) + r.POST("/panel/itemIconGroup/saveSort", itemIconGroup.SaveSort) + } +} diff --git a/service/router/system/A_ENTER.go b/service/router/system/A_ENTER.go index 2290c4f..62e8b7c 100644 --- a/service/router/system/A_ENTER.go +++ b/service/router/system/A_ENTER.go @@ -10,4 +10,5 @@ func Init(routerGroup *gin.RouterGroup) { InitCaptchaRouter(routerGroup) InitRegister(routerGroup) InitNoticeRouter(routerGroup) + InitModuleConfigRouter(routerGroup) } diff --git a/service/router/system/moduleConfig.go b/service/router/system/moduleConfig.go new file mode 100644 index 0000000..3a17216 --- /dev/null +++ b/service/router/system/moduleConfig.go @@ -0,0 +1,16 @@ +package system + +import ( + "sun-panel/api/api_v1" + "sun-panel/api/api_v1/middleware" + + "github.com/gin-gonic/gin" +) + +func InitModuleConfigRouter(router *gin.RouterGroup) { + api := api_v1.ApiGroupApp.ApiSystem.ModuleConfigApi + r := router.Group("", middleware.LoginInterceptor) + r.POST("/system/moduleConfig/getByName", api.GetByName) + r.POST("/system/moduleConfig/save", api.Save) + +} diff --git a/src/api/panel/itemIcon.ts b/src/api/panel/itemIcon.ts index b822100..8de1a09 100644 --- a/src/api/panel/itemIcon.ts +++ b/src/api/panel/itemIcon.ts @@ -14,9 +14,10 @@ export function edit(req: Panel.ItemInfo) { // }) // } -export function getListByGroupId() { +export function getListByGroupId(itemIconGroupId: number | undefined) { return post({ url: '/panel/itemIcon/getListByGroupId', + data: { itemIconGroupId }, }) } @@ -26,3 +27,10 @@ export function deletes(ids: number[]) { data: { ids }, }) } + +export function saveSort(data: Panel.ItemIconSortRequest) { + return post({ + url: '/panel/itemIcon/saveSort', + data, + }) +} diff --git a/src/api/panel/itemIconGroup.ts b/src/api/panel/itemIconGroup.ts new file mode 100644 index 0000000..ab6182d --- /dev/null +++ b/src/api/panel/itemIconGroup.ts @@ -0,0 +1,28 @@ +import { post } from '@/utils/request' + +export function edit(req: Panel.ItemIconGroup) { + return post({ + url: '/panel/itemIconGroup/edit', + data: req, + }) +} + +export function getList() { + return post({ + url: '/panel/itemIconGroup/getList', + }) +} + +export function deletes(ids: number[]) { + return post({ + url: '/panel/itemIconGroup/deletes', + data: { ids }, + }) +} + +export function saveSort(sortItems: Common.SortItemRequest[]) { + return post({ + url: '/panel/itemIconGroup/saveSort', + data: { sortItems }, + }) +} diff --git a/src/api/system/moduleConfig.ts b/src/api/system/moduleConfig.ts new file mode 100644 index 0000000..b9f4184 --- /dev/null +++ b/src/api/system/moduleConfig.ts @@ -0,0 +1,18 @@ +import { post } from '@/utils/request' + +export function getValueByName(name: string) { + return post({ + url: '/system/moduleConfig/getByName', + data: { name }, + }) +} + +export function save(name: string, value: any) { + return post({ + url: '/system/moduleConfig/save', + data: { + name, + value, + }, + }) +} diff --git a/src/assets/about_image/docker.png b/src/assets/about_image/docker.png new file mode 100644 index 0000000..4f6579e Binary files /dev/null and b/src/assets/about_image/docker.png differ diff --git a/src/assets/about_image/gitee.png b/src/assets/about_image/gitee.png new file mode 100644 index 0000000..fe2659a Binary files /dev/null and b/src/assets/about_image/gitee.png differ diff --git a/src/assets/about_image/github.png b/src/assets/about_image/github.png new file mode 100644 index 0000000..68cae8d Binary files /dev/null and b/src/assets/about_image/github.png differ diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..561e1f5 --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/search_engine_svg/baidu.svg b/src/assets/search_engine_svg/baidu.svg new file mode 100644 index 0000000..fcc30a0 --- /dev/null +++ b/src/assets/search_engine_svg/baidu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/search_engine_svg/bing.svg b/src/assets/search_engine_svg/bing.svg new file mode 100644 index 0000000..9af1c35 --- /dev/null +++ b/src/assets/search_engine_svg/bing.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/search_engine_svg/google.svg b/src/assets/search_engine_svg/google.svg new file mode 100644 index 0000000..b22ca18 --- /dev/null +++ b/src/assets/search_engine_svg/google.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/common/ItemIcon/index.vue b/src/components/common/ItemIcon/index.vue index 4e48390..708e470 100644 --- a/src/components/common/ItemIcon/index.vue +++ b/src/components/common/ItemIcon/index.vue @@ -1,40 +1,44 @@