Browse Source

Fix multiple issues

** Fix ids manager to configure url mappings.

** Fix notice content formatting issues when the type is not Text.

** Add the missing flutter package.
pull/874/head
colin 2 years ago
parent
commit
8d409fcc79
  1. 1
      apps/flutter/dev_app/pubspec.yaml
  2. 8
      apps/vue/src/api/messages/model/notificationsModel.ts
  3. 45
      apps/vue/src/layouts/default/header/components/notify/NoticeList.vue
  4. 3
      apps/vue/src/layouts/default/header/components/notify/data.ts
  5. 63
      apps/vue/src/layouts/default/header/components/notify/index.vue
  6. 20
      apps/vue/src/layouts/default/header/components/notify/useNotifications.ts
  7. 11
      aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs
  8. 3
      aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs
  9. 25
      aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json
  10. 3
      aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs
  11. 3
      aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs
  12. 3
      aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs
  13. 11
      aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs
  14. 25
      aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json

1
apps/flutter/dev_app/pubspec.yaml

@ -53,6 +53,7 @@ dependencies:
dio: ^5.2.0+1 dio: ^5.2.0+1
flutter_easyloading: ^3.0.5 flutter_easyloading: ^3.0.5
flutter_picker: ^2.1.0 flutter_picker: ^2.1.0
flutter_logs: ^2.1.11
get: ^4.6.5 get: ^4.6.5
get_storage: ^2.1.1 get_storage: ^2.1.1
rxdart: ^0.27.7 rxdart: ^0.27.7

8
apps/vue/src/api/messages/model/notificationsModel.ts

