feat:新增授权管理
This commit is contained in:
1 parent
a6b38c0fdc
commit
c9fed52b29
11 files changed
+173
-411
No files matched your search
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"WebFetch(domain:www.figma.com)"
|
||||
"WebFetch(domain:www.figma.com)",
|
||||
"Bash(git checkout:*)"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
|
||||
+57
-33
@@ -1,6 +1,24 @@
|
||||
import Axios from './https'
|
||||
// 授权码(AuthorizationCode)类型 - 供授权管理页面使用
|
||||
export interface AuthorizationCode {
|
||||
id: string;
|
||||
code: string;
|
||||
customer_id?: string;
|
||||
customer_name?: string;
|
||||
description?: string;
|
||||
status: 'normal' | 'locked' | 'expired';
|
||||
status_display?: string;
|
||||
created_at: string;
|
||||
updated_at?: string;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
is_locked?: boolean;
|
||||
max_activations?: number;
|
||||
current_activations?: number;
|
||||
deployment_type_display?: string; // 部署类型显示文本
|
||||
}
|
||||
|
||||
// 授权接口类型定义
|
||||
// 许可证(License)类型 - 供其他页面使用(保持兼容)
|
||||
export interface License {
|
||||
id: string;
|
||||
license_code: string;
|
||||
@@ -29,24 +47,20 @@ export interface License {
|
||||
export interface LicenseQueryRequest {
|
||||
page?: number;
|
||||
page_size?: number;
|
||||
search?: string;
|
||||
customer_id?: string;
|
||||
status?: 'active' | 'inactive' | 'expired';
|
||||
license_type?: string;
|
||||
sort?: 'created_at' | 'updated_at' | 'expiry_date' | 'activation_date';
|
||||
status?: 'normal' | 'locked' | 'expired';
|
||||
sort?: 'created_at' | 'updated_at' | 'code';
|
||||
order?: 'asc' | 'desc';
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
}
|
||||
|
||||
// 创建授权请求参数
|
||||
export interface LicenseCreateRequest {
|
||||
export interface AuthorizationCodeCreateRequest {
|
||||
customer_id: string;
|
||||
description: string;
|
||||
license_type: string;
|
||||
expiry_date: string;
|
||||
license_type?: string;
|
||||
expiry_date?: string;
|
||||
max_users?: number;
|
||||
features: string[];
|
||||
features?: string[];
|
||||
ip_restrictions?: string[];
|
||||
hardware_id?: string;
|
||||
}
|
||||
@@ -77,7 +91,7 @@ export interface LicenseQueryResponse {
|
||||
message: string;
|
||||
timestamp: string;
|
||||
data: {
|
||||
list: License[];
|
||||
list: AuthorizationCode[];
|
||||
total: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
@@ -97,56 +111,52 @@ export interface ApiResponse<T = any> {
|
||||
* 查询授权列表
|
||||
*/
|
||||
export function getLicenses(params?: LicenseQueryRequest): Promise<LicenseQueryResponse> {
|
||||
return Axios.get('/api/licenses', { params })
|
||||
return Axios.get('/api/v1/authorization-codes', { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权详情
|
||||
*/
|
||||
export function getLicenseDetail(id: string): Promise<ApiResponse<License>> {
|
||||
return Axios.get(`/api/licenses/${id}`)
|
||||
export function getLicenseDetail(id: string): Promise<ApiResponse<AuthorizationCode>> {
|
||||
return Axios.get(`/api/v1/authorization-codes/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建授权
|
||||
*/
|
||||
export function createLicense(data: LicenseCreateRequest): Promise<ApiResponse<License>> {
|
||||
return Axios.post('/api/licenses', data)
|
||||
export function createLicense(data: AuthorizationCodeCreateRequest): Promise<ApiResponse<AuthorizationCode>> {
|
||||
return Axios.post('/api/v1/authorization-codes', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新授权
|
||||
*/
|
||||
export function updateLicense(id: string, data: LicenseUpdateRequest): Promise<ApiResponse<License>> {
|
||||
return Axios.put(`/api/licenses/${id}`, data)
|
||||
export function updateLicense(id: string, data: LicenseUpdateRequest): Promise<ApiResponse<AuthorizationCode>> {
|
||||
return Axios.put(`/api/v1/authorization-codes/${id}`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除授权
|
||||
*/
|
||||
export function deleteLicense(id: string): Promise<ApiResponse> {
|
||||
return Axios.delete(`/api/licenses/${id}`)
|
||||
return Axios.delete(`/api/v1/authorization-codes/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活授权
|
||||
* 锁定/解锁授权码
|
||||
*/
|
||||
export function activateLicense(id: string): Promise<ApiResponse<License>> {
|
||||
return Axios.patch(`/api/licenses/${id}/activate`)
|
||||
export function lockAuthorizationCode(
|
||||
id: string,
|
||||
data: { is_locked: boolean; lock_reason?: string; reason?: string }
|
||||
): Promise<ApiResponse<AuthorizationCode>> {
|
||||
return Axios.put(`/api/v1/authorization-codes/${id}/lock`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用授权
|
||||
*/
|
||||
export function deactivateLicense(id: string): Promise<ApiResponse<License>> {
|
||||
return Axios.patch(`/api/licenses/${id}/deactivate`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权统计数据
|
||||
*/
|
||||
export function getLicenseStats(): Promise<ApiResponse<LicenseStats>> {
|
||||
return Axios.get('/api/licenses/stats')
|
||||
return Axios.get('/api/v1/authorization-codes/stats')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,6 +169,20 @@ export function getLicensesByCustomer(customerId: string, params?: Omit<LicenseQ
|
||||
/**
|
||||
* 续期授权
|
||||
*/
|
||||
export function renewLicense(id: string, expiry_date: string): Promise<ApiResponse<License>> {
|
||||
return Axios.patch(`/api/licenses/${id}/renew`, { expiry_date })
|
||||
export function renewLicense(id: string, expiry_date: string): Promise<ApiResponse<AuthorizationCode>> {
|
||||
return Axios.patch(`/api/v1/authorization-codes/${id}/renew`, { expiry_date })
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活授权
|
||||
*/
|
||||
export function activateLicense(id: string): Promise<ApiResponse<AuthorizationCode>> {
|
||||
return Axios.patch(`/api/v1/authorization-codes/${id}/activate`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用授权
|
||||
*/
|
||||
export function deactivateLicense(id: string): Promise<ApiResponse<AuthorizationCode>> {
|
||||
return Axios.patch(`/api/v1/authorization-codes/${id}/deactivate`)
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 178 KiB |
@@ -78,7 +78,8 @@ const router = useRouter()
|
||||
const navItems = computed(() => {
|
||||
return defaultNavItems.value.map(item => ({
|
||||
...item,
|
||||
active: route.path === item.href
|
||||
// 对于有子路由的项目,匹配路径前缀
|
||||
active: route.path === item.href || route.path.startsWith(item.href + '/')
|
||||
}))
|
||||
})
|
||||
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
"dashboard": "Dashboard",
|
||||
"customers": "Customer Management",
|
||||
"licenses": "License Management",
|
||||
"licenseList": "License List",
|
||||
"createLicense": "Create License",
|
||||
"roles": "Roles & Permissions",
|
||||
"users": "System Users",
|
||||
"login": "Login",
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
"dashboard": "ダッシュボード",
|
||||
"customers": "顧客管理",
|
||||
"licenses": "ライセンス管理",
|
||||
"licenseList": "ライセンス一覧",
|
||||
"createLicense": "ライセンス作成",
|
||||
"roles": "ロールと権限",
|
||||
"users": "システムユーザー",
|
||||
"login": "ログイン",
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
"dashboard": "仪表盘",
|
||||
"customers": "客户管理",
|
||||
"licenses": "授权管理",
|
||||
"licenseList": "授权列表",
|
||||
"createLicense": "创建授权",
|
||||
"roles": "角色权限",
|
||||
"users": "系统用户",
|
||||
"login": "登录",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: 13895237362 2205451508@qq.com
|
||||
* @Date: 2025-08-01 09:32:42
|
||||
* @LastEditors: 13895237362 2205451508@qq.com
|
||||
* @LastEditTime: 2025-08-14 09:10:33
|
||||
* @LastEditTime: 2025-10-13 16:00:25
|
||||
* @FilePath: /frontend/src/router/index.ts
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
*/
|
||||
@@ -22,7 +22,7 @@ const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/dashboard",
|
||||
component: () => import("@/views/Dashboard.vue"),
|
||||
meta: { title: "仪表板", requiresAuth: true }
|
||||
meta: { title: "仪表盘", requiresAuth: true }
|
||||
},
|
||||
{
|
||||
path: "/customers",
|
||||
@@ -31,8 +31,23 @@ const routes: Array<RouteRecordRaw> = [
|
||||
},
|
||||
{
|
||||
path: "/licenses",
|
||||
name: "licenses",
|
||||
component: () => import("@/views/Licenses/index.vue"),
|
||||
meta: { title: "授权管理", requiresAuth: true }
|
||||
meta: { title: "授权管理", requiresAuth: true },
|
||||
children: [
|
||||
{
|
||||
path: "list",
|
||||
name: "licenses-list",
|
||||
component: () => import("@/views/Licenses/LinenseList.vue"),
|
||||
meta: { title: "授权列表", requiresAuth: true }
|
||||
},
|
||||
{
|
||||
path: "create",
|
||||
name: "licenses-create",
|
||||
component: () => import("@/views/Licenses/LicenseForm.vue"),
|
||||
meta: { title: "创建授权", requiresAuth: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: "/roles",
|
||||
@@ -56,7 +71,7 @@ router.beforeEach((to, _from, next) => {
|
||||
// 设置页面标题
|
||||
document.title = typeof (to.meta.title) === "string" ? to.meta.title : "授权管理平台";
|
||||
|
||||
// 检查是否需要认证
|
||||
// 检查是否需要认�?
|
||||
if (to.meta.requiresAuth) {
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) {
|
||||
@@ -69,3 +84,4 @@ router.beforeEach((to, _from, next) => {
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -37,6 +37,40 @@ export function useBreadcrumb() {
|
||||
const breadcrumbs = computed<BreadcrumbItem[]>(() => {
|
||||
const currentPath = route.path
|
||||
|
||||
// 特殊处理授权管理子路由
|
||||
if (currentPath.startsWith('/licenses/')) {
|
||||
const items: BreadcrumbItem[] = []
|
||||
|
||||
// 添加授权管理作为父级
|
||||
items.push({
|
||||
title: t('navigation.breadcrumb.licenses'),
|
||||
path: '/licenses'
|
||||
})
|
||||
|
||||
// 如果有客户名称查询参数,显示客户名称
|
||||
if (route.query.customerName && typeof route.query.customerName === 'string') {
|
||||
items.push({
|
||||
title: route.query.customerName
|
||||
})
|
||||
} else {
|
||||
// 否则显示当前路由的标题
|
||||
const pathSegments = currentPath.split('/').filter(Boolean)
|
||||
const lastSegment = pathSegments[pathSegments.length - 1]
|
||||
|
||||
if (lastSegment === 'list') {
|
||||
items.push({
|
||||
title: t('navigation.breadcrumb.licenseList')
|
||||
})
|
||||
} else if (lastSegment === 'create') {
|
||||
items.push({
|
||||
title: t('navigation.breadcrumb.createLicense')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
// 从配置中获取面包屑
|
||||
const configKeys = routeBreadcrumbKeys[currentPath]
|
||||
if (configKeys) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: 13895237362 2205451508@qq.com
|
||||
* @Date: 2025-08-12 00:00:00
|
||||
* @LastEditors: 13895237362 2205451508@qq.com
|
||||
* @LastEditTime: 2025-09-29 17:29:42
|
||||
* @LastEditTime: 2025-10-16 15:29:00
|
||||
* @FilePath: /frontend/src/views/Licenses.vue
|
||||
* @Description: 授权管理页面
|
||||
-->
|
||||
@@ -10,7 +10,7 @@
|
||||
<Layout app-name="Cedar-V" :page-title="t('pages.licenses.title')">
|
||||
<div class="license-container">
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="main-content">
|
||||
<div v-if="!showSubRoute" class="main-content">
|
||||
<!-- 背景图片 -->
|
||||
<div class="background-section">
|
||||
<!-- 中央标题 -->
|
||||
@@ -70,223 +70,40 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 授权列表区域 -->
|
||||
<div v-if="showLicenseList" class="license-list-section">
|
||||
<div class="list-header">
|
||||
<div class="search-controls">
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
:placeholder="t('pages.licenses.search.placeholder')"
|
||||
prefix-icon="Search"
|
||||
clearable
|
||||
size="large"
|
||||
class="search-input"
|
||||
@input="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
:range-separator="t('pages.licenses.search.dateRange')"
|
||||
:start-placeholder="t('pages.licenses.search.startDate')"
|
||||
:end-placeholder="t('pages.licenses.search.endDate')"
|
||||
size="large"
|
||||
class="date-picker"
|
||||
@change="handleDateRangeChange"
|
||||
/>
|
||||
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="refreshLicenseList"
|
||||
>
|
||||
{{ t('pages.licenses.actions.refresh') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 授权表格 -->
|
||||
<div class="table-container">
|
||||
<el-table
|
||||
:data="licenseList"
|
||||
v-loading="loading"
|
||||
:element-loading-text="t('pages.licenses.table.loading')"
|
||||
stripe
|
||||
style="width: 100%"
|
||||
class="license-table"
|
||||
>
|
||||
<el-table-column
|
||||
prop="license_code"
|
||||
:label="t('pages.licenses.table.licenseCode')"
|
||||
width="200"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="customer_name"
|
||||
:label="t('pages.licenses.table.customerName')"
|
||||
width="180"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="description"
|
||||
:label="t('pages.licenses.table.description')"
|
||||
min-width="200"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="status"
|
||||
:label="t('pages.licenses.table.status')"
|
||||
width="120"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="getStatusType(row.status)"
|
||||
effect="plain"
|
||||
>
|
||||
{{ getStatusText(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="license_type_display"
|
||||
:label="t('pages.licenses.table.licenseType')"
|
||||
width="140"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="expiry_date"
|
||||
:label="t('pages.licenses.table.expiryDate')"
|
||||
width="180"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.expiry_date) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="created_at"
|
||||
:label="t('pages.licenses.table.createTime')"
|
||||
width="180"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.created_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
:label="t('pages.licenses.table.operation')"
|
||||
width="200"
|
||||
fixed="right"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleEdit(row)"
|
||||
>
|
||||
{{ t('pages.licenses.actions.edit') }}
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="row.status === 'inactive'"
|
||||
type="success"
|
||||
size="small"
|
||||
@click="handleActivate(row)"
|
||||
>
|
||||
{{ t('pages.licenses.actions.activate') }}
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="row.status === 'active'"
|
||||
type="warning"
|
||||
size="small"
|
||||
@click="handleDeactivate(row)"
|
||||
>
|
||||
{{ t('pages.licenses.actions.deactivate') }}
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(row)"
|
||||
>
|
||||
{{ t('pages.licenses.actions.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 子路由视图区域 -->
|
||||
<div v-if="showSubRoute" class="sub-route-section">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 创建/编辑授权对话框 -->
|
||||
<LicenseForm
|
||||
v-model:visible="formDialogVisible"
|
||||
:license-data="editingLicense"
|
||||
:customers="customers"
|
||||
@success="handleFormSuccess"
|
||||
/>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ref, onMounted, computed, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import Layout from '@/components/common/layout/Layout.vue'
|
||||
import LicenseForm from './LicenseForm.vue'
|
||||
import { getLicenses, deleteLicense, activateLicense, deactivateLicense, type License, type LicenseQueryRequest } from '@/api/license'
|
||||
import { getCustomers, type Customer } from '@/api/customer'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// 响应式数据
|
||||
const selectedCustomer = ref<string>('')
|
||||
const customers = ref<Customer[]>([])
|
||||
const showLicenseList = ref(false)
|
||||
const searchText = ref('')
|
||||
const dateRange = ref<[Date, Date] | null>(null)
|
||||
const loading = ref(false)
|
||||
const licenseList = ref<License[]>([])
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(20)
|
||||
const total = ref(0)
|
||||
const formDialogVisible = ref(false)
|
||||
const editingLicense = ref<License | null>(null)
|
||||
const showSubRoute = ref(false)
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive<LicenseQueryRequest>({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
search: '',
|
||||
customer_id: '',
|
||||
sort: 'created_at',
|
||||
order: 'desc'
|
||||
// 选中的客户信息
|
||||
const selectedCustomerInfo = computed(() => {
|
||||
if (!selectedCustomer.value) return null
|
||||
return customers.value.find(c => c.id === selectedCustomer.value) || null
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
// const formattedCustomers = computed(() => {
|
||||
// return customers.value.filter(customer => customer.status === 'active')
|
||||
// })
|
||||
|
||||
// 方法
|
||||
const loadCustomers = async () => {
|
||||
@@ -299,190 +116,45 @@ const loadCustomers = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const loadLicenseList = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
const response = await getLicenses(queryParams)
|
||||
licenseList.value = response.data.list
|
||||
total.value = response.data.total
|
||||
currentPage.value = response.data.page
|
||||
} catch (error) {
|
||||
console.error('Failed to load licenses:', error)
|
||||
ElMessage.error(t('pages.licenses.message.loadError'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleCustomerChange = (value: string) => {
|
||||
queryParams.customer_id = value
|
||||
const handleCustomerChange = () => {
|
||||
// 客户选择变化时的处理逻辑
|
||||
}
|
||||
|
||||
const handleQuery = () => {
|
||||
showLicenseList.value = true
|
||||
queryParams.page = 1
|
||||
currentPage.value = 1
|
||||
loadLicenseList()
|
||||
// 跳转到列表页,并传递客户信息参数
|
||||
showSubRoute.value = true
|
||||
router.push({
|
||||
name: 'licenses-list',
|
||||
query: {
|
||||
customerId: selectedCustomer.value || '',
|
||||
customerName: selectedCustomerInfo.value?.customer_name || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleCreateLicense = () => {
|
||||
editingLicense.value = null
|
||||
formDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
queryParams.search = searchText.value
|
||||
queryParams.page = 1
|
||||
currentPage.value = 1
|
||||
if (showLicenseList.value) {
|
||||
loadLicenseList()
|
||||
}
|
||||
}
|
||||
|
||||
const handleDateRangeChange = (value: [Date, Date] | null) => {
|
||||
if (value) {
|
||||
queryParams.start_date = value[0].toISOString().split('T')[0]
|
||||
queryParams.end_date = value[1].toISOString().split('T')[0]
|
||||
} else {
|
||||
queryParams.start_date = undefined
|
||||
queryParams.end_date = undefined
|
||||
}
|
||||
|
||||
if (showLicenseList.value) {
|
||||
queryParams.page = 1
|
||||
currentPage.value = 1
|
||||
loadLicenseList()
|
||||
}
|
||||
}
|
||||
|
||||
const refreshLicenseList = () => {
|
||||
if (showLicenseList.value) {
|
||||
loadLicenseList()
|
||||
}
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
queryParams.page_size = size
|
||||
queryParams.page = 1
|
||||
currentPage.value = 1
|
||||
loadLicenseList()
|
||||
}
|
||||
|
||||
const handleCurrentChange = (page: number) => {
|
||||
queryParams.page = page
|
||||
loadLicenseList()
|
||||
}
|
||||
|
||||
const handleEdit = (license: License) => {
|
||||
editingLicense.value = license
|
||||
formDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleActivate = async (license: License) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
t('pages.licenses.confirm.activateMessage', { code: license.license_code }),
|
||||
t('pages.licenses.confirm.activateTitle'),
|
||||
{
|
||||
confirmButtonText: t('pages.licenses.confirm.confirm'),
|
||||
cancelButtonText: t('pages.licenses.confirm.cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
|
||||
await activateLicense(license.id)
|
||||
ElMessage.success(t('pages.licenses.message.activateSuccess'))
|
||||
loadLicenseList()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('Failed to activate license:', error)
|
||||
ElMessage.error('激活授权失败')
|
||||
// 跳转到创建授权页,并传递客户信息参数
|
||||
showSubRoute.value = true
|
||||
router.push({
|
||||
name: 'licenses-create',
|
||||
query: {
|
||||
customerId: selectedCustomer.value || '',
|
||||
customerName: selectedCustomerInfo.value?.customer_name || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeactivate = async (license: License) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
t('pages.licenses.confirm.deactivateMessage', { code: license.license_code }),
|
||||
t('pages.licenses.confirm.deactivateTitle'),
|
||||
{
|
||||
confirmButtonText: t('pages.licenses.confirm.confirm'),
|
||||
cancelButtonText: t('pages.licenses.confirm.cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
|
||||
await deactivateLicense(license.id)
|
||||
ElMessage.success(t('pages.licenses.message.deactivateSuccess'))
|
||||
loadLicenseList()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('Failed to deactivate license:', error)
|
||||
ElMessage.error('停用授权失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleDelete = async (license: License) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
t('pages.licenses.confirm.deleteMessage', { code: license.license_code }),
|
||||
t('pages.licenses.confirm.deleteTitle'),
|
||||
{
|
||||
confirmButtonText: t('pages.licenses.confirm.confirm'),
|
||||
cancelButtonText: t('pages.licenses.confirm.cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
|
||||
await deleteLicense(license.id)
|
||||
ElMessage.success(t('pages.licenses.message.deleteSuccess'))
|
||||
loadLicenseList()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('Failed to delete license:', error)
|
||||
ElMessage.error(t('pages.licenses.message.deleteError'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleFormSuccess = () => {
|
||||
formDialogVisible.value = false
|
||||
if (showLicenseList.value) {
|
||||
loadLicenseList()
|
||||
}
|
||||
}
|
||||
|
||||
const getStatusType = (status: string) => {
|
||||
switch (status) {
|
||||
case 'active':
|
||||
return 'success'
|
||||
case 'inactive':
|
||||
return 'info'
|
||||
case 'expired':
|
||||
return 'danger'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
const getStatusText = (status: string) => {
|
||||
return t(`pages.licenses.status.${status}`)
|
||||
}
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
if (!dateString) return '--'
|
||||
const date = new Date(dateString)
|
||||
return date.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 监听路由变化,控制子路由显示
|
||||
watch(() => route.name, (newName) => {
|
||||
// 如果是子路由,显示子路由区域
|
||||
showSubRoute.value = newName === 'licenses-list' || newName === 'licenses-create'
|
||||
}, { immediate: true })
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
loadCustomers()
|
||||
@@ -684,6 +356,14 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.sub-route-section {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.license-list-section {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
|
||||
Reference in new issue
Block a user