feat: 支持网元分组填激活码
This commit is contained in:
@@ -12,7 +12,7 @@ export namespace LicenseApi {
|
|||||||
projectId?: number; // 项目ID
|
projectId?: number; // 项目ID
|
||||||
serialNo?: string; // sn
|
serialNo?: string; // sn
|
||||||
expiryDate: Dayjs | string; // 到期时间
|
expiryDate: Dayjs | string; // 到期时间
|
||||||
neList: number[]; // 网元开关
|
neList: number[]; // 网元
|
||||||
userNumber: number; // 用户数
|
userNumber: number; // 用户数
|
||||||
ranNumber: number; // 基站数
|
ranNumber: number; // 基站数
|
||||||
activationCode: string; // 激活码
|
activationCode: string; // 激活码
|
||||||
@@ -24,6 +24,12 @@ export namespace LicenseApi {
|
|||||||
status: number; // 状态
|
status: number; // 状态
|
||||||
remark: string; // 备注
|
remark: string; // 备注
|
||||||
action: number; // 操作
|
action: number; // 操作
|
||||||
|
neCodeList: NeCode[]; // 操作
|
||||||
|
}
|
||||||
|
export interface NeCode {
|
||||||
|
id: number; // 主键
|
||||||
|
neList: number[]; // 网元开关
|
||||||
|
activationCode: string; // 激活码
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,5 +26,9 @@
|
|||||||
"download": "Download",
|
"download": "Download",
|
||||||
"downloadFailed": "Download failed, please try again later",
|
"downloadFailed": "Download failed, please try again later",
|
||||||
"licenseFile": "License File",
|
"licenseFile": "License File",
|
||||||
"applySuccess": "Application successful, email reminder sent, please wait for approval"
|
"applySuccess": "Application successful, email reminder sent, please wait for approval",
|
||||||
|
"addNe": "Add Network Elements",
|
||||||
|
"enterCode": "Please enter Activation Code",
|
||||||
|
"selectNe": "Please select Network Element",
|
||||||
|
"detail": "detail"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,5 +26,9 @@
|
|||||||
"download": "下载",
|
"download": "下载",
|
||||||
"downloadFailed": "下载失败,请稍后重试",
|
"downloadFailed": "下载失败,请稍后重试",
|
||||||
"licenseFile": "License文件",
|
"licenseFile": "License文件",
|
||||||
"applySuccess": "申请成功,已发送邮件提醒,请等待审核"
|
"applySuccess": "申请成功,已发送邮件提醒,请等待审核",
|
||||||
|
"addNe": "添加网元",
|
||||||
|
"enterCode": "请输入激活码",
|
||||||
|
"selectNe": "请选择网元",
|
||||||
|
"detail": "详情"
|
||||||
}
|
}
|
||||||
|
|||||||
122
apps/web-antd/src/views/license/license/components/detail.vue
Normal file
122
apps/web-antd/src/views/license/license/components/detail.vue
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { LicenseApi } from '#/api/license/license';
|
||||||
|
|
||||||
|
import { h } from 'vue';
|
||||||
|
|
||||||
|
import { downloadFileFromBlobPart } from '@vben/utils';
|
||||||
|
|
||||||
|
import { Button, message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { useDescription } from '#/components/description';
|
||||||
|
import { DictTagGroup } from '#/components/dict-tag';
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
import { DICT_TYPE } from '#/utils';
|
||||||
|
|
||||||
|
import { useDetailSchema } from '../data';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
formData?: LicenseApi.License;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '网元',
|
||||||
|
dataIndex: 'neList',
|
||||||
|
key: 'neList',
|
||||||
|
customRender: (data: any) => {
|
||||||
|
return h(DictTagGroup, {
|
||||||
|
type: [
|
||||||
|
DICT_TYPE.LIC_NE_ALL,
|
||||||
|
DICT_TYPE.LIC_NE_5G,
|
||||||
|
DICT_TYPE.LIC_NE_4G,
|
||||||
|
DICT_TYPE.LIC_NE_23G,
|
||||||
|
DICT_TYPE.LIC_NE_ADD,
|
||||||
|
],
|
||||||
|
value: data.value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '激活码',
|
||||||
|
dataIndex: 'activationCode',
|
||||||
|
key: 'activationCode',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'License文件',
|
||||||
|
dataIndex: 'fileUrl',
|
||||||
|
key: 'fileUrl',
|
||||||
|
customRender: (data: any) => {
|
||||||
|
if (!data.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fileName = `${data.value?.slice(
|
||||||
|
Math.max(0, data.value.lastIndexOf('/') + 1),
|
||||||
|
data.value.lastIndexOf('_'),
|
||||||
|
)}.ini`;
|
||||||
|
// 创建下载链接
|
||||||
|
const link = h(
|
||||||
|
'span',
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
marginRight: '15px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fileName,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 创建下载按钮
|
||||||
|
const button = h(
|
||||||
|
Button,
|
||||||
|
{
|
||||||
|
onClick: async () => {
|
||||||
|
const res = await fetch(data.value);
|
||||||
|
if (!res.ok) {
|
||||||
|
message.error($t('license.downloadFailed'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const blob = await res.blob();
|
||||||
|
|
||||||
|
downloadFileFromBlobPart({ fileName, source: blob });
|
||||||
|
},
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
|
$t('license.download'),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 包裹容器
|
||||||
|
return h(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[link, button],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const [Description] = useDescription({
|
||||||
|
componentProps: {
|
||||||
|
bordered: true,
|
||||||
|
column: 1,
|
||||||
|
class: 'mx-4',
|
||||||
|
},
|
||||||
|
schema: useDetailSchema(),
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex-1 overflow-auto py-4">
|
||||||
|
<Description :data="props.formData" :label-style="{ width: '15%' }" />
|
||||||
|
<div class="mt-3">
|
||||||
|
<a-table
|
||||||
|
:data-source="props.formData?.neCodeList"
|
||||||
|
:columns="columns"
|
||||||
|
bordered
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
155
apps/web-antd/src/views/license/license/components/ne-code.vue
Normal file
155
apps/web-antd/src/views/license/license/components/ne-code.vue
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { FormInstance, SelectProps } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import type { LicenseApi } from '#/api/license/license';
|
||||||
|
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
|
||||||
|
import { MinusCircleOutlined, PlusOutlined } from '@vben/icons';
|
||||||
|
|
||||||
|
import { Textarea } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
import { DICT_TYPE, getDictOptions } from '#/utils';
|
||||||
|
|
||||||
|
const emit = defineEmits(['neCodeList']);
|
||||||
|
|
||||||
|
const neAllOptions = getDictOptions(DICT_TYPE.LIC_NE_ALL, 'number');
|
||||||
|
const ne5GOptions = getDictOptions(DICT_TYPE.LIC_NE_5G, 'number');
|
||||||
|
const ne4GOptions = getDictOptions(DICT_TYPE.LIC_NE_4G, 'number');
|
||||||
|
const ne23GOptions = getDictOptions(DICT_TYPE.LIC_NE_23G, 'number');
|
||||||
|
const neAddOptions = getDictOptions(DICT_TYPE.LIC_NE_ADD, 'number');
|
||||||
|
|
||||||
|
const options = ref<SelectProps['options']>([
|
||||||
|
{
|
||||||
|
label: '一体化',
|
||||||
|
options: neAllOptions,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '5G',
|
||||||
|
options: ne5GOptions,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '4G',
|
||||||
|
options: ne4GOptions,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '2/3G',
|
||||||
|
options: ne23GOptions,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '增值业务',
|
||||||
|
options: neAddOptions,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
let nextId = 2;
|
||||||
|
const formRef = ref<FormInstance>();
|
||||||
|
const dynamicValidateForm = reactive<{ neCodeList: LicenseApi.NeCode[] }>({
|
||||||
|
neCodeList: [{ neList: [], activationCode: '', id: 1 }],
|
||||||
|
});
|
||||||
|
const removeNeCode = (item: LicenseApi.NeCode) => {
|
||||||
|
const index = dynamicValidateForm.neCodeList.indexOf(item);
|
||||||
|
if (index !== -1) {
|
||||||
|
dynamicValidateForm.neCodeList.splice(index, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const addNeCode = () => {
|
||||||
|
dynamicValidateForm.neCodeList.push({
|
||||||
|
neList: [],
|
||||||
|
activationCode: '',
|
||||||
|
id: nextId++,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const filterOption = (input: string, option: any) => {
|
||||||
|
return option.label.toLowerCase().includes(input.toLowerCase());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = () => {
|
||||||
|
emit('neCodeList', dynamicValidateForm.neCodeList);
|
||||||
|
};
|
||||||
|
|
||||||
|
const availableOptions = (groupIdx: number) => {
|
||||||
|
// 其他分组已选标签
|
||||||
|
const otherSelected = new Set(
|
||||||
|
dynamicValidateForm.neCodeList
|
||||||
|
.filter((_, idx) => idx !== groupIdx)
|
||||||
|
.flatMap((g) => g.neList),
|
||||||
|
);
|
||||||
|
// return ne5GOptions.filter((tag) => !otherSelected.has(tag.value));
|
||||||
|
return options.value?.map((item) => ({
|
||||||
|
...item,
|
||||||
|
options: item.options.filter(
|
||||||
|
(option: any) => !otherSelected.has(option.value),
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const validate = () => formRef.value?.validate();
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
validate,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
name="dynamic_form_nest_item"
|
||||||
|
:model="dynamicValidateForm"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(neCode, index) in dynamicValidateForm.neCodeList"
|
||||||
|
:key="neCode.id"
|
||||||
|
class="flex w-full gap-1"
|
||||||
|
>
|
||||||
|
<a-form-item
|
||||||
|
:name="['neCodeList', index, 'neList']"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
message: $t('license.selectNe'),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
v-model:value="neCode.neList"
|
||||||
|
mode="multiple"
|
||||||
|
allow-clear
|
||||||
|
show-search
|
||||||
|
style="width: 220px"
|
||||||
|
:options="availableOptions(index)"
|
||||||
|
:filter-option="filterOption"
|
||||||
|
:placeholder="$t('license.selectNe')"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:name="['neCodeList', index, 'activationCode']"
|
||||||
|
:rules="{
|
||||||
|
required: true,
|
||||||
|
message: $t('license.enterCode'),
|
||||||
|
}"
|
||||||
|
class="flex-1"
|
||||||
|
>
|
||||||
|
<Textarea
|
||||||
|
:placeholder="$t('license.enterCode')"
|
||||||
|
allow-clear
|
||||||
|
v-model:value="neCode.activationCode"
|
||||||
|
:rows="1"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="dynamicValidateForm.neCodeList.length > 1">
|
||||||
|
<MinusCircleOutlined
|
||||||
|
@click="removeNeCode(neCode)"
|
||||||
|
class="mt-1 cursor-pointer"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
<a-form-item>
|
||||||
|
<a-button type="dashed" block @click="addNeCode">
|
||||||
|
<PlusOutlined class="mb-1" />
|
||||||
|
{{ $t('license.addNe') }}
|
||||||
|
</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</template>
|
||||||
@@ -8,16 +8,14 @@ import type { DescriptionItemSchema } from '#/components/description';
|
|||||||
import { h, ref } from 'vue';
|
import { h, ref } from 'vue';
|
||||||
|
|
||||||
import { useAccess } from '@vben/access';
|
import { useAccess } from '@vben/access';
|
||||||
import { downloadFileFromBlobPart, formatDateTime } from '@vben/utils';
|
import { formatDateTime } from '@vben/utils';
|
||||||
|
|
||||||
import { Button, message } from 'ant-design-vue';
|
|
||||||
|
|
||||||
import { z } from '#/adapter/form';
|
import { z } from '#/adapter/form';
|
||||||
import { getCustomerList } from '#/api/license/customer';
|
import { getCustomerList } from '#/api/license/customer';
|
||||||
import { isLicenseSnUnique } from '#/api/license/license';
|
import { isLicenseSnUnique } from '#/api/license/license';
|
||||||
import { getProjectList } from '#/api/license/project';
|
import { getProjectList } from '#/api/license/project';
|
||||||
import { getLicenseAdminList, getSimpleUserList } from '#/api/system/user';
|
import { getLicenseAdminList, getSimpleUserList } from '#/api/system/user';
|
||||||
import { DictTag, DictTagGroup } from '#/components/dict-tag';
|
import { DictTag } from '#/components/dict-tag';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
|
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
|
||||||
|
|
||||||
@@ -128,18 +126,26 @@ export function useFormSchema(): VbenFormSchema[] {
|
|||||||
valueFormat: 'x',
|
valueFormat: 'x',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// fieldName: 'neList',
|
||||||
|
// label: $t('license.neList'),
|
||||||
|
// component: 'CheckboxGroup',
|
||||||
|
// formItemClass: 'col-span-2',
|
||||||
|
// modelPropName: 'modelValue',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// fieldName: 'activationCode',
|
||||||
|
// label: $t('license.activationCode'),
|
||||||
|
// component: 'Textarea',
|
||||||
|
// formItemClass: 'col-span-2',
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
fieldName: 'neList',
|
fieldName: 'neCodeList',
|
||||||
label: $t('license.neList'),
|
label: $t('license.neList'),
|
||||||
component: 'CheckboxGroup',
|
component: '',
|
||||||
formItemClass: 'col-span-2',
|
formItemClass: 'col-span-2',
|
||||||
modelPropName: 'modelValue',
|
modelPropName: 'modelValue',
|
||||||
},
|
rules: z.string(),
|
||||||
{
|
|
||||||
fieldName: 'activationCode',
|
|
||||||
label: $t('license.activationCode'),
|
|
||||||
component: 'Textarea',
|
|
||||||
formItemClass: 'col-span-2',
|
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// fieldName: 'licenseContent',
|
// fieldName: 'licenseContent',
|
||||||
@@ -408,7 +414,15 @@ export function useGridColumns(
|
|||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
cellRender: {
|
cellRender: {
|
||||||
name: 'CellDictGroup',
|
name: 'CellDictGroup',
|
||||||
props: { type: DICT_TYPE.LIC_NE_LIST },
|
props: {
|
||||||
|
type: [
|
||||||
|
DICT_TYPE.LIC_NE_ALL,
|
||||||
|
DICT_TYPE.LIC_NE_5G,
|
||||||
|
DICT_TYPE.LIC_NE_4G,
|
||||||
|
DICT_TYPE.LIC_NE_23G,
|
||||||
|
DICT_TYPE.LIC_NE_ADD,
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -487,10 +501,14 @@ export function useGridColumns(
|
|||||||
},
|
},
|
||||||
name: 'CellOperation',
|
name: 'CellOperation',
|
||||||
options: [
|
options: [
|
||||||
// {
|
{
|
||||||
// code: 'edit',
|
code: 'detail',
|
||||||
// show: hasAccessByCodes(['license:license:update']),
|
text: $t('license.detail'),
|
||||||
// },
|
},
|
||||||
|
{
|
||||||
|
code: 'edit',
|
||||||
|
show: hasAccessByCodes(['license:license:update']),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
code: 'apply',
|
code: 'apply',
|
||||||
text: $t('license.apply'),
|
text: $t('license.apply'),
|
||||||
@@ -550,16 +568,16 @@ export function useDetailSchema(): DescriptionItemSchema[] {
|
|||||||
return formatDateTime(data?.expiryDate) as string;
|
return formatDateTime(data?.expiryDate) as string;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
field: 'neList',
|
// field: 'neList',
|
||||||
label: $t('license.neList'),
|
// label: $t('license.neList'),
|
||||||
content: (data) => {
|
// content: (data) => {
|
||||||
return h(DictTagGroup, {
|
// return h(DictTagGroup, {
|
||||||
type: DICT_TYPE.LIC_NE_LIST,
|
// type: DICT_TYPE.LIC_NE_LIST,
|
||||||
value: data.neList,
|
// value: data.neList,
|
||||||
});
|
// });
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
field: 'userNumber',
|
field: 'userNumber',
|
||||||
label: $t('license.userNumber'),
|
label: $t('license.userNumber'),
|
||||||
@@ -592,58 +610,59 @@ export function useDetailSchema(): DescriptionItemSchema[] {
|
|||||||
{
|
{
|
||||||
field: 'remark',
|
field: 'remark',
|
||||||
label: $t('license.remark'),
|
label: $t('license.remark'),
|
||||||
|
hidden: (data) => data,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
field: 'fileUrl',
|
// field: 'fileUrl',
|
||||||
label: $t('license.licenseFile'),
|
// label: $t('license.licenseFile'),
|
||||||
hidden: (data) => data.status !== 2,
|
// hidden: (data) => data.status !== 2,
|
||||||
content: (data) => {
|
// content: (data) => {
|
||||||
const fileName = `${data.fileUrl?.slice(
|
// const fileName = `${data.fileUrl?.slice(
|
||||||
Math.max(0, data.fileUrl.lastIndexOf('/') + 1),
|
// Math.max(0, data.fileUrl.lastIndexOf('/') + 1),
|
||||||
data.fileUrl.lastIndexOf('_'),
|
// data.fileUrl.lastIndexOf('_'),
|
||||||
)}.ini`;
|
// )}.ini`;
|
||||||
// 创建下载链接
|
// // 创建下载链接
|
||||||
const link = h(
|
// const link = h(
|
||||||
'span',
|
// 'span',
|
||||||
{
|
// {
|
||||||
style: {
|
// style: {
|
||||||
marginRight: '15px',
|
// marginRight: '15px',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
fileName,
|
// fileName,
|
||||||
);
|
// );
|
||||||
|
|
||||||
// 创建下载按钮
|
// // 创建下载按钮
|
||||||
const button = h(
|
// const button = h(
|
||||||
Button,
|
// Button,
|
||||||
{
|
// {
|
||||||
onClick: async () => {
|
// onClick: async () => {
|
||||||
const res = await fetch(data.fileUrl);
|
// const res = await fetch(data.fileUrl);
|
||||||
if (!res.ok) {
|
// if (!res.ok) {
|
||||||
message.error($t('license.downloadFailed'));
|
// message.error($t('license.downloadFailed'));
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
const blob = await res.blob();
|
// const blob = await res.blob();
|
||||||
|
|
||||||
downloadFileFromBlobPart({ fileName, source: blob });
|
// downloadFileFromBlobPart({ fileName, source: blob });
|
||||||
},
|
// },
|
||||||
type: 'primary',
|
// type: 'primary',
|
||||||
},
|
// },
|
||||||
$t('license.download'),
|
// $t('license.download'),
|
||||||
);
|
// );
|
||||||
|
|
||||||
// 包裹容器
|
// // 包裹容器
|
||||||
return h(
|
// return h(
|
||||||
'div',
|
// 'div',
|
||||||
{
|
// {
|
||||||
style: {
|
// style: {
|
||||||
display: 'flex',
|
// display: 'flex',
|
||||||
alignItems: 'center',
|
// alignItems: 'center',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
[link, button],
|
// [link, button],
|
||||||
);
|
// );
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,9 @@ import { useTabs } from '@vben/hooks';
|
|||||||
import { Button, message } from 'ant-design-vue';
|
import { Button, message } from 'ant-design-vue';
|
||||||
|
|
||||||
import { generateLicense, getLicense } from '#/api/license/license';
|
import { generateLicense, getLicense } from '#/api/license/license';
|
||||||
import { useDescription } from '#/components/description';
|
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { useDetailSchema } from '../data';
|
import Detail from '../components/detail.vue';
|
||||||
|
|
||||||
const { hasAccessByCodes } = useAccess();
|
const { hasAccessByCodes } = useAccess();
|
||||||
|
|
||||||
@@ -23,15 +22,6 @@ const router = useRouter();
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const formData = ref<LicenseApi.License>();
|
const formData = ref<LicenseApi.License>();
|
||||||
|
|
||||||
const [Description] = useDescription({
|
|
||||||
componentProps: {
|
|
||||||
bordered: true,
|
|
||||||
column: 1,
|
|
||||||
class: 'mx-4',
|
|
||||||
},
|
|
||||||
schema: useDetailSchema(),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** 获取详情数据 */
|
/** 获取详情数据 */
|
||||||
async function getDetail(id: any) {
|
async function getDetail(id: any) {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
@@ -39,7 +29,8 @@ async function getDetail(id: any) {
|
|||||||
}
|
}
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
formData.value = await getLicense(id);
|
const details = await getLicense(id);
|
||||||
|
formData.value = details;
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
@@ -96,9 +87,7 @@ getDetail(route.query.id);
|
|||||||
<template>
|
<template>
|
||||||
<Page auto-content-height v-loading="loading">
|
<Page auto-content-height v-loading="loading">
|
||||||
<div class="bg-card flex h-[100%] flex-col rounded-md p-4">
|
<div class="bg-card flex h-[100%] flex-col rounded-md p-4">
|
||||||
<div class="flex-1 overflow-auto py-4">
|
<Detail :form-data="formData" />
|
||||||
<Description :data="formData" :label-style="{ width: '250px' }" />
|
|
||||||
</div>
|
|
||||||
<div class="mt-4 flex justify-center space-x-2">
|
<div class="mt-4 flex justify-center space-x-2">
|
||||||
<Button @click="close"> {{ $t('common.back') }}</Button>
|
<Button @click="close"> {{ $t('common.back') }}</Button>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { useGridColumns, useGridFormSchema } from './data';
|
import { useGridColumns, useGridFormSchema } from './data';
|
||||||
|
import Detail from './modules/detail.vue';
|
||||||
import Form from './modules/form.vue';
|
import Form from './modules/form.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -30,6 +31,11 @@ const [FormModal, formModalApi] = useVbenModal({
|
|||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [DetailModal, detailModalApi] = useVbenModal({
|
||||||
|
connectedComponent: Detail,
|
||||||
|
destroyOnClose: true,
|
||||||
|
});
|
||||||
|
|
||||||
/** 刷新表格 */
|
/** 刷新表格 */
|
||||||
function onRefresh() {
|
function onRefresh() {
|
||||||
gridApi.query();
|
gridApi.query();
|
||||||
@@ -50,6 +56,11 @@ function onGenerate(row: LicenseApi.License) {
|
|||||||
router.push({ name: 'LicenseGenerate', query: { id: row.id } });
|
router.push({ name: 'LicenseGenerate', query: { id: row.id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 详情License */
|
||||||
|
function onDetail(row: LicenseApi.License) {
|
||||||
|
detailModalApi.setData(row).open();
|
||||||
|
}
|
||||||
|
|
||||||
/** 下载License */
|
/** 下载License */
|
||||||
async function onDownload(row: LicenseApi.License) {
|
async function onDownload(row: LicenseApi.License) {
|
||||||
const fileName = `${row.fileUrl?.slice(
|
const fileName = `${row.fileUrl?.slice(
|
||||||
@@ -105,6 +116,10 @@ function onActionClick({ code, row }: OnActionClickParams<LicenseApi.License>) {
|
|||||||
onDelete(row);
|
onDelete(row);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'detail': {
|
||||||
|
onDetail(row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'download': {
|
case 'download': {
|
||||||
onDownload(row);
|
onDownload(row);
|
||||||
break;
|
break;
|
||||||
@@ -162,7 +177,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
<template>
|
<template>
|
||||||
<Page auto-content-height>
|
<Page auto-content-height>
|
||||||
<FormModal @success="onRefresh" />
|
<FormModal @success="onRefresh" />
|
||||||
|
<DetailModal @success="onRefresh" />
|
||||||
<Grid :table-title="$t('license.list')">
|
<Grid :table-title="$t('license.list')">
|
||||||
<template #toolbar-tools>
|
<template #toolbar-tools>
|
||||||
<TableAction
|
<TableAction
|
||||||
|
|||||||
51
apps/web-antd/src/views/license/license/modules/detail.vue
Normal file
51
apps/web-antd/src/views/license/license/modules/detail.vue
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { LicenseApi } from '#/api/license/license';
|
||||||
|
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import Detail from '../components/detail.vue';
|
||||||
|
|
||||||
|
const formData = ref<LicenseApi.License>();
|
||||||
|
|
||||||
|
// const [Descriptions] = useDescription({
|
||||||
|
// componentProps: {
|
||||||
|
// bordered: true,
|
||||||
|
// column: 1,
|
||||||
|
// class: 'mx-4',
|
||||||
|
// },
|
||||||
|
// schema: useDetailSchema(),
|
||||||
|
// });
|
||||||
|
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
async onOpenChange(isOpen: boolean) {
|
||||||
|
if (!isOpen) {
|
||||||
|
formData.value = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 加载数据
|
||||||
|
const data = modalApi.getData<LicenseApi.License>();
|
||||||
|
if (!data || !data.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modalApi.lock();
|
||||||
|
try {
|
||||||
|
formData.value = data;
|
||||||
|
} finally {
|
||||||
|
modalApi.unlock();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal
|
||||||
|
title="License详情"
|
||||||
|
class="w-2/3"
|
||||||
|
:show-cancel-button="false"
|
||||||
|
:show-confirm-button="false"
|
||||||
|
>
|
||||||
|
<Detail :form-data="formData" />
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { LicenseApi } from '#/api/license/license';
|
import type { LicenseApi } from '#/api/license/license';
|
||||||
|
|
||||||
import { computed, reactive, watch } from 'vue';
|
import { computed, reactive, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
import { DICT_TYPE, getDictOptions } from '#/utils';
|
import { DICT_TYPE, getDictOptions } from '#/utils';
|
||||||
|
|
||||||
|
import NeCode from '../components/ne-code.vue';
|
||||||
import { formData, useFormSchema } from '../data';
|
import { formData, useFormSchema } from '../data';
|
||||||
|
|
||||||
const emit = defineEmits(['success']);
|
const emit = defineEmits(['success']);
|
||||||
@@ -26,7 +27,9 @@ const state = reactive({
|
|||||||
indeterminate: false,
|
indeterminate: false,
|
||||||
checkAll: false,
|
checkAll: false,
|
||||||
checkedList: [] as number[],
|
checkedList: [] as number[],
|
||||||
|
neCodeList: [] as LicenseApi.NeCode[],
|
||||||
});
|
});
|
||||||
|
const neCodeRef = ref();
|
||||||
|
|
||||||
const getTitle = computed(() => {
|
const getTitle = computed(() => {
|
||||||
if (formData.value?.id) {
|
if (formData.value?.id) {
|
||||||
@@ -54,6 +57,7 @@ const [Form, formApi] = useVbenForm({
|
|||||||
labelWidth: 80,
|
labelWidth: 80,
|
||||||
},
|
},
|
||||||
layout: 'horizontal',
|
layout: 'horizontal',
|
||||||
|
// fieldMappingTime: [['field4', ['phoneType', 'phoneNumber'], null]],
|
||||||
schema: useFormSchema(),
|
schema: useFormSchema(),
|
||||||
showDefaultActions: false,
|
showDefaultActions: false,
|
||||||
// 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
|
// 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
|
||||||
@@ -80,6 +84,11 @@ watch(
|
|||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
async onConfirm() {
|
async onConfirm() {
|
||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
|
try {
|
||||||
|
await neCodeRef.value[0].validate();
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -87,6 +96,7 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
// 提交表单
|
// 提交表单
|
||||||
const data = (await formApi.getValues()) as LicenseApi.License;
|
const data = (await formApi.getValues()) as LicenseApi.License;
|
||||||
data.neList = state.checkedList;
|
data.neList = state.checkedList;
|
||||||
|
data.neCodeList = state.neCodeList;
|
||||||
const action = formData.value?.action || 0;
|
const action = formData.value?.action || 0;
|
||||||
try {
|
try {
|
||||||
if (formData.value?.id) {
|
if (formData.value?.id) {
|
||||||
@@ -122,23 +132,29 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
const action = data.action || 0; // 确保 action 字段存在
|
const action = data.action || 0; // 确保 action 字段存在
|
||||||
formData.value = { ...data, action };
|
formData.value = { ...data, action };
|
||||||
data = await getLicense(data.id);
|
data = await getLicense(data.id);
|
||||||
data = { ...data, action }; // 保持 action 字段
|
|
||||||
} finally {
|
} finally {
|
||||||
modalApi.unlock();
|
modalApi.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// const neCodeList = data.neCodeList || [{ neList: [], activationCode: '' }];
|
||||||
|
// data = { ...data, neCodeList };
|
||||||
// 处理数据
|
// 处理数据
|
||||||
data.expiryDate = data.expiryDate ? data.expiryDate.toString() : '';
|
data.expiryDate = data.expiryDate ? data.expiryDate.toString() : '';
|
||||||
// 设置到 values
|
// 设置到 values
|
||||||
formData.value = data;
|
formData.value = data;
|
||||||
state.checkedList = data.neList || [];
|
state.checkedList = data.neList || [];
|
||||||
|
state.neCodeList = data.neCodeList || [];
|
||||||
await formApi.setValues(formData.value);
|
await formApi.setValues(formData.value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getNeCodeList = (neCodeList: LicenseApi.NeCode[]) => {
|
||||||
|
state.neCodeList = neCodeList;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal :title="getTitle" class="w-[800px]" :confirm-text="getConfirmText">
|
<Modal :title="getTitle" class="w-2/3" :confirm-text="getConfirmText">
|
||||||
<Form class="mx-4">
|
<Form class="mx-4">
|
||||||
<template #neList="slotProps">
|
<template #neList="slotProps">
|
||||||
<a-row>
|
<a-row>
|
||||||
@@ -159,6 +175,14 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
/>
|
/>
|
||||||
</a-row>
|
</a-row>
|
||||||
</template>
|
</template>
|
||||||
|
<template #neCodeList="slotProps">
|
||||||
|
<NeCode
|
||||||
|
v-bind="slotProps"
|
||||||
|
@ne-code-list="getNeCodeList"
|
||||||
|
ref="neCodeRef"
|
||||||
|
v-model:value="state.neCodeList"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user