Pre Merge pull request !142 from knightdreams6/dev

This commit is contained in:
knightdreams6 2024-08-26 09:56:29 +00:00 committed by Gitee
commit e488a9e1cf
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
6 changed files with 77 additions and 2 deletions

View File

@ -39,6 +39,7 @@
"jsencrypt": "3.3.2",
"nprogress": "0.2.0",
"pinia": "2.1.7",
"qrcode.vue": "3.4.1",
"screenfull": "6.0.2",
"vue": "3.4.34",
"vue-cropper": "1.1.1",

View File

@ -72,6 +72,21 @@ export const delUser = (userId: Array<string | number> | string | number) => {
});
};
/**
* OTP秘钥重置
* @param userId ID
*/
export const resetUserOptSecret = (userId: string | number) => {
return request({
url: '/system/user/resetOtpSecret/' + userId,
method: 'put',
headers: {
isEncrypt: true,
repeatSubmit: false
}
});
};
/**
*
* @param userId ID
@ -217,6 +232,7 @@ export default {
updateUser,
delUser,
resetUserPwd,
resetUserOptSecret,
changeUserStatus,
getUserProfile,
updateUserProfile,

View File

@ -39,6 +39,8 @@ export interface UserVO extends BaseEntity {
delFlag: string;
loginIp: string;
loginDate: string;
otpSecret: string;
otpUrl: string;
remark: string;
deptName: string;
roles: RoleVO[];

View File

@ -18,6 +18,7 @@ export interface LoginData {
tenantId?: string;
username?: string;
password?: string;
otpCode?: number;
rememberMe?: boolean;
socialCode?: string;
socialState?: string;

View File

@ -18,6 +18,11 @@
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item prop="otpCode">
<el-input v-model="loginForm.otpCode" type="number" size="large" auto-complete="off" placeholder="OTP验证码" @keyup.enter="handleLogin">
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template>
</el-input>
</el-form-item>
<el-form-item v-if="captchaEnabled" prop="code">
<el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin">
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template>
@ -76,6 +81,7 @@ const loginForm = ref<LoginData>({
tenantId: '000000',
username: 'admin',
password: 'admin123',
otpCode: NaN,
rememberMe: false,
code: '',
uuid: ''
@ -85,6 +91,7 @@ const loginRules: ElFormRules = {
tenantId: [{ required: true, trigger: 'blur', message: '请输入您的租户编号' }],
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
otpCode: [{ required: true, trigger: 'blur', message: '请输入您的OTP验证码' }],
code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
};

View File

@ -91,13 +91,14 @@
</el-row>
</template>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange" @cell-click="cellClickFunc">
<el-table-column type="selection" width="50" align="center" />
<el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
<el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
<el-table-column v-if="columns[7].visible" key="otpSecret" label="OTP秘钥" align="center" prop="otpSecret" width="120" />
<el-table-column v-if="columns[5].visible" key="status" label="状态" align="center">
<template #default="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
@ -123,6 +124,16 @@
<el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button>
</el-tooltip>
<el-tooltip content="重置OTP秘钥" placement="top">
<el-button
v-hasPermi="['system:user:resetPwd']"
link
type="primary"
icon="Lock"
@click="handleResetOtpSecret(scope.row)"
></el-button>
</el-tooltip>
<el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top">
<el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button>
</el-tooltip>
@ -281,6 +292,12 @@
</div>
</template>
</el-dialog>
<el-dialog v-model="optSecretVisible" title="OTP秘钥绑定" width="500" append-to-body>
<div style="display: flex; justify-content: center">
<qrcode-vue :value="otpUrl" :size="150" level="H" />
</div>
</el-dialog>
</div>
</template>
@ -294,6 +311,7 @@ import { treeselect } from '@/api/system/dept';
import { globalHeaders } from '@/utils/request';
import { to } from 'await-to-js';
import { optionselect } from '@/api/system/post';
import QrcodeVue from 'qrcode.vue';
const router = useRouter();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -334,7 +352,8 @@ const columns = ref<FieldOption[]>([
{ key: 3, label: `部门`, visible: true, children: [] },
{ key: 4, label: `手机号码`, visible: true, children: [] },
{ key: 5, label: `状态`, visible: true, children: [] },
{ key: 6, label: `创建时间`, visible: true, children: [] }
{ key: 6, label: `创建时间`, visible: true, children: [] },
{ key: 7, label: `OTP秘钥`, visible: true, children: [] }
]);
const deptTreeRef = ref<ElTreeInstance>();
@ -431,6 +450,18 @@ watchEffect(
}
);
const optSecretVisible = ref(false);
const otpUrl = ref(undefined);
const cellClickFunc = (row, column) => {
if (column?.rawColumnKey === 'otpSecret') {
otpUrl.value = row.otpUrl;
if (otpUrl.value) {
optSecretVisible.value = true;
}
}
};
/** 查询部门下拉树结构 */
const getTreeSelect = async () => {
const res = await api.deptTreeSelect();
@ -495,6 +526,23 @@ const handleAuthRole = (row: UserVO) => {
router.push('/system/user-auth/role/' + userId);
};
/** 重置谷歌密钥按钮操作 */
const handleResetOtpSecret = async (row: UserVO) => {
const [err, res] = await to(
ElMessageBox.confirm('请确认是否重置OTP密钥', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false
})
);
if (!err && res) {
await api.resetUserOptSecret(row.userId);
proxy?.$modal.msgSuccess('密钥重置成功');
await getList();
}
};
/** 重置密码按钮操作 */
const handleResetPwd = async (row: UserVO) => {
const [err, res] = await to(