init
This commit is contained in:
parent
446f4475f1
commit
abbc1dd7a6
|
|
@ -0,0 +1,716 @@
|
|||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useUserStore } from '../../stores/user'
|
||||
import { apiFetch } from '../../lib/api'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const users = ref([])
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
|
||||
// 分页相关
|
||||
const page = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
|
||||
// 表单状态
|
||||
const showAddModal = ref(false)
|
||||
const showEditModal = ref(false)
|
||||
const currentUser = ref(null)
|
||||
|
||||
// 表单数据
|
||||
const form = ref({
|
||||
userName: '',
|
||||
password: '',
|
||||
roleId: '',
|
||||
name: '',
|
||||
email: '',
|
||||
phone: ''
|
||||
})
|
||||
|
||||
// 验证错误
|
||||
const formErrors = ref({})
|
||||
|
||||
// 加载用户列表
|
||||
async function loadUsers() {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
|
||||
try {
|
||||
const res = await apiFetch(`/api/users?page=${page.value}&pageSize=${pageSize.value}`)
|
||||
if (res?.data) {
|
||||
users.value = res.data.users || []
|
||||
total.value = res.data.total || 0
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message || '加载用户列表失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
function resetForm() {
|
||||
form.value = {
|
||||
userName: '',
|
||||
password: '',
|
||||
roleId: '',
|
||||
mobile: '',
|
||||
orgId: ''
|
||||
}
|
||||
formErrors.value = {}
|
||||
}
|
||||
|
||||
// 打开添加用户模态框
|
||||
function openAddModal() {
|
||||
resetForm()
|
||||
showAddModal.value = true
|
||||
}
|
||||
|
||||
// 打开编辑用户模态框
|
||||
function openEditModal(user) {
|
||||
currentUser.value = user
|
||||
form.value = {
|
||||
userName: user.userName || '',
|
||||
password: '', // 编辑时不显示密码
|
||||
roleId: user.roleId || '',
|
||||
mobile: user.mobile || '',
|
||||
orgId: user.orgId || ''
|
||||
}
|
||||
formErrors.value = {}
|
||||
showEditModal.value = true
|
||||
}
|
||||
|
||||
// 验证表单
|
||||
function validateForm() {
|
||||
formErrors.value = {}
|
||||
let isValid = true
|
||||
|
||||
if (!form.value.userName.trim()) {
|
||||
formErrors.value.userName = '用户名不能为空'
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (!form.value.password.trim() && !currentUser.value) {
|
||||
formErrors.value.password = '密码不能为空'
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (!form.value.roleId) {
|
||||
formErrors.value.roleId = '角色不能为空'
|
||||
isValid = false
|
||||
}
|
||||
|
||||
if (!form.value.orgId) {
|
||||
formErrors.value.orgId = '机构不能为空'
|
||||
isValid = false
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
// 添加用户
|
||||
async function addUser() {
|
||||
if (!validateForm()) return
|
||||
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
|
||||
try {
|
||||
await apiFetch('/api/users', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(form.value)
|
||||
})
|
||||
showAddModal.value = false
|
||||
await loadUsers()
|
||||
} catch (err) {
|
||||
error.value = err.message || '添加用户失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户
|
||||
async function updateUser() {
|
||||
if (!validateForm() || !currentUser.value) return
|
||||
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
|
||||
try {
|
||||
const updateData = { ...form.value }
|
||||
// 如果密码为空,则不更新密码
|
||||
if (!updateData.password.trim()) {
|
||||
delete updateData.password
|
||||
}
|
||||
|
||||
await apiFetch(`/api/users/${currentUser.value.id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(updateData)
|
||||
})
|
||||
showEditModal.value = false
|
||||
await loadUsers()
|
||||
} catch (err) {
|
||||
error.value = err.message || '更新用户失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
async function deleteUser(userId) {
|
||||
if (!confirm('确定要删除该用户吗?')) return
|
||||
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
|
||||
try {
|
||||
await apiFetch(`/api/users/${userId}`, {
|
||||
method: 'DELETE'
|
||||
})
|
||||
await loadUsers()
|
||||
} catch (err) {
|
||||
error.value = err.message || '删除用户失败'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时获取用户列表
|
||||
onMounted(() => {
|
||||
loadUsers()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="user-page">
|
||||
<div class="page-header">
|
||||
<h1>用户管理</h1>
|
||||
<button class="btn-primary" @click="openAddModal">添加用户</button>
|
||||
</div>
|
||||
|
||||
<div v-if="error" class="error-message">{{ error }}</div>
|
||||
|
||||
<div class="user-list">
|
||||
<table class="user-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>用户名</th>
|
||||
<th>手机</th>
|
||||
<th>角色ID</th>
|
||||
<th>机构ID</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="user in users" :key="user.id">
|
||||
<td>{{ user.userName }}</td>
|
||||
<td>{{ user.mobile || '-' }}</td>
|
||||
<td>{{ user.roleId || '-' }}</td>
|
||||
<td>{{ user.orgId || '-' }}</td>
|
||||
<td class="actions">
|
||||
<button class="btn-edit" @click="openEditModal(user)">编辑</button>
|
||||
<button class="btn-delete" @click="deleteUser(user.id)">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div v-if="loading" class="loading">加载中...</div>
|
||||
<div v-else-if="users.length === 0" class="empty">暂无用户数据</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页组件 -->
|
||||
<div v-if="total > 0" class="pagination">
|
||||
<div class="pagination-info">
|
||||
共 {{ total }} 条记录,每页 {{ pageSize }} 条,第 {{ page }} / {{ Math.ceil(total / pageSize) }} 页
|
||||
</div>
|
||||
<div class="pagination-controls">
|
||||
<button
|
||||
class="pagination-btn"
|
||||
@click="page = 1; loadUsers()"
|
||||
:disabled="page === 1"
|
||||
>
|
||||
首页
|
||||
</button>
|
||||
<button
|
||||
class="pagination-btn"
|
||||
@click="page--; loadUsers()"
|
||||
:disabled="page === 1"
|
||||
>
|
||||
上一页
|
||||
</button>
|
||||
<button
|
||||
class="pagination-btn"
|
||||
@click="page++; loadUsers()"
|
||||
:disabled="page >= Math.ceil(total / pageSize)"
|
||||
>
|
||||
下一页
|
||||
</button>
|
||||
<button
|
||||
class="pagination-btn"
|
||||
@click="page = Math.ceil(total / pageSize); loadUsers()"
|
||||
:disabled="page >= Math.ceil(total / pageSize)"
|
||||
>
|
||||
末页
|
||||
</button>
|
||||
<select v-model="pageSize" @change="page = 1; loadUsers()" class="pagination-select">
|
||||
<option value="10">10条/页</option>
|
||||
<option value="20">20条/页</option>
|
||||
<option value="50">50条/页</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加用户模态框 -->
|
||||
<div v-if="showAddModal" class="modal" @click.self="showAddModal = false">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2>添加用户</h2>
|
||||
<button class="modal-close" @click="showAddModal = false">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="addUser">
|
||||
<div class="form-group">
|
||||
<label>用户名</label>
|
||||
<input v-model="form.userName" type="text" class="form-input" />
|
||||
<div v-if="formErrors.userName" class="form-error">{{ formErrors.userName }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>密码</label>
|
||||
<input v-model="form.password" type="password" class="form-input" />
|
||||
<div v-if="formErrors.password" class="form-error">{{ formErrors.password }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>角色ID</label>
|
||||
<input v-model="form.roleId" type="text" class="form-input" />
|
||||
<div v-if="formErrors.roleId" class="form-error">{{ formErrors.roleId }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>手机</label>
|
||||
<input v-model="form.mobile" type="tel" class="form-input" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>机构ID</label>
|
||||
<input v-model="form.orgId" type="text" class="form-input" />
|
||||
<div v-if="formErrors.orgId" class="form-error">{{ formErrors.orgId }}</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn-cancel" @click="showAddModal = false">取消</button>
|
||||
<button type="submit" class="btn-primary" :disabled="loading">
|
||||
{{ loading ? '提交中...' : '提交' }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑用户模态框 -->
|
||||
<div v-if="showEditModal" class="modal" @click.self="showEditModal = false">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2>编辑用户</h2>
|
||||
<button class="modal-close" @click="showEditModal = false">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form @submit.prevent="updateUser">
|
||||
<div class="form-group">
|
||||
<label>用户名</label>
|
||||
<input v-model="form.userName" type="text" class="form-input" />
|
||||
<div v-if="formErrors.userName" class="form-error">{{ formErrors.userName }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>密码(留空则不修改)</label>
|
||||
<input v-model="form.password" type="password" class="form-input" />
|
||||
<div v-if="formErrors.password" class="form-error">{{ formErrors.password }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>角色ID</label>
|
||||
<input v-model="form.roleId" type="text" class="form-input" />
|
||||
<div v-if="formErrors.roleId" class="form-error">{{ formErrors.roleId }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>手机</label>
|
||||
<input v-model="form.mobile" type="tel" class="form-input" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>机构ID</label>
|
||||
<input v-model="form.orgId" type="text" class="form-input" />
|
||||
<div v-if="formErrors.orgId" class="form-error">{{ formErrors.orgId }}</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="button" class="btn-cancel" @click="showEditModal = false">取消</button>
|
||||
<button type="submit" class="btn-primary" :disabled="loading">
|
||||
{{ loading ? '提交中...' : '提交' }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.user-page {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
font-size: 20px;
|
||||
font-weight: 900;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
height: 36px;
|
||||
padding: 0 16px;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
background: linear-gradient(135deg, #b48040, #205c40);
|
||||
color: white;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-primary:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
height: 28px;
|
||||
padding: 0 12px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #b48040;
|
||||
background: white;
|
||||
color: #b48040;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
margin-right: 8px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-edit:hover {
|
||||
background: #f9f0e6;
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
height: 28px;
|
||||
padding: 0 12px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e53e3e;
|
||||
background: white;
|
||||
color: #e53e3e;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background: #fed7d7;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
height: 36px;
|
||||
padding: 0 16px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #d1d5db;
|
||||
background: white;
|
||||
color: #374151;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
margin-right: 12px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-cancel:hover {
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background: #fed7d7;
|
||||
color: #c53030;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.user-list {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.user-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.user-table th {
|
||||
background: #f9fafb;
|
||||
padding: 12px 16px;
|
||||
text-align: left;
|
||||
font-weight: 800;
|
||||
font-size: 14px;
|
||||
color: #374151;
|
||||
border-bottom: 2px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.user-table td {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.user-table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loading {
|
||||
padding: 48px;
|
||||
text-align: center;
|
||||
color: #6b7280;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding: 48px;
|
||||
text-align: center;
|
||||
color: #6b7280;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.modal-header h2 {
|
||||
font-size: 18px;
|
||||
font-weight: 900;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
color: #6b7280;
|
||||
padding: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.modal-close:hover {
|
||||
background: #f3f4f6;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
color: #374151;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
outline: none;
|
||||
border-color: #b48040;
|
||||
box-shadow: 0 0 0 3px rgba(180, 128, 64, 0.1);
|
||||
}
|
||||
|
||||
.form-error {
|
||||
font-size: 12px;
|
||||
color: #e53e3e;
|
||||
margin-top: 4px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
/* 分页样式 */
|
||||
.pagination {
|
||||
margin-top: 24px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.pagination-info {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.pagination-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.pagination-btn {
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #d1d5db;
|
||||
background: white;
|
||||
color: #374151;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.pagination-btn:hover:not(:disabled) {
|
||||
background: #f3f4f6;
|
||||
border-color: #b48040;
|
||||
}
|
||||
|
||||
.pagination-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.pagination-select {
|
||||
height: 32px;
|
||||
padding: 0 8px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #d1d5db;
|
||||
background: white;
|
||||
color: #374151;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pagination-select:focus {
|
||||
outline: none;
|
||||
border-color: #b48040;
|
||||
box-shadow: 0 0 0 3px rgba(180, 128, 64, 0.1);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.user-page {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.user-table {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.user-table th,
|
||||
.user-table td {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.btn-edit,
|
||||
.btn-delete {
|
||||
margin-right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.pagination-controls {
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.pagination-btn {
|
||||
flex: 1;
|
||||
min-width: 80px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -50,9 +50,16 @@ const router = createRouter({
|
|||
{ path: 'home', component: AdminHome },
|
||||
{ path: 'archives', name: 'admin-archives', component: Archives },
|
||||
{ path: 'inspections', name: 'admin-inspections', component: Inspections },
|
||||
{ path: 'projects', name: 'admin-projects', component: Projects },
|
||||
{ path: 'system', name: 'admin-analytics', component: Analytics },
|
||||
{ path: 'org/list', name: 'admin-org', component: () => import('../pages/org/list.vue') },
|
||||
{ path: 'system/user', name: 'admin-system-usr', component: () => import('../pages/system/user.vue') },
|
||||
{ path: 'system/role', name: 'admin-system-role', component: () => import('../pages/system/role.vue') },
|
||||
{ path: 'system/option', name: 'admin-system-option', component: () => import('../pages/system/option.vue') },
|
||||
{ path: 'org/list', name: 'admin-org-list', component: () => import('../pages/org/list.vue') },
|
||||
{ path: 'org/person', name: 'admin-org-person', component: () => import('../pages/org/person.vue') },
|
||||
{ path: 'device/summary', name: 'admin-device-summary', component: () => import('../pages/device/summary.vue') },
|
||||
{ path: 'device/list', name: 'admin-device-list', component: () => import('../pages/device/list.vue') },
|
||||
{ path: 'project/list', name: 'admin-project-list', component: () => import('../pages/project/list.vue') },
|
||||
{ path: 'project/detail', name: 'admin-project-detail', component: () => import('../pages/project/detail.vue') },
|
||||
{path:'task/list',name:'admin-task-list',component:()=> import('../pages/task/list.vue')}
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in New Issue