Browse Source

feat:广告上传、查询

Zhenghanjv 2 months ago
parent
commit
6e6e74963f

+ 103 - 0
Platform/AI.Platform.Page/Pages/Media/Media.razor

@@ -0,0 +1,103 @@
+@page "/media/list"
+@attribute [ReuseTabsPage(Title = "广告列表")]
+
+<Spin Spinning="Loading">
+    <div  class="filter_box">
+        <div class="filter_row">
+            <span>文件名</span><Input Placeholder="请输入要查找的文件名" @bind-Value="filterData.searchFileName" Style="width:30%" />
+             <span>上传人</span><Input Placeholder="上传人" @bind-Value="filterData.searchMediaUploader" Style="width:30%" />
+        </div>
+        
+        <div class="filter_row">
+            <span>广告状态</span>
+            <SimpleSelect OnSelectedItemChanged="OnSelectItemChange" Style="width:30%">
+                <SelectOptions>
+                    <SimpleSelectOption Value="-1" Label="全部" style="width:30%" />
+                    <SimpleSelectOption Value="0" Label="禁用" style="width:30%" />
+                    <SimpleSelectOption Value="1" Label="可用" style="width:30%" />
+                </SelectOptions>
+            </SimpleSelect>
+
+           <span>油机状态</span>
+            <SimpleSelect Mode="SelectMode.Multiple" OnSelectedItemsChanged="OnSelectItemsChange" style="width:30%">
+                <SelectOptions>
+                    <SimpleSelectOption Value="idle" Label="空闲" />
+                    <SimpleSelectOption Value="lock" Label="锁枪" />
+                    <SimpleSelectOption Value="offline" Label="脱机" />
+                    <SimpleSelectOption Value="lift" Label="提枪" />
+                    <SimpleSelectOption Value="authorised" Label="授权" />
+                    <SimpleSelectOption Value="start" Label="开始" />
+                    <SimpleSelectOption Value="fueling" Label="加油中" />
+                </SelectOptions>
+            </SimpleSelect>
+        </div>
+
+        <div class="filter_row">
+            <span>有效时间段</span><RangePicker TValue="DateTime?[]" OnChange="@(date => onDateChage(date,1))" />
+            <span>更新时间</span><RangePicker TValue="DateTime?[]" OnChange="@(date => onDateChage(date, 2))" />
+        </div>
+        
+        <div class="filter_row" style="justify-content:start">
+            <span style="margin-right:5%">播放时段</span><RangePicker TValue="DateTime?[]" OnChange="@(date => onDateChage(date, 3))" Picker="DatePickerType.Time" Format="@("HH")"/>
+        </div>
+
+        <div class="filter_row" style="justify-content:start">
+            <Button Icon="search" OnClick="Query" Style="margin-right:2%">查询</Button>
+            <Button Icon="reload" OnClick="HandleReset" Style="margin-right:2%">重置</Button>
+            <Button Icon="upload" OnClick="@(() => ShowDialog(1, null))">上传广告</Button>
+        </div>
+    </div>
+
+    <UpdateMediaDialog onCallback="OnDialogCallback" onVisibleCallback="OnDialogVisibleCallback"  @bind-IsVisible="isOpen" @bind-model="model" />
+
+    @* <Table @ref="_Table" AutoHeight TItem="SystemMenu" DataSource="_DataSource" @bind-PageSize="Ps" @bind-PageIndex="Pi"
+           TreeChildren="item=>item.Children" @bind-SelectedRows="_SelectedRows" OnChange="OnChange">
+        <ColumnDefinitions Context="row">
+            <PropertyColumn Property="c => c.Name" Title="菜单名称" />
+            <PropertyColumn Property="c => c.Path" Title="路由" />
+            <PropertyColumn Property="c=>c.Necessary">
+                @{
+                    var tag = row.Necessary ? "必需" : "非必需";
+                    var color = row.Necessary ? TagColor.Green : TagColor.Blue;
+                }
+                <Tag Color="@color">@tag</Tag>
+            </PropertyColumn>
+            <PropertyColumn Property="c => c.Key" Title="自定义唯一键值" />
+            <PropertyColumn Property="c => c.Icon" Title="图标">
+                @{
+                    var type = row.Icon;
+                }
+                <Icon Type="@type" Theme="IconThemeType.Outline" />
+            </PropertyColumn>
+            <PropertyColumn Property="c => c.Sort" Title="排序" />
+        </ColumnDefinitions>
+        <PaginationTemplate>
+            <Pagination Class="@(context.PaginationClass + " my-custom-pagination")"
+                        Total="context.Total"
+                        PageSize="context.PageSize"
+                        Current="context.PageIndex"
+                        ShowSizeChanger
+                        OnChange="context.HandlePageChange" />
+        </PaginationTemplate>
+    </Table> *@
+</Spin>
+
+<style>
+    .filter_box{
+        display:flex;
+        flex-direction:column;
+        align-items:center;
+        background:#ffffff;
+        padding:2%;
+    }
+
+    .filter_row{
+        display:flex;
+        flex-direction:row;
+        justify-content:space-between;
+        align-items:center;
+        width:100%;
+        margin-top:2%;
+    }
+
+</style>

+ 277 - 0
Platform/AI.Platform.Page/Pages/Media/Media.razor.cs

