Browse Source

Merge pull request #773 from colinin/upt-7.0.1

Multiple update fixes
pull/786/head
yx lin 3 years ago
committed by GitHub
parent
commit
e44ae38bd5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 121
      apps/vue/src/api/platform/package/index.ts
  2. 84
      apps/vue/src/api/platform/package/model/index.ts
  3. 65
      apps/vue/src/views/platform/package/components/PackageModal.vue
  4. 98
      apps/vue/src/views/platform/package/components/PackageTable.vue
  5. 119
      apps/vue/src/views/platform/package/datas/ModalData.ts
  6. 118
      apps/vue/src/views/platform/package/datas/TableData.ts
  7. 13
      apps/vue/src/views/platform/package/index.vue
  8. 2
      aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj
  9. 7
      aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/TypeScript/TypeScriptServiceProxyGenerator.cs
  10. 54
      aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Vben/VbenModelScriptGenerator.cs
  11. 4
      aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json
  12. 7
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Localization/Resources/en.json
  13. 7
      aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Localization/Resources/zh-Hans.json

121
apps/vue/src/api/platform/package/index.ts

@ -0,0 +1,121 @@
import { defAbpHttp } from '/@/utils/http/abp';
import {
PackageCreateDto,
PackageDto,
PackageBlobUploadDto,
PackageBlobDto,
PackageBlobRemoveDto,
PackageBlobDownloadInput,
PackageGetLatestInput,
PackageGetPagedListInput,
PackageUpdateDto
} from './model';
const remoteServiceName = 'Platform';
const controllerName = 'Package';
export const CreateAsyncByInput = (input: PackageCreateDto) => {
return defAbpHttp.request<PackageDto>({
service: remoteServiceName,
controller: controllerName,
action: 'CreateAsync',
uniqueName: 'CreateAsyncByInput',
params: {
},
data: input,
});
};
export const DeleteAsyncById = (id: string) => {
return defAbpHttp.request<void>({
service: remoteServiceName,
controller: controllerName,
action: 'DeleteAsync',
uniqueName: 'DeleteAsyncById',
params: {
id: id,
},
});
};
export const UploadBlobAsyncByIdAndInput = (id: string, input: PackageBlobUploadDto) => {
return defAbpHttp.request<PackageBlobDto>({
service: remoteServiceName,
controller: controllerName,
action: 'UploadBlobAsync',
uniqueName: 'UploadBlobAsyncByIdAndInput',
params: id,
data: input,
});
};
export const RemoveBlobAsyncByIdAndInput = (id: string, input: PackageBlobRemoveDto) => {
return defAbpHttp.request<void>({
service: remoteServiceName,
controller: controllerName,
action: 'RemoveBlobAsync',
uniqueName: 'RemoveBlobAsyncByIdAndInput',
params: {
id: id,
input: input,
},
});
};
export const DownloadBlobAsyncByIdAndInput = (id: string, input: PackageBlobDownloadInput) => {
return defAbpHttp.request<Blob>({
service: remoteServiceName,
controller: controllerName,
action: 'DownloadBlobAsync',
uniqueName: 'DownloadBlobAsyncByIdAndInput',
params: {
id: id,
input: input,
},
},{
withToken: false,
});
};
export const GetAsyncById = (id: string) => {
return defAbpHttp.request<PackageDto>({
service: remoteServiceName,
controller: controllerName,
action: 'GetAsync',
uniqueName: 'GetAsyncById',
params: {
id: id,
},
},{
withToken: false,
});
};
export const GetLatestAsyncByInput = (input: PackageGetLatestInput) => {
return defAbpHttp.request<PackageDto>({
service: remoteServiceName,
controller: controllerName,
action: 'GetLatestAsync',
uniqueName: 'GetLatestAsyncByInput',
params: {
input: input,
},
},{
withToken: false,
});
};
export const GetListAsyncByInput = (input: PackageGetPagedListInput) => {
return defAbpHttp.pagedRequest<PackageDto>({
service: remoteServiceName,
controller: controllerName,
action: 'GetListAsync',
uniqueName: 'GetListAsyncByInput',
params: {
input: input,
},
});
};
export const UpdateAsyncByIdAndInput = (id: string, input: PackageUpdateDto) => {
return defAbpHttp.request<PackageDto>({
service: remoteServiceName,
controller: controllerName,
action: 'UpdateAsync',
uniqueName: 'UpdateAsyncByIdAndInput',
params: id,
data: input,
});
};

