Server: finish jtag controller; Web: finish sibebar animation

This commit is contained in:
SikongJueluo 2025-04-05 19:41:56 +08:00
parent 342a5a2436
commit 20d4fa12d8
No known key found for this signature in database
15 changed files with 336 additions and 168 deletions

View File

@ -33,9 +33,8 @@ if (app.Environment.IsDevelopment())
}); });
} }
// Setup UDP Server // Setup Program
var udpServer = new UDPServer(33000); MsgBus.Init();
udpServer.Start();
// Router // Router
app.MapGet("/", () => "Hello World!"); app.MapGet("/", () => "Hello World!");
@ -46,6 +45,5 @@ app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage);
app.Run("http://localhost:5000"); app.Run("http://localhost:5000");
// Close UDP Server // Close UDP Server
Console.WriteLine("UDP Server is Closing now..."); Console.WriteLine("Program is Closing now...");
udpServer.Stop(); MsgBus.Exit();

View File

@ -9,6 +9,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DotNext" Version="5.19.1" /> <PackageReference Include="DotNext" Version="5.19.1" />
<PackageReference Include="DotNext.Threading" Version="5.19.1" />
<PackageReference Include="Microsoft.OpenApi" Version="1.6.23" /> <PackageReference Include="Microsoft.OpenApi" Version="1.6.23" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" />

View File

@ -64,6 +64,21 @@ namespace Common
return num; return num;
} }
public static Result<byte[]> MultiBitsToBytes(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len)
{
return NumberToBytes(MultiBitsToNumber(bits1, bits1Len, bits2, bits2Len).Value,
(bits1Len + bits2Len) % 8 != 0 ? (bits1Len + bits2Len) / 8 + 1 : (bits1Len + bits2Len) / 8);
}
public static Result<ulong> MultiBitsToNumber(ulong bits1, uint bits1Len, ulong bits2, uint bits2Len)
{
if (bits1Len + bits2Len > 64) throw new ArgumentException("Two Bits is more than 64 bits");
ulong num = (bits1 << (int)bits2Len) | bits2;
return num;
}
public static Result<byte[]> StringToBytes(string str, int numBase = 16) public static Result<byte[]> StringToBytes(string str, int numBase = 16)
{ {
var len = str.Length; var len = str.Length;

View File

@ -28,6 +28,93 @@ public static class JtagAddr
public const UInt32 WRITE_CMD = 0x10_00_00_03; public const UInt32 WRITE_CMD = 0x10_00_00_03;
} }
/// <summary>
/// The Command bits of Jtag
/// </summary>
public static class JtagCmd
{
/// <summary>
/// 旁路指令
/// </summary>
public const UInt32 JTAG_DR_BYPASS = 0b1111111111;
/// <summary>
/// 采样指令
/// </summary>
public const UInt32 JTAG_DR_SAMPLE = 0b1010000000;
/// <summary>
/// 预装指令
/// </summary>
public const UInt32 JTAG_DR_PRELOAD = 0b1010000000;
/// <summary>
/// 外测试指令
/// </summary>
public const UInt32 JTAG_DR_EXTEST = 0b1010000001;
/// <summary>
/// 内测试指令
/// </summary>
public const UInt32 JTAG_DR_INTEST = 0b1010000010;
/// <summary>
/// 标识指令
/// </summary>
public const UInt32 JTAG_DR_IDCODE = 0b1010000011;
/// <summary>
/// 高阻指令
/// </summary>
public const UInt32 JTAG_DR_HIGHZ = 0b1010000101;
/// <summary>
/// 复位指令
/// </summary>
public const UInt32 JTAG_DR_JRST = 0b1010001010;
/// <summary>
/// 配置指令
/// </summary>
public const UInt32 JTAG_DR_CFGI = 0b1010001011;
/// <summary>
/// 回读指令
/// </summary>
public const UInt32 JTAG_DR_CFGO = 0b1010001100;
/// <summary>
/// 唤醒指令
/// </summary>
public const UInt32 JTAG_DR_JWAKEUP = 0b1010001101;
/// <summary>
/// 读UID指令
/// </summary>
public const UInt32 JTAG_DR_READ_UID = 0b0101001100;
/// <summary>
/// 读状态寄存器指令
/// </summary>
public const UInt32 JTAG_DR_RDSR = 0b0101011001;
/// <summary>
/// 设定JTAG默认状态为TEST_LOGIC_RESET态 JTAG复位
/// </summary>
public const UInt32 CMD_JTAG_CLOSE_TEST = 0b0000;
/// <summary>
/// 设定JTAG默认状态为RUN_TEST_IDLE态 JTAG空闲
/// </summary>
public const UInt32 CMD_JTAG_RUN_TEST = 0b0001;
/// <summary>
/// JTAG进入SHIFTIR循环cycle_num次后回到设定的默认状态
/// </summary>
public const UInt32 CMD_JTAG_LOAD_IR = 0b0010;
/// <summary>
/// JTAG进入SHIFTDR循环cycle_num次后回到设定的默认状态同时输入shift_in
/// </summary>
public const UInt32 CMD_JTAG_LOAD_DR_CAREI = 0b0011;
/// <summary>
/// JTAG进入SHIFTDR循环cycle_num次后回到设定的默认状态同时输出shift_out
/// </summary>
public const UInt32 CMD_JTAG_LOAD_DR_CAREO = 0b0100;
/// <summary>
/// JTAG进入RUN_TEST_IDLE态循环cycle_num次
/// </summary>
public const UInt32 CMD_JTAG_IDLE_DELAY = 0b0101;
}
class Jtag class Jtag
{ {
readonly int timeout; readonly int timeout;
@ -46,32 +133,78 @@ class Jtag
this.timeout = outTime; this.timeout = outTime;
} }
public async ValueTask<Result<bool>> ClearRegisters() public async ValueTask<Result<bool>> RunCommand(uint devAddr, uint cmd, uint exRet)
{ {
var ret = true; var ret = false;
var opts = new SendAddrPackOptions(); var opts = new SendAddrPackOptions();
opts.burstType = BurstType.FixedBurst; opts.burstType = BurstType.FixedBurst;
opts.burstLength = 4; opts.burstLength = 4;
opts.commandID = 0; opts.commandID = 0;
opts.address = JtagAddr.STATE; opts.address = devAddr;
// Write Jtag State Register // Write Jtag State Register
opts.isWrite = true; opts.isWrite = true;
ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts)); ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
if (!ret) throw new Exception("Send 1st Address Package Failed!"); if (!ret) throw new Exception("Send 1st Address Package Failed!");
ret = await UDPClientPool.SendDataPackAsync(ep, ret = await UDPClientPool.SendDataPackAsync(ep,
new SendDataPackage(NumberProcessor.NumberToBytes(0xFF_FF_FF_FF, 4).Value)); new SendDataPackage(NumberProcessor.NumberToBytes(cmd, 4).Value));
if (!ret) throw new Exception("Send Data Package Failed!"); if (!ret) throw new Exception("Send Data Package Failed!");
// Read Jtag State Register // Read Jtag State Register
opts.address = JtagAddr.STATE;
ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts)); ret = await UDPClientPool.SendAddrPackAsync(ep, new SendAddrPackage(opts));
if (!ret) throw new Exception("Send 2rd Address Package Failed!"); if (!ret) throw new Exception("Send 2rd Address Package Failed!");
// Wait for Ack // Wait for Ack
var data = await UDPServer. if (!MsgBus.IsRunning)
throw new Exception("Message Bus not Working!");
var data = await MsgBus.UDPServer.FindDataAsync(address);
if (!data.HasValue)
throw new Exception("Get None after Time out!");
var recvData = data.Value;
if (recvData.addr != address || recvData.port != port)
throw new Exception("Receive Data From Wrong Board!");
var retPack = RecvDataPackage.FromBytes(recvData.data);
if (!retPack.IsSuccessful)
throw new Exception("Not Current RecvDataPackage!", retPack.Error);
var retPackLen = retPack.Value.Options.data.Length;
if (retPackLen != 3)
throw new Exception($"RecvDataPackage BodyData Length not Equal to 3: Total {retPackLen} bytes");
if (NumberProcessor.BytesToNumber(retPack.Value.Options.data).Value == exRet)
ret = true;
return ret; return ret;
} }
public async ValueTask<Result<bool>> ClearAllRegisters()
{
return await RunCommand(JtagAddr.STATE, 0xFF_FF_FF_FF, 0x00_00_00_00);
}
public async ValueTask<Result<bool>> ClearWriteDataReg()
{
return await RunCommand(JtagAddr.STATE, 0x00_00_11_00, 0x00_00_00_00);
}
public async ValueTask<Result<bool>> RunTest()
{
return await RunCommand(JtagAddr.WRITE_CMD, 0x10_00_00_00, 0x01_00_00_00);
}
public async ValueTask<Result<bool>> WriteIDCode()
{
return await RunCommand(JtagAddr.WRITE_DATA, 0b1010000011, 0x01_00_00_00);
}
public async ValueTask<Result<bool>> LoadIR()
{
return await RunCommand(JtagAddr.WRITE_CMD, 0x20_00_00_0A, 0x01_00_00_00);
}
} }

22
server/src/MsgBus.cs Normal file
View File

@ -0,0 +1,22 @@
public static class MsgBus
{
private static readonly UDPServer udpServer = new UDPServer(33000);
public static UDPServer UDPServer { get { return udpServer; } }
private static bool isRunning = false;
public static bool IsRunning { get { return isRunning; } }
public static void Init()
{
udpServer.Start();
isRunning = true;
}
public static void Exit()
{
udpServer.Stop();
isRunning = false;
}
}

View File

@ -2,6 +2,7 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using DotNext; using DotNext;
using DotNext.Threading;
public struct UDPData public struct UDPData
{ {
@ -20,7 +21,7 @@ public class UDPServer
private UdpClient listener; private UdpClient listener;
private IPEndPoint groupEP; private IPEndPoint groupEP;
private Dictionary<string, List<UDPData>> udpData = new Dictionary<string, List<UDPData>>(); private Dictionary<string, List<UDPData>> udpData = new Dictionary<string, List<UDPData>>();
private Mutex mutUdpData = new Mutex(); private AsyncReaderWriterLock udpDataLock = new AsyncReaderWriterLock(1);
/// <summary> /// <summary>
/// Construct a udp server with fixed port /// Construct a udp server with fixed port
@ -50,32 +51,21 @@ public class UDPServer
/// Find UDP Receive Data According to ip address /// Find UDP Receive Data According to ip address
/// </summary> /// </summary>
/// <param name="ipAddr"> IP Address</param> /// <param name="ipAddr"> IP Address</param>
/// <param name="rwTimeout"> Read and Write Wait for Milliseconds </param>
/// <returns>UDP Data</returns> /// <returns>UDP Data</returns>
public Optional<UDPData> FindData(string ipAddr) public Optional<UDPData> FindData(string ipAddr, int rwTimeout = 1000)
{ {
UDPData? data = null; UDPData? data = null;
try using (udpDataLock.AcquireWriteLock(TimeSpan.FromMilliseconds(rwTimeout)))
{ {
var isOverTime = !mutUdpData.WaitOne(1000); if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
if (isOverTime) return Optional.None<UDPData>(); {
// Get data = udpData[ipAddr][0];
var listData = udpData[ipAddr]; udpData[ipAddr].RemoveAt(0);
data = listData[0]; }
// Delete
listData.RemoveAt(0);
}
catch
{
data = null;
}
finally
{
mutUdpData.ReleaseMutex();
} }
// Return if (data == null)
if (data is null)
{ {
return Optional.None<UDPData>(); return Optional.None<UDPData>();
} }
@ -93,35 +83,24 @@ public class UDPServer
/// <returns>[TODO:return]</returns> /// <returns>[TODO:return]</returns>
public async ValueTask<Optional<UDPData>> FindDataAsync(string ipAddr, int timeout = 1000) public async ValueTask<Optional<UDPData>> FindDataAsync(string ipAddr, int timeout = 1000)
{ {
var time = 0;
UDPData? data = null; UDPData? data = null;
while (time < timeout) using (await udpDataLock.AcquireWriteLockAsync(TimeSpan.FromMilliseconds(1000)))
{ {
await Task.Delay(1); if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0)
try
{ {
var isOverTime = !mutUdpData.WaitOne(timeout - time); data = udpData[ipAddr][0];
if (isOverTime) break; udpData[ipAddr].RemoveAt(0);
// Get
var listData = udpData[ipAddr];
data = listData[0];
// Delete
listData.RemoveAt(0);
} }
catch
{
data = null;
}
finally
{
mutUdpData.ReleaseMutex();
}
if (data is null) continue;
else break;
} }
if ((time >= timeout) || (data is null)) { return Optional.None<UDPData>(); }
else { return Optional.Some((UDPData)data); } if (data == null)
{
return Optional.None<UDPData>();
}
else
{
return Optional.Some((UDPData)data);
}
} }
private void ReceiveHandler(IAsyncResult res) private void ReceiveHandler(IAsyncResult res)
@ -131,7 +110,7 @@ public class UDPServer
var nowtime = DateTime.Now; var nowtime = DateTime.Now;
// Handle RemoteEP // Handle RemoteEP
string remoteStr; string remoteStr = "Unknown";
if (remoteEP is not null) if (remoteEP is not null)
{ {
var remoteAddress = remoteEP.Address.ToString(); var remoteAddress = remoteEP.Address.ToString();
@ -160,14 +139,10 @@ public class UDPServer
remoteStr = $"{remoteAddress}:{remotePort}"; remoteStr = $"{remoteAddress}:{remotePort}";
} }
else
{
remoteStr = "Unknown";
}
// Handle Package // Handle Package
var sign = bytes[0]; var sign = bytes[0];
string recvData; string recvData = "";
if (sign == (byte)WebProtocol.PackSign.SendAddr) if (sign == (byte)WebProtocol.PackSign.SendAddr)
{ {
var resData = WebProtocol.SendAddrPackage.FromBytes(bytes); var resData = WebProtocol.SendAddrPackage.FromBytes(bytes);
@ -176,18 +151,9 @@ public class UDPServer
else else
recvData = resData.Error.ToString(); recvData = resData.Error.ToString();
} }
else if (sign == (byte)WebProtocol.PackSign.SendData) else if (sign == (byte)WebProtocol.PackSign.SendData) { }
{ else if (sign == (byte)WebProtocol.PackSign.RecvData) { }
recvData = ""; else if (sign == (byte)WebProtocol.PackSign.RecvResp) { }
}
else if (sign == (byte)WebProtocol.PackSign.RecvData)
{
recvData = "";
}
else if (sign == (byte)WebProtocol.PackSign.RecvResp)
{
recvData = "";
}
else else
{ {
recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length); recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);

View File

@ -59,6 +59,7 @@ namespace WebProtocol
{ {
public byte commandID; public byte commandID;
public bool isSuccess; public bool isSuccess;
public byte[] data;
} }
public struct SendAddrPackage public struct SendAddrPackage
@ -184,13 +185,27 @@ namespace WebProtocol
this.bodyData = bodyData; this.bodyData = bodyData;
} }
public RecvPackOptions Options() public RecvPackOptions Options
{ {
RecvPackOptions opts; get
opts.commandID = commandID; {
opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false); RecvPackOptions opts;
opts.commandID = commandID;
opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false);
opts.data = bodyData;
return opts; return opts;
}
}
public static Result<RecvDataPackage> FromBytes(byte[] bytes)
{
if (bytes[0] != (byte)PackSign.RecvData)
throw new ArgumentException(
"The sign of bytes is not RecvData Package!",
nameof(bytes)
);
return new RecvDataPackage(bytes[1], bytes[2], bytes[4..]);
} }
} }

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import Sidebar from "./components/Sidebar.vue";
import { useThemeStore } from "./stores/theme"; import { useThemeStore } from "./stores/theme";
const theme = useThemeStore(); const theme = useThemeStore();
@ -6,12 +7,11 @@ const theme = useThemeStore();
<template> <template>
<div :data-theme="theme.currentTheme"> <div :data-theme="theme.currentTheme">
<header> <header class="relative">
<RouterLink to="/user"> Go to User</RouterLink> <div class="fixed left-0 top-0 z-50">
<RouterLink to="/login"> Go to Login</RouterLink> <Sidebar />
<router-link to="/test"> Go to Test</router-link> </div>
</header> </header>
<div></div>
<main> <main>
<RouterView /> <RouterView />

View File

@ -0,0 +1,11 @@
<template>
<button class="btn transition-transform duration-150 ease-in-out hover:scale-120">
Button A
</button>
</template>
<script lang="ts" setup></script>
<style scoped lang="postcss">
@import "@/assets/main.css";
</style>

View File

@ -1,123 +1,139 @@
<template> <template>
<div :class="[ <div class="card card-dash sidebar-base" :class="[isClose ? 'w-31' : 'w-80']">
'card-dash', <div class="card-body flex relative transition-all duration-500 ease-in-out">
'sidebar-base',
'transition-all',
'duration-500',
'ease-in-out',
isClose ? 'sidebar-close' : 'sidebar-open',
]">
<div class="card-body flex transition-all duration-500 ease-in-out">
<!-- Avatar and Name --> <!-- Avatar and Name -->
<div :class="['flex', 'items-center', isClose ? 'flex-col' : '']"> <div class="relative" :class="isClose ? 'h-50' : 'h-20'">
<!-- Img --> <!-- Img -->
<div class="avatar h-10"> <div class="avatar h-10 fixed top-10" :class="isClose ? 'left-10' : 'left-7'">
<div class="rounded-full"> <div class="rounded-full">
<img src="../assets/user.svg" alt="User" /> <img src="../assets/user.svg" alt="User" />
</div> </div>
</div> </div>
<!-- Text --> <!-- Text -->
<div v-if="!isClose" class="mx-5 grow"> <Transition>
<label class="text-2xl">用户名</label> <div v-if="!isClose" class="mx-5 grow fixed left-20 top-11">
</div> <label class="text-2xl">用户名</label>
</div>
<!-- Toggle Button --> </Transition>
<button class="btn btn-square rounded-lg p-2 m-3" @click="toggleSidebar">
<img src="../assets/left.svg" alt="Menu Button" class="opacity-50">
</button>
</div> </div>
<!-- Toggle Button -->
<button class="btn btn-square rounded-lg p-2 m-3 fixed" :class="isClose ? 'left-7 top-23' : 'left-60 top-7'"
@click="toggleSidebar">
<svg t="1741694970690" :class="isClose ? 'rotate-0' : 'rotate-540'" class="icon" viewBox="0 0 1024 1024"
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4546" xmlns:xlink="http://www.w3.org/1999/xlink"
width="200" height="200">
<path
d="M803.758 514.017c-0.001-0.311-0.013-0.622-0.018-0.933-0.162-23.974-9.386-47.811-27.743-65.903-0.084-0.082-0.172-0.157-0.256-0.239-0.154-0.154-0.296-0.315-0.451-0.468L417.861 94.096c-37.685-37.153-99.034-37.476-136.331-0.718-37.297 36.758-36.979 97.231 0.707 134.384l290.361 286.257-290.362 286.257c-37.685 37.153-38.004 97.625-0.707 134.383 37.297 36.758 98.646 36.435 136.331-0.718l357.43-352.378c0.155-0.153 0.297-0.314 0.451-0.468 0.084-0.082 0.172-0.157 0.256-0.239 18.354-18.089 27.578-41.922 27.743-65.892 0.004-0.315 0.017-0.631 0.018-0.947z"
:fill="theme.isLightTheme() ? '#828282' : '#C0C3C8'" p-id="4547"></path>
</svg>
</button>
<div class="divider"></div> <div class="divider"></div>
<ul class="menu h-full w-full"> <ul class="menu h-full w-full">
<li v-for="item in items" class="text-lg my-1"> <li v-for="item in items" class="text-xl my-1">
<a> <a>
<img class="h-[1.5em] opacity-50 mx-1" :src="item.icon" alt="An icon" /> <svg t="1741694797806" class="icon h-[1.5em] w-[1.5em] opacity-50 mx-1" viewBox="0 0 1024 1024"
<p v-if="!isClose">{{ item.msg }}</p> version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2622" xmlns:xlink="http://www.w3.org/1999/xlink"
width="200" height="200">
<path d="M192 192m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" p-id="2623"></path>
<path d="M192 512m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" p-id="2624"></path>
<path d="M192 832m-64 0a64 64 0 1 0 128 0 64 64 0 1 0-128 0Z" p-id="2625"></path>
<path
d="M864 160H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 480H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32zM864 800H352c-17.7 0-32 14.3-32 32s14.3 32 32 32h512c17.7 0 32-14.3 32-32s-14.3-32-32-32z"
p-id="2626"></path>
</svg>
<Transition>
<p v-if="!isClose">{{ item.msg }}</p>
</Transition>
</a> </a>
</li> </li>
</ul> </ul>
<div class="divider"></div> <div class="divider"></div>
<ul class="menu w-full"> <ul class="menu w-full">
<li class="mb-5"> <li>
<a @click="theme.toggleTheme" class="text-xl"> <a @click="theme.toggleTheme" class="text-xl">
<ThemeControlButton /> <ThemeControlButton />
<p v-if="!isClose">改变主题</p> <Transition>
<ThemeControlToggle v-if="!isClose" /> <p v-if="!isClose" class="break-keep">改变主题</p>
</Transition>
<Transition>
<ThemeControlToggle v-if="!isClose" />
</Transition>
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import iconMenu from "../assets/menu.svg" import iconMenu from "../assets/menu.svg";
import { useThemeStore } from "@/stores/theme"; import { useThemeStore } from "@/stores/theme";
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import ThemeControlButton from "./ThemeControlButton.vue"; import ThemeControlButton from "./ThemeControlButton.vue";
import ThemeControlToggle from "./ThemeControlToggle.vue"; import ThemeControlToggle from "./ThemeControlToggle.vue";
const theme = useThemeStore() const theme = useThemeStore();
const isClose = ref(false) const isClose = ref(false);
const items = [ const items = [
{ id: 1, icon: iconMenu, msg: "btn1" }, { id: 1, icon: iconMenu, msg: "btn1" },
{ id: 2, icon: iconMenu, msg: "btn2" }, { id: 2, icon: iconMenu, msg: "btn2" },
{ id: 3, icon: iconMenu, msg: "btn3" }, { id: 3, icon: iconMenu, msg: "btn3" },
{ id: 4, icon: iconMenu, msg: "btn4" }, { id: 4, icon: iconMenu, msg: "btn4" },
] ];
const themeSidebar = computed(() => {
return [
"card-dash",
"sidebar-base",
"transition",
"duration-300",
"ease-in-out",
isClose.value ? "sidebar-close" : "sidebar-open",
]
})
function closeSidebar() { function closeSidebar() {
isClose.value = true; isClose.value = true;
console.info("Close sidebar") console.info("Close sidebar");
} }
function openSidebar() { function openSidebar() {
isClose.value = false; isClose.value = false;
console.info("Open sidebar") console.info("Open sidebar");
} }
function toggleSidebar() { function toggleSidebar() {
if (isClose.value) { if (isClose.value) {
openSidebar() openSidebar();
// themeSidebar.value = "card-dash sidebar-base sidebar-open" // themeSidebar.value = "card-dash sidebar-base sidebar-open"
} } else {
else { closeSidebar();
closeSidebar()
// themeSidebar.value = "card-dash sidebar-base sidebar-close" // themeSidebar.value = "card-dash sidebar-base sidebar-close"
} }
} }
</script> </script>
<style scoped lang="postcss"> <style scoped lang="postcss">
@reference "../assets/main.css"; @reference "../assets/main.css";
* {
@apply transition-all duration-500 ease-in-out;
}
.sidebar-base { .sidebar-base {
@apply card shadow-xl h-screen; @apply shadow-xl h-screen;
} }
.sidebar-open { .sidebar-open {
@apply w-80 @apply w-80;
} }
.sidebar-close { .sidebar-close {
@apply w-31 @apply w-31;
}
.v-enter-active,
.v-leave-active {
transition: opacity 0.3s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
} }
</style> </style>