@@ -0,0 +1,277 @@
+using AI.Platform.Core;
+using AI.Platform.Core.Entity.Media;
+using AI.Platform.Page.Pages.Media.Model;
+using AntDesign;
+using AntDesign.TableModels;
+using Dm.util;
+using Microsoft.AspNetCore.Components;
+using Microsoft.JSInterop;
+using SqlSugar;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace AI.Platform.Page.Pages.Media;
+
+public partial class Media
+{
+    /// <summary>
+    /// 
+    /// </summary>
+    [Inject] NavigationManager NavigationManager { get; set; }
+    /// <summary>
+    /// 数据库仓储
+    /// </summary>
+    [Inject] SqlSugarRepository<MediaEntity> _Repository { get; set; }
+    /// <summary>
+    /// 
+    /// </summary>
+    [Inject] IJSRuntime IJSRuntime { get; set; }
+    /// <summary>
+    ///
+    /// </summary>
+    private ITable _Table;
+    /// <summary>
+    ///
+    /// </summary>
+    private IEnumerable<SystemMenu> _SelectedRows = [];
+    /// <summary>
+    /// 广告列表信息
+    /// </summary>
+    private List<MediaEntity> _DataSource;
+    /// <summary>
+    ///
+    /// </summary>
+    private int Pi = 1;
+    /// <summary>
+    ///
+    /// </summary>
+    private int Ps = 20;
+
+    /// <summary>
+    /// 总条数
+    /// </summary>
+    private int Total = 0;
+    /// <summary>
+    /// 加载
+    /// </summary>
+    private bool Loading = false;
+
+    /// <summary>
+    /// 查询过滤条件
+    /// </summary>
+    private FilterData filterData { set; get; } = new();
+
+    /// <summary>
+    /// 编辑弹窗
+    /// </summary>
+    private UpdateMediaDialog updateMediaDialog { set; get; } = new();
+
+    private bool isOpen { set; get; } = false;
+
+    private MediaDialogModel model = new MediaDialogModel();
+
+    private async Task ShowDialog(int type,MediaEntity? media)
+    {
+        model = new MediaDialogModel();
+        model.Type = type;
+        if(type == 2)
+        {
+            model.FileName = media?.FileName ?? "";
+            model.MediaUploader = media?.Uploader ?? "";
+            model.StartTime = media?.StartTime;
+            model.EndTime = media?.EndTime;
+            model.EffecitiveTime = media?.EffectiveTime;
+            model.FailureTime = media?.FailureTime;
+            model.MediaState = media?.MediaState ?? 0;
+            model.MachineStateList = JsonSerializer.Deserialize<List<string>>(media?.MachineState ?? "[]");
+        }
+
+        isOpen = true;
+    }
+    private void OnUploadChange(UploadInfo info)
+    {
+        // 处理上传逻辑
+    }
+    /// <summary>
+    /// 弹窗信息回调
+    /// </summary>
+    /// <param name="model"></param>
+    private async Task OnDialogCallback(MediaDialogModel model)
+    {
+        Console.WriteLine(model);
+        await _Repository.InsertAsync(model.ToCompany());
+        
+            
+    }
+
+    private void OnDialogVisibleCallback(bool isOpen)
+    {
+        this.isOpen = isOpen;
+    }
+
+    /// <summary>
+    /// 查
+    /// </summary>
+    /// <returns></returns>
+    private async Task Query()
+    {
+        Loading = true;
+
+        _DataSource = await _Repository.AsQueryable()
+            .WhereIF(filterData.searchFileName != null, it => it.FileName.Contains(filterData.searchFileName))
+            .WhereIF(filterData.searchMediaUploader != null, it => it.Uploader.Contains(filterData.searchMediaUploader))
+            .WhereIF(filterData.searchMediaState != null && filterData.searchMediaState != -1, it => it.MediaState == filterData.searchMediaState)
+            .WhereIF(filterData.searchMachineStateList.IsNotNullOrEmpty(), it => SqlFunc.ContainsArray(filterData.searchMachineStateList, it.MachineState))
+            .WhereIF(filterData.searchStartTime != null && filterData.searchEndTime != null, it => it.StartTime >= filterData.searchStartTime && it.EndTime <= filterData.searchEndTime)
+            .WhereIF(filterData.searchEffecitiveTime != null && filterData.searchFailureTime != null, it => it.EffectiveTime >= filterData.searchEffecitiveTime && it.FailureTime <= filterData.searchFailureTime)
+            .WhereIF(filterData.searchStartEditTime != null && filterData.searchEndEditTime != null, it => it.EditTime >= filterData.searchStartEditTime && it.EditTime <= filterData.searchEndEditTime)
+            .OrderByDescending(it => it.EditTime)
+            .ToPageListAsync(filterData.currentPage,filterData.pageSize);
+
+        Total = _DataSource.size();
+
+        Loading = false;
+    }
+
+    /// <summary>
+    /// 清空查询条件
+    /// </summary>
+    private void HandleReset()
+    {
+
+    }
+
+    /// <summary>
+    /// 单选选择器选择事件
+    /// </summary>
+    /// <param name="value">选择的值</param>
+    private void OnSelectItemChange(string value)
+    {
+        Console.WriteLine(value);
+        int state = -1;
+        int.TryParse(value, out state);
+        filterData.searchMediaState = state;
+    }
+
+    /// <summary>
+    /// 多选选择器选择事件
+    /// </summary>
+    /// <param name="values">选择的值</param>
+    private void OnSelectItemsChange(IEnumerable<string> values)
+    {
+        Console.WriteLine(values);
+        filterData.searchMachineStateList = values.ToList();
+    }
+
+    /// <summary>
+    /// 日期选择器选择回调
+    /// </summary>
+    /// <param name="value">选择的日期</param>
+    /// <param name="type">1:有效时间段;2:更新时间;3:播放时段</param>
+    private void onDateChage(DateRangeChangedEventArgs<DateTime?[]> value,int type)
+    {
+        switch (type)
+        {
+            case 1:
+                filterData.searchEffecitiveTime = value.Dates[0];
+                filterData.searchFailureTime = value.Dates[1];
+                break;
+            case 2:
+                filterData.searchStartEditTime = value.Dates[0];
+                filterData.searchEndEditTime = value.Dates[1];
+                break;
+            case 3:
+                DateTime? startTime = value.Dates[0];
+                DateTime? endTime = value.Dates[1];
+                filterData.searchStartTime = startTime?.Hour;
+                filterData.searchEndTime = endTime?.Hour;
+                break;
+        }
+        
+    }
+
+    protected override async void OnInitialized()
+    {
+
+    }
+
+    protected override async Task OnAfterRenderAsync(bool firstRender)
+    {
+        if (firstRender)
+        {
+            await NavigationManager.RedirectLogin(IJSRuntime);
+            await Query();
+        }
+    }
+
+    private async Task OnChange(QueryModel<SystemMenu> query)
+        => await Query();
+
+
+    /// <summary>
+    /// 查找条件
+    /// </summary>
+    public class FilterData
+    {
+        /// <summary>
+        /// 页码
+        /// </summary>
+        public int currentPage { set; get; } = 1;
+
+        /// <summary>
+        /// 页数
+        /// </summary>
+        public int pageSize { set; get; } = 10;
+
+        /// <summary>
+        /// 要查找的文件名
+        /// </summary>
+        public string? searchFileName { set; get; }
+
+        /// <summary>
+        /// 要查找文件开始播放时间
+        /// </summary>
+        public int? searchStartTime { set; get; }
+
+        /// <summary>
+        /// 要查找文件结束播放时间
+        /// </summary>
+        public int? searchEndTime { set; get; }
+
+        /// <summary>
+        /// 要查找文件生效时间
+        /// </summary>
+        public DateTime? searchEffecitiveTime { set; get; }
+
+        /// <summary>
+        /// 要查找文件失效时间
+        /// </summary>
+        public DateTime? searchFailureTime { set; get; }
+
+        /// <summary>
+        /// 要查找文件油机状态
+        /// </summary>
+        public List<string>? searchMachineStateList { set; get; }
+
+        /// <summary>
+        /// 要查找文件广告状态 0:禁用;1:可用
+        /// </summary>
+        public int? searchMediaState { set; get; }
+
+        /// <summary>
+        /// 要查找文件上传人
+        /// </summary>
+        public string? searchMediaUploader { set; get; }
+
+        /// <summary>
+        /// 根据文件修改时间范围查找(开始时间)
+        /// </summary>
+        public DateTime? searchStartEditTime { set; get; }
+
+        /// <summary>
+        /// 根据文件修改时间范围查找(结束时间)
+        /// </summary>
+        public DateTime? searchEndEditTime { set; get; }
+
+    }
+}