84
apps/vue/src/api/platform/package/model/index.ts

@ -0,0 +1,84 @@
export interface PackageCreateDto extends PackageCreateOrUpdateDto {
name: string;
version: string;
}
export interface PackageBlobUploadDto {
name: string;
size?: number;
summary?: string;
contentType?: string;
createdAt?: string;
updatedAt?: string;
license?: string;
authors?: string;
file: Blob;
}
export interface PackageBlobRemoveDto {
name: string;
}
export interface PackageBlobDownloadInput {
name: string;
}
export interface PackageGetLatestInput {
name: string;
}
export interface PackageGetPagedListInput extends PagedAndSortedResultRequestDto {
filter?: string;
name?: string;
note?: string;
version?: string;
description?: string;
forceUpdate?: boolean;
authors?: string;
}
export interface PackageUpdateDto extends PackageCreateOrUpdateDto {
concurrencyStamp?: string;
}
export interface PackageCreateOrUpdateDto {
note: string;
description?: string;
forceUpdate?: boolean;
authors?: string;
level?: PackageLevel;
}
export enum PackageLevel {
Resource = 0,
Full = 1,
None = -1,
}
export interface PackageBlobDto extends CreationAuditedEntityDto<number> {
name?: string;
url?: string;
size?: number;
summary?: string;
createdAt?: string;
updatedAt?: string;
license?: string;
authors?: string;
sHA256?: string;
contentType?: string;
downloadCount?: number;
extraProperties?: Dictionary<string, any>;
}
export interface PackageDto extends ExtensibleAuditedEntityDto<string> {
concurrencyStamp?: string;
name?: string;
note?: string;
version?: string;
description?: string;
forceUpdate?: boolean;
authors?: string;
level?: PackageLevel;
blobs?: PackageBlobDto[];
}

65
apps/vue/src/views/platform/package/components/PackageModal.vue

@ -0,0 +1,65 @@
<template>
<BasicModal
:title="L('Packages')"
:can-fullscreen="false"
:show-ok-btn="true"
:width="800"
:height="500"
@register="registerModal"
@ok="handleSubmit"
>
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { nextTick } from 'vue';
import { BasicForm, useForm } from '/@/components/Form';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { useMessage } from '/@/hooks/web/useMessage';
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { getModalFormSchemas } from '../datas/ModalData';
import { formatToDateTime } from '/@/utils/dateUtil';
import { GetAsyncById, CreateAsyncByInput, UpdateAsyncByIdAndInput } from '/@/api/platform/package';
const emits = defineEmits(['change', 'register']);
const { createMessage } = useMessage();
const { L } = useLocalization(['Platform', 'AbpUi']);
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({
layout: 'vertical',
showActionButtonGroup: false,
schemas: getModalFormSchemas(),
transformDateFunc: (date) => {
return date ? formatToDateTime(date) : '';
},
});
const [registerModal, { closeModal }] = useModalInner((data) => {
nextTick(() => {
resetFields();
if (data.id) {
fetchEntity(data.id);
}
});
});
function fetchEntity(id: string) {
GetAsyncById(id).then((dto) => {
setFieldsValue(dto);
});
}
function handleSubmit() {
validate().then((input) => {
const api = input.id
? UpdateAsyncByIdAndInput(input.id, input)
: CreateAsyncByInput(input);
api.then((dto) => {
createMessage.success(L('SuccessfullySaved'));
emits('change', dto);
closeModal();
});
});
}
</script>

98
apps/vue/src/views/platform/package/components/PackageTable.vue

