feat: 添加新功能

This commit is contained in:
陈益 2025-08-18 22:55:58 +08:00
parent 87ef39f072
commit 4e83383d07
25 changed files with 14 additions and 3789 deletions

View File

@ -1,3 +1,9 @@
/*
* @Description:
* @Author:
* @Date: 2025-06-19 22:14:51
* @LastEditors:
*/
import type { RouteRecordRaw } from 'vue-router'; import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts'; import { BasicLayout } from '#/layouts';
@ -14,68 +20,7 @@ const routes: RouteRecordRaw[] = [
}, },
name: 'code', name: 'code',
path: '/code', path: '/code',
children: [ children: [],
{
name: 'project',
path: 'project',
component: () => import('#/views/code/project/index.vue'),
meta: {
icon: 'ant-design:profile-outlined',
title: $t('abp.menu.code-project'),
authority: ['AbpCodeManagement.Project'],
},
},
{
name: 'template',
path: 'template',
component: () => import('#/views/code/template/index.vue'),
meta: {
icon: 'ant-design:file-markdown-filled',
title: $t('abp.menu.code-template'),
authority: ['AbpCodeManagement.Template'],
},
},
{
name: 'generate',
path: 'generate',
component: () => import('#/views/code/generate/index.vue'),
meta: {
icon: 'ant-design:copyright-circle-filled',
title: $t('abp.menu.code-genarate'),
authority: ['AbpCodeManagement.Generator'],
},
},
{
name: 'EntityModel',
path: 'entityModel',
component: () => import('#/views/code/project/entityModel/index.vue'),
meta: {
icon: 'ant-design:file-markdown-filled',
title: $t('abp.menu.code-entity'),
hideInMenu: true,
},
},
{
name: 'TemplateDetail',
path: 'templateDetail',
component: () => import('#/views/code/template/TemplateDetail.vue'),
meta: {
icon: 'ant-design:file-markdown-filled',
title: $t('abp.menu.code-template-detail'),
hideInMenu: true,
},
},
{
name: 'preview',
path: 'Preview',
component: () => import('#/views/code/generate/preview.vue'),
meta: {
icon: 'ant-design:file-markdown-filled',
title: $t('abp.menu.code-Preview'),
hideInMenu: true,
},
},
],
}, },
]; ];

View File

@ -1,3 +1,9 @@
/*
* @Description:
* @Author:
* @Date: 2025-06-19 22:14:51
* @LastEditors:
*/
import type { RouteRecordRaw } from 'vue-router'; import type { RouteRecordRaw } from 'vue-router';
import { BasicLayout } from '#/layouts'; import { BasicLayout } from '#/layouts';
@ -14,18 +20,7 @@ const routes: RouteRecordRaw[] = [
}, },
name: 'TextTemplate', name: 'TextTemplate',
path: '/TextTemplate', path: '/TextTemplate',
children: [ children: [],
{
path: 'page',
name: 'TextTemplatePage',
component: () => import('#/views/textTemplate/index.vue'),
meta: {
icon: 'ant-design:file-markdown-filled',
title: $t('textTemplate.templateList'),
authority: ['AbpTemplateManagement.Template'],
},
},
],
}, },
]; ];

View File

@ -1,132 +0,0 @@
<script lang="ts" setup>
import { onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import { Card, message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
// postGeneratorDown,
// postProjectsAll,
// postTemplatesAll,
} from '#/api-client/index';
import { $t } from '#/locales';
const router = useRouter();
const [BaseForm, baseFormApi] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
//
handleSubmit: onSubmit,
submitButtonOptions: {
content: $t('code.download'),
},
handleReset: onPreview,
resetButtonOptions: {
content: $t('code.preview'),
},
wrapperClass: 'grid-cols-1',
layout: 'horizontal',
schema: [
{
component: 'Select',
componentProps: {
allowClear: true,
filterOption: true,
options: [],
showSearch: true,
},
fieldName: 'projectId',
label: $t('code.project'),
rules: 'required',
},
{
component: 'Select',
componentProps: {
allowClear: true,
filterOption: true,
options: [],
showSearch: true,
},
fieldName: 'templateId',
label: $t('code.template'),
rules: 'required',
},
],
});
onMounted(async () => {
// const res = await postProjectsAll();
// baseFormApi.updateSchema([
// {
// componentProps: {
// options: res?.data?.map((item) => ({
// label: item.projectName,
// value: item.id,
// })),
// },
// fieldName: 'projectId',
// },
// ]);
// const res2 = await postTemplatesAll();
// baseFormApi.updateSchema([
// {
// componentProps: {
// options: res2?.data?.map((item) => ({
// label: item.name,
// value: item.id,
// })),
// },
// fieldName: 'templateId',
// },
// ]);
});
async function onSubmit() {
try {
baseFormApi.setState({ submitButtonOptions: { loading: true } });
const formValues = await baseFormApi.getValues();
// const { data } = await postGeneratorDown({
// body: { ...formValues },
// responseType: 'blob',
// });
// const url = window.URL.createObjectURL(new Blob([data as Blob]));
// const link = document.createElement('a');
// link.href = url;
message.success('功能暂时不可用');
} catch (error) {
message.error('操作失败');
} finally {
baseFormApi.setState({ submitButtonOptions: { loading: false } });
}
}
async function onPreview() {
baseFormApi.setState({ resetButtonOptions: { loading: true } });
const formValues = await baseFormApi.getValues();
router.push({
name: 'preview',
query: {
templateId: formValues.templateId,
projectId: formValues.projectId,
},
});
}
</script>
<template>
<Page
:description="$t('code.description')"
:title="$t('code.autoGenerate')"
content-class="flex flex-col gap-4"
>
<Card title="">
<BaseForm />
</Card>
</Page>
</template>

View File

@ -1,186 +0,0 @@
<script setup lang="ts">
import type { DataNode, TreeProps } from 'ant-design-vue/es/tree';
import { onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { $t } from '@vben/locales';
import { Button, Dropdown, Input, Menu, Spin, Tree } from 'ant-design-vue';
import { postGeneratorPreViewCode } from '#/api-client/index';
//
const expandedKeys = ref<(number | string)[]>([]);
//
const searchValue = ref<string>('');
//
const autoExpandParent = ref<boolean>(true);
//
const gData = ref<Array<DataNode>>([]);
// key
const currentSelectedKey = ref('');
const codeText = ref();
const route = useRoute();
const loading = ref<boolean>(true);
onMounted(() => {
getTreeData().then(() => {
loading.value = false;
});
});
const dataList = ref<DataNode[]>([]);
const generateList = (data: TreeProps['treeData']) => {
if (!data) return;
for (const node of data) {
const { key, title, children } = node;
dataList.value.push({ key, title });
if (children) {
generateList(children);
}
}
};
const getParentKey = (
key: number | string,
tree: TreeProps['treeData'],
): number | string | undefined => {
if (!tree) return undefined;
let parentKey;
for (const node of tree) {
if (node.children) {
if (node.children.some((item) => item.key === key)) {
parentKey = node.key;
} else if (getParentKey(key, node.children)) {
parentKey = getParentKey(key, node.children);
}
}
}
return parentKey;
};
// key
const getAllKeys = (tree: TreeProps['treeData']): (number | string)[] => {
const keys: (number | string)[] = [];
const traverse = (nodes: TreeProps['treeData']) => {
if (!nodes) return;
nodes.forEach((node) => {
if (node.key) {
keys.push(node.key);
}
if (node.children) {
traverse(node.children);
}
});
};
traverse(tree);
return keys;
};
//
const expandAll = () => {
expandedKeys.value = getAllKeys(gData.value as TreeProps['treeData']);
autoExpandParent.value = true;
};
//
const collapseAll = () => {
expandedKeys.value = [];
autoExpandParent.value = true;
};
// onExpand /
const onExpand = (keys: (number | string)[], info: any) => {
expandedKeys.value = keys;
autoExpandParent.value = false;
};
//
const showSaveContentBtn = ref<boolean>(false);
const onSelect = (keys: any[], event: any) => {
codeText.value = '';
showSaveContentBtn.value = false;
if (event.node.templateType === 10) return;
showSaveContentBtn.value = true;
currentSelectedKey.value = keys[0] ?? '';
codeText.value = event.node.content || '';
if (!keys[0]) return '';
};
async function getTreeData() {
const { data = [] } = await postGeneratorPreViewCode({
body: {
templateId: route.query.templateId as string,
projectId: route.query.projectId as string,
},
});
gData.value = data as DataNode[];
dataList.value = [];
generateList(data as TreeProps['treeData']);
}
watch(searchValue, (value) => {
if (!value) {
expandedKeys.value = [];
return;
}
const expanded = dataList.value
.map((item) => {
if (
typeof item.title === 'string' &&
item.title.toLowerCase().includes(value.toLowerCase())
) {
return getParentKey(item.key, gData.value as TreeProps['treeData']);
}
return null;
})
.filter(
(item, i, self): item is number | string =>
item !== null && item !== undefined && self.indexOf(item) === i,
);
expandedKeys.value = expanded;
autoExpandParent.value = true;
});
</script>
<template>
<Spin :spinning="loading" tip="loading...">
<div class="m-4 grid min-h-[calc(100vh-120px)] grid-cols-12 gap-4">
<div class="bg-card col-span-4 xl:col-span-3">
<div class="bg-card flex items-center justify-between p-3">
<Input.Search v-model:value="searchValue" class="ml-1 flex-1" />
<Dropdown class="ml-1">
<Button class="font-bold">......</Button>
<template #overlay>
<Menu>
<Menu.Item @click="expandAll">
{{ $t('common.expandAll') }}
</Menu.Item>
<Menu.Item @click="collapseAll">
{{ $t('common.collapseAll') }}
</Menu.Item>
</Menu>
</template>
</Dropdown>
</div>
<Tree
:auto-expand-parent="autoExpandParent"
:block-node="true"
:expanded-keys="expandedKeys"
:tree-data="gData"
class="mt-3"
@expand="onExpand"
@select="onSelect"
/>
</div>
<div class="bg-card col-span-8 xl:col-span-9">
<div class="bg-card">
<Codemirror v-model:value="codeText" />
</div>
</div>
</div>
</Spin>
</template>
<style scoped></style>

View File

@ -1,54 +0,0 @@
<script lang="ts" setup>
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
// import { postProjectsCreate } from '#/api-client/index';
import { $t } from '#/locales';
import { addFormSchema } from './schema';
const emit = defineEmits(['reload']);
const [Form, formApi] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
showDefaultActions: false,
// labelinputvertical
// labelinput
layout: 'horizontal',
schema: addFormSchema.value,
wrapperClass: 'grid-cols-1',
});
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) return;
try {
modalApi.setState({ loading: true, confirmLoading: true });
//
const values = await formApi.getValues();
//
// await postProjectsCreate({ body: { ...values } });
message.success($t('common.addSuccess'));
emit('reload');
modalApi.close();
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal :title="$t('common.add')">
<Form />
</Modal>
</template>

View File

@ -1,63 +0,0 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
// import { postProjectsUpdate } from '#/api-client/index';
import { $t } from '#/locales';
import { editFormSchema } from './schema';
const emit = defineEmits(['reload']);
const data = ref<any>({});
const [Form, formApi] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
showDefaultActions: false,
// labelinputvertical
// labelinput
layout: 'horizontal',
schema: editFormSchema.value,
wrapperClass: 'grid-cols-1',
});
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) return;
try {
modalApi.setState({ loading: true, confirmLoading: true });
//
const values = await formApi.getValues();
//
// await postProjectsUpdate({ body: { ...values } });
message.success($t('common.editSuccess'));
emit('reload');
modalApi.close();
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
onOpenChange(isOpen: boolean) {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
formApi.setValues(data.value.row);
}
},
});
</script>
<template>
<Modal :title="$t('common.edit')">
<Form />
</Modal>
</template>

View File

@ -1,74 +0,0 @@
<script lang="ts" setup>
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { postEntityModelsCreateAggregate } from '#/api-client/index';
import { $t } from '#/locales';
const props = defineProps({
projectId: {
type: String,
required: true,
},
});
const emit = defineEmits(['getTreeData']);
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
showDefaultActions: false,
layout: 'horizontal',
schema: [
{
component: 'Input',
componentProps: {
placeholder: $t('common.pleaseInput'),
},
fieldName: 'code',
label: $t('code.code'),
rules: 'required',
},
{
component: 'Textarea',
componentProps: {
placeholder: $t('common.pleaseInput'),
},
fieldName: 'description',
label: $t('common.description'),
rules: 'required',
},
],
wrapperClass: 'grid-cols-1',
});
const [Modal, modalApi] = useVbenModal({
onConfirm: async () => {
try {
modalApi.setState({ loading: true, confirmLoading: true });
const { valid } = await formApi.validate();
if (!valid) return;
const values = await formApi.getValues();
await postEntityModelsCreateAggregate({
body: {
code: values.code,
description: values.description,
projectId: props.projectId,
},
});
message.success($t('common.addSuccess'));
emit('getTreeData');
modalApi.close();
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal :title="$t('common.add')">
<Form />
</Modal>
</template>

View File

@ -1,153 +0,0 @@
<!--新增编辑实体Modal-->
<script lang="ts" setup>
import type {
CreateEntityModelInput,
UpdateEntityModelInput,
} from '#/api-client/index';
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
postEntityModelsCreateEntityModel,
postEntityModelsUpdateEntityModel,
} from '#/api-client/index';
import { $t } from '#/locales';
const emit = defineEmits(['getTreeData']);
const data = ref<Record<string, any>>({});
const [AddForm, addFormApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
// #/adapter.ts
component: 'Input',
fieldName: 'code',
label: $t('code.code'),
rules: 'required',
},
{
component: 'Textarea',
fieldName: 'description',
label: $t('code.desc'),
rules: 'required',
},
{
component: 'Select',
fieldName: 'relationalType',
label: $t('code.relational'),
rules: 'required',
componentProps: {
options: [
{ label: '一对一', value: '10' },
{ label: '一对多', value: '20' },
],
},
},
],
wrapperClass: 'grid-cols-1',
showDefaultActions: false,
});
const [EditForm, editFormApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
component: 'Input',
fieldName: 'code',
label: $t('code.code'),
rules: 'required',
},
{
component: 'Textarea',
fieldName: 'description',
label: $t('code.desc'),
rules: 'required',
},
{
component: 'Select',
fieldName: 'relationalType',
label: $t('code.relational'),
rules: 'required',
componentProps: {
options: [
{ label: '一对一', value: '10' },
{ label: '一对多', value: '20' },
],
},
dependencies: {
triggerFields: ['relationalType'],
if: () => !data.value.isRoot,
},
},
],
wrapperClass: 'grid-cols-1',
showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
onOpenChange: (isOpen: boolean) => {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
if (data.value.isEdit) {
const { row } = data.value;
editFormApi.setValues({
...row,
relationalType: String(row.relationalType),
});
}
}
},
onConfirm: async () => {
try {
modalApi.setState({ loading: true, confirmLoading: true });
if (data.value.isEdit) {
const { valid } = await editFormApi.validate();
if (!valid) return;
const editFormValues = await editFormApi.getValues();
const params = {
...editFormValues,
id: data.value.id,
} as UpdateEntityModelInput;
data.value.isRoot && delete params.relationalType;
await postEntityModelsUpdateEntityModel({
body: params,
});
} else {
const { valid } = await addFormApi.validate();
if (!valid) return;
const addFormValues = await addFormApi.getValues();
await postEntityModelsCreateEntityModel({
body: {
...addFormValues,
id: data.value.id,
} as CreateEntityModelInput,
});
message.success($t('common.addSuccess'));
}
modalApi.close();
emit('getTreeData');
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal :title="data.isEdit ? $t('common.edit') : $t('common.add')">
<component :is="data.isEdit ? EditForm : AddForm" />
</Modal>
</template>

View File

@ -1,190 +0,0 @@
<script lang="ts" setup>
import type {
CreateEntityModelPropertyInput,
UpdateEntityModelPropertyInput,
} from '#/api-client/index';
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
postDataTypesList,
postEntityModelsCreateEntityModelProperty,
postEntityModelsUpdateEntityModelProperty,
} from '#/api-client/index';
import { $t } from '#/locales';
const emit = defineEmits(['reload']);
const data = ref<Record<string, any>>({});
const dataTypeList = ref<any[]>();
const currentDataType = ref<string>();
const specialTypeList = new Set(['decimal', 'float']);
//
async function getOptions() {
const { data: List } = await postDataTypesList({
body: { entityModelId: data.value.entityModelId },
});
dataTypeList.value = List;
return List;
}
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
component: 'Input',
fieldName: 'code',
label: $t('code.code'),
rules: 'required',
formItemClass: 'col-span-2',
},
{
component: 'Textarea',
fieldName: 'description',
label: $t('code.desc'),
rules: 'required',
formItemClass: 'col-span-2',
},
{
component: 'Select',
fieldName: 'dataTypeId',
label: $t('code.dataType'),
formItemClass: 'col-span-2',
componentProps: () => ({
options: dataTypeList.value,
'field-names': { label: 'description', value: 'id' },
onChange: (_value: any, data: Record<string, any>) => {
currentDataType.value = data.code;
},
}),
},
{
component: 'Switch',
fieldName: 'isRequired',
label: $t('code.isRequired'),
defaultValue: true,
formItemClass: 'col-span-1',
componentProps: {
class: 'max-w-xs',
},
},
{
component: 'InputNumber',
fieldName: 'maxLength',
label: $t('code.maxLength'),
rules: 'required',
defaultValue: 128,
dependencies: {
triggerFields: ['dataTypeId'],
if: () => currentDataType.value === 'string',
},
formItemClass: 'col-span-1',
},
{
component: 'InputNumber',
fieldName: 'minLength',
label: $t('code.minLength'),
defaultValue: 0,
dependencies: {
triggerFields: ['dataTypeId'],
if: () => currentDataType.value === 'string',
},
componentProps: {
min: 0,
},
formItemClass: 'col-span-1',
},
{
component: 'InputNumber',
fieldName: 'decimalPrecision',
label: $t('code.decimalPrecision18'),
componentProps: {
max: 18,
},
dependencies: {
triggerFields: ['dataTypeId'],
if: () => specialTypeList.has(currentDataType.value as string),
},
formItemClass: 'col-span-1',
},
{
component: 'InputNumber',
fieldName: 'decimalScale',
label: $t('code.decimalPrecision6'),
dependencies: {
triggerFields: ['dataTypeId'],
if: () => specialTypeList.has(currentDataType.value as string),
},
componentProps: {
max: 18,
},
formItemClass: 'col-span-1',
},
],
wrapperClass: 'grid-cols-2',
showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
onOpenChange: async (isOpen: boolean) => {
if (isOpen) {
try {
modalApi.setState({ loading: true });
data.value = modalApi.getData<Record<string, any>>();
await getOptions();
if (data.value.isEdit) {
formApi.setValues({ ...data.value.row });
currentDataType.value = data.value.row.dataTypeCode;
}
} finally {
modalApi.setState({ loading: false });
}
}
},
onConfirm: async () => {
try {
modalApi.setState({ loading: true, confirmLoading: true });
const { valid } = await formApi.validate();
if (!valid) return;
const addFormValues = await formApi.getValues();
await (data.value.isEdit
? postEntityModelsUpdateEntityModelProperty({
body: {
...addFormValues,
id: data.value.entityModelId,
propertyId: data.value.row.id,
enumTypeId: addFormValues.dataTypeId,
} as UpdateEntityModelPropertyInput,
})
: postEntityModelsCreateEntityModelProperty({
body: {
...addFormValues,
id: data.value.entityModelId,
enumTypeId: addFormValues.dataTypeId,
} as CreateEntityModelPropertyInput,
}));
message.success(
data.value.isEdit ? $t('common.editSuccess') : $t('common.addSuccess'),
);
modalApi.close();
emit('reload');
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal :title="data.isEdit ? $t('common.edit') : $t('common.add')">
<Form />
</Modal>
</template>

View File

@ -1,96 +0,0 @@
<script lang="ts" setup>
import type {
CreateEnumTypeInput,
UpdateEnumTypeInput,
} from '#/api-client/index';
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
postEnumTypesCreateEnumType,
postEnumTypesUpdateEnumType,
} from '#/api-client/index';
import { $t } from '#/locales';
const emit = defineEmits(['reload']);
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
component: 'Input',
fieldName: 'code',
label: $t('code.code'),
rules: 'required',
},
{
component: 'Textarea',
fieldName: 'description',
label: $t('code.desc'),
rules: 'required',
},
],
wrapperClass: 'grid-cols-1',
showDefaultActions: false,
});
const data = ref<Record<string, any>>({});
const [Modal, modalApi] = useVbenModal({
onOpenChange: (isOpen: boolean) => {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
if (data.value.isEdit) {
const { row } = data.value;
formApi.setValues({
...row,
});
}
}
},
onConfirm: async () => {
try {
modalApi.setState({ loading: true, confirmLoading: true });
const { valid } = await formApi.validate();
if (!valid) return;
const formValues = await formApi.getValues();
if (data.value.isEdit) {
const params = {
...formValues,
id: data.value.row.id,
};
await postEnumTypesUpdateEnumType({
body: params as UpdateEnumTypeInput,
});
} else {
await postEnumTypesCreateEnumType({
body: {
...formValues,
...data.value,
} as CreateEnumTypeInput,
});
}
message.success(
data.value.isEdit ? $t('common.editSuccess') : $t('common.addSuccess'),
);
modalApi.close();
emit('reload');
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal :title="data.isEdit ? $t('common.edit') : $t('common.add')">
<Form />
</Modal>
</template>

View File

@ -1,121 +0,0 @@
<script lang="ts" setup>
import type {
CreateEnumTypePropertyInput,
UpdateEnumTypePropertyInput,
} from '#/api-client/index';
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
postEnumTypesCreateEnumTypeProperty,
postEnumTypesUpdateEnumTypeProperty,
} from '#/api-client/index';
import { $t } from '#/locales';
const emit = defineEmits(['reload']);
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
component: 'Input',
fieldName: 'id',
label: 'id',
dependencies: {
show: () => false,
triggerFields: ['id'],
},
},
{
component: 'Input',
fieldName: 'enumTypeId',
label: 'enumTypeId',
dependencies: {
show: () => false,
triggerFields: ['enumTypeId'],
},
},
{
component: 'Input',
fieldName: 'code',
label: $t('code.code'),
rules: 'required',
},
{
component: 'InputNumber',
fieldName: 'value',
label: $t('code.value'),
rules: 'required',
},
{
component: 'Textarea',
fieldName: 'description',
label: $t('code.desc'),
rules: 'required',
},
],
wrapperClass: 'grid-cols-1',
showDefaultActions: false,
});
const data = ref<Record<string, any>>({});
const [Modal, modalApi] = useVbenModal({
onOpenChange: (isOpen: boolean) => {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
if (data.value.isEdit) {
const { row, enumTypeId } = data.value;
formApi.setValues({
...row,
enumTypeId,
});
}
}
},
onConfirm: async () => {
try {
modalApi.setState({ loading: true, confirmLoading: true });
const { valid } = await formApi.validate();
if (!valid) return;
const formValues = await formApi.getValues();
if (data.value.isEdit) {
const params = {
...formValues,
id: data.value.row.id,
};
await postEnumTypesUpdateEnumTypeProperty({
body: params as UpdateEnumTypePropertyInput,
});
} else {
await postEnumTypesCreateEnumTypeProperty({
body: {
...formValues,
...data.value,
} as CreateEnumTypePropertyInput,
});
}
message.success(
data.value.isEdit ? $t('common.editSuccess') : $t('common.addSuccess'),
);
modalApi.close();
emit('reload');
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal :title="data.isEdit ? $t('common.edit') : $t('common.add')">
<Form />
</Modal>
</template>

View File

@ -1,806 +0,0 @@
<script setup lang="ts">
import type { TreeProps } from 'ant-design-vue';
import type { DataNode } from 'ant-design-vue/es/tree';
import type { VbenFormProps } from '@vben/common-ui';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import {
Button,
Dropdown,
Input,
Menu,
message as Message,
message,
Modal,
Spin,
Tabs,
Tree,
} from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import {
postEntityModelsDeleteAggregate,
postEntityModelsDeleteEntityModel,
postEntityModelsDeleteEntityModelProperty,
postEntityModelsPageProperty,
postEntityModelsTree,
postEnumTypesDeleteEnumType,
postEnumTypesDeleteEnumTypeProperty,
postEnumTypesPage,
postEnumTypesPageProperty,
} from '#/api-client/index';
import { $t } from '#/locales';
import AddAggregateRoot from './AddAggregateRootModal.vue';
import AddEditEntity from './AddEditEntityModal.vue';
import AddEditEntityProperty from './AddEditEntityPropertyModal.vue';
import AddEditEnumComponent from './AddEditEnumModal.vue';
import AddEditEnumPropertyComponent from './AddEditEnumPropertyModal.vue';
//
const expandedKeys = ref<(number | string)[]>([]);
//
const searchValue = ref<string>('');
//
const autoExpandParent = ref<boolean>(true);
//
const gData = ref<Array<DataNode>>([]);
// tab
const activeKey = ref('1');
// key
const currentSelectedKey = ref('');
//
const currentSelectedTreeNode = ref();
const route = useRoute();
const contextMenuOptions = [
{ label: $t('common.add'), key: 'add' },
{ label: $t('common.edit'), key: 'edit' },
{ label: $t('common.delete'), key: 'delete' },
];
const loading = ref<boolean>(true);
onMounted(() => {
getTreeData().then(() => {
loading.value = false;
});
});
const [AddAggregateRootModal, addAggregateRootModalApi] = useVbenModal({
//
connectedComponent: AddAggregateRoot,
});
const [AddEditEntityModal, addEditEntityModalApi] = useVbenModal({
//
connectedComponent: AddEditEntity,
});
//
const onContextMenuSelect = async (key: string) => {
// key
switch (key) {
// keyadd
case 'add': {
addEditEntityModalApi.setData({
isEdit: false,
id: currentSelectedKey.value,
});
addEditEntityModalApi.open();
break;
}
// keydelete
case 'delete': {
Modal.confirm({
title: `${$t('common.confirmDelete')}?`,
onOk: async () => {
//
const params = {
id: currentSelectedTreeNode.value.key,
aggregateId: currentSelectedTreeNode.value?.parentId,
};
// aggregateId
if (currentSelectedTreeNode.value?.parentId) {
await postEntityModelsDeleteEntityModel({
body: params,
});
} else {
delete params.aggregateId;
await postEntityModelsDeleteAggregate({
body: params,
});
}
Message.success($t('common.success'));
currentSelectedKey.value = '';
currentSelectedTreeNode.value = null;
getTreeData();
},
});
break;
}
case 'edit': {
//
addEditEntityModalApi.setData({
isEdit: true, //
isRoot: !currentSelectedTreeNode.value?.parentId, //
id: currentSelectedKey.value, // id
row: currentSelectedTreeNode.value, //
});
//
addEditEntityModalApi.open();
break;
}
}
};
//
const onContextMenuClick = (treeKey: string, nodeData: any, menuKey: any) => {
// keycurrentSelectedKey
currentSelectedKey.value = treeKey;
// currentSelectedTreeNode
currentSelectedTreeNode.value = nodeData;
// onContextMenuSelectmenuKey
onContextMenuSelect(menuKey);
};
const dataList = ref<DataNode[]>([]);
const generateList = (data: TreeProps['treeData']) => {
if (!data) return;
for (const node of data) {
const { key, title, children } = node;
dataList.value.push({ key, title });
if (children) {
generateList(children);
}
}
};
const getParentKey = (
key: number | string,
tree: TreeProps['treeData'],
): number | string | undefined => {
if (!tree) return undefined;
let parentKey;
for (const node of tree) {
if (node.children) {
if (node.children.some((item) => item.key === key)) {
parentKey = node.key;
} else if (getParentKey(key, node.children)) {
parentKey = getParentKey(key, node.children);
}
}
}
return parentKey;
};
// key
const getAllKeys = (tree: TreeProps['treeData']): (number | string)[] => {
const keys: (number | string)[] = [];
const traverse = (nodes: TreeProps['treeData']) => {
if (!nodes) return;
nodes.forEach((node) => {
if (node.key) {
keys.push(node.key);
}
if (node.children) {
traverse(node.children);
}
});
};
traverse(tree);
return keys;
};
//
const expandAll = () => {
expandedKeys.value = getAllKeys(gData.value as TreeProps['treeData']);
autoExpandParent.value = true;
};
//
const collapseAll = () => {
expandedKeys.value = [];
autoExpandParent.value = true;
};
// onExpand /
const onExpand = (keys: (number | string)[], info: any) => {
expandedKeys.value = keys;
autoExpandParent.value = false;
};
const onSelect = (keys: any[], event: any) => {
currentSelectedKey.value = keys[0] ?? '';
// parentDisplayName.value = event.node.title;
if (!keys[0]) return '';
};
async function getTreeData() {
const { data = [] } = await postEntityModelsTree({
body: { projectId: route.query.projectId as string },
});
gData.value = data as DataNode[];
dataList.value = [];
generateList(data as TreeProps['treeData']);
}
watch(searchValue, (value) => {
if (!value) {
expandedKeys.value = [];
return;
}
const expanded = dataList.value
.map((item) => {
if (
typeof item.title === 'string' &&
item.title.toLowerCase().includes(value.toLowerCase())
) {
return getParentKey(item.key, gData.value as TreeProps['treeData']);
}
return null;
})
.filter(
(item, i, self): item is number | string =>
item !== null && item !== undefined && self.indexOf(item) === i,
);
expandedKeys.value = expanded;
autoExpandParent.value = true;
});
const propertyFormOptions: VbenFormProps = {
resetButtonOptions: {
show: false,
},
schema: [
{
component: 'Input',
fieldName: 'filter',
label: $t('common.keyword'),
labelWidth: 50,
componentProps: {
allowClear: true,
},
},
],
showDefaultActions: true,
submitOnEnter: true,
showCollapseButton: false,
};
const propertyGridOptions: VxeGridProps<any> = {
columns: [
{ type: 'seq', title: $t('common.seq'), width: '50' },
{
field: 'code',
title: $t('code.code'),
minWidth: '200',
},
{
field: 'description',
title: $t('common.description'),
minWidth: '200',
},
{
field: 'dataTypeDescription',
title: $t('code.type'),
minWidth: '150',
},
{
field: 'isRequired',
title: $t('code.isRequired'),
minWidth: '150',
},
{
field: 'maxLength',
title: $t('code.maxLength'),
minWidth: '150',
},
{
field: 'minLength',
title: $t('code.minLength'),
minWidth: '150',
},
{
field: 'decimalPrecision',
title: $t('code.decimalPrecision18'),
minWidth: '150',
},
{
field: 'decimalScale',
title: $t('code.decimalPrecision6'),
minWidth: '150',
},
{
title: $t('common.action'),
field: 'action',
fixed: 'right',
width: '150',
slots: { default: 'action' },
},
],
minHeight: '800',
keepSource: true,
pagerConfig: {},
radioConfig: {
highlight: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
if (!currentSelectedKey.value) return;
const { data } = await postEntityModelsPageProperty({
body: {
pageIndex: page.currentPage,
pageSize: page.pageSize,
id: currentSelectedKey.value,
...formValues,
},
});
return data;
},
},
},
};
const [PropertyGrid, propertyGridApi] = useVbenVxeGrid({
gridOptions: propertyGridOptions,
formOptions: propertyFormOptions,
});
const enumFormOptions: VbenFormProps = {
resetButtonOptions: {
show: false,
},
schema: [
{
component: 'Input',
fieldName: 'filter',
label: $t('common.keyword'),
labelWidth: 50,
componentProps: {
allowClear: true,
},
},
],
showDefaultActions: true,
submitOnEnter: true,
showCollapseButton: false,
};
const enumGridOptions: VxeGridProps<any> = {
columns: [
{ type: 'radio', title: $t('common.seq'), width: '50' },
{
field: 'code',
title: $t('code.code'),
minWidth: '200',
},
{
field: 'description',
title: $t('common.description'),
minWidth: '200',
},
{
title: $t('common.action'),
field: 'action',
fixed: 'right',
width: '150',
slots: { default: 'action' },
},
],
minHeight: '800',
keepSource: true,
pagerConfig: {},
radioConfig: {
highlight: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
if (!currentSelectedKey.value) return;
const { data } = await postEnumTypesPage({
body: {
pageIndex: page.currentPage,
pageSize: page.pageSize,
id: currentSelectedKey.value,
...formValues,
},
});
return data;
},
},
},
};
const currentEnumTypeId = ref<string>('');
const enumGridEvent = {
radioChange: (values: any) => {
currentEnumTypeId.value = values.row.id;
enumPropertyGridApi.reload({
id: values.row.id,
});
},
};
const [EnumGrid, enumGridApi] = useVbenVxeGrid({
gridOptions: enumGridOptions,
formOptions: enumFormOptions,
gridEvents: enumGridEvent,
});
const enumPropertyFormOptions: VbenFormProps = {
resetButtonOptions: {
show: false,
},
schema: [
{
component: 'Input',
fieldName: 'filter',
label: $t('common.keyword'),
labelWidth: 50,
componentProps: {
allowClear: true,
},
},
],
showDefaultActions: true,
submitOnEnter: true,
showCollapseButton: false,
};
const enumPropertyGridOptions: VxeGridProps<any> = {
columns: [
{ type: 'seq', title: $t('common.seq'), width: '50' },
{
field: 'code',
title: $t('code.code'),
minWidth: '100',
},
{
field: 'value',
title: $t('code.value'),
minWidth: '100',
},
{
field: 'description',
title: $t('common.description'),
minWidth: '150',
},
{
title: $t('common.action'),
field: 'action',
fixed: 'right',
width: '150',
slots: { default: 'action' },
},
],
minHeight: '800',
keepSource: true,
pagerConfig: {},
radioConfig: {
highlight: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
if (!currentEnumTypeId.value) return;
const { data } = await postEnumTypesPageProperty({
body: {
pageIndex: page.currentPage,
pageSize: page.pageSize,
id: currentEnumTypeId.value,
...formValues,
},
});
return data;
},
},
},
};
const [EnumPropertyGrid, enumPropertyGridApi] = useVbenVxeGrid({
gridOptions: enumPropertyGridOptions,
formOptions: enumPropertyFormOptions,
});
watch(currentSelectedKey, () => {
propertyGridApi.reload();
enumGridApi.reload();
enumPropertyGridApi.reload();
});
const [AddEditEntityPropertyModal, addEditEntityPropertyModalApi] =
useVbenModal({
connectedComponent: AddEditEntityProperty,
});
const openAddEntityPropertyModal = () => {
if (!currentSelectedKey.value) {
message.error('请先选择实体');
return;
}
addEditEntityPropertyModalApi.setData({
entityModelId: currentSelectedKey.value,
isEdit: false,
});
addEditEntityPropertyModalApi.open();
};
const handleDeleteEntityModelProperty = async (row: Record<string, any>) => {
Modal.confirm({
title: `${$t('common.confirmDelete')}?`,
onOk: async () => {
await postEntityModelsDeleteEntityModelProperty({
body: {
propertyId: row.id,
id: currentSelectedKey.value,
},
});
message.success($t('common.deleteSuccess'));
propertyGridApi.reload();
},
});
};
const handleEditEntityModelProperty = async (row: Record<string, any>) => {
addEditEntityPropertyModalApi.setData({
entityModelId: currentSelectedKey.value,
isEdit: true,
row,
});
addEditEntityPropertyModalApi.open();
};
const [AddEditEnumModal, addEditEnumModalApi] = useVbenModal({
connectedComponent: AddEditEnumComponent,
});
const handleAddEnum = () => {
if (!currentSelectedKey.value) {
message.error($t('code.pleaseSelectEntity'));
return;
}
addEditEnumModalApi.setData({
entityModelId: currentSelectedKey.value,
projectId: route.query.projectId,
isEdit: false,
});
addEditEnumModalApi.open();
};
const handleEditEnum = (row: Record<string, any>) => {
addEditEnumModalApi.setData({
isEdit: true,
row,
});
addEditEnumModalApi.open();
};
const handleDeleteEnum = async (row: Record<string, any>) => {
Modal.confirm({
title: `${$t('common.confirmDelete')}?`,
onOk: async () => {
await postEnumTypesDeleteEnumType({
body: { id: row.id, entityModelId: currentSelectedKey.value },
});
message.success($t('common.deleteSuccess'));
enumGridApi.reload();
},
});
};
const [AddEditEnumPropertyModal, addEditEnumPropertyModalApi] = useVbenModal({
connectedComponent: AddEditEnumPropertyComponent,
});
const handleAddEnumProperty = () => {
if (!currentEnumTypeId.value) {
message.error($t('code.pleaseSelectEnum'));
return;
}
addEditEnumPropertyModalApi.setData({
enumTypeId: currentEnumTypeId.value,
isEdit: false,
});
addEditEnumPropertyModalApi.open();
};
const handleEditEnumProperty = (row: Record<string, any>) => {
addEditEnumPropertyModalApi.setData({
isEdit: true,
enumTypeId: currentEnumTypeId.value,
row,
});
addEditEnumPropertyModalApi.open();
};
const handleDeleteEnumProperty = async (row: Record<string, any>) => {
Modal.confirm({
title: `${$t('common.confirmDelete')}?`,
onOk: async () => {
await postEnumTypesDeleteEnumTypeProperty({
body: { id: row.id, enumTypeId: currentEnumTypeId.value },
});
message.success($t('common.deleteSuccess'));
enumPropertyGridApi.reload();
},
});
};
</script>
<template>
<Spin :spinning="loading" tip="loading...">
<Page :auto-content-height="true">
<div class="grid grid-cols-12 gap-4">
<div class="bg-card col-span-4 xl:col-span-3">
<div class="bg-card flex items-center justify-between p-3">
<Button
class="mx-3"
size="small"
type="primary"
@click="addAggregateRootModalApi.open"
>
<div class="flex items-center">
<span
class="icon-[material-symbols--add-circle-outline]"
></span>
<span class="ml-1"> {{ $t('common.add') }}</span>
</div>
</Button>
<Input.Search v-model:value="searchValue" class="ml-1 flex-1" />
<Dropdown class="ml-1">
<Button class="font-bold">......</Button>
<template #overlay>
<Menu>
<Menu.Item @click="expandAll">
{{ $t('common.expandAll') }}
</Menu.Item>
<Menu.Item @click="collapseAll">
{{ $t('common.collapseAll') }}
</Menu.Item>
</Menu>
</template>
</Dropdown>
</div>
<Tree
:auto-expand-parent="autoExpandParent"
:block-node="true"
:expanded-keys="expandedKeys"
:tree-data="gData"
class="mt-3"
@expand="onExpand"
@select="onSelect"
>
<template #title="{ title, key: treeKey, data: nodeData }">
<Dropdown :trigger="['contextmenu']">
<span v-if="title.includes(searchValue)" class="block w-full">
{{ title.substring(0, title.indexOf(searchValue)) }}
<span style="color: #f50">{{ searchValue }}</span>
{{
title.substring(
title.indexOf(searchValue) + searchValue.length,
)
}}
</span>
<span v-else class="block w-full">{{ title }}</span>
<template #overlay>
<Menu
@click="
({ key: menuKey }) =>
onContextMenuClick(treeKey, nodeData, menuKey)
"
>
<Menu.Item
v-for="item in contextMenuOptions"
:key="item.key"
>
{{ item.label }}
</Menu.Item>
</Menu>
</template>
</Dropdown>
</template>
</Tree>
</div>
<div class="col-span-8 xl:col-span-9">
<div class="bg-card">
<Tabs v-model:active-key="activeKey" class="px-3">
<Tabs.TabPane key="1" :tab="$t('code.property')">
<PropertyGrid>
<template #toolbar-tools>
<Button
:disabled="!currentSelectedKey"
type="primary"
@click="openAddEntityPropertyModal"
>
{{ $t('common.add') }}
</Button>
</template>
<template #action="{ row }">
<Button
type="link"
@click="handleEditEntityModelProperty(row)"
>
{{ $t('common.edit') }}
</Button>
<Button
danger
type="link"
@click="handleDeleteEntityModelProperty(row)"
>
{{ $t('common.delete') }}
</Button>
</template>
</PropertyGrid>
</Tabs.TabPane>
<Tabs.TabPane key="2" :tab="$t('code.enum')">
<div class="grid grid-cols-12 gap-4">
<div class="bg-card col-span-6">
<EnumGrid>
<template #toolbar-tools>
<Button type="primary" @click="handleAddEnum">
{{ $t('common.add') }}
</Button>
</template>
<template #action="{ row }">
<Button type="link" @click="handleEditEnum(row)">
{{ $t('common.edit') }}
</Button>
<Button
danger
type="link"
@click="handleDeleteEnum(row)"
>
{{ $t('common.delete') }}
</Button>
</template>
</EnumGrid>
</div>
<div class="bg-card col-span-6">
<EnumPropertyGrid>
<template #toolbar-tools>
<Button type="primary" @click="handleAddEnumProperty">
{{ $t('common.add') }}
</Button>
</template>
<template #action="{ row }">
<Button
type="link"
@click="handleEditEnumProperty(row)"
>
{{ $t('common.edit') }}
</Button>
<Button
danger
type="link"
@click="handleDeleteEnumProperty(row)"
>
{{ $t('common.delete') }}
</Button>
</template>
</EnumPropertyGrid>
</div>
</div>
</Tabs.TabPane>
</Tabs>
</div>
</div>
</div>
<AddAggregateRootModal
:project-id="route.query.projectId"
@get-tree-data="getTreeData"
/>
<AddEditEntityModal @get-tree-data="getTreeData" />
<AddEditEntityPropertyModal @reload="propertyGridApi.reload" />
<AddEditEnumModal @reload="enumGridApi.reload" />
<AddEditEnumPropertyModal @reload="enumPropertyGridApi.reload" />
</Page>
</Spin>
</template>
<style scoped></style>

View File

@ -1,174 +0,0 @@
<script lang="ts" setup>
import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { h } from 'vue';
import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { Modal, Tag } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
// import { postProjectsDelete, postProjectsPage } from '#/api-client/index';
import { TableAction } from '#/components/table-action';
import { $t } from '#/locales';
// modal
import AddModal from './AddModal.vue';
// modal
import EditModal from './EditModal.vue';
import { querySchema, tableSchema } from './schema';
const router = useRouter();
const formOptions: VbenFormProps = {
//
collapsed: false,
schema: querySchema.value,
//
showCollapseButton: true,
//
submitOnEnter: false,
};
const gridOptions: VxeGridProps<any> = {
checkboxConfig: {
highlight: true,
labelField: 'name',
},
columns: tableSchema.value,
keepSource: true,
height: 'auto',
pagerConfig: {},
toolbarConfig: {
custom: true,
},
customConfig: {
storage: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
// const { data } = await postProjectsPage({
// body: {
// pageIndex: page.currentPage,
// pageSize: page.pageSize,
// ...formValues,
// },
// });
// return data;
return { items: [], totalCount: 0 };
},
},
},
};
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions });
const [AddVbenModal, addModalApi] = useVbenModal({
//
connectedComponent: AddModal,
});
const [EditVbenModal, editModalApi] = useVbenModal({
//
connectedComponent: EditModal,
});
const handleAdd = () => {
addModalApi.open();
};
const handleEdit = (row: Record<string, any>) => {
editModalApi.setData({
row,
});
editModalApi.open();
};
const handleDelete = (row: any) => {
Modal.confirm({
title: `${$t('common.confirmDelete')}?`,
onOk: async () => {
// await postProjectsDelete({
// body: {
// id: row.id,
// },
// });
gridApi.reload();
},
});
};
const handleViewModel = (row: Record<string, any>) => {
router.push({
name: 'EntityModel',
query: {
projectId: row.id,
},
});
};
</script>
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<TableAction
:actions="[
{
label: $t('common.add'),
type: 'primary',
icon: 'ant-design:plus-outlined',
onClick: handleAdd.bind(null),
auth: ['AbpCodeManagement.Project.Create'],
},
]"
/>
</template>
<template #supportTenant="{ row }">
<component
:is="
h(
Tag,
{ color: row.supportTenant ? 'green' : 'red' },
row.supportTenant ? $t('common.yes') : $t('common.no'),
)
"
/>
</template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: $t('code.model'),
type: 'link',
size: 'small',
auth: ['AbpCodeManagement.Project.Model'],
onClick: handleViewModel.bind(null, row),
},
{
label: $t('common.edit'),
type: 'link',
size: 'small',
auth: ['AbpCodeManagement.Project.Update'],
onClick: handleEdit.bind(null, row),
},
{
label: $t('common.delete'),
type: 'link',
size: 'small',
auth: ['AbpCodeManagement.Project.Delete'],
popConfirm: {
title: $t('common.askConfirmDelete'),
confirm: handleDelete.bind(null, row),
},
},
]"
/>
</template>
</Grid>
<AddVbenModal @reload="gridApi.reload" />
<EditVbenModal @reload="gridApi.reload" />
</Page>
</template>
<style scoped></style>

