😎1、增加生成种子提示 2、调整文件上传

This commit is contained in:
zuohuaijun 2024-07-05 22:06:46 +08:00
parent 63ad79b527
commit ef08b47b8a
8 changed files with 88 additions and 76 deletions

View File

@ -37,7 +37,7 @@
<PackageReference Include="SqlSugarCore" Version="5.1.4.160" />
<PackageReference Include="SSH.NET" Version="2024.1.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.4.3" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1040" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1041" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>

View File

@ -0,0 +1,28 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 校验集合不能为空
/// </summary>
[SuppressSniffer]
public class NotEmptyAttribute : ValidationAttribute
{
/// <summary>
/// 校验集合不能为空
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public override bool IsValid(object value) => (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false;
/// <summary>
/// 错误信息
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public override string FormatErrorMessage(string name) => base.FormatErrorMessage(name);
}

View File

@ -655,6 +655,12 @@ public enum ErrorCodeEnum
[ErrorCodeItemMetadata("不允许添加相同字段名")]
db1002,
/// <summary>
/// 实体文件不存在或匹配不到。如果是刚刚生成的实体,请重启服务后再试
/// </summary>
[ErrorCodeItemMetadata("实体文件不存在或匹配不到。如果是刚刚生成的实体,请重启服务后再试")]
db1003,
/// <summary>
/// 父节点不存在
/// </summary>

View File

@ -316,7 +316,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
/// <param name="input"></param>
[ApiDescriptionSettings(Name = "CreateSeedData"), HttpPost]
[DisplayName("创建种子数据")]
public async void CreateSeedData(CreateSeedDataInput input)
public async Task CreateSeedData(CreateSeedDataInput input)
{
var config = App.GetOptions<DbConnectionOptions>().ConnectionConfigs.FirstOrDefault(u => u.ConfigId.ToString() == input.ConfigId);
input.Position = string.IsNullOrWhiteSpace(input.Position) ? "Admin.NET.Core" : input.Position;
@ -333,7 +333,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
entityType = item.Type;
break;
}
if (entityType == null) return;
if (entityType == null) throw Oops.Oh(ErrorCodeEnum.db1003);
input.EntityName = entityType.Name;
input.SeedDataName = entityType.Name + "SeedData";

View File

@ -168,7 +168,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
var ds = await _sysDictTypeRep.AsQueryable()
.InnerJoin<SysDictData>((u, a) => u.Id == a.DictTypeId)
.Where((u, a) => u.IsDelete == false && a.IsDelete == false && a.Status == StatusEnum.Enable)
.Select((u, a) => new { TypeCode = u.Code, a.Code, a.Name, a.Value, a.Remark, a.OrderNo, a.TagType })
.Select((u, a) => new { TypeCode = u.Code, a.Code, a.Name, a.Value, a.Remark, a.OrderNo, a.TagType, a.ExtData })
.ToListAsync();
return ds.OrderBy(u => u.OrderNo).GroupBy(u => u.TypeCode).ToDictionary(u => u.Key, u => u);
}

View File