@ -0,0 +1,98 @@
<template>
<div>
<BasicTable @register="registerTable">
<template #toolbar>
<Button
v-auth="['Platform.Package.Create']"
type="primary"
@click="handleAddNew"
>
{{ L('Package:AddNew') }}
</Button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:stop-button-propagation="true"
:actions="[
{
auth: 'Platform.Package.Update',
label: L('Edit'),
icon: 'ant-design:edit-outlined',
onClick: handleEdit.bind(null, record),
},
{
auth: 'Platform.Package.Delete',
label: L('Delete'),
color: 'error',
icon: 'ant-design:delete-outlined',
onClick: handleDelete.bind(null, record),
},
]"
/>
</template>
</template>
</BasicTable>
<PackageModal @register="registerModal" @change="reload" />
</div>
</template>
<script lang="ts" setup>
import { Button } from 'ant-design-vue';
import { BasicTable, TableAction, useTable } from '/@/components/Table';
import { getDataColumns } from '../datas/TableData';
import { getSearchFormProps } from '../datas/ModalData';
import { useModal } from '/@/components/Modal';
import { useMessage } from '/@/hooks/web/useMessage';
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { GetListAsyncByInput, DeleteAsyncById } from '/@/api/platform/package';
import { formatPagedRequest } from '/@/utils/http/abp/helper';
import PackageModal from './PackageModal.vue';
const { L } = useLocalization(['Platform', 'AbpUi']);
const { createConfirm, createMessage } = useMessage();
const [registerModal, { openModal }] = useModal();
const [registerTable, { reload }] = useTable({
rowKey: 'id',
title: L('Packages'),
api: GetListAsyncByInput,
columns: getDataColumns(),
beforeFetch: formatPagedRequest,
pagination: true,
striped: false,
useSearchForm: true,
showIndexColumn: false,
showTableSetting: true,
formConfig: getSearchFormProps(),
bordered: true,
canResize: true,
immediate: true,
actionColumn: {
width: 150,
title: L('Actions'),
dataIndex: 'action',
},
});
function handleAddNew() {
openModal(true, {});
}
function handleEdit(record) {
openModal(true, record);
}
function handleDelete(record) {
createConfirm({
iconType: 'warning',
title: L('AreYouSure'),
content: L('ItemWillBeDeletedMessage'),
onOk: () => {
return DeleteAsyncById(record.id).then(() => {
createMessage.success(L('SuccessfullyDeleted'));
reload();
});
},
});
}
</script>

119
apps/vue/src/views/platform/package/datas/ModalData.ts

@ -0,0 +1,119 @@
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { FormProps, FormSchema } from '/@/components/Form';
const { L } = useLocalization(['Platform', 'AbpUi']);
export function getSearchFormProps(): Partial<FormProps> {
return {
labelWidth: 100,
schemas: [
{
field: 'filter',
component: 'Input',
label: L('Search'),
colProps: {span: 24},
},
{
field: 'name',
component: 'Input',
label: L('DisplayName:Name'),
colProps: {span: 8},
},
{
field: 'note',
component: 'Input',
label: L('DisplayName:Note'),
colProps: {span: 8},
},
{
field: 'version',
component: 'Input',
label: L('DisplayName:Version'),
colProps: {span: 8},
},
{
field: 'description',
component: 'Input',
label: L('DisplayName:Description'),
colProps: {span: 8},
},
{
field: 'forceUpdate',
component: 'Input',
label: L('DisplayName:ForceUpdate'),
colProps: {span: 8},
},
{
field: 'authors',
component: 'Input',
label: L('DisplayName:Authors'),
colProps: {span: 8},
}
],
};
}
export function getModalFormSchemas(): FormSchema[] {
return [
{
field: 'note',
component: 'Input',
label: L('DisplayName:Note'),
colProps: {span: 24},
componentProps: {},
},
{
field: 'description',
component: 'Input',
label: L('DisplayName:Description'),
colProps: {span: 24},
componentProps: {},
},
{
field: 'forceUpdate',
component: 'Input',
label: L('DisplayName:ForceUpdate'),
colProps: {span: 24},
componentProps: {},
},
{
field: 'authors',
component: 'Input',
label: L('DisplayName:Authors'),
colProps: {span: 24},
componentProps: {},
},
{
field: 'name',
component: 'Input',
label: L('DisplayName:Name'),
colProps: {span: 24},
componentProps: {},
},
{
field: 'version',
component: 'Input',
label: L('DisplayName:Version'),
colProps: {span: 24},
componentProps: {},
},
{
field: 'id',
component: 'Input',
label: 'id',
show: false,
dynamicDisabled: true,
colProps: {span: 24},
componentProps: {},
},
{
field: 'concurrencyStamp',
component: 'Input',
label: 'concurrencyStamp',
show: false,
dynamicDisabled: true,
colProps: {span: 24},
componentProps: {},
},
];
}