+ 109 - 0
Platform/AI.Platform.Page/Pages/Media/Model/MediaModel.cs

@@ -0,0 +1,109 @@
+using AI.Platform.Core.Entity.Media;
+using Microsoft.AspNetCore.Components;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+
+namespace AI.Platform.Page.Pages.Media.Model
+{
+    public class MediaModel
+    {
+    }
+
+    /// <summary>
+    /// 用于新增/修改广告时传递弹窗数据
+    /// </summary>
+    public class MediaDialogModel
+    {
+        /// <summary>
+        /// 类型:1:新增;2:编辑;3:删除
+        /// </summary>
+        public int Type { get; set; }
+
+        /// <summary>
+        /// 文件名
+        /// </summary>
+        public string FileName { set; get; }
+
+        /// <summary>
+        /// 文件后缀
+        /// </summary>
+        public string FileExtension { set; get; }
+
+        /// <summary>
+        /// guid文件名
+        /// </summary>
+        public string GuidFileName { set; get; }
+
+        /// <summary>
+        /// 保存到服务器的地址
+        /// </summary>
+        public string SavePath { set; get; }
+
+        /// <summary>
+        /// 文件开始播放时间
+        /// </summary>
+        public int? StartTime { set; get; }
+
+        /// <summary>
+        /// 文件结束播放时间
+        /// </summary>
+        public int? EndTime { set; get; }
+
+        /// <summary>
+        /// 文件生效时间
+        /// </summary>
+        public DateTime? EffecitiveTime { set; get; }
+
+        /// <summary>
+        /// 文件失效时间
+        /// </summary>
+        public DateTime? FailureTime { set; get; }
+
+        /// <summary>
+        /// 文件油机状态
+        /// </summary>
+        public List<string> MachineStateList { set; get; }
+
+        /// <summary>
+        /// 文件广告状态 0:禁用;1:可用
+        /// </summary>
+        public int MediaState { set; get; }
+
+        /// <summary>
+        /// 文件上传人
+        /// </summary>
+        public string MediaUploader { set; get; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        public string Remark { set; get; }
+
+
+        public MediaEntity ToCompany()
+        {
+            
+            return new MediaEntity()
+            {
+                LocalPath = SavePath,
+                FileName = FileName,
+                GroupID = "",
+                BusinessUnitID = "",
+                FileExtension = this.FileExtension,
+                GuidFileName = this.GuidFileName,
+                StartTime = this.StartTime ?? 0,
+                EndTime = this.EndTime ?? 0,
+                EffectiveTime = this.EffecitiveTime ?? DateTime.Now,
+                FailureTime = this.FailureTime ?? DateTime.Now,
+                MachineState = JsonSerializer.Serialize(this.MachineStateList),
+                MediaState = this.MediaState,
+                Uploader = this.MediaUploader ?? "",
+                CreateTime = DateTime.Now,
+                EditTime = DateTime.Now,
+                Remark = this.Remark
+            };
+        }
+    }
+}

+ 261 - 0
Platform/AI.Platform.Page/Pages/Media/UpdateMediaDialog.razor

@@ -0,0 +1,261 @@
+@using AI.Platform.Page.Pages.Media.Model
+@using System.Threading.Tasks
+@using System.Text.Json
+
+@if (IsVisible)
+{
+    <div class="modal-overlay">
+        <div class="modal-content filter_box">
+            @if (Model?.Type == 1 || Model?.Type == 2)
+            {
+                <div class="filter_row">
+                    <span>文件名</span><Input Placeholder="文件名" @bind-Value="Model.FileName" Style="width:30%" Disabled />
+                    <span>上传人</span><Input Placeholder="上传人" @bind-Value="Model.MediaUploader" Style="width:30%" Disabled />
+                </div>
+
+                <div class="filter_row">
+                    <span>广告状态</span>
+                    <SimpleSelect DefaultValue="@Model.MediaState.ToString()" OnSelectedItemChanged="OnSelectItemChange" Style="width:30%">
+                        <SelectOptions>
+                            <SimpleSelectOption Value="0" Label="禁用" style="width:30%" />
+                            <SimpleSelectOption Value="1" Label="可用" style="width:30%" />
+                        </SelectOptions>
+                    </SimpleSelect>
+
+                    <span>油机状态</span>
+                    <SimpleSelect DefaultValues="@Model.MachineStateList" OnSelectedItemsChanged="OnSelectItemsChange" Mode="SelectMode.Multiple" style="width:30%">
+                        <SelectOptions>
+                            <SimpleSelectOption Value="idle" Label="空闲" />
+                            <SimpleSelectOption Value="lock" Label="锁枪" />
+                            <SimpleSelectOption Value="offline" Label="脱机" />
+                            <SimpleSelectOption Value="lift" Label="提枪" />
+                            <SimpleSelectOption Value="authorised" Label="授权" />
+                            <SimpleSelectOption Value="start" Label="开始" />
+                            <SimpleSelectOption Value="fueling" Label="加油中" />
+                        </SelectOptions>
+                    </SimpleSelect>
+                </div>
+
+                <div class="filter_row">
+                    <span>有效时间段</span><RangePicker TValue="DateTime?[]" OnChange="@(date => onDateChage(date, 1))" />
+                    <span style="margin-right:5%">播放时段</span><RangePicker TValue="DateTime?[]" Picker="DatePickerType.Time" Format="@("HH")" OnChange="@(date => onDateChage(date, 2))" />
+                </div>
+
+                <div class="filter_row" style="justify-content:start">
+                    <span>备注</span><Input Placeholder="备注" @bind-Value="Model.Remark" />
+                </div>
+            }
+
+            @if(Model?.Type == 1)
+            {
+                <Upload class="filter_row" Name="file" style="justify-content:center" Action="@Global.MediaUploadUrl" 
+                @bind-FileList="fileList" ListType="UploadListType.PictureCard"
+                ShowUploadList="true" ShowDownloadIcon="true" ShowPreviewIcon="true" ShowRemoveIcon="true" ShowButton="fileList.Count < 1"
+                OnCompleted="OnUploadCompleted" OnRemove="OnRemove">
+                    <div>
+                        <Icon Type="plus" />
+                        <div className="ant-upload-text">上传文件</div>
+                    </div>
+                </Upload>
+            }
+
+            <div class="filter_row" style="justify-content:end;margin-top:5%;">
+                <Button Icon="plus" OnClick="onSure" Style="margin-right:2%">确定</Button>
+                <Button Icon="reload" OnClick="Close" Style="margin-right:2%">取消</Button>
+            </div>
+        </div>
+        
+    </div>
+}
+
+
+@code {
+
+    /// <summary>
+    /// 信息回调
+    /// </summary>
+    [Parameter] public EventCallback<MediaDialogModel> ModelChanged { get; set; }
+
+    /// <summary>
+    /// 打开/关闭窗口回调
+    /// </summary>
+    [Parameter] public EventCallback<bool> IsVisibleChanged { get; set; }
+
+    /// <summary>
+    /// 信息回调
+    /// </summary>
+    [Parameter] public EventCallback<MediaDialogModel> onCallback { get; set; }
+
+    /// <summary>
+    /// 打开/关闭窗口回调
+    /// </summary>
+    [Parameter] public EventCallback<bool> onVisibleCallback { get; set; }
+
+    /// <summary>
+    /// 数据
+    /// </summary>
+    [Parameter] public MediaDialogModel Model { get; set; }
+
+    /// <summary>
+    /// 配置是否弹窗
+    /// </summary>
+    [Parameter] public bool IsVisible { get; set; }
+
+    private List<UploadFileItem> fileList = new List<UploadFileItem>();
+
+    /// <summary>
+    /// 关闭弹窗
+    /// </summary>
+    public async Task Close()
+    {
+        await OnlyClose();
+        if(Model.SavePath.IsNotNullOrEmpty()) File.Delete(Model.SavePath);
+    }
+    /// <summary>
+    /// 仅关闭弹窗
+    /// </summary>
+    /// <returns></returns>
+    private async Task OnlyClose()
+    {
+        if (IsVisibleChanged.HasDelegate)
+        {
+            await IsVisibleChanged.InvokeAsync(false);
+        }
+
+        if (onVisibleCallback.HasDelegate)
+        {
+            await onVisibleCallback.InvokeAsync(false);
+        }
+    }
+
+    /// <summary>
+    /// 上传文件完毕
+    /// </summary>
+    /// <param name="info"></param>
+    private void OnUploadCompleted(UploadInfo info)
+    {
+        string responseJson =  info.File.Response;
+        var response = JsonSerializer.Deserialize<Service.Output.Response<Service.Output.MediaFileUploadOutput>>(responseJson);
+
+        Model.FileName = response?.data.fileName ?? "";
+        Model.SavePath = response?.data.savePath ?? "";
+        Model.GuidFileName = response?.data.guidName ?? "";
+        Model.FileExtension = response?.data.extension ?? "";
+
+    }
+
+    private async Task<bool> OnRemove(UploadFileItem fileItem)
+    {
+        Console.WriteLine(fileItem);
+        if (Model.SavePath.IsNotNullOrEmpty()) File.Delete(Model.SavePath);
+        return true;
+    }
+
+    /// <summary>
+    /// 单选选择器选择事件
+    /// </summary>
+    /// <param name="value">选择的值</param>
+    private void OnSelectItemChange(string value)
+    {
+        Console.WriteLine(value);
+        int state = -1;
+        int.TryParse(value, out state);
+        Model.MediaState = state;
+    }
+
+    /// <summary>
+    /// 多选选择器选择事件
+    /// </summary>
+    /// <param name="values">选择的值</param>
+    private void OnSelectItemsChange(IEnumerable<string> values)
+    {
+        Console.WriteLine(values);
+        Model.MachineStateList = values.ToList();
+    }
+
+    /// <summary>
+    /// 日期选择器选择回调
+    /// </summary>
+    /// <param name="value">选择的日期</param>
+    /// <param name="type">1:有效时间段;2:播放时段</param>
+    private void onDateChage(DateRangeChangedEventArgs<DateTime?[]> value, int type)
+    {
+        switch (type)
+        {
+            case 1:
+                Model.EffecitiveTime = value.Dates[0];
+                Model.FailureTime = value.Dates[1];
+                break;
+            case 2:
+                DateTime? startTime = value.Dates[0];
+                DateTime? endTime = value.Dates[1];
+                Model.StartTime = startTime?.Hour;
+                Model.EndTime = endTime?.Hour;
+                break;
+        }
+    }
+
+    /// <summary>
+    /// 确定按钮事件
+    /// </summary>
+    /// <returns></returns>
+    private async Task onSure()
+    {
+        if (ModelChanged.HasDelegate)
+        {
+            await ModelChanged.InvokeAsync(Model);
+        }
+
+        if (onCallback.HasDelegate)
+        {
+            await onCallback.InvokeAsync(Model);
+        }
+        await OnlyClose();
+    }
+
+
+
+}
+
+
+<style>
+    /* 遮罩层:全屏、半透明 */
+    .modal-overlay {
+        position: fixed;
+        top: 0;
+        left: 0;
+        width: 100vw;
+        height: 100vh;
+        background-color: rgba(0, 0, 0, 0.5); /* 半透明黑色遮罩 */
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        z-index: 1000;
+    }
+
+    /* 弹窗内容:白色卡片,居中由父容器控制 */
+    .modal-content {
+        background: white;
+        border-radius: 8px;
+        width: 80%;
+        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+        /* 注意:不要设 height: 100vh,否则会拉满全屏 */
+    }
+
+    .filter_box {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        background: #ffffff;
+        padding: 2%;
+    }
+
+    .filter_row {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        align-items: center;
+        width: 100%;
+        margin-top: 2%;
+    }
+</style>

+ 56 - 0
Platform/AI.Platform.Service/FileService.cs

@@ -8,6 +8,8 @@ using AI.Platform.Core;
 using static AI.Platform.Core.Entity.PublicEnum;
 using System.Net;
 using System;
+using AI.Platform.Service.Output;
+using Microsoft.AspNetCore.Http.HttpResults;
 
 namespace AI.Platform.Service;
 
@@ -66,4 +68,58 @@ public class FileService : BaseService
         var relativePath = $"/image/{classification}/{currentDate:yyyy}/{currentDate:MM}/{currentDate:dd}/{fileName}";
         return relativePath;
     }
