diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 29be5107e..5ca720cda 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -11,29 +11,28 @@ jobs: environment: Deploy steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - # - uses: actions/setup-java@v4 - # with: - # java-version: '17' - # distribution: 'temurin' + # - uses: actions/setup-java@v4 + # with: + # java-version: '17' + # distribution: 'temurin' - # - run: mvn -B clean package -DskipTests + # - run: mvn -B clean package -DskipTests - # - uses: actions/setup-node@v4 - # with: - # node-version: '20' + # - uses: actions/setup-node@v4 + # with: + # node-version: '20' - # - run: | - # cd open-isle-cli - # npm ci - # npm run build - - - name: Deploy to Server - uses: appleboy/ssh-action@v1.0.3 - with: - host: ${{ secrets.SSH_HOST }} - username: root - key: ${{ secrets.SSH_KEY }} - script: bash /opt/openisle/deploy.sh + # - run: | + # cd open-isle-cli + # npm ci + # npm run build + - name: Deploy to Server + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.SSH_HOST }} + username: root + key: ${{ secrets.SSH_KEY }} + script: bash /opt/openisle/deploy.sh diff --git a/README.md b/README.md index 5a40441bc..524c49bba 100644 --- a/README.md +++ b/README.md @@ -13,16 +13,19 @@ OpenIsle 是一个使用 Spring Boot 和 Vue 3 构建的全栈开源社区平台 ## 🚀 部署 ### 后端 + 1. 确保安装 JDK 17 及 Maven 2. 信息配置修改 `src/main/resources/application.properties`,或通过环境变量设置数据库等参数 3. 执行 `mvn clean package` 生成包,之后使用 `java -jar target/openisle-0.0.1-SNAPSHOT.jar`启动,或在开发时直接使用 `mvn spring-boot:run` ### 前端 + 1. `cd open-isle-cli` 2. 执行 `npm install` 3. `npm run serve`可在本地启动开发服务,产品环境使用 `npm run build`生成 `dist/` 文件,配合线上网站方式部署 ## ✨ 项目特点 + - JWT 认证以及 Google、GitHub、Discord、Twitter 等多种 OAuth 登录 - 支持分类、标签的贴文管理以及草稿保存功能 - 嵌套评论、指定贴文或评论的点赞/抖弹系统 @@ -35,6 +38,7 @@ OpenIsle 是一个使用 Spring Boot 和 Vue 3 构建的全栈开源社区平台 - 浏览器推送通知,离开网站也能及时收到提醒 ## 🌟 项目优势 + - 全面开源,便于二次开发和自定义扩展 - Spring Boot + Vue 3 成熟技术栈,学习起点低,社区资源丰富 - 支持多种登录方式和角色权限,容易展展到不同场景 @@ -52,6 +56,7 @@ OpenIsle 是一个使用 Spring Boot 和 Vue 3 构建的全栈开源社区平台 本项目以 MIT License 发布,欢迎自由使用与修改。 ## 🙏 鼓赞 + - [Spring Boot](https://spring.io/projects/spring-boot) - [JJWT](https://github.com/jwtk/jjwt) - [Lombok](https://github.com/projectlombok/lombok) diff --git a/frontend_nuxt/assets/global.css b/frontend_nuxt/assets/global.css index 668654b83..6ad583063 100644 --- a/frontend_nuxt/assets/global.css +++ b/frontend_nuxt/assets/global.css @@ -184,7 +184,7 @@ body { margin: 1.2em 0; font-size: 14px; line-height: 1.45; - overflow-x: auto; /* 小屏可横向滚动 */ + overflow-x: auto; /* 小屏可横向滚动 */ } .info-content-text thead th { @@ -196,11 +196,11 @@ body { } [data-theme='dark'] .info-content-text thead th { - background-color: var(--primary-color-hover); /* 暗色稍暗一点 */ + background-color: var(--primary-color-hover); /* 暗色稍暗一点 */ } .info-content-text tbody tr:nth-child(even) { - background-color: rgba(208, 250, 255, 0.25); /* 斑马纹 */ + background-color: rgba(208, 250, 255, 0.25); /* 斑马纹 */ } [data-theme='dark'] .info-content-text tbody tr:nth-child(even) { @@ -232,7 +232,7 @@ body { @media (max-width: 768px) { .vditor { min-height: 100px; - } + } .vditor-toolbar { overflow-x: auto; @@ -255,7 +255,6 @@ body { margin-bottom: 3px; } - .vditor-toolbar--pin { top: 0 !important; } @@ -296,11 +295,13 @@ body { right: 0; width: 100px; height: 100%; - box-shadow: 0 0 10px var(--primary-color), 0 0 5px var(--primary-color); + box-shadow: + 0 0 10px var(--primary-color), + 0 0 5px var(--primary-color); opacity: 1; transform: rotate(3deg) translate(0px, -4px); } #nprogress .spinner { display: none; -} \ No newline at end of file +} diff --git a/frontend_nuxt/components/AchievementList.vue b/frontend_nuxt/components/AchievementList.vue index 5c925c61d..2039401a0 100644 --- a/frontend_nuxt/components/AchievementList.vue +++ b/frontend_nuxt/components/AchievementList.vue @@ -3,7 +3,10 @@
-
展示
+
+ 展示 +
{{ medal.title }}
{{ medal.description }} @@ -38,12 +43,12 @@ const props = defineProps({ medals: { type: Array, required: true, - default: () => [] + default: () => [], }, canSelect: { type: Boolean, - default: false - } + default: false, + }, }) const sortedMedals = computed(() => { @@ -64,12 +69,14 @@ const selectMedal = async (medal) => { method: 'POST', headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${getToken()}` + Authorization: `Bearer ${getToken()}`, }, - body: JSON.stringify({ type: medal.type }) + body: JSON.stringify({ type: medal.type }), }) if (res.ok) { - props.medals.forEach(m => { m.selected = m.type === medal.type }) + props.medals.forEach((m) => { + m.selected = m.type === medal.type + }) toast('展示勋章已更新') } else { toast('选择勋章失败') @@ -78,7 +85,6 @@ const selectMedal = async (medal) => { toast('选择勋章失败') } } - - diff --git a/frontend_nuxt/components/ActivityPopup.vue b/frontend_nuxt/components/ActivityPopup.vue index c6aa221e7..1758c1ecf 100644 --- a/frontend_nuxt/components/ActivityPopup.vue +++ b/frontend_nuxt/components/ActivityPopup.vue @@ -21,10 +21,10 @@ export default { props: { visible: { type: Boolean, default: false }, icon: String, - text: String + text: String, }, emits: ['close'], - setup (props, { emit }) { + setup(props, { emit }) { const router = useRouter() const gotoActivity = () => { emit('close') @@ -32,7 +32,7 @@ export default { } const close = () => emit('close') return { gotoActivity, close } - } + }, } diff --git a/frontend_nuxt/components/ArticleCategory.vue b/frontend_nuxt/components/ArticleCategory.vue index 859f4a475..b994b2ea6 100644 --- a/frontend_nuxt/components/ArticleCategory.vue +++ b/frontend_nuxt/components/ArticleCategory.vue @@ -18,7 +18,7 @@ import { useRouter } from 'vue-router' export default { name: 'ArticleCategory', props: { - category: { type: Object, default: null } + category: { type: Object, default: null }, }, setup(props) { const router = useRouter() @@ -30,7 +30,7 @@ export default { }) } return { gotoCategory } - } + }, } diff --git a/frontend_nuxt/components/ArticleTags.vue b/frontend_nuxt/components/ArticleTags.vue index ed015dcf1..f43572403 100644 --- a/frontend_nuxt/components/ArticleTags.vue +++ b/frontend_nuxt/components/ArticleTags.vue @@ -23,30 +23,28 @@ import { useRouter } from 'vue-router' export default { name: 'ArticleTags', props: { - tags: { type: Array, default: () => [] } + tags: { type: Array, default: () => [] }, }, setup() { const router = useRouter() - const gotoTag = tag => { + const gotoTag = (tag) => { const value = encodeURIComponent(tag.id ?? tag.name) router.push({ path: '/', query: { tags: value } }).then(() => { window.location.reload() }) } return { gotoTag } - } + }, } - - diff --git a/frontend_nuxt/components/AvatarCropper.vue b/frontend_nuxt/components/AvatarCropper.vue index 2cb0a1d62..2cf260fd7 100644 --- a/frontend_nuxt/components/AvatarCropper.vue +++ b/frontend_nuxt/components/AvatarCropper.vue @@ -21,12 +21,12 @@ export default { props: { src: { type: String, - required: true + required: true, }, show: { type: Boolean, - default: false - } + default: false, + }, }, emits: ['close', 'crop'], data() { @@ -39,7 +39,7 @@ export default { } else { this.destroy() } - } + }, }, mounted() { if (this.show) { @@ -53,7 +53,7 @@ export default { aspectRatio: 1, viewMode: 1, autoCropArea: 1, - responsive: true + responsive: true, }) }, destroy() { @@ -64,15 +64,15 @@ export default { }, onConfirm() { if (!this.cropper) return - this.cropper.getCroppedCanvas({ width: 256, height: 256 }).toBlob(blob => { + this.cropper.getCroppedCanvas({ width: 256, height: 256 }).toBlob((blob) => { const file = new File([blob], 'avatar.png', { type: 'image/png' }) const url = URL.createObjectURL(blob) this.$emit('crop', { file, url }) this.$emit('close') this.destroy() }) - } - } + }, + }, } @@ -84,7 +84,7 @@ export default { right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.8); - opacity: 1.0; + opacity: 1; display: flex; align-items: center; justify-content: center; @@ -139,4 +139,3 @@ export default { } } - diff --git a/frontend_nuxt/components/BaseInput.vue b/frontend_nuxt/components/BaseInput.vue index c596c86b6..211e19ec8 100644 --- a/frontend_nuxt/components/BaseInput.vue +++ b/frontend_nuxt/components/BaseInput.vue @@ -23,7 +23,6 @@
- @@ -75,7 +74,7 @@ export default { outline: none; width: 100%; font-size: 14px; - resize: none; + resize: none; background-color: transparent; color: var(--text-color); } diff --git a/frontend_nuxt/components/BasePlaceholder.vue b/frontend_nuxt/components/BasePlaceholder.vue index fed94821d..166663a10 100644 --- a/frontend_nuxt/components/BasePlaceholder.vue +++ b/frontend_nuxt/components/BasePlaceholder.vue @@ -12,8 +12,8 @@ export default { name: 'BasePlaceholder', props: { text: { type: String, default: '' }, - icon: { type: String, default: 'fas fa-inbox' } - } + icon: { type: String, default: 'fas fa-inbox' }, + }, } diff --git a/frontend_nuxt/components/BasePopup.vue b/frontend_nuxt/components/BasePopup.vue index 2c8dfee46..a4ed47b68 100644 --- a/frontend_nuxt/components/BasePopup.vue +++ b/frontend_nuxt/components/BasePopup.vue @@ -12,14 +12,14 @@ export default { name: 'BasePopup', props: { visible: { type: Boolean, default: false }, - closeOnOverlay: { type: Boolean, default: true } + closeOnOverlay: { type: Boolean, default: true }, }, emits: ['close'], methods: { - onOverlayClick () { + onOverlayClick() { if (this.closeOnOverlay) this.$emit('close') - } - } + }, + }, } diff --git a/frontend_nuxt/components/BaseTimeline.vue b/frontend_nuxt/components/BaseTimeline.vue index af39b4c6b..41d6064a2 100644 --- a/frontend_nuxt/components/BaseTimeline.vue +++ b/frontend_nuxt/components/BaseTimeline.vue @@ -21,8 +21,8 @@ export default { name: 'BaseTimeline', props: { - items: { type: Array, default: () => [] } - } + items: { type: Array, default: () => [] }, + }, } @@ -92,12 +92,10 @@ export default { } @media (max-width: 768px) { - .timeline-icon { margin-right: 2px; width: 30px; height: 30px; } } - diff --git a/frontend_nuxt/components/CallbackPage.vue b/frontend_nuxt/components/CallbackPage.vue index c06e3f5e4..b8bbd2b68 100644 --- a/frontend_nuxt/components/CallbackPage.vue +++ b/frontend_nuxt/components/CallbackPage.vue @@ -7,7 +7,7 @@ diff --git a/frontend_nuxt/components/CategorySelect.vue b/frontend_nuxt/components/CategorySelect.vue index d2e0b0524..377c21aa9 100644 --- a/frontend_nuxt/components/CategorySelect.vue +++ b/frontend_nuxt/components/CategorySelect.vue @@ -1,10 +1,20 @@