vue&element项目实战 之element使用&用户&字典模块实现
6.用户模块
用户模块api
import request from '@/utils/request'
export function login(data) {
return request({
url: '/sys-user/login',
method: 'post',
data
})
}export function getInfo(token) {
return request({
url: '/sys-user/queryUserInfo',
method: 'get',
params: { token }
})
}
// 退出登录
export const logout = () => request({ url: '/sys-user/logout', method: 'post' })// 获取用户列表
export const queryList = (param) => request({ url: '/sys-user/queryList', params: param, method: 'post' })// 修改或更新用户
export const updateOrSave = (param) => request({ url: '/sys-user/updateOrSave', params: param, method: 'post' })// 修改或更新用户
export const deleteUser = (id) => request({ url: `/sys-user/delete?id=${id}`, method: 'post' })
用户模块代码
<template> <div> <span> 更新时间: <el-date-picker v-model="time" type="daterange" range-separator="至" start-placeholder="开始" end-placeholder="结束" size="default" /> </span> <span v-for="(item, index) in infoArray" :key="index"> {{ item.label }}: <el-select v-model="queryParam[item.value]" class="m-2" placeholder="请选择"> <el-option v-for="item in infolist[item.value]" :key="item.value" :label="item.text" :value="item.value" /> </el-select> </span> <el-button type="primary" @click="queryList()">查询</el-button> <el-button type="primary" @click="showDialog()">新增</el-button> <el-table :data="tableData" border style="width: 100%"> <template v-for="(item, index) in columnList"> <el-table-column :key="index" :prop="item.field" :label="item.title" :width="item.width"> <template slot-scope="scope"> <span> {{ scope.row[item.field] | qxSelffilter(item.value) }}</span> </template> </el-table-column> </template> <el-table-column label="操作"> <template slot-scope="{row,$index}"> <el-button type="primary" @click="updateShowDialog(row)"> 修改 </el-button> <el-button type="danger" @click="deleteUser(row)"> 删除 </el-button> </template> </el-table-column> </el-table> <el-pagination style="margin-top: 20px; text-align: center" :current-page="queryParam.currentPage" :page-size="queryParam.pageSize" :page-sizes="[3, 5, 10, 20]" :total="total" :pager-count="5" layout=" prev, pager, next , total,sizes" @size-change="handleSizeChange" @current-change="goPage" /> <!-- 弹框 :visible.sync:控制对话框显示与隐藏用的 Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可 --> <el-dialog :visible.sync="dialogFormVisible" :title="dialogName"> <el-form ref="ruleForm" :model="form" :rules="rules"> <el-form-item label="账号" prop="userName"> <el-input v-model="form.userName" autocomplete="off" /> </el-form-item> <el-form-item label="密码" prop="password"> <el-input v-model="form.password" autocomplete="off" /> </el-form-item> <!-- 下拉选项 item: { label: "用户状态", value: "status", enumType: "status" }, obj: {"enumType":"status","value":"0","text":"启用"} --> <span v-for="(item, index) in infoArray" :key="index"> <el-form-item :label="item.label" :prop="item.value"> <el-select v-model="form[item.value]" class="m-2" placeholder="请选择"> <el-option v-for="obj in infolist[item.value]" :key="obj.value" :label="obj.text" :value="item.String ? obj.value : Number(obj.value)" /> </el-select> </el-form-item> </span> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogFormVisible = false">取消</el-button> <el-button type="primary" @click="submitForm"> 确定 </el-button> </span> </template> </el-dialog> </div> </template> <script> import { EnumUtility } from '@/utils/EnumUtility' import * as DateUtil from '@/utils/DateUtil' export default { name: 'UserInfo', data() { const _startTime = DateUtil.ToString( DateUtil.AddDays(new Date(), -7), 'yyyy-MM-dd' ) const _endTime = DateUtil.ToString(new Date(), 'yyyy-MM-dd') // 自定义校验规则 var validateUserName = (rule, value, callback) => { // 自定义校验规则 if (value.length < 6 || value.length > 10) { callback(new Error('登录账号6-10位')) } else { callback() } } return { // 时间选择器 time: [_startTime, _endTime], // 下拉选择属性 infoArray: [ /* * label:下拉选项的标题,如:用户状态 * value: 选择值列表 与 传到 服务端的字段: 如:status=30 * enumType:从字典=>枚举 中的下拉选项映射值 , 枚举值赋值是在创建vue对象后,即方法中实现的 */ { label: '用户状态', value: 'status', enumType: 'status' }, { label: '用户类型', value: 'type', enumType: 'user_type' } ], // 下拉选项值 /* 枚举中完成赋值的status,type*/ infolist: {}, // 列表查询参数 queryParam: { currentPage: 1, pageSize: 10, startTime: _startTime, endTime: DateUtil.ToString( DateUtil.AddDays(_endTime, +1), 'yyyy-MM-dd' ) }, // 列表数据 tableData: [], total: 0, // 列字段 columnList: [ { title: '编号', field: 'id' }, { title: '账号', field: 'userName' }, { title: '类型', field: 'type', value: { enum: 'user_type' }}, { title: '状态', field: 'status', value: { enum: 'status' }}, { title: '备注', field: 'remark' }, { title: '更新时间', field: 'updateTime', value: { date: 'MM-dd hh:mm:ss' } }, { title: '创建时间', field: 'createTime', value: { date: 'MM-dd hh:mm:ss' } } ], dialogFormVisible: false, // 是否显示弹框 dialogName: '', // 弹框标题 如:新增用户 或 修改 用户 form: { // 新增 或 修改表单数据 }, rules: { // 品牌名称的验证规则 // require:必须要校验字段(前面五角星有关系) message 提示信息 trigger:用户行为设置(事件的设置:blur、change) // tmName 对应表单上的prop的名称必须一致 <el-form-item label="品牌名称" :label-width="formLabelWidth" prop="tmName"> userName: [ { required: true, message: '必须输入登录账号', trigger: 'blur' }, // { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }, // 自定义校验规则 { validator: validateUserName, trigger: 'change' } ], password: [{ required: true, message: '请输入密码' }], status: [{ required: true, message: '请选择状态' }], type: [{ required: true, message: '请选择类型' }] } } }, watch: { time(val) { if (!val) { // 参数为空时清空数据 this.queryParam.startTime = '' this.queryParam.endTime = '' } if (val && val.length > 0) { this.queryParam.startTime = DateUtil.ToString(val[0], 'yyyy-MM-dd') this.queryParam.endTime = DateUtil.ToString( DateUtil.AddDays(val[1], +1), 'yyyy-MM-dd' ) } } }, mounted() { // this.queryList() }, created() { // 给枚举赋值 const enumUtility = new EnumUtility() this.infoArray.forEach((element) => { if (element.enumType) { // 枚举数据结构 [{"enumType":"status","value":"0","text":"启用"},{"enumType":"status","value":"1","text":"禁用"}] console.log('element.enumType=', element.enumType) console.log('enumUtility.Get(element.enumType)', enumUtility.Get(element.enumType)) this.infolist[element.value] = enumUtility.Get(element.enumType) } }) }, methods: { async queryList() { const result = await this.$api.user.queryList(this.queryParam) if (result.code == '100') { this.tableData = result.data.list this.total = result.data.total } }, goPage(currentPage) { this.queryParam.currentPage = currentPage this.queryList() }, handleSizeChange(pageSize) { this.queryParam.pageSize = pageSize this.queryParam.currentPage = 1 this.queryList() }, showDialog() { // console.log('显示弹框') this.dialogName = '添加用户' this.form = {} this.dialogFormVisible = true }, updateShowDialog(row) { this.dialogName = '修改用户' this.form = { ...row } // 显示对话框 this.dialogFormVisible = true }, submitForm() { // 当全部验证字段通过,再去书写业务逻辑 this.$refs.ruleForm.validate(async(success) => { if (success) { const result = await this.$api.user.updateOrSave(this.form) if (result.code == '100') { // 关闭窗口 this.dialogFormVisible = false // 查询数据 this.queryList() } } else { console.log('检查提交参数') return false } }) }, deleteUser(row) { // 弹框 this.$confirm(`你确定删除:${row.userName}?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) .then(async() => { // 当用户点击确定按钮的时候会出发 // 向服务器发请求 const result = await this.$api.user.deleteUser(row.id) // 如果删除成功 if (result.code == '100') { this.$message({ type: 'success', message: '删除成功!' }) // 再次获取品牌列表数据 this.queryList() } }) .catch(() => { // 当用户点击取消按钮的时候会触发 this.$message({ type: 'info', message: '已取消删除' }) }) } } } </script> <style lang="scss"></style>
管道过滤器配置
// 全局过滤器要放在Vue实例化代码前面,不然会报错
// eslint-disable-next-line no-unused-vars
import qxfilter from '@/utils/filter/filter'
引入时间格式依赖
"moment": "^2.29.1"
页面显示
7.字典模块
编辑弹框
<template> <el-dialog :title="ruleForm.dialogName" :visible.sync="showEdit" :close-on-click-modal="false" width="550px" center @close="close" > <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="100px" class="flex flex_center" > <el-form-item v-for="item in ruleList" :key="item.title" :label="item.title" :prop="item.field" > <el-input v-if="!item.option" v-model="ruleForm[item.field]" :type="item.type" clearable :disabled="item.field == 'enumType' && ruleForm.id" placeholder="请输入" /> <el-select v-else v-model="ruleForm[item.field]" filterable placeholder="请选择" > <el-option v-for="(it, Index) in infolist[item.option]" :key="Index" :label="it.text" :value="Number(it.value)" /> </el-select> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button> <el-button type="danger" @click="close()">取消</el-button> </span> </el-dialog> </template> <script> export default { props: { showEdit: Boolean, infolist: Object, ruleForm: Object }, data() { return { ruleList: [ { title: '字典类型', field: 'enumType' }, { title: '字典值', field: 'value' }, { title: '显示名称', field: 'text' }, { title: '排序编号', field: 'shortNo', type: 'number' }, { title: '状态', field: 'status', option: 'status' } ], rules: {} } }, computed: {}, watch: { ruleForm(val) { // 监听变化的值,及时校验输入看数据 if (!this.ruleForm.id && this.$refs['ruleForm']) { this.resetForm('ruleForm') } } }, created() { this.ruleList.forEach((element) => { this.rules[element.field] = [ { required: true, message: `${element.title}不能为空` } ] }) }, mounted() {}, methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { // valid 表示输入框的校验结果,校验通过返回true if (valid) { this.saveOrUpdateDic() } else { return false } }) }, async saveOrUpdateDic() { const result = await this.$api.dic.saveOrUpdateDic(this.ruleForm) if (result.code === '100') { // 成功消息提示 this.$message.success('添加成功') // 关闭窗口 this.close('insert') } else { if (result.message) this.$message.error(result.message) } }, resetForm(formName) { this.$refs[formName].resetFields() }, // 关闭弹框 close(val) { const data = { name: 'showEdit', isRefresh: val } // 子组件向父组件通信 this.$emit('close', data) this.resetForm('ruleForm') } } } </script> <style scoped> </style>
列表页面
<template> <div> <span v-for="(item, index) in infoArray" :key="index"> {{ item.label }}: <el-select v-model="queryParam[item.value]" class="m-2" placeholder="请选择" > <el-option v-for="item in infolist[item.value]" :key="item.value" :label="item.text" :value="item.value" /> </el-select> </span> <span v-for="item in infoInput" :key="item.value" class="info"> <el-input v-model="queryParam[item.value]" :placeholder="item.placeholder" > <i slot="prefix" class="el-input__icon el-icon-search" /> </el-input> </span> <el-button type="primary" @click="queryList()">查询</el-button> <el-button type="primary" @click="showDialog()">新增</el-button> <el-table :data="tableData" border style="width: 100%"> <template v-for="(item, index) in columnList"> <el-table-column :key="index" :prop="item.field" :label="item.title" :width="item.width" > <template slot-scope="scope"> <span> {{ scope.row[item.field] | qxSelffilter(item.value) }}</span> </template> </el-table-column> </template> <el-table-column label="操作"> <template slot-scope="{ row, $index }"> <el-button type="primary" @click="updateShowDialog(row)"> 修改 </el-button> <el-button type="danger" @click="deleteUser(row)"> 删除 </el-button> </template> </el-table-column> </el-table> <edit-model :show-edit="dialogFormVisible" :infolist="infolist" :rule-form="itemEdit" @close="CloseShow" /> </div> </template> <script> import EditModel from './model/EditModel.vue' export default { name: 'DicInfo', components: { EditModel }, data() { return { // 下拉选择属性 infoArray: [ /* * label:下拉选项的标题,如:用户状态 * value: 选择值列表 与 传到 服务端的字段: 如:status=30 * enumType:从字典=>枚举 中的下拉选项映射值 , 枚举值赋值是在创建vue对象后,即方法中实现的 */ { label: '字典状态', value: 'status', enumType: 'status' } ], infoInput: [ /* infoInput:输入框数据 */ { placeholder: '输入:字典类型', value: 'enumType' }, { placeholder: '输入:显示名称', value: 'text' } ], // 下拉选项值 /* 枚举中完成赋值的status,type*/ infolist: { status: [ { enumType: 'status', value: '0', text: '启用' }, { enumType: 'status', value: '1', text: '禁用' } ] }, // 列表查询参数 queryParam: {}, // 列表数据 tableData: [], // 列字段 columnList: [ { title: '编号', field: 'id' }, { title: '字典类型', field: 'enumType' }, { title: '字典值', field: 'value' }, { title: '显示名称', field: 'text' }, { title: '排序编号', field: 'shortNo' }, { title: '状态', field: 'status', value: { enum: 'status' }}, { title: '更新时间', field: 'updateTime', value: { date: 'MM-dd hh:mm:ss' } }, { title: '创建时间', field: 'createTime', value: { date: 'MM-dd hh:mm:ss' } } ], dialogFormVisible: false, // 是否显示弹框 itemEdit: { dialogName: '修改字典' // 弹框标题 如:新增用户 或 修改 用户 }, // 编辑或修改的字段,如name, idd等 rules: { // 品牌名称的验证规则 // require:必须要校验字段(前面五角星有关系) message 提示信息 trigger:用户行为设置(事件的设置:blur、change) // tmName 对应表单上的prop的名称必须一致 <el-form-item label="品牌名称" :label-width="formLabelWidth" prop="tmName"> userName: [ { required: true, message: '必须输入登录账号', trigger: 'blur' } ], password: [{ required: true, message: '请输入密码' }], status: [{ required: true, message: '请选择状态' }], type: [{ required: true, message: '请选择类型' }] } } }, watch: {}, mounted() { // this.queryList() }, created() { // 给枚举赋值 { label: "字典状态", value: "status", enumType: "status" }, // let enumUtility = new EnumUtility(); // this.infoArray.forEach((element) => { // if (element.enumType) { // 枚举数据结构 [{"enumType":"status","value":"0","text":"启用"},{"enumType":"status","value":"1","text":"禁用"}] // this.infolist[element.value] = enumUtility.Get(element.enumType); // } // }); }, methods: { async queryList() { const result = await this.$api.dic.getDicList(this.queryParam) if (result.code == '100') { this.tableData = result.data } }, goPage() { this.queryList() }, showDialog() { // console.log('显示弹框') this.dialogFormVisible = true this.itemEdit = { enumType: '', value: '', text: '', status: '', shortNo: '', dialogName: '添加字典' } }, updateShowDialog(row) { this.itemEdit = { ...row } this.itemEdit['dialogName'] = '修改字典' // 显示对话框 this.dialogFormVisible = true }, submitForm() { // 当全部验证字段通过,再去书写业务逻辑 this.$refs.ruleForm.validate(async(success) => { if (success) { const result = await this.$api.user.updateOrSave(this.form) // eslint-disable-next-line eqeqeq if (result.code == '100') { // 关闭窗口 this.dialogFormVisible = false // 查询数据 this.queryList() } } else { console.log('检查提交参数') return false } }) }, deleteUser(row) { // 弹框 this.$confirm(`你确定删除字典:${row.enumType}?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) .then(async() => { // 当用户点击确定按钮的时候会出发 // 向服务器发请求 const result = await this.$api.dic.deleteDic(row.id) // 如果删除成功 if (result.code == '100') { this.$message({ type: 'success', message: '删除成功!' }) // 再次获取品牌列表数据 this.queryList() } }) .catch(() => { // 当用户点击取消按钮的时候会触发 this.$message({ type: 'info', message: '已取消删除' }) }) }, CloseShow(data) { // console.log(data); // 关闭对话 this.dialogFormVisible = false if (data.isRefresh == 'update') { this.queryList() // 更新的情况 } if (data.isRefresh == 'insert') { this.queryList() // 新增的情况 } } } } </script> <style lang="scss"> </style>
页面显示
8.打包部署
打包:

将dist文件压缩上传到nginx配置的路径下
如果,nginx不熟悉,可以学习我们之前专门讲解的nginx课程
这里给出nginx在Windows下的常用命令,实际开发中nginx都是部署在linux上的,但是我们自己学习一般是在windows上操作,本质上是一样的
1.启动
start nginx
2.停止
taskkill /f /t /im nginx.exe
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 卡券后台管理系统 upstream couponAdminApi{ server 127.0.0.1:6001; #server 127.1.2.51:6001; # 负载均衡配置 } server { listen 6002; server_name localhost; location / { root F:\vue\kecheng\webhome\quanyi; #vue打包后的项目地址 index index.html index.htm; } location /prod-api/ { # return 500; proxy_set_header Host pro.ldp.com; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real_IP $remote_addr; proxy_pass http: //couponAdminApi/; } } |
部署好后,重启nginx,访问
http://localhost:6002/
完美!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人