+
+    /// <summary>
+    /// 上传多媒体文件
+    /// </summary>
+    /// <param name="classification"></param>
+    /// <returns></returns>
+    [HttpPost, AllowAnonymous]
+    public async Task<MediaFileUploadOutput> UploadMedia(IFormFile file)
+    {
+       
+        if (file == null || file.Length <= 0)
+        {
+            return new MediaFileUploadOutput()
+            {
+                isSuccess = false,
+                msg = "上传文件为空"
+            };
+        }
+
+        using var memoryStream = new MemoryStream();
+        file.CopyTo(memoryStream);
+        var fileBytes = memoryStream.ToArray();
+
+        // 获取文件扩展名
+        var fileExtension = Path.GetExtension(file.FileName);
+        // 生成文件名
+        var id = Guid.NewGuid().ToString().ToUpper().Replace("-", "");
+        var fileName = $"{id}_{file.FileName}";
+        // 获取当前日期
+        var currentDate = DateTime.Now;
+        // 构建目录路径
+        var directoryPath = Path.Combine("wwwroot", "madia", currentDate.ToString("MM"), currentDate.ToString("dd"));
+        // 创建目录
+        if (!Directory.Exists(directoryPath))
+        {
+            Directory.CreateDirectory(directoryPath);
+        }
+        // 构建文件路径
+        var filePath = Path.Combine(directoryPath, fileName);
+        // 保存文件
+        await System.IO.File.WriteAllBytesAsync(filePath, fileBytes);
+
+        //// 构建返回的相对路径
+        //var relativePath = $"/image/{currentDate:yyyy}/{currentDate:MM}/{currentDate:dd}/{fileName}";
+        //return relativePath;
+        return new MediaFileUploadOutput()
+        {
+            isSuccess = true,
+            msg = "上传成功",
+            fileName = file.FileName,
+            guidName = fileName,
+            savePath = filePath
+        };
+    }
 }

