Commit d44aa23a by zhangxingmin

租户管理、项目管理、用户管理

parent 884357e6
......@@ -117,3 +117,24 @@ export function deptTreeSelect(roleId) {
method: 'get'
})
}
//作用域切换搜索
export function searchScopeList(data) {
debugger
return request({
url: '/user/api/sysUser/scope/page',
method: 'post',
data: data
})
}
// 修改项目状态
export function changeProjectStatus(data) {
debugger
return request({
url: '/user/api/sysProject/edit/status',
method: 'patch',
params: data
})
}
import request from '@/utils/request'
// 查询项目用户关系列表
export function listProjectUser(data) {
return request({
url: '/user/api/relProjectUser/page',
method: 'post',
data: data
})
}
// 查询导入用户关系列表
export function listImportProjectUser(data) {
return request({
url: '/user/api/relProjectUser/select/user/page',
method: 'post',
data: data
})
}
// 导入用户列表数据提交
export function addImportProjectUserList(importProjectUserListIds, projectBizId) {
const data = {
userBizIdList: importProjectUserListIds,
projectBizId: projectBizId
}
return request({
url: '/user/api/relProjectUser/add/user/list',
method: 'post',
data: data
})
}
// 删除项目和用户关系
export function delRelProjectUser(id) {
return request({
url: '/user/api/relProjectUser/del?id=' + id,
method: 'delete'
})
}
// 查询项目角色关系列表
export function listProjectRole(data) {
return request({
url: '/user/api/relProjectRole/page',
method: 'post',
data: data
})
}
// 删除项目和角色关系
export function delRelProjectRole(id) {
return request({
url: '/user/api/relProjectRole/del?id=' + id,
method: 'delete'
})
}
// 查询导入角色关系列表
export function listImportProjectRole(data) {
return request({
url: '/user/api/relProjectRole/select/role/page',
method: 'post',
data: data
})
}
// 导入角色列表数据提交
export function addImportProjectRoleList(importProjectRoleListIds, projectBizId) {
const data = {
roleBizIdList: importProjectRoleListIds,
projectBizId: projectBizId
}
return request({
url: '/user/api/relProjectRole/add/role/list',
method: 'post',
data: data
})
}
// 查询项目和菜单关系列表
export function listMenu(data) {
return request({
url: '/user/api/relProjectMenu/page',
method: 'post',
data: data
})
}
// 获取项目菜单导入的菜单树
export function getMenuTree(projectBizId) {
const data = {
projectBizId: projectBizId
}
return request({
url: '/user/api/relProjectMenu/import/query/menu/tree',
method: 'post',
data: data
})
}
// 获取项目菜单导入选中的菜单列表
export function getImportSelectedMenuList(projectBizId) {
return request({
url: '/user/api/relProjectMenu/import/query/selected/menu/list?projectBizId=' + projectBizId,
method: 'get'
})
}
// 导入菜单列表数据提交
export function addImportProjectMenuList(data) {
return request({
url: '/user/api/relProjectMenu/add/menu/list',
method: 'post',
data: data
})
}
//分配角色-左侧待选列表
export function listLeftRole(data) {
debugger
return request({
url: '/user/api/relUserRole/candidate/project/userRolePage',
method: 'post',
data: data
})
}
//分配角色-右侧已选列表
export function listRightRole(data) {
return request({
url: '/user/api/relUserRole/selected/project/userRolePage',
method: 'post',
data: data
})
}
//分配角色-左侧待选列表-添加用户角色列表关系
export function addRightRoleList(data) {
return request({
url: '/user/api/relUserRole/add/project/userRoleList',
method: 'post',
data: data
})
}
//分配角色-右侧已选列表-移除用户角色列表关系
export function delRightRoleList(data) {
return request({
url: '/user/api/relUserRole/del/project/userRoleList',
method: 'post',
data: data
})
}
//项目和菜单关系树形列表查询
export function getFpMenuTree(data) {
return request({
url: '/user/api/relProjectMenu/tree',
method: 'post',
data: data
})
}
//项目和菜单关系树形列表查询
export function getSelectedFpMenuList(data) {
return request({
url: '/user/api/relRoleMenu/selected/project/roleMenuList',
method: 'post',
data: data
})
}
//添加菜单角色列表关系
export function addFpMenuList(data) {
return request({
url: '/user/api/relRoleMenu/add/project/roleMenuList',
method: 'post',
data: data
})
}
......@@ -134,3 +134,12 @@ export function deptTreeSelect() {
method: 'get'
})
}
// 修改租户状态
export function changeTenantStatus(data) {
return request({
url: '/user/api/sysTenant/edit/status',
method: 'patch',
params: data
})
}
......@@ -146,15 +146,65 @@ export function addImportTenantMenuList(data) {
})
}
export function getUserRole(data) {
//分配角色-左侧待选列表
export function listLeftRole(data) {
debugger
return request({
url: '/user/api/relUserRole/candidate/tenant/userRolePage',
method: 'post',
data: data
})
}
export function assignUserRole(data) {
//分配角色-右侧已选列表
export function listRightRole(data) {
return request({
url: '/user/api/relUserRole/selected/tenant/userRolePage',
method: 'post',
data: data
})
}
export function removeUserRoles(data) {
//分配角色-左侧待选列表-添加用户角色列表关系
export function addRightRoleList(data) {
return request({
url: '/user/api/relUserRole/add/tenant/userRoleList',
method: 'post',
data: data
})
}
//分配角色-右侧已选列表-移除用户角色列表关系
export function delRightRoleList(data) {
return request({
url: '/user/api/relUserRole/del/tenant/userRoleList',
method: 'post',
data: data
})
}
export function listRole(data) {
//租户和菜单关系树形列表查询
export function getFpMenuTree(data) {
return request({
url: '/user/api/relTenantMenu/tree',
method: 'post',
data: data
})
}
//租户和菜单关系树形列表查询
export function getSelectedFpMenuList(data) {
return request({
url: '/user/api/relRoleMenu/selected/tenant/roleMenuList',
method: 'post',
data: data
})
}
//添加菜单角色列表关系
export function addFpMenuList(data) {
return request({
url: '/user/api/relRoleMenu/add/tenant/roleMenuList',
method: 'post',
data: data
})
}
......@@ -11,9 +11,9 @@ export function listUser(data) {
}
// 查询用户详细
export function getUser(userId) {
export function getUser(userBizId) {
return request({
url: '/system/user/' + parseStrEmpty(userId),
url: '/user/api/sysUser/detail?userBizId=' + userBizId,
method: 'get'
})
}
......@@ -21,7 +21,7 @@ export function getUser(userId) {
// 新增用户
export function addUser(data) {
return request({
url: '/system/user',
url: '/user/api/sysUser/add',
method: 'post',
data: data
})
......@@ -30,17 +30,19 @@ export function addUser(data) {
// 修改用户
export function updateUser(data) {
return request({
url: '/system/user',
url: '/user/api/sysUser/edit',
method: 'put',
data: data
})
}
// 删除用户
export function delUser(userId) {
// 用户状态修改
export function changeUserStatus(data) {
debugger
return request({
url: '/system/user/' + userId,
method: 'delete'
url: '/user/api/sysUser/edit/status',
method: 'patch',
params: data
})
}
......@@ -57,49 +59,6 @@ export function resetUserPwd(userId, password) {
})
}
// 用户状态修改
export function changeUserStatus(userId, status) {
const data = {
userId,
status
}
return request({
url: '/system/user/changeStatus',
method: 'put',
data: data
})
}
// 查询用户个人信息
export function getUserProfile() {
return request({
url: '/system/user/profile',
method: 'get'
})
}
// 修改用户个人信息
export function updateUserProfile(data) {
return request({
url: '/system/user/profile',
method: 'put',
data: data
})
}
// 用户密码重置
export function updateUserPwd(oldPassword, newPassword) {
const data = {
oldPassword,
newPassword
}
return request({
url: '/system/user/profile/updatePwd',
method: 'put',
data: data
})
}
// 用户头像上传
export function uploadAvatar(data) {
return request({
......@@ -110,27 +69,3 @@ export function uploadAvatar(data) {
})
}
// 查询授权角色
export function getAuthRole(userId) {
return request({
url: '/system/user/authRole/' + userId,
method: 'get'
})
}
// 保存授权角色
export function updateAuthRole(data) {
return request({
url: '/system/user/authRole',
method: 'put',
params: data
})
}
// 查询部门下拉树结构
export function deptTreeSelect() {
return request({
url: '/system/user/deptTree',
method: 'get'
})
}
......@@ -140,18 +140,65 @@
<el-form-item label="项目访问地址" prop="projectUrl">
<el-input v-model="form.projectUrl" placeholder="请输入项目访问地址" />
</el-form-item>
<!-- 作用域选择 -->
<el-form-item label="作用域">
<el-radio-group v-model="form.scope">
<el-radio-group v-model="form.scope" @change="handleScopeChange">
<el-radio
v-for="dict in sys_scope"
v-for="dict in filteredScopeOptions"
:key="Number(dict.value)"
:value="Number(dict.value)">
:value="Number(dict.value)"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="所属租户" prop="tenantBizId">
<el-input v-model="form.tenantBizId" placeholder="请输入所属租户" />
<!-- 所属租户 - 可搜索下拉框 -->
<el-form-item
v-if="[2].includes(form.scope)"
label="所属租户"
prop="tenantBizId"
>
<el-select
v-model="form.tenantBizId"
filterable
remote
reserve-keyword
placeholder="请输入关键词搜索租户"
:remote-method="searchTenants"
:loading="tenantLoading"
>
<el-option
v-for="item in tenantOptions"
:key="item.tenantBizId"
:label="item.tenantName"
:value="item.tenantBizId"
/>
</el-select>
</el-form-item>
<!-- 所属项目 - 可搜索下拉框 -->
<el-form-item
v-if="[3].includes(form.scope)"
label="所属项目"
prop="projectBizId"
>
<el-select
v-model="form.projectBizId"
filterable
remote
reserve-keyword
placeholder="请输入关键词搜索项目"
:remote-method="searchProjects"
:loading="projectLoading"
>
<el-option
v-for="item in projectOptions"
:key="item.projectBizId"
:label="item.projectName"
:value="item.projectBizId"
/>
</el-select>
</el-form-item>
<el-form-item label="项目描述">
<el-input v-model="form.description" type="textarea" placeholder="请输入项目描述"></el-input>
......@@ -225,7 +272,10 @@
</template>
<script setup name="Project">
import { addProject, changeRoleStatus, dataScope, delRole, getProject, listProject, updateProject, deptTreeSelect } from "@/api/system/project"
import { computed } from 'vue'
import { addProject, changeRoleStatus, dataScope, delRole, getProject, listProject, updateProject, deptTreeSelect,searchScopeList,changeProjectStatus } from "@/api/system/project"
import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu"
import useUserStore from '@/store/modules/user'
import {formatIsoToDateTime} from '@/utils/date'
......@@ -265,7 +315,9 @@ const dataScopeOptions = ref([
])
const data = reactive({
form: {},
form: {
scope: 1
},
queryParams: {
pageNum: 1,
pageSize: 10,
......@@ -281,7 +333,17 @@ const data = reactive({
scope: [{ required: true, message: "作用域不能为空", trigger: "blur" }],
logoUrl: [{ required: true, message: "项目图标地址不能为空", trigger: "blur" }],
isIn: [{ required: true, message: "是否内置项目不能为空", trigger: "blur" }],
},
}
})
const filteredScopeOptions = computed(() => {
if (!sys_scope.value || !Array.isArray(sys_scope.value)) return []
return sys_scope.value.filter(option => {
// 添加安全判断
if (!option || typeof option.value === 'undefined') return false
return Number(option.value) !== 3
})
})
const { queryParams, form, rules } = toRefs(data)
......@@ -335,18 +397,14 @@ function handleSelectionChange(selection) {
/** 项目状态修改 */
function handleStatusChange(row, event) {
// 忽略初始化时的自动触发
if (!event || event.type !== 'change') return;
let text = row.status === "0" ? "启用" : "停用"
const projectName = row.projectName || "未命名项目"
let text = row.status === 0 ? "停用" : "启用"
const projectName = row.projectName
proxy.$modal.confirm(`确认要${text}"${projectName}"项目吗?`)
.then(() => changeProjectStatus(row.projectId, row.status))
.then(() => changeProjectStatus({projectBizId: row.projectBizId, status: row.status}))
.then(() => proxy.$modal.msgSuccess(`${text}成功`))
.catch(() => {
// 操作取消时恢复原状态
row.status = row.status === "0" ? "1" : "0"
row.status = row.status === 0 ? 1 : 0
})
}
......@@ -364,9 +422,9 @@ function handleCommand(command, row) {
}
}
/** 分配用户 */
function handleAuthUser(row) {
router.push("/system/role-auth/user/" + row.roleId)
/** 分配权限 */
function handlePermission(row) {
router.push(`/system/project/permission?projectBizId=` + row.projectBizId)
}
/** 所有部门节点数据 */
......@@ -415,6 +473,13 @@ function handleUpdate(row) {
startTime: formatIsoToDateTime(resData.startTime),
endTime: formatIsoToDateTime(resData.endTime)
};
// 根据作用域类型预加载关联数据
if (resData.scope === 2) {
tenantOptions.value.push({
tenantBizId: resData.tenantBizId,
tenantName: resData.tenantName
});
}
open.value = true
})
title.value = "修改项目"
......@@ -483,15 +548,13 @@ function getMenuAllCheckedKeys() {
function submitForm() {
proxy.$refs["projectRef"].validate(valid => {
if (valid) {
if (form.value.projectBizId != undefined) {
debugger
if (form.value.projectBizId) {
updateProject(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
debugger
addProject(form.value).then(response => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
......@@ -553,5 +616,69 @@ function cancelDataScope() {
reset()
}
//========作用域-切换逻辑开始=========
const tenantOptions = ref([])
const tenantLoading = ref(false)
const projectOptions = ref([])
const projectLoading = ref(false)
// 作用域变更处理
function handleScopeChange(val) {
console.log('作用域变更:', val);
// 清空不需要的字段值
if (val === 2) {
form.value.projectBizId = '';
// 自动加载租户列表(可选)
searchTenants('');
} else if (val === 3) {
form.value.tenantBizId = '';
// 自动加载项目列表(可选)
searchProjects('');
} else if (val === 1) {
//系统级
form.value.tenantBizId = '';
form.value.projectBizId = '';
}
}
// 搜索租户方法
function searchTenants(query) {
tenantLoading.value = true;
try {
const params = {
loginTenantBizId: userStore.currentTenant.apiLoginTenantInfoResponse.tenantBizId,
scope: 2,name: query, pageNo:1, pageSize: 10 };
searchScopeList(params).then(response => {
tenantOptions.value = response.data.records
})
} catch (error) {
console.error('租户搜索失败', error);
tenantOptions.value = [];
} finally {
tenantLoading.value = false;
}
}
// 搜索项目方法
function searchProjects(query) {
projectLoading.value = true;
try {
const params = {
loginTenantBizId: userStore.currentTenant.apiLoginTenantInfoResponse.tenantBizId,
scope: 3,name: query, pageNo:1, pageSize: 10 };
searchScopeList(params).then(response => {
projectOptions.value = response.data.records
})
} catch (error) {
console.error('项目搜索失败', error);
projectOptions.value = [];
} finally {
projectLoading.value = false;
}
}
//========作用域-切换逻辑结束=========
getList()
</script>
......@@ -12,8 +12,18 @@
<el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="租户状态" clearable style="width: 240px">
<!-- <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />-->
<el-select
v-model="queryParams.status"
placeholder="租户状态"
clearable
style="width: 240px"
>
<el-option
v-for="dict in sys_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" style="width: 308px">
......@@ -38,12 +48,13 @@
</el-table-column>
<el-table-column label="最大项目数" align="center" prop="maxProject" />
<el-table-column label="最大用户数" align="center" prop="maxUser" />
<el-table-column label="状态" align="center" key="status" >
<el-table-column label="状态" align="center">
<template #default="scope">
<el-switch
v-model="scope.row.status"
active-value="1"
inactive-value="0"
:active-value="1"
:inactive-value="0"
@change="(val) => handleStatusChange(scope.row, $event)"
></el-switch>
</template>
</el-table-column>
......@@ -155,12 +166,12 @@
<script setup name="Tenant">
import { getToken } from "@/utils/auth"
import useAppStore from '@/store/modules/app'
import { changeUserStatus, listTenant, resetUserPwd, delUser, getTenant, updateTenant, addTenant } from "@/api/system/tenant"
import { changeUserStatus, listTenant, resetUserPwd, delUser, getTenant, updateTenant, addTenant,changeTenantStatus } from "@/api/system/tenant"
const router = useRouter()
const appStore = useAppStore()
const { proxy } = getCurrentInstance()
// const { sys_normal_disable, sys_user_sex } = proxy.useDict("sys_normal_disable", "sys_user_sex")
const { sys_status,sys_scope,sys_no_yes } = proxy.useDict("sys_status","sys_scope","sys_no_yes")
const tenantList = ref([])
const open = ref(false)
......@@ -265,15 +276,16 @@ function handleExport() {
},`user_${new Date().getTime()}.xlsx`)
}
/** 用户状态修改 */
function handleStatusChange(row) {
let text = row.status === "1" ? "启用" : "停用"
proxy.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
return changeUserStatus(row.tenantBizId, row.status)
}).then(() => {
proxy.$modal.msgSuccess(text + "成功")
}).catch(function () {
row.status = row.status === "1" ? "0" : "1"
/** 租户状态修改 */
function handleStatusChange(row, event) {
let text = row.status === 0 ? "停用" : "启用"
const tenantName = row.tenantName
proxy.$modal.confirm(`确认要${text}"${tenantName}"租户吗?`)
.then(() => changeTenantStatus({tenantBizId: row.tenantBizId, status: row.status}))
.then(() => proxy.$modal.msgSuccess(`${text}成功`))
.catch(() => {
// 操作取消时恢复原状态
row.status = row.status === 0 ? 1 : 0
})
}
......
<template>
<div class="app-container">
<h4 class="form-header h4">基本信息</h4>
<el-form :model="form" label-width="80px">
<el-row>
<el-col :span="8" :offset="2">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" disabled />
</el-form-item>
</el-col>
<el-col :span="8" :offset="2">
<el-form-item label="登录账号" prop="userName">
<el-input v-model="form.userName" disabled />
</el-form-item>
</el-col>
</el-row>
</el-form>
<h4 class="form-header h4">角色信息</h4>
<el-table v-loading="loading" :row-key="getRowKey" @row-click="clickRow" ref="roleRef" @selection-change="handleSelectionChange" :data="roles.slice((pageNum - 1) * pageSize, pageNum * pageSize)">
<el-table-column label="序号" width="55" type="index" align="center">
<template #default="scope">
<span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55"></el-table-column>
<el-table-column label="角色编号" align="center" prop="roleId" />
<el-table-column label="角色名称" align="center" prop="roleName" />
<el-table-column label="权限字符" align="center" prop="roleKey" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="pageNum" v-model:limit="pageSize" />
<el-form label-width="100px">
<div style="text-align: center;margin-left:-120px;margin-top:30px;">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
</div>
</el-form>
</div>
</template>
<script setup name="AuthRole">
import { getAuthRole, updateAuthRole } from "@/api/system/user"
const route = useRoute()
const { proxy } = getCurrentInstance()
const loading = ref(true)
const total = ref(0)
const pageNum = ref(1)
const pageSize = ref(10)
const roleIds = ref([])
const roles = ref([])
const form = ref({
nickName: undefined,
userName: undefined,
userId: undefined
})
/** 单击选中行数据 */
function clickRow(row) {
if (checkSelectable(row)) {
proxy.$refs["roleRef"].toggleRowSelection(row)
}
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
roleIds.value = selection.map(item => item.roleId)
}
/** 保存选中的数据编号 */
function getRowKey(row) {
return row.roleId
}
// 检查角色状态
function checkSelectable(row) {
return row.status === "0" ? true : false
}
/** 关闭按钮 */
function close() {
const obj = { path: "/system/user" }
proxy.$tab.closeOpenPage(obj)
}
/** 提交按钮 */
function submitForm() {
const userId = form.value.userId
const rIds = roleIds.value.join(",")
updateAuthRole({ userId: userId, roleIds: rIds }).then(response => {
proxy.$modal.msgSuccess("授权成功")
close()
})
}
(() => {
const userId = route.params && route.params.userId
if (userId) {
loading.value = true
getAuthRole(userId).then(response => {
form.value = response.user
roles.value = response.roles
total.value = roles.value.length
nextTick(() => {
roles.value.forEach(row => {
if (row.flag) {
proxy.$refs["roleRef"].toggleRowSelection(row)
}
})
})
loading.value = false
})
}
})()
</script>
<template>
<div class="app-container">
<el-row :gutter="20">
<el-col :span="6" :xs="24">
<el-card class="box-card">
<template v-slot:header>
<div class="clearfix">
<span>个人信息</span>
</div>
</template>
<div>
<div class="text-center">
<userAvatar />
</div>
<ul class="list-group list-group-striped">
<li class="list-group-item">
<svg-icon icon-class="user" />用户名称
<div class="pull-right">{{ state.user.userName }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="phone" />手机号码
<div class="pull-right">{{ state.user.phonenumber }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="email" />用户邮箱
<div class="pull-right">{{ state.user.email }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="tree" />所属部门
<div class="pull-right" v-if="state.user.dept">{{ state.user.dept.deptName }} / {{ state.postGroup }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="peoples" />所属角色
<div class="pull-right">{{ state.roleGroup }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="date" />创建日期
<div class="pull-right">{{ state.user.createTime }}</div>
</li>
</ul>
</div>
</el-card>
</el-col>
<el-col :span="18" :xs="24">
<el-card>
<template v-slot:header>
<div class="clearfix">
<span>基本资料</span>
</div>
</template>
<el-tabs v-model="selectedTab">
<el-tab-pane label="基本资料" name="userinfo">
<userInfo :user="state.user" />
</el-tab-pane>
<el-tab-pane label="修改密码" name="resetPwd">
<resetPwd />
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup name="Profile">
import userAvatar from "./userAvatar"
import userInfo from "./userInfo"
import resetPwd from "./resetPwd"
import { getUserProfile } from "@/api/system/user"
const route = useRoute()
const selectedTab = ref("userinfo")
const state = reactive({
user: {},
roleGroup: {},
postGroup: {}
})
function getUser() {
getUserProfile().then(response => {
state.user = response.data
state.roleGroup = response.roleGroup
state.postGroup = response.postGroup
})
}
onMounted(() => {
const activeTab = route.params && route.params.activeTab
if (activeTab) {
selectedTab.value = activeTab
}
getUser()
})
</script>
<template>
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import { updateUserPwd } from "@/api/system/user"
const { proxy } = getCurrentInstance()
const user = reactive({
oldPassword: undefined,
newPassword: undefined,
confirmPassword: undefined
})
const equalToPassword = (rule, value, callback) => {
if (user.newPassword !== value) {
callback(new Error("两次输入的密码不一致"))
} else {
callback()
}
}
const rules = ref({
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
})
/** 提交按钮 */
function submit() {
proxy.$refs.pwdRef.validate(valid => {
if (valid) {
updateUserPwd(user.oldPassword, user.newPassword).then(response => {
proxy.$modal.msgSuccess("修改成功")
})
}
})
}
/** 关闭按钮 */
function close() {
proxy.$tab.closePage()
}
</script>
<template>
<div class="user-info-head" @click="editCropper()">
<img :src="options.img" title="点击上传头像" class="img-circle img-lg" />
<el-dialog :title="title" v-model="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
<el-row>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<vue-cropper
ref="cropper"
:img="options.img"
:info="true"
:autoCrop="options.autoCrop"
:autoCropWidth="options.autoCropWidth"
:autoCropHeight="options.autoCropHeight"
:fixedBox="options.fixedBox"
:outputType="options.outputType"
@realTime="realTime"
v-if="visible"
/>
</el-col>
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
<div class="avatar-upload-preview">
<img :src="options.previews.url" :style="options.previews.img" />
</div>
</el-col>
</el-row>
<br />
<el-row>
<el-col :lg="2" :md="2">
<el-upload
action="#"
:http-request="requestUpload"
:show-file-list="false"
:before-upload="beforeUpload"
>
<el-button>
选择
<el-icon class="el-icon--right"><Upload /></el-icon>
</el-button>
</el-upload>
</el-col>
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
<el-button icon="Plus" @click="changeScale(1)"></el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="Minus" @click="changeScale(-1)"></el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
</el-col>
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
<el-button icon="RefreshRight" @click="rotateRight()"></el-button>
</el-col>
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
<el-button type="primary" @click="uploadImg()">提 交</el-button>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<script setup>
import "vue-cropper/dist/index.css"
import { VueCropper } from "vue-cropper"
import { uploadAvatar } from "@/api/system/user"
import useUserStore from "@/store/modules/user"
const userStore = useUserStore()
const { proxy } = getCurrentInstance()
const open = ref(false)
const visible = ref(false)
const title = ref("修改头像")
//图片裁剪数据
const options = reactive({
img: userStore.avatar, // 裁剪图片的地址
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度
fixedBox: true, // 固定截图框大小 不允许改变
outputType: "png", // 默认生成截图为PNG格式
filename: 'avatar', // 文件名称
previews: {} //预览数据
})
/** 编辑头像 */
function editCropper() {
open.value = true
}
/** 打开弹出层结束时的回调 */
function modalOpened() {
visible.value = true
}
/** 覆盖默认上传行为 */
function requestUpload() {}
/** 向左旋转 */
function rotateLeft() {
proxy.$refs.cropper.rotateLeft()
}
/** 向右旋转 */
function rotateRight() {
proxy.$refs.cropper.rotateRight()
}
/** 图片缩放 */
function changeScale(num) {
num = num || 1
proxy.$refs.cropper.changeScale(num)
}
/** 上传预处理 */
function beforeUpload(file) {
if (file.type.indexOf("image/") == -1) {
proxy.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。")
} else {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => {
options.img = reader.result
options.filename = file.name
}
}
}
/** 上传图片 */
function uploadImg() {
proxy.$refs.cropper.getCropBlob(data => {
let formData = new FormData()
formData.append("avatarfile", data, options.filename)
uploadAvatar(formData).then(response => {
open.value = false
options.img = import.meta.env.VITE_APP_BASE_API + response.imgUrl
userStore.avatar = options.img
proxy.$modal.msgSuccess("修改成功")
visible.value = false
})
})
}
/** 实时预览 */
function realTime(data) {
options.previews = data
}
/** 关闭窗口 */
function closeDialog() {
options.img = userStore.avatar
options.visible = false
}
</script>
<style lang='scss' scoped>
.user-info-head {
position: relative;
display: inline-block;
height: 120px;
}
.user-info-head:hover:after {
content: "+";
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: #eee;
background: rgba(0, 0, 0, 0.5);
font-size: 24px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
cursor: pointer;
line-height: 110px;
border-radius: 50%;
}
</style>
\ No newline at end of file
<template>
<el-form ref="userRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" maxlength="30" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" maxlength="11" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" maxlength="50" />
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="form.sex">
<el-radio value="0"></el-radio>
<el-radio value="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">保存</el-button>
<el-button type="danger" @click="close">关闭</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import { updateUserProfile } from "@/api/system/user"
const props = defineProps({
user: {
type: Object
}
})
const { proxy } = getCurrentInstance()
const form = ref({})
const rules = ref({
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
})
/** 提交按钮 */
function submit() {
proxy.$refs.userRef.validate(valid => {
if (valid) {
updateUserProfile(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功")
props.user.phonenumber = form.value.phonenumber
props.user.email = form.value.email
})
}
})
}
/** 关闭按钮 */
function close() {
proxy.$tab.closePage()
}
// 回显当前登录用户信息
watch(() => props.user, user => {
if (user) {
form.value = { nickName: user.nickName, phonenumber: user.phonenumber, email: user.email, sex: user.sex }
}
},{ immediate: true })
</script>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment