feat(aihr): 重构运营后台与租户知识治理
- 重构运营总览、侧栏和内容运营工作台\n- 增加大喇叭、成果审核与运营统计链路\n- 补齐租户、知识空间、分类和知识维护闭环\n- 加固标签页租户上下文、停用租户写保护与迁移预检
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<div class="tenant-governance p-2">
|
||||
<section class="tenant-governance__head">
|
||||
<div>
|
||||
<h1>租户管理</h1>
|
||||
<p>维护租户主体,并按“租户 → 知识空间 → 分类 → 知识”进入内容治理。</p>
|
||||
</div>
|
||||
<div class="tenant-governance__hint">知识空间、分类和知识仍按当前切换租户隔离管理。</div>
|
||||
</section>
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
@@ -72,8 +79,18 @@
|
||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="150" label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<el-table-column width="230" label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-hasPermi="['system:tenant:edit']"
|
||||
link
|
||||
type="primary"
|
||||
:loading="tenantContextSwitching"
|
||||
:disabled="tenantContextSwitching || scope.row.status !== '0'"
|
||||
:title="scope.row.status === '0' ? '进入此租户的知识维护' : '停用租户不能维护知识'"
|
||||
@click="manageKnowledge(scope.row)"
|
||||
>知识维护</el-button
|
||||
>
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||
</el-tooltip>
|
||||
@@ -160,6 +177,7 @@ import {
|
||||
} from '@/api/system/tenant';
|
||||
import { selectTenantPackage } from '@/api/system/tenantPackage';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { switchDynamicTenantContext, tenantContextSwitching } from '@/utils/tenant-context';
|
||||
import { TenantForm, TenantQuery, TenantVO } from '@/api/system/tenant/types';
|
||||
import { TenantPkgVO } from '@/api/system/tenantPackage/types';
|
||||
|
||||
@@ -232,6 +250,21 @@ const data = reactive<PageData<TenantForm, TenantQuery>>({
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 切换到目标租户后再进入空间、分类和文档维护。后端以动态租户上下文为准。 */
|
||||
const manageKnowledge = async (row: TenantVO) => {
|
||||
if (!row.tenantId || tenantContextSwitching.value) return;
|
||||
if (row.status !== '0') {
|
||||
proxy?.$modal.msgError('停用租户不能维护知识');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await switchDynamicTenantContext({ tenantId: row.tenantId, companyName: row.companyName }, '/knowledge/spaces');
|
||||
proxy?.$modal.msgSuccess(`已切换至“${row.companyName}”,可继续维护知识空间、分类和知识`);
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError(error instanceof Error && error.message ? error.message : '租户切换失败,请刷新后重试');
|
||||
}
|
||||
};
|
||||
|
||||
/** 查询所有租户套餐 */
|
||||
const getTenantPackage = async () => {
|
||||
const res = await selectTenantPackage();
|
||||
@@ -380,3 +413,43 @@ onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tenant-governance__head {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 8px 2px 16px;
|
||||
|
||||
h1 {
|
||||
margin: 0 0 6px;
|
||||
color: #162033;
|
||||
font-size: 24px;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: #657184;
|
||||
}
|
||||
}
|
||||
|
||||
.tenant-governance__hint {
|
||||
max-width: 420px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #dbe7fb;
|
||||
border-radius: 8px;
|
||||
color: #39699f;
|
||||
background: #f4f8ff;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.tenant-governance__head {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -294,7 +294,7 @@ import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
|
||||
import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
|
||||
import { RoleVO } from '@/api/system/role/types';
|
||||
import { PostVO } from '@/api/system/post/types';
|
||||
import { globalHeaders } from '@/utils/request';
|
||||
import { globalHeaders, reconcileTenantContextResponse } from '@/utils/request';
|
||||
import { to } from 'await-to-js';
|
||||
import { optionselect } from '@/api/system/post';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
@@ -332,6 +332,9 @@ const upload = reactive<ImportOption>({
|
||||
// 上传的地址
|
||||
url: import.meta.env.VITE_APP_BASE_API + '/system/user/importData'
|
||||
});
|
||||
watchEffect(() => {
|
||||
upload.headers = globalHeaders();
|
||||
});
|
||||
// 列显隐信息
|
||||
const columns = ref<FieldOption[]>([
|
||||
{ key: 0, label: `用户编号`, visible: false, children: [] },
|
||||
@@ -570,13 +573,14 @@ const handleFileUploadProgress = () => {
|
||||
};
|
||||
/** 文件上传成功处理 */
|
||||
const handleFileSuccess = (response: any, file: UploadFile) => {
|
||||
const tenantContextChanged = reconcileTenantContextResponse(response);
|
||||
upload.open = false;
|
||||
upload.isUploading = false;
|
||||
uploadRef.value?.handleRemove(file);
|
||||
ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
|
||||
dangerouslyUseHTMLString: true
|
||||
});
|
||||
getList();
|
||||
if (!tenantContextChanged) getList();
|
||||
};
|
||||
|
||||
/** 提交上传文件 */
|
||||
@@ -615,9 +619,7 @@ const handleUpdate = async (row?: UserForm) => {
|
||||
dialog.title = '修改用户';
|
||||
Object.assign(form.value, data.user);
|
||||
postOptions.value = data.posts;
|
||||
roleOptions.value = Array.from(
|
||||
new Map([...data.roles, ...data.user.roles].map(role => [role.roleId, role])).values()
|
||||
);
|
||||
roleOptions.value = Array.from(new Map([...data.roles, ...data.user.roles].map((role) => [role.roleId, role])).values());
|
||||
form.value.postIds = data.postIds;
|
||||
form.value.roleIds = data.roleIds;
|
||||
form.value.password = '';
|
||||
|
||||
Reference in New Issue
Block a user