View File

@ -1,29 +1,31 @@
<template> <template>
<div class="card card-dash shadow-xl w-90 h-60"> <div class="card card-dash shadow-xl w-90 h-60">
<div class="card-body flex"> <div class="card-body flex">
<!-- Title --> <!-- Title -->
<h1 class="card-title place-self-center font-bold text-2xl">上传比特流文件</h1> <h1 class="card-title place-self-center font-bold text-2xl">
上传比特流文件
</h1>
<!-- Input File --> <!-- Input File -->
<fieldset class="fieldset w-full"> <fieldset class="fieldset w-full">
<legend class="fieldset-legend text-sm">选择或拖拽上传文件</legend> <legend class="fieldset-legend text-sm">选择或拖拽上传文件</legend>
<input type="file" class="file-input" @change="handleFileChange" /> <input type="file" class="file-input" @change="handleFileChange" />
<label class="fieldset-label">Max size 2MB</label> <label class="fieldset-label">文件最大容量: 2MB</label>
</fieldset> </fieldset>
<!-- Upload Button --> <!-- Upload Button -->
<div class="card-actions"> <div class="card-actions">
<button @click="uploadBitStream" class="btn btn-primary grow">上传</button> <button @click="uploadBitStream" class="btn btn-primary grow">
上传
</button>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { client } from '@/client'; import { client } from "@/client";
import { TRPCClientError } from '@trpc/client'; import { TRPCClientError } from "@trpc/client";
var bitstream = null; var bitstream = null;
@ -32,7 +34,7 @@ function handleFileChange(event: Event): void {
const file = target.files?.[0]; // const file = target.files?.[0]; //
if (!file) { if (!file) {
console.error('未选择文件'); console.error("未选择文件");
return; return;
} }
@ -45,22 +47,18 @@ async function uploadBitStream() {
try { try {
const serverStatus = await client.api.status.query(); const serverStatus = await client.api.status.query();
if (serverStatus != "OK") { if (serverStatus != "OK") {
throw new Error("Server Busy...") throw new Error("Server Busy...");
} }
} catch (error) { } catch (error) {
if (error instanceof TRPCClientError) { if (error instanceof TRPCClientError) {
console.error("Can't connect to Server!") console.error("Can't connect to Server!");
} else { } else {
console.error(error) console.error(error);
} }
} }
} }
function checkFileType(file: File) { function checkFileType(file: File) { }
}
</script> </script>
<style scoped lang="postcss"> <style scoped lang="postcss">

