diff --git a/README.md b/README.md index b3619d90..6f6d26e6 100644 --- a/README.md +++ b/README.md @@ -26,16 +26,13 @@ ### 稳定版本下载 - Windows - - 安装包: `whu-library-seat-setup-.exe` - - 链接: [v1.2.1](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.2.1/whu-library-seat-setup-1.2.1.exe) + - 链接: [v1.3.0](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.3.0/whu-library-seat-setup-1.3.0.exe) - Mac OS - - 安装包: `whu-library-seat-.dmg` - - 链接: [v1.2.1](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.2.1/whu-library-seat-1.2.1.dmg) + - 链接: [v1.3.0](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.3.0/whu-library-seat-1.3.0.dmg) - Linux - - 安装包: `whu-library-seat--x86_64.AppImage` - - 链接: [v1.2.1](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.2.1/whu-library-seat-1.2.1-x86_64.AppImage) + - 链接: [v1.3.0](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.3.0/whu-library-seat-1.3.0-x86_64.AppImage) ### 安装软件 diff --git a/docs/specification/README.md b/docs/specification/README.md index f1941c0e..cc5dfcc8 100644 --- a/docs/specification/README.md +++ b/docs/specification/README.md @@ -9,16 +9,13 @@ #### 稳定版本下载 - Windows - - 安装包: `whu-library-seat-setup-.exe` - - 链接: [v1.2.1](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.2.1/whu-library-seat-setup-1.2.1.exe) + - 链接: [v1.3.0](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.3.0/whu-library-seat-setup-1.3.0.exe) - Mac OS - - 安装包: `whu-library-seat-.dmg` - - 链接: [v1.2.1](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.2.1/whu-library-seat-1.2.1.dmg) + - 链接: [v1.3.0](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.3.0/whu-library-seat-1.3.0.dmg) - Linux - - 安装包: `whu-library-seat--x86_64.AppImage` - - 链接: [v1.2.1](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.2.1/whu-library-seat-1.2.1-x86_64.AppImage) + - 链接: [v1.3.0](https://github.com/CS-Tao/whu-library-seat/releases/download/v1.3.0/whu-library-seat-1.3.0-x86_64.AppImage) ### 安装软件 diff --git a/package.json b/package.json index bdc3129c..81f04752 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "whu-library-seat", - "version": "1.2.1", + "version": "1.3.0", "author": "CS-Tao ", "description": "武汉大学图书馆抢座软件", "license": null, diff --git a/src/renderer/api/gitcontents.api.js b/src/renderer/api/gitcontents.api.js index e335d9c8..a64468a7 100644 --- a/src/renderer/api/gitcontents.api.js +++ b/src/renderer/api/gitcontents.api.js @@ -35,7 +35,7 @@ export default { validateUser: () => { return service({ url: urls.gitcontents.validateUser.url(), - method: 'get', + method: urls.gitcontents.validateUser.method, params: { time: new Date() } diff --git a/src/renderer/api/library.api.js b/src/renderer/api/library.api.js index 89304151..4634f48b 100644 --- a/src/renderer/api/library.api.js +++ b/src/renderer/api/library.api.js @@ -6,7 +6,7 @@ export default { Login: (account, passwd) => { return request({ url: urls.library.Login.url(), - method: 'get', + method: urls.library.Login.method, params: { username: account, password: passwd @@ -17,7 +17,7 @@ export default { FreeFilters: (token) => { return request({ url: urls.library.FreeFilters.url(), - method: 'get', + method: urls.library.FreeFilters.method, headers: { token } @@ -27,7 +27,7 @@ export default { RoomStats: (libraryId, token) => { return request({ url: urls.library.RoomStats.url(libraryId), - method: 'get', + method: urls.library.RoomStats.method, headers: { token } @@ -37,7 +37,7 @@ export default { ValidateToken: (token) => { return request({ url: urls.library.ValidateToken.url(), - method: 'get', + method: urls.library.ValidateToken.method, headers: { token } @@ -47,7 +47,7 @@ export default { LayoutByDate: (roomId, dateStr, token) => { return request({ url: urls.library.LayoutByDate.url(roomId, dateStr), - method: 'get', + method: urls.library.LayoutByDate.method, headers: { token } @@ -59,7 +59,7 @@ export default { SearchSeat: (buildingId, roomId, dateStr, startTime, endTime, token) => { return request({ url: urls.library.SearchSeat.url(dateStr, startTime, endTime), - method: 'post', + method: urls.library.SearchSeat.method, headers: { token }, @@ -71,7 +71,7 @@ export default { Book: (t, t2, startTime, endTime, seat, date, token) => { return request({ url: urls.library.Book.url(), - method: 'post', + method: urls.library.Book.method, headers: { token }, @@ -82,7 +82,7 @@ export default { Cancel: (id, token) => { return request({ url: urls.library.Cancel.url(id), - method: 'get', + method: urls.library.Cancel.method, headers: { token } @@ -92,7 +92,7 @@ export default { User: (token) => { return request({ url: urls.library.User.url(), - method: 'get', + method: urls.library.User.method, headers: { token } @@ -102,7 +102,17 @@ export default { History: (page, count, token) => { return request({ url: urls.library.History.url(page, count), - method: 'get', + method: urls.library.History.method, + headers: { + token + } + }) + }, + // 终止使用 + Stop: (token) => { + return request({ + url: urls.library.Stop.url(), + method: urls.library.Stop.method, headers: { token } diff --git a/src/renderer/api/mock/index.js b/src/renderer/api/mock/index.js index 5ee80a07..42f17e6c 100644 --- a/src/renderer/api/mock/index.js +++ b/src/renderer/api/mock/index.js @@ -1,37 +1,47 @@ import Mock from 'mockjs' import gitcontentsApi from './gitcontents.api' +import usageApi from './usage.api' import libraryApi from './library.api' import urls from '../urls' // 用户验证 -Mock.mock(urls.gitcontents.validateUser.regular, 'get', gitcontentsApi.validateUser) +Mock.mock(urls.gitcontents.validateUser.regular, gitcontentsApi.validateUser.method, gitcontentsApi.validateUser) + +// 登录状态 +Mock.mock(urls.usage.loginState.regular, usageApi.loginState.method, usageApi.loginState) + +// 抢座状态 +Mock.mock(urls.gitcontents.grabState.regular, usageApi.grabState.method, usageApi.grabState) // 登录 -Mock.mock(urls.library.Login.regular, 'get', libraryApi.Login) +Mock.mock(urls.library.Login.regular, libraryApi.Login.method, libraryApi.Login) // 得到可以使用的房间信息 -Mock.mock(urls.library.FreeFilters.regular, 'get', libraryApi.FreeFilters) +Mock.mock(urls.library.FreeFilters.regular, libraryApi.FreeFilters.method, libraryApi.FreeFilters) // 得到房间详细信息 -Mock.mock(urls.library.RoomStats.regular, 'get', libraryApi.RoomStats) +Mock.mock(urls.library.RoomStats.regular, libraryApi.RoomStats.method, libraryApi.RoomStats) // 验证 token 是否可用 -Mock.mock(urls.library.ValidateToken.regular, 'get', libraryApi.ValidateToken) +Mock.mock(urls.library.ValidateToken.regular, libraryApi.ValidateToken.method, libraryApi.ValidateToken) // 得到位置详细信息 -Mock.mock(urls.library.LayoutByDate.regular, 'get', libraryApi.LayoutByDate) +Mock.mock(urls.library.LayoutByDate.regular, libraryApi.LayoutByDate.method, libraryApi.LayoutByDate) // 按时间搜索位置 -Mock.mock(urls.library.SearchSeat.regular, 'post', libraryApi.SearchSeat) +Mock.mock(urls.library.SearchSeat.regular, libraryApi.SearchSeat.method, libraryApi.SearchSeat) // 预约位置 -Mock.mock(urls.library.Book.regular, 'post', libraryApi.Book) +Mock.mock(urls.library.Book.regular, libraryApi.Book.method, libraryApi.Book) // 取消预约 -Mock.mock(urls.library.Cancel.regular, 'get', libraryApi.Cancel) +Mock.mock(urls.library.Cancel.regular, libraryApi.Cancel.method, libraryApi.Cancel) // 得到用户信息 -Mock.mock(urls.library.User.regular, 'get', libraryApi.User) +Mock.mock(urls.library.User.regular, libraryApi.User.method, libraryApi.User) // 得到预约历史 -Mock.mock(urls.library.History.regular, 'get', libraryApi.History) +Mock.mock(urls.library.History.regular, libraryApi.History.method, libraryApi.History) + +// 终止使用 +Mock.mock(urls.library.Stop.regular, libraryApi.Stop.method, libraryApi.Stop) diff --git a/src/renderer/api/mock/library.api.js b/src/renderer/api/mock/library.api.js index 8668ef9a..f5a27de5 100644 --- a/src/renderer/api/mock/library.api.js +++ b/src/renderer/api/mock/library.api.js @@ -602,5 +602,9 @@ export default { '23022': {'type': 'empty'}}}, 'message': '', 'code': '0'} + }, + Stop: config => { + console.log('Mock: ' + config.url) + return {'status': 'success', 'data': null, 'message': '已终止使用当前预约', 'code': '0'} } } diff --git a/src/renderer/api/mock/usage.api.js b/src/renderer/api/mock/usage.api.js new file mode 100644 index 00000000..bca3726d --- /dev/null +++ b/src/renderer/api/mock/usage.api.js @@ -0,0 +1,20 @@ +export default { + loginState: config => { + console.log('Mock: ' + config.url) + return { + 'status': 'success', + 'code': '0', + 'message': '', + 'data': null + } + }, + grabState: config => { + console.log('Mock: ' + config.url) + return { + 'status': 'success', + 'code': '0', + 'message': '', + 'data': null + } + } +} diff --git a/src/renderer/api/urls/index.js b/src/renderer/api/urls/index.js index b6904900..79357aab 100644 --- a/src/renderer/api/urls/index.js +++ b/src/renderer/api/urls/index.js @@ -5,7 +5,26 @@ const urls = { url () { return '/user-validation/validation.json' }, - regular: /\/user-validation\/validation.json/ + regular: /\/user-validation\/validation.json/, + method: 'get' + } + }, + usage: { + // 登录状态 + loginState: { + url () { + return '/loginState' + }, + regular: /\/user-loginState/, + method: 'post' + }, + // 抢座状态 + grabState: { + url () { + return '/grabState' + }, + regular: /\/grabState/, + method: 'post' } }, library: { @@ -14,70 +33,88 @@ const urls = { url () { return '/rest/auth' }, - regular: /\/rest\/auth/ + regular: /\/rest\/auth/, + method: 'get' }, // 得到可以使用的房间信息 FreeFilters: { url () { return '/rest/v2/free/filters' }, - regular: /\/rest\/v2\/free\/filters/ + regular: /\/rest\/v2\/free\/filters/, + method: 'get' }, // 得到房间详细信息 RoomStats: { url (libraryId) { return `/rest/v2/room/stats2/${libraryId}` }, - regular: /\/rest\/v2\/room\/stats2\// + regular: /\/rest\/v2\/room\/stats2\//, + method: 'get' }, ValidateToken: { // 验证 token 是否可用 url () { return '/rest/v2/violations' }, - regular: /\/rest\/v2\/violations/ + regular: /\/rest\/v2\/violations/, + method: 'get' }, // 得到位置详细信息 LayoutByDate: { url (roomId, dateStr) { return `/rest/v2/room/layoutByDate/${roomId}/${dateStr}` }, - regular: /\/rest\/v2\/room\/layoutByDate\// + regular: /\/rest\/v2\/room\/layoutByDate\//, + method: 'get' }, // 按时间搜索位置 SearchSeat: { url (dateStr, startTime, endTime) { return `/rest/v2/searchSeats/${dateStr}/${startTime}/${endTime}` }, - regular: /\/rest\/v2\/searchSeats\// + regular: /\/rest\/v2\/searchSeats\//, + method: 'post' }, // 预约位置 Book: { url () { return '/rest/v2/freeBook' }, - regular: /\/rest\/v2\/freeBook/ + regular: /\/rest\/v2\/freeBook/, + method: 'post' }, // 取消预约 Cancel: { url (id) { return `/rest/v2/cancel/${id}` }, - regular: /\/rest\/v2\/cancel\// + regular: /\/rest\/v2\/cancel\//, + method: 'get' }, // 得到用户信息 User: { url () { return '/rest/v2/user' }, - regular: /\/rest\/v2\/user/ + regular: /\/rest\/v2\/user/, + method: 'get' }, // 得到预约历史 History: { url (page, count) { return `/rest/v2/history/${page}/${count}` }, - regular: /\/rest\/v2\/history\// + regular: /\/rest\/v2\/history\//, + method: 'get' + }, + // 终止使用 + Stop: { + url () { + return '/rest/v2/stop' + }, + regular: /\/rest\/v2\/stop/, + method: 'get' } } } diff --git a/src/renderer/api/usage.api.js b/src/renderer/api/usage.api.js new file mode 100644 index 00000000..56546464 --- /dev/null +++ b/src/renderer/api/usage.api.js @@ -0,0 +1,42 @@ +import axios from 'axios' +import { remote } from 'electron' +import urls from './urls' + +var service = axios.create({ + baseURL: 'https://seat-records.cs-tao.cc', + timeout: 5000, + withCredentials: true +}) + +const appVersion = remote.app.getVersion() + +export default { + // 登录状态 + loginState: (account, state, code) => { + return service({ + url: urls.usage.loginState.url(), + method: urls.usage.loginState.method, + data: { + account, + state, + code, + version: appVersion, + time: new Date() + } + }) + }, + // 抢座状态 + grabState: (account, state, code) => { + return service({ + url: urls.usage.grabState.url(), + method: urls.usage.grabState.method, + data: { + account, + state, + code, + version: appVersion, + time: new Date() + } + }) + } +} diff --git a/src/renderer/components/Body/index.vue b/src/renderer/components/Body/index.vue index 43cced72..9b7aaadc 100644 --- a/src/renderer/components/Body/index.vue +++ b/src/renderer/components/Body/index.vue @@ -62,6 +62,7 @@ import userForm from './User' import historyForm from './History' import timerForm from './Timer' import libraryRestApi from '@/api/library.api' +import usageApi from '@/api/usage.api' import { ipcRenderer } from 'electron' const emptyMessage = '数据加载失败' @@ -282,8 +283,57 @@ export default { } }).catch(() => {}) }, - reserveSeat (beginTime, endTime, seatNum, date, userToken) { - this.triedSeatIds.push(seatNum) + reserveSeat (beginTime, endTime, seatNum, date, userToken, cancelCurrent = false) { + if (cancelCurrent) { + // 查询预约历史 + libraryRestApi.History(1, 20, this.userToken).then((response) => { + if (response.data.status === 'success') { + var reservations = response.data.data.reservations + var reservation = reservations.filter((item) => { + return item.stat === 'RESERVE' || item.stat === 'CHECK_IN' || item.stat === 'AWAY' + }) + if (reservation && reservation.length > 0) { + if (reservation[0].stat === 'RESERVE') { + // 取消当前预约 + libraryRestApi.Cancel(reservation[0].id, this.userToken).then((response) => { + if (response.data.status === 'success') { + this.$message({ + type: 'success', + duration: '1000', + message: '取消已有预约' + }) + } + this.reserveSeat(beginTime, endTime, seatNum, date, userToken) + }).catch(() => { + this.reserveSeat(beginTime, endTime, seatNum, date, userToken) + }) + } else { + // 终止当前使用 + libraryRestApi.Cancel(reservation[0].id, this.userToken).then((response) => { + if (response.data.status === 'success') { + this.$message({ + type: 'success', + duration: '1000', + message: response.data.message ? response.data.message : emptyMessage + }) + } + this.reserveSeat(beginTime, endTime, seatNum, date, userToken) + }).catch(() => { + this.reserveSeat(beginTime, endTime, seatNum, date, userToken) + }) + } + } else { + this.reserveSeat(beginTime, endTime, seatNum, date, userToken) + } + } else { + this.reserveSeat(beginTime, endTime, seatNum, date, userToken) + } + }).catch(() => { + this.reserveSeat(beginTime, endTime, seatNum, date, userToken) + }) + return + } + if (!this.triedSeatIds.includes(seatNum)) { this.triedSeatIds.push(seatNum) } libraryRestApi.Book(1, 2, beginTime, endTime, seatNum, date, userToken).then((response) => { if (response.data.status === 'success') { this.$store.dispatch('updateTimer', 'success') @@ -299,14 +349,21 @@ export default { duration: 0 }) this.windowsNotification('预约成功', '请打开软件查看') + usageApi.grabState(this.userAccount, true, 6).then(() => {}).catch(() => {}) } else { if (response.data.code === 1 || response.data.code === '1') { // 预约失败,请尽快选择其他时段或座位 // 系统可预约时间为 22:45 ~ 23:50 - if (response.data.message === '预约失败,请尽快选择其他时段或座位' || response.data.message === '参数错误') { + if (response.data.message === '预约失败,请尽快选择其他时段或座位' || response.data.message === '参数错误' || response.data.message === '已有1个有效预约,请在使用结束后再次进行选择') { // 位置不可用,如果未达抢座上限则继续抢 this.grabCount += 1 - var newSeatId = this.getNewSeatNum() + var cancelCurrentBool = response.data.message === '已有1个有效预约,请在使用结束后再次进行选择' + var newSeatId = -1 + if (cancelCurrentBool) { + newSeatId = seatNum + } else { + newSeatId = this.getNewSeatNum() + } if (this.grabCount >= maxGrabCount) { this.$store.dispatch('updateTimer', 'fail') this.$message({ @@ -316,6 +373,7 @@ export default { message: `抢座失败:达到抢座尝试上限(${maxGrabCount}),结束抢座` }) this.windowsNotification('抢座失败', `达到抢座尝试上限(${maxGrabCount}),结束抢座`) + usageApi.grabState(this.userAccount, false, 7).then(() => {}).catch(() => {}) } else if (newSeatId === -1) { this.$store.dispatch('updateTimer', 'fail') this.$message({ @@ -325,6 +383,7 @@ export default { message: '抢座失败:该房间在指定的时间段内没有空闲位置' }) this.windowsNotification('抢座失败', '该房间在指定的时间段内没有空闲位置') + usageApi.grabState(this.userAccount, false, 8).then(() => {}).catch(() => {}) } else if (!this.stopGrab) { this.$store.dispatch('updateTimer', 'working') // 打印信息 @@ -346,7 +405,7 @@ export default { if (this.grabCount === arbitraryGrabCount) { this.searchSeatsByTime(this.form.library, this.form.room, date, beginTime, endTime, userToken) } - this.reserveSeat(beginTime, endTime, newSeatId, date, userToken) + this.reserveSeat(beginTime, endTime, newSeatId, date, userToken, cancelCurrentBool) } else {} } else { this.$store.dispatch('updateTimer', 'fail') @@ -357,6 +416,7 @@ export default { message: response.data.message ? response.data.message : emptyMessage }) this.windowsNotification('抢座失败', response.data.message ? response.data.message : emptyMessage) + usageApi.grabState(this.userAccount, false, 9).then(() => {}).catch(() => {}) } } else if (response.data.code === 12 && response.data.code === '12') { // 登录失败: 用户名或密码不正确 @@ -368,6 +428,7 @@ export default { message: response.data.message ? response.data.message : emptyMessage }) this.windowsNotification('抢座失败', response.data.message ? response.data.message : emptyMessage) + usageApi.grabState(this.userAccount, false, 10).then(() => {}).catch(() => {}) } else { // 其他 this.$store.dispatch('updateTimer', 'fail') @@ -378,6 +439,7 @@ export default { message: response.data.message ? response.data.message : emptyMessage }) this.windowsNotification('抢座失败', response.data.message ? response.data.message : emptyMessage) + usageApi.grabState(this.userAccount, false, 11).then(() => {}).catch(() => {}) } } }).catch(() => {}) diff --git a/src/renderer/components/Header/index.vue b/src/renderer/components/Header/index.vue index 794b0a37..8b19798e 100644 --- a/src/renderer/components/Header/index.vue +++ b/src/renderer/components/Header/index.vue @@ -60,7 +60,14 @@
- + + {{btnText}} +
@@ -72,6 +79,7 @@ import { mapGetters } from 'vuex' import settingsForm from './Settings' import gitcontentsApi from '@/api/gitcontents.api' +import usageApi from '@/api/usage.api' import libraryRestApi from '@/api/library.api' const emptyMessage = '数据加载失败' @@ -85,7 +93,8 @@ export default { }, accountLocked: false, passwdLocked: false, - settingsVisible: false + settingsVisible: false, + working: false } }, components: { @@ -98,6 +107,9 @@ export default { 'hasToken', 'userToken' ]), + btnText () { + return this.working ? '白名单验证' : '登录' + }, isLover () { return this.userInfo.account === 2017302590175 } @@ -168,6 +180,7 @@ export default { this.showWarning('密码不能为空') return false } + this.working = true gitcontentsApi.validateUser().then((response) => { if (response.data.status === 'success') { var users = response.data.data.users @@ -184,10 +197,12 @@ export default { if (userItem === null) { this.$store.dispatch('setToken', null) this.showError('对不起,您未在用户白名单中,不能使用本软件,您可以在 [菜单] -> [关于] -> [申请权限] 中了解如何获取权限') + usageApi.loginState(this.userInfo.account, false, 0).then(() => {}).catch(() => {}) return false } else if (!userItem.status) { this.$store.dispatch('setToken', null) this.showError('对不起,您未在用户白名单中,不能使用本软件,您可以在 [菜单] -> [关于] -> [申请权限] 中了解如何获取权限') + usageApi.loginState(this.userInfo.account, false, 1).then(() => {}).catch(() => {}) return false } for (let index = 0; index < groups.length; index++) { @@ -200,10 +215,12 @@ export default { if (groupItem === null) { this.$store.dispatch('setToken', null) this.showError('对不起,您未在用户白名单中,不能使用本软件,您可以在 [菜单] -> [关于] -> [申请权限] 中了解如何获取权限') + usageApi.loginState(this.userInfo.account, false, 2).then(() => {}).catch(() => {}) return false } else if (!groupItem.status) { this.$store.dispatch('setToken', null) this.showError('对不起,您未在用户白名单中,不能使用本软件,您可以在 [菜单] -> [关于] -> [申请权限] 中了解如何获取权限') + usageApi.loginState(this.userInfo.account, false, 3).then(() => {}).catch(() => {}) return false } this.login() @@ -229,9 +246,11 @@ export default { this.$store.dispatch('setAccount', this.userInfo.account) this.$store.dispatch('setPasswd', this.userInfo.passwd) + this.working = false libraryRestApi.Login(this.userInfo.account, this.userInfo.passwd).then((response) => { if (response.data.status === 'success') { this.loadRooms(response.data.data.token) + usageApi.loginState(this.userInfo.account, true, 4).then(() => {}).catch(() => {}) } else { this.$store.dispatch('setToken', null) this.$message({ @@ -240,6 +259,7 @@ export default { showClose: true, message: response.data.message ? response.data.message : emptyMessage }) + usageApi.loginState(this.userInfo.account, false, 5).then(() => {}).catch(() => {}) } }).catch(() => {}) }, @@ -351,6 +371,13 @@ export default { background: $primary-button-background-click!important; } } + .button-disabled { + margin: 20px 0 60px 0; + width: 90px; + color: $text-color; + background: $disabled-button-background-blur!important; + border-color: $disabled-button-border!important; + } } .logo { fill: $text-color-lowlight;