View File

@ -1,169 +0,0 @@
import type { VxeGridProps } from '#/adapter/vxe-table';
import { computed } from 'vue';
import { z } from '@vben/common-ui';
import dayjs from 'dayjs';
import { $t } from '#/locales';
export const querySchema = computed(() => [
{
component: 'Input',
fieldName: 'filter',
label: $t('code.projectName'),
},
]);
export const tableSchema: any = computed((): VxeGridProps['columns'] => [
{ title: $t('common.seq'), type: 'seq', width: 50 },
{ field: 'companyName', title: $t('code.companyName'), minWidth: '150' },
{
field: 'projectName',
title: $t('code.projectName'),
minWidth: '150',
},
{ field: 'nameSpace', title: $t('code.namespace'), minWidth: '150' },
{
field: 'supportTenant',
title: $t('code.supportTenant'),
minWidth: '150',
slots: { default: 'supportTenant' },
},
{ field: 'remark', title: $t('code.remark'), minWidth: '150' },
{
field: 'creationTime',
title: $t('common.createTime'),
minWidth: '150',
formatter: ({ cellValue }) => {
return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss');
},
},
{
title: $t('common.action'),
field: 'action',
fixed: 'right',
width: '250',
slots: { default: 'action' },
},
]);
export const addFormSchema = computed(() => [
{
component: 'Input',
componentProps: {},
fieldName: 'companyName',
label: $t('code.companyName'),
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.companyName'),
}),
},
{
component: 'Input',
componentProps: {},
fieldName: 'projectName',
label: $t('code.projectName'),
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.projectEnglishName'),
}),
},
// {
// component: 'Input',
// componentProps: {},
// fieldName: 'nameSpace',
// label: $t('code.namespace'),
// rules: z
// .string()
// .min(1, { message: $t('common.pleaseInput') + $t('code.namespace') }),
// },
{
component: 'RadioGroup',
componentProps: {
options: [
{
label: $t('common.yes'),
value: true,
},
{
label: $t('common.no'),
value: false,
},
],
},
defaultValue: 0,
fieldName: 'supportTenant',
label: $t('code.supportTenant'),
},
{
component: 'Input',
componentProps: {},
fieldName: 'remark',
label: $t('code.remark'),
},
]);
export const editFormSchema = computed(() => [
{
component: 'Input',
componentProps: {},
fieldName: 'id',
label: 'id',
dependencies: {
show: () => false,
triggerFields: ['id'],
},
},
{
component: 'Input',
componentProps: {},
fieldName: 'companyName',
label: $t('code.companyName'),
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.companyName'),
}),
},
{
component: 'Input',
componentProps: {},
fieldName: 'projectName',
label: $t('code.projectName'),
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.projectEnglishName'),
}),
},
// {
// component: 'Input',
// componentProps: {},
// fieldName: 'nameSpace',
// label: $t('code.namespace'),
// rules: z
// .string()
// .min(1, { message: $t('common.pleaseInput') + $t('code.namespace') }),
// },
{
component: 'RadioGroup',
componentProps: {
options: [
{
label: $t('common.yes'),
value: true,
},
{
label: $t('common.no'),
value: false,
},
],
},
defaultValue: 0,
fieldName: 'supportTenant',
label: $t('code.supportTenant'),
},
{
component: 'Input',
componentProps: {},
fieldName: 'remark',
label: $t('code.remark'),
},
]);

