curd组件内置新增编辑

This commit is contained in:
qianlishi
2025-01-10 13:27:46 +08:00
parent c8dfe947e8
commit eeac9008b4
7 changed files with 149 additions and 47 deletions

View File

@@ -3,12 +3,12 @@
* @Author: qianlishi
* @Date: 2024-12-30 18:16:00
* @LastEditors: qianlishi
* @LastEditTime: 2025-01-09 20:16:16
* @LastEditTime: 2025-01-09 22:20:55
-->
<template>
<div class="view-container">
<div v-if="getBindValue.treeOptions" class="view-container-left">
<JsqTree default-expand-all v-bind="getTreeBindValue" :node-props="toClickTree" />
<div v-if="getTreeBindValue" class="view-container-left">
<JsqTree default-expand-all v-bind="getTreeBindValue" :node-props="toClickTree" ref="JsqTreeRef"/>
</div>
<div class="view-container-right">
<JsqSearchForm v-model="formModel" v-bind="getSearchFormOption" @toRestForm='toRestForm' @toQuery="toQuery"/>
@@ -16,14 +16,14 @@
<JsqTable v-bind="getTableOptions" />
</div>
</div>
<JsqDialog ref="dialogRef" v-bind='getDialogRecordingOptions'/>
<JsqDialog ref="dialogRef" v-bind='getDialogRecordingOptions' :api="getApiOptions" @refresh="toQuery"/>
</template>
<script lang="ts" setup>
import { onMounted, ref, unref, useAttrs, computed, watch } from 'vue';
import { basicProps } from './props';
import { CrudActionType, serachFormProps } from './types';
import { deepMerge } from '@/utils';
import { editFormShow, DialogType } from '@/enums/common';
import { DialogType } from '@/enums/common';
import type { TreeOption } from 'naive-ui'
import { useDialog, useMessage } from 'naive-ui'
@@ -34,10 +34,11 @@
import { JsqButtons } from './components/Jsq-buttons'
import JsqDialog from './components/jsq-dialog.vue'
const message = useMessage()
const messages = useMessage()
const dialog = useDialog()
const dialogRef = ref<InstanceType<typeof JsqDialog> | null>(null)
const JsqTreeRef = ref<InstanceType<typeof JsqTree> | null>(null)
const formModel = ref({})
const selectIds = ref<string[]>([])
const selectSections = ref<serachFormProps[]>([])
@@ -88,14 +89,6 @@
return unref(getBindValue).apiOptions
})
const isEditShow = (val: editFormShow | boolean) => {
if(typeof val === 'boolean' || typeof val === 'undefined') {
return !val
}
return Object.values(editFormShow).includes(val)
}
/**
* columns 分开编辑配置,表格配置
* 分页配置
@@ -170,6 +163,8 @@
const toQuery = () => {
loadData()
// 查询左侧树
getTreeBindValue && JsqTreeRef.value?.loadData()
}
const toRestForm = () => {
@@ -177,19 +172,16 @@
treePrams.value = {}
pageNumber.value = 1
pageSize.value = 10
loadData()
toQuery()
}
// 新增
const toAdd = () => {
console.log(getSearchForm())
dialogRef.value?.initModel({ type: DialogType.ADD })
}
// 编辑
const toUpdate = (row) => {
console.log(row)
console.log('编辑')
dialogRef.value?.initModel({type: DialogType.EDIT, row })
}
@@ -201,12 +193,13 @@
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
const { code, message } = await unref(getTableOptions)?.removeApi(selectIds)
const { code, message } = await unref(getApiOptions)?.removeApi(selectIds)
if(code != 200) return
message.success(message)
messages.success(message)
toQuery()
},
onNegativeClick: () => {
message.error('取消成功')
messages.error('取消成功')
}
})
}
@@ -220,12 +213,13 @@
positiveText: '确定',
negativeText: '取消',
onPositiveClick: async () => {
const { code, message } = await unref(getTableOptions)?.removeApi(ids)
const { code, message } = await unref(getApiOptions)?.removeApi(ids)
if(code != 200) return
message.success(message)
messages.success(message)
toQuery()
},
onNegativeClick: () => {
message.error('取消成功')
messages.error('取消成功')
}
})
}

View File

@@ -88,7 +88,7 @@
import { basicProps } from './props';
import { deepMerge } from '@/utils';
import { isFunction } from '@/utils/is';
import { isFunction, isNullOrUnDef } from '@/utils/is';
// 通过props传递的参数
const props = defineProps({ ...basicProps });
@@ -97,6 +97,7 @@
const emit = defineEmits(['register', 'change', 'toRestForm', 'toQuery']);
// 表单对象
const defaultFormModel = ref<any>({});
const formModel = reactive<Recordable>({});
const formElRef = ref<Nullable<FormActionType>>(null);
// useSearchForm传递过来的参数
@@ -156,9 +157,30 @@
formModel.showMoreSearch = !formModel.showMoreSearch;
};
watch(() => getSchema.value, (schema)=> {
if(schema?.length) {
initDefault()
}
})
// 初始化默认值
const initDefault = () => {
const schemas = unref(getSchema)
const obj: Recordable = {}
schemas.forEach(item => {
const { defaultValue } = item.componentProps!
if(!isNullOrUnDef(defaultValue)) {
obj[item.field] = defaultValue
formModel[item.field] = defaultValue
}
})
defaultFormModel.value = obj
}
const toRestForm = () => {
Object.keys(formModel).forEach((key) => {
formModel[key] = null;
formModel[key] = defaultFormModel[key] || null;
});
emit('toRestForm')
}
@@ -169,6 +191,7 @@
};
onMounted(() => {
initDefault()
emit('register', formActionType);
});

View File

@@ -1,19 +1,20 @@
<template>
<basicModal @register="register" >
<basicModal @register="register" @onOk='handleSubmit' @onClose="close">
<n-form
class="form"
v-bind="getBindValue"
size="small"
label-placement="left"
:model="formModel"
ref="formElRef"
>
<div class="search-box">
<div class="search-box-form">
<n-grid :x-gap="12" :y-gap="8" :cols="3">
<n-grid :x-gap="12" :y-gap="8" :cols="2">
<template v-for="(schema, index) in getSchema">
<n-gi >
<n-gi>
<n-form-item
v-if="!isHideForm(schema)"
v-bind="getFormItem(schema)"
:rule="schema.rules"
:label="schema.label"
:path="schema.field"
>
@@ -73,21 +74,30 @@
</basicModal>
</template>
<script lang='ts' setup>
import { useAttrs, computed, reactive, unref } from 'vue'
import { useAttrs, computed, reactive, unref, ref } from 'vue'
import { basicModal, useModal } from '@/components/Modal'
import { DialogType } from '@/enums/common'
import { DialogType, DialogTitle } from '@/enums/common'
import { JsqSelect } from '@/components/Base/Jsq-select';
import { isFunction } from '@/utils/is';
import { useMessage } from 'naive-ui'
import { isFunction, isNullOrUnDef } from '@/utils/is';
interface InitModelProps {
type: DialogType,
row?: Object
}
const messages = useMessage()
const emit = defineEmits(['refresh'])
const attrs = useAttrs()
const defaultFormModel = ref<any>({});
const formModel = reactive<Recordable>({})
console.log('11', attrs)
const dialogType = ref<DialogType>(DialogType.ADD)
const formElRef = ref()
const rowData = ref<object>({})
const getBindValue = computed(() => ({ ...attrs} as Recordable));
@@ -111,23 +121,89 @@
return componentProps;
};
const isHideForm = (schema) => {
const { editHide = '' } = schema
return editHide.includes(dialogType.value)
}
const getSchema = computed(() => {
return unref(getBindValue).schemas
})
const [register, { openModal }] = useModal({
title: '新增'
const setParams = () => {
return formModel
}
const handleSubmit = async () => {
const params = setParams()
const api = dialogType.value == DialogType.ADD ? unref(getBindValue).api.addApi : unref(getBindValue).api.updateApi
const { code, message } = await api(params)
if(code != 200) return
emit('refresh')
messages.success(message)
handleClose()
}
const handleClose = () => {
resetFields()
closeModal()
}
const close = () => {
resetFields()
}
const [register, { openModal, closeModal }] = useModal({
title: DialogTitle[dialogType.value]
})
const initModel = (props: InitModelProps) => {
initDefault()
const { type, row } = props
console.log('type', type)
console.log('row', row)
dialogType.value = type
rowData.value = row || {}
if(dialogType.value !== DialogType.ADD) {
getDetailData(row)
}
openModal()
}
const getDetailData = async (row) => {
const { code, data } = await unref(getBindValue).api.getDataByIdApi(row)
if(code != 200) return
Object.assign(formModel, data)
}
// 初始化默认值
const initDefault = () => {
const schemas = unref(getSchema)
const obj: Recordable = {}
schemas.forEach(item => {
const { defaultValue } = item.componentProps
if(!isNullOrUnDef(defaultValue)) {
obj[item.field] = defaultValue
formModel[item.field] = defaultValue
}
})
defaultFormModel.value = obj
}
// 重置表单
const resetFields = () => {
Object.keys(formModel).forEach(key => {
formModel[key] = unref(defaultFormModel)[key] || null
})
}
defineExpose({
initModel
})
</script>
<style lang='less' scoped></style>
<style lang='less' scoped>
.form {
margin-top: 20px;
}
</style>

View File

@@ -6,7 +6,7 @@ export type JsqTreeProps = {
// 对外暴露的方法
export interface TreeActionType {
setProps: (treeProps: Partial<TreeProps>) => Promise<void>;
loadData: (params: any) => Promise<void>;
loadData: (params?: any) => Promise<void>;
}
export type TreeRegisterFn = (treeInstance: TreeActionType) => void

View File

@@ -15,3 +15,9 @@ export enum DialogType { // 弹框类型
EDIT = 'EDIT',
VIEW = 'VIEW'
}
export enum DialogTitle {
ADD = '新增',
EDIT = '编辑',
VIEW = '查看'
}

View File

@@ -3,7 +3,7 @@
* @Author: qianlishi
* @Date: 2024-12-08 17:38:28
* @LastEditors: qianlishi
* @LastEditTime: 2025-01-09 20:11:15
* @LastEditTime: 2025-01-09 22:22:16
-->
<template>
<div class="view-container">
@@ -39,8 +39,8 @@
const { columns } = getTableColumns({ updateClick, removeSingle })
const [register, { toAdd, toUpdate, toRemoveAll, toRemove }] = useCrud({
treeOptions: getTreeOptions(), // 左侧树
searchFormOption: { // 搜索条件
treeOptions: getTreeOptions(),
searchFormOption: {
schemas: getFormSchemas({}).value,
},
tableButtonsOptions: {
@@ -48,7 +48,10 @@
tableButtons: rowsButtons
},
dialogRecordingData: {
width: 1200,
width: 800,
size: "small",
labelPlacement: "left",
labelWidth: 100,
schemas: getDialogRecordingSchemas()
},
tableOptions: {

View File

@@ -3,7 +3,7 @@
* @Author: qianlishi
* @Date: 2025-01-03 01:01:14
* @LastEditors: qianlishi
* @LastEditTime: 2025-01-09 13:18:33
* @LastEditTime: 2025-01-09 22:26:28
*/
import { computed, h } from 'vue';
import { cloneDeep } from 'lodash-es';
@@ -169,7 +169,7 @@ export const getDialogRecordingSchemas = () => {
dictCode: 'ENABLE_FLAG',
},
rules: [
{ required: true, message: "启用状态必填", trigger: "blur" }
{ required: true, message: "启用状态必填", trigger: ['blur', 'change'] }
],
},
{