feat(client): 实现账号设备试用期管理功能
- 新增设备试用期过期时间字段及管理接口 - 实现试用期状态检查与过期提醒逻辑 - 支持账号类型区分试用与付费用户 - 添加设备注册时自动设置3天试用期- 实现VIP状态刷新与过期类型判断 -优化账号列表查询支持按客户端用户名过滤 - 更新客户端设备管理支持试用期控制- 完善登录流程支持试用期状态提示 -修复设备离线通知缺少用户名参数问题 - 调整账号默认设置清除逻辑关联客户端用户名
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {onMounted, ref, computed, defineAsyncComponent, type Component, onUnmounted} from 'vue'
|
import {onMounted, ref, computed, defineAsyncComponent, type Component, onUnmounted, provide} from 'vue'
|
||||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||||
import 'element-plus/dist/index.css'
|
import 'element-plus/dist/index.css'
|
||||||
@@ -8,6 +8,7 @@ import {deviceApi, type DeviceItem, type DeviceQuota} from './api/device'
|
|||||||
import {getOrCreateDeviceId} from './utils/deviceId'
|
import {getOrCreateDeviceId} from './utils/deviceId'
|
||||||
import {getToken, setToken, removeToken, getUsernameFromToken, getClientIdFromToken} from './utils/token'
|
import {getToken, setToken, removeToken, getUsernameFromToken, getClientIdFromToken} from './utils/token'
|
||||||
import {CONFIG} from './api/http'
|
import {CONFIG} from './api/http'
|
||||||
|
import {getSettings} from './utils/settings'
|
||||||
const LoginDialog = defineAsyncComponent(() => import('./components/auth/LoginDialog.vue'))
|
const LoginDialog = defineAsyncComponent(() => import('./components/auth/LoginDialog.vue'))
|
||||||
const RegisterDialog = defineAsyncComponent(() => import('./components/auth/RegisterDialog.vue'))
|
const RegisterDialog = defineAsyncComponent(() => import('./components/auth/RegisterDialog.vue'))
|
||||||
const NavigationBar = defineAsyncComponent(() => import('./components/layout/NavigationBar.vue'))
|
const NavigationBar = defineAsyncComponent(() => import('./components/layout/NavigationBar.vue'))
|
||||||
@@ -16,6 +17,7 @@ const AmazonDashboard = defineAsyncComponent(() => import('./components/amazon/A
|
|||||||
const ZebraDashboard = defineAsyncComponent(() => import('./components/zebra/ZebraDashboard.vue'))
|
const ZebraDashboard = defineAsyncComponent(() => import('./components/zebra/ZebraDashboard.vue'))
|
||||||
const UpdateDialog = defineAsyncComponent(() => import('./components/common/UpdateDialog.vue'))
|
const UpdateDialog = defineAsyncComponent(() => import('./components/common/UpdateDialog.vue'))
|
||||||
const SettingsDialog = defineAsyncComponent(() => import('./components/common/SettingsDialog.vue'))
|
const SettingsDialog = defineAsyncComponent(() => import('./components/common/SettingsDialog.vue'))
|
||||||
|
const TrialExpiredDialog = defineAsyncComponent(() => import('./components/common/TrialExpiredDialog.vue'))
|
||||||
|
|
||||||
const dashboardsMap: Record<string, Component> = {
|
const dashboardsMap: Record<string, Component> = {
|
||||||
rakuten: RakutenDashboard,
|
rakuten: RakutenDashboard,
|
||||||
@@ -51,23 +53,39 @@ const userPermissions = ref<string>('')
|
|||||||
|
|
||||||
// VIP状态
|
// VIP状态
|
||||||
const vipExpireTime = ref<Date | null>(null)
|
const vipExpireTime = ref<Date | null>(null)
|
||||||
|
const deviceTrialExpired = ref(false)
|
||||||
|
const accountType = ref<string>('trial')
|
||||||
const vipStatus = computed(() => {
|
const vipStatus = computed(() => {
|
||||||
if (!vipExpireTime.value) return { isVip: false, daysLeft: 0, status: 'expired' }
|
if (!vipExpireTime.value) return { isVip: false, daysLeft: 0, status: 'expired' }
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const expire = new Date(vipExpireTime.value)
|
const expire = new Date(vipExpireTime.value)
|
||||||
const daysLeft = Math.ceil((expire.getTime() - now.getTime()) / (1000 * 60 * 60 * 24))
|
const daysLeft = Math.ceil((expire.getTime() - now.getTime()) / (1000 * 60 * 60 * 24))
|
||||||
|
|
||||||
if (daysLeft <= 0) return { isVip: false, daysLeft: 0, status: 'expired' }
|
if (daysLeft <= 0) return { isVip: false, daysLeft: 0, status: 'expired' }
|
||||||
if (daysLeft <= 7) return { isVip: true, daysLeft, status: 'warning' }
|
if (daysLeft <= 7) return { isVip: true, daysLeft, status: 'warning' }
|
||||||
if (daysLeft <= 30) return { isVip: true, daysLeft, status: 'normal' }
|
if (daysLeft <= 30) return { isVip: true, daysLeft, status: 'normal' }
|
||||||
return { isVip: true, daysLeft, status: 'active' }
|
return { isVip: true, daysLeft, status: 'active' }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 功能可用性(账号VIP + 设备试用期)
|
||||||
|
const canUseFunctions = computed(() => {
|
||||||
|
// 付费账号不受设备限制
|
||||||
|
if (accountType.value === 'paid') return vipStatus.value.isVip
|
||||||
|
// 试用账号需要账号VIP有效 且 设备未过期
|
||||||
|
return vipStatus.value.isVip && !deviceTrialExpired.value
|
||||||
|
})
|
||||||
|
|
||||||
// 更新对话框状态
|
// 更新对话框状态
|
||||||
const showUpdateDialog = ref(false)
|
const showUpdateDialog = ref(false)
|
||||||
|
const updateDialogRef = ref()
|
||||||
|
|
||||||
// 设置对话框状态
|
// 设置对话框状态
|
||||||
const showSettingsDialog = ref(false)
|
const showSettingsDialog = ref(false)
|
||||||
|
|
||||||
|
// 试用期过期对话框
|
||||||
|
const showTrialExpiredDialog = ref(false)
|
||||||
|
const trialExpiredType = ref<'device' | 'account' | 'both'>('device')
|
||||||
|
|
||||||
// 菜单配置 - 复刻ERP客户端格式
|
// 菜单配置 - 复刻ERP客户端格式
|
||||||
const menuConfig = [
|
const menuConfig = [
|
||||||
{key: 'rakuten', name: 'Rakuten', index: 'rakuten', icon: 'R'},
|
{key: 'rakuten', name: 'Rakuten', index: 'rakuten', icon: 'R'},
|
||||||
@@ -147,7 +165,7 @@ function handleMenuSelect(key: string) {
|
|||||||
addToHistory(key)
|
addToHistory(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleLoginSuccess(data: { token: string; permissions?: string; expireTime?: string }) {
|
async function handleLoginSuccess(data: { token: string; permissions?: string; expireTime?: string; accountType?: string; deviceTrialExpired?: boolean }) {
|
||||||
try {
|
try {
|
||||||
setToken(data.token)
|
setToken(data.token)
|
||||||
isAuthenticated.value = true
|
isAuthenticated.value = true
|
||||||
@@ -157,6 +175,8 @@ async function handleLoginSuccess(data: { token: string; permissions?: string; e
|
|||||||
currentUsername.value = getUsernameFromToken(data.token)
|
currentUsername.value = getUsernameFromToken(data.token)
|
||||||
userPermissions.value = data.permissions || ''
|
userPermissions.value = data.permissions || ''
|
||||||
vipExpireTime.value = data.expireTime ? new Date(data.expireTime) : null
|
vipExpireTime.value = data.expireTime ? new Date(data.expireTime) : null
|
||||||
|
accountType.value = data.accountType || 'trial'
|
||||||
|
deviceTrialExpired.value = data.deviceTrialExpired || false
|
||||||
|
|
||||||
const deviceId = await getOrCreateDeviceId()
|
const deviceId = await getOrCreateDeviceId()
|
||||||
await deviceApi.register({
|
await deviceApi.register({
|
||||||
@@ -165,6 +185,31 @@ async function handleLoginSuccess(data: { token: string; permissions?: string; e
|
|||||||
os: navigator.platform
|
os: navigator.platform
|
||||||
})
|
})
|
||||||
SSEManager.connect()
|
SSEManager.connect()
|
||||||
|
|
||||||
|
// 根据不同场景显示提示
|
||||||
|
const accountExpired = vipExpireTime.value && new Date() > vipExpireTime.value
|
||||||
|
const deviceExpired = deviceTrialExpired.value
|
||||||
|
const isPaid = accountType.value === 'paid'
|
||||||
|
|
||||||
|
if (isPaid) {
|
||||||
|
// 场景5: 付费用户
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
} else if (deviceExpired && accountExpired) {
|
||||||
|
// 场景4: 试用已到期,请订阅
|
||||||
|
trialExpiredType.value = 'both'
|
||||||
|
showTrialExpiredDialog.value = true
|
||||||
|
} else if (accountExpired) {
|
||||||
|
// 场景3: 账号试用已到期,请订阅
|
||||||
|
trialExpiredType.value = 'account'
|
||||||
|
showTrialExpiredDialog.value = true
|
||||||
|
} else if (deviceExpired) {
|
||||||
|
// 场景2: 设备试用已到期,请更换设备或订阅
|
||||||
|
trialExpiredType.value = 'device'
|
||||||
|
showTrialExpiredDialog.value = true
|
||||||
|
} else {
|
||||||
|
// 场景1: 允许使用
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
isAuthenticated.value = false
|
isAuthenticated.value = false
|
||||||
showAuthDialog.value = true
|
showAuthDialog.value = true
|
||||||
@@ -179,6 +224,8 @@ function clearLocalAuth() {
|
|||||||
currentUsername.value = ''
|
currentUsername.value = ''
|
||||||
userPermissions.value = ''
|
userPermissions.value = ''
|
||||||
vipExpireTime.value = null
|
vipExpireTime.value = null
|
||||||
|
deviceTrialExpired.value = false
|
||||||
|
accountType.value = 'trial'
|
||||||
showAuthDialog.value = true
|
showAuthDialog.value = true
|
||||||
showDeviceDialog.value = false
|
showDeviceDialog.value = false
|
||||||
SSEManager.disconnect()
|
SSEManager.disconnect()
|
||||||
@@ -187,7 +234,7 @@ function clearLocalAuth() {
|
|||||||
async function logout() {
|
async function logout() {
|
||||||
try {
|
try {
|
||||||
const deviceId = getClientIdFromToken()
|
const deviceId = getClientIdFromToken()
|
||||||
if (deviceId) await deviceApi.offline({ deviceId })
|
if (deviceId) await deviceApi.offline({ deviceId, username: currentUsername.value })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('离线通知失败:', error)
|
console.warn('离线通知失败:', error)
|
||||||
}
|
}
|
||||||
@@ -235,6 +282,8 @@ async function checkAuth() {
|
|||||||
isAuthenticated.value = true
|
isAuthenticated.value = true
|
||||||
currentUsername.value = getUsernameFromToken(token)
|
currentUsername.value = getUsernameFromToken(token)
|
||||||
userPermissions.value = res.data.permissions || ''
|
userPermissions.value = res.data.permissions || ''
|
||||||
|
deviceTrialExpired.value = res.data.deviceTrialExpired || false
|
||||||
|
accountType.value = res.data.accountType || 'trial'
|
||||||
|
|
||||||
if (res.data.expireTime) {
|
if (res.data.expireTime) {
|
||||||
vipExpireTime.value = new Date(res.data.expireTime)
|
vipExpireTime.value = new Date(res.data.expireTime)
|
||||||
@@ -249,6 +298,38 @@ async function checkAuth() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新VIP状态(采集前调用)
|
||||||
|
async function refreshVipStatus() {
|
||||||
|
try {
|
||||||
|
const token = getToken()
|
||||||
|
if (!token) return false
|
||||||
|
|
||||||
|
const res = await authApi.verifyToken(token)
|
||||||
|
deviceTrialExpired.value = res.data.deviceTrialExpired || false
|
||||||
|
accountType.value = res.data.accountType || 'trial'
|
||||||
|
if (res.data.expireTime) {
|
||||||
|
vipExpireTime.value = new Date(res.data.expireTime)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断过期类型
|
||||||
|
function checkExpiredType(): 'device' | 'account' | 'both' {
|
||||||
|
const accountExpired = vipExpireTime.value && new Date() > vipExpireTime.value
|
||||||
|
const deviceExpired = deviceTrialExpired.value
|
||||||
|
|
||||||
|
if (deviceExpired && accountExpired) return 'both'
|
||||||
|
if (accountExpired) return 'account'
|
||||||
|
if (deviceExpired) return 'device'
|
||||||
|
return 'account' // 默认
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提供给子组件使用
|
||||||
|
provide('refreshVipStatus', refreshVipStatus)
|
||||||
|
provide('checkExpiredType', checkExpiredType)
|
||||||
|
|
||||||
const SSEManager = {
|
const SSEManager = {
|
||||||
connection: null as EventSource | null,
|
connection: null as EventSource | null,
|
||||||
@@ -364,7 +445,7 @@ async function confirmRemoveDevice(row: DeviceItem) {
|
|||||||
type: 'warning'
|
type: 'warning'
|
||||||
})
|
})
|
||||||
|
|
||||||
await deviceApi.remove({deviceId: row.deviceId})
|
await deviceApi.remove({deviceId: row.deviceId, username: currentUsername.value})
|
||||||
devices.value = devices.value.filter(d => d.deviceId !== row.deviceId)
|
devices.value = devices.value.filter(d => d.deviceId !== row.deviceId)
|
||||||
deviceQuota.value.used = Math.max(0, deviceQuota.value.used - 1)
|
deviceQuota.value.used = Math.max(0, deviceQuota.value.used - 1)
|
||||||
|
|
||||||
@@ -382,8 +463,30 @@ async function confirmRemoveDevice(row: DeviceItem) {
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
showContent()
|
showContent()
|
||||||
await checkAuth()
|
await checkAuth()
|
||||||
|
|
||||||
|
// 检查是否有待安装的更新
|
||||||
|
await checkPendingUpdate()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
async function checkPendingUpdate() {
|
||||||
|
try {
|
||||||
|
const result = await (window as any).electronAPI.checkPendingUpdate()
|
||||||
|
if (result && result.hasPendingUpdate) {
|
||||||
|
// 有待安装的更新,直接弹出安装对话框
|
||||||
|
showUpdateDialog.value = true
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('检查待安装更新失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理自动更新配置变化
|
||||||
|
function handleAutoUpdateChanged(enabled: boolean) {
|
||||||
|
if (enabled && updateDialogRef.value) {
|
||||||
|
updateDialogRef.value.checkForUpdatesNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
SSEManager.disconnect()
|
SSEManager.disconnect()
|
||||||
})
|
})
|
||||||
@@ -461,7 +564,7 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<keep-alive v-if="activeDashboard">
|
<keep-alive v-if="activeDashboard">
|
||||||
<component :is="activeDashboard" :key="activeMenu" :is-vip="vipStatus.isVip"/>
|
<component :is="activeDashboard" :key="activeMenu" :is-vip="canUseFunctions"/>
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
<div v-if="showPlaceholder" class="placeholder">
|
<div v-if="showPlaceholder" class="placeholder">
|
||||||
<div class="placeholder-card">
|
<div class="placeholder-card">
|
||||||
@@ -483,10 +586,13 @@ onUnmounted(() => {
|
|||||||
@back-to-login="backToLogin"/>
|
@back-to-login="backToLogin"/>
|
||||||
|
|
||||||
<!-- 更新对话框 -->
|
<!-- 更新对话框 -->
|
||||||
<UpdateDialog v-model="showUpdateDialog" />
|
<UpdateDialog ref="updateDialogRef" v-model="showUpdateDialog" />
|
||||||
|
|
||||||
<!-- 设置对话框 -->
|
<!-- 设置对话框 -->
|
||||||
<SettingsDialog v-model="showSettingsDialog" />
|
<SettingsDialog v-model="showSettingsDialog" @auto-update-changed="handleAutoUpdateChanged" />
|
||||||
|
|
||||||
|
<!-- 试用期过期弹框 -->
|
||||||
|
<TrialExpiredDialog v-model="showTrialExpiredDialog" :expired-type="trialExpiredType" />
|
||||||
|
|
||||||
<!-- 设备管理弹框 -->
|
<!-- 设备管理弹框 -->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted, defineAsyncComponent, inject } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { amazonApi } from '../../api/amazon'
|
import { amazonApi } from '../../api/amazon'
|
||||||
import { handlePlatformFileExport } from '../../utils/settings'
|
import { handlePlatformFileExport } from '../../utils/settings'
|
||||||
|
|
||||||
|
const TrialExpiredDialog = defineAsyncComponent(() => import('../common/TrialExpiredDialog.vue'))
|
||||||
|
|
||||||
|
const refreshVipStatus = inject<() => Promise<boolean>>('refreshVipStatus')
|
||||||
|
|
||||||
// 接收VIP状态
|
// 接收VIP状态
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
isVip: boolean
|
isVip: boolean
|
||||||
@@ -24,6 +28,12 @@ const pageSize = ref(15)
|
|||||||
const amazonUpload = ref<HTMLInputElement | null>(null)
|
const amazonUpload = ref<HTMLInputElement | null>(null)
|
||||||
const dragActive = ref(false)
|
const dragActive = ref(false)
|
||||||
|
|
||||||
|
// 试用期过期弹框
|
||||||
|
const showTrialExpiredDialog = ref(false)
|
||||||
|
const trialExpiredType = ref<'device' | 'account' | 'both'>('account')
|
||||||
|
|
||||||
|
const checkExpiredType = inject<() => 'device' | 'account' | 'both'>('checkExpiredType')
|
||||||
|
|
||||||
// 计算属性 - 当前页数据
|
// 计算属性 - 当前页数据
|
||||||
const paginatedData = computed(() => {
|
const paginatedData = computed(() => {
|
||||||
const start = (currentPage.value - 1) * pageSize.value
|
const start = (currentPage.value - 1) * pageSize.value
|
||||||
@@ -90,19 +100,13 @@ async function onDrop(e: DragEvent) {
|
|||||||
|
|
||||||
// 批量获取产品信息 - 核心数据处理逻辑
|
// 批量获取产品信息 - 核心数据处理逻辑
|
||||||
async function batchGetProductInfo(asinList: string[]) {
|
async function batchGetProductInfo(asinList: string[]) {
|
||||||
|
// 刷新VIP状态
|
||||||
|
if (refreshVipStatus) await refreshVipStatus()
|
||||||
|
|
||||||
// VIP检查
|
// VIP检查
|
||||||
if (!props.isVip) {
|
if (!props.isVip) {
|
||||||
try {
|
if (checkExpiredType) trialExpiredType.value = checkExpiredType()
|
||||||
await ElMessageBox.confirm(
|
showTrialExpiredDialog.value = true
|
||||||
'VIP已过期,数据采集功能受限。请联系管理员续费后继续使用。',
|
|
||||||
'VIP功能限制',
|
|
||||||
{
|
|
||||||
confirmButtonText: '我知道了',
|
|
||||||
showCancelButton: false,
|
|
||||||
type: 'warning'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} catch {}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,6 +395,9 @@ onMounted(async () => {
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 试用期过期弹框 -->
|
||||||
|
<TrialExpiredDialog v-model="showTrialExpiredDialog" :expired-type="trialExpiredType" />
|
||||||
|
|
||||||
<!-- 表格上方进度条 -->
|
<!-- 表格上方进度条 -->
|
||||||
<div v-if="progressVisible" class="progress-head">
|
<div v-if="progressVisible" class="progress-head">
|
||||||
<div class="progress-section">
|
<div class="progress-section">
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { zebraApi, type BanmaAccount } from '../../api/zebra'
|
import { zebraApi, type BanmaAccount } from '../../api/zebra'
|
||||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||||
|
import { getUsernameFromToken } from '../../utils/token'
|
||||||
|
|
||||||
type PlatformKey = 'zebra' | 'shopee' | 'rakuten' | 'amazon'
|
type PlatformKey = 'zebra' | 'shopee' | 'rakuten' | 'amazon'
|
||||||
|
|
||||||
@@ -18,7 +19,8 @@ const PLATFORM_LABEL: Record<PlatformKey, string> = {
|
|||||||
|
|
||||||
const accounts = ref<BanmaAccount[]>([])
|
const accounts = ref<BanmaAccount[]>([])
|
||||||
async function load() {
|
async function load() {
|
||||||
const res = await zebraApi.getAccounts()
|
const username = getUsernameFromToken()
|
||||||
|
const res = await zebraApi.getAccounts(username)
|
||||||
const list = (res as any)?.data ?? res
|
const list = (res as any)?.data ?? res
|
||||||
accounts.value = Array.isArray(list) ? list : []
|
accounts.value = Array.isArray(list) ? list : []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,36 +54,18 @@ public class BanmaOrderServiceImpl implements IBanmaOrderService {
|
|||||||
builder.readTimeout(Duration.ofSeconds(10));
|
builder.readTimeout(Duration.ofSeconds(10));
|
||||||
restTemplate = builder.build();
|
restTemplate = builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private void fetchTokenFromServer(Long accountId) {
|
private void fetchTokenFromServer(Long accountId) {
|
||||||
ResponseEntity<Map> resp = restTemplate.getForEntity(RUOYI_ADMIN_BASE + "/tool/banma/accounts", Map.class);
|
Map<String, Object> resp = restTemplate.getForObject(RUOYI_ADMIN_BASE + "/tool/banma/accounts", Map.class);
|
||||||
Object body = resp.getBody();
|
List<Map<String, Object>> list = (List<Map<String, Object>>) resp.get("data");
|
||||||
if (body == null) return;
|
if (list == null || list.isEmpty()) return;
|
||||||
Object data = ((Map<String, Object>) body).get("data");
|
Map<String, Object> account = accountId != null
|
||||||
List<Map<String, Object>> list;
|
? list.stream().filter(m -> accountId.equals(((Number) m.get("id")).longValue())).findFirst().orElse(null)
|
||||||
if (data instanceof List) {
|
: list.stream().filter(m -> ((Number) m.getOrDefault("isDefault", 0)).intValue() == 1).findFirst().orElse(list.get(0));
|
||||||
list = (List<Map<String, Object>>) data;
|
|
||||||
} else if (body instanceof Map && ((Map) body).get("list") instanceof List) {
|
if (account != null) {
|
||||||
list = (List<Map<String, Object>>) ((Map) body).get("list");
|
String token = (String) account.get("token");
|
||||||
} else {
|
currentAuthToken = token != null && token.startsWith("Bearer ") ? token : "Bearer " + token;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (list.isEmpty()) return;
|
|
||||||
Map<String, Object> picked;
|
|
||||||
if (accountId != null) {
|
|
||||||
picked = list.stream().filter(m -> Objects.equals(((Number) m.get("id")).longValue(), accountId)).findFirst().orElse(null);
|
|
||||||
if (picked == null) return;
|
|
||||||
} else {
|
|
||||||
picked = list.stream()
|
|
||||||
.filter(m -> Objects.equals(((Number) m.getOrDefault("status", 1)).intValue(), 1))
|
|
||||||
.sorted((a,b) -> Integer.compare(((Number) b.getOrDefault("isDefault", 0)).intValue(), ((Number) a.getOrDefault("isDefault", 0)).intValue()))
|
|
||||||
.findFirst().orElse(list.get(0));
|
|
||||||
}
|
|
||||||
Object token = picked.get("token");
|
|
||||||
if (token instanceof String && !((String) token).isEmpty()) {
|
|
||||||
String t = (String) token;
|
|
||||||
currentAuthToken = t.startsWith("Bearer ") ? t : ("Bearer " + t);
|
|
||||||
currentAccountId = accountId;
|
currentAccountId = accountId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import com.ruoyi.system.domain.SysCache;
|
|||||||
public class CacheController
|
public class CacheController
|
||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisTemplate<String, String> redisTemplate;
|
private RedisTemplate<Object, Object> redisTemplate;
|
||||||
|
|
||||||
private final static List<SysCache> caches = new ArrayList<SysCache>();
|
private final static List<SysCache> caches = new ArrayList<SysCache>();
|
||||||
{
|
{
|
||||||
@@ -80,15 +80,16 @@ public class CacheController
|
|||||||
@GetMapping("/getKeys/{cacheName}")
|
@GetMapping("/getKeys/{cacheName}")
|
||||||
public AjaxResult getCacheKeys(@PathVariable String cacheName)
|
public AjaxResult getCacheKeys(@PathVariable String cacheName)
|
||||||
{
|
{
|
||||||
Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
|
Set<Object> cacheKeys = redisTemplate.keys(cacheName + "*");
|
||||||
return AjaxResult.success(new TreeSet<>(cacheKeys));
|
return AjaxResult.success(cacheKeys != null ? new TreeSet<>(cacheKeys.stream().map(String::valueOf).collect(java.util.stream.Collectors.toSet())) : new TreeSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
||||||
@GetMapping("/getValue/{cacheName}/{cacheKey}")
|
@GetMapping("/getValue/{cacheName}/{cacheKey}")
|
||||||
public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
|
public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
|
||||||
{
|
{
|
||||||
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
|
Object cacheValueObj = redisTemplate.opsForValue().get(cacheKey);
|
||||||
|
String cacheValue = cacheValueObj != null ? cacheValueObj.toString() : null;
|
||||||
SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
|
SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
|
||||||
return AjaxResult.success(sysCache);
|
return AjaxResult.success(sysCache);
|
||||||
}
|
}
|
||||||
@@ -97,8 +98,10 @@ public class CacheController
|
|||||||
@DeleteMapping("/clearCacheName/{cacheName}")
|
@DeleteMapping("/clearCacheName/{cacheName}")
|
||||||
public AjaxResult clearCacheName(@PathVariable String cacheName)
|
public AjaxResult clearCacheName(@PathVariable String cacheName)
|
||||||
{
|
{
|
||||||
Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
|
Set<Object> cacheKeys = redisTemplate.keys(cacheName + "*");
|
||||||
redisTemplate.delete(cacheKeys);
|
if (cacheKeys != null && !cacheKeys.isEmpty()) {
|
||||||
|
redisTemplate.delete(cacheKeys);
|
||||||
|
}
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,8 +117,10 @@ public class CacheController
|
|||||||
@DeleteMapping("/clearCacheAll")
|
@DeleteMapping("/clearCacheAll")
|
||||||
public AjaxResult clearCacheAll()
|
public AjaxResult clearCacheAll()
|
||||||
{
|
{
|
||||||
Collection<String> cacheKeys = redisTemplate.keys("*");
|
Set<Object> cacheKeys = redisTemplate.keys("*");
|
||||||
redisTemplate.delete(cacheKeys);
|
if (cacheKeys != null && !cacheKeys.isEmpty()) {
|
||||||
|
redisTemplate.delete(cacheKeys);
|
||||||
|
}
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,7 +149,6 @@ public class ClientAccountController extends BaseController {
|
|||||||
if (userDevice >= deviceLimit) {
|
if (userDevice >= deviceLimit) {
|
||||||
return AjaxResult.error("设备数量已达上限(" + deviceLimit + "个),请先移除其他设备");
|
return AjaxResult.error("设备数量已达上限(" + deviceLimit + "个),请先移除其他设备");
|
||||||
}
|
}
|
||||||
|
|
||||||
String token = Jwts.builder()
|
String token = Jwts.builder()
|
||||||
.setHeaderParam("kid", jwtRsaKeyService.getKeyId())
|
.setHeaderParam("kid", jwtRsaKeyService.getKeyId())
|
||||||
.setSubject(username)
|
.setSubject(username)
|
||||||
@@ -161,15 +160,24 @@ public class ClientAccountController extends BaseController {
|
|||||||
.signWith(SignatureAlgorithm.RS256, jwtRsaKeyService.getPrivateKey())
|
.signWith(SignatureAlgorithm.RS256, jwtRsaKeyService.getPrivateKey())
|
||||||
.compact();
|
.compact();
|
||||||
|
|
||||||
|
// 检查设备试用期(仅对trial账号生效)
|
||||||
|
boolean deviceTrialExpired = false;
|
||||||
|
if ("trial".equals(account.getAccountType())) {
|
||||||
|
ClientDevice device = clientDeviceMapper.selectByDeviceIdAndUsername(clientId, username);
|
||||||
|
deviceTrialExpired = device != null
|
||||||
|
&& device.getTrialExpireTime() != null
|
||||||
|
&& new Date().after(device.getTrialExpireTime());
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Object> data = new HashMap<>();
|
Map<String, Object> data = new HashMap<>();
|
||||||
data.put("token", token);
|
data.put("token", token);
|
||||||
data.put("permissions", account.getPermissions());
|
data.put("permissions", account.getPermissions());
|
||||||
data.put("accountName", account.getAccountName());
|
data.put("accountName", account.getAccountName());
|
||||||
data.put("expireTime", account.getExpireTime());
|
data.put("expireTime", account.getExpireTime());
|
||||||
|
data.put("accountType", account.getAccountType());
|
||||||
|
data.put("deviceTrialExpired", deviceTrialExpired);
|
||||||
return AjaxResult.success(data);
|
return AjaxResult.success(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证token
|
* 验证token
|
||||||
*/
|
*/
|
||||||
@@ -181,17 +189,35 @@ public class ClientAccountController extends BaseController {
|
|||||||
.parseClaimsJws(token)
|
.parseClaimsJws(token)
|
||||||
.getBody();
|
.getBody();
|
||||||
String username = (String) claims.get("sub");
|
String username = (String) claims.get("sub");
|
||||||
|
String clientId = (String) claims.get("clientId");
|
||||||
|
|
||||||
ClientAccount account = clientAccountService.selectClientAccountByUsername(username);
|
ClientAccount account = clientAccountService.selectClientAccountByUsername(username);
|
||||||
if (account == null || !"0".equals(account.getStatus())) {
|
if (account == null || !"0".equals(account.getStatus())) {
|
||||||
return AjaxResult.error("token无效");
|
return AjaxResult.error("token无效");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 付费账号到期自动降级为试用账号
|
||||||
|
if ("paid".equals(account.getAccountType()) && account.getExpireTime() != null && new Date().after(account.getExpireTime())) {
|
||||||
|
account.setAccountType("trial");
|
||||||
|
clientAccountService.updateClientAccount(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查设备试用期(仅对trial账号生效)
|
||||||
|
boolean deviceTrialExpired = false;
|
||||||
|
if ("trial".equals(account.getAccountType())) {
|
||||||
|
ClientDevice device = clientDeviceMapper.selectByDeviceIdAndUsername(clientId, username);
|
||||||
|
deviceTrialExpired = device != null
|
||||||
|
&& device.getTrialExpireTime() != null
|
||||||
|
&& new Date().after(device.getTrialExpireTime());
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
result.put("username", username);
|
result.put("username", username);
|
||||||
result.put("permissions", account.getPermissions());
|
result.put("permissions", account.getPermissions());
|
||||||
result.put("accountName", account.getAccountName());
|
result.put("accountName", account.getAccountName());
|
||||||
result.put("expireTime", account.getExpireTime());
|
result.put("expireTime", account.getExpireTime());
|
||||||
|
result.put("accountType", account.getAccountType());
|
||||||
|
result.put("deviceTrialExpired", deviceTrialExpired);
|
||||||
return AjaxResult.success(result);
|
return AjaxResult.success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +243,7 @@ public class ClientAccountController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户端账号注册
|
* 客户端账号注册
|
||||||
* 新设备注册送3天VIP,同一设备ID重复注册不赠送
|
* 新账号注册赠送3天VIP试用期
|
||||||
*/
|
*/
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
public AjaxResult register(@RequestBody Map<String, String> registerData) {
|
public AjaxResult register(@RequestBody Map<String, String> registerData) {
|
||||||
@@ -232,16 +258,8 @@ public class ClientAccountController extends BaseController {
|
|||||||
clientAccount.setStatus("0");
|
clientAccount.setStatus("0");
|
||||||
clientAccount.setPermissions("{\"amazon\":true,\"rakuten\":true,\"zebra\":true}");
|
clientAccount.setPermissions("{\"amazon\":true,\"rakuten\":true,\"zebra\":true}");
|
||||||
clientAccount.setPassword(passwordEncoder.encode(password));
|
clientAccount.setPassword(passwordEncoder.encode(password));
|
||||||
|
clientAccount.setAccountType("trial");
|
||||||
// 新设备赠送3天VIP
|
clientAccount.setExpireTime(new Date(System.currentTimeMillis() + 3 * 24L * 60 * 60 * 1000));
|
||||||
ClientDevice existingDevice = clientDeviceMapper.selectByDeviceId(deviceId);
|
|
||||||
int vipDays = (existingDevice == null) ? 3 : 0;
|
|
||||||
|
|
||||||
if (vipDays > 0) {
|
|
||||||
clientAccount.setExpireTime(new Date(System.currentTimeMillis() + vipDays * 24L * 60 * 60 * 1000));
|
|
||||||
} else {
|
|
||||||
clientAccount.setExpireTime(new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
int result = clientAccountService.insertClientAccount(clientAccount);
|
int result = clientAccountService.insertClientAccount(clientAccount);
|
||||||
if (result <= 0) {
|
if (result <= 0) {
|
||||||
@@ -263,6 +281,8 @@ public class ClientAccountController extends BaseController {
|
|||||||
data.put("permissions", clientAccount.getPermissions());
|
data.put("permissions", clientAccount.getPermissions());
|
||||||
data.put("accountName", clientAccount.getAccountName());
|
data.put("accountName", clientAccount.getAccountName());
|
||||||
data.put("expireTime", clientAccount.getExpireTime());
|
data.put("expireTime", clientAccount.getExpireTime());
|
||||||
|
data.put("accountType", clientAccount.getAccountType());
|
||||||
|
data.put("deviceTrialExpired", false);
|
||||||
return AjaxResult.success(data);
|
return AjaxResult.success(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,6 +320,7 @@ public class ClientAccountController extends BaseController {
|
|||||||
Date newExpireTime = cal.getTime();
|
Date newExpireTime = cal.getTime();
|
||||||
|
|
||||||
account.setExpireTime(newExpireTime);
|
account.setExpireTime(newExpireTime);
|
||||||
|
account.setAccountType("paid");
|
||||||
account.setUpdateBy(getUsername());
|
account.setUpdateBy(getUsername());
|
||||||
clientAccountService.updateClientAccount(account);
|
clientAccountService.updateClientAccount(account);
|
||||||
|
|
||||||
|
|||||||
@@ -97,32 +97,33 @@ public class ClientDeviceController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
public AjaxResult register(@RequestBody ClientDevice device, HttpServletRequest request) {
|
public AjaxResult register(@RequestBody ClientDevice device, HttpServletRequest request) {
|
||||||
ClientDevice exists = clientDeviceMapper.selectByDeviceId(device.getDeviceId());
|
|
||||||
String ip = IpUtils.getIpAddr(request);
|
String ip = IpUtils.getIpAddr(request);
|
||||||
String username = device.getUsername();
|
String username = device.getUsername();
|
||||||
|
String deviceId = device.getDeviceId();
|
||||||
String os = device.getOs();
|
String os = device.getOs();
|
||||||
String deviceName = username + "@" + ip + " (" + os + ")";
|
String deviceName = username + "@" + ip + " (" + os + ")";
|
||||||
|
ClientDevice exists = clientDeviceMapper.selectByDeviceIdAndUsername(deviceId, username);
|
||||||
if (exists == null) {
|
if (exists == null) {
|
||||||
// 检查设备数量限制
|
// 检查设备数量限制
|
||||||
try {
|
try {
|
||||||
checkDeviceLimit(device.getUsername(), device.getDeviceId());
|
checkDeviceLimit(username, deviceId);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
return AjaxResult.error(e.getMessage());
|
return AjaxResult.error(e.getMessage());
|
||||||
}
|
}
|
||||||
device.setIp(ip);
|
device.setIp(ip);
|
||||||
device.setStatus("online");
|
device.setStatus("online");
|
||||||
device.setLastActiveAt(new java.util.Date());
|
device.setLastActiveAt(new java.util.Date());
|
||||||
|
device.setTrialExpireTime(new java.util.Date(System.currentTimeMillis() + 3 * 24L * 60 * 60 * 1000));
|
||||||
device.setName(deviceName);
|
device.setName(deviceName);
|
||||||
clientDeviceMapper.insert(device);
|
clientDeviceMapper.insert(device);
|
||||||
} else {
|
} else {
|
||||||
exists.setUsername(device.getUsername());
|
|
||||||
exists.setName(deviceName);
|
exists.setName(deviceName);
|
||||||
exists.setOs(device.getOs());
|
exists.setOs(os);
|
||||||
exists.setStatus("online");
|
exists.setStatus("online");
|
||||||
exists.setIp(ip);
|
exists.setIp(ip);
|
||||||
exists.setLocation(device.getLocation());
|
exists.setLocation(device.getLocation());
|
||||||
exists.setLastActiveAt(new java.util.Date());
|
exists.setLastActiveAt(new java.util.Date());
|
||||||
clientDeviceMapper.updateByDeviceId(exists);
|
clientDeviceMapper.updateByDeviceIdAndUsername(exists);
|
||||||
}
|
}
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
@@ -137,6 +138,15 @@ public class ClientDeviceController {
|
|||||||
clientDeviceMapper.updateByDeviceId(device);
|
clientDeviceMapper.updateByDeviceId(device);
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改设备试用期过期时间
|
||||||
|
*/
|
||||||
|
@PostMapping("/updateExpire")
|
||||||
|
public AjaxResult updateExpire(@RequestBody ClientDevice device) {
|
||||||
|
clientDeviceMapper.updateByDeviceIdAndUsername(device);
|
||||||
|
return AjaxResult.success();
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 移除设备
|
* 移除设备
|
||||||
* 根据 deviceId 删除设备绑定记录。
|
* 根据 deviceId 删除设备绑定记录。
|
||||||
@@ -144,19 +154,20 @@ public class ClientDeviceController {
|
|||||||
@PostMapping("/remove")
|
@PostMapping("/remove")
|
||||||
public AjaxResult remove(@RequestBody Map<String, String> body) {
|
public AjaxResult remove(@RequestBody Map<String, String> body) {
|
||||||
String deviceId = body.get("deviceId");
|
String deviceId = body.get("deviceId");
|
||||||
|
String username = body.get("username");
|
||||||
if (deviceId == null || deviceId.isEmpty()) {
|
if (deviceId == null || deviceId.isEmpty()) {
|
||||||
return AjaxResult.error("deviceId不能为空");
|
return AjaxResult.error("deviceId不能为空");
|
||||||
}
|
}
|
||||||
ClientDevice exists = clientDeviceMapper.selectByDeviceId(deviceId);
|
ClientDevice exists = clientDeviceMapper.selectByDeviceIdAndUsername(deviceId, username);
|
||||||
if (exists == null) {
|
if (exists == null) {
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
if (!"removed".equals(exists.getStatus())) {
|
if (!"removed".equals(exists.getStatus())) {
|
||||||
exists.setStatus("removed");
|
exists.setStatus("removed");
|
||||||
exists.setLastActiveAt(new java.util.Date());
|
exists.setLastActiveAt(new java.util.Date());
|
||||||
clientDeviceMapper.updateByDeviceId(exists);
|
clientDeviceMapper.updateByDeviceIdAndUsername(exists);
|
||||||
sseHubService.sendEvent(exists.getUsername(), deviceId, "DEVICE_REMOVED", "{}");
|
sseHubService.sendEvent(username, deviceId, "DEVICE_REMOVED", "{}");
|
||||||
sseHubService.disconnectDevice(exists.getUsername(), deviceId);
|
sseHubService.disconnectDevice(username, deviceId);
|
||||||
}
|
}
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
@@ -167,11 +178,13 @@ public class ClientDeviceController {
|
|||||||
@PostMapping("/offline")
|
@PostMapping("/offline")
|
||||||
public AjaxResult offline(@RequestBody Map<String, String> body) {
|
public AjaxResult offline(@RequestBody Map<String, String> body) {
|
||||||
String deviceId = body.get("deviceId");
|
String deviceId = body.get("deviceId");
|
||||||
ClientDevice device = clientDeviceMapper.selectByDeviceId(deviceId);
|
String username = body.get("username");
|
||||||
|
ClientDevice device = clientDeviceMapper.selectByDeviceIdAndUsername(deviceId, username);
|
||||||
|
if (device != null) {
|
||||||
device.setStatus("offline");
|
device.setStatus("offline");
|
||||||
device.setLastActiveAt(new java.util.Date());
|
device.setLastActiveAt(new java.util.Date());
|
||||||
clientDeviceMapper.updateByDeviceId(device);
|
clientDeviceMapper.updateByDeviceIdAndUsername(device);
|
||||||
|
}
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,38 +195,37 @@ public class ClientDeviceController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/heartbeat")
|
@PostMapping("/heartbeat")
|
||||||
public AjaxResult heartbeat(@RequestBody ClientDevice device, HttpServletRequest request) {
|
public AjaxResult heartbeat(@RequestBody ClientDevice device, HttpServletRequest request) {
|
||||||
ClientDevice exists = clientDeviceMapper.selectByDeviceId(device.getDeviceId());
|
|
||||||
String ip = IpUtils.getIpAddr(request);
|
String ip = IpUtils.getIpAddr(request);
|
||||||
String username = device.getUsername();
|
String username = device.getUsername();
|
||||||
|
String deviceId = device.getDeviceId();
|
||||||
String os = device.getOs();
|
String os = device.getOs();
|
||||||
String deviceName = username + "@" + ip + " (" + os + ")";
|
String deviceName = username + "@" + ip + " (" + os + ")";
|
||||||
|
|
||||||
|
ClientDevice exists = clientDeviceMapper.selectByDeviceIdAndUsername(deviceId, username);
|
||||||
if (exists == null) {
|
if (exists == null) {
|
||||||
// 新设备注册
|
// 新设备注册
|
||||||
device.setIp(ip);
|
device.setIp(ip);
|
||||||
device.setStatus("online");
|
device.setStatus("online");
|
||||||
device.setLastActiveAt(new java.util.Date());
|
device.setLastActiveAt(new java.util.Date());
|
||||||
|
device.setTrialExpireTime(new java.util.Date(System.currentTimeMillis() + 3 * 24L * 60 * 60 * 1000));
|
||||||
device.setName(deviceName);
|
device.setName(deviceName);
|
||||||
clientDeviceMapper.insert(device);
|
clientDeviceMapper.insert(device);
|
||||||
} else if ("removed".equals(exists.getStatus())) {
|
} else if ("removed".equals(exists.getStatus())) {
|
||||||
// 被移除设备重新激活
|
// 被移除设备重新激活
|
||||||
exists.setUsername(device.getUsername());
|
|
||||||
exists.setName(deviceName);
|
exists.setName(deviceName);
|
||||||
exists.setOs(device.getOs());
|
exists.setOs(os);
|
||||||
exists.setStatus("online");
|
exists.setStatus("online");
|
||||||
exists.setIp(ip);
|
exists.setIp(ip);
|
||||||
exists.setLocation(device.getLocation());
|
exists.setLocation(device.getLocation());
|
||||||
exists.setLastActiveAt(new java.util.Date());
|
exists.setLastActiveAt(new java.util.Date());
|
||||||
clientDeviceMapper.updateByDeviceId(exists);
|
clientDeviceMapper.updateByDeviceIdAndUsername(exists);
|
||||||
} else {
|
} else {
|
||||||
// 已存在设备更新
|
// 已存在设备更新
|
||||||
exists.setUsername(device.getUsername());
|
|
||||||
exists.setStatus("online");
|
exists.setStatus("online");
|
||||||
exists.setIp(ip);
|
exists.setIp(ip);
|
||||||
exists.setLastActiveAt(new java.util.Date());
|
exists.setLastActiveAt(new java.util.Date());
|
||||||
exists.setName(deviceName);
|
exists.setName(deviceName);
|
||||||
clientDeviceMapper.updateByDeviceId(exists);
|
clientDeviceMapper.updateByDeviceIdAndUsername(exists);
|
||||||
}
|
}
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ruoyi.web.controller.tool;
|
package com.ruoyi.web.controller.tool;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import com.ruoyi.common.annotation.Anonymous;
|
import com.ruoyi.common.annotation.Anonymous;
|
||||||
@@ -10,9 +11,7 @@ import com.ruoyi.system.domain.BanmaAccount;
|
|||||||
import com.ruoyi.system.service.IBanmaAccountService;
|
import com.ruoyi.system.service.IBanmaAccountService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 斑马账号管理(数据库版,极简接口):
|
* 斑马账号管理
|
||||||
* - 仅负责账号与 Token 的存取
|
|
||||||
* - 不参与登录/刷新与数据采集,客户端自行处理
|
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/tool/banma")
|
@RequestMapping("/tool/banma")
|
||||||
@@ -22,46 +21,35 @@ public class BanmaOrderController extends BaseController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IBanmaAccountService accountService;
|
private IBanmaAccountService accountService;
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询账号列表(
|
|
||||||
*/
|
|
||||||
@GetMapping("/accounts")
|
@GetMapping("/accounts")
|
||||||
public R<?> listAccounts() {
|
public R<?> listAccounts(String name) {
|
||||||
List<BanmaAccount> list = accountService.listSimple();
|
return R.ok(accountService.listSimple(name));
|
||||||
return R.ok(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增或编辑账号(含设为默认)
|
|
||||||
*/
|
|
||||||
@PostMapping("/accounts")
|
@PostMapping("/accounts")
|
||||||
public R<?> saveAccount(@RequestBody BanmaAccount body) {
|
public R<?> saveAccount(@RequestBody BanmaAccount body, String name) {
|
||||||
Long id = accountService.saveOrUpdate(body);
|
if (body.getId() == null && accountService.validateAndGetToken(body.getUsername(), body.getPassword()) == null) {
|
||||||
boolean ok = false;
|
throw new RuntimeException("账号或密码错误");
|
||||||
try { ok = accountService.refreshToken(id); } catch (Exception ignore) {}
|
}
|
||||||
return ok ? R.ok(Map.of("id", id)) : R.fail("账号或密码错误,无法获取Token");
|
Long id = accountService.saveOrUpdate(body, name);
|
||||||
|
accountService.refreshToken(id);
|
||||||
|
return R.ok(Map.of("id", id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除账号
|
|
||||||
*/
|
|
||||||
@DeleteMapping("/accounts/{id}")
|
@DeleteMapping("/accounts/{id}")
|
||||||
public R<?> remove(@PathVariable Long id) {
|
public R<?> remove(@PathVariable Long id) {
|
||||||
accountService.remove(id);
|
accountService.remove(id);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 手动刷新单个账号 Token */
|
|
||||||
@PostMapping("/accounts/{id}/refresh-token")
|
@PostMapping("/accounts/{id}/refresh-token")
|
||||||
public R<?> refreshOne(@PathVariable Long id) {
|
public R<?> refreshOne(@PathVariable Long id) {
|
||||||
accountService.refreshToken(id);
|
accountService.refreshToken(id);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 手动刷新全部启用账号 Token */
|
|
||||||
@PostMapping("/refresh-all")
|
@PostMapping("/refresh-all")
|
||||||
public R<?> refreshAll() {
|
public R<?> refreshAll() {
|
||||||
accountService.refreshAllTokens();
|
accountService.listSimple().forEach(account -> accountService.refreshToken(account.getId()));
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ public class BanmaAccount extends BaseEntity {
|
|||||||
private String username;
|
private String username;
|
||||||
/** 登录密码(服务端刷新Token用,不对外返回) */
|
/** 登录密码(服务端刷新Token用,不对外返回) */
|
||||||
private String password;
|
private String password;
|
||||||
|
/** 客户端账号用户名(关联client_account.username) */
|
||||||
|
private String clientUsername;
|
||||||
/** 访问 Token(客户端刷新后回写) */
|
/** 访问 Token(客户端刷新后回写) */
|
||||||
private String token;
|
private String token;
|
||||||
/** Token 过期时间(可选) */
|
/** Token 过期时间(可选) */
|
||||||
@@ -37,6 +39,8 @@ public class BanmaAccount extends BaseEntity {
|
|||||||
public void setUsername(String username) { this.username = username; }
|
public void setUsername(String username) { this.username = username; }
|
||||||
public String getPassword() { return password; }
|
public String getPassword() { return password; }
|
||||||
public void setPassword(String password) { this.password = password; }
|
public void setPassword(String password) { this.password = password; }
|
||||||
|
public String getClientUsername() { return clientUsername; }
|
||||||
|
public void setClientUsername(String clientUsername) { this.clientUsername = clientUsername; }
|
||||||
public String getToken() { return token; }
|
public String getToken() { return token; }
|
||||||
public void setToken(String token) { this.token = token; }
|
public void setToken(String token) { this.token = token; }
|
||||||
public Date getTokenExpireAt() { return tokenExpireAt; }
|
public Date getTokenExpireAt() { return tokenExpireAt; }
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ public class ClientAccount extends BaseEntity
|
|||||||
@Excel(name = "设备数量限制")
|
@Excel(name = "设备数量限制")
|
||||||
private Integer deviceLimit;
|
private Integer deviceLimit;
|
||||||
|
|
||||||
|
/** 账号类型 */
|
||||||
|
@Excel(name = "账号类型")
|
||||||
|
private String accountType; // trial试用, paid付费
|
||||||
|
|
||||||
public void setId(Long id)
|
public void setId(Long id)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@@ -147,4 +151,14 @@ public class ClientAccount extends BaseEntity
|
|||||||
{
|
{
|
||||||
return deviceLimit;
|
return deviceLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAccountType(String accountType)
|
||||||
|
{
|
||||||
|
this.accountType = accountType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccountType()
|
||||||
|
{
|
||||||
|
return accountType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,9 @@ public class ClientDevice extends BaseEntity {
|
|||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
@Excel(name = "最近在线", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
@Excel(name = "最近在线", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date lastActiveAt;
|
private Date lastActiveAt;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
@Excel(name = "试用期过期时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date trialExpireTime;
|
||||||
|
|
||||||
public Long getId() { return id; }
|
public Long getId() { return id; }
|
||||||
public void setId(Long id) { this.id = id; }
|
public void setId(Long id) { this.id = id; }
|
||||||
@@ -49,6 +52,8 @@ public class ClientDevice extends BaseEntity {
|
|||||||
public void setLocation(String location) { this.location = location; }
|
public void setLocation(String location) { this.location = location; }
|
||||||
public Date getLastActiveAt() { return lastActiveAt; }
|
public Date getLastActiveAt() { return lastActiveAt; }
|
||||||
public void setLastActiveAt(Date lastActiveAt) { this.lastActiveAt = lastActiveAt; }
|
public void setLastActiveAt(Date lastActiveAt) { this.lastActiveAt = lastActiveAt; }
|
||||||
|
public Date getTrialExpireTime() { return trialExpireTime; }
|
||||||
|
public void setTrialExpireTime(Date trialExpireTime) { this.trialExpireTime = trialExpireTime; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ruoyi.system.mapper;
|
package com.ruoyi.system.mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
import com.ruoyi.system.domain.BanmaAccount;
|
import com.ruoyi.system.domain.BanmaAccount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,7 +13,7 @@ public interface BanmaAccountMapper {
|
|||||||
int insert(BanmaAccount entity);
|
int insert(BanmaAccount entity);
|
||||||
int update(BanmaAccount entity);
|
int update(BanmaAccount entity);
|
||||||
int deleteById(Long id);
|
int deleteById(Long id);
|
||||||
int clearDefault();
|
int clearDefault(@Param("clientUsername") String clientUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
package com.ruoyi.system.mapper;
|
package com.ruoyi.system.mapper;
|
||||||
|
|
||||||
import com.ruoyi.system.domain.ClientDevice;
|
import com.ruoyi.system.domain.ClientDevice;
|
||||||
import io.lettuce.core.dynamic.annotation.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface ClientDeviceMapper {
|
public interface ClientDeviceMapper {
|
||||||
ClientDevice selectByDeviceId(String deviceId);
|
ClientDevice selectByDeviceId(@Param("deviceId") String deviceId);
|
||||||
|
ClientDevice selectByDeviceIdAndUsername(@Param("deviceId") String deviceId, @Param("username") String username);
|
||||||
List<ClientDevice> selectByUsername(@Param("username") String username);
|
List<ClientDevice> selectByUsername(@Param("username") String username);
|
||||||
List<ClientDevice> selectOnlineDevices();
|
List<ClientDevice> selectOnlineDevices();
|
||||||
int insert(ClientDevice device);
|
int insert(ClientDevice device);
|
||||||
int updateByDeviceId(ClientDevice device);
|
int updateByDeviceId(ClientDevice device);
|
||||||
int deleteByDeviceId(String deviceId);
|
int updateByDeviceIdAndUsername(ClientDevice device);
|
||||||
int countByUsername(String username);
|
int deleteByDeviceId(@Param("deviceId") String deviceId);
|
||||||
|
int countByUsername(@Param("username") String username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,14 @@ public class BanmaAccountServiceImpl implements IBanmaAccountService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BanmaAccount> listSimple() {
|
public List<BanmaAccount> listSimple() {
|
||||||
List<BanmaAccount> list = mapper.selectList(new BanmaAccount());
|
return listSimple(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BanmaAccount> listSimple(String clientUsername) {
|
||||||
|
BanmaAccount query = new BanmaAccount();
|
||||||
|
query.setClientUsername(clientUsername);
|
||||||
|
List<BanmaAccount> list = mapper.selectList(query);
|
||||||
// 隐藏密码
|
// 隐藏密码
|
||||||
for (BanmaAccount a : list) { a.setPassword(null); }
|
for (BanmaAccount a : list) { a.setPassword(null); }
|
||||||
return list;
|
return list;
|
||||||
@@ -34,13 +41,25 @@ public class BanmaAccountServiceImpl implements IBanmaAccountService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long saveOrUpdate(BanmaAccount entity) {
|
public Long saveOrUpdate(BanmaAccount entity) {
|
||||||
|
return saveOrUpdate(entity, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long saveOrUpdate(BanmaAccount entity, String clientUsername) {
|
||||||
|
// 设置客户端用户名
|
||||||
|
if (clientUsername != null) {
|
||||||
|
entity.setClientUsername(clientUsername);
|
||||||
|
}
|
||||||
|
|
||||||
if (entity.getId() == null) {
|
if (entity.getId() == null) {
|
||||||
mapper.insert(entity);
|
mapper.insert(entity);
|
||||||
} else {
|
} else {
|
||||||
mapper.update(entity);
|
mapper.update(entity);
|
||||||
}
|
}
|
||||||
if (Objects.equals(entity.getIsDefault(), 1)) {
|
|
||||||
mapper.clearDefault();
|
// 如果设为默认,则清除该客户端的其他默认账号
|
||||||
|
if (Objects.equals(entity.getIsDefault(), 1) && entity.getClientUsername() != null) {
|
||||||
|
mapper.clearDefault(entity.getClientUsername());
|
||||||
BanmaAccount only = new BanmaAccount();
|
BanmaAccount only = new BanmaAccount();
|
||||||
only.setId(entity.getId());
|
only.setId(entity.getId());
|
||||||
only.setIsDefault(1);
|
only.setIsDefault(1);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<result property="name" column="name"/>
|
<result property="name" column="name"/>
|
||||||
<result property="username" column="username"/>
|
<result property="username" column="username"/>
|
||||||
<result property="password" column="password"/>
|
<result property="password" column="password"/>
|
||||||
|
<result property="clientUsername" column="client_username"/>
|
||||||
<result property="token" column="token"/>
|
<result property="token" column="token"/>
|
||||||
<result property="tokenExpireAt" column="token_expire_at"/>
|
<result property="tokenExpireAt" column="token_expire_at"/>
|
||||||
<result property="isDefault" column="is_default"/>
|
<result property="isDefault" column="is_default"/>
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, name, username, password, token, token_expire_at, is_default, status, remark, create_by, create_time, update_by, update_time
|
id, name, username, password, client_username, token, token_expire_at, is_default, status, remark, create_by, create_time, update_by, update_time
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="selectById" parameterType="long" resultMap="BanmaAccountResult">
|
<select id="selectById" parameterType="long" resultMap="BanmaAccountResult">
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
<select id="selectList" parameterType="com.ruoyi.system.domain.BanmaAccount" resultMap="BanmaAccountResult">
|
<select id="selectList" parameterType="com.ruoyi.system.domain.BanmaAccount" resultMap="BanmaAccountResult">
|
||||||
select <include refid="Base_Column_List"/> from banma_account
|
select <include refid="Base_Column_List"/> from banma_account
|
||||||
<where>
|
<where>
|
||||||
|
<if test="clientUsername != null and clientUsername != ''"> and client_username = #{clientUsername}</if>
|
||||||
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
|
<if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if>
|
||||||
<if test="username != null and username != ''"> and username like concat('%', #{username}, '%')</if>
|
<if test="username != null and username != ''"> and username like concat('%', #{username}, '%')</if>
|
||||||
<if test="status != null"> and status = #{status}</if>
|
<if test="status != null"> and status = #{status}</if>
|
||||||
@@ -42,6 +44,7 @@
|
|||||||
<if test="name != null">name,</if>
|
<if test="name != null">name,</if>
|
||||||
<if test="username != null">username,</if>
|
<if test="username != null">username,</if>
|
||||||
<if test="password != null">password,</if>
|
<if test="password != null">password,</if>
|
||||||
|
<if test="clientUsername != null">client_username,</if>
|
||||||
<if test="token != null">token,</if>
|
<if test="token != null">token,</if>
|
||||||
<if test="tokenExpireAt != null">token_expire_at,</if>
|
<if test="tokenExpireAt != null">token_expire_at,</if>
|
||||||
<if test="isDefault != null">is_default,</if>
|
<if test="isDefault != null">is_default,</if>
|
||||||
@@ -54,6 +57,7 @@
|
|||||||
<if test="name != null">#{name},</if>
|
<if test="name != null">#{name},</if>
|
||||||
<if test="username != null">#{username},</if>
|
<if test="username != null">#{username},</if>
|
||||||
<if test="password != null">#{password},</if>
|
<if test="password != null">#{password},</if>
|
||||||
|
<if test="clientUsername != null">#{clientUsername},</if>
|
||||||
<if test="token != null">#{token},</if>
|
<if test="token != null">#{token},</if>
|
||||||
<if test="tokenExpireAt != null">#{tokenExpireAt},</if>
|
<if test="tokenExpireAt != null">#{tokenExpireAt},</if>
|
||||||
<if test="isDefault != null">#{isDefault},</if>
|
<if test="isDefault != null">#{isDefault},</if>
|
||||||
@@ -70,6 +74,7 @@
|
|||||||
<if test="name != null">name=#{name},</if>
|
<if test="name != null">name=#{name},</if>
|
||||||
<if test="username != null">username=#{username},</if>
|
<if test="username != null">username=#{username},</if>
|
||||||
<if test="password != null">password=#{password},</if>
|
<if test="password != null">password=#{password},</if>
|
||||||
|
<if test="clientUsername != null">client_username=#{clientUsername},</if>
|
||||||
<if test="token != null">token=#{token},</if>
|
<if test="token != null">token=#{token},</if>
|
||||||
<if test="tokenExpireAt != null">token_expire_at=#{tokenExpireAt},</if>
|
<if test="tokenExpireAt != null">token_expire_at=#{tokenExpireAt},</if>
|
||||||
<if test="isDefault != null">is_default=#{isDefault},</if>
|
<if test="isDefault != null">is_default=#{isDefault},</if>
|
||||||
@@ -83,6 +88,9 @@
|
|||||||
|
|
||||||
<update id="clearDefault">
|
<update id="clearDefault">
|
||||||
update banma_account set is_default = 0 where is_default = 1
|
update banma_account set is_default = 0 where is_default = 1
|
||||||
|
<if test="clientUsername != null and clientUsername != ''">
|
||||||
|
and client_username = #{clientUsername}
|
||||||
|
</if>
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<delete id="deleteById" parameterType="long">
|
<delete id="deleteById" parameterType="long">
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="remark" column="remark" />
|
<result property="remark" column="remark" />
|
||||||
<result property="permissions" column="permissions" />
|
<result property="permissions" column="permissions" />
|
||||||
<result property="deviceLimit" column="device_limit" />
|
<result property="deviceLimit" column="device_limit" />
|
||||||
|
<result property="accountType" column="account_type" />
|
||||||
<result property="createBy" column="create_by" />
|
<result property="createBy" column="create_by" />
|
||||||
<result property="createTime" column="create_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updateBy" column="update_by" />
|
<result property="updateBy" column="update_by" />
|
||||||
@@ -23,7 +24,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
|
|
||||||
<sql id="selectClientAccountVo">
|
<sql id="selectClientAccountVo">
|
||||||
select id, account_name, username, password, status, expire_time,
|
select id, account_name, username, password, status, expire_time,
|
||||||
allowed_ip_range, remark, permissions, device_limit, create_by, create_time, update_by, update_time
|
allowed_ip_range, remark, permissions, device_limit, account_type, create_by, create_time, update_by, update_time
|
||||||
from client_account
|
from client_account
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="remark != null">remark,</if>
|
<if test="remark != null">remark,</if>
|
||||||
<if test="permissions != null">permissions,</if>
|
<if test="permissions != null">permissions,</if>
|
||||||
<if test="deviceLimit != null">device_limit,</if>
|
<if test="deviceLimit != null">device_limit,</if>
|
||||||
|
<if test="accountType != null">account_type,</if>
|
||||||
<if test="createBy != null">create_by,</if>
|
<if test="createBy != null">create_by,</if>
|
||||||
create_time
|
create_time
|
||||||
</trim>
|
</trim>
|
||||||
@@ -72,6 +74,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="remark != null">#{remark},</if>
|
<if test="remark != null">#{remark},</if>
|
||||||
<if test="permissions != null">#{permissions},</if>
|
<if test="permissions != null">#{permissions},</if>
|
||||||
<if test="deviceLimit != null">#{deviceLimit},</if>
|
<if test="deviceLimit != null">#{deviceLimit},</if>
|
||||||
|
<if test="accountType != null">#{accountType},</if>
|
||||||
<if test="createBy != null">#{createBy},</if>
|
<if test="createBy != null">#{createBy},</if>
|
||||||
sysdate()
|
sysdate()
|
||||||
</trim>
|
</trim>
|
||||||
@@ -89,6 +92,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="remark != null">remark = #{remark},</if>
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
<if test="permissions != null">permissions = #{permissions},</if>
|
<if test="permissions != null">permissions = #{permissions},</if>
|
||||||
<if test="deviceLimit != null">device_limit = #{deviceLimit},</if>
|
<if test="deviceLimit != null">device_limit = #{deviceLimit},</if>
|
||||||
|
<if test="accountType != null">account_type = #{accountType},</if>
|
||||||
<if test="updateBy != null">update_by = #{updateBy},</if>
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
update_time = sysdate()
|
update_time = sysdate()
|
||||||
</trim>
|
</trim>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<result property="ip" column="ip"/>
|
<result property="ip" column="ip"/>
|
||||||
<result property="location" column="location"/>
|
<result property="location" column="location"/>
|
||||||
<result property="lastActiveAt" column="last_active_at"/>
|
<result property="lastActiveAt" column="last_active_at"/>
|
||||||
|
<result property="trialExpireTime" column="trial_expire_time"/>
|
||||||
<result property="createTime" column="create_time"/>
|
<result property="createTime" column="create_time"/>
|
||||||
<result property="updateTime" column="update_time"/>
|
<result property="updateTime" column="update_time"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
@@ -19,13 +20,17 @@
|
|||||||
select * from client_device where device_id = #{deviceId}
|
select * from client_device where device_id = #{deviceId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByDeviceIdAndUsername" resultMap="ClientDeviceMap">
|
||||||
|
select * from client_device where device_id = #{deviceId} and username = #{username}
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectByUsername" resultMap="ClientDeviceMap">
|
<select id="selectByUsername" resultMap="ClientDeviceMap">
|
||||||
select * from client_device where username = #{username} and status != 'removed' order by update_time desc
|
select * from client_device where username = #{username} and status != 'removed' order by update_time desc
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<insert id="insert" parameterType="com.ruoyi.system.domain.ClientDevice" useGeneratedKeys="true" keyProperty="id">
|
<insert id="insert" parameterType="com.ruoyi.system.domain.ClientDevice" useGeneratedKeys="true" keyProperty="id">
|
||||||
insert into client_device(username, device_id, name, os, status, ip, location, last_active_at, create_time, update_time)
|
insert into client_device(username, device_id, name, os, status, ip, location, last_active_at, trial_expire_time, create_time, update_time)
|
||||||
values(#{username}, #{deviceId}, #{name}, #{os}, #{status}, #{ip}, #{location}, #{lastActiveAt}, now(), now())
|
values(#{username}, #{deviceId}, #{name}, #{os}, #{status}, #{ip}, #{location}, #{lastActiveAt}, #{trialExpireTime}, now(), now())
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
<update id="updateByDeviceId" parameterType="com.ruoyi.system.domain.ClientDevice">
|
<update id="updateByDeviceId" parameterType="com.ruoyi.system.domain.ClientDevice">
|
||||||
@@ -37,10 +42,26 @@
|
|||||||
ip = #{ip},
|
ip = #{ip},
|
||||||
location = #{location},
|
location = #{location},
|
||||||
last_active_at = #{lastActiveAt},
|
last_active_at = #{lastActiveAt},
|
||||||
|
trial_expire_time = #{trialExpireTime},
|
||||||
update_time = now()
|
update_time = now()
|
||||||
where device_id = #{deviceId}
|
where device_id = #{deviceId}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="updateByDeviceIdAndUsername" parameterType="com.ruoyi.system.domain.ClientDevice">
|
||||||
|
update client_device
|
||||||
|
<set>
|
||||||
|
<if test="name != null">name = #{name},</if>
|
||||||
|
<if test="os != null">os = #{os},</if>
|
||||||
|
<if test="status != null">status = #{status},</if>
|
||||||
|
<if test="ip != null">ip = #{ip},</if>
|
||||||
|
<if test="location != null">location = #{location},</if>
|
||||||
|
<if test="lastActiveAt != null">last_active_at = #{lastActiveAt},</if>
|
||||||
|
<if test="trialExpireTime != null">trial_expire_time = #{trialExpireTime},</if>
|
||||||
|
update_time = now()
|
||||||
|
</set>
|
||||||
|
where device_id = #{deviceId} and username = #{username}
|
||||||
|
</update>
|
||||||
|
|
||||||
<delete id="deleteByDeviceId">
|
<delete id="deleteByDeviceId">
|
||||||
delete from client_device where device_id = #{deviceId}
|
delete from client_device where device_id = #{deviceId}
|
||||||
</delete>
|
</delete>
|
||||||
|
|||||||
@@ -69,3 +69,21 @@ export function renewAccount(data) {
|
|||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取账号设备列表
|
||||||
|
export function getDeviceList(username) {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/device/list',
|
||||||
|
method: 'get',
|
||||||
|
params: { username }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改设备试用期过期时间
|
||||||
|
export function updateDeviceExpire(data) {
|
||||||
|
return request({
|
||||||
|
url: '/monitor/device/updateExpire',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user