@ -10,6 +10,13 @@ export enum NotificationType {
ServiceCallback = 30, ServiceCallback = 30,
} }
export enum NotificationContentType {
Text = 0,
Html = 1,
Markdown = 2,
Json = 3,
}
export enum NotificationSeverity { export enum NotificationSeverity {
Success = 0, Success = 0,
Info = 10, Info = 10,
@ -37,6 +44,7 @@ export interface NotificationInfo {
lifetime: NotificationLifetime; lifetime: NotificationLifetime;
type: NotificationType; type: NotificationType;
severity: NotificationSeverity; severity: NotificationSeverity;
contentType: NotificationContentType;
} }
export interface NotificationGroup { export interface NotificationGroup {

45
apps/vue/src/layouts/default/header/components/notify/NoticeList.vue

@ -34,13 +34,15 @@
<div> <div>
<div class="description" v-if="item.description"> <div class="description" v-if="item.description">
<a-typography-paragraph <a-typography-paragraph
@click="handleContentClick(item)"
style="width: 100%; margin-bottom: 0 !important" style="width: 100%; margin-bottom: 0 !important"
:style="{ cursor: isContentClickable ? 'pointer' : '' }"
:ellipsis=" :ellipsis="
$props.descRows && $props.descRows > 0 $props.descRows && $props.descRows > 0
? { rows: $props.descRows, tooltip: !!item.description } ? { rows: $props.descRows, tooltip: !!item.description }
: false : false
" "
:content="item.description" :content="getContent(item)"
/> />
</div> </div>
<div class="datetime"> <div class="datetime">
@ -61,6 +63,7 @@
import { ListItem } from './data'; import { ListItem } from './data';
import { useDesign } from '/@/hooks/web/useDesign'; import { useDesign } from '/@/hooks/web/useDesign';
import { List, Avatar, Tag, Typography } from 'ant-design-vue'; import { List, Avatar, Tag, Typography } from 'ant-design-vue';
import { NotificationContentType } from "/@/api/messages/model/notificationsModel";
import { isNumber } from '/@/utils/is'; import { isNumber } from '/@/utils/is';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -95,6 +98,9 @@
onTitleClick: { onTitleClick: {
type: Function as PropType<(Recordable) => void>, type: Function as PropType<(Recordable) => void>,
}, },
onContentClick: {
type: Function as PropType<(Recordable) => void>,
},
}, },
emits: ['update:currentPage'], emits: ['update:currentPage'],
setup(props, { emit }) { setup(props, { emit }) {
@ -103,9 +109,22 @@
const getData = computed(() => { const getData = computed(() => {
const { pageSize, list } = props; const { pageSize, list } = props;
if (pageSize === false) return []; if (pageSize === false) return [];
let size = isNumber(pageSize) ? pageSize : 5; let size = isNumber(pageSize) ? pageSize : 10;
return list.slice(size * (unref(current) - 1), size * unref(current)); return list.slice(size * (unref(current) - 1), size * unref(current));
}); });
const getContent = computed(() => {
return (item: ListItem) => {
switch (item.contentType) {
default:
case NotificationContentType.Text:
return item.description;
case NotificationContentType.Html:
case NotificationContentType.Json:
case NotificationContentType.Markdown:
return item.title;
}
};
});
watch( watch(
() => props.currentPage, () => props.currentPage,
(v) => { (v) => {
@ -113,12 +132,15 @@
}, },
); );
const isTitleClickable = computed(() => !!props.onTitleClick); const isTitleClickable = computed(() => !!props.onTitleClick);
const isContentClickable = computed(() => !!props.onContentClick);
const getPagination = computed(() => { const getPagination = computed(() => {
const { list, pageSize } = props; const { list, pageSize } = props;
if (pageSize > 0 && list && list.length > pageSize) { if (pageSize === false) return false;
const size = isNumber(pageSize) ? pageSize : 5;
if (size > 0 && list && list.length > size) {
return { return {
total: list.length, total: list.length,
pageSize, pageSize: size,
//size: 'small', //size: 'small',
current: unref(current), current: unref(current),
onChange(page) { onChange(page) {
@ -135,7 +157,20 @@
props.onTitleClick && props.onTitleClick(item); props.onTitleClick && props.onTitleClick(item);
} }
return { prefixCls, getPagination, getData, handleTitleClick, isTitleClickable }; function handleContentClick(item: ListItem) {
props.onContentClick && props.onContentClick(item);
}
return {
prefixCls,
getPagination,
getData,
getContent,
handleTitleClick,
isTitleClickable,
handleContentClick,
isContentClickable,
};
}, },
}); });
</script> </script>

3
apps/vue/src/layouts/default/header/components/notify/data.ts

@ -1,3 +1,5 @@
import { NotificationContentType } from "/@/api/messages/model/notificationsModel";
export interface ListItem { export interface ListItem {
id: string; id: string;
avatar: string; avatar: string;
@ -12,6 +14,7 @@ export interface ListItem {
clickClose?: boolean; clickClose?: boolean;
extra?: string; extra?: string;
color?: string; color?: string;
contentType?: NotificationContentType;
} }
export interface TabItem { export interface TabItem {

63
apps/vue/src/layouts/default/header/components/notify/index.vue

@ -1,6 +1,37 @@
<template> <template>
<div :class="prefixCls"> <div :class="prefixCls">
<Popover title="" trigger="click" :overlayClassName="`${prefixCls}__overlay`"> <Badge :count="count" dot :numberStyle="numberStyle">
<BellOutlined @click="showDrawer" />
</Badge>
<Drawer v-model:visible="open" title="" :class="`${prefixCls}__overlay`" placement="right" :closable="false">
<Tabs>
<TabPane :key="notifierRef.key" :tab="notifierRef.name">
<NoticeList :list="notifierRef.list" @title-click="readNotifer" @content-click="handleShowNotifications" />
</TabPane>
<TabPane :key="messageRef.key" :tab="messageRef.name">
<NoticeList :list="messageRef.list">
<template #footer>
<ButtonGroup style="width: 100%">
<Button
:disabled="messageRef.list.length === 0"
style="width: 50%"
type="link"
@click="clearMessage"
>清空消息</Button
>
<Button style="width: 50%" type="link" @click="handleShowMessages"
>查看更多</Button
>
</ButtonGroup>
</template>
</NoticeList>
</TabPane>
<TabPane :key="tasksRef.key" :tab="tasksRef.name">
<NoticeList :list="tasksRef.list" />
</TabPane>
</Tabs>
</Drawer>
<!-- <Popover title="" trigger="click" :overlayClassName="`${prefixCls}__overlay`">
<Badge :count="count" dot :numberStyle="numberStyle"> <Badge :count="count" dot :numberStyle="numberStyle">
<BellOutlined /> <BellOutlined />
</Badge> </Badge>
@ -32,12 +63,12 @@
</TabPane> </TabPane>
</Tabs> </Tabs>
</template> </template>
</Popover> </Popover> -->
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent } from 'vue'; import { computed, defineComponent, ref } from 'vue';
import { Button, Popover, Tabs, Badge } from 'ant-design-vue'; import { Button, Drawer, Popover, Tabs, Badge } from 'ant-design-vue';
import { BellOutlined } from '@ant-design/icons-vue'; import { BellOutlined } from '@ant-design/icons-vue';
import NoticeList from './NoticeList.vue'; import NoticeList from './NoticeList.vue';
import { useGo } from '/@/hooks/web/usePage'; import { useGo } from '/@/hooks/web/usePage';
@ -50,6 +81,7 @@
components: { components: {
Button, Button,
ButtonGroup: Button.Group, ButtonGroup: Button.Group,
Drawer,
Popover, Popover,
BellOutlined, BellOutlined,
Tabs, Tabs,
@ -60,6 +92,7 @@
setup() { setup() {
const { prefixCls } = useDesign('header-notify'); const { prefixCls } = useDesign('header-notify');
const go = useGo(); const go = useGo();
const open = ref(false);
const { tasksRef } = useTasks(); const { tasksRef } = useTasks();
const { messageRef, clearMessage } = useMessages(); const { messageRef, clearMessage } = useMessages();
const { notifierRef, readNotifer } = useNotifications(); const { notifierRef, readNotifer } = useNotifications();
@ -78,16 +111,30 @@
go('/sys/chat?type=chat-message'); go('/sys/chat?type=chat-message');
} }
function handleShowNotifications() {
console.log('handleShowNotifications');
open.value = false;
go('/messages/notifications');
}
function showDrawer() {
console.log('showDrawer');
open.value = true;
}
return { return {
prefixCls, prefixCls,
count, count,
numberStyle: {}, numberStyle: {},
open,
showDrawer,
notifierRef, notifierRef,
readNotifer, readNotifer,
messageRef, messageRef,
clearMessage, clearMessage,
tasksRef, tasksRef,
handleShowMessages, handleShowMessages,
handleShowNotifications,
}; };
}, },
}); });
@ -98,14 +145,6 @@
.@{prefix-cls} { .@{prefix-cls} {
padding-top: 2px; padding-top: 2px;
&__overlay {
max-width: 360px;
}
.ant-tabs-content {
width: 300px;
}
.ant-badge { .ant-badge {
font-size: 18px; font-size: 18px;

20
apps/vue/src/layouts/default/header/components/notify/useNotifications.ts

@ -6,6 +6,7 @@ import {
NotificationInfo, NotificationInfo,
NotificationSeverity, NotificationSeverity,
NotificationReadState, NotificationReadState,
NotificationContentType,
} from '/@/api/messages/model/notificationsModel'; } from '/@/api/messages/model/notificationsModel';
import { formatToDateTime } from '/@/utils/dateUtil'; import { formatToDateTime } from '/@/utils/dateUtil';
import { TabItem, ListItem as Notification } from './data'; import { TabItem, ListItem as Notification } from './data';
@ -79,6 +80,7 @@ export function useNotifications() {
extra: description, extra: description,
datetime: formatToDateTime(notificationInfo.creationTime, 'YYYY-MM-DD HH:mm:ss'), datetime: formatToDateTime(notificationInfo.creationTime, 'YYYY-MM-DD HH:mm:ss'),
type: String(notificationInfo.type), type: String(notificationInfo.type),
contentType: notificationInfo.contentType,
}; };
if (notifer && notificationInfo.type !== NotificationType.ServiceCallback) { if (notifer && notificationInfo.type !== NotificationType.ServiceCallback) {
@ -95,6 +97,16 @@ export function useNotifications() {
function _notification(notifier: Notification, severity: NotificationSeverity) { function _notification(notifier: Notification, severity: NotificationSeverity) {
let message = notifier.description;
switch (notifier.contentType) {
default:
case NotificationContentType.Text:
message = notifier.description;
case NotificationContentType.Html:
case NotificationContentType.Json:
case NotificationContentType.Markdown:
message = notifier.title;
}
switch (severity) { switch (severity) {
case NotificationSeverity.Error: case NotificationSeverity.Error:
case NotificationSeverity.Fatal: case NotificationSeverity.Fatal:
@ -102,7 +114,7 @@ export function useNotifications() {
notifier.avatar = errorAvatar; notifier.avatar = errorAvatar;
notification['error']({ notification['error']({
message: notifier.title, message: notifier.title,
description: notifier.description, description: message,
}); });
break; break;
case NotificationSeverity.Warn: case NotificationSeverity.Warn:
@ -110,7 +122,7 @@ export function useNotifications() {
notifier.avatar = warningAvatar; notifier.avatar = warningAvatar;
notification['warning']({ notification['warning']({
message: notifier.title, message: notifier.title,
description: notifier.description, description: message,
}); });
break; break;
case NotificationSeverity.Info: case NotificationSeverity.Info:
@ -118,7 +130,7 @@ export function useNotifications() {
notifier.avatar = infoAvatar; notifier.avatar = infoAvatar;
notification['info']({ notification['info']({
message: notifier.title, message: notifier.title,
description: notifier.description, description: message,
}); });
break; break;
case NotificationSeverity.Success: case NotificationSeverity.Success:
@ -126,7 +138,7 @@ export function useNotifications() {
notifier.avatar = successAvatar; notifier.avatar = successAvatar;
notification['success']({ notification['success']({
message: notifier.title, message: notifier.title,
description: notifier.description, description: message,
}); });
break; break;
} }

11
aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.Configure.cs

@ -181,8 +181,15 @@ public partial class AuthServerHttpApiHostModule
{ {
Configure<AppUrlOptions>(options => Configure<AppUrlOptions>(options =>
{ {
options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"]; var applicationConfiguration = configuration.GetSection("App:Urls:Applications");
options.Applications["STS"].RootUrl = configuration["App:StsUrl"]; foreach (var appConfig in applicationConfiguration.GetChildren())
{
options.Applications[appConfig.Key].RootUrl = appConfig["RootUrl"];
foreach (var urlsConfig in appConfig.GetSection("Urls").GetChildren())
{
options.Applications[appConfig.Key].Urls[urlsConfig.Key] = urlsConfig.Value;
}
}
}); });
} }

3
aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/AuthServerHttpApiHostModule.cs

@ -111,6 +111,9 @@ public partial class AuthServerHttpApiHostModule : AbpModule
app.UseCors(DefaultCorsPolicyName); app.UseCors(DefaultCorsPolicyName);
// 认证 // 认证
app.UseAuthentication(); app.UseAuthentication();
// IDS与JWT不匹配可能造成鉴权错误
// TODO: abp在某个更新版本建议移除此中间价
app.UseAbpClaimsMap();
// 多租户 // 多租户
app.UseMultiTenancy(); app.UseMultiTenancy();
// 授权 // 授权

25
aspnet-core/services/LY.MicroService.AuthServer.HttpApi.Host/appsettings.Development.json

@ -9,9 +9,28 @@
"tag": "AuthServer.Admin" "tag": "AuthServer.Admin"
}, },
"App": { "App": {
"SelfUrl": "http://127.0.0.1:30015/", "CorsOrigins": "http://127.0.0.1:3100",
"StsUrl": "http://127.0.0.1:44385/", "Urls": {
"CorsOrigins": "http://127.0.0.1:3100" "Applications": {
"MVC": {
"RootUrl": "http://127.0.0.1:44385/",
"Urls": {
"Abp.Account.EmailConfirm": "Account/EmailConfirm",
"Abp.Account.EmailVerifyLogin": "Account/VerifyCode"
}
},
"STS": {
"RootUrl": "http://127.0.0.1:44385/"
},
"VueVbenAdmin": {
"RootUrl": "http://127.0.0.1:3100/",
"Urls": {
"Abp.Account.EmailConfirm": "account/email-confirm",
"Abp.Account.EmailVerifyLogin": "account/verify-code"
}
}
}
}
}, },
"Auditing": { "Auditing": {
"AllEntitiesSelector": true "AllEntitiesSelector": true

3
aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/BackendAdminHttpApiHostModule.cs

@ -148,6 +148,9 @@ public partial class BackendAdminHttpApiHostModule : AbpModule
app.UseCors(DefaultCorsPolicyName); app.UseCors(DefaultCorsPolicyName);
// 认证 // 认证
app.UseAuthentication(); app.UseAuthentication();
// IDS与JWT不匹配可能造成鉴权错误
// TODO: abp在某个更新版本建议移除此中间价
app.UseAbpClaimsMap();
// jwt // jwt
app.UseJwtTokenMiddleware(); app.UseJwtTokenMiddleware();
// 多租户 // 多租户

3
aspnet-core/services/LY.MicroService.LocalizationManagement.HttpApi.Host/LocalizationManagementHttpApiHostModule.cs

@ -104,6 +104,9 @@ namespace LY.MicroService.LocalizationManagement
app.UseCors(DefaultCorsPolicyName); app.UseCors(DefaultCorsPolicyName);
// 认证 // 认证
app.UseAuthentication(); app.UseAuthentication();
// IDS与JWT不匹配可能造成鉴权错误
// TODO: abp在某个更新版本建议移除此中间价
app.UseAbpClaimsMap();
// jwt // jwt
app.UseJwtTokenMiddleware(); app.UseJwtTokenMiddleware();
// 本地化 // 本地化

3
aspnet-core/services/LY.MicroService.PlatformManagement.HttpApi.Host/PlatformManagementHttpApiHostModule.cs

@ -155,6 +155,9 @@ public partial class PlatformManagementHttpApiHostModule : AbpModule
app.UseCors(DefaultCorsPolicyName); app.UseCors(DefaultCorsPolicyName);
// 认证 // 认证
app.UseAuthentication(); app.UseAuthentication();
// IDS与JWT不匹配可能造成鉴权错误
// TODO: abp在某个更新版本建议移除此中间价
app.UseAbpClaimsMap();
// jwt // jwt
app.UseJwtTokenMiddleware(); app.UseJwtTokenMiddleware();
// 多租户 // 多租户

11
aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/IdentityServerHttpApiHostModule.Configure.cs

@ -180,8 +180,15 @@ public partial class IdentityServerHttpApiHostModule
{ {
Configure<AppUrlOptions>(options => Configure<AppUrlOptions>(options =>
{ {
options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"]; var applicationConfiguration = configuration.GetSection("App:Urls:Applications");
options.Applications["STS"].RootUrl = configuration["App:StsUrl"]; foreach (var appConfig in applicationConfiguration.GetChildren())
{
options.Applications[appConfig.Key].RootUrl = appConfig["RootUrl"];
foreach (var urlsConfig in appConfig.GetSection("Urls").GetChildren())
{
options.Applications[appConfig.Key].Urls[urlsConfig.Key] = urlsConfig.Value;
}
}
}); });
} }
private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration) private void ConfigureDistributedLocking(IServiceCollection services, IConfiguration configuration)

25
aspnet-core/services/LY.MicroService.identityServer.HttpApi.Host/appsettings.Development.json

@ -9,9 +9,28 @@
"tag": "IdentityServer.Admin" "tag": "IdentityServer.Admin"
}, },
"App": { "App": {
"SelfUrl": "http://127.0.0.1:30015/", "CorsOrigins": "http://127.0.0.1:3100",
"StsUrl": "http://127.0.0.1:44385/", "Urls": {
"CorsOrigins": "http://127.0.0.1:3100" "Applications": {
"MVC": {
"RootUrl": "http://127.0.0.1:44385/",
"Urls": {
"Abp.Account.EmailConfirm": "Account/EmailConfirm",
"Abp.Account.EmailVerifyLogin": "Account/VerifyCode"
}
},
"STS": {
"RootUrl": "http://127.0.0.1:44385/"
},
"VueVbenAdmin": {
"RootUrl": "http://127.0.0.1:3100/",
"Urls": {
"Abp.Account.EmailConfirm": "account/email-confirm",
"Abp.Account.EmailVerifyLogin": "account/verify-code"
}
}
}
}
}, },
"Auditing": { "Auditing": {
"AllEntitiesSelector": true "AllEntitiesSelector": true

Loading…
Cancel
Save