[FEAT] 優化後端帳號權限邏輯、開發商品管理功能及聯絡資訊 UI 改版
All checks were successful
star-cloud-deploy-demo / deploy-demo (push) Successful in 1m2s

This commit is contained in:
2026-03-27 13:43:08 +08:00
parent 8ec5473ec7
commit 740eaa30b7
22 changed files with 1783 additions and 615 deletions

View File

@@ -297,8 +297,8 @@
class="p-2 rounded-lg bg-slate-50 dark:bg-slate-800 text-slate-400 hover:text-cyan-500 hover:bg-cyan-500/5 dark:hover:bg-cyan-500/10 border border-transparent hover:border-cyan-500/20 transition-all inline-flex group/btn"
title="{{ __('View Details') }}">
<svg class="w-4 h-4 stroke-[2.5]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round"
d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
</svg>
</button>
</td>
@@ -870,10 +870,10 @@
<div
class="h-full flex flex-col bg-white dark:bg-slate-900 shadow-2xl border-l border-slate-100 dark:border-slate-800">
<div
class="px-6 py-4 border-b border-slate-100 dark:border-slate-800 flex items-center justify-between">
class="px-6 py-3 border-b border-slate-100 dark:border-slate-800 flex items-center justify-between">
<div>
<h2 class="text-xl font-black text-slate-800 dark:text-white">{{ __('Parameters') }}</h2>
<p class="text-[10px] font-bold text-slate-400 uppercase tracking-[0.2em] mt-1"
<p class="text-xs font-bold text-slate-400 uppercase tracking-[0.2em] mt-1"
x-text="currentMachine?.name"></p>
</div>
<button @click="showDetailDrawer = false"
@@ -884,10 +884,10 @@
</svg>
</button>
</div>
<div class="flex-1 overflow-y-auto px-6 py-4 space-y-6 custom-scrollbar">
<div class="flex-1 overflow-y-auto px-6 pt-1 pb-6 space-y-6 custom-scrollbar">
<template x-if="currentMachine?.image_urls && currentMachine.image_urls.length > 0">
<section class="space-y-4">
<h3 class="text-[11px] font-black text-indigo-500 uppercase tracking-[0.3em]">{{
<h3 class="text-xs font-black text-indigo-500 uppercase tracking-[0.3em]">{{
__('Machine Images') }}</h3>
<div class="grid grid-cols-2 gap-3">
<template x-for="(url, index) in currentMachine.image_urls" :key="index">
@@ -906,28 +906,28 @@
</section>
</template>
<section class="space-y-6">
<h3 class="text-[11px] font-black text-cyan-500 uppercase tracking-[0.3em]">{{ __('Hardware
<h3 class="text-xs font-black text-cyan-500 uppercase tracking-[0.3em]">{{ __('Hardware
& Network') }}</h3>
<div class="grid grid-cols-1 gap-4">
<div
class="bg-slate-50 dark:bg-slate-800/40 p-5 rounded-2xl border border-slate-100 dark:border-slate-800/80">
<span
class="text-[10px] font-bold text-slate-400 uppercase tracking-widest block mb-1.5">{{
class="text-xs font-bold text-slate-400 uppercase tracking-widest block mb-1.5">{{
__('Serial & Version') }}</span>
<div class="flex items-center justify-between">
<div class="text-xs font-mono font-bold text-slate-700 dark:text-slate-300"
<div class="text-sm font-mono font-bold text-slate-700 dark:text-slate-300"
x-text="currentMachine?.serial_no"></div>
<span
class="px-2 py-0.5 rounded-md bg-white dark:bg-slate-900 text-[9px] font-black text-slate-500 border border-slate-100 dark:border-slate-800"
class="px-2 py-0.5 rounded-md bg-white dark:bg-slate-900 text-[10px] font-black text-slate-500 border border-slate-100 dark:border-slate-800"
x-text="'v' + (currentMachine?.firmware_version || '1.0')"></span>
</div>
</div>
<div
class="bg-slate-50 dark:bg-slate-800/40 p-5 rounded-2xl border border-slate-100 dark:border-slate-800/80">
<span
class="text-[10px] font-bold text-slate-400 uppercase tracking-widest block mb-1.5">{{
class="text-xs font-bold text-slate-400 uppercase tracking-widest block mb-1.5">{{
__('Heartbeat') }}</span>
<div class="text-xs font-bold text-slate-700 dark:text-slate-300"
<div class="text-sm font-bold text-slate-700 dark:text-slate-300"
x-text="currentMachine?.last_heartbeat_at ? new Date(currentMachine.last_heartbeat_at).toLocaleString() : '--'">
</div>
</div>
@@ -936,24 +936,24 @@
<!-- Operational Settings -->
<section class="space-y-6">
<h3 class="text-[11px] font-black text-amber-500 uppercase tracking-[0.3em]">{{
<h3 class="text-xs font-black text-amber-500 uppercase tracking-[0.3em]">{{
__('Operations') }}</h3>
<div class="space-y-4">
<div
class="flex items-center justify-between p-2 border-b border-slate-50 dark:border-white/5">
<span class="text-xs font-bold text-slate-500">{{ __('Heating Range') }}</span>
<span class="text-xs font-black text-slate-700 dark:text-slate-300"
<span class="text-sm font-bold text-slate-500">{{ __('Heating Range') }}</span>
<span class="text-sm font-black text-slate-700 dark:text-slate-300"
x-text="(currentMachine?.heating_start_time ? currentMachine.heating_start_time.substring(0, 5) : '00:00') + ' ~ ' + (currentMachine?.heating_end_time ? currentMachine.heating_end_time.substring(0, 5) : '00:00')"></span>
</div>
<div
class="flex items-center justify-between p-2 border-b border-slate-50 dark:border-white/5">
<span class="text-xs font-bold text-slate-500">{{ __('Card Reader No') }}</span>
<span class="text-xs font-black text-slate-700 dark:text-slate-300"
<span class="text-sm font-bold text-slate-500">{{ __('Card Reader No') }}</span>
<span class="text-sm font-black text-slate-700 dark:text-slate-300"
x-text="currentMachine?.card_reader_no || '--'"></span>
</div>
<div class="flex flex-col gap-3 p-3 mt-1 bg-slate-50 dark:bg-slate-800/40 rounded-xl border border-slate-100 dark:border-slate-700/50 relative">
<div class="flex items-center justify-between">
<span class="text-[11px] font-black text-slate-500 uppercase tracking-widest">{{ __('API Token') }}</span>
<span class="text-xs font-black text-slate-500 uppercase tracking-widest">{{ __('API Token') }}</span>
<div class="flex items-center gap-1">
<template x-if="currentMachine?.api_token">
<div class="flex items-center gap-1">
@@ -971,7 +971,7 @@
</div>
</template>
<button @click="regenerateToken()" :disabled="loadingRegenerate"
class="ml-2 px-2.5 py-1.5 rounded-lg bg-rose-50 dark:bg-rose-500/10 text-rose-500 hover:bg-rose-100 dark:hover:bg-rose-500/20 text-[10px] font-black uppercase tracking-widest transition-all disabled:opacity-50 flex items-center gap-1.5 border border-rose-100 dark:border-rose-500/20"
class="ml-2 px-2.5 py-1.5 rounded-lg bg-rose-50 dark:bg-rose-500/10 text-rose-500 hover:bg-rose-100 dark:hover:bg-rose-500/20 text-xs font-black uppercase tracking-widest transition-all disabled:opacity-50 flex items-center gap-1.5 border border-rose-100 dark:border-rose-500/20"
title="{{ __('Regenerate') }}">
<svg x-show="loadingRegenerate" class="animate-spin w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
<svg x-show="!loadingRegenerate" class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
@@ -980,8 +980,8 @@
</div>
</div>
<div class="bg-white dark:bg-slate-900/50 rounded-lg border border-slate-200 dark:border-slate-700/50 p-2.5 overflow-x-auto custom-scrollbar">
<span class="text-xs font-mono font-bold tracking-[0.1em] text-cyan-600 dark:text-cyan-400 select-all block whitespace-nowrap min-w-full"
x-text="currentMachine?.api_token ? (showApiToken ? currentMachine.api_token : '•'.repeat(40)) : '{{ __('None') }}'"></span>
<span class="text-sm font-mono font-bold tracking-[0.1em] text-cyan-600 dark:text-cyan-400 select-all block whitespace-nowrap min-w-full"
x-text="currentMachine?.api_token ? (showApiToken ? currentMachine.api_token : '•'.repeat(16)) : '{{ __('None') }}'"></span>
</div>
</div>
</div>
@@ -989,11 +989,11 @@
<!-- Location -->
<section class="space-y-4">
<h3 class="text-[11px] font-black text-emerald-500 uppercase tracking-[0.3em]">{{
<h3 class="text-xs font-black text-emerald-500 uppercase tracking-[0.3em]">{{
__('Location') }}</h3>
<div
class="p-4 bg-emerald-50/30 dark:bg-emerald-500/5 rounded-2xl border border-emerald-100/50 dark:border-emerald-500/10">
<p class="text-xs text-emerald-700 dark:text-emerald-400 leading-relaxed font-bold"
<p class="text-sm text-emerald-700 dark:text-emerald-400 leading-relaxed font-bold"
x-text="currentMachine?.location || '{{ __('No location set') }}'"></p>
</div>
</section>