Commit f539d7a0 by 李宁

1

1 parent e5b81eec
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
{
"hash": "655e7fe4",
"configHash": "92cf418e",
"lockfileHash": "d600e0a3",
"browserHash": "d2e0d31b",
"optimized": {
"vue": {
"src": "../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "b7821ec5",
"needsInterop": false
},
"pinia": {
"src": "../../node_modules/pinia/dist/pinia.mjs",
"file": "pinia.js",
"fileHash": "a659a454",
"needsInterop": false
},
"element-plus": {
"src": "../../node_modules/element-plus/es/index.mjs",
"file": "element-plus.js",
"fileHash": "13083701",
"needsInterop": false
},
"@element-plus/icons-vue": {
"src": "../../node_modules/@element-plus/icons-vue/dist/index.js",
"file": "@element-plus_icons-vue.js",
"fileHash": "d67fc749",
"needsInterop": false
},
"axios": {
"src": "../../node_modules/axios/index.js",
"file": "axios.js",
"fileHash": "e22e391f",
"needsInterop": false
},
"vue-router": {
"src": "../../node_modules/vue-router/dist/vue-router.mjs",
"file": "vue-router.js",
"fileHash": "30652b08",
"needsInterop": false
}
},
"chunks": {
"chunk-XAE367SZ": {
"file": "chunk-XAE367SZ.js"
},
"chunk-YHMWYXEE": {
"file": "chunk-YHMWYXEE.js"
},
"chunk-G3PMV62Z": {
"file": "chunk-G3PMV62Z.js"
}
}
}
\ No newline at end of file \ No newline at end of file
This diff could not be displayed because it is too large.
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
export {
__commonJS,
__export,
__toESM
};
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
import {
BaseTransition,
BaseTransitionPropsValidators,
Comment,
DeprecationTypes,
EffectScope,
ErrorCodes,
ErrorTypeStrings,
Fragment,
KeepAlive,
ReactiveEffect,
Static,
Suspense,
Teleport,
Text,
TrackOpTypes,
Transition,
TransitionGroup,
TriggerOpTypes,
VueElement,
assertNumber,
callWithAsyncErrorHandling,
callWithErrorHandling,
camelize,
capitalize,
cloneVNode,
compatUtils,
compile,
computed,
createApp,
createBaseVNode,
createBlock,
createCommentVNode,
createElementBlock,
createHydrationRenderer,
createPropsRestProxy,
createRenderer,
createSSRApp,
createSlots,
createStaticVNode,
createTextVNode,
createVNode,
customRef,
defineAsyncComponent,
defineComponent,
defineCustomElement,
defineEmits,
defineExpose,
defineModel,
defineOptions,
defineProps,
defineSSRCustomElement,
defineSlots,
devtools,
effect,
effectScope,
getCurrentInstance,
getCurrentScope,
getCurrentWatcher,
getTransitionRawChildren,
guardReactiveProps,
h,
handleError,
hasInjectionContext,
hydrate,
hydrateOnIdle,
hydrateOnInteraction,
hydrateOnMediaQuery,
hydrateOnVisible,
initCustomFormatter,
initDirectivesForSSR,
inject,
isMemoSame,
isProxy,
isReactive,
isReadonly,
isRef,
isRuntimeOnly,
isShallow,
isVNode,
markRaw,
mergeDefaults,
mergeModels,
mergeProps,
nextTick,
normalizeClass,
normalizeProps,
normalizeStyle,
onActivated,
onBeforeMount,
onBeforeUnmount,
onBeforeUpdate,
onDeactivated,
onErrorCaptured,
onMounted,
onRenderTracked,
onRenderTriggered,
onScopeDispose,
onServerPrefetch,
onUnmounted,
onUpdated,
onWatcherCleanup,
openBlock,
popScopeId,
provide,
proxyRefs,
pushScopeId,
queuePostFlushCb,
reactive,
readonly,
ref,
registerRuntimeCompiler,
render,
renderList,
renderSlot,
resolveComponent,
resolveDirective,
resolveDynamicComponent,
resolveFilter,
resolveTransitionHooks,
setBlockTracking,
setDevtoolsHook,
setTransitionHooks,
shallowReactive,
shallowReadonly,
shallowRef,
ssrContextKey,
ssrUtils,
stop,
toDisplayString,
toHandlerKey,
toHandlers,
toRaw,
toRef,
toRefs,
toValue,
transformVNodeArgs,
triggerRef,
unref,
useAttrs,
useCssModule,
useCssVars,
useHost,
useId,
useModel,
useSSRContext,
useShadowRoot,
useSlots,
useTemplateRef,
useTransitionState,
vModelCheckbox,
vModelDynamic,
vModelRadio,
vModelSelect,
vModelText,
vShow,
version,
warn,
watch,
watchEffect,
watchPostEffect,
watchSyncEffect,
withAsyncContext,
withCtx,
withDefaults,
withDirectives,
withKeys,
withMemo,
withModifiers,
withScopeId
} from "./chunk-YHMWYXEE.js";
import "./chunk-G3PMV62Z.js";
export {
BaseTransition,
BaseTransitionPropsValidators,
Comment,
DeprecationTypes,
EffectScope,
ErrorCodes,
ErrorTypeStrings,
Fragment,
KeepAlive,
ReactiveEffect,
Static,
Suspense,
Teleport,
Text,
TrackOpTypes,
Transition,
TransitionGroup,
TriggerOpTypes,
VueElement,
assertNumber,
callWithAsyncErrorHandling,
callWithErrorHandling,
camelize,
capitalize,
cloneVNode,
compatUtils,
compile,
computed,
createApp,
createBlock,
createCommentVNode,
createElementBlock,
createBaseVNode as createElementVNode,
createHydrationRenderer,
createPropsRestProxy,
createRenderer,
createSSRApp,
createSlots,
createStaticVNode,
createTextVNode,
createVNode,
customRef,
defineAsyncComponent,
defineComponent,
defineCustomElement,
defineEmits,
defineExpose,
defineModel,
defineOptions,
defineProps,
defineSSRCustomElement,
defineSlots,
devtools,
effect,
effectScope,
getCurrentInstance,
getCurrentScope,
getCurrentWatcher,
getTransitionRawChildren,
guardReactiveProps,
h,
handleError,
hasInjectionContext,
hydrate,
hydrateOnIdle,
hydrateOnInteraction,
hydrateOnMediaQuery,
hydrateOnVisible,
initCustomFormatter,
initDirectivesForSSR,
inject,
isMemoSame,
isProxy,
isReactive,
isReadonly,
isRef,
isRuntimeOnly,
isShallow,
isVNode,
markRaw,
mergeDefaults,
mergeModels,
mergeProps,
nextTick,
normalizeClass,
normalizeProps,
normalizeStyle,
onActivated,
onBeforeMount,
onBeforeUnmount,
onBeforeUpdate,
onDeactivated,
onErrorCaptured,
onMounted,
onRenderTracked,
onRenderTriggered,
onScopeDispose,
onServerPrefetch,
onUnmounted,
onUpdated,
onWatcherCleanup,
openBlock,
popScopeId,
provide,
proxyRefs,
pushScopeId,
queuePostFlushCb,
reactive,
readonly,
ref,
registerRuntimeCompiler,
render,
renderList,
renderSlot,
resolveComponent,
resolveDirective,
resolveDynamicComponent,
resolveFilter,
resolveTransitionHooks,
setBlockTracking,
setDevtoolsHook,
setTransitionHooks,
shallowReactive,
shallowReadonly,
shallowRef,
ssrContextKey,
ssrUtils,
stop,
toDisplayString,
toHandlerKey,
toHandlers,
toRaw,
toRef,
toRefs,
toValue,
transformVNodeArgs,
triggerRef,
unref,
useAttrs,
useCssModule,
useCssVars,
useHost,
useId,
useModel,
useSSRContext,
useShadowRoot,
useSlots,
useTemplateRef,
useTransitionState,
vModelCheckbox,
vModelDynamic,
vModelRadio,
vModelSelect,
vModelText,
vShow,
version,
warn,
watch,
watchEffect,
watchPostEffect,
watchSyncEffect,
withAsyncContext,
withCtx,
withDefaults,
withDirectives,
withKeys,
withMemo,
withModifiers,
withScopeId
};
{
"version": 3,
"sources": [],
"sourcesContent": [],
"mappings": "",
"names": []
}
...@@ -270,6 +270,8 @@ if (props.expandedIds && props.expandedIds.size === 0) { ...@@ -270,6 +270,8 @@ if (props.expandedIds && props.expandedIds.size === 0) {
} }
}) })
} }
</script> </script>
<style scoped> <style scoped>
.space-y-1 > * + * { .space-y-1 > * + * {
......
...@@ -360,7 +360,7 @@ const handleSave = async () => { ...@@ -360,7 +360,7 @@ const handleSave = async () => {
}) })
if (response.c === 0) { if (response.c === 0) {
handleFilter() handleFilter()
ElMessage.success('创建成功'); ElMessage.success(editingRole.value?'编辑成功':'创建成功');
} else { } else {
ElMessage.error(response.m); ElMessage.error(response.m);
} }
......
...@@ -21,36 +21,41 @@ ...@@ -21,36 +21,41 @@
<div class="relative"> <div class="relative">
<Search class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-500 z-10" /> <Search class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-500 z-10" />
<el-input <el-input
v-model="generalSearch" v-model="userNameSearch"
placeholder="搜索用户姓名/手机号/工号" placeholder="搜索用户姓名"
class="h-10 search-input text-ellipsis-input" class="h-10 search-input text-ellipsis-input"
clearable clearable
/> />
</div> </div>
<el-select <div class="relative">
v-model="roleFilter" <Search class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-500 z-10" />
placeholder="角色" <el-input
class="h-10 w-full" v-model="phoneSearch"
clearable placeholder="搜索手机号"
> class="h-10 search-input text-ellipsis-input"
<el-option label="全部角色" value="all" /> clearable
<el-option
v-for="role in availableRoles"
:key="role.id"
:label="role.name"
:value="role.id"
/> />
</el-select> </div>
<div class="relative">
<Search class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-neutral-500 z-10" />
<el-input
v-model="codeSearch"
placeholder="搜索工号"
class="h-10 search-input text-ellipsis-input"
clearable
/>
</div>
<el-select <el-select
v-model="accountTypeFilter" v-model="accountTypeFilter"
placeholder="账号类型" placeholder="账号类型"
class="h-10 w-full" class="h-10 w-full"
clearable clearable
> >
<el-option label="全部类型" value="all" /> <el-option label="全部类型" value="" />
<el-option label="地市级" value="地市级" /> <el-option label="地市级" value="1" />
<el-option label="区县级" value="区县级" /> <el-option label="区县级" value="2" />
<el-option label="一线人员" value="一线人员" /> <el-option label="一线人员" value="3" />
</el-select> </el-select>
<el-select <el-select
v-model="statusFilter" v-model="statusFilter"
...@@ -59,16 +64,16 @@ ...@@ -59,16 +64,16 @@
clearable clearable
> >
<el-option label="全部状态" value="all" /> <el-option label="全部状态" value="all" />
<el-option label="正常" value="正常" /> <el-option label="正常" value="1" />
<el-option label="禁用" value="禁用" /> <el-option label="禁用" value="0" />
</el-select> </el-select>
<el-select <el-select
v-model="organizationFilter" v-model="organizationFilter"
placeholder="所属组织" placeholder="所属区域"
class="h-10 w-full" class="h-10 w-full"
clearable clearable
> >
<el-option label="全部组织" value="all" /> <el-option label="全部区域" value="all" />
<el-option <el-option
v-for="org in organizationOptions" v-for="org in organizationOptions"
:key="org.id" :key="org.id"
...@@ -232,7 +237,7 @@ ...@@ -232,7 +237,7 @@
<el-option <el-option
v-for="role in availableRoles" v-for="role in availableRoles"
:key="role.id" :key="role.id"
:label="`${role.name}${role.description ? ` - ${role.description}` : ''}`" :label="`${role.roleName}${role.remark ? ` - ${role.remark}` : ''}`"
:value="role.id" :value="role.id"
/> />
</el-select> </el-select>
...@@ -254,7 +259,7 @@ ...@@ -254,7 +259,7 @@
<!-- 所属组织(当前登录用户不可修改) --> <!-- 所属组织(当前登录用户不可修改) -->
<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">
<h3 class="text-neutral-900">所属组织 <span class="text-red-500">*</span></h3> <h3 class="text-neutral-900">所属区域 <span class="text-red-500">*</span></h3>
<el-tag <el-tag
v-if="formData.organizationId" v-if="formData.organizationId"
type="primary" type="primary"
...@@ -312,10 +317,11 @@ ...@@ -312,10 +317,11 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch } from 'vue' import { ref, computed, watch ,onMounted,getCurrentInstance} 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'
const { $api } = getCurrentInstance()!.appContext.config.globalProperties
// 类型定义 // 类型定义
export interface User { export interface User {
id: string id: string
...@@ -360,10 +366,12 @@ const emit = defineEmits<{ ...@@ -360,10 +366,12 @@ const emit = defineEmits<{
// 响应式数据 // 响应式数据
const isDialogOpen = ref(false) const isDialogOpen = ref(false)
const editingUser = ref<User | null>(null) const editingUser = ref<User | null>(null)
const generalSearch = ref('') const userNameSearch = ref('')
const phoneSearch = ref('')
const codeSearch = ref('')
const roleFilter = ref<string>('all') const roleFilter = ref<string>('all')
const accountTypeFilter = ref<'all' | '地市级' | '区县级' | '一线人员'>('all') const accountTypeFilter = ref<'' | '1' | '2' | '3'>('')
const statusFilter = ref<'all' | '正常' | '禁用'>('all') const statusFilter = ref<'' | '1' | '0'>('')
const organizationFilter = ref<string>('all') const organizationFilter = ref<string>('all')
const organizationExpandedIds = ref(new Set<string>()) const organizationExpandedIds = ref(new Set<string>())
// 表单数据 // 表单数据
...@@ -371,18 +379,47 @@ const formData = ref({ ...@@ -371,18 +379,47 @@ const formData = ref({
username: '', username: '',
realName: '', realName: '',
phone: '', phone: '',
accountType: '一线人员' as '地市级' | '区县级' | '一线人员', accountType: '',
organizationId: '', organizationId: '',
roleId: '', roleId: '',
isActive: true isActive: true
}) })
// 计算属性 // 计算属性
const availableRoles = computed(() => const availableRoles = ref([])
props.roles.filter(r => r.status === '启用' && r.name !== '地市主管理员') const filteredUsers = ref([])
)
const topLevelOrganizations = computed(() => const topLevelOrganizations = computed(() =>
props.organizations.filter(o => !o.parentId) props.organizations.filter(o => o.id)
) )
onMounted(() => {
getRoleList()
getAccountList()
})
const getRoleList = async ()=>{
try {
const response = await $api.queryRoleList({})
if (response && response.c === 0) {
availableRoles.value = response.d.filter(item=>{return item.status==1})
}
} catch (error) {
}
}
const getAccountList = async ()=>{
try {
const response = await $api.queryAccountList({
phone: '',
status: '',
})
if (response && response.c === 0) {
filteredUsers.value = response.d
}
} catch (error) {
}
}
const totalUsers = computed(() => props.users.length - 1) // 排除当前登录用户 const totalUsers = computed(() => props.users.length - 1) // 排除当前登录用户
const hasFilters = computed(() => const hasFilters = computed(() =>
generalSearch.value !== '' || generalSearch.value !== '' ||
...@@ -391,27 +428,7 @@ const hasFilters = computed(() => ...@@ -391,27 +428,7 @@ const hasFilters = computed(() =>
statusFilter.value !== 'all' || statusFilter.value !== 'all' ||
organizationFilter.value !== 'all' organizationFilter.value !== 'all'
) )
const filteredUsers = computed(() => {
return props.users.filter(user => {
// 过滤掉当前登录用户
if (user.id === props.currentUserId) return false
// 通用搜索:支持搜索用户姓名、手机号、工号
const searchTerm = generalSearch.value.toLowerCase()
let matchGeneral = true
if (searchTerm !== '') {
matchGeneral = user.realName.toLowerCase().includes(searchTerm) ||
(user.phone && user.phone.toLowerCase().includes(searchTerm)) ||
user.username.toLowerCase().includes(searchTerm)
}
const matchRole = roleFilter.value === 'all' || user.roleId === roleFilter.value
const matchAccountType = accountTypeFilter.value === 'all' || user.accountType === accountTypeFilter.value
const matchStatus = statusFilter.value === 'all' || user.status === statusFilter.value
const matchOrganization = organizationFilter.value === 'all' || user.organizationId === organizationFilter.value
return matchGeneral && matchRole && matchAccountType && matchStatus && matchOrganization
})
})
const roleHint = computed(() => { const roleHint = computed(() => {
if (!formData.value.roleId) return '' if (!formData.value.roleId) return ''
...@@ -527,7 +544,7 @@ const isOrganizationSelectable = (orgType: string, roleId: string): boolean => { ...@@ -527,7 +544,7 @@ const isOrganizationSelectable = (orgType: string, roleId: string): boolean => {
return true return true
} }
} }
const handleSave = () => { const handleSave = async () => {
// 表单验证 // 表单验证
if (!formData.value.username.trim()) { if (!formData.value.username.trim()) {
ElMessage.error('请输入工号') ElMessage.error('请输入工号')
...@@ -547,21 +564,22 @@ const handleSave = () => { ...@@ -547,21 +564,22 @@ const handleSave = () => {
ElMessage.error('请输入正确的11位手机号') ElMessage.error('请输入正确的11位手机号')
return return
} }
// 当前登录用户不需要验证组织(不可修改) if (!formData.value.accountType) {
if (!editingUser.value || !isCurrentUser(editingUser.value)) { ElMessage.error('请选择账号类型')
if (!formData.value.organizationId) { return
ElMessage.error('请选择所属组织')
return
}
} }
if (!formData.value.roleId) { if (!formData.value.roleId) {
ElMessage.error('请选择角色') ElMessage.error('请选择角色')
return return
} }
if (!formData.value.accountType) { // 当前登录用户不需要验证组织(不可修改)
ElMessage.error('请选择账号类型') if (!editingUser.value || !isCurrentUser(editingUser.value)) {
return if (!formData.value.organizationId) {
ElMessage.error('请选择所属区域')
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
...@@ -580,16 +598,22 @@ const handleSave = () => { ...@@ -580,16 +598,22 @@ const handleSave = () => {
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) {
emit('updateUser', editingUser.value.id, userData)
ElMessage.success('用户更新成功')
const response = await $api.addAndUpdateRole({
})
if (response.c === 0) {
//handleFilter()
ElMessage.success(editingUser.value?'编辑成功':'创建成功');
} else { } else {
emit('addUser', userData) ElMessage.error(response.m);
ElMessage.success('用户创建成功')
} }
isDialogOpen.value = false isDialogOpen.value = false
} }
// 组织下拉选项(扁平化带缩进) // 组织下拉选项(扁平化带缩进)
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!