+ 55 - 0
Platform/AI.Platform.Service/Output/MediaFileUploadOutput.cs

@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace AI.Platform.Service.Output
+{
+
+    public class Response<T>
+    {
+        public int code { set; get; }
+
+        public bool isSuccess { set; get; }
+
+        public string message { set; get; }
+
+        public T data { set; get; }
+
+    }
+
+    /// <summary>
+    /// 用于多媒体文件上传返回响应内容
+    /// </summary>
+    public class MediaFileUploadOutput
+    {
+        /// <summary>
+        /// 是否成功
+        /// </summary>
+        public bool isSuccess { set;get;  }
+
+        /// <summary>
+        /// 说明
+        /// </summary>
+        public string msg {  set; get; }
+
+        /// <summary>
+        /// 存到服务器的地址
+        /// </summary>
+        public string savePath { set; get; }
+
+        /// <summary>
+        /// 文件名
+        /// </summary>
+        public string fileName { set; get; }
+
+        /// <summary>
+        /// 加上guid前缀文件名
+        /// </summary>
+        public string guidName { set; get; }
+
+        /// <summary>
+        /// 后缀名
+        /// </summary>
+        public string extension { set; get; }
+    }
+}

+ 3 - 0
Platform/AI.Platform.Tool/Configuration/App.json

