😎1、首页跑马灯消息默认取最新的一条通知公告 2、优化字典处理 3、升级依赖

This commit is contained in:
zuohuaijun 2025-03-26 13:02:44 +08:00
parent 8dee48f983
commit 882a588abb
14 changed files with 452 additions and 28 deletions

View File

@ -56,7 +56,7 @@
<PackageReference Include="SSH.NET" Version="2024.2.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.0.2" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1207" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1208" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>

View File

@ -17,7 +17,7 @@ public partial class SysNotice : EntityTenant
/// <summary>
/// 标题
/// </summary>
[SugarColumn(ColumnDescription = "标题", Length = 32)]
[SugarColumn(ColumnDescription = "标题", Length = 128)]
[Required, MaxLength(32)]
[SensitiveDetection('*')]
public virtual string Title { get; set; }

View File

@ -0,0 +1,25 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 系统通知公告表种子数据
/// </summary>
public class SysNoticeSeedData : ISqlSugarEntitySeedData<SysNotice>
{
/// <summary>
/// 种子数据
/// </summary>
/// <returns></returns>
public IEnumerable<SysNotice> HasData()
{
return
[
new SysNotice{ Id=1300000000101, Title="欢迎使用 Admin.NET 通用权限开发框架 <a href=\"https://gitee.com/zuohuaijun/Admin.NET\" target=\"_blank\">https://gitee.com/zuohuaijun/Admin.NET</a>", Content="https://adminnet.top/", CreateTime=DateTime.Parse("2025-03-26 00:00:00"), Status=NoticeStatusEnum.PUBLIC },
];
}
}

View File

@ -0,0 +1,20 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core.Service;
public class NoticeOutput : BaseIdInput
{
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
}

View File

@ -171,6 +171,35 @@ public class SysNoticeService : IDynamicApiController, ITransient
return noticeUserList.Select(t => t.SysNotice).ToList();
}
/// <summary>
/// 获取最新的通知公告标题
/// </summary>
/// <returns></returns>
[DisplayName("获取最新的通知公告标题")]
public async Task<NoticeOutput> GetNoticeTitle()
{
return await _sysNoticeRep.AsQueryable()
.OrderBy(u => u.CreateTime, OrderByType.Desc)
.Select(u => new NoticeOutput
{
Id = u.Id,
Title = u.Title,
CreateTime = u.CreateTime
})
.FirstAsync();
}
/// <summary>
/// 获取通知公告详情
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[DisplayName("获取通知公告详情")]
public async Task<SysNotice> GetNotice(NoticeInput input)
{
return await _sysNoticeRep.GetFirstAsync(u => u.Id == input.Id);
}
/// <summary>
/// 初始化通知公告信息
/// </summary>

View File

@ -26,7 +26,7 @@
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.13.0" />
<PackageReference Include="Rezero.Api" Version="1.8.3" />
<PackageReference Include="Rezero.Api" Version="1.8.5" />
</ItemGroup>
<ItemGroup>

View File

@ -2,7 +2,7 @@
"name": "admin.net.pro",
"type": "module",
"version": "2.4.33",
"lastBuildTime": "2025.03.25",
"lastBuildTime": "2025.03.26",
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
"author": "zuohuaijun",
"license": "MIT",
@ -47,7 +47,7 @@
"jsplumb": "^2.15.6",
"jwchat": "^2.0.3",
"lodash-es": "^4.17.21",
"md-editor-v3": "^5.4.4",
"md-editor-v3": "^5.4.5",
"mitt": "^3.0.1",
"monaco-editor": "^0.52.2",
"mqtt": "^5.10.4",
@ -77,8 +77,8 @@
"vue-signature-pad": "^3.0.2",
"vue3-flag-icons": "^0.0.3",
"vue3-tree-org": "^4.2.2",
"vxe-pc-ui": "^4.4.24",
"vxe-table": "^4.11.29",
"vxe-pc-ui": "^4.4.26",
"vxe-table": "^4.12.0",
"vxe-table-plugin-element": "^4.0.4",
"vxe-table-plugin-export-xlsx": "^4.0.7",
"xe-utils": "^3.7.4",
@ -88,7 +88,7 @@
"@iconify/vue": "^4.3.0",
"@plugin-web-update-notification/vite": "^2.0.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.17.25",
"@types/node": "^20.17.27",
"@types/nprogress": "^0.2.3",
"@types/sortablejs": "^1.15.8",
"@typescript-eslint/eslint-plugin": "^8.28.0",

View File