0
src/stores/sidebar.ts Normal file
View File

View File

@ -2,16 +2,16 @@
<div class="w-screen h-screen"> <div class="w-screen h-screen">
<!-- <Switch width="720" height="720" /> --> <!-- <Switch width="720" height="720" /> -->
<MechanicalButton width="720" height="720" /> <MechanicalButton width="720" height="720" />
<PopButton></PopButton>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import MechanicalButton from '@/components/equipments/MechanicalButton.vue'; import PopButton from "@/components/PopButton.vue";
import Switch from '@/components/equipments/Switch.vue'; // import MechanicalButton from "@/components/equipments/MechanicalButton.vue";
// import Switch from "@/components/equipments/Switch.vue";
</script> </script>
<style scoped lang="postcss"> <style scoped lang="postcss">
@import "../assets/main.css" @import "../assets/main.css";
</style> </style>

View File

@ -1,10 +1,6 @@
<template> <template>
<header> <header></header>
</header>
<main class="relative"> <main class="relative">
<div class="fixed left-0 top-0 z-50">
<Sidebar />
</div>
<div class="w-screen h-screen flex items-center justify-center"> <div class="w-screen h-screen flex items-center justify-center">
<UploadCard /> <UploadCard />
</div> </div>
@ -12,10 +8,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import UploadCard from '@/components/UploadCard.vue'; import UploadCard from "@/components/UploadCard.vue";
import Sidebar from '../components/Sidebar.vue' import Sidebar from "../components/Sidebar.vue";
</script> </script>
<style scoped> <style scoped>
@import "../assets/main.css" @import "../assets/main.css";
</style> </style>

View File

@ -6,9 +6,6 @@
}, },
{ {
"path": "./tsconfig.app.json" "path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.bun.json"
} }
] ]
} }