@@ -44,5 +44,8 @@
   "Upload": {
     "Url": "http://localhost:48747/api/file/uploadImage",
     "MaxSize": 1024 // 单位MB
+  },
+  "MediaUpload": {
+    "Url": "http://localhost:5076/api/File/UploadMedia"
   }
 }

+ 1 - 1
Platform/AI.Platform.Tool/Configuration/DataBase.json

@@ -10,7 +10,7 @@
       {
         "ConfigId": "0", //默认库标识-禁止修改
         "DbType": "MySql", //MySql、SqlServer、Sqlite、Oracle、PostgreSQL、Dm、Kdbndp、Oscar、MySqlConnector、Access、OpenGauss、QuestDB、HG、ClickHouse、GBase、Odbc、Custom
-        "ConnectionString": "Data Source=localhost;Port=3307;Initial Catalog=thesystem;Persist Security Info=True;User ID=root;Password=Wayne@123;Pooling=True;charset=utf8mb4;MAX Pool Size=200;Min Pool Size=1;Connection Lifetime=30;AllowLoadLocalInfile=true;", // 库连接字符串
+        "ConnectionString": "Data Source=localhost;Port=3306;Initial Catalog=thesystem;Persist Security Info=True;User ID=root;Password=123456;Pooling=True;charset=utf8mb4;MAX Pool Size=200;Min Pool Size=1;Connection Lifetime=30;AllowLoadLocalInfile=true;", // 库连接字符串
         //"ConnectionString": "Data Source=./thesystem.db",
         "DbSettings": {
           "EnableDiffLog": true, //启用库表差异日志

+ 57 - 0
Platform/AI.Platform.Tool/Entity/Media/MediaEntity.cs

@@ -0,0 +1,57 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace AI.Platform.Core.Entity.Media
+{
+    [SugarTable(null,"广告列表")]
+    public class MediaEntity: EntityBaseLite
+    {
+        [SugarColumn(ColumnDescription = "集团ID", IsNullable = false,DefaultValue = "")]
+        public string GroupID {  get; set; }
+
+        [SugarColumn(ColumnDescription = "站点ID", IsNullable = false, DefaultValue = "")]
+        public string BusinessUnitID { get; set; }
+
+        [SugarColumn(ColumnDescription = "广告文件本地存储路径", IsNullable = false, DefaultValue = "")]
+        public string LocalPath { get; set; }
+
+        [SugarColumn(ColumnDescription = "文件名", IsNullable = false, DefaultValue = "")]
+        public string FileName { get; set; }
+
+        [SugarColumn(ColumnDescription = "加上Guid前缀文件名", IsNullable = false, DefaultValue = "")]
+        public string GuidFileName { get; set; }
+
+        [SugarColumn(ColumnDescription = "文件后缀", IsNullable = false, DefaultValue = "")]
+        public string FileExtension { get; set; }
+
+        [SugarColumn(ColumnDescription = "开始播放时间(小时,0~23)", IsNullable = false)]
+        public int StartTime { get; set; }
+
+        [SugarColumn(ColumnDescription = "结束播放时间(小时,0~23)", IsNullable = false)]
+        public int EndTime { get; set; }
+
+        [SugarColumn(ColumnDescription = "广告生效日期", IsNullable = false)]
+        public DateTime EffectiveTime { get; set; }
+
+        [SugarColumn(ColumnDescription = "广告失效日期", IsNullable = false)]
+        public DateTime FailureTime { get; set; }
+
+        [SugarColumn(ColumnDescription = "油机状态,json串存储。设置该广告在什么油机状态下播放", IsNullable = false)]
+        public string MachineState { get; set; }
+
+        [SugarColumn(ColumnDescription = "广告状态,0:禁用;1:启用", IsNullable = false)]
+        public int MediaState { get; set; }
+
+        [SugarColumn(ColumnDescription = "上传人", IsNullable = false, DefaultValue = "")]
+        public string Uploader { get; set; }
+
+        [SugarColumn(ColumnDescription = "修改时间", IsNullable = false)]
+        public DateTime EditTime { get; set; }
+
+        [SugarColumn(ColumnDescription = "备注", IsNullable = true, DefaultValue = "")]
+        public string Remark{ get; set; }
+
+    }
+}

+ 2 - 0
Platform/AI.Platform.Tool/Entity/System/SystemMenu.cs

@@ -99,5 +99,7 @@ public class SystemMenuSeedData : ISeedData<SystemMenu>
             new SystemMenu() { Id = 18, ParentId = 19, Path="/report/shiftSettlementDailyReport", Name="班结日报表", Key="report.shiftSettlementDailyReport", Icon="snippets", Sort=1, Enabled=true, CreateTime = DateTime.Now },
             new SystemMenu() { Id = 20, ParentId = 19, Path="/report/shiftSalesReport", Name="班次销售报表", Key="report.shiftSalesReport", Icon="snippets", Sort=1, Enabled=true, CreateTime = DateTime.Now },
 
+             new SystemMenu() { Id = 21, ParentId = 0, Path="/media", Name="媒体管理", Key="media", Icon="appstore", Sort=1, Enabled=true, CreateTime = DateTime.Now },
+            new SystemMenu() { Id = 22, ParentId = 21, Path="/media/list", Name="广告列表", Key="media.list", Icon="snippets", Sort=1, Enabled=true, CreateTime = DateTime.Now },
         ];
 }