View File

@ -1,128 +0,0 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
postTemplatesControlType,
postTemplatesCreateDetail,
postTemplatesUpdateDetail,
} from '#/api-client/index';
import { $t } from '#/locales';
const emit = defineEmits(['getTreeData']);
const data = ref<Record<string, any>>({});
const controlTypeList = ref<any[]>();
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
component: 'Select',
fieldName: 'templateType',
label: '类型',
componentProps: () => {
return {
options: [
{ label: '文件夹', value: 10 },
{ label: '文件', value: 20 },
],
};
},
},
{
component: 'Select',
fieldName: 'controlType',
label: $t('code.templateType'),
componentProps: () => {
return {
options: controlTypeList.value,
fieldNames: { label: 'key', value: 'value' },
};
},
dependencies: {
triggerFields: ['templateType'],
if: (values) => {
return values.templateType === 20;
},
},
},
{
component: 'Input',
fieldName: 'name',
label: $t('code.name'),
rules: 'required',
},
{
component: 'Textarea',
fieldName: 'description',
label: $t('code.desc'),
rules: 'required',
},
],
wrapperClass: 'grid-cols-1',
showDefaultActions: false,
});
const getControlTypeList = async () => {
const { data = [] } = await postTemplatesControlType();
controlTypeList.value = data;
};
const [Modal, modalApi] = useVbenModal({
onOpenChange: (isOpen: boolean) => {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
getControlTypeList();
if (data.value.isEdit) {
const { row } = data.value;
formApi.setValues({
...row,
});
}
}
},
onConfirm: async () => {
try {
modalApi.setState({ loading: true, confirmLoading: true });
const { valid } = await formApi.validate();
if (!valid) return;
const formValues = await formApi.getValues();
if (data.value.isEdit) {
await postTemplatesUpdateDetail({
body: {
...formValues,
templateId: data.value.templateId,
templateDetailId: data.value.templateDetailId,
},
});
message.success($t('common.editSuccess'));
} else {
await postTemplatesCreateDetail({
body: {
...formValues,
templateId: data.value.templateId,
},
});
message.success($t('common.addSuccess'));
}
modalApi.close();
emit('getTreeData');
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal :title="data.isEdit ? $t('common.edit') : $t('common.add')">
<Form />
</Modal>
</template>

View File

@ -1,52 +0,0 @@
<script lang="ts" setup>
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { postTemplatesCreate } from '#/api-client/index';
import { $t } from '#/locales';
import { addFormSchema } from './schema';
const emit = defineEmits(['reload']);
const [Form, formApi] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
showDefaultActions: false,
layout: 'horizontal',
schema: addFormSchema.value,
wrapperClass: 'grid-cols-1',
});
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) return;
try {
modalApi.setState({ loading: true, confirmLoading: true });
//
const values = await formApi.getValues();
//
await postTemplatesCreate({ body: { ...values } });
message.success($t('common.addSuccess'));
emit('reload');
modalApi.close();
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal :title="$t('common.add')">
<Form />
</Modal>
</template>

View File

@ -1,74 +0,0 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal, z } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { postTemplatesCopy } from '#/api-client/index';
import { $t } from '#/locales';
const emit = defineEmits(['reload']);
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
showDefaultActions: false,
layout: 'horizontal',
schema: [
{
fieldName: 'name',
label: $t('code.templateName'),
component: 'Input',
componentProps: {},
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.templateName'),
}),
},
{
fieldName: 'remark',
label: $t('code.remark'),
component: 'Input',
componentProps: {},
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.remark'),
}),
},
],
wrapperClass: 'grid-cols-1',
});
const data = ref<any>();
const [Modal, modalApi] = useVbenModal({
onOpenChange: (isOpen: boolean) => {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
}
},
onCancel() {
modalApi.close();
},
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) return;
try {
modalApi.setState({ loading: true, confirmLoading: true });
const values = await formApi.getValues();
await postTemplatesCopy({ body: { ...values, id: data.value.id } });
message.success($t('common.copySuccess'));
emit('reload');
modalApi.close();
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal title="复制模板组">
<Form />
</Modal>
</template>

View File

@ -1,63 +0,0 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { postTemplatesUpdate } from '#/api-client/index';
import { $t } from '#/locales';
import { editFormSchema } from './schema';
const emit = defineEmits(['reload']);
const data = ref<any>({});
const [Form, formApi] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
showDefaultActions: false,
// labelinputvertical
// labelinput
layout: 'horizontal',
schema: editFormSchema.value,
wrapperClass: 'grid-cols-1',
});
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) return;
try {
modalApi.setState({ loading: true, confirmLoading: true });
//
const values = await formApi.getValues();
//
await postTemplatesUpdate({ body: { ...values } });
message.success($t('common.editSuccess'));
emit('reload');
modalApi.close();
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
onOpenChange(isOpen: boolean) {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
formApi.setValues(data.value.row);
}
},
});
</script>
<template>
<Modal :title="$t('common.edit')">
<Form />
</Modal>
</template>

