zhangjf 4b4fcf2ead feat: 完成阶段四前端开发和阶段五部署准备
阶段四:前端开发
- 管理后台 (worklog-web): Vue 3 + Element Plus
  - 登录页面、主布局、人员管理、模板管理、工作日志
  - baseURL: /wladmin/api/v1

- 移动端 H5 (worklog-mobile): Vue 3 + Vant 4
  - 登录、首页、日志列表、新建/编辑/详情页
  - baseURL: /wlmobile/api/v1

阶段五:部署准备
- 后端打包: worklog-api-1.0.0.jar (48MB)
- 前端打包: worklog-web (1.6MB), worklog-mobile (632KB)
- 单元测试: 29个测试全部通过
- API端口调整为 8200
- Nginx配置更新

配置变更
- 后端端口: 8080 → 8200
- 前端 baseURL: /wlog → /wladmin, /wlmobile
- Nginx 代理路径更新
2026-02-24 17:33:16 +08:00

299 lines
8.6 KiB
Vue

<template>
<div class="user-page">
<el-card>
<!-- 搜索栏 -->
<el-form :inline="true" :model="searchForm" class="search-form">
<el-form-item label="姓名">
<el-input v-model="searchForm.name" placeholder="请输入姓名" clearable />
</el-form-item>
<el-form-item label="账号">
<el-input v-model="searchForm.username" placeholder="请输入账号" clearable />
</el-form-item>
<el-form-item label="状态">
<el-select v-model="searchForm.status" placeholder="请选择" clearable>
<el-option label="启用" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<!-- 工具栏 -->
<el-row class="toolbar" justify="space-between">
<el-col :span="12">
<el-button type="primary" @click="handleAdd">新增用户</el-button>
</el-col>
</el-row>
<!-- 表格 -->
<el-table :data="tableData" v-loading="loading" stripe>
<el-table-column prop="username" label="账号" width="120" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="phone" label="联系方式" width="130" />
<el-table-column prop="email" label="邮箱" width="180" />
<el-table-column prop="position" label="职位" width="120" />
<el-table-column prop="role" label="角色" width="100">
<template #default="{ row }">
<el-tag :type="row.role === 'ADMIN' ? 'danger' : 'info'">
{{ row.role === 'ADMIN' ? '管理员' : '普通用户' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createdTime" label="创建时间" width="180" />
<el-table-column label="操作" fixed="right" width="200">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
<el-button
type="primary"
link
@click="handleStatus(row)"
v-if="row.role !== 'ADMIN'"
>
{{ row.status === 1 ? '禁用' : '启用' }}
</el-button>
<el-button
type="danger"
link
@click="handleDelete(row)"
v-if="row.role !== 'ADMIN'"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="pageNum"
v-model:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
@size-change="handleSearch"
@current-change="handleSearch"
class="pagination"
/>
</el-card>
<!-- 新增/编辑对话框 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px">
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="账号" prop="username" v-if="!form.id">
<el-input v-model="form.username" placeholder="请输入账号" />
</el-form-item>
<el-form-item label="密码" prop="password" v-if="!form.id">
<el-input v-model="form.password" type="password" placeholder="请输入密码" show-password />
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="联系方式">
<el-input v-model="form.phone" placeholder="请输入联系方式" />
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="职位">
<el-input v-model="form.position" placeholder="请输入职位" />
</el-form-item>
<el-form-item label="角色" v-if="!form.id">
<el-select v-model="form.role" placeholder="请选择角色">
<el-option label="普通用户" value="USER" />
<el-option label="管理员" value="ADMIN" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { pageUsers, createUser, updateUser, updateUserStatus, deleteUser } from '@/api/user'
import type { User } from '@/api/user'
import type { FormInstance, FormRules } from 'element-plus'
const loading = ref(false)
const submitLoading = ref(false)
const tableData = ref<User[]>([])
const total = ref(0)
const pageNum = ref(1)
const pageSize = ref(10)
const searchForm = reactive({
name: '',
username: '',
status: undefined as number | undefined
})
const dialogVisible = ref(false)
const formRef = ref<FormInstance>()
const form = reactive({
id: '',
username: '',
password: '',
name: '',
phone: '',
email: '',
position: '',
role: 'USER'
})
const dialogTitle = computed(() => form.id ? '编辑用户' : '新增用户')
const rules: FormRules = {
username: [{ required: true, message: '请输入账号', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }]
}
// 加载数据
async function loadData() {
loading.value = true
try {
const result = await pageUsers({
pageNum: pageNum.value,
pageSize: pageSize.value,
...searchForm
})
tableData.value = result.list
total.value = result.total
} finally {
loading.value = false
}
}
// 搜索
function handleSearch() {
pageNum.value = 1
loadData()
}
// 重置
function handleReset() {
searchForm.name = ''
searchForm.username = ''
searchForm.status = undefined
handleSearch()
}
// 新增
function handleAdd() {
form.id = ''
form.username = ''
form.password = ''
form.name = ''
form.phone = ''
form.email = ''
form.position = ''
form.role = 'USER'
dialogVisible.value = true
}
// 编辑
function handleEdit(row: User) {
form.id = row.id
form.username = row.username
form.password = ''
form.name = row.name
form.phone = row.phone || ''
form.email = row.email || ''
form.position = row.position || ''
form.role = row.role
dialogVisible.value = true
}
// 提交
async function handleSubmit() {
const valid = await formRef.value?.validate()
if (!valid) return
submitLoading.value = true
try {
if (form.id) {
await updateUser(form.id, {
name: form.name,
phone: form.phone,
email: form.email,
position: form.position
})
ElMessage.success('更新成功')
} else {
await createUser({
username: form.username,
password: form.password,
name: form.name,
phone: form.phone,
email: form.email,
position: form.position,
role: form.role
})
ElMessage.success('创建成功')
}
dialogVisible.value = false
loadData()
} finally {
submitLoading.value = false
}
}
// 更新状态
async function handleStatus(row: User) {
const newStatus = row.status === 1 ? 0 : 1
await ElMessageBox.confirm(
`确定要${newStatus === 1 ? '启用' : '禁用'}该用户吗?`,
'提示',
{ type: 'warning' }
)
await updateUserStatus(row.id, newStatus)
ElMessage.success('操作成功')
loadData()
}
// 删除
async function handleDelete(row: User) {
await ElMessageBox.confirm('确定要删除该用户吗?', '提示', { type: 'warning' })
await deleteUser(row.id)
ElMessage.success('删除成功')
loadData()
}
// 初始化
loadData()
</script>
<style scoped>
.user-page {
height: 100%;
}
.search-form {
margin-bottom: 16px;
}
.toolbar {
margin-bottom: 16px;
}
.pagination {
margin-top: 16px;
justify-content: flex-end;
}
</style>