Commit 969889c6 by 李宁

1

1 parent dd3bdb7a
...@@ -5,37 +5,28 @@ import request from '../../request' ...@@ -5,37 +5,28 @@ import request from '../../request'
*/ */
export function queryAccountList(data) { export function queryAccountList(data) {
return request({ return request({
url: '/compass/api/system/account/page', url: '/crm/getUserPageList',
data, data,
}) })
} }
/** /**
* 查询角色列表 * 添加/更新账号
*/
export function queryRoleList(data) {
return request({
url: '/compass/api/common/enums/account-roles',
method: 'GET'
})
}
/**
* 删除账号
*/ */
export function deleteRole(data) { export function addAndUpdateRole(data) {
return request({ return request({
url: '/compass/api/system/account/delete', url: '/crm' + (data.id?'/updateUser':'/createUser'),
data, data,
}) })
} }
/** /**
* 添加/更新账号 * 获取指定区域下的所有区域
*/ */
export function addAndUpdateRole(data) { export function queryAreaData(data) {
return request({ return request({
url: '/compass/api/system/account' + (data.id?'/update':'/create'), url: '/crm/getArea?areaId='+data.areaId,
data, method: 'GET'
}) })
} }
\ No newline at end of file \ No newline at end of file
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
<span class="text-[16px]">享零工云平台</span> <span class="text-[16px]">享零工云平台</span>
</h1> </h1>
</div> </div>
<!-- 导航菜单 --> <!-- 导航菜单 -->
<nav class="flex-1 py-6 px-3 overflow-hidden"> <nav class="flex-1 py-6 px-3 overflow-hidden">
<div class="space-y-6"> <div class="space-y-6">
...@@ -62,7 +61,6 @@ ...@@ -62,7 +61,6 @@
</button> </button>
</template> </template>
</div> </div>
<!-- 系统管理菜单 --> <!-- 系统管理菜单 -->
<div class="space-y-1" v-if="systemMenuItems.length>0"> <div class="space-y-1" v-if="systemMenuItems.length>0">
<div v-if="!isSidebarCollapsed" class="px-4 mb-2"> <div v-if="!isSidebarCollapsed" class="px-4 mb-2">
...@@ -110,7 +108,6 @@ ...@@ -110,7 +108,6 @@
</div> </div>
</div> </div>
</nav> </nav>
<!-- 收缩按钮 --> <!-- 收缩按钮 -->
<div class="p-4 border-t border-neutral-800"> <div class="p-4 border-t border-neutral-800">
<button <button
...@@ -132,7 +129,6 @@ ...@@ -132,7 +129,6 @@
</button> </button>
</div> </div>
</div> </div>
<!-- 右侧主内容区 --> <!-- 右侧主内容区 -->
<div class="flex-1 flex flex-col overflow-hidden"> <div class="flex-1 flex flex-col overflow-hidden">
<!-- 顶部Header --> <!-- 顶部Header -->
...@@ -188,7 +184,6 @@ ...@@ -188,7 +184,6 @@
</div> </div>
</template> </template>
</div> </div>
<!-- 用户下拉菜单 --> <!-- 用户下拉菜单 -->
<el-dropdown trigger="click" @command="handleCommand"> <el-dropdown trigger="click" @command="handleCommand">
<el-button <el-button
...@@ -216,7 +211,6 @@ ...@@ -216,7 +211,6 @@
</template> </template>
</el-dropdown> </el-dropdown>
</header> </header>
<!-- 页面内容区 --> <!-- 页面内容区 -->
<main class="flex-1 overflow-auto p-6 bg-[#F0F2F5]"> <main class="flex-1 overflow-auto p-6 bg-[#F0F2F5]">
<!-- 订单监控页面 --> <!-- 订单监控页面 -->
...@@ -276,7 +270,6 @@ ...@@ -276,7 +270,6 @@
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { import {
...@@ -290,10 +283,8 @@ import { ...@@ -290,10 +283,8 @@ import {
ChevronDown ChevronDown
} from 'lucide-vue-next' } from 'lucide-vue-next'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
// 导入图片资源 // 导入图片资源
import platformLogoImg from '@/assets/8a3322d5ba8c2ae3592af24d73566a63828a3a27.png' import platformLogoImg from '@/assets/8a3322d5ba8c2ae3592af24d73566a63828a3a27.png'
// 导入子组件 // 导入子组件
import OrderMonitoring from './OrderMonitoring.vue' import OrderMonitoring from './OrderMonitoring.vue'
import OrderDetail from './OrderDetail.vue' import OrderDetail from './OrderDetail.vue'
...@@ -301,9 +292,7 @@ import BusinessRulesManagement from './BusinessRulesManagement.vue' ...@@ -301,9 +292,7 @@ import BusinessRulesManagement from './BusinessRulesManagement.vue'
import RoleManagement, { type Permission } from './RoleManagement.vue' import RoleManagement, { type Permission } from './RoleManagement.vue'
import UserManagement, { type User as UserType } from './UserManagement.vue' import UserManagement, { type User as UserType } from './UserManagement.vue'
import RoleIcon from './icons/RoleIcon.vue' import RoleIcon from './icons/RoleIcon.vue'
const platformLogo = ref(platformLogoImg) const platformLogo = ref(platformLogoImg)
// 本地Role类型定义,确保permissions字段是必需的 // 本地Role类型定义,确保permissions字段是必需的
interface Role { interface Role {
id: string id: string
...@@ -314,22 +303,17 @@ interface Role { ...@@ -314,22 +303,17 @@ interface Role {
status: '启用' | '禁用' status: '启用' | '禁用'
createTime?: string createTime?: string
} }
interface DesktopMainProps { interface DesktopMainProps {
currentUser: { username: string; role: 'admin' | 'viewer' } | null; currentUser: { username: string; role: 'admin' | 'viewer' } | null;
} }
const props = defineProps<DesktopMainProps>() const props = defineProps<DesktopMainProps>()
const emit = defineEmits(['logout']) const emit = defineEmits(['logout'])
// 响应式数据 // 响应式数据
const isSidebarCollapsed = ref(false) const isSidebarCollapsed = ref(false)
const activeMenu = ref<string>('orders') // 当前激活的菜单 const activeMenu = ref<string>('orders') // 当前激活的菜单
const activeView = ref<string>('orders') // 当前显示的视图 const activeView = ref<string>('orders') // 当前显示的视图
const selectedOrderId = ref<string | null>(null) // 当前查看的订单ID const selectedOrderId = ref<string | null>(null) // 当前查看的订单ID
const userInfo = ref(localStorage.getItem('pcUserInfo')?JSON.parse(localStorage.getItem('pcUserInfo')):{}) const userInfo = ref(localStorage.getItem('pcUserInfo')?JSON.parse(localStorage.getItem('pcUserInfo')):{})
// 菜单配置 // 菜单配置
// const businessMenuItems = [ // const businessMenuItems = [
// { id: 'orders', label: '登记订单管理', icon: LayoutDashboard }, // { id: 'orders', label: '登记订单管理', icon: LayoutDashboard },
...@@ -353,10 +337,8 @@ const businessMenuItems = computed(() => { ...@@ -353,10 +337,8 @@ const businessMenuItems = computed(() => {
return barr return barr
} }
} }
return [] return []
}) })
// const systemMenuItems = [ // const systemMenuItems = [
// { id: 'roles', label: '角色管理', icon: RoleIcon }, // { id: 'roles', label: '角色管理', icon: RoleIcon },
// { id: 'users', label: '账号管理', icon: Users } // { id: 'users', label: '账号管理', icon: Users }
...@@ -379,24 +361,20 @@ const systemMenuItems = computed(() => { ...@@ -379,24 +361,20 @@ const systemMenuItems = computed(() => {
return barr return barr
} }
} }
return [] return []
}) })
const menuMap: Record<string, string> = { const menuMap: Record<string, string> = {
orders: '登记订单管理', orders: '登记订单管理',
business: '业务酬金管理', business: '业务酬金管理',
roles: '角色管理', roles: '角色管理',
users: '账号管理', users: '账号管理',
} }
const currentMenuTitle = computed(() => { const currentMenuTitle = computed(() => {
if (activeView.value === 'order-detail') { if (activeView.value === 'order-detail') {
return '订单详情' return '订单详情'
} }
return menuMap[activeView.value] || '首页' return menuMap[activeView.value] || '首页'
}) })
// 业务规则数据 // 业务规则数据
const businessRules = ref<BusinessRule[]>([ const businessRules = ref<BusinessRule[]>([
{ {
...@@ -432,14 +410,11 @@ const businessRules = ref<BusinessRule[]>([ ...@@ -432,14 +410,11 @@ const businessRules = ref<BusinessRule[]>([
createTime: '2025-10-20 10:15' createTime: '2025-10-20 10:15'
} }
]) ])
// 模拟订单数据 // 模拟订单数据
// 使用空数组,让 OrderMonitoring 组件自动生成模拟数据 // 使用空数组,让 OrderMonitoring 组件自动生成模拟数据
const orders = ref([]) const orders = ref([])
// 存储从 OrderMonitoring 组件获取的订单数据 // 存储从 OrderMonitoring 组件获取的订单数据
const allOrders = ref([] as any[]) const allOrders = ref([] as any[])
// 类型定义 // 类型定义
interface BusinessRule { interface BusinessRule {
id: string id: string
...@@ -449,8 +424,6 @@ interface BusinessRule { ...@@ -449,8 +424,6 @@ interface BusinessRule {
status: "生效中" | "已停用" status: "生效中" | "已停用"
createTime: string createTime: string
} }
interface Organization { interface Organization {
id: string id: string
name: string name: string
...@@ -458,8 +431,6 @@ interface Organization { ...@@ -458,8 +431,6 @@ interface Organization {
parentId?: string parentId?: string
children?: Organization[] children?: Organization[]
} }
// 角色管理数据 // 角色管理数据
const roles = ref<Role[]>([ const roles = ref<Role[]>([
{ {
...@@ -509,21 +480,17 @@ const roles = ref<Role[]>([ ...@@ -509,21 +480,17 @@ const roles = ref<Role[]>([
createTime: '2025-10-20 10:00:00' createTime: '2025-10-20 10:00:00'
} }
]) ])
// 权限数据 // 权限数据
const permissions = ref<Permission[]>(JSON.parse(localStorage.getItem('pcUserInfo') || '{}').functions || []) const permissions = ref<Permission[]>(JSON.parse(localStorage.getItem('pcUserInfo') || '{}').functions || [])
// 根据订单ID获取订单详情 // 根据订单ID获取订单详情
const getOrderById = (orderId: string) => { const getOrderById = (orderId: string) => {
return allOrders.value.find((order: any) => order.id === orderId) return allOrders.value.find((order: any) => order.id === orderId)
} }
// 方法 // 方法
const handleMenuChange = (menuId: string) => { const handleMenuChange = (menuId: string) => {
activeMenu.value = menuId activeMenu.value = menuId
activeView.value = menuId activeView.value = menuId
} }
const handleCommand = (command: string) => { const handleCommand = (command: string) => {
if (command === 'logout') { if (command === 'logout') {
ElMessageBox.confirm('确定要退出登录吗?', '提示', { ElMessageBox.confirm('确定要退出登录吗?', '提示', {
...@@ -540,17 +507,14 @@ const handleCommand = (command: string) => { ...@@ -540,17 +507,14 @@ const handleCommand = (command: string) => {
ElMessage.info(`点击了 ${command}`) ElMessage.info(`点击了 ${command}`)
} }
} }
const handleViewOrderDetail = (order: any) => { const handleViewOrderDetail = (order: any) => {
selectedOrderId.value = order.id selectedOrderId.value = order.id
activeView.value = 'order-detail' activeView.value = 'order-detail'
} }
const handleBackToOrders = () => { const handleBackToOrders = () => {
selectedOrderId.value = null selectedOrderId.value = null
activeView.value = 'orders' activeView.value = 'orders'
} }
const handleUpdateOrder = (updates: any) => { const handleUpdateOrder = (updates: any) => {
// 更新 allOrders 中的订单数据 // 更新 allOrders 中的订单数据
const orderIndex = allOrders.value.findIndex(order => order.id === selectedOrderId.value) const orderIndex = allOrders.value.findIndex(order => order.id === selectedOrderId.value)
...@@ -560,12 +524,10 @@ const handleUpdateOrder = (updates: any) => { ...@@ -560,12 +524,10 @@ const handleUpdateOrder = (updates: any) => {
console.log('更新订单:', updates) console.log('更新订单:', updates)
ElMessage.success('订单更新成功') ElMessage.success('订单更新成功')
} }
// 接收来自 OrderMonitoring 组件的订单数据 // 接收来自 OrderMonitoring 组件的订单数据
const handleOrdersUpdate = (ordersList: any[]) => { const handleOrdersUpdate = (ordersList: any[]) => {
allOrders.value = ordersList allOrders.value = ordersList
} }
// 面包屑导航点击处理 // 面包屑导航点击处理
const handleBreadcrumbClick = (level: string) => { const handleBreadcrumbClick = (level: string) => {
if (level === 'level1') { if (level === 'level1') {
...@@ -579,7 +541,6 @@ const handleBreadcrumbClick = (level: string) => { ...@@ -579,7 +541,6 @@ const handleBreadcrumbClick = (level: string) => {
} }
} }
} }
// 业务规则管理方法 // 业务规则管理方法
const handleAddBusinessRule = (ruleData: Omit<BusinessRule, 'id' | 'createTime'>) => { const handleAddBusinessRule = (ruleData: Omit<BusinessRule, 'id' | 'createTime'>) => {
const newRule = { const newRule = {
...@@ -597,7 +558,6 @@ const handleAddBusinessRule = (ruleData: Omit<BusinessRule, 'id' | 'createTime'> ...@@ -597,7 +558,6 @@ const handleAddBusinessRule = (ruleData: Omit<BusinessRule, 'id' | 'createTime'>
ElMessage.success('业务规则创建成功') ElMessage.success('业务规则创建成功')
console.log('新增业务规则:', newRule) console.log('新增业务规则:', newRule)
} }
const handleUpdateBusinessRule = (ruleId: string, updates: Partial<BusinessRule>) => { const handleUpdateBusinessRule = (ruleId: string, updates: Partial<BusinessRule>) => {
const ruleIndex = businessRules.value.findIndex(rule => rule.id === ruleId) const ruleIndex = businessRules.value.findIndex(rule => rule.id === ruleId)
if (ruleIndex !== -1) { if (ruleIndex !== -1) {
...@@ -610,7 +570,6 @@ const handleUpdateBusinessRule = (ruleId: string, updates: Partial<BusinessRule> ...@@ -610,7 +570,6 @@ const handleUpdateBusinessRule = (ruleId: string, updates: Partial<BusinessRule>
console.log('更新业务规则:', ruleId, updates) console.log('更新业务规则:', ruleId, updates)
} }
} }
const handleToggleBusinessRuleStatus = (ruleId: string) => { const handleToggleBusinessRuleStatus = (ruleId: string) => {
const ruleIndex = businessRules.value.findIndex(rule => rule.id === ruleId) const ruleIndex = businessRules.value.findIndex(rule => rule.id === ruleId)
if (ruleIndex !== -1) { if (ruleIndex !== -1) {
...@@ -624,7 +583,6 @@ const handleToggleBusinessRuleStatus = (ruleId: string) => { ...@@ -624,7 +583,6 @@ const handleToggleBusinessRuleStatus = (ruleId: string) => {
} }
} }
} }
const handleDeleteBusinessRule = (ruleId: string) => { const handleDeleteBusinessRule = (ruleId: string) => {
const ruleIndex = businessRules.value.findIndex(rule => rule.id === ruleId) const ruleIndex = businessRules.value.findIndex(rule => rule.id === ruleId)
if (ruleIndex !== -1) { if (ruleIndex !== -1) {
...@@ -633,7 +591,6 @@ const handleDeleteBusinessRule = (ruleId: string) => { ...@@ -633,7 +591,6 @@ const handleDeleteBusinessRule = (ruleId: string) => {
console.log('删除业务规则:', ruleId) console.log('删除业务规则:', ruleId)
} }
} }
// 角色管理方法 // 角色管理方法
const handleAddRole = (roleData: any) => { const handleAddRole = (roleData: any) => {
const newRole: Role = { const newRole: Role = {
...@@ -652,7 +609,6 @@ const handleAddRole = (roleData: any) => { ...@@ -652,7 +609,6 @@ const handleAddRole = (roleData: any) => {
roles.value.push(newRole) roles.value.push(newRole)
console.log('新增角色:', newRole) console.log('新增角色:', newRole)
} }
const handleUpdateRole = (roleId: string, updates: any) => { const handleUpdateRole = (roleId: string, updates: any) => {
const roleIndex = roles.value.findIndex(role => role.id === roleId) const roleIndex = roles.value.findIndex(role => role.id === roleId)
if (roleIndex !== -1) { if (roleIndex !== -1) {
...@@ -667,7 +623,6 @@ const handleUpdateRole = (roleId: string, updates: any) => { ...@@ -667,7 +623,6 @@ const handleUpdateRole = (roleId: string, updates: any) => {
} }
} }
} }
// 组织架构数据 // 组织架构数据
const organizations = ref<Organization[]>([ const organizations = ref<Organization[]>([
{ {
...@@ -720,10 +675,8 @@ const organizations = ref<Organization[]>([ ...@@ -720,10 +675,8 @@ const organizations = ref<Organization[]>([
] ]
} }
]) ])
// 当前登录用户ID // 当前登录用户ID
const currentUserId = ref('user-001') const currentUserId = ref('user-001')
// 用户数据 // 用户数据
const users = ref<UserType[]>([ const users = ref<UserType[]>([
{ {
...@@ -775,7 +728,6 @@ const users = ref<UserType[]>([ ...@@ -775,7 +728,6 @@ const users = ref<UserType[]>([
creatorId: 'user-001' creatorId: 'user-001'
} }
]) ])
// 用户管理方法 // 用户管理方法
const handleAddUser = (userData: Omit<UserType, 'id' | 'createTime' | 'creatorId'>) => { const handleAddUser = (userData: Omit<UserType, 'id' | 'createTime' | 'creatorId'>) => {
const newUser = { const newUser = {
...@@ -794,7 +746,6 @@ const handleAddUser = (userData: Omit<UserType, 'id' | 'createTime' | 'creatorId ...@@ -794,7 +746,6 @@ const handleAddUser = (userData: Omit<UserType, 'id' | 'createTime' | 'creatorId
users.value.push(newUser) users.value.push(newUser)
console.log('新增用户:', newUser) console.log('新增用户:', newUser)
} }
const handleUpdateUser = (userId: string, updates: Partial<UserType>) => { const handleUpdateUser = (userId: string, updates: Partial<UserType>) => {
const userIndex = users.value.findIndex(user => user.id === userId) const userIndex = users.value.findIndex(user => user.id === userId)
if (userIndex !== -1) { if (userIndex !== -1) {
...@@ -806,7 +757,6 @@ const handleUpdateUser = (userId: string, updates: Partial<UserType>) => { ...@@ -806,7 +757,6 @@ const handleUpdateUser = (userId: string, updates: Partial<UserType>) => {
console.log('更新用户:', userId, updates) console.log('更新用户:', userId, updates)
} }
} }
const handleDeleteUser = (userId: string) => { const handleDeleteUser = (userId: string) => {
const userIndex = users.value.findIndex(user => user.id === userId) const userIndex = users.value.findIndex(user => user.id === userId)
if (userIndex !== -1) { if (userIndex !== -1) {
...@@ -815,18 +765,15 @@ const handleDeleteUser = (userId: string) => { ...@@ -815,18 +765,15 @@ const handleDeleteUser = (userId: string) => {
} }
} }
</script> </script>
<style scoped> <style scoped>
/* 隐藏滚动条但保持滚动功能 */ /* 隐藏滚动条但保持滚动功能 */
.hide-scrollbar { .hide-scrollbar {
scrollbar-width: none; /* Firefox */ scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */ -ms-overflow-style: none; /* IE and Edge */
} }
.hide-scrollbar::-webkit-scrollbar { .hide-scrollbar::-webkit-scrollbar {
display: none; /* Chrome, Safari, and Opera */ display: none; /* Chrome, Safari, and Opera */
} }
/* 移除右上角用户信息按钮的悬浮背景效果 */ /* 移除右上角用户信息按钮的悬浮背景效果 */
:deep(header .el-button.is-text:hover), :deep(header .el-button.is-text:hover),
:deep(header .el-button.is-text:focus), :deep(header .el-button.is-text:focus),
......
...@@ -48,7 +48,6 @@ ...@@ -48,7 +48,6 @@
class="inline-block w-2 h-2 rounded-sm bg-white" class="inline-block w-2 h-2 rounded-sm bg-white"
/> />
</div> </div>
<!-- 组织图标 --> <!-- 组织图标 -->
<Building2 <Building2
:class="[ :class="[
...@@ -110,11 +109,9 @@ ...@@ -110,11 +109,9 @@
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { Building2, ChevronDown, ChevronRight } from 'lucide-vue-next' import { Building2, ChevronDown, ChevronRight } from 'lucide-vue-next'
interface Organization { interface Organization {
id: string id: string
name: string name: string
...@@ -122,13 +119,11 @@ interface Organization { ...@@ -122,13 +119,11 @@ interface Organization {
parentId?: string parentId?: string
children?: Organization[] children?: Organization[]
} }
interface Role { interface Role {
id: string id: string
name: string name: string
level: '地市级' | '区县级' | '一线人员' level: '地市级' | '区县级' | '一线人员'
} }
interface Props { interface Props {
organizations: Organization[] organizations: Organization[]
selectedId?: string selectedId?: string
...@@ -137,7 +132,6 @@ interface Props { ...@@ -137,7 +132,6 @@ interface Props {
expandedIds?: Set<string> expandedIds?: Set<string>
accountType?: '地市级' | '区县级' | '一线人员' accountType?: '地市级' | '区县级' | '一线人员'
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
selectedId: '', selectedId: '',
roleId: '', roleId: '',
...@@ -145,12 +139,10 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -145,12 +139,10 @@ const props = withDefaults(defineProps<Props>(), {
expandedIds: () => new Set(), expandedIds: () => new Set(),
accountType: undefined accountType: undefined
}) })
const emit = defineEmits<{ const emit = defineEmits<{
select: [orgId: string] select: [orgId: string]
'toggle-expand': [orgId: string] 'toggle-expand': [orgId: string]
}>() }>()
// 如果没有传入 expandedIds,使用本地状态 // 如果没有传入 expandedIds,使用本地状态
const localExpandedIds = ref(new Set<string>()) const localExpandedIds = ref(new Set<string>())
const expandedIds = computed(() => const expandedIds = computed(() =>
...@@ -158,12 +150,10 @@ const expandedIds = computed(() => ...@@ -158,12 +150,10 @@ const expandedIds = computed(() =>
? props.expandedIds ? props.expandedIds
: localExpandedIds.value : localExpandedIds.value
) )
// 工具函数 // 工具函数
const hasChildren = (org: Organization): boolean => { const hasChildren = (org: Organization): boolean => {
return !!(org.children && org.children.length > 0) return !!(org.children && org.children.length > 0)
} }
const isSelectable = (org: Organization): boolean => { const isSelectable = (org: Organization): boolean => {
console.log('检查组织可选性:', org.name, org.type, '账号类型:', props.accountType) console.log('检查组织可选性:', org.name, org.type, '账号类型:', props.accountType)
...@@ -196,7 +186,6 @@ const isSelectable = (org: Organization): boolean => { ...@@ -196,7 +186,6 @@ const isSelectable = (org: Organization): boolean => {
// 如果没有账号类型,可以选择所有组织 // 如果没有账号类型,可以选择所有组织
return true return true
} }
// 检查组织是否属于区县下 // 检查组织是否属于区县下
const isUnderCounty = (org: Organization): boolean => { const isUnderCounty = (org: Organization): boolean => {
console.log('OrganizationTree.vue:202 检查组织是否属于区县下:', org.name, org.type, org.id) console.log('OrganizationTree.vue:202 检查组织是否属于区县下:', org.name, org.type, org.id)
...@@ -239,7 +228,6 @@ const isUnderCounty = (org: Organization): boolean => { ...@@ -239,7 +228,6 @@ const isUnderCounty = (org: Organization): boolean => {
console.log('OrganizationTree.vue:241 未找到区县父组织') console.log('OrganizationTree.vue:241 未找到区县父组织')
return false return false
} }
const getOrgTypeLabel = (type: Organization['type']) => { const getOrgTypeLabel = (type: Organization['type']) => {
switch (type) { switch (type) {
case '地市': case '地市':
...@@ -252,21 +240,18 @@ const getOrgTypeLabel = (type: Organization['type']) => { ...@@ -252,21 +240,18 @@ const getOrgTypeLabel = (type: Organization['type']) => {
return type return type
} }
} }
const getRoleLevel = (roleId: string): string => { const getRoleLevel = (roleId: string): string => {
if (!props.roles || props.roles.length === 0) return '区县级' if (!props.roles || props.roles.length === 0) return '区县级'
const role = props.roles.find(r => r.id === roleId) const role = props.roles.find(r => r.id === roleId)
return role ? role.level : '区县级' return role ? role.level : '区县级'
} }
// 事件处理 // 事件处理
const handleSelect = (org: Organization) => { const handleSelect = (org: Organization) => {
if (isSelectable(org)) { if (isSelectable(org)) {
emit('select', org.id) emit('select', org.id)
} }
} }
const toggleExpand = (orgId: string) => { const toggleExpand = (orgId: string) => {
if (props.expandedIds && props.expandedIds.size > 0) { if (props.expandedIds && props.expandedIds.size > 0) {
// 使用父组件的展开状态 // 使用父组件的展开状态
...@@ -280,11 +265,9 @@ const toggleExpand = (orgId: string) => { ...@@ -280,11 +265,9 @@ const toggleExpand = (orgId: string) => {
} }
} }
} }
const handleToggleExpand = (orgId: string) => { const handleToggleExpand = (orgId: string) => {
emit('toggle-expand', orgId) emit('toggle-expand', orgId)
} }
// 初始化展开顶级组织 // 初始化展开顶级组织
if (props.expandedIds && props.expandedIds.size === 0) { if (props.expandedIds && props.expandedIds.size === 0) {
props.organizations.forEach(org => { props.organizations.forEach(org => {
...@@ -294,127 +277,97 @@ if (props.expandedIds && props.expandedIds.size === 0) { ...@@ -294,127 +277,97 @@ if (props.expandedIds && props.expandedIds.size === 0) {
}) })
} }
</script> </script>
<style scoped> <style scoped>
.space-y-1 > * + * { .space-y-1 > * + * {
margin-top: 0.25rem; margin-top: 0.25rem;
} }
.flex { .flex {
display: flex; display: flex;
} }
.items-center { .items-center {
align-items: center; align-items: center;
} }
.gap-2 { .gap-2 {
gap: 0.5rem; gap: 0.5rem;
} }
.p-1 { .p-1 {
padding: 0.25rem; padding: 0.25rem;
} }
.p-2 { .p-2 {
padding: 0.5rem; padding: 0.5rem;
} }
.rounded { .rounded {
border-radius: 0.25rem; border-radius: 0.25rem;
} }
.cursor-pointer { .cursor-pointer {
cursor: pointer; cursor: pointer;
} }
.cursor-not-allowed { .cursor-not-allowed {
cursor: not-allowed; cursor: not-allowed;
} }
.transition-colors { .transition-colors {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms; transition-duration: 150ms;
} }
.opacity-40 { .opacity-40 {
opacity: 0.4; opacity: 0.4;
} }
.bg-blue-50 { .bg-blue-50 {
background-color: #eff6ff; background-color: #eff6ff;
} }
.border { .border {
border-width: 1px; border-width: 1px;
} }
.border-blue-500 { .border-blue-500 {
border-color: #3b82f6; border-color: #3b82f6;
} }
.hover\:bg-neutral-50:hover { .hover\:bg-neutral-50:hover {
background-color: #f9fafb; background-color: #f9fafb;
} }
.hover\:bg-neutral-200:hover { .hover\:bg-neutral-200:hover {
background-color: #e5e7eb; background-color: #e5e7eb;
} }
.h-4 { .h-4 {
height: 1rem; height: 1rem;
} }
.w-4 { .w-4 {
width: 1rem; width: 1rem;
} }
.w-6 { .w-6 {
width: 1.5rem; width: 1.5rem;
} }
.text-neutral-300 { .text-neutral-300 {
color: #d1d5db; color: #d1d5db;
} }
.text-neutral-400 { .text-neutral-400 {
color: #9ca3af; color: #9ca3af;
} }
.text-neutral-500 { .text-neutral-500 {
color: #6b7280; color: #6b7280;
} }
.text-neutral-600 { .text-neutral-600 {
color: #4b5563; color: #4b5563;
} }
.text-neutral-900 { .text-neutral-900 {
color: #111827; color: #111827;
} }
.text-blue-600 { .text-blue-600 {
color: #2563eb; color: #2563eb;
} }
.text-xs { .text-xs {
font-size: 0.75rem; font-size: 0.75rem;
line-height: 1rem; line-height: 1rem;
} }
.flex-1 { .flex-1 {
flex: 1 1 0%; flex: 1 1 0%;
} }
.ml-4 { .ml-4 {
margin-left: 1rem; margin-left: 1rem;
} }
.border-l-2 { .border-l-2 {
border-left-width: 2px; border-left-width: 2px;
} }
.border-neutral-200 { .border-neutral-200 {
border-color: #e5e7eb; border-color: #e5e7eb;
} }
......
...@@ -261,6 +261,21 @@ const topLevelPermissions = computed(() => ...@@ -261,6 +261,21 @@ const topLevelPermissions = computed(() =>
const filteredRoles = ref([]) const filteredRoles = ref([])
const getAllIds = (tree)=>{
const ids = [] // 结果池
const stack = [...tree] // 根节点入栈
while (stack.length) {
const node = stack.pop()
if (node.id !== undefined) ids.push(node.id) // 收集当前节点
if (node.children?.length) {
// 子节点全部入栈(顺序无所谓就 push,要顺序就 unshift)
stack.push(...node.children)
}
}
return ids
}
// 获取角色的权限ID列表,兼容不同的字段名 // 获取角色的权限ID列表,兼容不同的字段名
const getRolePermissionIds = async (role: Role)=> { const getRolePermissionIds = async (role: Role)=> {
try { try {
...@@ -268,12 +283,8 @@ const getRolePermissionIds = async (role: Role)=> { ...@@ -268,12 +283,8 @@ const getRolePermissionIds = async (role: Role)=> {
id: role.id id: role.id
}) })
return [1,2,3,4]
if (response.c === 0 && response.d) { if (response.c === 0 && response.d) {
// 假设返回的数据结构是 { functionIds: ['id1', 'id2', ...] } return getAllIds(response.d.list)
return response.d.functionIds || response.d.permissionIds || []
} else { } else {
console.warn('获取角色权限失败:', response.msg) console.warn('获取角色权限失败:', response.msg)
return role.permissionIds || role.permissions || [] return role.permissionIds || role.permissions || []
...@@ -340,17 +351,8 @@ const handleSave = async () => { ...@@ -340,17 +351,8 @@ const handleSave = async () => {
return return
} }
const roleData = {
name: roleName.value.trim(),
description: roleDescription.value.trim(),
permissionIds: selectedPermissions.value,
status: roleStatus.value
}
console.log(roleData)
const response = await $api.createOrUpdateRole({ const response = await $api.createOrUpdateRole({
roleId: '', roleId: editingRole.value?editingRole.value.id:'',
roleName: roleName.value.trim(), roleName: roleName.value.trim(),
remark: roleDescription.value.trim(), remark: roleDescription.value.trim(),
status: roleStatus.value, status: roleStatus.value,
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
新增用户 新增用户
</el-button> </el-button>
</div> </div>
<!-- 搜索和筛选 --> <!-- 搜索和筛选 -->
<el-card> <el-card>
<div class="grid grid-cols-5 gap-4 px-6 py-6"> <div class="grid grid-cols-5 gap-4 px-6 py-6">
...@@ -28,7 +27,6 @@ ...@@ -28,7 +27,6 @@
clearable clearable
/> />
</div> </div>
<el-select <el-select
v-model="roleFilter" v-model="roleFilter"
placeholder="角色" placeholder="角色"
...@@ -43,7 +41,6 @@ ...@@ -43,7 +41,6 @@
:value="role.id" :value="role.id"
/> />
</el-select> </el-select>
<el-select <el-select
v-model="accountTypeFilter" v-model="accountTypeFilter"
placeholder="账号类型" placeholder="账号类型"
...@@ -55,7 +52,6 @@ ...@@ -55,7 +52,6 @@
<el-option label="区县级" value="区县级" /> <el-option label="区县级" value="区县级" />
<el-option label="一线人员" value="一线人员" /> <el-option label="一线人员" value="一线人员" />
</el-select> </el-select>
<el-select <el-select
v-model="statusFilter" v-model="statusFilter"
placeholder="状态" placeholder="状态"
...@@ -66,7 +62,6 @@ ...@@ -66,7 +62,6 @@
<el-option label="正常" value="正常" /> <el-option label="正常" value="正常" />
<el-option label="禁用" value="禁用" /> <el-option label="禁用" value="禁用" />
</el-select> </el-select>
<el-select <el-select
v-model="organizationFilter" v-model="organizationFilter"
placeholder="所属组织" placeholder="所属组织"
...@@ -83,7 +78,6 @@ ...@@ -83,7 +78,6 @@
</el-select> </el-select>
</div> </div>
</el-card> </el-card>
<!-- 用户列表 --> <!-- 用户列表 -->
<el-card class="p-5"> <el-card class="p-5">
...@@ -182,7 +176,6 @@ ...@@ -182,7 +176,6 @@
</el-table> </el-table>
</div> </div>
</el-card> </el-card>
<!-- 新增/编辑用户对话框 --> <!-- 新增/编辑用户对话框 -->
<el-dialog <el-dialog
v-model="isDialogOpen" v-model="isDialogOpen"
...@@ -205,23 +198,18 @@ ...@@ -205,23 +198,18 @@
:disabled="!!editingUser" :disabled="!!editingUser"
/> />
</el-form-item> </el-form-item>
<el-form-item label="用户姓名" required> <el-form-item label="用户姓名" required>
<el-input <el-input
v-model="formData.realName" v-model="formData.realName"
placeholder="真实姓名" placeholder="真实姓名"
/> />
</el-form-item> </el-form-item>
<el-form-item label="手机号" required> <el-form-item label="手机号" required>
<el-input <el-input
v-model="formData.phone" v-model="formData.phone"
placeholder="11位手机号" placeholder="11位手机号"
/> />
</el-form-item> </el-form-item>
<el-form-item label="账号类型" required> <el-form-item label="账号类型" required>
<el-select <el-select
v-model="formData.accountType" v-model="formData.accountType"
...@@ -234,7 +222,6 @@ ...@@ -234,7 +222,6 @@
<el-option label="一线人员" value="一线人员" /> <el-option label="一线人员" value="一线人员" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="角色" required class="col-span-2"> <el-form-item label="角色" required class="col-span-2">
<el-select <el-select
v-model="formData.roleId" v-model="formData.roleId"
...@@ -254,7 +241,6 @@ ...@@ -254,7 +241,6 @@
</div> </div>
</el-form-item> </el-form-item>
</div> </div>
<div class="flex items-center justify-between p-4 bg-neutral-50 rounded border border-neutral-200"> <div class="flex items-center justify-between p-4 bg-neutral-50 rounded border border-neutral-200">
<div> <div>
<div class="text-neutral-900 font-medium">用户状态</div> <div class="text-neutral-900 font-medium">用户状态</div>
...@@ -265,7 +251,6 @@ ...@@ -265,7 +251,6 @@
/> />
</div> </div>
</div> </div>
<!-- 所属组织(当前登录用户不可修改) --> <!-- 所属组织(当前登录用户不可修改) -->
<div v-if="!editingUser || !isCurrentUser(editingUser)" class="space-y-4"> <div v-if="!editingUser || !isCurrentUser(editingUser)" class="space-y-4">
<div class="flex items-center justify-between pb-2 border-b border-neutral-200"> <div class="flex items-center justify-between pb-2 border-b border-neutral-200">
...@@ -296,7 +281,6 @@ ...@@ -296,7 +281,6 @@
提示:点击组织名称选择,点击箭头展开/收起子组织。灰色不可选的组织表示不符合当前角色的层级要求。 提示:点击组织名称选择,点击箭头展开/收起子组织。灰色不可选的组织表示不符合当前角色的层级要求。
</p> </p>
</div> </div>
<!-- 当前登录用户的组织信息(只读显示) --> <!-- 当前登录用户的组织信息(只读显示) -->
<div v-else-if="editingUser && isCurrentUser(editingUser)" class="space-y-4"> <div v-else-if="editingUser && isCurrentUser(editingUser)" class="space-y-4">
<h3 class="text-neutral-900 pb-2 border-b border-neutral-200">所属组织</h3> <h3 class="text-neutral-900 pb-2 border-b border-neutral-200">所属组织</h3>
...@@ -320,7 +304,6 @@ ...@@ -320,7 +304,6 @@
</div> </div>
</div> </div>
</div> </div>
<template #footer> <template #footer>
<el-button @click="isDialogOpen = false">取消</el-button> <el-button @click="isDialogOpen = false">取消</el-button>
<el-button type="primary" @click="handleSave">确定</el-button> <el-button type="primary" @click="handleSave">确定</el-button>
...@@ -328,19 +311,16 @@ ...@@ -328,19 +311,16 @@
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch } from 'vue' import { ref, computed, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Building2, Search } from 'lucide-vue-next' import { Plus, Building2, Search } from 'lucide-vue-next'
import OrganizationTree from './OrganizationTree.vue' import OrganizationTree from './OrganizationTree.vue'
// 类型定义 // 类型定义
export interface User { export interface User {
id: string id: string
username: string username: string
realName: string realName: string
organizationId: string organizationId: string
roleId: string roleId: string
accountType?: '地市级' | '区县级' | '一线人员' accountType?: '地市级' | '区县级' | '一线人员'
...@@ -350,7 +330,6 @@ export interface User { ...@@ -350,7 +330,6 @@ export interface User {
createTime?: string createTime?: string
creatorId?: string creatorId?: string
} }
interface Role { interface Role {
id: string id: string
name: string name: string
...@@ -359,7 +338,6 @@ interface Role { ...@@ -359,7 +338,6 @@ interface Role {
status: '启用' | '禁用' status: '启用' | '禁用'
permissions: string[] permissions: string[]
} }
interface Organization { interface Organization {
id: string id: string
name: string name: string
...@@ -367,7 +345,6 @@ interface Organization { ...@@ -367,7 +345,6 @@ interface Organization {
parentId?: string parentId?: string
children?: Organization[] children?: Organization[]
} }
// Props // Props
interface UserManagementProps { interface UserManagementProps {
users: User[] users: User[]
...@@ -375,13 +352,11 @@ interface UserManagementProps { ...@@ -375,13 +352,11 @@ interface UserManagementProps {
organizations: Organization[] organizations: Organization[]
currentUserId: string currentUserId: string
} }
const props = defineProps<UserManagementProps>() const props = defineProps<UserManagementProps>()
const emit = defineEmits<{ const emit = defineEmits<{
addUser: [user: Omit<User, 'id' | 'createTime' | 'creatorId'>] addUser: [user: Omit<User, 'id' | 'createTime' | 'creatorId'>]
updateUser: [id: string, updates: Partial<User>] updateUser: [id: string, updates: Partial<User>]
}>() }>()
// 响应式数据 // 响应式数据
const isDialogOpen = ref(false) const isDialogOpen = ref(false)
const editingUser = ref<User | null>(null) const editingUser = ref<User | null>(null)
...@@ -391,30 +366,24 @@ const accountTypeFilter = ref<'all' | '地市级' | '区县级' | '一线人员' ...@@ -391,30 +366,24 @@ const accountTypeFilter = ref<'all' | '地市级' | '区县级' | '一线人员'
const statusFilter = ref<'all' | '正常' | '禁用'>('all') const statusFilter = ref<'all' | '正常' | '禁用'>('all')
const organizationFilter = ref<string>('all') const organizationFilter = ref<string>('all')
const organizationExpandedIds = ref(new Set<string>()) const organizationExpandedIds = ref(new Set<string>())
// 表单数据 // 表单数据
const formData = ref({ const formData = ref({
username: '', username: '',
realName: '', realName: '',
phone: '', phone: '',
accountType: '一线人员' as '地市级' | '区县级' | '一线人员', accountType: '一线人员' as '地市级' | '区县级' | '一线人员',
organizationId: '', organizationId: '',
roleId: '', roleId: '',
isActive: true isActive: true
}) })
// 计算属性 // 计算属性
const availableRoles = computed(() => const availableRoles = computed(() =>
props.roles.filter(r => r.status === '启用' && r.name !== '地市主管理员') props.roles.filter(r => r.status === '启用' && r.name !== '地市主管理员')
) )
const topLevelOrganizations = computed(() => const topLevelOrganizations = computed(() =>
props.organizations.filter(o => !o.parentId) props.organizations.filter(o => !o.parentId)
) )
const totalUsers = computed(() => props.users.length - 1) // 排除当前登录用户 const totalUsers = computed(() => props.users.length - 1) // 排除当前登录用户
const hasFilters = computed(() => const hasFilters = computed(() =>
generalSearch.value !== '' || generalSearch.value !== '' ||
roleFilter.value !== 'all' || roleFilter.value !== 'all' ||
...@@ -422,7 +391,6 @@ const hasFilters = computed(() => ...@@ -422,7 +391,6 @@ const hasFilters = computed(() =>
statusFilter.value !== 'all' || statusFilter.value !== 'all' ||
organizationFilter.value !== 'all' organizationFilter.value !== 'all'
) )
const filteredUsers = computed(() => { const filteredUsers = computed(() => {
return props.users.filter(user => { return props.users.filter(user => {
// 过滤掉当前登录用户 // 过滤掉当前登录用户
...@@ -441,11 +409,9 @@ const filteredUsers = computed(() => { ...@@ -441,11 +409,9 @@ const filteredUsers = computed(() => {
const matchAccountType = accountTypeFilter.value === 'all' || user.accountType === accountTypeFilter.value const matchAccountType = accountTypeFilter.value === 'all' || user.accountType === accountTypeFilter.value
const matchStatus = statusFilter.value === 'all' || user.status === statusFilter.value const matchStatus = statusFilter.value === 'all' || user.status === statusFilter.value
const matchOrganization = organizationFilter.value === 'all' || user.organizationId === organizationFilter.value const matchOrganization = organizationFilter.value === 'all' || user.organizationId === organizationFilter.value
return matchGeneral && matchRole && matchAccountType && matchStatus && matchOrganization return matchGeneral && matchRole && matchAccountType && matchStatus && matchOrganization
}) })
}) })
const roleHint = computed(() => { const roleHint = computed(() => {
if (!formData.value.roleId) return '' if (!formData.value.roleId) return ''
...@@ -454,7 +420,6 @@ const roleHint = computed(() => { ...@@ -454,7 +420,6 @@ const roleHint = computed(() => {
return `${role.name}` return `${role.name}`
}) })
// 工具函数 // 工具函数
const getOrganizationById = (id: string): Organization | undefined => { const getOrganizationById = (id: string): Organization | undefined => {
const find = (orgs: Organization[]): Organization | undefined => { const find = (orgs: Organization[]): Organization | undefined => {
...@@ -469,11 +434,9 @@ const getOrganizationById = (id: string): Organization | undefined => { ...@@ -469,11 +434,9 @@ const getOrganizationById = (id: string): Organization | undefined => {
} }
return find(props.organizations) return find(props.organizations)
} }
const getRoleById = (id: string): Role | undefined => { const getRoleById = (id: string): Role | undefined => {
return props.roles.find(r => r.id === id) return props.roles.find(r => r.id === id)
} }
const getAccountTypeTagType = (accountType: string) => { const getAccountTypeTagType = (accountType: string) => {
switch (accountType) { switch (accountType) {
case '地市级': return 'warning' case '地市级': return 'warning'
...@@ -482,25 +445,21 @@ const getAccountTypeTagType = (accountType: string) => { ...@@ -482,25 +445,21 @@ const getAccountTypeTagType = (accountType: string) => {
default: return 'info' default: return 'info'
} }
} }
const isCurrentUser = (user: User): boolean => { const isCurrentUser = (user: User): boolean => {
return user.id === props.currentUserId return user.id === props.currentUserId
} }
const getRowStyle = ({ row }: { row: User }) => { const getRowStyle = ({ row }: { row: User }) => {
if (isCurrentUser(row)) { if (isCurrentUser(row)) {
return { backgroundColor: '#f0f9ff', borderLeft: '4px solid #1677ff' } return { backgroundColor: '#f0f9ff', borderLeft: '4px solid #1677ff' }
} }
return {} return {}
} }
// 事件处理 // 事件处理
const handleOpenAddDialog = () => { const handleOpenAddDialog = () => {
editingUser.value = null editingUser.value = null
formData.value = { formData.value = {
username: '', username: '',
realName: '', realName: '',
phone: '', phone: '',
accountType: '一线人员' as '地市级' | '区县级' | '一线人员', accountType: '一线人员' as '地市级' | '区县级' | '一线人员',
organizationId: '', organizationId: '',
...@@ -509,13 +468,11 @@ const handleOpenAddDialog = () => { ...@@ -509,13 +468,11 @@ const handleOpenAddDialog = () => {
} }
isDialogOpen.value = true isDialogOpen.value = true
} }
const handleOpenEditDialog = (user: User) => { const handleOpenEditDialog = (user: User) => {
editingUser.value = user editingUser.value = user
formData.value = { formData.value = {
username: user.username, username: user.username,
realName: user.realName, realName: user.realName,
phone: user.phone || '', phone: user.phone || '',
accountType: user.accountType || '一线人员', accountType: user.accountType || '一线人员',
organizationId: user.organizationId, organizationId: user.organizationId,
...@@ -524,7 +481,6 @@ const handleOpenEditDialog = (user: User) => { ...@@ -524,7 +481,6 @@ const handleOpenEditDialog = (user: User) => {
} }
isDialogOpen.value = true isDialogOpen.value = true
} }
const handleAccountTypeChange = () => { const handleAccountTypeChange = () => {
// 当账号类型变更时,清空组织选择 // 当账号类型变更时,清空组织选择
formData.value.organizationId = '' formData.value.organizationId = ''
...@@ -539,15 +495,12 @@ const handleAccountTypeChange = () => { ...@@ -539,15 +495,12 @@ const handleAccountTypeChange = () => {
ElMessage.info('账号类型为一线人员,所属组织只能选择客户经理团队') ElMessage.info('账号类型为一线人员,所属组织只能选择客户经理团队')
} }
} }
const handleRoleChange = () => { const handleRoleChange = () => {
// 角色变更时不进行层级检查 // 角色变更时不进行层级检查
} }
const handleOrganizationSelect = (orgId: string) => { const handleOrganizationSelect = (orgId: string) => {
formData.value.organizationId = orgId formData.value.organizationId = orgId
} }
const handleToggleExpand = (orgId: string) => { const handleToggleExpand = (orgId: string) => {
if (organizationExpandedIds.value.has(orgId)) { if (organizationExpandedIds.value.has(orgId)) {
organizationExpandedIds.value.delete(orgId) organizationExpandedIds.value.delete(orgId)
...@@ -555,7 +508,6 @@ const handleToggleExpand = (orgId: string) => { ...@@ -555,7 +508,6 @@ const handleToggleExpand = (orgId: string) => {
organizationExpandedIds.value.add(orgId) organizationExpandedIds.value.add(orgId)
} }
} }
const isOrganizationSelectable = (orgType: string, roleId: string): boolean => { const isOrganizationSelectable = (orgType: string, roleId: string): boolean => {
// 只根据账号类型进行组织层级限制,不根据角色层级限制 // 只根据账号类型进行组织层级限制,不根据角色层级限制
const accountType = formData.value.accountType const accountType = formData.value.accountType
...@@ -575,33 +527,26 @@ const isOrganizationSelectable = (orgType: string, roleId: string): boolean => { ...@@ -575,33 +527,26 @@ const isOrganizationSelectable = (orgType: string, roleId: string): boolean => {
return true return true
} }
} }
const handleSave = () => { const handleSave = () => {
// 表单验证 // 表单验证
if (!formData.value.username.trim()) { if (!formData.value.username.trim()) {
ElMessage.error('请输入工号') ElMessage.error('请输入工号')
return return
} }
if (!formData.value.realName.trim()) { if (!formData.value.realName.trim()) {
ElMessage.error('请输入用户姓名') ElMessage.error('请输入用户姓名')
return return
} }
if (!formData.value.phone.trim()) { if (!formData.value.phone.trim()) {
ElMessage.error('请输入手机号') ElMessage.error('请输入手机号')
return return
} }
// 验证手机号格式 // 验证手机号格式
const phoneRegex = /^1[3-9]\d{9}$/ const phoneRegex = /^1[3-9]\d{9}$/
if (!phoneRegex.test(formData.value.phone.trim())) { if (!phoneRegex.test(formData.value.phone.trim())) {
ElMessage.error('请输入正确的11位手机号') ElMessage.error('请输入正确的11位手机号')
return return
} }
// 当前登录用户不需要验证组织(不可修改) // 当前登录用户不需要验证组织(不可修改)
if (!editingUser.value || !isCurrentUser(editingUser.value)) { if (!editingUser.value || !isCurrentUser(editingUser.value)) {
if (!formData.value.organizationId) { if (!formData.value.organizationId) {
...@@ -609,17 +554,14 @@ const handleSave = () => { ...@@ -609,17 +554,14 @@ const handleSave = () => {
return return
} }
} }
if (!formData.value.roleId) { if (!formData.value.roleId) {
ElMessage.error('请选择角色') ElMessage.error('请选择角色')
return return
} }
if (!formData.value.accountType) { if (!formData.value.accountType) {
ElMessage.error('请选择账号类型') ElMessage.error('请选择账号类型')
return return
} }
// 检查用户名是否重复 // 检查用户名是否重复
const existingUser = props.users.find(u => const existingUser = props.users.find(u =>
u.username === formData.value.username.trim() && u.id !== editingUser.value?.id u.username === formData.value.username.trim() && u.id !== editingUser.value?.id
...@@ -628,7 +570,6 @@ const handleSave = () => { ...@@ -628,7 +570,6 @@ const handleSave = () => {
ElMessage.error('该工号已存在') ElMessage.error('该工号已存在')
return return
} }
const userData: any = { const userData: any = {
username: formData.value.username.trim(), username: formData.value.username.trim(),
realName: formData.value.realName.trim(), realName: formData.value.realName.trim(),
...@@ -638,14 +579,10 @@ const handleSave = () => { ...@@ -638,14 +579,10 @@ const handleSave = () => {
phone: formData.value.phone.trim() || undefined, phone: formData.value.phone.trim() || undefined,
creatorId: props.currentUserId creatorId: props.currentUserId
} }
// 当前登录用户不可修改自己的所属组织 // 当前登录用户不可修改自己的所属组织
if (!editingUser.value || !isCurrentUser(editingUser.value)) { if (!editingUser.value || !isCurrentUser(editingUser.value)) {
userData.organizationId = formData.value.organizationId userData.organizationId = formData.value.organizationId
} }
if (editingUser.value) { if (editingUser.value) {
emit('updateUser', editingUser.value.id, userData) emit('updateUser', editingUser.value.id, userData)
ElMessage.success('用户更新成功') ElMessage.success('用户更新成功')
...@@ -653,10 +590,8 @@ const handleSave = () => { ...@@ -653,10 +590,8 @@ const handleSave = () => {
emit('addUser', userData) emit('addUser', userData)
ElMessage.success('用户创建成功') ElMessage.success('用户创建成功')
} }
isDialogOpen.value = false isDialogOpen.value = false
} }
// 组织下拉选项(扁平化带缩进) // 组织下拉选项(扁平化带缩进)
const organizationOptions = computed(() => { const organizationOptions = computed(() => {
const result: { id: string; label: string }[] = [] const result: { id: string; label: string }[] = []
...@@ -670,9 +605,7 @@ const organizationOptions = computed(() => { ...@@ -670,9 +605,7 @@ const organizationOptions = computed(() => {
traverse(props.organizations || []) traverse(props.organizations || [])
return result return result
}) })
</script> </script>
<style scoped> <style scoped>
/* 让表单项标签和输入框呈上下结构 */ /* 让表单项标签和输入框呈上下结构 */
:deep(.el-form-item) { :deep(.el-form-item) {
...@@ -680,197 +613,150 @@ const organizationOptions = computed(() => { ...@@ -680,197 +613,150 @@ const organizationOptions = computed(() => {
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
} }
:deep(.el-form-item__label) { :deep(.el-form-item__label) {
margin-bottom: 0; margin-bottom: 0;
text-align: left !important; text-align: left !important;
padding: 0 !important; padding: 0 !important;
} }
:deep(.el-form-item__content) { :deep(.el-form-item__content) {
margin-left: 0 !important; margin-left: 0 !important;
} }
.space-y-6 > * + * { .space-y-6 > * + * {
margin-top: 1.5rem; margin-top: 1.5rem;
} }
.space-y-4 > * + * { .space-y-4 > * + * {
margin-top: 1rem; margin-top: 1rem;
} }
.grid { .grid {
display: grid; display: grid;
} }
.grid-cols-2 { .grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: repeat(2, minmax(0, 1fr));
} }
.col-span-2 { .col-span-2 {
grid-column: span 2 / span 2; grid-column: span 2 / span 2;
} }
.grid-cols-4 { .grid-cols-4 {
grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-columns: repeat(4, minmax(0, 1fr));
} }
.grid-cols-5 { .grid-cols-5 {
grid-template-columns: repeat(5, minmax(0, 1fr)); grid-template-columns: repeat(5, minmax(0, 1fr));
} }
.gap-4 { .gap-4 {
gap: 1rem; gap: 1rem;
} }
.h-10 { .h-10 {
height: 2.5rem; height: 2.5rem;
} }
.w-full { .w-full {
width: 100%; width: 100%;
} }
.text-xs { .text-xs {
font-size: 0.75rem; font-size: 0.75rem;
line-height: 1rem; line-height: 1rem;
} }
.text-sm { .text-sm {
font-size: 0.875rem; font-size: 0.875rem;
line-height: 1.25rem; line-height: 1.25rem;
} }
.font-semibold { .font-semibold {
font-weight: 600; font-weight: 600;
} }
.font-bold { .font-bold {
font-weight: 700; font-weight: 700;
} }
.text-neutral-500 { .text-neutral-500 {
color: #6b7280; color: #6b7280;
} }
.text-neutral-700 { .text-neutral-700 {
color: #374151; color: #374151;
} }
.text-neutral-900 { .text-neutral-900 {
color: #111827; color: #111827;
} }
.text-blue-600 { .text-blue-600 {
color: #2563eb; color: #2563eb;
} }
.text-red-500 { .text-red-500 {
color: #ef4444; color: #ef4444;
} }
.border-neutral-200 { .border-neutral-200 {
border-color: #e5e7eb; border-color: #e5e7eb;
} }
.border-neutral-300 { .border-neutral-300 {
border-color: #d1d5db; border-color: #d1d5db;
} }
.bg-neutral-50 { .bg-neutral-50 {
background-color: #f9fafb; background-color: #f9fafb;
} }
.rounded { .rounded {
border-radius: 0.25rem; border-radius: 0.25rem;
} }
.rounded-lg { .rounded-lg {
border-radius: 0.5rem; border-radius: 0.5rem;
} }
.border { .border {
border-width: 1px; border-width: 1px;
} }
.border-b { .border-b {
border-bottom-width: 1px; border-bottom-width: 1px;
} }
.p-4 { .p-4 {
padding: 1rem; padding: 1rem;
} }
.p-5 { .p-5 {
padding: 1.25rem; padding: 1.25rem;
} }
.p-6 { .p-6 {
padding: 1.5rem; padding: 1.5rem;
} }
.px-4 { .px-4 {
padding-left: 1rem; padding-left: 1rem;
padding-right: 1rem; padding-right: 1rem;
} }
.py-3 { .py-3 {
padding-top: 0.75rem; padding-top: 0.75rem;
padding-bottom: 0.75rem; padding-bottom: 0.75rem;
} }
.pb-2 { .pb-2 {
padding-bottom: 0.5rem; padding-bottom: 0.5rem;
} }
.mt-1 { .mt-1 {
margin-top: 0.25rem; margin-top: 0.25rem;
} }
.mb-4 { .mb-4 {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.ml-2 { .ml-2 {
margin-left: 0.5rem; margin-left: 0.5rem;
} }
.mr-1 { .mr-1 {
margin-right: 0.25rem; margin-right: 0.25rem;
} }
.flex { .flex {
display: flex; display: flex;
} }
.items-center { .items-center {
align-items: center; align-items: center;
} }
.justify-between { .justify-between {
justify-content: space-between; justify-content: space-between;
} }
.gap-2 { .gap-2 {
gap: 0.5rem; gap: 0.5rem;
} }
.gap-3 { .gap-3 {
gap: 0.75rem; gap: 0.75rem;
} }
.overflow-hidden { .overflow-hidden {
overflow: hidden; overflow: hidden;
} }
.overflow-y-auto { .overflow-y-auto {
overflow-y: auto; overflow-y: auto;
} }
.max-h-\[400px\] { .max-h-\[400px\] {
max-height: 400px; max-height: 400px;
} }
/* 用户管理对话框样式 */ /* 用户管理对话框样式 */
:deep(.user-management-dialog) { :deep(.user-management-dialog) {
max-height: 90vh; max-height: 90vh;
...@@ -879,29 +765,24 @@ const organizationOptions = computed(() => { ...@@ -879,29 +765,24 @@ const organizationOptions = computed(() => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
:deep(.user-management-dialog .el-dialog__body) { :deep(.user-management-dialog .el-dialog__body) {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
max-height: calc(90vh - 120px); /* 减去头部和底部的空间 */ max-height: calc(90vh - 120px); /* 减去头部和底部的空间 */
padding: 24px !important; padding: 24px !important;
} }
:deep(.user-management-dialog .el-dialog__header) { :deep(.user-management-dialog .el-dialog__header) {
flex-shrink: 0; flex-shrink: 0;
padding: 24px 24px 0 24px !important; padding: 24px 24px 0 24px !important;
} }
:deep(.user-management-dialog .el-dialog__footer) { :deep(.user-management-dialog .el-dialog__footer) {
flex-shrink: 0; flex-shrink: 0;
padding: 0 24px 24px 24px !important; padding: 0 24px 24px 24px !important;
} }
/* 搜索输入框样式 - 与订单管理保持一致 */ /* 搜索输入框样式 - 与订单管理保持一致 */
:deep(.search-input .el-input__wrapper) { :deep(.search-input .el-input__wrapper) {
padding-left: 2.5rem !important; padding-left: 2.5rem !important;
} }
:deep(.search-input .el-input__inner) { :deep(.search-input .el-input__inner) {
padding-left: 0 !important; padding-left: 0 !important;
} }
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!