118
apps/vue/src/views/platform/package/datas/TableData.ts

@ -0,0 +1,118 @@
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { BasicColumn } from '/@/components/Table';
import { formatToDateTime } from '/@/utils/dateUtil';
const { L } = useLocalization(['Platform', 'AbpUi']);
export function getDataColumns(): BasicColumn[] {
return [
{
title: L('DisplayName:Id'),
dataIndex: 'id',
align: 'left',
width: 1,
sorter: true,
resizable: true,
ifShow: false,
},
{
title: L('DisplayName:CreationTime'),
dataIndex: 'creationTime',
align: 'left',
width: 1,
sorter: true,
resizable: true,
ifShow: false,
format: (text) => {
return text ? formatToDateTime(text) : text;
}
},
{
title: L('DisplayName:CreatorId'),
dataIndex: 'creatorId',
align: 'left',
width: 1,
sorter: true,
resizable: true,
ifShow: false,
},
{
title: L('DisplayName:LastModificationTime'),
dataIndex: 'lastModificationTime',
align: 'left',
width: 1,
sorter: true,
resizable: true,
ifShow: false,
format: (text) => {
return text ? formatToDateTime(text) : text;
}
},
{
title: L('DisplayName:LastModifierId'),
dataIndex: 'lastModifierId',
align: 'left',
width: 1,
sorter: true,
resizable: true,
ifShow: false,
},
{
title: L('DisplayName:ConcurrencyStamp'),
dataIndex: 'concurrencyStamp',
align: 'left',
width: 1,
sorter: true,
resizable: true,
ifShow: false,
},
{
title: L('DisplayName:Name'),
dataIndex: 'name',
align: 'left',
width: 120,
sorter: true,
resizable: true,
},
{
title: L('DisplayName:Note'),
dataIndex: 'note',
align: 'left',
width: 120,
sorter: true,
resizable: true,
},
{
title: L('DisplayName:Version'),
dataIndex: 'version',
align: 'left',
width: 120,
sorter: true,
resizable: true,
},
{
title: L('DisplayName:Description'),
dataIndex: 'description',
align: 'left',
width: 120,
sorter: true,
resizable: true,
},
{
title: L('DisplayName:ForceUpdate'),
dataIndex: 'forceUpdate',
align: 'left',
width: 120,
sorter: true,
resizable: true,
},
{
title: L('DisplayName:Authors'),
dataIndex: 'authors',
align: 'left',
width: 120,
sorter: true,
resizable: true,
},
];
}

13
apps/vue/src/views/platform/package/index.vue

@ -0,0 +1,13 @@
<template>
<PackageTable />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import PackageTable from './components/PackageTable.vue';
export default defineComponent({
name: 'PlatformPackages',
components: { PackageTable },
});
</script>

2
aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN.Abp.Cli.csproj

@ -5,7 +5,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Version>7.0.0</Version>
<Version>7.0.1</Version>
<Copyright>colin</Copyright>
<Description>Use LINGYUN.MicroService.Templates command line</Description>
<PackAsTool>true</PackAsTool>

7
aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/ServiceProxying/TypeScript/TypeScriptServiceProxyGenerator.cs

