完成新增用户接口的对接,完善新增用户业务逻辑 #28

Merged
ppnwsfegt merged 3 commits from Brunch_LPQ into main 2 months ago

@ -23,6 +23,13 @@ public class SysUserController {
// 新增用户 // 新增用户
@PostMapping//使用post请求 @PostMapping//使用post请求
public ResultVo addUser(@RequestBody SysUser sysUser){ public ResultVo addUser(@RequestBody SysUser sysUser){
// 判断用户是否重复
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(SysUser::getUsername,sysUser.getUsername()).eq(SysUser::getPhone,sysUser.getPhone());
SysUser user = sysUserService.getOne(queryWrapper);
if(user != null){
return ResultUtils.error("用户已存在!或该手机号已被使用!");
}
if(sysUserService.save(sysUser)){ if(sysUserService.save(sysUser)){
return ResultUtils.success("新增用户成功!"); return ResultUtils.success("新增用户成功!");
} }

@ -1,7 +1,6 @@
<!-- 作为应用程序的根组件并提供路由视图的容器 --> <!-- 作为应用程序的根组件并提供路由视图的容器 -->
<template> <template>
<router-view/> <router-view />
</template> </template>
<style lang="scss"> <style lang="scss"></style>
</style>

@ -0,0 +1,7 @@
import http from "../../http";
import type { UserModel } from "./userModel";
// 新增接口
export const addUserApi = (parm:UserModel)=>{
return http.post("/api/user", parm)
}

@ -0,0 +1,18 @@
// 定义列表查询的数据类型
export type ListUserParm = {
currentPage: number;
pageSize: number;
name: string;
phone: string;
}
// 定义表单数据类型
export type UserModel = {
userId: string;
username: string;
password: string;
phone: string;
email: string;
sex: string;
name: string;
}

@ -25,15 +25,14 @@
<script setup lang="ts"> <script setup lang="ts">
// //
//
interface DialogProps{ interface DialogProps{
// //
title?: string; title: string;
// & // &
visible: boolean; visible: boolean;
// //
width?: number; width: number;
height?: number; height: number;
} }
// //
@ -60,7 +59,7 @@ const onConfirm = ()=>{
<style lang="scss"> <style lang="scss">
.container{ .container{
overflow-x: initial; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
} }

@ -0,0 +1,28 @@
import { ref } from "vue"
// 抽取增删改的业务操作
export default function useUser() {
// 获取AddUser里面的show方法
const showBtn = ref<{ show: (title: string, width: number, height: number) => {} }>();
// 增
const addBtn = () => {
showBtn.value?.show("新增", 630, 180)
}
// 删
const deleteBtn = () => {
}
// 改
const editBtn = () => {
}
return {
showBtn,
addBtn,
deleteBtn,
editBtn
}
}

@ -0,0 +1,41 @@
// 抽离表格相关业务
import type { ListUserParm } from "@/api/user/userModel";
import { ref, reactive } from "vue";
export default function useUserTable() {
// 列表查询的参数
const listParm = reactive<ListUserParm>({
currentPage: 1,
pageSize: 10,
name: '',
phone: ''
})
// 列表
const getList = () => {
}
// 获取show方法
const tableShowBtn = ref<{show:(title: string)=>void}>()
// 搜索按钮
const searchBtn = () => {
}
// 重置按钮
const resetBtn = () => {
tableShowBtn.value?.show("重置")
}
// 将表格查询的方法返回出去
return {
tableShowBtn,
listParm,
getList,
searchBtn,
resetBtn
}
}

@ -6,10 +6,10 @@ export default function useDialog(){
// reactive 定义复杂数据类型的响应式数据 // reactive 定义复杂数据类型的响应式数据
const dialog = reactive({ const dialog = reactive({
// title: '新增', title: '新增',
visible: false, visible: false,
// width: 600, width: 630,
// height: 100 height: 280
}) })
// 弹框关闭 // 弹框关闭
@ -23,7 +23,12 @@ export default function useDialog(){
} }
// 显示弹框 // 显示弹框
const onShow = ()=>{ const onShow = (title: string, width: number, height: number)=>{
// 设置一个string参数当不同按钮调用时可以直接传参改弹框标题
dialog.title = title
// 宽高参数
dialog.width = width
dialog.height = height
dialog.visible = true dialog.visible = true
} }

@ -1,9 +1,12 @@
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosRequestHeaders, InternalAxiosRequestConfig } from "axios" import axios from "axios"
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosRequestHeaders, InternalAxiosRequestConfig } from "axios"
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
// axios请求配置 // axios请求配置
const config = { const config = {
baseURL:'http://localhost:8089', // baseURL:'http://localhost:8089',
baseURL:'/api',
timeout:10000, timeout:10000,
} }

@ -48,7 +48,7 @@
justify-content: space-between; justify-content: space-between;
} }
.main { // .main {
background-color: darkcyan; // background-color: darkcyan;
} // }
</style> </style>

