feat(oidc): 接入统一认证登录与身份自助绑定
- 登录页接入统一认证入口并处理认证回调 - 个人中心新增认证身份区块,支持自助绑定与解绑 - 头像菜单与应用中心新增认证身份入口 - 应用中心删除经营管理分组,业务系统卡片指向统一认证授权地址 - 用户管理页移除认证身份代绑入口与弹窗 - 身份关联接口从用户域移到认证域
This commit is contained in:
@@ -220,7 +220,6 @@ const sortFlag = ref<Sortable | null>(null);
|
||||
|
||||
const fieldConfigs = computed(() => formData.value?.fieldConfigs || []);
|
||||
|
||||
// 只看 AI 改动过的字段
|
||||
const onlyAiChanged = ref(false);
|
||||
|
||||
// AI 改动过的字段数
|
||||
@@ -334,6 +333,10 @@ function destroySort() {
|
||||
/**
|
||||
* 暴露字段排序、显隐切换与定位能力
|
||||
*/
|
||||
|
||||
/**
|
||||
* 暴露给父组件
|
||||
*/
|
||||
defineExpose({ initSort, destroySort, showOnlyAiChanged, locateField });
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
|
||||
@@ -198,6 +198,9 @@ import { useGenConfig } from "../composables/useGenConfig";
|
||||
import { useCodePreview } from "../composables/useCodePreview";
|
||||
import { useLocalWrite } from "../composables/useLocalWrite";
|
||||
import { useAiFillDiff, type AiChangeRow } from "../composables/useAiFillDiff";
|
||||
import BasicConfigStep from "./BasicConfigStep.vue";
|
||||
import FieldConfigStep from "./FieldConfigStep.vue";
|
||||
import PreviewStep from "./PreviewStep.vue";
|
||||
|
||||
const STEP = { BASIC_CONFIG: 0, FIELD_CONFIG: 1, PREVIEW: 2 } as const;
|
||||
const STEPS = [
|
||||
@@ -244,9 +247,9 @@ const loading = ref(false);
|
||||
const aiLoading = ref(false);
|
||||
const loadingText = ref("loading...");
|
||||
|
||||
const basicConfigRef = ref();
|
||||
const fieldConfigRef = ref();
|
||||
const previewRef = ref();
|
||||
const basicConfigRef = ref<InstanceType<typeof BasicConfigStep>>();
|
||||
const fieldConfigRef = ref<InstanceType<typeof FieldConfigStep>>();
|
||||
const previewRef = ref<InstanceType<typeof PreviewStep>>();
|
||||
|
||||
const {
|
||||
genConfigFormData,
|
||||
@@ -482,7 +485,7 @@ async function handleNext() {
|
||||
|
||||
if (currentStep.value === STEP.PREVIEW) {
|
||||
const pageType = genConfigFormData.value.pageType || "classic";
|
||||
GeneratorAPI.download(currentTableName.value, pageType as "classic" | "crud", "ts");
|
||||
await GeneratorAPI.download(currentTableName.value, pageType as "classic" | "crud", "ts");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,8 @@ import "codemirror/mode/javascript/javascript.js";
|
||||
import Codemirror from "codemirror-editor-vue3";
|
||||
import type { CmComponentRef } from "codemirror-editor-vue3";
|
||||
import type { EditorConfiguration } from "codemirror";
|
||||
import type { TreeInstance } from "element-plus";
|
||||
import type { TreeNode } from "../utils/tree-builder";
|
||||
import GeneratorAPI from "@/api/codegen";
|
||||
import type { GenConfigForm } from "@/api/codegen";
|
||||
import { getFileIcon } from "../utils/tree-builder";
|
||||
@@ -158,7 +160,7 @@ const props = defineProps<{
|
||||
previewScope: "all" | "frontend" | "backend";
|
||||
previewTypes: string[];
|
||||
previewTypeOptions: string[];
|
||||
filteredTreeData: any[];
|
||||
filteredTreeData: TreeNode[];
|
||||
code: string;
|
||||
currentFileKey: string;
|
||||
tableName: string;
|
||||
@@ -170,13 +172,13 @@ const props = defineProps<{
|
||||
const emit = defineEmits<{
|
||||
(_e: "update:previewScope", _val: "all" | "frontend" | "backend"): void;
|
||||
(_e: "update:previewTypes", _val: string[]): void;
|
||||
(_e: "file-click", _data: any): void;
|
||||
(_e: "file-click", _data: TreeNode): void;
|
||||
(_e: "copy"): void;
|
||||
}>();
|
||||
|
||||
const cmRef = ref<CmComponentRef>();
|
||||
const cmOptions: EditorConfiguration = { mode: "text/javascript" };
|
||||
const fileTreeRef = ref();
|
||||
const fileTreeRef = ref<TreeInstance>();
|
||||
const fileTreeWidth = ref(280);
|
||||
|
||||
const currentFilePath = computed(() => {
|
||||
@@ -189,15 +191,16 @@ const currentFilePath = computed(() => {
|
||||
/**
|
||||
* 切换预览范围
|
||||
*/
|
||||
function onScopeChange(val: any) {
|
||||
emit("update:previewScope", val as "all" | "frontend" | "backend");
|
||||
function onScopeChange(val: unknown) {
|
||||
if (val === "all" || val === "frontend" || val === "backend") emit("update:previewScope", val);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换预览文件类型
|
||||
*/
|
||||
function onTypesChange(val: any) {
|
||||
emit("update:previewTypes", val as string[]);
|
||||
function onTypesChange(val: unknown) {
|
||||
if (Array.isArray(val) && val.every((item) => typeof item === "string"))
|
||||
emit("update:previewTypes", val);
|
||||
}
|
||||
|
||||
const currentLanguage = computed(() => {
|
||||
@@ -211,7 +214,7 @@ const fileCount = computed(() => {
|
||||
/**
|
||||
* 递归统计文件数量
|
||||
*/
|
||||
function walk(nodes: any[]) {
|
||||
function walk(nodes: TreeNode[]) {
|
||||
nodes.forEach((n) => {
|
||||
if (!n.children || !n.children.length) count++;
|
||||
else walk(n.children);
|
||||
@@ -226,48 +229,52 @@ const fileCount = computed(() => {
|
||||
*/
|
||||
function handleDownload() {
|
||||
const pageType = props.genConfigFormData.pageType || "classic";
|
||||
GeneratorAPI.download(props.tableName, pageType as "classic" | "crud", "ts");
|
||||
return GeneratorAPI.download(props.tableName, pageType as "classic" | "crud", "ts");
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新代码编辑器布局
|
||||
*/
|
||||
function refreshEditor() {
|
||||
const inst = cmRef.value as any;
|
||||
inst?.cminstance?.refresh?.();
|
||||
inst?.cm?.refresh?.();
|
||||
inst?.editor?.refresh?.();
|
||||
cmRef.value?.refresh();
|
||||
}
|
||||
|
||||
// 拖拽结束、再次开始或组件卸载时,共用同一份监听清理函数。
|
||||
let stopResize: (() => void) | undefined;
|
||||
|
||||
/**
|
||||
* 开始拖动文件树宽度
|
||||
*/
|
||||
function startResize(e: MouseEvent) {
|
||||
stopResize?.();
|
||||
const startX = e.clientX;
|
||||
const startWidth = fileTreeWidth.value;
|
||||
/**
|
||||
* 拖动中更新文件树宽度
|
||||
* 按鼠标位移调整预览区域宽度。
|
||||
*/
|
||||
const onMove = (ev: MouseEvent) => {
|
||||
fileTreeWidth.value = Math.max(200, Math.min(500, startWidth + ev.clientX - startX));
|
||||
};
|
||||
/**
|
||||
* 结束拖动并解绑监听
|
||||
* 结束拖动并移除鼠标监听。
|
||||
*/
|
||||
const onUp = () => {
|
||||
document.removeEventListener("mousemove", onMove);
|
||||
document.removeEventListener("mouseup", onUp);
|
||||
stopResize = undefined;
|
||||
};
|
||||
stopResize = onUp;
|
||||
document.addEventListener("mousemove", onMove);
|
||||
document.addEventListener("mouseup", onUp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 暴露编辑器刷新与文件树引用
|
||||
* 父组件切换到预览步骤后刷新编辑器布局。
|
||||
*/
|
||||
defineExpose({ refreshEditor, fileTreeRef });
|
||||
defineExpose({ refreshEditor });
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stopResize?.();
|
||||
cmRef.value?.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -80,7 +80,7 @@ import { MagicStick, Refresh, RefreshLeft, Search } from "@element-plus/icons-vu
|
||||
import { ElMessage, ElMessageBox, type FormInstance } from "element-plus";
|
||||
|
||||
import GeneratorAPI from "@/api/codegen";
|
||||
import type { TableItem, TableQueryParams } from "@/api/codegen";
|
||||
import type { TableItem, TableQuery } from "@/api/codegen";
|
||||
import { usePageTable } from "@/composables";
|
||||
|
||||
// 表已配置代码生成(1:是;0:否)
|
||||
@@ -100,7 +100,7 @@ const queryFormRef = ref<FormInstance>();
|
||||
// 分页表格数据管理
|
||||
const { loading, list, total, params, fetchData, handleQuery, handleResetQuery } = usePageTable<
|
||||
TableItem,
|
||||
TableQueryParams
|
||||
TableQuery
|
||||
>({
|
||||
initialParams: {
|
||||
pageNum: 1,
|
||||
|
||||
@@ -25,7 +25,6 @@ export function useCodePreview(genConfigFormData: Ref<GenConfigForm>) {
|
||||
|
||||
const code = ref("");
|
||||
const currentFileKey = ref("");
|
||||
const fileTreeRef = ref();
|
||||
|
||||
const { copy, copied } = useClipboard();
|
||||
|
||||
@@ -53,21 +52,15 @@ export function useCodePreview(genConfigFormData: Ref<GenConfigForm>) {
|
||||
previewTypeOptions.value = typeOptions;
|
||||
previewTypes.value = [...typeOptions];
|
||||
|
||||
/**
|
||||
* 构建树
|
||||
*/
|
||||
// 构建树
|
||||
const tree = buildFileTree(previewList);
|
||||
treeData.value = tree?.children ? [...tree.children] : [];
|
||||
|
||||
/**
|
||||
* 选中第一个叶子节点
|
||||
*/
|
||||
// 选中第一个叶子节点
|
||||
const firstLeaf = findFirstLeaf(tree);
|
||||
if (firstLeaf) {
|
||||
code.value = firstLeaf.content || "";
|
||||
currentFileKey.value = firstLeaf.key || "";
|
||||
await nextTick();
|
||||
fileTreeRef.value?.setCurrentKey?.(currentFileKey.value);
|
||||
}
|
||||
|
||||
return previewList;
|
||||
@@ -93,7 +86,7 @@ export function useCodePreview(genConfigFormData: Ref<GenConfigForm>) {
|
||||
// 过滤条件变了之后,如果当前选中的文件还在就继续高亮,否则选第一个
|
||||
watch(
|
||||
() => filteredTreeData.value,
|
||||
async (nodes) => {
|
||||
(nodes) => {
|
||||
if (!nodes.length) {
|
||||
currentFileKey.value = "";
|
||||
code.value = "";
|
||||
@@ -102,8 +95,6 @@ export function useCodePreview(genConfigFormData: Ref<GenConfigForm>) {
|
||||
if (currentFileKey.value) {
|
||||
const leaf = findLeafByKey(nodes, currentFileKey.value);
|
||||
if (leaf) {
|
||||
await nextTick();
|
||||
fileTreeRef.value?.setCurrentKey?.(currentFileKey.value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -111,8 +102,6 @@ export function useCodePreview(genConfigFormData: Ref<GenConfigForm>) {
|
||||
if (first) {
|
||||
code.value = first.content || "";
|
||||
currentFileKey.value = first.key || "";
|
||||
await nextTick();
|
||||
fileTreeRef.value?.setCurrentKey?.(currentFileKey.value);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
@@ -126,7 +115,6 @@ export function useCodePreview(genConfigFormData: Ref<GenConfigForm>) {
|
||||
previewTypeOptions,
|
||||
code,
|
||||
currentFileKey,
|
||||
fileTreeRef,
|
||||
handlePreview,
|
||||
handleFileTreeNodeClick,
|
||||
handleCopyCode,
|
||||
|
||||
@@ -75,8 +75,6 @@ export function useLocalWrite(genConfigFormData: Ref<GenConfigForm>) {
|
||||
writeDialog.visible = false;
|
||||
}
|
||||
|
||||
// ---- 内部工具函数 ----
|
||||
|
||||
/**
|
||||
* 判断生成项写入前端还是后端根目录
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user