+ 2 - 2
Platform/AI.Platform.Tool/Entity/System/SystemUser.cs

@@ -151,9 +151,9 @@ public class SystemUserSeedData : ISeedData<SystemUser>
 
 public class LoginInput
 {
-    [Required] public string Account { get; set; }
+    [Required] public string Account { get; set; } = "admin";
 
-    [Required] public string Password { get; set; }
+    [Required] public string Password { get; set; } = "123456";
 
     public string Mobile { get; set; }
 

+ 5 - 1
Platform/AI.Platform.Tool/Util/Global.cs

@@ -44,7 +44,11 @@ public static class Global
     /// <summary>
     /// 上传地址
     /// </summary>
-    public static string UploadUrl { get { return Setting.Get<string>("Upload:Url"); } }
+    public static string UploadUrl { get { return Setting.Get<string>("Upload:Url"); } }
+    /// <summary>
+    /// 媒体文件上传地址
+    /// </summary>
+    public static string MediaUploadUrl { get { return Setting.Get<string>("MediaUpload:Url"); } }
     /// <summary>
     /// 富文本apikey
     /// </summary>

+ 5 - 0
Platform/AI.Platform.Web/AI.Platform.Web.csproj

@@ -26,5 +26,10 @@
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </Content>
   </ItemGroup>
+  
+  <ItemGroup>
+    <Folder Include="wwwroot\madia\01\" />
+    <Folder Include="wwwroot\madia\01\20\" />
+  </ItemGroup>
 
 </Project>

+ 7 - 4
Platform/AI.Platform.Web/Components/Pages/Account/Login/Login.razor.cs

@@ -1,7 +1,9 @@
-using AI.Platform.Web.Common;
-using AI.Platform.Core;
+using AI.Platform.Core;
 using AI.Platform.Core.Util;
+using AI.Platform.Page.Pages.Media;
+using AI.Platform.Web.Common;
 using Microsoft.JSInterop;
+using System.Collections.Generic;
 
 namespace AI.Platform.Web.Components.Pages.Account.Login;
 
@@ -110,8 +112,9 @@ public partial class Login
         }
 
         //AuthStateProvider.SignIn(Global.CurrentUser);
