物业代码生成

This commit is contained in:
2025-06-18 11:03:42 +08:00
commit 1262d4c745
1881 changed files with 249599 additions and 0 deletions

View File

@@ -0,0 +1,223 @@
import type { FormSchemaGetter } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import { DictEnum } from '@vben/constants';
import { Tag } from 'ant-design-vue';
import { z } from '#/adapter/form';
import { getDictOptions } from '#/utils/dict';
const accessPolicyOptions = [
{ color: 'orange', label: '私有', value: '0' },
{ color: 'green', label: '公开', value: '1' },
{ color: 'blue', label: '自定义', value: '2' },
];
export const querySchema: FormSchemaGetter = () => [
{
component: 'Input',
fieldName: 'configKey',
label: '配置名称',
},
{
component: 'Input',
fieldName: 'bucketName',
label: '桶名称',
},
{
component: 'Select',
componentProps: {
options: [
{ label: '是', value: '0' },
{ label: '否', value: '1' },
],
},
fieldName: 'status',
label: '是否默认',
},
];
export const columns: VxeGridProps['columns'] = [
{ type: 'checkbox', width: 60 },
{
title: '配置名称',
field: 'configKey',
},
{
title: '访问站点',
field: 'endpoint',
showOverflow: true,
},
{
title: '桶名称',
field: 'bucketName',
},
{
title: '域',
field: 'region',
},
{
title: '权限桶类型',
field: 'accessPolicy',
slots: {
default: ({ row }) => {
const current = accessPolicyOptions.find(
(item) => item.value === row.accessPolicy,
);
if (current) {
return <Tag color={current.color}>{current.label}</Tag>;
}
return '未知类型';
},
},
},
{
title: '是否默认',
field: 'status',
slots: {
default: 'status',
},
},
{
field: 'action',
fixed: 'right',
slots: { default: 'action' },
title: '操作',
resizable: false,
width: 'auto',
},
];
export const drawerSchema: FormSchemaGetter = () => [
{
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
fieldName: 'ossConfigId',
},
{
component: 'Divider',
componentProps: {
orientation: 'center',
},
fieldName: 'divider1',
hideLabel: true,
renderComponentContent: () => ({
default: () => '基本信息',
}),
},
{
component: 'Input',
fieldName: 'configKey',
label: '配置名称',
rules: 'required',
},
{
component: 'Input',
fieldName: 'endpoint',
label: '服务地址',
renderComponentContent: (formModel) => ({
addonBefore: () => (formModel.isHttps === 'Y' ? 'https://' : 'http://'),
}),
rules: z
.string()
.refine((domain) => domain && !/^https?:\/\/.*/.test(domain), {
message: '请输入正确的域名, 不需要http(s)',
}),
},
{
component: 'Input',
fieldName: 'domain',
label: '自定义域名',
},
{
component: 'Input',
fieldName: 'tip',
label: '占位作为提示使用',
hideLabel: true,
},
{
component: 'Divider',
componentProps: {
orientation: 'center',
},
fieldName: 'divider2',
hideLabel: true,
renderComponentContent: () => ({
default: () => '认证信息',
}),
},
{
component: 'Input',
fieldName: 'accessKey',
label: 'accessKey',
rules: 'required',
},
{
component: 'Input',
fieldName: 'secretKey',
label: 'secretKey',
rules: 'required',
},
{
component: 'Divider',
componentProps: {
orientation: 'center',
},
fieldName: 'divider3',
hideLabel: true,
renderComponentContent: () => ({
default: () => '其他信息',
}),
},
{
component: 'Input',
fieldName: 'bucketName',
label: '桶名称',
rules: 'required',
},
{
component: 'Input',
fieldName: 'prefix',
label: '前缀',
},
{
component: 'RadioGroup',
componentProps: {
buttonStyle: 'solid',
options: accessPolicyOptions,
optionType: 'button',
},
defaultValue: '0',
fieldName: 'accessPolicy',
formItemClass: 'col-span-3 lg:col-span-2',
label: '权限桶类型',
},
{
component: 'RadioGroup',
componentProps: {
buttonStyle: 'solid',
options: getDictOptions(DictEnum.SYS_YES_NO),
optionType: 'button',
},
defaultValue: 'N',
fieldName: 'isHttps',
formItemClass: 'col-span-3 lg:col-span-1',
label: '是否https',
rules: 'required',
},
{
component: 'Input',
fieldName: 'region',
label: '区域',
},
{
component: 'Textarea',
fieldName: 'remark',
formItemClass: 'items-start',
label: '备注',
},
];

View File