@ -107,7 +107,7 @@
// //
const collapse = computed(()=>{ const collapse = computed(()=>{
return store.getCollapse return store.collapse
}) })
</script> </script>

@ -25,7 +25,7 @@
// watch // watch
watch( watch(
()=> store.getCollapse, ()=> store.collapse,
(collapsed: boolean) => { (collapsed: boolean) => {
if (!collapsed){ if (!collapsed){
setTimeout(() =>{ setTimeout(() =>{

@ -16,10 +16,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, Ref, watch } from 'vue'; import { onMounted, ref, watch } from 'vue';
import type { Ref } from 'vue';
// //
import { useRoute, RouteLocationMatched } from 'vue-router' import { useRoute } from 'vue-router'
import type { RouteLocationMatched } from 'vue-router'
// //
const route = useRoute() const route = useRoute()

@ -27,7 +27,7 @@
// //
const status = computed(()=>{ const status = computed(()=>{
return store.getCollapse return store.collapse
}) })
// //

@ -1,25 +1,18 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useCollapseStore = defineStore('collapseStore', { export const useCollapseStore = defineStore('collapseStore', () => {
state: () => { const collapse = ref(false)
return {
collapse: false const getCollapse = () => collapse.value
}
}, const setCollapse = (value: boolean) => {
collapse.value = value
// getter }
getters:{
// 数据放在state里面需要传递state return {
getCollapse(state){ collapse,
return state.collapse getCollapse,
} setCollapse
},
// action
actions:{
// 设置state里面的数据
setCollapse(collapse:boolean){
this.collapse = collapse
}
} }
}) })

@ -1,31 +1,21 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
// `defineStore()` 的返回值的命名是自由的 export const useTestStore = defineStore('testStore', () => {
// 但最好含有 store 的名字,且以 `use` 开头,以 `Store` 结尾。 // State
// (比如 `useUserStore``useCartStore``useProductStore`) const count = ref(0)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useTestStore = defineStore('testStore', {
// state可以理解为一个共享的内存
state: () => {
return {
count: 0
}
},
// getter // Getter
getters:{ const doubleCount = computed(() => count.value * 2)
// 数据放在state里面需要传递state
doubleCount(state){
return state.count
}
},
// action // Action
actions:{ function setCount(value: number) {
// 设置state里面的数据 count.value = value
// count:number表示传递进去的count应该是一个number类型 }
setCount(count:number){
this.count = count return {
} count,
doubleCount,
setCount
} }
}) })

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
首页面 首页面
<el-button type="primary" size="default" @click="onShow"></el-button> <!-- <el-button type="primary" size="default" @click="onShow('测试')"></el-button> -->
</div> </div>
<SysDialog <SysDialog

@ -0,0 +1,157 @@
<template>
<SysDialog :title="dialog.title" :visible="dialog.visible" :width="dialog.width" :height="dialog.height"
@onClose="onClose" @onConfirm="commit">
<!-- 通过插槽名称输入内容 -->
<template #content>
<el-form :model="addModel" ref="addFormRef" :rules="rules" label-width="80px" :inline="false" size="default">
<!-- 创建el-row容器将姓名性别放入一行美化页面 -->
<el-row :gutter="20">
<el-col :span="12" :offset="0">
<el-form-item prop="name" label="姓名">
<el-input v-model="addModel.name"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<!-- 通过单选框实现性别选择 -->
<el-form-item prop="sex" label="性别">
<el-radio-group v-model="addModel.sex">
<el-radio :value="'0'"></el-radio>
<el-radio :value="'1'"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12" :offset="0">
<el-form-item prop="phone" label="电话">
<el-input v-model="addModel.phone"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="email" label="邮箱">
<el-input v-model="addModel.email"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12" :offset="0">
<el-form-item prop="username" label="账户">
<el-input v-model="addModel.username"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="password" label="密码">
<el-input type="password" v-model="addModel.password"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
</SysDialog>
</template>
<script setup lang="ts">
//
import SysDialog from '@/components/SysDialog.vue';
//
import useDialog from '@/hooks/useDialog';
import { ref, reactive } from 'vue';
// UserModel
import type { UserModel } from '@/api/user/userModel';
import type { FormInstance } from 'element-plus';
// post
import { addUserApi } from '../../api/user/index';
//
const { dialog, onClose, onConfirm, onShow } = useDialog()
//
const show = (title: string, width: number, height: number) => {
// dialog.title:
onShow(title, width, height)
// dialog.visible = true;
//
addFormRef.value?.resetFields()
}
//
defineExpose({
show
})
//
const addModel = reactive<UserModel>({
userId: "",
username: "",
password: "",
phone: "",
email: "",
sex: "",
name: "",
})
// ref
const addFormRef = ref<FormInstance>()
//
const rules = reactive({
name: [{
required: true,
message: '请输入姓名',
trigger: 'blur'
}],
sex: [{
required: true,
message: '请选择性别',
trigger: 'blur'
}],
phone: [{
required: true,
message: '请输入电话',
trigger: 'blur'
}],
username: [{
required: true,
message: '请输入用户名',
trigger: 'blur'
}],
password: [{
required: true,
message: '请输入密码',
trigger: 'blur'
}]
})
//
const commit = () => {
addFormRef.value?.validate(async(valid) => {
if(valid){
// addUserApi
let res = await addUserApi(addModel)
if(res && res.code == 200){
onConfirm()
}
}
})
}
</script>
<style></style>

@ -1,13 +1,45 @@
<template> <template>
<div> <el-main>
用户管理 <!-- 搜索栏 -->
</div> <el-form :model="listParm" label-width="80px" :inline="true" size="default">
<el-form-item>
<el-input v-model="listParm.name" placeholder="请输入姓名:"></el-input>
</el-form-item>
<el-form-item>
<el-input v-model="listParm.phone" placeholder="请输入电话:"></el-input>
</el-form-item>
<el-form-item>
<el-button :icon="Search" @click="searchBtn"></el-button>
<el-button plain :icon="Close" type="danger" @click="resetBtn"></el-button>
<el-button plain type="primary" :icon="Plus" @click="addBtn"></el-button>
</el-form-item>
</el-form>
</el-main>
<!-- 新增编辑按钮弹框 -->
<AddUser ref="showBtn"></AddUser>
<AddUser ref="tableShowBtn"></AddUser>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
</script> import { Search, Close, Plus } from '@element-plus/icons-vue'
// useUserTable,
// vite-env.d.ts
import useUserTable from '@/compositions/user/useUserTable';
<style scoped> //
const { tableShowBtn, listParm, getList, searchBtn, resetBtn } = useUserTable()
// useUser,
import useUser from '@/compositions/user/useUser';
const { showBtn, addBtn, deleteBtn, editBtn } = useUser()
// AddUser,
import AddUser from './AddUser.vue';
</script>
</style> <style scoped></style>

@ -39,9 +39,7 @@ declare module '@/components/*' {
declare module 'pinia'; declare module 'pinia';
declare module '@/store/*' { declare module '@/store/*' {
import { StoreDefinition } from 'pinia'; import { StoreDefinition } from 'pinia';
// 允许导出任意具名成员
export const useTestStore: StoreDefinition;
// 或者更通用的声明方式
export function useTestStore(): any; export function useTestStore(): any;
// useCollapseStore导出 // useCollapseStore导出
@ -49,8 +47,33 @@ declare module '@/store/*' {
} }
// 添加hooks路径别名支持 // 添加hooks路径别名支持
declare module '@/hooks/useDialog' { declare module '@/hooks/*' {
// 我们可以根据实际情况导出具体的类型如果暂时不想写具体类型可以导出any
const content: any; const content: any;
export default content; export default content;
}
// 添加compositions路径别名支持
declare module '@/compositions/*' {
const compositions: any;
export default compositions;
}
// 添加api路径别名支持
declare module '@/api/user/userModel' {
export type ListUserParm = {
currentPage: number;
pageSize: number;
name: string;
phone: string;
}
export type UserModel = {
userId: string;
username: string;
password: string;
phone: string;
email: string;
sex: string;
name: string;
}
} }

@ -8,7 +8,8 @@
"paths": { "paths": {
"@/*": [ "@/*": [
"src/*" "src/*"
] ],
"@/api/*": ["src/api/*"]
}, },
// //
"lib": ["ES2015", "ES2015.Promise", "DOM", "DOM.Iterable", "ESNext"], "lib": ["ES2015", "ES2015.Promise", "DOM", "DOM.Iterable", "ESNext"],
@ -29,6 +30,7 @@
"src/**/*.ts", "src/**/*.ts",
"src/**/*.tsx", "src/**/*.tsx",
"src/**/*.vue", "src/**/*.vue",
"vite-env.d.ts" // "vite-env.d.ts", //
"src/api/**/*.ts"
] ]
} }

@ -4,11 +4,19 @@ import path from 'path' //导入nodejs核心模块path解构提取resolce方
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [vue()], plugins: [vue()],
server:{ server: {
host: '0.0.0.0',//解决控制台Network:use--host to expose host: '0.0.0.0',//解决控制台Network:use--host to expose
port: 8080,//配置端口号 port: 8080,//配置端口号
hmr:true,//开启热更新 hmr: true,//开启热更新
open:true//启动在浏览器打开 open: true,//启动在浏览器打开
// 跨域配置,所有api的请求都会被转接到后端接口
proxy: {
'/api': { // 这里也匹配 /api 路径
target: 'http://localhost:8089',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}, },
// resolve: { // resolve: {
// //为项目设置别名,简化项目路径 // //为项目设置别名,简化项目路径

Loading…
Cancel
Save