-
-        NavigationManager.NavigateTo("/");
+        
+        //NavigationManager.NavigateTo("/");
+        NavigationManager.NavigateTo("/media/list");
     }
 
     /// <summary>

+ 3 - 3
Platform/AI.Platform.Web/Properties/launchSettings.json

@@ -7,7 +7,7 @@
         "ASPNETCORE_ENVIRONMENT": "Development"
       },
       "dotnetRunMessages": true,
-      "applicationUrl": "http://10.153.140.8:5076"
+      "applicationUrl": "http://0.0.0.0:5076"
     },
     "IIS Express": {
       "commandName": "IISExpress",
@@ -19,10 +19,10 @@
     "WSL": {
       "commandName": "WSL2",
       "launchBrowser": true,
-      "launchUrl": "http://10.153.140.8:5076",
+      "launchUrl": "http://0.0.0.0:5076",
       "environmentVariables": {
         "ASPNETCORE_ENVIRONMENT": "Development",
-        "ASPNETCORE_URLS": "http://10.153.140.8:5076"
+        "ASPNETCORE_URLS": "http://0.0.0.0:5076"
       },
       "distributionName": ""
     }

+ 43 - 43
Platform/AI.Platform.sln

@@ -1,43 +1,43 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 18
-VisualStudioVersion = 18.0.11205.157
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Platform.Web", "AI.Platform.Web\AI.Platform.Web.csproj", "{CD72F325-F64D-5992-45B2-04A79568251A}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Platform.Page", "AI.Platform.Page\AI.Platform.Page.csproj", "{0CD1C335-D77D-C117-9863-C4A896E9F9EF}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Platform.Core", "AI.Platform.Tool\AI.Platform.Core.csproj", "{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Platform.Service", "AI.Platform.Service\AI.Platform.Service.csproj", "{43370A18-DDB2-A1E7-4393-06E6346C702A}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Any CPU = Debug|Any CPU
-		Release|Any CPU = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{CD72F325-F64D-5992-45B2-04A79568251A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{CD72F325-F64D-5992-45B2-04A79568251A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{CD72F325-F64D-5992-45B2-04A79568251A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{CD72F325-F64D-5992-45B2-04A79568251A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{0CD1C335-D77D-C117-9863-C4A896E9F9EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{0CD1C335-D77D-C117-9863-C4A896E9F9EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{0CD1C335-D77D-C117-9863-C4A896E9F9EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{0CD1C335-D77D-C117-9863-C4A896E9F9EF}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}.Release|Any CPU.Build.0 = Release|Any CPU
-		{43370A18-DDB2-A1E7-4393-06E6346C702A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{43370A18-DDB2-A1E7-4393-06E6346C702A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{43370A18-DDB2-A1E7-4393-06E6346C702A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{43370A18-DDB2-A1E7-4393-06E6346C702A}.Release|Any CPU.Build.0 = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {EB731BF7-1359-44A5-9345-349878B2E2F0}
-	EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 18
+VisualStudioVersion = 18.0.11205.157
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Platform.Web", "AI.Platform.Web\AI.Platform.Web.csproj", "{CD72F325-F64D-5992-45B2-04A79568251A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Platform.Page", "AI.Platform.Page\AI.Platform.Page.csproj", "{0CD1C335-D77D-C117-9863-C4A896E9F9EF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Platform.Core", "AI.Platform.Tool\AI.Platform.Core.csproj", "{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI.Platform.Service", "AI.Platform.Service\AI.Platform.Service.csproj", "{43370A18-DDB2-A1E7-4393-06E6346C702A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{CD72F325-F64D-5992-45B2-04A79568251A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CD72F325-F64D-5992-45B2-04A79568251A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CD72F325-F64D-5992-45B2-04A79568251A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CD72F325-F64D-5992-45B2-04A79568251A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0CD1C335-D77D-C117-9863-C4A896E9F9EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0CD1C335-D77D-C117-9863-C4A896E9F9EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0CD1C335-D77D-C117-9863-C4A896E9F9EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0CD1C335-D77D-C117-9863-C4A896E9F9EF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F5217BB3-0108-E0D0-9D3D-97F53B0D92A7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{43370A18-DDB2-A1E7-4393-06E6346C702A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{43370A18-DDB2-A1E7-4393-06E6346C702A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{43370A18-DDB2-A1E7-4393-06E6346C702A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{43370A18-DDB2-A1E7-4393-06E6346C702A}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {EB731BF7-1359-44A5-9345-349878B2E2F0}
+	EndGlobalSection
+EndGlobal