View File

@ -1,432 +0,0 @@
<script setup lang="ts">
import type { DataNode, TreeProps } from 'ant-design-vue/es/tree';
import type { CreateTemplateDetailInput } from '#/api-client/index';
import { onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useVbenForm, useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import {
Button,
Dropdown,
Input,
Menu,
message as Message,
message,
Modal,
Spin,
Tree,
} from 'ant-design-vue';
import {
postTemplatesControlType,
postTemplatesCreateDetail,
postTemplatesDeleteDetail,
postTemplatesTree,
postTemplatesUpdateDetailContent,
} from '#/api-client/index';
import AddEditTemplateModal from './AddEditTemplateModal.vue';
//
const expandedKeys = ref<(number | string)[]>([]);
//
const searchValue = ref<string>('');
//
const autoExpandParent = ref<boolean>(true);
//
const gData = ref<Array<DataNode>>([]);
// key
const currentSelectedKey = ref('');
//
const currentSelectedTreeNode = ref();
const codeText = ref();
const route = useRoute();
const contextMenuOptions = [
{ label: $t('code.addFolder'), key: 'addFolder' },
{ label: $t('code.addFile'), key: 'addfile' },
{ label: $t('common.edit'), key: 'edit' },
{ label: $t('common.delete'), key: 'delete' },
];
const loading = ref<boolean>(true);
onMounted(() => {
getTreeData().then(() => {
loading.value = false;
});
});
//
const onContextMenuSelect = async (key: string) => {
// key
switch (key) {
case 'addfile': {
openCreateDetailModal(key);
break;
}
// keyadd
case 'addFolder': {
openCreateDetailModal(key);
break;
}
case 'delete': {
Modal.confirm({
title: `${$t('common.confirmDelete')}?`,
onOk: async () => {
const params = {
templateId: route.query.templateId as string,
templateDetailId: currentSelectedKey.value,
};
await postTemplatesDeleteDetail({
body: params,
});
Message.success($t('common.success'));
currentSelectedKey.value = '';
currentSelectedTreeNode.value = null;
getTreeData();
},
});
break;
}
case 'edit': {
addEditModalApi.setData({
isEdit: true,
templateId: route.query.templateId as string,
templateDetailId: currentSelectedKey.value,
row: currentSelectedTreeNode.value,
});
addEditModalApi.open();
break;
}
}
};
//
const onContextMenuClick = (treeKey: string, nodeData: any, menuKey: any) => {
// keycurrentSelectedKey
currentSelectedKey.value = treeKey;
// currentSelectedTreeNode
currentSelectedTreeNode.value = nodeData;
// onContextMenuSelectmenuKey
onContextMenuSelect(menuKey);
};
const dataList = ref<DataNode[]>([]);
const generateList = (data: TreeProps['treeData']) => {
if (!data) return;
for (const node of data) {
const { key, title, children } = node;
dataList.value.push({ key, title });
if (children) {
generateList(children);
}
}
};
const getParentKey = (
key: number | string,
tree: TreeProps['treeData'],
): number | string | undefined => {
if (!tree) return undefined;
let parentKey;
for (const node of tree) {
if (node.children) {
if (node.children.some((item) => item.key === key)) {
parentKey = node.key;
} else if (getParentKey(key, node.children)) {
parentKey = getParentKey(key, node.children);
}
}
}
return parentKey;
};
// key
const getAllKeys = (tree: TreeProps['treeData']): (number | string)[] => {
const keys: (number | string)[] = [];
const traverse = (nodes: TreeProps['treeData']) => {
if (!nodes) return;
nodes.forEach((node) => {
if (node.key) {
keys.push(node.key);
}
if (node.children) {
traverse(node.children);
}
});
};
traverse(tree);
return keys;
};
//
const expandAll = () => {
expandedKeys.value = getAllKeys(gData.value as TreeProps['treeData']);
autoExpandParent.value = true;
};
//
const collapseAll = () => {
expandedKeys.value = [];
autoExpandParent.value = true;
};
// onExpand /
const onExpand = (keys: (number | string)[], info: any) => {
expandedKeys.value = keys;
autoExpandParent.value = false;
};
//
const showSaveContentBtn = ref<boolean>(false);
const onSelect = (keys: any[], event: any) => {
codeText.value = '';
showSaveContentBtn.value = false;
if (event.node.templateType === 10) return;
showSaveContentBtn.value = true;
currentSelectedKey.value = keys[0] ?? '';
codeText.value = event.node.content || '';
if (!keys[0]) return '';
};
const saveContent = async () => {
if (!currentSelectedKey.value) {
message.error('请选择节点');
return;
}
const params = {
templateId: route.query.templateId as string,
templateDetailId: currentSelectedKey.value,
content: codeText.value,
};
await postTemplatesUpdateDetailContent({ body: params });
message.success($t('common.editSuccess'));
};
async function getTreeData() {
const { data = [] } = await postTemplatesTree({
body: { templateId: route.query.templateId as string },
});
gData.value = data as DataNode[];
dataList.value = [];
generateList(data as TreeProps['treeData']);
}
watch(searchValue, (value) => {
if (!value) {
expandedKeys.value = [];
return;
}
const expanded = dataList.value
.map((item) => {
if (
typeof item.title === 'string' &&
item.title.toLowerCase().includes(value.toLowerCase())
) {
return getParentKey(item.key, gData.value as TreeProps['treeData']);
}
return null;
})
.filter(
(item, i, self): item is number | string =>
item !== null && item !== undefined && self.indexOf(item) === i,
);
expandedKeys.value = expanded;
autoExpandParent.value = true;
});
const [AddEditModal, addEditModalApi] = useVbenModal({
connectedComponent: AddEditTemplateModal,
});
const openTemplateModal = () => {
addEditModalApi.setData({
isEdit: false,
templateId: route.query.templateId as string,
});
addEditModalApi.open();
};
const [CreateDetailModal, createDetailModalApi] = useVbenModal({
onOpenChange: (isOpen: boolean) => {
if (isOpen) {
getControlTypeList();
}
},
onConfirm: async () => {
try {
createDetailModalApi.setState({ loading: true, confirmLoading: true });
const { valid } = await createDetailFormApi.validate();
if (!valid) return;
const formValues = await createDetailFormApi.getValues();
let params: CreateTemplateDetailInput = {};
if (isFloder.value) {
//
params = {
...formValues,
templateId: route.query.templateId as string,
parentId: currentSelectedKey.value,
templateType: 10,
};
} else {
//
params = {
...formValues,
templateId: route.query.templateId as string,
parentId: currentSelectedKey.value,
templateType: 20,
};
}
await postTemplatesCreateDetail({ body: params });
message.success($t('common.addSuccess'));
createDetailModalApi.close();
getTreeData();
} finally {
createDetailModalApi.setState({ loading: false, confirmLoading: false });
}
},
});
const controlTypeList = ref<any[]>();
const isFloder = ref<boolean>(false);
const getControlTypeList = async () => {
const { data = [] } = await postTemplatesControlType();
controlTypeList.value = data;
};
const [CreateDetailForm, createDetailFormApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
layout: 'horizontal',
schema: [
{
component: 'Select',
fieldName: 'controlType',
label: '模板策略',
componentProps: () => {
return {
options: controlTypeList.value,
fieldNames: { label: 'key', value: 'value' },
};
},
dependencies: {
triggerFields: ['templateType'],
if: () => {
return !isFloder.value;
},
},
},
{
component: 'Input',
fieldName: 'name',
label: '名称',
rules: 'required',
},
{
component: 'Textarea',
fieldName: 'description',
label: '描述',
},
],
wrapperClass: 'grid-cols-1',
showDefaultActions: false,
});
const openCreateDetailModal = (key: string) => {
isFloder.value = key === 'addFolder';
createDetailModalApi.open();
};
</script>
<template>
<Spin :spinning="loading" tip="loading...">
<div class="m-4 grid min-h-[calc(100vh-120px)] grid-cols-12 gap-4">
<div class="bg-card col-span-4 xl:col-span-3">
<div class="bg-card flex items-center justify-between p-3">
<Button class="mx-3" size="small" type="primary">
<div class="flex items-center">
<span class="icon-[material-symbols--add-circle-outline]"></span>
<span class="ml-1" @click="openTemplateModal">{{
$t('common.add')
}}</span>
</div>
</Button>
<Input.Search v-model:value="searchValue" class="ml-1 flex-1" />
<Dropdown class="ml-1">
<Button class="font-bold">......</Button>
<template #overlay>
<Menu>
<Menu.Item @click="expandAll">
{{ $t('common.expandAll') }}
</Menu.Item>
<Menu.Item @click="collapseAll">
{{ $t('common.collapseAll') }}
</Menu.Item>
</Menu>
</template>
</Dropdown>
</div>
<Tree
:auto-expand-parent="autoExpandParent"
:block-node="true"
:expanded-keys="expandedKeys"
:tree-data="gData"
class="mt-3"
@expand="onExpand"
@select="onSelect"
>
<template #title="{ title, key: treeKey, data: nodeData }">
<Dropdown :trigger="['contextmenu']">
<span v-if="title.includes(searchValue)" class="block w-full">
{{ title.substring(0, title.indexOf(searchValue)) }}
<span style="color: #f50">{{ searchValue }}</span>
{{
title.substring(
title.indexOf(searchValue) + searchValue.length,
)
}}
</span>
<span v-else class="block w-full">{{ title }}</span>
<template #overlay>
<Menu
@click="
({ key: menuKey }) =>
onContextMenuClick(treeKey, nodeData, menuKey)
"
>
<Menu.Item v-for="item in contextMenuOptions" :key="item.key">
{{ item.label }}
</Menu.Item>
</Menu>
</template>
</Dropdown>
</template>
</Tree>
</div>
<div class="bg-card col-span-8 xl:col-span-9">
<div class="bg-card">
<Button
v-show="showSaveContentBtn"
style="margin-left: 96%"
type="primary"
@click="saveContent"
>
{{ $t('common.save') }}
</Button>
<Codemirror v-model:value="codeText" />
</div>
</div>
<AddEditModal @get-tree-data="getTreeData" />
<CreateDetailModal :title="$t('common.add')">
<CreateDetailForm />
</CreateDetailModal>
</div>
</Spin>
</template>
<style scoped></style>

