ruoyi-plus-soybean/src/views/system/tenant/modules/tenant-operate-drawer.vue
2025-03-19 23:27:42 +08:00

323 lines
9.4 KiB
Vue

<script setup lang="ts">
import { computed, reactive, ref, watch } from 'vue';
import { useLoading } from '@sa/hooks';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
import { fetchCreateTenant, fetchUpdateTenant } from '@/service/api/system/tenant';
import { fetchGetTenantPackageSelectList } from '@/service/api/system/tenantPackage';
defineOptions({
name: 'TenantOperateDrawer'
});
interface Props {
/** the type of operation */
operateType: NaiveUI.TableOperateType;
/** the edit row data */
rowData?: Api.System.Tenant | null;
}
const props = defineProps<Props>();
interface Emits {
(e: 'submitted'): void;
}
const emit = defineEmits<Emits>();
const visible = defineModel<boolean>('visible', {
default: false
});
const { formRef, validate, restoreValidation } = useNaiveForm();
const { createRequiredRule, patternRules } = useFormRules();
const { loading: packageLoading, startLoading: startPackageLoading, endLoading: endPackageLoading } = useLoading();
const title = computed(() => {
const titles: Record<NaiveUI.TableOperateType, string> = {
add: '新增租户',
edit: '编辑租户'
};
return titles[props.operateType];
});
type Model = Api.System.TenantOperateParams;
const model: Model = reactive(createDefaultModel());
function createDefaultModel(): Model {
return {
tenantId: '',
contactUserName: '',
contactPhone: '',
companyName: '',
licenseNumber: '',
address: '',
intro: '',
domain: '',
remark: '',
packageId: null,
expireTime: null,
accountCount: null,
status: '0',
username: '',
password: ''
};
}
type RuleKey = Extract<
keyof Model,
'id' | 'contactUserName' | 'contactPhone' | 'companyName' | 'packageId' | 'accountCount' | 'username' | 'password'
>;
const rules: Record<RuleKey, App.Global.FormRule | App.Global.FormRule[]> = {
id: createRequiredRule('id不能为空'),
contactUserName: createRequiredRule('联系人不能为空'),
contactPhone: [createRequiredRule('联系电话不能为空'), patternRules.phone],
companyName: createRequiredRule('企业名称不能为空'),
packageId: createRequiredRule('租户套餐不能为空'),
accountCount: createRequiredRule('用户数量不能为空'),
username: [
createRequiredRule('管理员账号不能为空'),
{
min: 2,
max: 20,
message: '账号长度必须介于2-20之间',
trigger: ['blur', 'change']
}
],
password: [
createRequiredRule('管理员密码不能为空'),
{
min: 5,
max: 20,
message: '密码长度必须介于5-20之间',
trigger: ['blur', 'change']
}
]
};
/** the enabled package options */
const packageOptions = ref<CommonType.Option<CommonType.IdType>[]>([]);
async function getPackageOptions() {
startPackageLoading();
const { error, data } = await fetchGetTenantPackageSelectList();
if (!error) {
packageOptions.value = data.map(item => ({
label: item.packageName,
value: item.packageId
}));
}
endPackageLoading();
}
function handleUpdateModelWhenEdit() {
if (props.operateType === 'add') {
Object.assign(model, createDefaultModel());
return;
}
if (props.operateType === 'edit' && props.rowData) {
Object.assign(model, props.rowData);
}
}
function closeDrawer() {
visible.value = false;
}
async function handleSubmit() {
await validate();
// request
if (props.operateType === 'add') {
const {
contactUserName,
contactPhone,
companyName,
licenseNumber,
address,
intro,
domain,
remark,
packageId,
expireTime,
accountCount,
status,
username,
password
} = model;
const { error } = await fetchCreateTenant({
contactUserName,
contactPhone,
companyName,
username,
password,
licenseNumber,
address,
intro,
domain,
remark,
packageId,
expireTime,
accountCount,
status
});
if (error) return;
}
if (props.operateType === 'edit') {
const {
id,
tenantId,
contactUserName,
contactPhone,
companyName,
licenseNumber,
address,
intro,
domain,
remark,
packageId,
expireTime,
accountCount,
status
} = model;
const { error } = await fetchUpdateTenant({
id,
tenantId,
contactUserName,
contactPhone,
companyName,
licenseNumber,
address,
intro,
domain,
remark,
packageId,
expireTime,
accountCount,
status
});
if (error) return;
}
window.$message?.success($t('common.updateSuccess'));
closeDrawer();
emit('submitted');
}
watch(visible, () => {
if (visible.value) {
getPackageOptions();
handleUpdateModelWhenEdit();
restoreValidation();
}
});
</script>
<template>
<NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
<NDrawerContent :title="title" :native-scrollbar="false" closable>
<NForm ref="formRef" :model="model" :rules="rules">
<NDivider>基本信息</NDivider>
<NFormItem label="企业名称" path="companyName">
<NInput v-model:value="model.companyName" placeholder="请输入企业名称" />
</NFormItem>
<NFormItem label="联系人" path="contactUserName">
<NInput v-model:value="model.contactUserName" placeholder="请输入联系人" />
</NFormItem>
<NFormItem label="联系电话" path="contactPhone">
<NInput v-model:value="model.contactPhone" placeholder="请输入联系电话" />
</NFormItem>
<div v-if="props.operateType === 'add'">
<NDivider>管理员信息</NDivider>
<NFormItem label="管理员账号" path="username">
<NInput v-model:value="model.username" placeholder="请输入管理员账号" />
</NFormItem>
<NFormItem label="管理员密码" path="password">
<NInput
v-model:value="model.password"
type="password"
show-password-on="click"
placeholder="请输入管理员密码"
/>
</NFormItem>
</div>
<NDivider>租户设置</NDivider>
<NFormItem label="租户套餐" path="packageId">
<NSelect
v-model:value="model.packageId"
clearable
:disabled="props.operateType === 'edit'"
placeholder="请选择租户套餐"
:options="packageOptions"
:loading="packageLoading"
/>
</NFormItem>
<NFormItem label="过期时间" path="expireTime">
<NDatePicker
v-model:formatted-value="model.expireTime"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
clearable
class="w-full"
/>
</NFormItem>
<NFormItem label="用户数量" path="accountCount">
<template #label>
<span class="flex-y-center">
用户数量
<NTooltip :show-arrow="false" trigger="hover">
<template #trigger>
<icon-mingcute:question-line class="ml-4px cursor-pointer text-14px" />
</template>
-1不限制用户数量
</NTooltip>
</span>
</template>
<NInputNumber v-model:value="model.accountCount" placeholder="请输入用户数量" min="-1" class="w-full" />
</NFormItem>
<NFormItem label="绑定域名" path="domain">
<template #label>
<span class="flex-y-center">
绑定域名
<NTooltip :show-arrow="false" trigger="hover">
<template #trigger>
<icon-mingcute:question-line class="ml-4px cursor-pointer text-14px" />
</template>
可填写域名/端口 填写域名如: www.test.com 或者 www.test.com:8080 填写ip:端口如: 127.0.0.1:8080
</NTooltip>
</span>
</template>
<NInputGroup>
<NInputGroupLabel>http(s)://</NInputGroupLabel>
<NInput v-model:value="model.domain" placeholder="请输入" />
</NInputGroup>
</NFormItem>
<NFormItem label="租户状态" path="status">
<DictRadio v-model:value="model.status" dict-code="sys_normal_disable" />
</NFormItem>
<NDivider>企业信息</NDivider>
<NFormItem label="企业地址" path="address">
<NInput v-model:value="model.address" placeholder="请输入企业地址" />
</NFormItem>
<NFormItem label="企业代码" path="licenseNumber">
<NInput v-model:value="model.licenseNumber" placeholder="请输入企业代码" />
</NFormItem>
<NFormItem label="企业简介" path="intro">
<NInput v-model:value="model.intro" type="textarea" placeholder="请输入企业简介" />
</NFormItem>
<NFormItem label="备注" path="remark">
<NInput v-model:value="model.remark" type="textarea" placeholder="请输入备注" />
</NFormItem>
</NForm>
<template #footer>
<NSpace :size="16">
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
<NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
</NSpace>
</template>
</NDrawerContent>
</NDrawer>
</template>
<style scoped></style>