feat: 新增电工 APP 账号开通与密码重置功能
- 新增后端重置密码接口及前端对应操作入口 - 新增补开电工 APP 账号的更新参数 - 新增 hasAccount 字段标识电工是否开通 APP 账号 - 新增数据库菜单及角色绑定支持密码重置权限 - 移除后台角色中错误的 WORKER 和 CUSTOMER 角色
This commit is contained in:
1 parent
6cf6a3d5b9
commit
f8117e33b6
9 files changed
+164
-18
No files matched your search
@@ -43,6 +43,8 @@ export interface WorkerRecord {
|
||||
auditBy?: number;
|
||||
auditAt?: string;
|
||||
lastLoginAt?: string;
|
||||
// 是否已开通电工 APP 登录账号
|
||||
hasAccount?: boolean;
|
||||
certStatus?: WorkerCertStatus;
|
||||
certs?: WorkerCertSummary[];
|
||||
createdAt?: string;
|
||||
@@ -119,6 +121,9 @@ export const workerRegistryApi = {
|
||||
|
||||
audit: (id: number, data: WorkerAuditPayload) => request.put(`/workers/${id}/audit`, data),
|
||||
|
||||
// 重置 APP 登录密码(后端固定重置为手机号后 6 位)
|
||||
resetPassword: (id: number) => request.post(`/workers/${id}/reset-password`),
|
||||
|
||||
addCert: (id: number, data: WorkerCertPayload) => request.post(`/workers/${id}/certs`, data),
|
||||
|
||||
updateCert: (id: number, certId: number, data: WorkerCertPayload) =>
|
||||
|
||||
@@ -165,6 +165,19 @@
|
||||
<template #icon><AuditOutlined /></template>
|
||||
审核
|
||||
</a-button>
|
||||
<a-popconfirm
|
||||
v-if="canResetPassword"
|
||||
title="确定重置该电工的 APP 登录密码吗?"
|
||||
description="重置后密码为手机号后 6 位"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
@confirm="handleResetPassword(record.id)"
|
||||
>
|
||||
<a-button type="link" size="small">
|
||||
<template #icon><KeyOutlined /></template>
|
||||
重置密码
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
<a-popconfirm
|
||||
v-if="canDelete"
|
||||
title="确定要删除该电工吗?"
|
||||
@@ -240,8 +253,11 @@
|
||||
<a-form-item label="服务评分" name="rating">
|
||||
<a-input-number v-model:value="formData.rating" :min="0" :max="5" :step="0.1" style="width: 160px" />
|
||||
</a-form-item>
|
||||
<a-form-item v-if="!isEdit" label="APP 登录账号">
|
||||
<div class="switch-line">
|
||||
<a-form-item label="APP 登录账号">
|
||||
<div v-if="isEdit && formData.hasAccount" class="switch-line">
|
||||
<span class="form-tip">该电工已开通 APP 登录账号,如需重置密码请使用列表中的「重置密码」。</span>
|
||||
</div>
|
||||
<div v-else class="switch-line">
|
||||
<a-switch v-model:checked="formData.withAccount" />
|
||||
<span class="form-tip">开启后同时创建电工 APP 登录密码,默认密码为手机号后 6 位</span>
|
||||
</div>
|
||||
@@ -381,6 +397,7 @@ import {
|
||||
DeleteOutlined,
|
||||
EditOutlined,
|
||||
AuditOutlined,
|
||||
KeyOutlined,
|
||||
TeamOutlined,
|
||||
ClockCircleOutlined,
|
||||
WarningOutlined,
|
||||
@@ -425,6 +442,7 @@ const canCreate = computed(() => permissionStore.hasPermission('worker:create'))
|
||||
const canUpdate = computed(() => permissionStore.hasPermission('worker:update'));
|
||||
const canDelete = computed(() => permissionStore.hasPermission('worker:delete'));
|
||||
const canAudit = computed(() => permissionStore.hasPermission('worker:audit'));
|
||||
const canResetPassword = computed(() => permissionStore.hasPermission('worker:reset-password'));
|
||||
|
||||
// ==================== 列表数据 ====================
|
||||
const loading = ref(false);
|
||||
@@ -501,7 +519,7 @@ const columns = [
|
||||
{ title: '在岗状态', key: 'status', align: 'center' as const, width: 110 },
|
||||
{ title: '评分', key: 'rating', align: 'center' as const, width: 90 },
|
||||
{ title: '完成数', dataIndex: 'completedCount', key: 'completedCount', align: 'center' as const, width: 90 },
|
||||
{ title: '操作', key: 'action', width: 210, fixed: 'right' as const },
|
||||
{ title: '操作', key: 'action', width: 300, fixed: 'right' as const },
|
||||
];
|
||||
|
||||
const pagination = computed(() => ({
|
||||
@@ -529,6 +547,8 @@ const formData = reactive({
|
||||
status: 1,
|
||||
rating: 5,
|
||||
withAccount: false,
|
||||
// 编辑时用于判断该电工是否已开通 APP 账号
|
||||
hasAccount: false,
|
||||
});
|
||||
|
||||
const formRules = {
|
||||
@@ -664,6 +684,8 @@ async function handleEdit(record: WorkerRecord) {
|
||||
formData.workerTitle = record.workerTitle || '';
|
||||
formData.status = record.status;
|
||||
formData.rating = Number(record.rating ?? 5);
|
||||
formData.hasAccount = record.hasAccount === true;
|
||||
formData.withAccount = false;
|
||||
|
||||
modalVisible.value = true;
|
||||
await loadCertRows(record.id);
|
||||
@@ -674,6 +696,7 @@ async function loadCertRows(workerId: number) {
|
||||
try {
|
||||
const res: any = await workerRegistryApi.getDetail(workerId);
|
||||
if (res.code === 200 && res.data) {
|
||||
formData.hasAccount = res.data.hasAccount === true;
|
||||
const certs: WorkerCert[] = res.data.certs || [];
|
||||
certRows.value = certs.map((c) => ({
|
||||
_key: certKeySeed++,
|
||||
@@ -700,6 +723,7 @@ function resetForm() {
|
||||
formData.status = 1;
|
||||
formData.rating = 5;
|
||||
formData.withAccount = false;
|
||||
formData.hasAccount = false;
|
||||
certRows.value = [];
|
||||
|
||||
if (formRef.value) {
|
||||
@@ -822,6 +846,8 @@ async function handleSubmit() {
|
||||
let res: any;
|
||||
if (isEdit.value && editId.value) {
|
||||
payload.status = formData.status;
|
||||
// 补开 APP 账号:仅对尚未开通的电工生效
|
||||
payload.withAccount = formData.withAccount;
|
||||
res = await workerRegistryApi.update(editId.value, payload);
|
||||
} else {
|
||||
payload.withAccount = formData.withAccount;
|
||||
@@ -880,6 +906,21 @@ async function handleDelete(id: number) {
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 重置密码 ====================
|
||||
async function handleResetPassword(id: number) {
|
||||
try {
|
||||
const res: any = await workerRegistryApi.resetPassword(id);
|
||||
if (res.code === 200) {
|
||||
message.success('密码已重置为手机号后 6 位');
|
||||
fetchList();
|
||||
} else {
|
||||
message.error(res.message || '重置密码失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('重置密码失败');
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 审核 ====================
|
||||
function handleAudit(record: WorkerRecord) {
|
||||
auditRecord.value = record;
|
||||
|
||||
Reference in new issue
Block a user