diff --git a/src/locales/langs/zh.json b/src/locales/langs/zh.json index 9160776..53d5599 100644 --- a/src/locales/langs/zh.json +++ b/src/locales/langs/zh.json @@ -422,7 +422,7 @@ "agent": "代理商管理", "customerAccount": "客户账号", "enterpriseCustomer": "企业客户", - "enterpriseCustomerAccounts": "企业客户账号列表", + "enterpriseCustomerAccounts": "客户账号列表", "enterpriseCards": "企业卡管理", "customerCommission": "客户账号佣金" }, diff --git a/src/views/account-management/account/index.vue b/src/views/account-management/account/index.vue index 1d47fe3..b3d4f3b 100644 --- a/src/views/account-management/account/index.vue +++ b/src/views/account-management/account/index.vue @@ -82,27 +82,107 @@ - - -
- - {{ role.role_name }} - - {{ role.role_type === 1 ? '平台角色' : '客户角色' }} - - + + +
+ +
+
+ 可分配角色 + +
+
+ +
+ + + {{ role.role_name }} + + {{ role.role_type === 1 ? '平台角色' : '客户角色' }} + + + +
+
+
+
+ + +
+ + 添加 + +
+ + +
+
+ 已分配角色 + +
+
+
+
+ + {{ role.role_name }} + + {{ role.role_type === 1 ? '平台角色' : '客户角色' }} + + + + 移除 + +
+
+
+
+
@@ -122,7 +202,7 @@ import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue' import { AccountService } from '@/api/modules/account' import { RoleService } from '@/api/modules/role' - import { ShopService } from '@/api/modules' + import { ShopService, EnterpriseService } from '@/api/modules' import type { SearchFormItem } from '@/types' import type { PlatformRole } from '@/types/api' import { formatDateTime } from '@/utils/business/format' @@ -139,8 +219,12 @@ const loading = ref(false) const roleSubmitLoading = ref(false) const currentAccountId = ref(0) + const currentAccountName = ref('') const selectedRoles = ref([]) const allRoles = ref([]) + const rolesToAdd = ref([]) + const leftRoleFilter = ref('') + const rightRoleFilter = ref('') // 定义表单搜索初始值 const initialSearchState = { @@ -239,6 +323,22 @@ placeholder: '请输入店铺名称搜索' } }, + { + label: '关联企业', + prop: 'enterprise_id', + type: 'select', + options: enterpriseList.value.map((enterprise) => ({ + label: enterprise.enterprise_name, + value: enterprise.id + })), + config: { + clearable: true, + filterable: true, + remote: true, + remoteMethod: handleEnterpriseSearch, + placeholder: '请输入企业名称搜索' + } + }, { label: '状态', prop: 'status', @@ -436,6 +536,7 @@ getAccountList() loadAllRoles() loadShopList() + loadEnterpriseList() }) // 加载所有角色列表 @@ -450,10 +551,29 @@ } } + // 计算属性:过滤后的可分配角色 + const filteredAvailableRoles = computed(() => { + if (!leftRoleFilter.value) return allRoles.value + const keyword = leftRoleFilter.value.toLowerCase() + return allRoles.value.filter((role) => role.role_name.toLowerCase().includes(keyword)) + }) + + // 计算属性:过滤后的已分配角色 + const filteredAssignedRoles = computed(() => { + const assignedRolesList = allRoles.value.filter((role) => selectedRoles.value.includes(role.ID)) + if (!rightRoleFilter.value) return assignedRolesList + const keyword = rightRoleFilter.value.toLowerCase() + return assignedRolesList.filter((role) => role.role_name.toLowerCase().includes(keyword)) + }) + // 显示分配角色对话框 const showRoleDialog = async (row: any) => { currentAccountId.value = row.id + currentAccountName.value = row.username selectedRoles.value = [] + rolesToAdd.value = [] + leftRoleFilter.value = '' + rightRoleFilter.value = '' try { // 每次打开对话框时重新加载最新的角色列表 @@ -464,7 +584,8 @@ if (res.code === 0) { // 提取角色ID数组 const roles = res.data || [] - selectedRoles.value = roles.map((role: any) => role.id) + // 兼容 ID 和 id 两种字段名 + selectedRoles.value = roles.map((role: any) => role.ID || role.id) // 数据加载完成后再打开对话框 roleDialogVisible.value = true } @@ -473,19 +594,41 @@ } } - // 提交分配角色 - const handleAssignRoles = async () => { - roleSubmitLoading.value = true + // 批量添加角色 + const addRoles = async () => { + if (rolesToAdd.value.length === 0) return + try { - await AccountService.assignRolesToAccount(currentAccountId.value, selectedRoles.value) - ElMessage.success('分配角色成功') - roleDialogVisible.value = false + // 将选中的角色添加到已分配列表 + const newRoles = [...new Set([...selectedRoles.value, ...rolesToAdd.value])] + await AccountService.assignRolesToAccount(currentAccountId.value, newRoles) + + selectedRoles.value = newRoles + rolesToAdd.value = [] + + ElMessage.success('角色添加成功') // 刷新列表以更新角色显示 await getAccountList() } catch (error) { - console.error(error) - } finally { - roleSubmitLoading.value = false + console.error('添加角色失败:', error) + } + } + + // 移除单个角色 + const removeSingleRole = async (roleId: number) => { + try { + // 从已分配列表中移除该角色 + const newRoles = selectedRoles.value.filter((id) => id !== roleId) + await AccountService.assignRolesToAccount(currentAccountId.value, newRoles) + + selectedRoles.value = newRoles + + ElMessage.success('角色移除成功') + // 刷新列表以更新角色显示 + await getAccountList() + } catch (error) { + console.error('移除角色失败:', error) + ElMessage.error('角色移除失败') } } @@ -620,10 +763,156 @@ const handleShopSearch = (query: string) => { loadShopList(query) } + + // 加载企业列表 + const loadEnterpriseList = async (keyword: string = '') => { + try { + const res = await EnterpriseService.getEnterprises({ + page: 1, + page_size: 20, // 默认加载20条 + status: 1, // 只加载启用的企业 + enterprise_name: keyword || undefined // 根据企业名称搜索 + }) + if (res.code === 0) { + enterpriseList.value = res.data.items || [] + } + } catch (error) { + console.error('获取企业列表失败:', error) + } + } + + // 企业搜索处理 + const handleEnterpriseSearch = (query: string) => { + loadEnterpriseList(query) + } diff --git a/src/views/account-management/enterprise-customer/index.vue b/src/views/account-management/enterprise-customer/index.vue index beeaef1..92c174f 100644 --- a/src/views/account-management/enterprise-customer/index.vue +++ b/src/views/account-management/enterprise-customer/index.vue @@ -6,7 +6,7 @@ v-model:filter="searchForm" :items="searchFormItems" :show-expand="false" - :label-width="90" + label-width="90" @reset="handleReset" @search="handleSearch" > @@ -210,7 +210,7 @@ import { h } from 'vue' import { useRouter } from 'vue-router' import { EnterpriseService, ShopService } from '@/api/modules' - import { ElMessage, ElMessageBox, ElTag, ElSwitch } from 'element-plus' + import { ElMessage, ElSwitch } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus' import type { EnterpriseItem, ShopResponse } from '@/types/api' import type { SearchFormItem } from '@/types' @@ -220,8 +220,6 @@ import ArtMenuRight from '@/components/core/others/ArtMenuRight.vue' import type { MenuItemType } from '@/components/core/others/ArtMenuRight.vue' import { formatDateTime } from '@/utils/business/format' - import { BgColorEnum } from '@/enums/appEnum' - import { RoutesAlias } from '@/router/routesAlias' defineOptions({ name: 'EnterpriseCustomer' }) @@ -807,9 +805,3 @@ } } - - diff --git a/src/views/account-management/platform-account/index.vue b/src/views/account-management/platform-account/index.vue index ad24ac0..f8774b0 100644 --- a/src/views/account-management/platform-account/index.vue +++ b/src/views/account-management/platform-account/index.vue @@ -114,18 +114,107 @@ - - -
- {{ role.role_name }} + + +
+ +
+
+ 可分配角色 + +
+
+ +
+ + + {{ role.role_name }} + + {{ role.role_type === 1 ? '平台角色' : '客户角色' }} + + + +
+
+
+
+ + +
+ + 添加 + +
+ + +
+
+ 已分配角色 + +
+
+
+
+ + {{ role.role_name }} + + {{ role.role_type === 1 ? '平台角色' : '客户角色' }} + + + + 移除 + +
+
+
+
+
@@ -185,8 +274,12 @@ const roleSubmitLoading = ref(false) const passwordSubmitLoading = ref(false) const currentAccountId = ref(0) + const currentAccountName = ref('') const selectedRoles = ref([]) const allRoles = ref([]) + const rolesToAdd = ref([]) + const leftRoleFilter = ref('') + const rightRoleFilter = ref('') // 定义表单搜索初始值 const initialSearchState = { @@ -528,10 +621,29 @@ } } + // 计算属性:过滤后的可分配角色 + const filteredAvailableRoles = computed(() => { + if (!leftRoleFilter.value) return allRoles.value + const keyword = leftRoleFilter.value.toLowerCase() + return allRoles.value.filter((role) => role.role_name.toLowerCase().includes(keyword)) + }) + + // 计算属性:过滤后的已分配角色 + const filteredAssignedRoles = computed(() => { + const assignedRolesList = allRoles.value.filter((role) => selectedRoles.value.includes(role.ID)) + if (!rightRoleFilter.value) return assignedRolesList + const keyword = rightRoleFilter.value.toLowerCase() + return assignedRolesList.filter((role) => role.role_name.toLowerCase().includes(keyword)) + }) + // 显示分配角色对话框 const showRoleDialog = async (row: PlatformAccount) => { currentAccountId.value = row.id + currentAccountName.value = row.username selectedRoles.value = [] + rolesToAdd.value = [] + leftRoleFilter.value = '' + rightRoleFilter.value = '' try { // 每次打开对话框时重新加载最新的角色列表 @@ -542,7 +654,8 @@ if (res.code === 0) { // 提取角色ID数组 const roles = res.data || [] - selectedRoles.value = roles.map((role: any) => role.id) + // 兼容 ID 和 id 两种字段名 + selectedRoles.value = roles.map((role: any) => role.ID || role.id) // 数据加载完成后再打开对话框 roleDialogVisible.value = true } @@ -551,19 +664,42 @@ } } - // 提交分配角色 - const handleAssignRoles = async () => { - roleSubmitLoading.value = true + // 批量添加角色 + const addRoles = async () => { + if (rolesToAdd.value.length === 0) return + try { - await AccountService.assignRolesToAccount(currentAccountId.value, selectedRoles.value) - ElMessage.success('分配角色成功') - roleDialogVisible.value = false + // 将选中的角色添加到已分配列表 + const newRoles = [...new Set([...selectedRoles.value, ...rolesToAdd.value])] + await AccountService.assignRolesToAccount(currentAccountId.value, newRoles) + + selectedRoles.value = newRoles + rolesToAdd.value = [] + + ElMessage.success('角色添加成功') // 刷新列表以更新角色显示 await getAccountList() } catch (error) { - console.error(error) - } finally { - roleSubmitLoading.value = false + console.error('添加角色失败:', error) + ElMessage.error('角色添加失败') + } + } + + // 移除单个角色 + const removeSingleRole = async (roleId: number) => { + try { + // 从已分配列表中移除该角色 + const newRoles = selectedRoles.value.filter((id) => id !== roleId) + await AccountService.assignRolesToAccount(currentAccountId.value, newRoles) + + selectedRoles.value = newRoles + + ElMessage.success('角色移除成功') + // 刷新列表以更新角色显示 + await getAccountList() + } catch (error) { + console.error('移除角色失败:', error) + ElMessage.error('角色移除失败') } } @@ -768,4 +904,128 @@ .platform-account-page { // 平台账号管理页面样式 } + + .dialog-header { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + + .dialog-title { + font-size: 18px; + font-weight: 600; + } + + .account-info { + display: flex; + align-items: center; + gap: 8px; + + .account-name { + font-size: 14px; + color: var(--el-text-color-regular); + } + } + } + + .role-transfer-container { + display: flex; + justify-content: space-between; + align-items: stretch; + gap: 20px; + padding: 20px 0; + min-height: 500px; + + .transfer-panel { + flex: 1; + display: flex; + flex-direction: column; + border: 1px solid var(--el-border-color); + border-radius: 4px; + overflow: hidden; + max-width: 380px; + + .panel-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 16px; + background: var(--el-fill-color-light); + border-bottom: 1px solid var(--el-border-color); + + .panel-title { + font-size: 16px; + font-weight: 600; + color: var(--el-text-color-primary); + } + } + + .panel-body { + flex: 1; + overflow-y: auto; + padding: 12px; + + .role-list { + display: flex; + flex-direction: column; + gap: 8px; + + .role-item { + padding: 10px 12px; + border: 1px solid var(--el-border-color-lighter); + border-radius: 4px; + transition: all 0.2s; + + &:hover { + background: var(--el-fill-color-light); + border-color: var(--el-border-color); + } + + .role-info { + display: flex; + align-items: center; + gap: 8px; + flex: 1; + } + + :deep(.el-checkbox) { + width: 100%; + + .el-checkbox__label { + width: 100%; + } + } + } + + .assigned-role-item { + display: flex; + justify-content: space-between; + align-items: center; + gap: 12px; + + .role-info { + flex: 1; + } + + .el-button { + flex-shrink: 0; + } + } + } + } + } + + .transfer-buttons { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 12px; + padding: 0 10px; + + .el-button { + width: 100px; + } + } + } diff --git a/src/views/common/account-list.vue b/src/views/common/account-list.vue index 57d4c12..1b1f4b6 100644 --- a/src/views/common/account-list.vue +++ b/src/views/common/account-list.vue @@ -28,7 +28,7 @@ :currentPage="pagination.page" :pageSize="pagination.pageSize" :total="pagination.total" - :marginTop="10" + :marginTop="10"v height="60vh" @size-change="handleSizeChange" @current-change="handleCurrentChange" @@ -43,7 +43,7 @@