feat(dependencies): update asyncmy and pandas versions for improved performance and compatibility

- Upgraded asyncmy from version 0.2.9 to 0.2.11 to leverage enhancements and bug fixes.
- Updated pandas from version 2.2.2 to 2.2.3 for better data processing capabilities.
- Added a new configuration option LOGIN_RESOLVE_IP_LOCATION to control IP location resolution during login.
- Enhanced login service to handle IP location resolution based on the new configuration.
- Improved validation logic in menu request handling to ensure proper redirection address for specific menu types.
- Adjusted CRUD template generation to dynamically use primary key column names for better flexibility.
- Updated Vue components to ensure proper handling of dynamic primary key references in menu items and forms.
This commit is contained in:
zhangtao
2026-03-29 20:33:33 +08:00
parent 25f497a55b
commit 7081850d46
19 changed files with 602 additions and 177 deletions
@@ -111,7 +111,7 @@ class {{ class_name }}CRUD(CRUDBase[{{ class_name }}Model, {{ class_name }}Creat
返回:
- Dict: 分页数据
"""
order_by_list = order_by or [{'id': 'asc'}]
order_by_list = order_by or [{'{{ pk_column_name }}': 'asc'}]
search_dict = search or {}
return await self.page(
offset=offset,
@@ -17,7 +17,7 @@ class {{ class_name }}CreateSchema(BaseModel):
{{ function_name }}新增模型
"""
{% for column in columns %}
{% if column.column_name not in ['id', 'uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] %}
{% if column.column_name not in ['uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] and column.column_name != pk_column_name %}
{% if column.column_name == 'status' %}
{{ column.column_name }}: {{ column.python_type }} = Field(default="0", description='{{ column.column_comment }}')
{% elif column.column_name == 'description' %}
@@ -74,7 +74,7 @@ class {{ class_name }}Service:
- dict - 分页查询结果
"""
search_dict = search.__dict__ if search else {}
order_by_list = order_by or [{'id': 'asc'}]
order_by_list = order_by or [{'{{ pk_column_name }}': 'asc'}]
offset = (page_no - 1) * page_size
result = await {{ class_name }}CRUD(auth).page_{{ business_name }}_crud(
offset=offset,
@@ -128,7 +128,7 @@ class {{ class_name }}Service:
{% for column in columns %}
{% if column.is_unique == '1' %}
exist_obj = await {{ class_name }}CRUD(auth).get({{ column.column_name }}=data.{{ column.column_name }})
if exist_obj and exist_obj.id != id:
if exist_obj and getattr(exist_obj, '{{ pk_column_name }}') != id:
raise CustomException(msg='更新失败,{{ column.column_comment }}重复')
{% endif %}
{% endfor %}
@@ -271,7 +271,7 @@ class {{ class_name }}Service:
exists_obj = await {{ class_name }}CRUD(auth).get({{ column.column_name }}=create_schema.{{ column.column_name }})
if exists_obj:
if update_support:
await {{ class_name }}CRUD(auth).update(id=exists_obj.id, data=create_schema)
await {{ class_name }}CRUD(auth).update(id=getattr(exists_obj, '{{ pk_column_name }}'), data=create_schema)
success_count += 1
else:
error_msgs.append(f"第{count}行: {{ column.column_comment }} {create_schema.{{ column.column_name }}} 已存在")
@@ -110,8 +110,11 @@ export interface {{ class_name }}PageQuery extends PageQuery {
// 列表展示项
export interface {{ class_name }}Table extends BaseType {
{% if pk_column_name != 'id' and pk_column %}
{{ pk_column_name }}?: {{ pk_column.python_type | python_to_ts_type }};
{% endif %}
{% for column in columns %}
{% if column.column_name not in ['id', 'uuid', 'status', 'description', 'created_time', 'updated_time'] %}
{% if column.column_name not in ['id', 'uuid', 'status', 'description', 'created_time', 'updated_time'] and column.column_name != pk_column_name %}
{{ column.column_name }}?: {{ column.python_type | python_to_ts_type }};
{% endif %}
{% endfor %}
@@ -121,8 +124,11 @@ export interface {{ class_name }}Table extends BaseType {
// 新增/修改/详情表单参数
export interface {{ class_name }}Form extends BaseFormType {
{% if pk_column_name != 'id' and pk_column %}
{{ pk_column_name }}?: {{ pk_column.python_type | python_to_ts_type }};
{% endif %}
{% for column in columns %}
{% if (column.is_insert or column.is_edit) and column.column_name not in ['id', 'uuid', 'status', 'description', 'created_time', 'updated_time', 'created_id', 'updated_id'] %}
{% if (column.is_insert or column.is_edit) and column.column_name not in ['uuid', 'status', 'description', 'created_time', 'updated_time', 'created_id', 'updated_id'] and column.column_name != pk_column_name %}
{{ column.column_name }}?: {{ column.python_type | python_to_ts_type }};
{% endif %}
{% endfor %}
@@ -128,7 +128,7 @@
size="small"
link
icon="View"
@click="handleOpenDialog('detail', scope.row.id)"
@click="handleOpenDialog('detail', scope.row['{{ pk_column_name }}'])"
>
详情
</el-button>
@@ -138,7 +138,7 @@
size="small"
link
icon="Edit"
@click="handleOpenDialog('update', scope.row.id)"
@click="handleOpenDialog('update', scope.row['{{ pk_column_name }}'])"
>
编辑
</el-button>
@@ -148,7 +148,7 @@
size="small"
link
icon="Delete"
@click="handleRowDelete(scope.row.id)"
@click="handleRowDelete(scope.row['{{ pk_column_name }}'])"
>
删除
</el-button>
@@ -210,7 +210,7 @@
{% set parentheseIndex = column_comment.find("") %}
{% set comment = column_comment[:parentheseIndex] if parentheseIndex != -1 else column_comment %}
{% set required = 'true' if not column.is_nullable else 'false' %}
{% if column.column_name not in ['id', 'uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] %}
{% if column.column_name not in ['uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] and column.column_name != pk_column_name %}
{% if column.column_name == "status" %}
<el-form-item label="状态" prop="status" :required="true">
<el-radio-group v-model="formData.status">
@@ -321,6 +321,9 @@ import SingleImageUpload from "@/components/Upload/SingleImageUpload.vue";
const { searchRef, contentRef, handleQueryClick, handleResetClick, refreshList } = useCrudList();
/** 数据表主键字段名(与导入表结构一致,避免非 id 主键时操作错行) */
const PK = "{{ pk_column_name }}" as const;
function triggerUserSearch() {
nextTick(() => refreshList());
}
@@ -523,7 +526,7 @@ const detailFormData = ref<{{ class_name }}Table>({});
const formData = reactive<{{ class_name }}Form>({
{% for column in columns %}
{% if column.is_insert or column.is_edit %}
{% if column.column_name not in ['id', 'uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] %}
{% if column.column_name not in ['uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] and column.column_name != pk_column_name %}
{{ column.column_name }}: undefined,
{% endif %}
{% endif %}
@@ -539,7 +542,7 @@ const dialogVisible = reactive({
const rules = reactive({
{% for column in columns %}
{% if column.is_insert or column.is_edit %}
{% if column.column_name not in ['id', 'uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] %}
{% if column.column_name not in ['uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] and column.column_name != pk_column_name %}
{{ column.column_name }}: [{ required: {% if not column.is_nullable %}true{% else %}false{% endif %}, message: "请填写{{ column.column_comment or column.column_name }}", trigger: "blur" }],
{% endif %}
{% endif %}
@@ -568,7 +571,7 @@ function handleRowDelete(id: number) {
const initialFormData: {{ class_name }}Form = {
{% for column in columns %}
{% if column.is_insert or column.is_edit %}
{% if column.column_name not in ['id', 'uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] %}
{% if column.column_name not in ['uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] and column.column_name != pk_column_name %}
{{ column.column_name }}: undefined,
{% endif %}
{% endif %}
@@ -603,7 +606,7 @@ async function handleOpenDialog(type: "create" | "update" | "detail", id?: numbe
dialogVisible.title = "新增{{ function_name }}";
{% for column in columns %}
{% if column.is_insert or column.is_edit %}
{% if column.column_name not in ['id', 'uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] %}
{% if column.column_name not in ['uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] and column.column_name != pk_column_name %}
formData.{{ column.column_name }} = undefined;
{% endif %}
{% endif %}
@@ -616,10 +619,10 @@ async function handleSubmit() {
dataFormRef.value.validate(async (valid: boolean) => {
if (valid) {
const submitData = { ...formData };
const id = formData.id;
const id = formData[PK] as number | undefined;
try {
if (id) {
await {{ class_name }}API.update{{ class_name }}(id, { id, ...submitData });
await {{ class_name }}API.update{{ class_name }}(id, { ...submitData, [PK]: id });
} else {
await {{ class_name }}API.create{{ class_name }}(submitData);
}
@@ -635,7 +638,7 @@ async function handleSubmit() {
async function handleMoreClick(status: string) {
const rows = contentRef.value?.getSelectionData() ?? [];
const ids = rows.map((r: { id?: number }) => r.id).filter(Boolean) as number[];
const ids = rows.map((r: Record<string, number | undefined>) => r[PK]).filter(Boolean) as number[];
if (!ids.length) return;
ElMessageBox.confirm(`确认${status === "0" ? "启用" : "停用"}该项数据?`, "警告", {
confirmButtonText: "确定",
@@ -161,7 +161,11 @@ class Jinja2TemplateUtil:
"parent_list_rel_name": "",
"parent_table_name": "",
"parent_model_class_name": "",
"parent_pk_column_name": "id",
# 数据表实际主键列名(用于生成前端行键等;ModelMixin 仍默认带 id 字段)
"pk_column_name": (gen_table.pk_column.column_name if gen_table.pk_column else None)
or "id",
"parent_pk_column_name": (gen_table.pk_column.column_name if gen_table.pk_column else None)
or "id",
"sub_table_fk_name": "",
}