View File

@ -1,212 +0,0 @@
<script lang="ts" setup>
import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { useRouter } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui';
import { Modal } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { postTemplatesDelete, postTemplatesPage } from '#/api-client/index';
import { TableAction } from '#/components/table-action';
import { $t } from '#/locales';
// modal
import AddModal from './AddModal.vue';
import CopyModaComponent from './CopyModal.vue';
// modal
import EditModal from './EditModal.vue';
import { querySchema, tableSchema } from './schema';
const router = useRouter();
const formOptions: VbenFormProps = {
//
collapsed: false,
schema: querySchema.value,
//
showCollapseButton: true,
//
submitOnEnter: false,
};
const gridOptions: VxeGridProps<any> = {
checkboxConfig: {
highlight: true,
labelField: 'name',
},
columns: tableSchema.value,
keepSource: true,
height: 'auto',
pagerConfig: {},
toolbarConfig: {
custom: true,
},
customConfig: {
storage: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
const { data } = await postTemplatesPage({
body: {
pageIndex: page.currentPage,
pageSize: page.pageSize,
...formValues,
},
});
return data;
},
},
},
};
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions });
const [AddVbenModal, addModalApi] = useVbenModal({
//
connectedComponent: AddModal,
});
const [EditVbenModal, editModalApi] = useVbenModal({
//
connectedComponent: EditModal,
});
const handleAdd = () => {
addModalApi.open();
};
const handleEdit = (row: Record<string, any>) => {
editModalApi.setData({
row,
});
editModalApi.open();
};
const handleDelete = (row: any) => {
Modal.confirm({
title: `${$t('common.confirmDelete')}?`,
onOk: async () => {
await postTemplatesDelete({
body: {
id: row.id,
},
});
gridApi.reload();
},
});
};
const [CopyModal, copyModalApi] = useVbenModal({
connectedComponent: CopyModaComponent,
});
const handleCopy = (row: Record<string, any>) => {
copyModalApi.setData({
id: row.id,
});
copyModalApi.open();
};
const handleViewDetail = (row: Record<string, any>) => {
router.push({
name: 'TemplateDetail',
query: {
templateId: row.id,
},
});
};
</script>
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<TableAction
:actions="[
{
label: $t('common.add'),
type: 'primary',
icon: 'ant-design:plus-outlined',
onClick: handleAdd.bind(null),
auth: ['AbpCodeManagement.Template.Create'],
},
]"
/>
</template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: $t('code.detail'),
type: 'link',
size: 'small',
auth: ['AbpCodeManagement.Template.Update'],
onClick: handleViewDetail.bind(null, row),
},
{
label: $t('code.copy'),
type: 'link',
size: 'small',
auth: ['AbpCodeManagement.Template.Copy'],
onClick: handleCopy.bind(null, row),
},
{
label: $t('common.edit'),
type: 'link',
size: 'small',
auth: ['AbpCodeManagement.Template.Copy'],
onClick: handleEdit.bind(null, row),
},
{
label: $t('common.delete'),
type: 'link',
size: 'small',
auth: ['AbpCodeManagement.Template.Delete'],
popConfirm: {
title: $t('common.askConfirmDelete'),
confirm: handleDelete.bind(null, row),
},
},
]"
/>
<!-- <Button
type="link"
v-access:code="'AbpCodeManagement.Template.Update'"
@click="handleViewDetail(row)"
>
{{ $t('code.detail') }}
</Button>
<Button
type="link"
v-access:code="'AbpCodeManagement.Template.Copy'"
@click="handleCopy(row)"
>
{{ $t('code.copy') }}
</Button>
<Button
type="link"
v-access:code="'AbpCodeManagement.Template.Update'"
@click="handleEdit(row)"
>
{{ $t('common.edit') }}
</Button>
<Button
danger
type="link"
v-access:code="'AbpCodeManagement.Template.Delete'"
@click="handleDelete(row)"
>
{{ $t('common.delete') }}
</Button> -->
</template>
</Grid>
<AddVbenModal @reload="gridApi.reload" />
<EditVbenModal @reload="gridApi.reload" />
<CopyModal @reload="gridApi.reload" />
</Page>
</template>
<style scoped></style>

View File

