Merge pull request #453 from LingkongSky/main

add the Wol custom name
This commit is contained in:
wenjie
2025-04-13 23:30:48 -07:00
committed by GitHub
5 changed files with 142 additions and 20 deletions

View File

@@ -12,6 +12,11 @@ type DeleteMacReq struct {
Mac string `form:"mac" validate:"required"`
}
type SetMacNameReq struct {
Mac string `form:"mac" validate:"required"`
Name string `form:"name" validate:"required"`
}
type TailscaleState string
const (

View File

@@ -14,9 +14,9 @@ func networkRouter(r *gin.Engine) {
api := r.Group("/api").Use(middleware.CheckToken())
api.POST("/network/wol", service.WakeOnLAN) // wake on lan
api.GET("/network/wol/mac", service.GetMac) // get mac list
api.DELETE("/network/wol/mac", service.DeleteMac) // delete mac
api.GET("/network/wifi", service.GetWifi) // get Wi-Fi information
api.POST("/network/wol", service.WakeOnLAN) // wake on lan
api.GET("/network/wol/mac", service.GetMac) // get mac list
api.DELETE("/network/wol/mac", service.DeleteMac) // delete mac
api.POST("/network/wol/mac/setName", service.SetMacName) // set mac name
api.GET("/network/wifi", service.GetWifi) // get Wi-Fi information
}

View File

@@ -65,6 +65,54 @@ func (s *Service) GetMac(c *gin.Context) {
rsp.OkRspWithData(c, data)
}
func (s *Service) SetMacName(c *gin.Context) {
var req proto.SetMacNameReq // Mac:string Name:string
var rsp proto.Response
if err := proto.ParseFormRequest(c, &req); err != nil {
rsp.ErrRsp(c, -1, "invalid arguments")
return
}
content, err := os.ReadFile(WolMacFile)
if err != nil {
log.Errorf("failed to open %s: %s", WolMacFile, err)
rsp.ErrRsp(c, -2, "read failed")
return
}
macs := strings.Split(string(content), "\n")
var newLines []string
macFound := false
for _, line := range macs {
parts := strings.Split(line, " ")
if req.Mac != parts[0] {
newLines = append(newLines, line)
continue
}
newLines = append(newLines, parts[0]+" "+req.Name)
macFound = true
}
if !macFound {
log.Errorf("failed to found mac %s: %s", req.Mac, err)
rsp.ErrRsp(c, -3, "write failed")
return
}
data := strings.Join(newLines, "\n")
err = os.WriteFile(WolMacFile, []byte(data), 0o644)
if err != nil {
log.Errorf("failed to write %s: %s", WolMacFile, err)
rsp.ErrRsp(c, -3, "write failed")
return
}
rsp.OkRsp(c)
log.Debugf("set wol mac name: %s %s", req.Mac, req.Name)
}
func (s *Service) DeleteMac(c *gin.Context) {
var req proto.DeleteMacReq
var rsp proto.Response
@@ -85,7 +133,8 @@ func (s *Service) DeleteMac(c *gin.Context) {
var newMacs []string
for _, mac := range macs {
if req.Mac != mac {
parts := strings.Split(mac, " ")
if req.Mac != parts[0] {
newMacs = append(newMacs, mac)
}
}
@@ -164,7 +213,8 @@ func isMacExist(mac string) bool {
macs := strings.Split(string(content), "\n")
for _, item := range macs {
if mac == item {
parts := strings.Split(item, " ")
if mac == parts[0] {
return true
}
}

View File

@@ -21,6 +21,11 @@ export function deleteWolMac(mac: string) {
});
}
// set Mac name
export function setWolMacName(mac: string,name: string) {
return http.post('/api/network/wol/mac/setName', { mac, name });
}
// get wifi information
export function getWiFi() {
return http.get('/api/network/wifi');

View File

@@ -3,13 +3,21 @@ import { Button, Divider, Input, List } from 'antd';
import type { InputRef } from 'antd';
import clsx from 'clsx';
import { useSetAtom } from 'jotai';
import { NetworkIcon, SendIcon, Trash2Icon } from 'lucide-react';
import { Eye, EyeClosed, NetworkIcon, Pencil, SendIcon, Trash2Icon } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { deleteWolMac, getWolMacs, wol } from '@/api/network.ts';
import { deleteWolMac, getWolMacs, setWolMacName, wol } from '@/api/network.ts';
import { isKeyboardEnableAtom } from '@/jotai/keyboard.ts';
import { MenuItem } from '@/components/menu-item.tsx';
interface MacItem {
name: string;
mac: string;
isShow: boolean;
isName: boolean;
isEdit: boolean;
}
export const Wol = () => {
const { t } = useTranslation();
@@ -19,20 +27,18 @@ export const Wol = () => {
const [status, setStatus] = useState('');
const [log, setLog] = useState('');
const [macList, setMacList] = useState<string[]>([]);
const [macList, setMacList] = useState<MacItem[]>([]);
const inputRef = useRef<InputRef>(null);
function handleOpenChange(open: boolean) {
if (open) {
getMacs();
setIsKeyboardEnable(false);
} else {
setInput('');
setStatus('');
setLog('');
setIsKeyboardEnable(true);
}
}
@@ -48,14 +54,53 @@ export const Wol = () => {
return;
}
setMacList(rsp.data.macs.filter((mac: string) => mac !== ''));
const isEdit = false;
const macList = rsp.data.macs
.filter((item: string) => item.trim() !== '')
.map((item: string) => {
const parts = item.split(" ");
const isName = parts.length > 1;
const name = isName ? parts[1] : '';
const mac = parts[0];
const isShow = !isName;
return { name, mac, isShow, isName, isEdit};
});
setMacList([]);
setMacList(macList);
});
}
function toggleShow(mac: string) {
setMacList(
macList.map((item) =>
item.mac === mac ? { ...item, isShow: !item.isShow } : item
)
);
}
function editMac(mac: string,isEdit: boolean) {
setMacList(
macList.map((item) =>
item.mac === mac ? { ...item, isEdit: !isEdit } : item
)
);
}
async function setMacName(e: React.KeyboardEvent<HTMLInputElement>, mac: string) {
const value: string = e.currentTarget.value;
const rsp = await setWolMacName(mac,value);
if (rsp.code !== 0) {
console.log(rsp.msg);
return;
}
getMacs();
}
function deleteMac(mac: string) {
deleteWolMac(mac).then((rsp) => {
if (rsp.code === 0) {
setMacList(macList.filter((item) => item !== mac));
getMacs();
}
});
}
@@ -79,10 +124,12 @@ export const Wol = () => {
setStatus('success');
setLog(t('wol.sent'));
getMacs();
setInput('');
})
.catch(() => {
setStatus('failed');
});
});
}
const content = (
@@ -95,7 +142,7 @@ export const Wol = () => {
<div className="pb-1 text-neutral-500">{t('wol.input')}</div>
<div className="flex items-center space-x-1">
<Input ref={inputRef} value={input} onChange={handleChange} />
<Input ref={inputRef} value={input} onChange={handleChange} onPressEnter={() => wake()}/>
<Button type="primary" onClick={() => wake()}>
{t('wol.ok')}
</Button>
@@ -118,19 +165,34 @@ export const Wol = () => {
itemLayout="horizontal"
locale={{ emptyText: ' ' }}
dataSource={macList}
renderItem={(mac) => (
renderItem={(item) => (
<List.Item className="flex w-full items-center justify-between">
<div className="h-[24px] max-w-[200px]">{mac}</div>
<div className="h-[24px] max-w-[200px]">
{item.isEdit ? <Input onFocus={() => setIsKeyboardEnable(false)} onBlur={() => setIsKeyboardEnable(true)} defaultValue={item.name} onPressEnter={(e) => setMacName(e, item.mac)} />:(item.isShow ? item.mac : item.name)}
</div>
<div className="flex items-center space-x-1">
{item.isName && <div
className="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-500 hover:bg-neutral-700/80"
onClick={() => toggleShow(item.mac)}
>
{item.isShow ? <EyeClosed size={16} /> : <Eye size={16} />}
</div>}
<div
className="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-500 hover:bg-neutral-700"
onClick={() => editMac(item.mac,item.isEdit)}
>
<Pencil size={16} />
</div>
<div
className="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-green-500 hover:bg-neutral-700/80"
onClick={() => wake(mac)}
onClick={() => wake(item.mac)}
>
<SendIcon size={16} />
</div>
<div
className="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-red-500 hover:bg-neutral-700"
onClick={() => deleteMac(mac)}
onClick={() => deleteMac(item.mac)}
>
<Trash2Icon size={16} />
</div>