feat: 注册页加部门选择/用户管理修部门下拉/超管可跨店建用户/公开部门接口

This commit is contained in:
li
2026-03-14 18:28:35 +08:00
parent f7adb5f609
commit 94b46611d3
98 changed files with 209 additions and 129 deletions
+43 -16
View File
@@ -7,12 +7,15 @@ import axios from 'axios'
const router = useRouter()
const loading = ref(false)
const packagesLoading = ref(false)
const deptLoading = ref(false)
const packages = ref([])
const stores = ref([])
const departments = ref([])
const form = reactive({
store_id: '',
registration_package_id: '',
department_id: '',
username: '',
password: '',
name: '',
@@ -22,7 +25,7 @@ const form = reactive({
const formRef = ref(null)
const rules = {
store_id: [{ required: true, message: '请选择门店', trigger: 'change' }],
registration_package_id: [{ required: true, message: '请选择岗位套餐', trigger: 'change' }],
registration_package_id: [{ required: true, message: '请选择申请岗位', trigger: 'change' }],
username: [
{ required: true, message: '请输入登录账号', trigger: 'blur' },
{ min: 2, max: 50, message: '2-50个字符', trigger: 'blur' },
@@ -47,19 +50,29 @@ async function fetchStores() {
}
}
async function fetchPackages() {
if (!form.store_id) return
packagesLoading.value = true
async function onStoreChange() {
form.registration_package_id = ''
form.department_id = ''
packages.value = []
departments.value = []
if (!form.store_id) return
packagesLoading.value = true
deptLoading.value = true
try {
const res = await axios.get('/api/v1/auth/register/packages', {
params: { store_id: form.store_id },
})
packages.value = res.data?.data || []
const [pkgRes, deptRes] = await Promise.all([
axios.get('/api/v1/auth/register/packages', { params: { store_id: form.store_id } }),
axios.get('/api/v1/auth/register/departments', { params: { store_id: form.store_id } }),
])
packages.value = pkgRes.data?.data || []
departments.value = deptRes.data?.data || []
} catch {
packages.value = []
departments.value = []
} finally {
packagesLoading.value = false
deptLoading.value = false
}
}
@@ -95,22 +108,19 @@ onMounted(fetchStores)
</div>
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
<!-- 门店 -->
<el-form-item label="所属门店" prop="store_id">
<el-select
v-model="form.store_id"
placeholder="请选择门店"
style="width: 100%"
@change="fetchPackages"
@change="onStoreChange"
>
<el-option
v-for="s in stores"
:key="s.id"
:label="s.name"
:value="s.id"
/>
<el-option v-for="s in stores" :key="s.id" :label="s.name" :value="s.id" />
</el-select>
</el-form-item>
<!-- 申请岗位套餐 -->
<el-form-item label="申请岗位" prop="registration_package_id">
<el-select
v-model="form.registration_package_id"
@@ -129,7 +139,24 @@ onMounted(fetchStores)
<span v-if="p.description" class="text-gray-400 text-xs ml-2">{{ p.description }}</span>
</el-option>
<template v-if="packages.length === 0 && form.store_id && !packagesLoading" #empty>
<div class="text-center py-4 text-gray-400 text-sm">该门店暂无可用套餐</div>
<div class="text-center py-4 text-gray-400 text-sm">该门店暂无可用套餐,请联系管理员</div>
</template>
</el-select>
</el-form-item>
<!-- 所属部门 -->
<el-form-item label="所属部门" prop="department_id">
<el-select
v-model="form.department_id"
placeholder="请先选择门店"
style="width: 100%"
:loading="deptLoading"
:disabled="!form.store_id"
clearable
>
<el-option v-for="d in departments" :key="d.id" :label="d.name" :value="d.id" />
<template v-if="departments.length === 0 && form.store_id && !deptLoading" #empty>
<div class="text-center py-4 text-gray-400 text-sm">该门店暂无部门数据</div>
</template>
</el-select>
</el-form-item>
+36 -13
View File
@@ -1,11 +1,16 @@
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, onMounted, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { userApi, roleApi, departmentApi } from '@/api/system.js'
import { userApi, roleApi, departmentApi, storeApi } from '@/api/system.js'
import { useUserStore } from '@/stores/user.js'
const userStore = useUserStore()
const isSuper = computed(() => userStore.userInfo?.is_super)
// ─── State ───────────────────────────────────────────────────────────────────
const tableData = ref([])
const stores = ref([])
const total = ref(0)
const loading = ref(false)
const dialogVisible = ref(false)
@@ -42,7 +47,8 @@ const form = reactive({
role_ids: [],
status: 1,
password: '',
password_confirm: ''
password_confirm: '',
store_id: ''
})
const isEdit = ref(false)
@@ -99,6 +105,14 @@ const resetPwdRules = {
// ─── Methods ──────────────────────────────────────────────────────────────────
function flattenDeptTree(nodes, result = []) {
for (const n of nodes) {
result.push({ id: n.id, name: n.name })
if (n.children?.length) flattenDeptTree(n.children, result)
}
return result
}
async function fetchList() {
loading.value = true
try {
@@ -124,7 +138,9 @@ async function fetchRoles() {
async function fetchDepartments() {
try {
const res = await departmentApi.getList({ per_page: 500 })
departments.value = res.data?.list || res.data?.data || []
// API returns tree array directly in res.data, flatten it for selects
const raw = Array.isArray(res.data) ? res.data : (res.data?.list || res.data?.data || [])
departments.value = flattenDeptTree(raw)
} catch {
//
}
@@ -146,7 +162,7 @@ function handleAdd() {
Object.assign(form, {
id: null, username: '', name: '', phone: '', email: '',
department_id: '', position_id: '', role_ids: [], status: 1,
password: '', password_confirm: ''
password: '', password_confirm: '', store_id: ''
})
dialogVisible.value = true
}
@@ -276,6 +292,11 @@ onMounted(() => {
fetchList()
fetchRoles()
fetchDepartments()
if (isSuper.value) {
storeApi.getList({ page_size: 200 }).then(res => {
stores.value = res.data?.list || []
}).catch(() => {})
}
})
</script>
@@ -411,6 +432,13 @@ onMounted(() => {
label-position="right"
>
<el-row :gutter="16">
<el-col v-if="isSuper && !isEdit" :span="24">
<el-form-item label="所属门店" prop="store_id">
<el-select v-model="form.store_id" placeholder="超管可指定门店(不选则为当前门店)" clearable style="width:100%">
<el-option v-for="s in stores" :key="s.id" :label="s.name" :value="s.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" placeholder="请输入用户名" :disabled="isEdit" />
@@ -433,14 +461,9 @@ onMounted(() => {
</el-col>
<el-col :span="12">
<el-form-item label="部门" prop="department_id">
<el-tree-select
v-model="form.department_id"
:data="departments"
:props="{ label: 'name', value: 'id', children: 'children' }"
placeholder="选择部门"
clearable
style="width: 100%"
/>
<el-select v-model="form.department_id" placeholder="选择部门" clearable style="width:100%">
<el-option v-for="d in departments" :key="d.id" :label="d.name" :value="d.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">