@@ -0,0 +1,166 @@
<script setup lang="ts">
import type { VbenFormProps } from '@vben/common-ui';
import type { VxeGridProps } from '#/adapter/vxe-table';
import type { OssConfig } from '#/api/system/oss-config/model';
import { useAccess } from '@vben/access';
import { Page, useVbenDrawer } from '@vben/common-ui';
import { getVxePopupContainer } from '@vben/utils';
import { Modal, Popconfirm, Space } from 'ant-design-vue';
import { useVbenVxeGrid, vxeCheckboxChecked } from '#/adapter/vxe-table';
import {
ossConfigChangeStatus,
ossConfigList,
ossConfigRemove,
} from '#/api/system/oss-config';
import { TableSwitch } from '#/components/table';
import { columns, querySchema } from './data';
import ossConfigDrawer from './oss-config-drawer.vue';
const formOptions: VbenFormProps = {
schema: querySchema(),
commonConfig: {
labelWidth: 80,
componentProps: {
allowClear: true,
},
},
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
};
const gridOptions: VxeGridProps = {
checkboxConfig: {
// 高亮
highlight: true,
// 翻页时保留选中状态
reserve: true,
// 点击行选中
// trigger: 'row',
},
columns,
height: 'auto',
keepSource: true,
pagerConfig: {},
proxyConfig: {
ajax: {
query: async ({ page }, formValues = {}) => {
return await ossConfigList({
pageNum: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'ossConfigId',
},
id: 'system-oss-config-index',
};
const [BasicTable, tableApi] = useVbenVxeGrid({
formOptions,
gridOptions,
});
const [OssConfigDrawer, drawerApi] = useVbenDrawer({
connectedComponent: ossConfigDrawer,
});
function handleAdd() {
drawerApi.setData({});
drawerApi.open();
}
async function handleEdit(record: OssConfig) {
drawerApi.setData({ id: record.ossConfigId });
drawerApi.open();
}
async function handleDelete(row: OssConfig) {
await ossConfigRemove([row.ossConfigId]);
await tableApi.query();
}
function handleMultiDelete() {
const rows = tableApi.grid.getCheckboxRecords();
const ids = rows.map((row: OssConfig) => row.ossConfigId);
Modal.confirm({
title: '提示',
okType: 'danger',
content: `确认删除选中的${ids.length}条记录吗?`,
onOk: async () => {
await ossConfigRemove(ids);
await tableApi.query();
},
});
}
const { hasAccessByCodes } = useAccess();
</script>
<template>
<Page :auto-content-height="true">
<BasicTable table-title="oss配置列表">
<template #toolbar-tools>
<Space>
<a-button
:disabled="!vxeCheckboxChecked(tableApi)"
danger
type="primary"
v-access:code="['system:ossConfig:remove']"
@click="handleMultiDelete"
>
{{ $t('pages.common.delete') }}
</a-button>
<a-button
type="primary"
v-access:code="['system:ossConfig:add']"
@click="handleAdd"
>
{{ $t('pages.common.add') }}
</a-button>
</Space>
</template>
<template #status="{ row }">
<TableSwitch
v-model:value="row.status"
:api="() => ossConfigChangeStatus(row)"
:disabled="!hasAccessByCodes(['system:ossConfig:edit'])"
checked-text=""
un-checked-text=""
@reload="tableApi.query()"
/>
</template>
<template #action="{ row }">
<Space>
<ghost-button
v-access:code="['system:ossConfig:edit']"
@click="handleEdit(row)"
>
{{ $t('pages.common.edit') }}
</ghost-button>
<Popconfirm
:get-popup-container="getVxePopupContainer"
placement="left"
title="确认删除?"
@confirm="handleDelete(row)"
>
<ghost-button
danger
v-access:code="['system:ossConfig:remove']"
@click.stop=""
>
{{ $t('pages.common.delete') }}
</ghost-button>
</Popconfirm>
</Space>
</template>
</BasicTable>
<OssConfigDrawer @reload="tableApi.query()" />
</Page>
</template>

View File

@@ -0,0 +1,115 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { cloneDeep } from '@vben/utils';
import { Alert } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import {
ossConfigAdd,
ossConfigInfo,
ossConfigUpdate,
} from '#/api/system/oss-config';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { drawerSchema } from './data';
const emit = defineEmits<{ reload: [] }>();
const isUpdate = ref(false);
const title = computed(() => {
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
});
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
formItemClass: 'col-span-3',
labelWidth: 100,
},
schema: drawerSchema(),
showDefaultActions: false,
wrapperClass: 'grid-cols-3',
});
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [BasicDrawer, drawerApi] = useVbenDrawer({
onBeforeClose,
onClosed: handleClosed,
onConfirm: handleConfirm,
async onOpenChange(isOpen) {
if (!isOpen) {
return null;
}
drawerApi.drawerLoading(true);
const { id } = drawerApi.getData() as { id?: number | string };
isUpdate.value = !!id;
if (isUpdate.value && id) {
const record = await ossConfigInfo(id);
await formApi.setValues(record);
}
await markInitialized();
drawerApi.drawerLoading(false);
},
});
async function handleConfirm() {
try {
drawerApi.lock(true);
/**
* 这里解构出来的values只能获取到自定义校验参数的值
* 需要自行调用formApi.getValues()获取表单值
*/
const { valid } = await formApi.validate();
if (!valid) {
return;
}
const data = cloneDeep(await formApi.getValues());
await (isUpdate.value ? ossConfigUpdate(data) : ossConfigAdd(data));
resetInitialized();
emit('reload');
drawerApi.close();
} catch (error) {
console.error(error);
} finally {
drawerApi.lock(false);
}
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
</script>
<template>
<BasicDrawer :title="title" class="w-[650px]">
<BasicForm>
<template #tip>
<div class="ml-7 w-full">
<Alert
message="私有桶使用自定义域名无法预览, 但可以正常上传/下载"
show-icon
type="warning"
/>
</div>
</template>
</BasicForm>
</BasicDrawer>
</template>
<style lang="scss" scoped>
:deep(.ant-divider) {
margin: 8px 0;
}
</style>