feat(web): 创作者审核页支持开号/重置密码;登录落地按角色分流 + 首登强制改密
为什么:后台能开号了,但界面还没有入口;而且创作者登录后会落到 /dashboard/index(他没有运营后台权限) 直接掉 404。这批把开号入口、一次性凭据展示、落地分流与首登改密一次补齐。 - 创作者入驻页:「新增创作者」按钮(名称/类型/联系人/邮箱/国家)、「账号」列(已开通/未开通)、 行内「开通账号 / 重置密码」;密码一次性弹窗展示(等宽可选中 + 一键复制 + 提示只显示这一次) - 落地分流:新增 landingPath()(取账号能进的第一个菜单),登录与访问根路径都走它 —— 创作者落 /creator-center/workspace,超管第一条仍是工作台(行为不变) - 首登强制改密:Layout 挂 MustChangePasswordDialog,登录或刷新后若 profile 带 mustChangePassword 就弹不可关闭的 改密框,改完清标记;只能改密或退出登录
This commit is contained in:
1 parent
bac070b60b
commit
8ce43ccd4c
10 files changed
+378
-7
No files matched your search
@@ -13,6 +13,8 @@ import {
|
||||
|
||||
const { can } = useRbac()
|
||||
const canAudit = can('creator:audit')
|
||||
/** 开通 / 重置账号是独立权限点(第一阶段只给超管) */
|
||||
const canOpenAccount = can('creator:account')
|
||||
|
||||
const {
|
||||
rows,
|
||||
@@ -38,7 +40,19 @@ const {
|
||||
openDocuments,
|
||||
openAudit,
|
||||
confirmAudit,
|
||||
freeze
|
||||
freeze,
|
||||
createVisible,
|
||||
createSaving,
|
||||
createForm,
|
||||
openCreate,
|
||||
confirmCreate,
|
||||
accountVisible,
|
||||
accountSaving,
|
||||
accountResult,
|
||||
openAccount,
|
||||
resetPassword,
|
||||
copyCredential,
|
||||
closeAccount
|
||||
} = useCreatorAudit()
|
||||
</script>
|
||||
|
||||
@@ -47,7 +61,9 @@ const {
|
||||
eyebrow="创作者管理"
|
||||
title="创作者入驻"
|
||||
description="审核创作者主体与资质,通过后创作者才能提交内容。"
|
||||
/>
|
||||
>
|
||||
<el-button v-if="canAudit" type="primary" @click="openCreate">新增创作者</el-button>
|
||||
</PageHeading>
|
||||
|
||||
<section class="panel">
|
||||
<div class="console-toolbar">
|
||||
@@ -127,6 +143,12 @@ const {
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="账号" width="110">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.adminUserId" type="success" effect="light">已开通</el-tag>
|
||||
<span v-else class="console-muted">未开通</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="auditAt"
|
||||
label="审核时间"
|
||||
@@ -141,7 +163,7 @@ const {
|
||||
show-overflow-tooltip
|
||||
:formatter="dateCell"
|
||||
/>
|
||||
<el-table-column label="操作" width="230" fixed="right">
|
||||
<el-table-column label="操作" width="330" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<div class="table-actions">
|
||||
<el-button type="primary" size="small" @click="openDocuments(row)">资质</el-button>
|
||||
@@ -155,6 +177,21 @@ const {
|
||||
@click="freeze(row)"
|
||||
>冻结</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="canOpenAccount && !row.adminUserId"
|
||||
type="primary"
|
||||
size="small"
|
||||
:loading="accountSaving"
|
||||
:disabled="row.status !== 'approved'"
|
||||
@click="openAccount(row)"
|
||||
>开通账号</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="canOpenAccount && row.adminUserId"
|
||||
size="small"
|
||||
@click="resetPassword(row)"
|
||||
>重置密码</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -231,4 +268,73 @@ const {
|
||||
<el-button type="primary" :loading="auditSaving" @click="confirmAudit">提交</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="createVisible" title="新增创作者" width="480px">
|
||||
<el-form label-position="top">
|
||||
<el-form-item label="创作者名称" required>
|
||||
<el-input v-model="createForm.name" maxlength="128" placeholder="公司名或个人名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<el-radio-group v-model="createForm.type">
|
||||
<el-radio v-for="item in CREATOR_TYPE" :key="item.value" :value="item.value">{{
|
||||
item.label
|
||||
}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人">
|
||||
<el-input v-model="createForm.contactName" maxlength="64" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系邮箱">
|
||||
<el-input v-model="createForm.contactEmail" maxlength="128" />
|
||||
</el-form-item>
|
||||
<el-form-item label="国家 / 地区">
|
||||
<el-input v-model="createForm.countryCode" maxlength="8" placeholder="ID" />
|
||||
</el-form-item>
|
||||
<el-alert
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="编号自动生成(CR+日期+序号),也是开通账号时默认的登录名;录入后需要先通过入驻审核才能开通账号"
|
||||
/>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="createVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="createSaving" @click="confirmCreate">录入</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
:model-value="accountVisible"
|
||||
:title="accountResult?.created ? '账号已开通' : '账号凭据'"
|
||||
width="520px"
|
||||
@close="closeAccount"
|
||||
@update:model-value="closeAccount"
|
||||
>
|
||||
<el-alert
|
||||
v-if="accountResult?.password"
|
||||
class="creator-account-alert"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="密码只显示这一次,关闭后无法再次查看;请立即复制并转达给创作者"
|
||||
/>
|
||||
<el-descriptions :column="1" border>
|
||||
<el-descriptions-item label="登录账号">
|
||||
<span class="creator-account-value">{{ accountResult?.username }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="初始密码">
|
||||
<span v-if="accountResult?.password" class="creator-account-value">{{
|
||||
accountResult.password
|
||||
}}</span>
|
||||
<span v-else class="console-muted">本次未生成新密码(账号此前已开通)</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="说明">
|
||||
<span class="console-muted">{{ accountResult?.message }}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<template #footer>
|
||||
<el-button v-if="accountResult?.password" @click="copyCredential">复制账号与密码</el-button>
|
||||
<el-button type="primary" @click="closeAccount">我已保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -1,6 +1,13 @@
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { auditCreatorApi, listCreatorDocumentsApi, pageCreatorsApi } from '@/api/admin/creator'
|
||||
import {
|
||||
auditCreatorApi,
|
||||
createCreatorApi,
|
||||
listCreatorDocumentsApi,
|
||||
openCreatorAccountApi,
|
||||
pageCreatorsApi,
|
||||
resetCreatorPasswordApi
|
||||
} from '@/api/admin/creator'
|
||||
|
||||
/** 与后端 CreatorService 的状态取值保持一致 */
|
||||
export const CREATOR_STATUS = [
|
||||
@@ -138,6 +145,97 @@ export function useCreatorAudit() {
|
||||
|
||||
onMounted(load)
|
||||
|
||||
// ---------- 手工录入创作者主体 ----------
|
||||
const createVisible = ref(false)
|
||||
const createSaving = ref(false)
|
||||
const createForm = reactive({
|
||||
name: '',
|
||||
type: 'COMPANY',
|
||||
contactName: '',
|
||||
contactEmail: '',
|
||||
countryCode: 'ID'
|
||||
})
|
||||
|
||||
function openCreate() {
|
||||
Object.assign(createForm, {
|
||||
name: '',
|
||||
type: 'COMPANY',
|
||||
contactName: '',
|
||||
contactEmail: '',
|
||||
countryCode: 'ID'
|
||||
})
|
||||
createVisible.value = true
|
||||
}
|
||||
|
||||
async function confirmCreate() {
|
||||
if (!createForm.name.trim()) return ElMessage.warning('请填写创作者名称')
|
||||
createSaving.value = true
|
||||
try {
|
||||
await createCreatorApi({ ...createForm, name: createForm.name.trim() })
|
||||
ElMessage.success('已录入,待入驻审核通过后才能开通账号')
|
||||
createVisible.value = false
|
||||
await load()
|
||||
} finally {
|
||||
createSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- 开通账号 / 重置密码 ----------
|
||||
const accountVisible = ref(false)
|
||||
const accountSaving = ref(false)
|
||||
/** 一次性凭据展示:password 只在开通 / 重置那一次有值 */
|
||||
const accountResult = ref(null)
|
||||
|
||||
async function openAccount(row) {
|
||||
accountSaving.value = true
|
||||
try {
|
||||
const res = await openCreatorAccountApi(row.id)
|
||||
accountResult.value = res.data || null
|
||||
accountVisible.value = true
|
||||
await load()
|
||||
} finally {
|
||||
accountSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function resetPassword(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`重置后「${row.name}」的旧密码立即失效,需要把新密码重新转达给他。确认重置?`,
|
||||
'重置账号密码',
|
||||
{ confirmButtonText: '确认重置', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
accountSaving.value = true
|
||||
try {
|
||||
const res = await resetCreatorPasswordApi(row.id)
|
||||
accountResult.value = res.data || null
|
||||
accountVisible.value = true
|
||||
} finally {
|
||||
accountSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 一次性密码要能被复制走;复制完由运营自己销毁截图 */
|
||||
async function copyCredential() {
|
||||
const item = accountResult.value
|
||||
if (!item?.password) return
|
||||
const text = `登录地址:${window.location.origin}/#/login\n账号:${item.username}\n初始密码:${item.password}`
|
||||
try {
|
||||
await navigator.clipboard.writeText(text)
|
||||
ElMessage.success('账号与密码已复制')
|
||||
} catch {
|
||||
ElMessage.warning('浏览器不允许自动复制,请手动选中复制')
|
||||
}
|
||||
}
|
||||
|
||||
function closeAccount() {
|
||||
accountVisible.value = false
|
||||
accountResult.value = null
|
||||
}
|
||||
|
||||
return {
|
||||
rows,
|
||||
total,
|
||||
@@ -162,6 +260,18 @@ export function useCreatorAudit() {
|
||||
openDocuments,
|
||||
openAudit,
|
||||
confirmAudit,
|
||||
freeze
|
||||
freeze,
|
||||
createVisible,
|
||||
createSaving,
|
||||
createForm,
|
||||
openCreate,
|
||||
confirmCreate,
|
||||
accountVisible,
|
||||
accountSaving,
|
||||
accountResult,
|
||||
openAccount,
|
||||
resetPassword,
|
||||
copyCredential,
|
||||
closeAccount
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user