@ -5,7 +5,6 @@
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Aliyun.OSS.Util;
using Furion.VirtualFileServer;
using OnceMi.AspNetCore.OSS;
namespace Admin.NET.Core.Service;
@ -112,7 +111,7 @@ public class SysFileService : IDynamicApiController, ITransient
[DisplayName("根据文件Id或Url下载")]
public async Task<IActionResult> DownloadFile(FileInput input)
{
var file = input.Id > 0 ? await GetFile(input) : await _sysFileRep.GetFirstAsync(u => u.Url == input.Url);
var file = input.Id > 0 ? await GetFile(input) : await _sysFileRep.CopyNew().GetFirstAsync(u => u.Url == input.Url);
var fileName = HttpUtility.UrlEncode(file.FileName, Encoding.GetEncoding("UTF-8"));
if (_OSSProviderOptions.IsEnable)
@ -198,7 +197,7 @@ public class SysFileService : IDynamicApiController, ITransient
}
else if (App.Configuration["SSHProvider:IsEnable"].ToBoolean())
{
var sysFile = await _sysFileRep.GetFirstAsync(u => u.Url == url) ?? throw Oops.Oh($"文件不存在");
var sysFile = await _sysFileRep.CopyNew().GetFirstAsync(u => u.Url == url) ?? throw Oops.Oh($"文件不存在");
using (SSHHelper helper = new SSHHelper(App.Configuration["SSHProvider:Host"],
App.Configuration["SSHProvider:Port"].ToInt(), App.Configuration["SSHProvider:Username"], App.Configuration["SSHProvider:Password"]))
{
@ -207,14 +206,17 @@ public class SysFileService : IDynamicApiController, ITransient
}
else
{
var sysFile = await _sysFileRep.GetFirstAsync(u => u.Url == url) ?? throw Oops.Oh($"文件不存在");
var sysFile = await _sysFileRep.CopyNew().GetFirstAsync(u => u.Url == url) ?? throw Oops.Oh($"文件不存在");
var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, sysFile.FilePath);
if (!Directory.Exists(filePath))
Directory.CreateDirectory(filePath);
var realFile = Path.Combine(filePath, $"{sysFile.Id}{sysFile.Suffix}");
if (!File.Exists(realFile))
throw Oops.Oh($"文件[{realFile}]不在存");
{
Log.Error($"DownloadFileBase64:文件[{realFile}]不存在");
throw Oops.Oh($"文件[{sysFile.FilePath}]不存在");
}
byte[] fileBytes = File.ReadAllBytes(realFile);
return Convert.ToBase64String(fileBytes);
}
@ -278,7 +280,7 @@ public class SysFileService : IDynamicApiController, ITransient
/// <returns></returns>
private async Task<SysFile> GetFile([FromQuery] FileInput input)
{
var file = await _sysFileRep.GetFirstAsync(u => u.Id == input.Id);
var file = await _sysFileRep.CopyNew().GetFirstAsync(u => u.Id == input.Id);
return file ?? throw Oops.Oh(ErrorCodeEnum.D8000);
}
@ -321,6 +323,8 @@ public class SysFileService : IDynamicApiController, ITransient
// 获取文件后缀
var suffix = Path.GetExtension(file.FileName).ToLower(); // 后缀
if (string.IsNullOrWhiteSpace(suffix))
suffix = string.Concat(".", file.ContentType.AsSpan(file.ContentType.LastIndexOf('/') + 1));
if (!string.IsNullOrWhiteSpace(suffix))
{
//var contentTypeProvider = FS.GetFileExtensionContentTypeProvider();

View File

@ -4,7 +4,7 @@
<el-card :model="connection">
<h1>连接参数(Configuration)</h1>
<el-form label-position="top" :model="connection">
<el-row :gutter="20">
<el-row :gutter="6">
<el-col :span="8">
<el-form-item prop="host" label="协议|主机|端口">
<el-input v-model="connection.host" :disabled="connSuccess" type="password" show-password>
@ -49,7 +49,6 @@
<el-button
type="primary"
:icon="Setting"
size="default"
class="sub-btn"
:disabled="client.connected"
@click="createConnection"
@ -58,7 +57,7 @@
>
{{ client.connected ? '已连接(Connected)' : '连接(Connect)' }}
</el-button>
<el-button v-if="client.connected" type="warning" size="default" :icon="Discount" @click="destroyConnection" :loading="btnLoadingType === 'disconnect'"> 断开(Disconnect) </el-button>
<el-button v-if="client.connected" class="sub-btn" type="warning" :icon="Discount" @click="destroyConnection" :loading="btnLoadingType === 'disconnect'"> 断开(Disconnect) </el-button>
</el-col>
</el-row>
</el-form>
@ -67,7 +66,7 @@
<el-card shadow="hover">
<h1>订阅(Subscribe)</h1>
<el-form label-position="top" :model="subscription">
<el-row :gutter="20">
<el-row :gutter="6">
<el-col :span="12">
<el-form-item prop="topic" label="订阅主题(Topic)">
<el-input v-model="connection.subTopics" :disabled="subscribedSuccess" type="password" show-password></el-input>
@ -84,7 +83,6 @@
<el-button
type="primary"
:icon="Connection"
size="default"
class="sub-btn"
:style="{ display: subscribedSuccess ? 'none' : '' }"
:loading="btnLoadingType === 'subscribe'"
@ -93,16 +91,7 @@
>
{{ subscribedSuccess ? '已订阅(Subscribed)' : '订阅(Subscribe)' }}
</el-button>
<el-button
v-if="subscribedSuccess"
type="warning"
:icon="Discount"
size="default"
class="sub-btn"
:loading="btnLoadingType === 'unsubscribe'"
:disabled="!client.connected"
@click="doUnSubscribe"
>
<el-button v-if="subscribedSuccess" type="warning" :icon="Discount" class="sub-btn" :loading="btnLoadingType === 'unsubscribe'" :disabled="!client.connected" @click="doUnSubscribe">
取消(Unsubscribe)
</el-button>
</el-col>
@ -113,7 +102,7 @@
<el-card shadow="hover">
<h1>发布(Publish)</h1>
<el-form label-position="top" :model="publish">
<el-row :gutter="30">
<el-row :gutter="6">
<el-col :span="8">
<el-form-item prop="topic" label="发布主题(Topic)">
<el-input v-model="connection.pubTopic" type="password" show-password></el-input>
@ -136,7 +125,7 @@
</el-col>
</el-row>
<el-row :gutter="30">
<el-row :gutter="6">
<el-col :span="16">
<el-form-item prop="payload" label="操作指令(Payload)">
<el-input v-model="publish.payload" clearable maxlength="64" show-word-limit>
@ -158,15 +147,7 @@
</el-form-item>
</el-col>
<el-col :span="8" class="text-right">
<el-button
type="success"
:icon="Position"
size="default"
class="sub-btn"
:loading="btnLoadingType === 'publish'"
:disabled="!client.connected"
@click="doPublish(publish.payload, connection.pubTopic)"
>
<el-button type="success" :icon="Position" class="sub-btn" :loading="btnLoadingType === 'publish'" :disabled="!client.connected" @click="doPublish(publish.payload, connection.pubTopic)">
发布(Publish)
</el-button>
</el-col>
@ -176,113 +157,104 @@
<el-card shadow="hover">
<h1>
<el-button @click="clsmsg" type="Success" size="default" :icon="Delete" title="点击清空历史记录">接收(Receive)</el-button>
<el-tag size="default" title="接收次数"> {{ recvnum }}</el-tag>
<el-tag size="default" :title="dht_tm">{{ dht_wsd }}</el-tag>
<el-tag size="default" title="设备已工作时长">{{ parseInt(runSeconds) }} </el-tag>
<el-button @click="clsmsg" type="success" :icon="Delete" title="点击清空历史记录">接收(Receive)</el-button>
<el-tag title="接收次数"> {{ recvnum }}</el-tag>
<el-tag :title="dht_tm">{{ dht_wsd }}</el-tag>
<el-tag title="设备已工作时长">{{ parseInt(runSeconds) }} </el-tag>
<el-button
type="success"
title="关闭一路"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-if="connection.ch1_Status"
icon="ele-Check"
size="default"
id="ch1"
v-preventReClick="2000"
v-reclick="2000"
@click="switchLight('55 AA AA AA AA 81 01 00')"
>关闭</el-button
>
<el-button
type="warning"
title="打开一路"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-else="!connection.ch1_Status"
icon="ele-CloseBold"
size="default"
id="ch1"
v-preventReClick="2000"
v-reclick="2000"
@click="switchLight('55 AA AA AA AA 81 01 01')"
>打开</el-button
>
<el-button
type="success"
title="关闭二路"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-if="connection.ch2_Status"
icon="ele-Check"
size="default"
id="ch2"
v-preventReClick="2000"
v-reclick="2000"
@click="switchLight('55 AA AA AA AA 81 02 00')"
>关闭</el-button
>
<el-button
type="warning"
title="打开二路"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-else="!connection.ch2_Status"
icon="ele-CloseBold"
size="default"
id="ch2"
v-preventReClick="2000"
v-reclick="2000"
@click="switchLight('55 AA AA AA AA 81 02 01')"
>打开</el-button
>
<el-button
type="success"
title="关闭三路"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-if="connection.ch3_Status"
icon="ele-Check"
size="default"
id="ch3"
v-preventReClick="2000"
v-reclick="2000"
@click="switchLight('55 AA AA AA AA 81 03 00')"
>关闭</el-button
>
<el-button
type="warning"
title="打开三路"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-else="!connection.ch3_Status"
icon="ele-CloseBold"
size="default"
id="ch3"
v-preventReClick="2000"
v-reclick="2000"
@click="switchLight('55 AA AA AA AA 81 03 01')"
>打开</el-button
>
<el-button
type="success"
title="关闭四路"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-if="connection.ch4_Status"
icon="ele-Check"
size="default"
id="ch4"
v-preventReClick="2000"
v-reclick="2000"
@click="switchLight('55 AA AA AA AA 81 04 00')"
>关闭</el-button
>
<el-button
type="warning"
title="打开四路"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-else="!connection.ch4_Status"
icon="ele-CloseBold"
size="default"
id="ch4"
v-preventReClick="2000"
v-reclick="2000"
@click="switchLight('55 AA AA AA AA 81 04 01')"
>打开</el-button
>
<el-button
type="danger"
title="四路全部关闭"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-if="connection.all_Status"
icon="ele-SwitchButton"
size="default"
id="ch5"
@click="switchLight('55 AA AA AA AA 81 A4 00')"
>全关</el-button
@ -290,16 +262,15 @@
<el-button
type="success"
title="四路全部打开"
:disabled="!connection.onlineStatus | !client.connected"
:disabled="!connection.onlineStatus || !client.connected"
v-else="!connection.all_Status"
icon="ele-Switch"
size="default"
id="ch5"
@click="switchLight('55 AA AA AA AA 81 A4 01')"
>全开</el-button
>
<el-alert v-if="!client.connected || !connection.onlineStatus" title="网络服务断开或设备离线!" center type="warning" effect="light" />
<el-alert v-if="!client.connected || !connection.onlineStatus" title="网络服务断开或设备离线!" center type="warning" effect="light" style="margin-top: 4px" />
</h1>
<!-- 绑定接收日志只读 -->
<el-col :span="24">
@ -347,7 +318,7 @@ const retryTimes = ref(0); //重连次数
* ws -> 8083; wss -> 8084
* By default, EMQX allows clients to connect without authentication.
* https://docs.emqx.com/en/enterprise/v4.4/advanced/auth.html#anonymous-login
* for more options and details, please refer to https://github.com/mqttjs/MQTT.js#mqttclientstreambuilder-options
*/
const connection = reactive({
@ -748,20 +719,19 @@ const clsmsg = () => {
<style lang="scss" scoped>
.mqtt-box {
max-width: 100%;
padding: 4px;
margin: 10px auto 0 auto;
margin: 0 auto;
}
.header {
font-size: 24px;
font-weight: bold;
margin: -12px auto 8px auto;
margin: -6px auto 0px auto;
}
h1 {
font-size: 16px;
margin-top: 10px auto 20px auto;
padding: 5px 0px 5px 0;
padding: 6px 0px 6px 0;
}
.el-col {
@ -772,7 +742,7 @@ h1 {
font-size: 13px;
}
.el-card {
margin-bottom: 12px;
margin-bottom: 6px;
}
.el-card__body {
padding: 24px;

View File

@ -32,7 +32,11 @@
<el-button-group style="padding-left: 12px; padding-right: 12px">
<el-button icon="ele-Plus" @click="showAddColumn"> 增加列 </el-button>
<el-button icon="ele-Plus" @click="showGenDialog"> 生成实体 </el-button>
<el-button icon="ele-Plus" @click="showGenSeedDataDialog"> 生成种子 </el-button>
<el-popover placement="bottom" title="温馨提示" :width="200" trigger="hover" content="如果是刚刚生成的实体,请重启服务后再生成种子">
<template #reference>
<el-button icon="ele-Plus" @click="showGenSeedDataDialog"> 生成种子 </el-button>
</template>
</el-popover>
</el-button-group>
<el-button icon="ele-View" type="primary" @click="visualTable" plain> 可视化 </el-button>
</template>