@ -19,8 +19,10 @@ import { Configuration } from '../configuration';
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
import { AddNoticeInput } from '../models';
import { AdminNETResultListSysNotice } from '../models';
import { AdminNETResultNoticeOutput } from '../models';
import { AdminNETResultSqlSugarPagedListSysNotice } from '../models';
import { AdminNETResultSqlSugarPagedListSysNoticeUser } from '../models';
import { AdminNETResultSysNotice } from '../models';
import { DeleteNoticeInput } from '../models';
import { NoticeInput } from '../models';
import { PageNoticeInput } from '../models';
@ -127,6 +129,97 @@ export const SysNoticeApiAxiosParamCreator = function (configuration?: Configura
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {NoticeInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysNoticeNoticeGet: async (body?: NoticeInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysNotice/notice`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysNoticeNoticeTitleGet: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysNotice/noticeTitle`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary 📢
@ -447,6 +540,33 @@ export const SysNoticeApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary
* @param {NoticeInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysNoticeNoticeGet(body?: NoticeInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultSysNotice>>> {
const localVarAxiosArgs = await SysNoticeApiAxiosParamCreator(configuration).apiSysNoticeNoticeGet(body, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysNoticeNoticeTitleGet(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultNoticeOutput>>> {
const localVarAxiosArgs = await SysNoticeApiAxiosParamCreator(configuration).apiSysNoticeNoticeTitleGet(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 📢
@ -559,6 +679,25 @@ export const SysNoticeApiFactory = function (configuration?: Configuration, base
async apiSysNoticeDeletePost(body?: DeleteNoticeInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysNoticeApiFp(configuration).apiSysNoticeDeletePost(body, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {NoticeInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysNoticeNoticeGet(body?: NoticeInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultSysNotice>> {
return SysNoticeApiFp(configuration).apiSysNoticeNoticeGet(body, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysNoticeNoticeTitleGet(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultNoticeOutput>> {
return SysNoticeApiFp(configuration).apiSysNoticeNoticeTitleGet(options).then((request) => request(axios, basePath));
},
/**
*
* @summary 📢
@ -650,6 +789,27 @@ export class SysNoticeApi extends BaseAPI {
public async apiSysNoticeDeletePost(body?: DeleteNoticeInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysNoticeApiFp(this.configuration).apiSysNoticeDeletePost(body, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {NoticeInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysNoticeApi
*/
public async apiSysNoticeNoticeGet(body?: NoticeInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultSysNotice>> {
return SysNoticeApiFp(this.configuration).apiSysNoticeNoticeGet(body, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysNoticeApi
*/
public async apiSysNoticeNoticeTitleGet(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultNoticeOutput>> {
return SysNoticeApiFp(this.configuration).apiSysNoticeNoticeTitleGet(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 📢

View File

@ -0,0 +1,69 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { NoticeOutput } from './notice-output';
/**
*
*
* @export
* @interface AdminNETResultNoticeOutput
*/
export interface AdminNETResultNoticeOutput {
/**
*
*
* @type {number}
* @memberof AdminNETResultNoticeOutput
*/
code?: number;
/**
* successwarningerror
*
* @type {string}
* @memberof AdminNETResultNoticeOutput
*/
type?: string | null;
/**
*
*
* @type {string}
* @memberof AdminNETResultNoticeOutput
*/
message?: string | null;
/**
* @type {NoticeOutput}
* @memberof AdminNETResultNoticeOutput
*/
result?: NoticeOutput;
/**
*
*
* @type {any}
* @memberof AdminNETResultNoticeOutput
*/
extras?: any | null;
/**
*
*
* @type {Date}
* @memberof AdminNETResultNoticeOutput
*/
time?: Date;
}

View File

@ -0,0 +1,69 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { SysNotice } from './sys-notice';
/**
*
*
* @export
* @interface AdminNETResultSysNotice
*/
export interface AdminNETResultSysNotice {
/**
*
*
* @type {number}
* @memberof AdminNETResultSysNotice
*/
code?: number;
/**
* successwarningerror
*
* @type {string}
* @memberof AdminNETResultSysNotice
*/
type?: string | null;
/**
*
*
* @type {string}
* @memberof AdminNETResultSysNotice
*/
message?: string | null;
/**
* @type {SysNotice}
* @memberof AdminNETResultSysNotice
*/
result?: SysNotice;
/**
*
*
* @type {any}
* @memberof AdminNETResultSysNotice
*/
extras?: any | null;
/**
*
*
* @type {Date}
* @memberof AdminNETResultSysNotice
*/
time?: Date;
}

View File

@ -81,6 +81,7 @@ export * from './admin-netresult-list-table-output';
export * from './admin-netresult-list-tree-node';
export * from './admin-netresult-login-output';
export * from './admin-netresult-login-user-output';
export * from './admin-netresult-notice-output';
export * from './admin-netresult-object';
export * from './admin-netresult-sm-key-pair-output';
export * from './admin-netresult-sql-sugar-paged-list-job-detail-output';
@ -125,6 +126,7 @@ export * from './admin-netresult-sys-log-diff';
export * from './admin-netresult-sys-log-ex';
export * from './admin-netresult-sys-log-msg';
export * from './admin-netresult-sys-log-op';
export * from './admin-netresult-sys-notice';
export * from './admin-netresult-sys-print';
export * from './admin-netresult-sys-schedule';
export * from './admin-netresult-sys-upgrade';
@ -290,6 +292,7 @@ export * from './mqtt-session-status';
export * from './mzb-input';
export * from './navigate';
export * from './notice-input';
export * from './notice-output';
export * from './notice-status-enum';
export * from './notice-type-enum';
export * from './notice-user-status-enum';

View File

@ -0,0 +1,46 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/**
*
*
* @export
* @interface NoticeOutput
*/
export interface NoticeOutput {
/**
* Id
*
* @type {number}
* @memberof NoticeOutput
*/
id: number;
/**
*
*
* @type {string}
* @memberof NoticeOutput
*/
title?: string | null;
/**
*
*
* @type {Date}
* @memberof NoticeOutput
*/
createTime?: Date;
}

View File

@ -4,7 +4,7 @@
<i v-if="leftIcon" class="notice-bar-warp-left-icon" :class="leftIcon"></i>
<div class="notice-bar-warp-text-box">
<div class="notice-bar-warp-text" ref="noticeBarTextRef">
<div v-html="displayText" data-slate-editor />
<div v-html="state.noticeTitle" data-slate-editor />
</div>
</div>
<!-- <SvgIcon :name="rightIcon" v-if="rightIcon" class="notice-bar-warp-right-icon" @click="onRightIconClick" /> -->
@ -16,9 +16,10 @@
import { reactive, ref, onMounted, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
import { getAPI } from '/@/utils/axios-utils';
import { SysNoticeApi } from '/@/api-services/api';
const defaultText = t('message.list.welcomein') + ' <a href="https://gitee.com/zuohuaijun/Admin.NET" target="_blank">https://gitee.com/zuohuaijun/Admin.NET</a>';
const i18n = useI18n();
const props = defineProps({
mode: { type: String, default: '' }, // closeable link
@ -33,7 +34,7 @@ const props = defineProps({
leftIcon: { type: String, default: 'iconfont icon-tongzhi2' }, //
rightIcon: { type: String, default: '' }, //
});
const displayText = ref(props.text || defaultText);
const displayText = ref(undefined);
const emit = defineEmits(['close', 'link']);
const noticeBarWarpRef = ref<HTMLDivElement | null>(null);
@ -43,14 +44,16 @@ const state = reactive({
warpOWidth: 0,
textOWidth: 0,
animationDuration: 0,
noticeTitle: '',
});
//
onMounted(() => {
if (!props.scrollable) {
initAnimation();
}
displayText.value = defaultText;
onMounted(async () => {
if (!props.scrollable) initAnimation();
//
var res = await getAPI(SysNoticeApi).apiSysNoticeNoticeTitleGet();
state.noticeTitle = res.data.result?.title ?? ''; // i18n.t(res.data.result?.title ?? '');
});
//

View File

@ -40,17 +40,17 @@ export const useUserInfo = defineStore('userInfo', {
.then((res) => res.data.result ?? {});
var dictListTemp = JSON.parse(JSON.stringify(dictList));
await Promise.all(
Object.keys(dictList).map(async (key) => {
dictList[key].forEach((da: any, index: any) => {
setDictLangMessageAsync(dictListTemp[key][index]);
});
// 如果 key 以 "Enum" 结尾,则转换 value 为数字
if (key.endsWith('Enum')) {
dictListTemp[key].forEach((e: any) => (e.value = Number(e.value)));
}
})
);
// await Promise.all(
// Object.keys(dictList).map(async (key) => {
// dictList[key].forEach((da: any, index: any) => {
// setDictLangMessageAsync(dictListTemp[key][index]);
// });
// // 如果 key 以 "Enum" 结尾,则转换 value 为数字
// if (key.endsWith('Enum')) {
// dictListTemp[key].forEach((e: any) => (e.value = Number(e.value)));
// }
// })
// );
this.dictList = dictListTemp;
},