@ -31,7 +31,12 @@ public class TypeScriptServiceProxyGenerator : ServiceProxyGeneratorBase<TypeScr
public async override Task GenerateProxyAsync(Volo.Abp.Cli.ServiceProxying.GenerateProxyArgs args)
{
var applicationApiDescriptionModel = await GetApplicationApiDescriptionModelAsync(args);
var applicationApiDescriptionModel = await GetApplicationApiDescriptionModelAsync(
args,
new Volo.Abp.Http.Modeling.ApplicationApiDescriptionModelRequestDto
{
IncludeTypes = true
});
var outputFolderRoot = args.Output;
foreach (var module in applicationApiDescriptionModel.Modules)

54
aspnet-core/modules/cli/LINGYUN.Abp.Cli/LINGYUN/Abp/Cli/UI/Vben/VbenModelScriptGenerator.cs

@ -178,13 +178,14 @@ public class VbenModelScriptGenerator : IVbenModelScriptGenerator, ISingletonDep
var component = new ComponentModel
{
Name = inputModelProp.JsonName ?? inputModelProp.Name.ToCamelCase(),
Component = "Input",
Component = GetComponentType(inputModelProp.Type),
DisplayName = "DisplayName:" + inputModelProp.Name.ToPascalCase(),
Required = inputModelProp.IsRequired,
ColProps = "" +
"{" +
$"span: {span}" +
"}",
HasDate = inputModelProp.Type.Contains("DateTime")
};
if (appModel.Types.TryGetValue(inputModelProp.Type, out var inputModelPropType) &&
@ -194,7 +195,6 @@ public class VbenModelScriptGenerator : IVbenModelScriptGenerator, ISingletonDep
var optionsStr = Environment.NewLine;
var options = new object[inputModelPropType.EnumNames.Length];
for (var index = 0; index < inputModelPropType.EnumNames.Length; index++)
{
optionsStr += "" +
@ -233,13 +233,14 @@ public class VbenModelScriptGenerator : IVbenModelScriptGenerator, ISingletonDep
var component = new ComponentModel
{
Name = inputModelProp.JsonName ?? inputModelProp.Name.ToCamelCase(),
Component = "Input",
Component = GetComponentType(inputModelProp.Type),
DisplayName = "DisplayName:" + inputModelProp.Name.ToPascalCase(),
Required = !inputModelProp.IsOptional,
ColProps = "" +
"{" +
$"span: {span}" +
"}",
HasDate = inputModelProp.Type.Contains("DateTime"),
};
if (appModel.Types.TryGetValue(inputModelProp.Type, out var inputModelPropType) &&
@ -249,7 +250,6 @@ public class VbenModelScriptGenerator : IVbenModelScriptGenerator, ISingletonDep
var optionsStr = Environment.NewLine;
var options = new object[inputModelPropType.EnumNames.Length];
for (var index = 0; index < inputModelPropType.EnumNames.Length; index++)
{
optionsStr += "" +
@ -321,14 +321,15 @@ public class VbenModelScriptGenerator : IVbenModelScriptGenerator, ISingletonDep
var component = new ComponentModel
{
Name = inputModelProp.JsonName ?? inputModelProp.Name.ToCamelCase(),
Component = "Input",
Component = GetComponentType(inputModelProp.Type),
DisplayName = "DisplayName:" + inputModelProp.Name.ToPascalCase(),
Required = inputModelProp.IsRequired,
ColProps = "" +
"{" +
"span: 24" +
"}",
ComponentProps = "{}"
ComponentProps = "{}",
HasDate = inputModelProp.Type.Contains("DateTime")
};
if (DisableInputModelFields.Contains(inputModelProp.Name, StringComparer.InvariantCultureIgnoreCase))
@ -351,14 +352,15 @@ public class VbenModelScriptGenerator : IVbenModelScriptGenerator, ISingletonDep
var component = new ComponentModel
{
Name = modelProp.JsonName ?? modelProp.Name.ToCamelCase(),
Component = "Input",
Component = GetComponentType(modelProp.Type),
DisplayName = "DisplayName:" + modelProp.Name.ToPascalCase(),
Required = modelProp.IsRequired,
ColProps = "" +
"{" +
"span: 24" +
"}",
ComponentProps = "{}"
ComponentProps = "{}",
HasDate = modelProp.Type.Contains("DateTime")
};
if (DisableInputModelFields.Contains(modelProp.Name, StringComparer.InvariantCultureIgnoreCase))
@ -424,6 +426,40 @@ public class VbenModelScriptGenerator : IVbenModelScriptGenerator, ISingletonDep
protected virtual bool IsAbpBaseType(string typeSimple) => TypeScriptModelGenerator.AbpBaseTypes.Any(typeSimple.StartsWith);
protected virtual string GetComponentType(string typeSimple)
{
if (typeSimple.Contains("DateTime"))
{
return "DatePicker";
}
if (typeSimple.Contains("Boolean"))
{
return "Checkbox";
}
if (typeSimple.Contains("Enum"))
{
return "Select";
}
if (typeSimple.Contains("Int") ||
typeSimple.Contains("Byte") ||
typeSimple.Contains("Single") ||
typeSimple.Contains("Double") ||
typeSimple.Contains("Decimal"))
{
return "InputNumber";
}
if (typeSimple.Contains("Object"))
{
return "CodeEditorX";
}
return "Input";
}
protected virtual string GetAbpBaseType(string typeSimple) =>
TypeScriptModelGenerator.AbpBaseTypes.FirstOrDefault(typeSimple.StartsWith);
@ -476,4 +512,6 @@ public class ComponentModel
public bool Sorter { get; set; } = true;
public bool Resizable { get; set; } = true;
public bool Required { get; set; } = false;
public bool HasDate { get; set; } = false;
}

4
aspnet-core/modules/cli/LINGYUN.Abp.Cli/Properties/launchSettings.json

@ -2,8 +2,8 @@
"profiles": {
"LINGYUN.Abp.Cli": {
"commandName": "Project",
"commandLineArgs": "generate-view -t vben-view -m task-management -o D:\\Projects\\Development\\view-script -url http://127.0.0.1:30000/"
// "commandLineArgs": "generate-proxy -t ts -asp vben-dynamic -u http://127.0.0.1:30000 -m task-management -o D:\\Projects\\Development\\type-script"
"commandLineArgs": "generate-view -t vben-view -m auditing -o D:\\Projects\\Development\\view-script -url http://127.0.0.1:30000/"
//"commandLineArgs": "generate-proxy -t ts -asp vben-dynamic -u http://127.0.0.1:30000 -m platform -o D:\\Projects\\Development\\type-script"
}
}
}

7
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Localization/Resources/en.json

@ -37,6 +37,10 @@
"DisplayName:Basic": "Basic",
"DisplayName:DataDictionary": "Data Dictionary",
"DisplayName:RoleName": "Role Name",
"DisplayName:Note": "Note",
"DisplayName:Version": "Version",
"DisplayName:ForceUpdate": "Force Update",
"DisplayName:Authors": "Authors",
"Layout:AddNew": "Add New",
"Layout:Edit": "Edit",
"Layout:EditByName": "Edit Layout - {0}",
@ -60,6 +64,7 @@
"DuplicateDataItem": "A data dictionary entry named {0} already exists!",
"DataItemNotFound": "There is no data dictionary entry named {0}!",
"UnableRemoveHasChildNode": "Current data dictionary exists child node, cannot delete!",
"DuplicateLayout": "A layout named {0} already exists!"
"DuplicateLayout": "A layout named {0} already exists!",
"Packages": "Packages"
}
}

7
aspnet-core/modules/platform/LINGYUN.Platform.Domain.Shared/LINGYUN/Platform/Localization/Resources/zh-Hans.json

@ -37,6 +37,10 @@
"DisplayName:Basic": "基础信息",
"DisplayName:DataDictionary": "数据字典",
"DisplayName:RoleName": "角色名称",
"DisplayName:Note": "发版说明",
"DisplayName:Version": "版本",
"DisplayName:ForceUpdate": "强制更新",
"DisplayName:Authors": "作者",
"Layout:AddNew": "添加新布局",
"Layout:Edit": "编辑布局",
"Layout:EditByName": "编辑布局 - {0}",
@ -60,6 +64,7 @@
"DuplicateDataItem": "已经存在名为 {0} 的数据字典项!",
"DataItemNotFound": "不存在名为 {0} 的数据字典项!",
"UnableRemoveHasChildNode": "当前数据字典存在子节点,无法删除!",
"DuplicateLayout": "已经存在名为 {0} 的布局!"
"DuplicateLayout": "已经存在名为 {0} 的布局!",
"Packages": "包列表"
}
}
Loading…
Cancel
Save