From 630ec1e774ca3b530abbce69480641d0ff1ed2c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E5=B0=8F=E6=B6=9B?= <1537080775@qq.com>
Date: Fri, 5 Jul 2024 10:24:07 +0800
Subject: [PATCH 1/2] =?UTF-8?q?feat(20240705=5FtableSelector):=20=E8=A1=A8?=
=?UTF-8?q?=E6=A0=BC=E9=80=89=E6=8B=A9=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 增加树形结构懒加载
---
web/src/components/tableSelector/index.vue | 298 +++++++++++----------
1 file changed, 153 insertions(+), 145 deletions(-)
diff --git a/web/src/components/tableSelector/index.vue b/web/src/components/tableSelector/index.vue
index 7ad3cad84a..ab6ca7d046 100644
--- a/web/src/components/tableSelector/index.vue
+++ b/web/src/components/tableSelector/index.vue
@@ -1,203 +1,211 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--
Gitee
From 6d587fc1e2761790c515553650f55eb5b29cfe3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E5=B0=8F=E6=B6=9B?= <1537080775@qq.com>
Date: Fri, 5 Jul 2024 17:24:36 +0800
Subject: [PATCH 2/2] =?UTF-8?q?feat(20240705=5Farea):=20=E5=9C=B0=E5=8C=BA?=
=?UTF-8?q?=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 优化地区管理:增删改查
- 优化tableSelect组件:增加树形结构和懒加载
---
backend/dvadmin/system/views/area.py | 50 ++-
web/src/components/tableSelector/index.vue | 4 +-
web/src/utils/columnPermission.ts | 1 -
web/src/views/system/areas/crud.tsx | 436 ++++++++++-----------
4 files changed, 237 insertions(+), 254 deletions(-)
diff --git a/backend/dvadmin/system/views/area.py b/backend/dvadmin/system/views/area.py
index 3a727282f9..7a19eb076c 100644
--- a/backend/dvadmin/system/views/area.py
+++ b/backend/dvadmin/system/views/area.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+import pypinyin
from django.db.models import Q
from rest_framework import serializers
@@ -15,6 +16,11 @@ class AreaSerializer(CustomModelSerializer):
"""
pcode_count = serializers.SerializerMethodField(read_only=True)
hasChild = serializers.SerializerMethodField()
+ pcode_info = serializers.SerializerMethodField()
+
+ def get_pcode_info(self, instance):
+ pcode = Area.objects.filter(code=instance.pcode_id).values("name", "code")
+ return pcode
def get_pcode_count(self, instance: Area):
return Area.objects.filter(pcode=instance).count()
@@ -36,6 +42,18 @@ class AreaCreateUpdateSerializer(CustomModelSerializer):
地区管理 创建/更新时的列化器
"""
+ def to_internal_value(self, data):
+ pinyin = ''.join([''.join(i) for i in pypinyin.pinyin(data["name"], style=pypinyin.NORMAL)])
+ data["level"] = 1
+ data["pinyin"] = pinyin
+ data["initials"] = pinyin[0].upper() if pinyin else "#"
+ pcode = data["pcode"] if 'pcode' in data else None
+ if pcode:
+ pcode = Area.objects.get(pk=pcode)
+ data["pcode"] = pcode.code
+ data["level"] = pcode.level + 1
+ return super().to_internal_value(data)
+
class Meta:
model = Area
fields = '__all__'
@@ -52,20 +70,28 @@ class AreaViewSet(CustomModelViewSet, FieldPermissionMixin):
"""
queryset = Area.objects.all()
serializer_class = AreaSerializer
+ create_serializer_class = AreaCreateUpdateSerializer
+ update_serializer_class = AreaCreateUpdateSerializer
extra_filter_class = []
- def get_queryset(self):
+ def list(self, request, *args, **kwargs):
self.request.query_params._mutable = True
params = self.request.query_params
- pcode = params.get('pcode', None)
- page = params.get('page', None)
- limit = params.get('limit', None)
- if page:
- del params['page']
- if limit:
- del params['limit']
- if params and pcode:
- queryset = self.queryset.filter(enable=True, pcode=pcode)
- else:
+ known_params = {'page', 'limit', 'pcode'}
+ # 使用集合操作检查是否有未知参数
+ other_params_exist = any(param not in known_params for param in params)
+ if other_params_exist:
queryset = self.queryset.filter(enable=True)
- return queryset
+ else:
+ pcode = params.get('pcode', None)
+ params['limit'] = 999
+ if params and pcode:
+ queryset = self.queryset.filter(enable=True, pcode=pcode)
+ else:
+ queryset = self.queryset.filter(enable=True, level=1)
+ page = self.paginate_queryset(queryset)
+ if page is not None:
+ serializer = self.get_serializer(page, many=True, request=request)
+ return self.get_paginated_response(serializer.data)
+ serializer = self.get_serializer(queryset, many=True, request=request)
+ return SuccessResponse(data=serializer.data, msg="获取成功")
diff --git a/web/src/components/tableSelector/index.vue b/web/src/components/tableSelector/index.vue
index ab6ca7d046..8e8c91a9dc 100644
--- a/web/src/components/tableSelector/index.vue
+++ b/web/src/components/tableSelector/index.vue
@@ -2,7 +2,7 @@
{
const handleCurrentChange = (val: any) => {
const { tableConfig } = props;
if (!tableConfig.isMultiple && val) {
- data.value = val[tableConfig.label];
+ data.value = [val[tableConfig.label]];
emit('update:modelValue', val[tableConfig.value]);
}
};
diff --git a/web/src/utils/columnPermission.ts b/web/src/utils/columnPermission.ts
index aff14412b3..7ef06de0ba 100644
--- a/web/src/utils/columnPermission.ts
+++ b/web/src/utils/columnPermission.ts
@@ -28,7 +28,6 @@ export const handleColumnPermission = async (func: Function, crudOptions: any,ex
if (excludeColumns.includes(item.field_name)) {
continue
} else if(item.field_name === col) {
- columns[col].column.show = item['is_query']
// 如果列表不可见,则禁止在列设置中选择
// 只有列表不可见,才修改列配置,这样才不影响默认的配置
if(!item['is_query']){
diff --git a/web/src/views/system/areas/crud.tsx b/web/src/views/system/areas/crud.tsx
index 01d1860253..1a1e47b0c4 100644
--- a/web/src/views/system/areas/crud.tsx
+++ b/web/src/views/system/areas/crud.tsx
@@ -1,244 +1,202 @@
import * as api from './api';
-import {
- dict,
- UserPageQuery,
- AddReq,
- DelReq,
- EditReq,
- compute,
- CreateCrudOptionsProps,
- CreateCrudOptionsRet
-} from '@fast-crud/fast-crud';
-import {dictionary} from '/@/utils/dictionary';
-import {successMessage} from '/@/utils/message';
-import {auth} from "/@/utils/authFunction";
+import { dict, UserPageQuery, AddReq, DelReq, EditReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet } from '@fast-crud/fast-crud';
+import { dictionary } from '/@/utils/dictionary';
+import { successMessage } from '/@/utils/message';
+import { auth } from '/@/utils/authFunction';
+import tableSelector from '/@/components/tableSelector/index.vue';
+import { shallowRef } from 'vue';
-export const createCrudOptions = function ({crudExpose}: CreateCrudOptionsProps): CreateCrudOptionsRet {
- const pageRequest = async (query: UserPageQuery) => {
- return await api.GetList(query);
- };
- const editRequest = async ({form, row}: EditReq) => {
- form.id = row.id;
- return await api.UpdateObj(form);
- };
- const delRequest = async ({row}: DelReq) => {
- return await api.DelObj(row.id);
- };
- const addRequest = async ({form}: AddReq) => {
- return await api.AddObj(form);
- };
+export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
+ const pageRequest = async (query: UserPageQuery) => {
+ return await api.GetList(query);
+ };
+ const editRequest = async ({ form, row }: EditReq) => {
+ form.id = row.id;
+ return await api.UpdateObj(form);
+ };
+ const delRequest = async ({ row }: DelReq) => {
+ return await api.DelObj(row.id);
+ };
+ const addRequest = async ({ form }: AddReq) => {
+ return await api.AddObj(form);
+ };
- /**
- * 懒加载
- * @param row
- * @returns {Promise}
- */
- const loadContentMethod = (tree: any, treeNode: any, resolve: Function) => {
- pageRequest({pcode: tree.code}).then((res: APIResponseData) => {
- resolve(res.data);
- });
- };
+ /**
+ * 懒加载
+ * @param row
+ * @returns {Promise}
+ */
+ const loadContentMethod = (tree: any, treeNode: any, resolve: Function) => {
+ pageRequest({ pcode: tree.code }).then((res: APIResponseData) => {
+ resolve(res.data);
+ });
+ };
- return {
- crudOptions: {
- request: {
- pageRequest,
- addRequest,
- editRequest,
- delRequest,
- },
- actionbar: {
- buttons: {
- add: {
- show: auth('area:Create'),
- }
- }
- },
- rowHandle: {
- //固定右侧
- fixed: 'right',
- width: 200,
- buttons: {
- view: {
- show: false,
- },
- edit: {
- iconRight: 'Edit',
- type: 'text',
- show: auth('area:Update')
- },
- remove: {
- iconRight: 'Delete',
- type: 'text',
- show: auth('area:Delete')
- },
- },
- },
- pagination: {
- show: false,
- },
- table: {
- rowKey: 'id',
- lazy: true,
- load: loadContentMethod,
- treeProps: {children: 'children', hasChildren: 'hasChild'},
- },
- columns: {
- _index: {
- title: '序号',
- form: {show: false},
- column: {
- type: 'index',
- align: 'center',
- width: '70px',
- columnSetDisabled: true, //禁止在列设置中选择
- },
- },
- // pcode: {
- // title: '父级地区',
- // show: false,
- // search: {
- // show: true,
- // },
- // type: 'dict-tree',
- // form: {
- // component: {
- // showAllLevels: false, // 仅显示最后一级
- // props: {
- // elProps: {
- // clearable: true,
- // showAllLevels: false, // 仅显示最后一级
- // props: {
- // checkStrictly: true, // 可以不需要选到最后一级
- // emitPath: false,
- // clearable: true,
- // },
- // },
- // },
- // },
- // },
- // },
- name: {
- title: '名称',
- search: {
- show: true,
- },
- treeNode: true,
- type: 'input',
- column: {
- minWidth: 120,
- },
- form: {
- rules: [
- // 表单校验规则
- {required: true, message: '名称必填项'},
- ],
- component: {
- placeholder: '请输入名称',
- },
- },
- },
- code: {
- title: '地区编码',
- search: {
- show: true,
- },
- type: 'input',
- column: {
- minWidth: 90,
- },
- form: {
- rules: [
- // 表单校验规则
- {required: true, message: '地区编码必填项'},
- ],
- component: {
- placeholder: '请输入地区编码',
- },
- },
- },
- pinyin: {
- title: '拼音',
- search: {
- disabled: true,
- },
- type: 'input',
- column: {
- minWidth: 120,
- },
- form: {
- rules: [
- // 表单校验规则
- {required: true, message: '拼音必填项'},
- ],
- component: {
- placeholder: '请输入拼音',
- },
- },
- },
- level: {
- title: '地区层级',
- search: {
- disabled: true,
- },
- type: 'input',
- column: {
- minWidth: 100,
- },
- form: {
- disabled: false,
- rules: [
- // 表单校验规则
- {required: true, message: '拼音必填项'},
- ],
- component: {
- placeholder: '请输入拼音',
- },
- },
- },
- initials: {
- title: '首字母',
- column: {
- minWidth: 100,
- },
- form: {
- rules: [
- // 表单校验规则
- {required: true, message: '首字母必填项'},
- ],
-
- component: {
- placeholder: '请输入首字母',
- },
- },
- },
- enable: {
- title: '是否启用',
- search: {
- show: true,
- },
- type: 'dict-radio',
- column: {
- minWidth: 90,
- component: {
- name: 'fs-dict-switch',
- activeText: '',
- inactiveText: '',
- style: '--el-switch-on-color: var(--el-color-primary); --el-switch-off-color: #dcdfe6',
- onChange: compute((context) => {
- return () => {
- api.UpdateObj(context.row).then((res: APIResponseData) => {
- successMessage(res.msg as string);
- });
- };
- }),
- },
- },
- dict: dict({
- data: dictionary('button_status_bool'),
- }),
- },
- },
- },
- };
+ return {
+ crudOptions: {
+ request: {
+ pageRequest,
+ addRequest,
+ editRequest,
+ delRequest,
+ },
+ actionbar: {
+ buttons: {
+ add: {
+ show: auth('area:Create'),
+ },
+ },
+ },
+ rowHandle: {
+ //固定右侧
+ fixed: 'right',
+ width: 200,
+ buttons: {
+ view: {
+ show: false,
+ },
+ edit: {
+ iconRight: 'Edit',
+ type: 'text',
+ show: auth('area:Update'),
+ },
+ remove: {
+ iconRight: 'Delete',
+ type: 'text',
+ show: auth('area:Delete'),
+ },
+ },
+ },
+ pagination: {
+ show: false,
+ },
+ table: {
+ rowKey: 'id',
+ lazy: true,
+ load: loadContentMethod,
+ treeProps: { children: 'children', hasChildren: 'hasChild' },
+ },
+ columns: {
+ _index: {
+ title: '序号',
+ form: { show: false },
+ column: {
+ type: 'index',
+ align: 'center',
+ width: '70px',
+ columnSetDisabled: true, //禁止在列设置中选择
+ },
+ },
+ name: {
+ title: '名称',
+ search: {
+ show: true,
+ },
+ treeNode: true,
+ type: 'input',
+ column: {
+ minWidth: 120,
+ },
+ form: {
+ rules: [
+ // 表单校验规则
+ { required: true, message: '名称必填项' },
+ ],
+ component: {
+ placeholder: '请输入名称',
+ },
+ },
+ },
+ pcode: {
+ title: '父级地区',
+ search: {
+ disabled: true,
+ },
+ width: 130,
+ type: 'table-selector',
+ form: {
+ component: {
+ name: shallowRef(tableSelector),
+ vModel: 'modelValue',
+ displayLabel: compute(({ row }) => {
+ if (row) {
+ return row.pcode_info;
+ }
+ return null;
+ }),
+ tableConfig: {
+ url: '/api/system/area/',
+ label: 'name',
+ value: 'id',
+ isTree: true,
+ isMultiple: false,
+ lazy: true,
+ load: loadContentMethod,
+ treeProps: { children: 'children', hasChildren: 'hasChild' },
+ columns: [
+ {
+ prop: 'name',
+ label: '地区',
+ width: 150,
+ },
+ {
+ prop: 'code',
+ label: '地区编码',
+ },
+ ],
+ },
+ },
+ },
+ column: {
+ show: false,
+ },
+ },
+ code: {
+ title: '地区编码',
+ search: {
+ show: true,
+ },
+ type: 'input',
+ column: {
+ minWidth: 90,
+ },
+ form: {
+ rules: [
+ // 表单校验规则
+ { required: true, message: '地区编码必填项' },
+ ],
+ component: {
+ placeholder: '请输入地区编码',
+ },
+ },
+ },
+ enable: {
+ title: '是否启用',
+ search: {
+ show: true,
+ },
+ type: 'dict-radio',
+ column: {
+ minWidth: 90,
+ component: {
+ name: 'fs-dict-switch',
+ activeText: '',
+ inactiveText: '',
+ style: '--el-switch-on-color: var(--el-color-primary); --el-switch-off-color: #dcdfe6',
+ onChange: compute((context) => {
+ return () => {
+ api.UpdateObj(context.row).then((res: APIResponseData) => {
+ successMessage(res.msg as string);
+ });
+ };
+ }),
+ },
+ },
+ dict: dict({
+ data: dictionary('button_status_bool'),
+ }),
+ },
+ },
+ },
+ };
};
--
Gitee