为什么:后台能开号了,但界面还没有入口;而且创作者登录后会落到 /dashboard/index(他没有运营后台权限) 直接掉 404。这批把开号入口、一次性凭据展示、落地分流与首登改密一次补齐。 - 创作者入驻页:「新增创作者」按钮(名称/类型/联系人/邮箱/国家)、「账号」列(已开通/未开通)、 行内「开通账号 / 重置密码」;密码一次性弹窗展示(等宽可选中 + 一键复制 + 提示只显示这一次) - 落地分流:新增 landingPath()(取账号能进的第一个菜单),登录与访问根路径都走它 —— 创作者落 /creator-center/workspace,超管第一条仍是工作台(行为不变) - 首登强制改密:Layout 挂 MustChangePasswordDialog,登录或刷新后若 profile 带 mustChangePassword 就弹不可关闭的 改密框,改完清标记;只能改密或退出登录
278 lines
7.0 KiB
JavaScript
278 lines
7.0 KiB
JavaScript
import { onMounted, reactive, ref } from 'vue'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import {
|
|
auditCreatorApi,
|
|
createCreatorApi,
|
|
listCreatorDocumentsApi,
|
|
openCreatorAccountApi,
|
|
pageCreatorsApi,
|
|
resetCreatorPasswordApi
|
|
} from '@/api/admin/creator'
|
|
|
|
/** 与后端 CreatorService 的状态取值保持一致 */
|
|
export const CREATOR_STATUS = [
|
|
{ value: 'pending', label: '待审核', tag: 'warning' },
|
|
{ value: 'approved', label: '已通过', tag: 'success' },
|
|
{ value: 'rejected', label: '已驳回', tag: 'danger' },
|
|
{ value: 'frozen', label: '已冻结', tag: 'info' }
|
|
]
|
|
|
|
export const CREATOR_TYPE = [
|
|
{ value: 'INDIVIDUAL', label: '个人' },
|
|
{ value: 'COMPANY', label: '机构' }
|
|
]
|
|
|
|
export function creatorStatusMeta(status) {
|
|
return (
|
|
CREATOR_STATUS.find((item) => item.value === status) || { label: status || '-', tag: 'info' }
|
|
)
|
|
}
|
|
|
|
export function creatorTypeText(type) {
|
|
return CREATOR_TYPE.find((item) => item.value === type)?.label || type || '-'
|
|
}
|
|
|
|
export function useCreatorAudit() {
|
|
const rows = ref([])
|
|
const total = ref(0)
|
|
const loading = ref(false)
|
|
const keyword = ref('')
|
|
const statusFilter = ref(undefined)
|
|
const typeFilter = ref(undefined)
|
|
const currentPage = ref(1)
|
|
const pageSize = ref(10)
|
|
|
|
const auditVisible = ref(false)
|
|
const auditSaving = ref(false)
|
|
const auditTarget = ref(null)
|
|
const auditForm = reactive({ action: 'APPROVE', reason: '', rejectCode: '' })
|
|
|
|
const documentsVisible = ref(false)
|
|
const documentsLoading = ref(false)
|
|
const documents = ref([])
|
|
const documentsTarget = ref(null)
|
|
|
|
async function load() {
|
|
loading.value = true
|
|
try {
|
|
const res = await pageCreatorsApi({
|
|
pageIndex: currentPage.value,
|
|
pageSize: pageSize.value,
|
|
keyword: keyword.value.trim() || undefined,
|
|
status: statusFilter.value,
|
|
type: typeFilter.value
|
|
})
|
|
rows.value = res.data?.list || []
|
|
total.value = res.data?.total || 0
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
function query() {
|
|
currentPage.value = 1
|
|
load()
|
|
}
|
|
|
|
function reset() {
|
|
keyword.value = ''
|
|
statusFilter.value = undefined
|
|
typeFilter.value = undefined
|
|
query()
|
|
}
|
|
|
|
function handleSizeChange() {
|
|
currentPage.value = 1
|
|
load()
|
|
}
|
|
|
|
async function openDocuments(row) {
|
|
documentsTarget.value = row
|
|
documentsVisible.value = true
|
|
documentsLoading.value = true
|
|
documents.value = []
|
|
try {
|
|
documents.value = (await listCreatorDocumentsApi(row.id)).data || []
|
|
} finally {
|
|
documentsLoading.value = false
|
|
}
|
|
}
|
|
|
|
function openAudit(row, action = 'APPROVE') {
|
|
auditTarget.value = row
|
|
auditForm.action = action
|
|
auditForm.reason = ''
|
|
auditForm.rejectCode = ''
|
|
auditVisible.value = true
|
|
}
|
|
|
|
async function confirmAudit() {
|
|
const row = auditTarget.value
|
|
if (!row) return
|
|
if (auditForm.action === 'REJECT' && !auditForm.reason.trim()) {
|
|
return ElMessage.warning('驳回必须填写原因')
|
|
}
|
|
auditSaving.value = true
|
|
try {
|
|
await auditCreatorApi(row.id, {
|
|
action: auditForm.action,
|
|
reason: auditForm.reason.trim(),
|
|
rejectCode: auditForm.rejectCode.trim()
|
|
})
|
|
ElMessage.success('审核已提交')
|
|
auditVisible.value = false
|
|
await load()
|
|
} finally {
|
|
auditSaving.value = false
|
|
}
|
|
}
|
|
|
|
/** 冻结是不可逆的运营动作,单独二次确认 */
|
|
async function freeze(row) {
|
|
try {
|
|
await ElMessageBox.confirm(`冻结后「${row.name}」将无法提交内容,确认冻结?`, '冻结创作者', {
|
|
confirmButtonText: '确认冻结',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
})
|
|
} catch {
|
|
return
|
|
}
|
|
await auditCreatorApi(row.id, { action: 'FREEZE', reason: '运营冻结' })
|
|
ElMessage.success('已冻结')
|
|
await load()
|
|
}
|
|
|
|
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,
|
|
loading,
|
|
keyword,
|
|
statusFilter,
|
|
typeFilter,
|
|
currentPage,
|
|
pageSize,
|
|
auditVisible,
|
|
auditSaving,
|
|
auditTarget,
|
|
auditForm,
|
|
documentsVisible,
|
|
documentsLoading,
|
|
documents,
|
|
documentsTarget,
|
|
load,
|
|
query,
|
|
reset,
|
|
handleSizeChange,
|
|
openDocuments,
|
|
openAudit,
|
|
confirmAudit,
|
|
freeze,
|
|
createVisible,
|
|
createSaving,
|
|
createForm,
|
|
openCreate,
|
|
confirmCreate,
|
|
accountVisible,
|
|
accountSaving,
|
|
accountResult,
|
|
openAccount,
|
|
resetPassword,
|
|
copyCredential,
|
|
closeAccount
|
|
}
|
|
}
|