fetch(modify):修复API的URL
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m1s

This commit is contained in:
sexygoat
2026-02-03 10:04:59 +08:00
parent 06cde977ad
commit 2c6fe4375b
17 changed files with 225 additions and 205 deletions

View File

@@ -9,7 +9,7 @@
import zh from 'element-plus/es/locale/lang/zh-cn'
import en from 'element-plus/es/locale/lang/en'
import { systemUpgrade } from '@/utils'
import { UserService } from './api/usersApi'
import { AuthService } from '@/api/modules'
import { ApiStatus } from './utils/http/status'
import { setThemeTransitionClass } from '@/utils'
import { checkStorageCompatibility } from '@/utils'
@@ -41,7 +41,7 @@
const getUserInfo = async () => {
if (userStore.isLogin && userStore.accessToken) {
try {
const res = await UserService.getUserInfo()
const res = await AuthService.getUserInfo()
if (res.code === ApiStatus.success && res.data) {
// API 返回的是 { user, permissions },我们需要保存 user 和 permissions
userStore.setUserInfo(res.data.user)

View File

@@ -1,54 +0,0 @@
/**
* 认证相关 API
*/
import request from '@/utils/http'
import {
BaseResponse,
LoginParams,
LoginData,
UserInfoResponse,
RefreshTokenData
} from '@/types/api'
export class AuthService {
/**
* 用户登录
* @param params 登录参数
*/
static login(params: LoginParams): Promise<BaseResponse<LoginData>> {
return request.post<BaseResponse<LoginData>>({
url: '/api/admin/login',
data: params
})
}
/**
* 获取用户信息
* GET /api/admin/me
*/
static getUserInfo(): Promise<BaseResponse<UserInfoResponse>> {
return request.get<BaseResponse<UserInfoResponse>>({
url: '/api/admin/me'
})
}
/**
* 用户登出
*/
static logout(): Promise<BaseResponse<void>> {
return request.post<BaseResponse<void>>({
url: '/api/admin/logout'
})
}
/**
* 刷新 Token
* @param refreshToken 刷新令牌
*/
static refreshToken(refreshToken: string): Promise<BaseResponse<RefreshTokenData>> {
return request.post<BaseResponse<RefreshTokenData>>({
url: '/api/auth/refresh',
data: { refreshToken }
})
}
}

View File

@@ -92,4 +92,24 @@ export class AccountService extends BaseService {
static removeRoleFromAccount(accountId: number, roleId: number): Promise<BaseResponse> {
return this.delete<BaseResponse>(`/api/admin/accounts/${accountId}/roles/${roleId}`)
}
/**
* 修改账号密码
* PUT /api/admin/accounts/{id}/password
* @param id 账号ID
* @param password 新密码
*/
static updateAccountPassword(id: number, password: string): Promise<BaseResponse> {
return this.put<BaseResponse>(`/api/admin/accounts/${id}/password`, { password })
}
/**
* 修改账号状态
* PUT /api/admin/accounts/{id}/status
* @param id 账号ID
* @param status 状态 (0:禁用, 1:启用)
*/
static updateAccountStatus(id: number, status: 0 | 1): Promise<BaseResponse> {
return this.put<BaseResponse>(`/api/admin/accounts/${id}/status`, { status })
}
}

View File

@@ -16,42 +16,42 @@ import type {
export class AuthService extends BaseService {
/**
* 用户登录
* 用户登录(统一认证接口)
* @param params 登录参数
*/
static login(params: LoginParams): Promise<BaseResponse<LoginData>> {
return this.post<BaseResponse<LoginData>>('/api/admin/login', params)
return this.post<BaseResponse<LoginData>>('/api/auth/login', params)
}
/**
* 退出登录
* 退出登录(统一认证接口)
*/
static logout(): Promise<BaseResponse> {
return this.post<BaseResponse>('/api/admin/logout')
return this.post<BaseResponse>('/api/auth/logout')
}
/**
* 获取当前用户信息
* GET /api/admin/me
* 获取当前用户信息(统一认证接口)
* GET /api/auth/me
*/
static getUserInfo(): Promise<BaseResponse<UserInfoResponse>> {
return this.get<BaseResponse<UserInfoResponse>>('/api/admin/me')
return this.get<BaseResponse<UserInfoResponse>>('/api/auth/me')
}
/**
* 刷新 Token
* 刷新 Token(统一认证接口)
* @param params 刷新参数
*/
static refreshToken(params: RefreshTokenParams): Promise<BaseResponse<RefreshTokenData>> {
return this.post<BaseResponse<RefreshTokenData>>('/api/auth/refresh', params)
return this.post<BaseResponse<RefreshTokenData>>('/api/auth/refresh-token', params)
}
/**
* 修改密码
* 修改密码(统一认证接口)
* @param params 修改密码参数
*/
static changePassword(params: ChangePasswordParams): Promise<BaseResponse> {
return this.post<BaseResponse>('/api/auth/change-password', params)
return this.put<BaseResponse>('/api/auth/password', params)
}
/**

View File

@@ -1,5 +1,14 @@
/**
* 客户账号管理 API
* 客户账号管理 API (企业账号)
*
* @deprecated 此 API 已废弃,请使用统一的 AccountService 代替
* @see AccountService - 统一账号管理接口 (/api/admin/accounts)
*
* 迁移说明:
* - 所有账号类型统一使用 /api/admin/accounts 接口
* - 通过 user_type 参数区分账号类型 (2=平台, 3=代理, 4=企业)
* - customer-accounts 已改名为 enterprise企业账号
* - 详见docs/迁移指南.md
*/
import { BaseService } from '../BaseService'

View File

@@ -1,5 +1,13 @@
/**
* 平台账号相关 API - 匹配后端实际接口
*
* @deprecated 此 API 已废弃,请使用统一的 AccountService 代替
* @see AccountService - 统一账号管理接口 (/api/admin/accounts)
*
* 迁移说明:
* - 所有账号类型统一使用 /api/admin/accounts 接口
* - 通过 user_type 参数区分账号类型 (2=平台, 3=代理, 4=企业)
* - 详见docs/迁移指南.md
*/
import { BaseService } from '../BaseService'

View File

@@ -1,5 +1,13 @@
/**
* 代理账号相关 API - 匹配后端实际接口
*
* @deprecated 此 API 已废弃,请使用统一的 AccountService 代替
* @see AccountService - 统一账号管理接口 (/api/admin/accounts)
*
* 迁移说明:
* - 所有账号类型统一使用 /api/admin/accounts 接口
* - 通过 user_type 参数区分账号类型 (2=平台, 3=代理, 4=企业)
* - 详见docs/迁移指南.md
*/
import { BaseService } from '../BaseService'

View File

@@ -1,39 +0,0 @@
import request from '@/utils/http'
import { BaseResponse, UserInfoResponse } from '@/types/api'
interface LoginParams {
username: string
password: string
device?: string
}
interface UserListParams {
current?: number
size?: number
}
export class UserService {
// 登录
static login(params: LoginParams) {
return request.post<BaseResponse>({
url: '/api/admin/login',
params
})
}
// 获取用户信息
// GET /api/admin/me
static getUserInfo() {
return request.get<BaseResponse<UserInfoResponse>>({
url: '/api/admin/me'
})
}
// 获取用户列表
static getUserList(params?: UserListParams) {
return request.get<BaseResponse>({
url: '/api/user/list',
params
})
}
}

View File

@@ -12,7 +12,7 @@
<!-- 表格 -->
<ArtTable
ref="tableRef"
row-key="id"
row-key="ID"
:loading="loading"
:data="accountList"
height="60vh"
@@ -24,7 +24,7 @@
@current-change="handleCurrentChange"
>
<template #default>
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
<ElTableColumn v-for="col in columns" :key="col.prop || (col as any).type" v-bind="col" />
</template>
</ArtTable>
</ElDialog>
@@ -33,23 +33,25 @@
<script setup lang="ts">
import { h } from 'vue'
import { ElMessage, ElTag } from 'element-plus'
import { CustomerAccountService } from '@/api/modules'
import { AccountService } from '@/api/modules'
import type { SearchFormItem } from '@/types'
import type { PlatformAccount } from '@/types/api'
import { formatDateTime } from '@/utils/business/format'
interface CustomerAccount {
id: number
username: string
phone: string
user_type: number
user_type_name: string
shop_id: number | null
shop_name: string
enterprise_id: number | null
enterprise_name: string
status: number
status_name: string
created_at: string
// 用户类型映射
const getUserTypeName = (type: number): string => {
const typeMap: Record<number, string> = {
1: '超级管理员',
2: '平台用户',
3: '代理账号',
4: '企业账号'
}
return typeMap[type] || '未知'
}
// 状态名称映射
const getStatusName = (status: number): string => {
return status === 1 ? '启用' : '禁用'
}
const props = defineProps<{
@@ -69,7 +71,7 @@
const loading = ref(false)
const tableRef = ref()
const accountList = ref<CustomerAccount[]>([])
const accountList = ref<PlatformAccount[]>([])
// 搜索表单初始值
const initialSearchState = {
@@ -160,40 +162,38 @@
width: 130
},
{
prop: 'user_type_name',
prop: 'user_type',
label: '用户类型',
width: 110,
formatter: (row: CustomerAccount) => {
return h(ElTag, { type: getUserTypeTag(row.user_type) }, () => row.user_type_name)
formatter: (row: PlatformAccount) => {
return h(ElTag, { type: getUserTypeTag(row.user_type) }, () => getUserTypeName(row.user_type))
}
},
{
prop: 'shop_name',
label: '店铺名称',
minWidth: 150,
showOverflowTooltip: true,
formatter: (row: CustomerAccount) => row.shop_name || '-'
prop: 'shop_id',
label: '店铺ID',
width: 100,
formatter: (row: PlatformAccount) => row.shop_id || '-'
},
{
prop: 'enterprise_name',
label: '企业名称',
minWidth: 150,
showOverflowTooltip: true,
formatter: (row: CustomerAccount) => row.enterprise_name || '-'
prop: 'enterprise_id',
label: '企业ID',
width: 100,
formatter: (row: PlatformAccount) => row.enterprise_id || '-'
},
{
prop: 'status',
label: '状态',
width: 100,
formatter: (row: CustomerAccount) => {
return h(ElTag, { type: getStatusTag(row.status) }, () => row.status_name)
formatter: (row: PlatformAccount) => {
return h(ElTag, { type: getStatusTag(row.status) }, () => getStatusName(row.status))
}
},
{
prop: 'created_at',
prop: 'CreatedAt',
label: '创建时间',
width: 180,
formatter: (row: CustomerAccount) => formatDateTime(row.created_at)
formatter: (row: PlatformAccount) => formatDateTime(row.CreatedAt)
}
])
@@ -213,7 +213,7 @@
try {
const params: any = {
page: pagination.page,
page_size: pagination.pageSize,
pageSize: pagination.pageSize,
username: searchForm.username || undefined,
phone: searchForm.phone || undefined,
user_type: searchForm.user_type,
@@ -235,7 +235,7 @@
}
})
const res = await CustomerAccountService.getCustomerAccounts(params)
const res = await AccountService.getAccounts(params)
if (res.code === 0) {
accountList.value = res.data.items || []
pagination.total = res.data.total || 0

View File

@@ -10,7 +10,7 @@ import type { FormInstance, FormRules } from 'element-plus'
import { useUserStore } from '@/store/modules/user'
import { HOME_PAGE } from '@/router/routesAlias'
import AppConfig from '@/config'
import { AuthService } from '@/api/authApi'
import { AuthService } from '@/api/modules'
import { ApiStatus } from '@/utils/http/status'
import { MOCK_ACCOUNTS, mockLogin, mockGetUserInfo, type MockAccount } from '@/mock/auth'
import { saveCredentials, getRememberedCredentials } from '@/utils/auth/rememberPassword'

View File

@@ -317,6 +317,7 @@ function buildRouteMap(routes: AppRouteRecord[], parentPath = ''): Map<string, A
/**
* 将后端菜单数据转换为路由格式
* 递归处理所有层级的 children
*/
function convertBackendMenuToRoute(
menu: any,
@@ -328,6 +329,32 @@ function convertBackendMenuToRoute(
if (!matchedRoute) {
console.warn(`未找到与菜单 URL "${menuUrl}" 匹配的路由定义: ${menu.name}`)
// 如果当前菜单没有匹配的路由,但有 children尝试递归处理 children
if (menu.children && menu.children.length > 0) {
const children = menu.children
.map((child: any) => convertBackendMenuToRoute(child, routeMap, menuUrl))
.filter((child: AppRouteRecord | null) => child !== null)
// 如果子菜单有有效的路由,返回一个包含子菜单的占位路由
if (children.length > 0) {
return {
path: menuUrl,
name: menu.name || menuUrl.replace(/\//g, '_'),
meta: {
title: menu.name,
permission: menu.perm_code,
sort: menu.sort || 0,
icon: menu.icon,
isHide: false,
roles: undefined,
permissions: undefined
},
children: children
} as AppRouteRecord
}
}
return null
}
@@ -347,6 +374,7 @@ function convertBackendMenuToRoute(
}
}
// 递归处理所有层级的 children
if (menu.children && menu.children.length > 0) {
const children = menu.children
.map((child: any) => convertBackendMenuToRoute(child, routeMap, menuUrl))

View File

@@ -45,6 +45,7 @@ export interface PermissionTreeNode {
url?: string // 请求路径
platform?: string // 适用端口 (all:全部, web:Web后台, h5:H5端)
sort?: number // 排序值
status?: number // 状态 (0:禁用, 1:启用)
available_for_role_types?: string // 可用角色类型 (1:平台角色, 2:客户角色)
children?: PermissionTreeNode[] // 子权限列表
}

View File

@@ -44,11 +44,3 @@ export interface PlatformRoleFormData {
role_type: RoleType
status: RoleStatus
}
// 权限树节点
export interface PermissionTreeNode {
id: number
label: string
value: string
children?: PermissionTreeNode[]
}

View File

@@ -165,9 +165,9 @@
import type { FormRules } from 'element-plus'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import { PlatformAccountService, RoleService } from '@/api/modules'
import { AccountService, RoleService } from '@/api/modules'
import type { SearchFormItem } from '@/types'
import type { PlatformRole, PlatformAccountResponse } from '@/types/api'
import type { PlatformRole, PlatformAccount } from '@/types/api'
import { formatDateTime } from '@/utils/business/format'
import { CommonStatus, getStatusText, STATUS_SELECT_OPTIONS } from '@/config/constants'
@@ -202,7 +202,7 @@
})
// 表格数据
const tableData = ref<PlatformAccountResponse[]>([])
const tableData = ref<PlatformAccount[]>([])
// 表格实例引用
const tableRef = ref()
@@ -268,7 +268,7 @@
]
// 显示对话框
const showDialog = (type: string, row?: PlatformAccountResponse) => {
const showDialog = (type: string, row?: PlatformAccount) => {
dialogVisible.value = true
dialogType.value = type
@@ -284,7 +284,7 @@
formData.user_type = row.user_type
formData.enterprise_id = row.enterprise_id || null
formData.shop_id = row.shop_id || null
formData.status = row.status
formData.status = row.status as CommonStatus
formData.password = ''
} else {
formData.id = 0
@@ -299,7 +299,7 @@
}
// 删除账号
const deleteAccount = (row: PlatformAccountResponse) => {
const deleteAccount = (row: PlatformAccount) => {
ElMessageBox.confirm(`确定要删除平台账号 ${row.username} 吗?`, '删除平台账号', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@@ -307,7 +307,7 @@
})
.then(async () => {
try {
await PlatformAccountService.deletePlatformAccount(row.ID)
await AccountService.deleteAccount(row.ID)
ElMessage.success('删除成功')
getAccountList()
} catch (error) {
@@ -320,7 +320,7 @@
}
// 显示修改密码对话框
const showPasswordDialog = (row: PlatformAccountResponse) => {
const showPasswordDialog = (row: PlatformAccount) => {
currentAccountId.value = row.ID
passwordForm.new_password = ''
passwordDialogVisible.value = true
@@ -346,7 +346,7 @@
{
prop: 'user_type',
label: '账号类型',
formatter: (row: PlatformAccountResponse) => {
formatter: (row: PlatformAccount) => {
const typeMap: Record<number, string> = {
1: '超级管理员',
2: '平台用户',
@@ -359,7 +359,7 @@
{
prop: 'status',
label: '状态',
formatter: (row: PlatformAccountResponse) => {
formatter: (row: PlatformAccount) => {
return h(ElSwitch, {
modelValue: row.status,
activeValue: CommonStatus.ENABLED,
@@ -375,14 +375,14 @@
{
prop: 'CreatedAt',
label: '创建时间',
formatter: (row: PlatformAccountResponse) => formatDateTime(row.CreatedAt)
formatter: (row: PlatformAccount) => formatDateTime(row.CreatedAt)
},
{
prop: 'operation',
label: '操作',
width: 240,
fixed: 'right',
formatter: (row: PlatformAccountResponse) => {
formatter: (row: PlatformAccount) => {
return h('div', { style: 'display: flex; gap: 8px;' }, [
h(ArtButtonTable, {
icon: '&#xe72b;',
@@ -444,7 +444,7 @@
}
// 显示分配角色对话框
const showRoleDialog = async (row: PlatformAccountResponse) => {
const showRoleDialog = async (row: PlatformAccount) => {
currentAccountId.value = row.ID
selectedRoles.value = []
@@ -453,7 +453,7 @@
await loadAllRoles()
// 先加载当前账号的角色,再打开对话框
const res = await PlatformAccountService.getPlatformAccountRoles(row.ID)
const res = await AccountService.getAccountRoles(row.ID)
if (res.code === 0) {
// 提取角色ID数组
const roles = res.data || []
@@ -470,9 +470,7 @@
const handleAssignRoles = async () => {
roleSubmitLoading.value = true
try {
await PlatformAccountService.assignRolesToPlatformAccount(currentAccountId.value, {
role_ids: selectedRoles.value
})
await AccountService.assignRolesToAccount(currentAccountId.value, selectedRoles.value)
ElMessage.success('分配角色成功')
roleDialogVisible.value = false
// 刷新列表以更新角色显示
@@ -492,9 +490,10 @@
if (valid) {
passwordSubmitLoading.value = true
try {
await PlatformAccountService.changePlatformAccountPassword(currentAccountId.value, {
new_password: passwordForm.new_password
})
await AccountService.updateAccountPassword(
currentAccountId.value,
passwordForm.new_password
)
ElMessage.success('修改密码成功')
passwordDialogVisible.value = false
} catch (error) {
@@ -512,12 +511,13 @@
try {
const params = {
page: pagination.currentPage,
page_size: pagination.pageSize,
pageSize: pagination.pageSize,
user_type: 2, // 筛选平台账号
username: searchForm.username || undefined,
phone: searchForm.phone || undefined,
status: searchForm.status
}
const res = await PlatformAccountService.getPlatformAccounts(params)
const res = await AccountService.getAccounts(params)
if (res.code === 0) {
tableData.value = res.data.items || []
pagination.total = res.data.total || 0
@@ -611,16 +611,15 @@
data.enterprise_id = formData.enterprise_id
}
await PlatformAccountService.createPlatformAccount(data)
await AccountService.createAccount(data)
ElMessage.success('新增成功')
} else {
const data: any = {
username: formData.username,
phone: formData.phone,
status: formData.status
phone: formData.phone
}
await PlatformAccountService.updatePlatformAccount(formData.id, data)
await AccountService.updateAccount(formData.id, data)
ElMessage.success('更新成功')
}
@@ -652,7 +651,7 @@
// 先更新UI
row.status = newStatus
try {
await PlatformAccountService.updatePlatformAccount(row.ID, { status: newStatus })
await AccountService.updateAccountStatus(row.ID, newStatus as 0 | 1)
ElMessage.success('状态切换成功')
} catch (error) {
// 切换失败,恢复原状态

View File

@@ -126,9 +126,9 @@
import type { FormRules } from 'element-plus'
import { useCheckedColumns } from '@/composables/useCheckedColumns'
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
import { ShopAccountService, ShopService } from '@/api/modules'
import { AccountService, ShopService } from '@/api/modules'
import type { SearchFormItem } from '@/types'
import type { ShopAccountResponse, ShopResponse } from '@/types/api'
import type { PlatformAccount, ShopResponse } from '@/types/api'
import { formatDateTime } from '@/utils/business/format'
import { CommonStatus, getStatusText, STATUS_SELECT_OPTIONS } from '@/config/constants'
@@ -163,7 +163,7 @@
})
// 表格数据
const tableData = ref<ShopAccountResponse[]>([])
const tableData = ref<PlatformAccount[]>([])
// 表格实例引用
const tableRef = ref()
@@ -243,14 +243,14 @@
]
// 显示对话框
const showDialog = (type: string, row?: ShopAccountResponse) => {
const showDialog = (type: string, row?: PlatformAccount) => {
dialogType.value = type
if (type === 'edit' && row) {
formData.id = row.id
formData.id = row.ID
formData.username = row.username
formData.phone = row.phone
formData.shop_id = row.shop_id
formData.shop_id = row.shop_id || 0
formData.password = ''
} else {
formData.id = 0
@@ -269,8 +269,8 @@
}
// 显示修改密码对话框
const showPasswordDialog = (row: ShopAccountResponse) => {
currentAccountId.value = row.id
const showPasswordDialog = (row: PlatformAccount) => {
currentAccountId.value = row.ID
passwordForm.new_password = ''
// 重置表单验证状态
@@ -282,12 +282,12 @@
}
// 状态切换处理
const handleStatusChange = async (row: ShopAccountResponse, newStatus: number) => {
const handleStatusChange = async (row: PlatformAccount, newStatus: number) => {
const oldStatus = row.status
// 先更新UI
row.status = newStatus
try {
await ShopAccountService.updateShopAccountStatus(row.id, { status: newStatus })
await AccountService.updateAccountStatus(row.ID, newStatus as 0 | 1)
ElMessage.success('状态切换成功')
} catch (error) {
// 切换失败,恢复原状态
@@ -318,7 +318,7 @@
{
prop: 'status',
label: '状态',
formatter: (row: ShopAccountResponse) => {
formatter: (row: PlatformAccount) => {
return h(ElSwitch, {
modelValue: row.status,
activeValue: CommonStatus.ENABLED,
@@ -334,14 +334,14 @@
{
prop: 'created_at',
label: '创建时间',
formatter: (row: ShopAccountResponse) => formatDateTime(row.created_at)
formatter: (row: PlatformAccount) => formatDateTime(row.CreatedAt)
},
{
prop: 'operation',
label: '操作',
width: 120,
fixed: 'right',
formatter: (row: ShopAccountResponse) => {
formatter: (row: PlatformAccount) => {
return h('div', { style: 'display: flex; gap: 8px;' }, [
h(ArtButtonTable, {
icon: '&#xe722;',
@@ -447,9 +447,10 @@
if (valid) {
passwordSubmitLoading.value = true
try {
await ShopAccountService.updateShopAccountPassword(currentAccountId.value, {
new_password: passwordForm.new_password
})
await AccountService.updateAccountPassword(
currentAccountId.value,
passwordForm.new_password
)
ElMessage.success('重置密码成功')
passwordDialogVisible.value = false
} catch (error) {
@@ -467,13 +468,14 @@
try {
const params = {
page: pagination.currentPage,
page_size: pagination.pageSize,
pageSize: pagination.pageSize,
user_type: 3, // 筛选代理账号
username: searchForm.username || undefined,
phone: searchForm.phone || undefined,
shop_id: searchForm.shop_id,
status: searchForm.status
}
const res = await ShopAccountService.getShopAccounts(params)
const res = await AccountService.getAccounts(params)
if (res.code === 0) {
tableData.value = res.data.items || []
pagination.total = res.data.total || 0
@@ -536,17 +538,18 @@
username: formData.username,
password: formData.password,
phone: formData.phone,
user_type: 3, // 代理账号
shop_id: formData.shop_id
}
await ShopAccountService.createShopAccount(data)
await AccountService.createAccount(data)
ElMessage.success('新增成功')
} else {
const data = {
username: formData.username
}
await ShopAccountService.updateShopAccount(formData.id, data)
await AccountService.updateAccount(formData.id, data)
ElMessage.success('更新成功')
}

View File

@@ -89,6 +89,12 @@
<ElFormItem label="排序序号" prop="sort">
<ElInputNumber v-model="form.sort" :min="0" :max="9999" style="width: 100%" />
</ElFormItem>
<ElFormItem label="状态" prop="status">
<ElRadioGroup v-model="form.status">
<ElRadio :value="1">启用</ElRadio>
<ElRadio :value="0">禁用</ElRadio>
</ElRadioGroup>
</ElFormItem>
</ElForm>
<template #footer>
<div class="dialog-footer">
@@ -110,6 +116,8 @@
ElMessage,
ElMessageBox,
ElTag,
ElRadio,
ElRadioGroup,
type FormInstance,
type FormRules
} from 'element-plus'
@@ -123,7 +131,9 @@
PERMISSION_TYPE_OPTIONS,
PERMISSION_TYPE_SELECT_OPTIONS,
getPermissionTypeText,
getPermissionTypeTag
getPermissionTypeTag,
CommonStatus,
getStatusText
} from '@/config/constants'
defineOptions({ name: 'Permission' })
@@ -177,6 +187,7 @@
{ label: '权限类型', prop: 'perm_type' },
{ label: '菜单路径', prop: 'url' },
{ label: '适用端口', prop: 'platform' },
{ label: '状态', prop: 'status' },
{ label: '排序', prop: 'sort' },
{ label: '操作', prop: 'operation' }
]
@@ -195,14 +206,15 @@
// 表单引用和数据
const formRef = ref<FormInstance>()
const form = reactive<CreatePermissionParams>({
const form = reactive<CreatePermissionParams & { status?: number }>({
perm_name: '',
perm_code: '',
perm_type: PermissionType.MENU,
parent_id: undefined,
url: '',
platform: 'all',
sort: 0
sort: 0,
status: CommonStatus.ENABLED
})
// 表单验证规则
@@ -261,6 +273,21 @@
return platformMap[row.platform || 'all'] || row.platform
}
},
{
prop: 'status',
label: '状态',
width: 80,
formatter: (row: PermissionTreeNode) => {
const status = row.status ?? CommonStatus.ENABLED
return h(
ElTag,
{
type: status === CommonStatus.ENABLED ? 'success' : 'info'
},
() => getStatusText(status)
)
}
},
{
prop: 'sort',
label: '排序',
@@ -396,7 +423,8 @@
parent_id: undefined, // 树结构中没有parent_id需要从API获取
url: row.url || '',
platform: row.platform || 'all',
sort: row.sort || 0
sort: row.sort || 0,
status: row.status ?? CommonStatus.ENABLED
})
} else {
currentPermissionId.value = 0
@@ -469,7 +497,8 @@
parent_id: undefined,
url: '',
platform: 'all',
sort: 0
sort: 0,
status: CommonStatus.ENABLED
})
}

View File

@@ -133,6 +133,12 @@
>
{{ data.perm_type === 1 ? '菜单' : '按钮' }}
</ElTag>
<ElTag
:type="data.status === 1 ? 'success' : 'info'"
size="small"
>
{{ data.status === 1 ? '启用' : '禁用' }}
</ElTag>
</span>
</template>
</ElTree>
@@ -183,6 +189,12 @@
>
{{ data.perm_type === 1 ? '菜单' : '按钮' }}
</ElTag>
<ElTag
:type="data.status === 1 ? 'success' : 'info'"
size="small"
>
{{ data.status === 1 ? '启用' : '禁用' }}
</ElTag>
</span>
<ElButton
type="danger"
@@ -352,6 +364,7 @@
activeText: getStatusText(CommonStatus.ENABLED),
inactiveText: getStatusText(CommonStatus.DISABLED),
inlinePrompt: true,
disabled: !hasAuth('role:update_status'),
'onUpdate:modelValue': (val: string | number | boolean) =>
handleStatusChange(row, val as number)
})
@@ -431,6 +444,7 @@
id: node.id,
label: node.perm_name,
perm_type: node.perm_type,
status: node.status ?? 1,
children: node.children && node.children.length > 0 ? buildTreeData(node.children) : undefined
}))
}
@@ -471,11 +485,13 @@
}
// 根据权限ID列表设置树节点的禁用状态
// 同时禁用状态为禁用(status=0)的权限
const setTreeNodesDisabled = (treeNodes: any[], idsToDisable: number[]): any[] => {
return treeNodes.map((node) => {
const newNode = {
...node,
disabled: idsToDisable.includes(node.id)
// 如果已分配或状态为禁用,则禁用该节点
disabled: idsToDisable.includes(node.id) || node.status === 0
}
if (node.children && node.children.length > 0) {