@ -1,80 +0,0 @@
import type { VxeGridProps } from '#/adapter/vxe-table';
import { computed } from 'vue';
import { z } from '@vben/common-ui';
import { $t } from '#/locales';
export const querySchema = computed(() => [
{
component: 'Input',
fieldName: 'filter',
label: $t('code.templateName'),
},
]);
export const tableSchema: any = computed((): VxeGridProps['columns'] => [
{ title: $t('common.seq'), type: 'seq', width: 50 },
{ title: $t('code.templateName'), field: 'name', minWidth: '150' },
{ title: $t('code.remark'), field: 'remark', minWidth: '150' },
{
title: $t('common.action'),
field: 'action',
fixed: 'right',
width: '300',
slots: { default: 'action' },
},
]);
export const addFormSchema = computed(() => [
{
fieldName: 'name',
label: $t('code.templateName'),
component: 'Input',
componentProps: {},
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.templateName'),
}),
},
{
fieldName: 'remark',
label: $t('code.remark'),
component: 'Input',
componentProps: {},
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.remark'),
}),
},
]);
export const editFormSchema = computed(() => [
{
component: 'Input',
componentProps: {},
fieldName: 'id',
label: 'id',
dependencies: {
show: () => false,
triggerFields: ['id'],
},
},
{
fieldName: 'name',
label: $t('code.templateName'),
component: 'Input',
componentProps: {},
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.templateName'),
}),
},
{
fieldName: 'remark',
label: $t('code.remark'),
component: 'Input',
componentProps: {},
rules: z.string().min(1, {
message: $t('common.pleaseInput') + $t('code.remark'),
}),
},
]);

View File

@ -1,58 +0,0 @@
<script lang="ts" setup>
import type { CreateTextTemplateInput } from '#/api-client/index';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { postTextTemplatesCreate } from '#/api-client/index';
import { $t } from '#/locales';
import { addFormSchema } from './schema';
const emit = defineEmits(['reload']);
const [Form, formApi] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
showDefaultActions: false,
// labelinputvertical
// labelinput
layout: 'horizontal',
schema: addFormSchema.value,
wrapperClass: 'grid-cols-1',
});
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) return;
try {
modalApi.setState({ loading: true, confirmLoading: true });
//
const values = await formApi.getValues();
//
await postTextTemplatesCreate({
body: { ...values } as CreateTextTemplateInput,
});
message.success($t('common.addSuccess'));
emit('reload');
modalApi.close();
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
});
</script>
<template>
<Modal :title="$t('common.add')">
<Form />
</Modal>
</template>

View File

@ -1,67 +0,0 @@
<script lang="ts" setup>
import type { UpdateTextTemplateInput } from '#/api-client/index';
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { postTextTemplatesUpdate } from '#/api-client/index';
import { $t } from '#/locales';
import { editFormSchema } from './schema';
const emit = defineEmits(['reload']);
const data = ref<any>({});
const [Form, formApi] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
showDefaultActions: false,
// labelinputvertical
// labelinput
layout: 'horizontal',
schema: editFormSchema.value,
wrapperClass: 'grid-cols-1',
});
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) return;
try {
modalApi.setState({ loading: true, confirmLoading: true });
//
const values = await formApi.getValues();
//
await postTextTemplatesUpdate({
body: { ...values } as UpdateTextTemplateInput,
});
message.success($t('common.editSuccess'));
emit('reload');
modalApi.close();
} finally {
modalApi.setState({ loading: false, confirmLoading: false });
}
},
onOpenChange(isOpen: boolean) {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
formApi.setValues(data.value.row);
}
},
});
</script>
<template>
<Modal :title="$t('common.edit')">
<Form />
</Modal>
</template>

View File

@ -1,176 +0,0 @@
<script lang="ts" setup>
import type { VbenFormProps } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { Page, useVbenModal } from '@vben/common-ui';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import {
postTextTemplatesDelete,
postTextTemplatesExport,
postTextTemplatesPage,
} from '#/api-client/index';
import { TableAction } from '#/components/table-action';
import { $t } from '#/locales';
// modal
import AddModal from './AddModal.vue';
// modal
import EditModal from './EditModal.vue';
import { querySchema, tableSchema } from './schema';
const formOptions: VbenFormProps = {
//
collapsed: false,
schema: querySchema.value,
//
showCollapseButton: true,
//
submitOnEnter: false,
wrapperClass: 'grid-cols-4',
};
const gridOptions: VxeGridProps<any> = {
checkboxConfig: {
highlight: true,
labelField: 'name',
},
columns: tableSchema,
keepSource: true,
height: 'auto',
pagerConfig: {},
toolbarConfig: {
custom: true,
},
customConfig: {
storage: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
if (formValues?.time?.length === 2) {
formValues = {
...formValues,
startCreationTime: formValues.time[0],
endCreationTime: formValues.time[1],
};
}
const { data } = await postTextTemplatesPage({
body: {
pageIndex: page.currentPage,
pageSize: page.pageSize,
...formValues,
},
});
return data;
},
},
},
};
const [Grid, gridApi] = useVbenVxeGrid({ formOptions, gridOptions });
const [AddVbenModal, addModalApi] = useVbenModal({
//
connectedComponent: AddModal,
});
const [EditVbenModal, editModalApi] = useVbenModal({
//
connectedComponent: EditModal,
});
const handleAdd = () => {
addModalApi.open();
};
const handleEdit = (row: Record<string, any>) => {
editModalApi.setData({
row,
});
editModalApi.open();
};
const handleDelete = async (row: any) => {
await postTextTemplatesDelete({
body: {
id: row.id,
},
});
gridApi.reload();
};
const exportData = async () => {
gridApi.setLoading(true);
try {
const formValues = await gridApi.formApi.getValues();
const {
pager: { currentPage, pageSize },
} = await gridApi.grid.getProxyInfo();
const pagination = { pageIndex: currentPage, pageSize };
const { data } = await postTextTemplatesExport({
body: { ...formValues, ...pagination },
responseType: 'blob',
});
const url = window.URL.createObjectURL(new Blob([data as Blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', '模板导出.xlsx');
document.body.append(link);
link.click();
link.remove();
window.URL.revokeObjectURL(url);
} finally {
gridApi.setLoading(false);
}
};
</script>
<template>
<Page auto-content-height>
<Grid>
<template #toolbar-actions>
<TableAction
:actions="[
{
label: $t('common.add'),
type: 'primary',
icon: 'ant-design:plus-outlined',
onClick: handleAdd.bind(null),
auth: ['AbpTemplateManagement.Template.Create'],
},
{
label: $t('common.export'),
type: 'primary',
icon: 'ant-design:download-outlined',
onClick: exportData.bind(null),
auth: ['AbpTemplateManagement.Template.Export'],
},
]"
/>
</template>
<template #action="{ row }">
<TableAction
:actions="[
{
label: $t('common.edit'),
auth: ['AbpTemplateManagement.Template.Update'],
onClick: handleEdit.bind(null, row),
},
{
label: $t('common.delete'),
auth: ['AbpTemplateManagement.Template.Delete'],
popConfirm: {
title: $t('common.askConfirmDelete'),
confirm: handleDelete.bind(null, row),
},
},
]"
/>
</template>
</Grid>
<AddVbenModal @reload="gridApi.reload" />
<EditVbenModal @reload="gridApi.reload" />
</Page>
</template>
<style scoped></style>

View File

@ -1,155 +0,0 @@
import type { VxeGridProps } from '#/adapter/vxe-table';
import { computed } from 'vue';
import { $t } from '#/locales';
export const querySchema = computed(() => [
// {
// component: 'RangePicker',
// fieldName: 'time',
// label: $t('common.createTime'),
// componentProps: {
// 'value-format': 'YYYY-MM-DD',
// },
// defaultValue: [
// // 最近7天
// dayjs().subtract(7, 'day').format('YYYY-MM-DD'),
// dayjs().subtract(-1, 'day').format('YYYY-MM-DD'),
// ],
// },
{
component: 'Input',
fieldName: 'name',
label: $t('textTemplate.name'),
},
{
component: 'Input',
fieldName: 'code',
label: $t('textTemplate.code'),
},
{
component: 'Input',
fieldName: 'content',
label: $t('textTemplate.content'),
},
]);
export const tableSchema: any = computed((): VxeGridProps['columns'] => [
{ title: $t('common.seq'), type: 'seq', width: 50 },
{
title: $t('textTemplate.name'),
minWidth: '150',
field: 'name',
},
{
title: $t('textTemplate.code'),
minWidth: '150',
field: 'code',
},
{
title: $t('textTemplate.content'),
minWidth: '150',
field: 'content',
},
{
title: $t('textTemplate.cultureName'),
minWidth: '150',
field: 'cultureName',
},
{
title: $t('common.action'),
field: 'action',
fixed: 'right',
width: '150',
slots: { default: 'action' },
},
]);
export const addFormSchema = computed(() => [
{
fieldName: 'name',
label: $t('textTemplate.name'),
rules: 'required',
component: 'Input',
},
{
fieldName: 'code',
label: $t('textTemplate.code'),
rules: 'required',
component: 'Input',
},
{
fieldName: 'content',
label: $t('textTemplate.content'),
rules: 'required',
component: 'Textarea',
},
{
fieldName: 'cultureName',
label: $t('textTemplate.cultureName'),
rules: 'required',
component: 'Select',
componentProps: {
options: [
{
label: 'en',
value: 'en',
},
{
label: '简体中文',
value: 'zh-Hans',
},
],
},
},
]);
export const editFormSchema = computed(() => [
{
component: 'Input',
componentProps: {},
fieldName: 'id',
label: 'id',
dependencies: {
show: () => false,
triggerFields: ['id'],
},
},
{
fieldName: 'name',
label: $t('textTemplate.name'),
rules: 'required',
component: 'Input',
},
{
fieldName: 'code',
label: $t('textTemplate.code'),
rules: 'required',
component: 'Input',
},
{
fieldName: 'content',
label: $t('textTemplate.content'),
rules: 'required',
component: 'Textarea',
},
{
fieldName: 'cultureName',
label: $t('textTemplate.cultureName'),
rules: 'required',
component: 'Select',
componentProps: {
options: [
{
label: 'en',
value: 'en',
},
{
label: '简体中文',
value: 'zh-Hans',
},
],
},
},
]);