mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-29 23:44:41 +00:00
refactor: 大规模代码整理与功能优化
1. 重构后端API路由、CRUD与模块结构,整合日志管理,移除废弃demo代码 2. 优化前端组件类型定义、样式与路由配置,修复权限判断逻辑 3. 调整默认排序规则、滚动条样式与工具类函数,更新依赖与配置文件 4. 修复多处类型不匹配与默认值问题,完善表单与菜单验证逻辑
This commit is contained in:
@@ -45,9 +45,11 @@ const hasAnyAuthItem = computed(() => {
|
||||
return props.list.some((item) => !item.auth || hasAuth(item.auth));
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "click", item: ButtonMoreItem): void;
|
||||
}>();
|
||||
interface Emits {
|
||||
click: [item: ButtonMoreItem];
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const handleClick = (item: ButtonMoreItem) => {
|
||||
emit("click", item);
|
||||
|
||||
@@ -30,9 +30,11 @@ interface Props {
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "click"): void;
|
||||
}>();
|
||||
interface Emits {
|
||||
click: [];
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
// 默认按钮配置
|
||||
const defaultButtons = {
|
||||
|
||||
@@ -46,7 +46,7 @@ defineOptions({ name: "FaDragVerify" });
|
||||
const emit = defineEmits(["handlerMove", "update:value", "passCallback"]);
|
||||
|
||||
// 组件属性接口定义
|
||||
interface PropsType {
|
||||
interface Props {
|
||||
/** 是否通过验证 */
|
||||
value: boolean;
|
||||
/** 组件宽度 */
|
||||
@@ -80,7 +80,7 @@ interface PropsType {
|
||||
}
|
||||
|
||||
// 属性默认值设置
|
||||
const props = withDefaults(defineProps<PropsType>(), {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
value: false,
|
||||
width: "100%",
|
||||
height: 40,
|
||||
|
||||
@@ -46,7 +46,7 @@ interface ColumnConfig {
|
||||
}
|
||||
|
||||
/** 导出配置选项 */
|
||||
interface ExportOptions {
|
||||
interface Props {
|
||||
/** 数据源 */
|
||||
data: ExportData[];
|
||||
/** 文件名(不含扩展名) */
|
||||
@@ -90,7 +90,7 @@ interface ExportOptions {
|
||||
};
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<ExportOptions>(), {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
filename: () => `export_${new Date().toISOString().slice(0, 10)}`,
|
||||
sheetName: "Sheet1",
|
||||
type: "primary",
|
||||
@@ -108,12 +108,14 @@ const props = withDefaults(defineProps<ExportOptions>(), {
|
||||
workbookOptions: () => ({}),
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
interface Emits {
|
||||
"before-export": [data: ExportData[]];
|
||||
"export-success": [filename: string, rowCount: number];
|
||||
"export-error": [error: ExportError];
|
||||
"export-progress": [progress: number];
|
||||
}>();
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
/** 导出错误类型 */
|
||||
class ExportError extends Error {
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
<div class="inline-block">
|
||||
<ElUpload
|
||||
:auto-upload="false"
|
||||
accept=".xlsx, .xls"
|
||||
:accept="accept"
|
||||
:show-file-list="false"
|
||||
:disabled="disabled"
|
||||
@change="handleFileChange"
|
||||
>
|
||||
<ElButton type="primary" v-ripple>
|
||||
<slot>导入 Excel</slot>
|
||||
<ElButton type="primary" v-ripple :loading="loading">
|
||||
<slot>{{ buttonText }}</slot>
|
||||
</ElButton>
|
||||
</ElUpload>
|
||||
</div>
|
||||
@@ -20,6 +21,24 @@ import type { UploadFile } from "element-plus";
|
||||
|
||||
defineOptions({ name: "FaExcelImport" });
|
||||
|
||||
interface Props {
|
||||
/** 接受的文件类型 */
|
||||
accept?: string;
|
||||
/** 按钮文本 */
|
||||
buttonText?: string;
|
||||
/** 加载状态 */
|
||||
loading?: boolean;
|
||||
/** 是否禁用 */
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
accept: ".xlsx, .xls",
|
||||
buttonText: "导入 Excel",
|
||||
loading: false,
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
// Excel 导入工具函数
|
||||
async function importExcel(file: File): Promise<Array<Record<string, unknown>>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -44,10 +63,12 @@ async function importExcel(file: File): Promise<Array<Record<string, unknown>>>
|
||||
}
|
||||
|
||||
// 定义 emits
|
||||
const emit = defineEmits<{
|
||||
interface Emits {
|
||||
"import-success": [data: Array<Record<string, unknown>>];
|
||||
"import-error": [error: Error];
|
||||
}>();
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
// 处理文件导入
|
||||
const handleFileChange = async (uploadFile: UploadFile) => {
|
||||
|
||||
@@ -277,7 +277,7 @@ export interface FormItem {
|
||||
}
|
||||
|
||||
// 表单配置
|
||||
interface FormProps {
|
||||
interface Props {
|
||||
/** 表单数据 */
|
||||
items: FormItem[];
|
||||
/** 每列的宽度(基于 24 格布局) */
|
||||
@@ -319,7 +319,7 @@ interface SanitizeOutputOptions {
|
||||
keepFalse: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<FormProps>(), {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
span: 6,
|
||||
gutter: 12,
|
||||
@@ -334,12 +334,12 @@ const props = withDefaults(defineProps<FormProps>(), {
|
||||
maxHeight: "75vh",
|
||||
});
|
||||
|
||||
interface FormEmits {
|
||||
interface Emits {
|
||||
reset: [];
|
||||
submit: [Record<string, any>];
|
||||
}
|
||||
|
||||
const emit = defineEmits<FormEmits>();
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const modelValue = defineModel<Record<string, any>>({ default: {} });
|
||||
const initialModelValue = ref<Record<string, any>>({});
|
||||
@@ -520,9 +520,20 @@ const getSanitizedOutput = () => {
|
||||
};
|
||||
|
||||
const getProps = (item: FormItem) => {
|
||||
if (item.props) return item.props;
|
||||
const props = { ...item };
|
||||
rootProps.forEach((key) => delete (props as Record<string, any>)[key]);
|
||||
let props: Record<string, any>;
|
||||
if (item.props) {
|
||||
props = { ...item.props };
|
||||
} else {
|
||||
props = { ...item };
|
||||
rootProps.forEach((key) => delete props[key]);
|
||||
}
|
||||
|
||||
// 对于日期选择器组件,确保 type 被传递给 FaDatePicker
|
||||
const datePickerTypes = ["date", "daterange", "datetime", "datetimerange", "monthrange"];
|
||||
if (item.type && datePickerTypes.includes(item.type) && !props.type) {
|
||||
props.type = item.type;
|
||||
}
|
||||
|
||||
return props;
|
||||
};
|
||||
|
||||
|
||||
@@ -31,24 +31,29 @@ type DatePickerType =
|
||||
| "daterange"
|
||||
| "monthrange";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue?: any;
|
||||
type?: DatePickerType;
|
||||
format?: string;
|
||||
rangeSeparator?: string;
|
||||
startPlaceholder?: string;
|
||||
endPlaceholder?: string;
|
||||
}>(),
|
||||
{
|
||||
type: "datetimerange",
|
||||
rangeSeparator: "至",
|
||||
startPlaceholder: "开始日期",
|
||||
endPlaceholder: "结束日期",
|
||||
}
|
||||
);
|
||||
defineOptions({ name: "FaDatePicker" });
|
||||
|
||||
const emit = defineEmits(["update:model-value"]);
|
||||
interface Props {
|
||||
modelValue?: any;
|
||||
type?: DatePickerType;
|
||||
format?: string;
|
||||
rangeSeparator?: string;
|
||||
startPlaceholder?: string;
|
||||
endPlaceholder?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: "datetimerange",
|
||||
rangeSeparator: "至",
|
||||
startPlaceholder: "开始日期",
|
||||
endPlaceholder: "结束日期",
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: "update:model-value", value: any): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
/** 是否为范围选择模式 */
|
||||
const isRangeType = computed(() => {
|
||||
|
||||
@@ -47,22 +47,23 @@ import {
|
||||
|
||||
defineOptions({ name: "FaSearchBarWithAudit", inheritAttrs: false });
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
/** 仅业务条件表单项,不含审计四字段 */
|
||||
items: SearchFormItem[];
|
||||
/** 为 false 时与原生 FaSearchBar 一致,仅使用 `items` */
|
||||
includeAudit?: boolean;
|
||||
/** 传给 getAuditSearchFormItems 的选项 */
|
||||
auditItemOptions?: GetAuditSearchFormItemsOptions;
|
||||
}>(),
|
||||
{ includeAudit: true }
|
||||
);
|
||||
interface Props {
|
||||
/** 仅业务条件表单项,不含审计四字段 */
|
||||
items: SearchFormItem[];
|
||||
/** 为 false 时与原生 FaSearchBar 一致,仅使用 `items` */
|
||||
includeAudit?: boolean;
|
||||
/** 传给 getAuditSearchFormItems 的选项 */
|
||||
auditItemOptions?: GetAuditSearchFormItemsOptions;
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
const props = withDefaults(defineProps<Props>(), { includeAudit: true });
|
||||
|
||||
interface Emits {
|
||||
search: [Record<string, any>];
|
||||
reset: [];
|
||||
}>();
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const modelValue = defineModel<Record<string, any>>({ default: () => ({}) });
|
||||
const attrs = useAttrs();
|
||||
|
||||
@@ -18,14 +18,20 @@
|
||||
import type { ISelectConfig } from "@/components/others/fa-table-select/index.vue";
|
||||
import UserAPI, { UserPageQuery } from "@/api/module_system/user";
|
||||
|
||||
// 父组件双向绑定的值(选中用户ID)
|
||||
const props = defineProps<{ modelValue?: number }>();
|
||||
defineOptions({ name: "FaUserTableSelect" });
|
||||
|
||||
// 事件向上派发,支持父组件监听和 v-model(仅回传选中用户ID)
|
||||
const emit = defineEmits<{
|
||||
interface Props {
|
||||
modelValue?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
|
||||
interface Emits {
|
||||
confirmClick: [data: IUser[]];
|
||||
"update:modelValue": [val: number | undefined];
|
||||
}>();
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const selectConfig: ISelectConfig = {
|
||||
pk: "id",
|
||||
|
||||
@@ -190,7 +190,7 @@ export interface SearchFormItem {
|
||||
}
|
||||
|
||||
// 表单配置
|
||||
interface SearchBarProps {
|
||||
interface Props {
|
||||
/** 表单数据 */
|
||||
items: SearchFormItem[];
|
||||
/** 每列的宽度(基于 24 格布局) */
|
||||
@@ -234,7 +234,7 @@ interface SanitizeOutputOptions {
|
||||
keepFalse: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<SearchBarProps>(), {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
span: 6,
|
||||
gutter: 12,
|
||||
@@ -250,12 +250,12 @@ const props = withDefaults(defineProps<SearchBarProps>(), {
|
||||
sanitizeOutput: () => ({}),
|
||||
});
|
||||
|
||||
interface SearchBarEmits {
|
||||
interface Emits {
|
||||
reset: [];
|
||||
search: [Record<string, any>];
|
||||
}
|
||||
|
||||
const emit = defineEmits<SearchBarEmits>();
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const modelValue = defineModel<Record<string, any>>({ default: {} });
|
||||
const initialModelValue = ref<Record<string, any>>({});
|
||||
|
||||
Reference in New Issue
Block a user