init plugins
This commit is contained in:
parent
3c1517f434
commit
86e49a26aa
63 changed files with 1457 additions and 434 deletions
46
app/app.go
46
app/app.go
|
|
@ -3,12 +3,10 @@ package app
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"godoos/cmd"
|
cmd "godo/cmd"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
|
|
||||||
wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
|
wruntime "github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
@ -28,7 +26,7 @@ func NewApp() *App {
|
||||||
// so we can call the runtime methods
|
// so we can call the runtime methods
|
||||||
func (a *App) Startup(ctx context.Context) {
|
func (a *App) Startup(ctx context.Context) {
|
||||||
a.ctx = ctx
|
a.ctx = ctx
|
||||||
go cmd.OsStart()
|
cmd.OsStart()
|
||||||
}
|
}
|
||||||
func (a *App) Shutdown(ctx context.Context) {
|
func (a *App) Shutdown(ctx context.Context) {
|
||||||
a.ctx = ctx
|
a.ctx = ctx
|
||||||
|
|
@ -44,35 +42,31 @@ func (a *App) OpenDirDialog() string {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetAbsPath(path string) (string, error) {
|
|
||||||
var absPath string
|
|
||||||
var err error
|
|
||||||
if filepath.IsAbs(path) {
|
|
||||||
absPath = filepath.Clean(path)
|
|
||||||
} else {
|
|
||||||
absPath, err = filepath.Abs(filepath.Join(a.exDir, path))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
absPath = strings.ReplaceAll(absPath, "/", string(os.PathSeparator))
|
|
||||||
//println("GetAbsPath:", absPath)
|
|
||||||
return absPath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) RestartApp() error {
|
func (a *App) RestartApp() error {
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
name, err := os.Executable()
|
name, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
exec.Command(name, os.Args[1:]...).Start()
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
cmd = exec.Command(name, os.Args[1:]...)
|
||||||
|
case "darwin": // macOS
|
||||||
|
cmd = exec.Command("/usr/bin/open", name)
|
||||||
|
case "linux":
|
||||||
|
cmd = exec.Command(name, os.Args[1:]...)
|
||||||
|
// Optionally, you could use 'xdg-open' or 'gnome-open' etc.
|
||||||
|
// cmd = exec.Command("/usr/bin/gnome-open", name)
|
||||||
|
default:
|
||||||
|
return errors.New("unsupported OS")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cmd != nil {
|
||||||
|
cmd.Start()
|
||||||
wruntime.Quit(a.ctx)
|
wruntime.Quit(a.ctx)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("unsupported OS")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) GetPlatform() string {
|
return errors.New("failed to restart application")
|
||||||
return runtime.GOOS
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
132
app/download.go
132
app/download.go
|
|
@ -1,132 +0,0 @@
|
||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/cavaliergopher/grab/v3"
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (a *App) DownloadFile(path string, url string) error {
|
|
||||||
absPath, err := a.GetAbsPath(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = grab.Get(absPath, url)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type DownloadStatus struct {
|
|
||||||
resp *grab.Response
|
|
||||||
cancel context.CancelFunc
|
|
||||||
Name string `json:"name"`
|
|
||||||
Path string `json:"path"`
|
|
||||||
Url string `json:"url"`
|
|
||||||
Transferred int64 `json:"transferred"`
|
|
||||||
Size int64 `json:"size"`
|
|
||||||
Speed float64 `json:"speed"`
|
|
||||||
Progress float64 `json:"progress"`
|
|
||||||
Downloading bool `json:"downloading"`
|
|
||||||
Done bool `json:"done"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var downloadList []*DownloadStatus
|
|
||||||
|
|
||||||
func existsInDownloadList(path string, url string) bool {
|
|
||||||
for _, ds := range downloadList {
|
|
||||||
if ds.Path == path || ds.Url == url {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) PauseDownload(url string) {
|
|
||||||
for _, ds := range downloadList {
|
|
||||||
if ds.Url == url {
|
|
||||||
if ds.cancel != nil {
|
|
||||||
ds.cancel()
|
|
||||||
}
|
|
||||||
ds.resp = nil
|
|
||||||
ds.Downloading = false
|
|
||||||
ds.Speed = 0
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) ContinueDownload(url string) {
|
|
||||||
for _, ds := range downloadList {
|
|
||||||
if ds.Url == url {
|
|
||||||
if !ds.Downloading && ds.resp == nil && !ds.Done {
|
|
||||||
ds.Downloading = true
|
|
||||||
|
|
||||||
req, err := grab.NewRequest(ds.Path, ds.Url)
|
|
||||||
if err != nil {
|
|
||||||
ds.Downloading = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// if PauseDownload() is called before the request finished, ds.Downloading will be false
|
|
||||||
// if the user keeps clicking pause and resume, it may result in multiple requests being successfully downloaded at the same time
|
|
||||||
// so we have to create a context and cancel it when PauseDownload() is called
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
ds.cancel = cancel
|
|
||||||
req = req.WithContext(ctx)
|
|
||||||
resp := grab.DefaultClient.Do(req)
|
|
||||||
|
|
||||||
if resp != nil && resp.HTTPResponse != nil &&
|
|
||||||
resp.HTTPResponse.StatusCode >= 200 && resp.HTTPResponse.StatusCode < 300 {
|
|
||||||
ds.resp = resp
|
|
||||||
} else {
|
|
||||||
ds.Downloading = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) AddToDownloadList(path string, url string) {
|
|
||||||
absPath, err := a.GetAbsPath(path)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !existsInDownloadList(absPath, url) {
|
|
||||||
downloadList = append(downloadList, &DownloadStatus{
|
|
||||||
resp: nil,
|
|
||||||
Name: filepath.Base(path),
|
|
||||||
Path: absPath,
|
|
||||||
Url: url,
|
|
||||||
Downloading: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
a.ContinueDownload(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) DownloadLoop() {
|
|
||||||
ticker := time.NewTicker(500 * time.Millisecond)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
<-ticker.C
|
|
||||||
for _, ds := range downloadList {
|
|
||||||
if ds.resp != nil {
|
|
||||||
ds.Transferred = ds.resp.BytesComplete()
|
|
||||||
ds.Size = ds.resp.Size()
|
|
||||||
ds.Speed = ds.resp.BytesPerSecond()
|
|
||||||
ds.Progress = 100 * ds.resp.Progress()
|
|
||||||
ds.Downloading = !ds.resp.IsComplete()
|
|
||||||
ds.Done = ds.resp.Progress() == 1
|
|
||||||
if !ds.Downloading {
|
|
||||||
ds.resp = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runtime.EventsEmit(a.ctx, "downloadList", downloadList)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -21,6 +19,17 @@ type ProgressReader struct {
|
||||||
total int64
|
total int64
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
type DownloadStatus struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
Transferred int64 `json:"transferred"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Speed float64 `json:"speed"`
|
||||||
|
Progress float64 `json:"progress"`
|
||||||
|
Downloading bool `json:"downloading"`
|
||||||
|
Done bool `json:"done"`
|
||||||
|
}
|
||||||
|
|
||||||
func (pr *ProgressReader) Read(p []byte) (n int, err error) {
|
func (pr *ProgressReader) Read(p []byte) (n int, err error) {
|
||||||
n, err = pr.reader.Read(p)
|
n, err = pr.reader.Read(p)
|
||||||
|
|
@ -88,13 +97,6 @@ func (a *App) UpdateApp(url string) (broken bool, err error) {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
// restart app
|
// restart app
|
||||||
if runtime.GOOS == "windows" {
|
a.RestartApp()
|
||||||
name, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
exec.Command(name, os.Args[1:]...).Start()
|
|
||||||
wruntime.Quit(a.ctx)
|
|
||||||
}
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
frontend/components.d.ts
vendored
5
frontend/components.d.ts
vendored
|
|
@ -7,9 +7,10 @@ export {}
|
||||||
/* prettier-ignore */
|
/* prettier-ignore */
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
|
AddApp: typeof import('./src/components/store/AddApp.vue')['default']
|
||||||
AppIcon: typeof import('./src/components/taskbar/AppIcon.vue')['default']
|
AppIcon: typeof import('./src/components/taskbar/AppIcon.vue')['default']
|
||||||
AppIconGroup: typeof import('./src/components/taskbar/AppIconGroup.vue')['default']
|
AppIconGroup: typeof import('./src/components/taskbar/AppIconGroup.vue')['default']
|
||||||
AppItem: typeof import('./src/components/builtin/AppItem.vue')['default']
|
AppItem: typeof import('./src/components/store/AppItem.vue')['default']
|
||||||
Battery: typeof import('./src/components/taskbar/Battery.vue')['default']
|
Battery: typeof import('./src/components/taskbar/Battery.vue')['default']
|
||||||
BatteryPop: typeof import('./src/components/taskbar/BatteryPop.vue')['default']
|
BatteryPop: typeof import('./src/components/taskbar/BatteryPop.vue')['default']
|
||||||
Browser: typeof import('./src/components/builtin/Browser.vue')['default']
|
Browser: typeof import('./src/components/builtin/Browser.vue')['default']
|
||||||
|
|
@ -106,7 +107,7 @@ declare module 'vue' {
|
||||||
StartMenu: typeof import('./src/components/taskbar/StartMenu.vue')['default']
|
StartMenu: typeof import('./src/components/taskbar/StartMenu.vue')['default']
|
||||||
StartOption: typeof import('./src/components/taskbar/StartOption.vue')['default']
|
StartOption: typeof import('./src/components/taskbar/StartOption.vue')['default']
|
||||||
StateIcon: typeof import('./src/components/taskbar/StateIcon.vue')['default']
|
StateIcon: typeof import('./src/components/taskbar/StateIcon.vue')['default']
|
||||||
Store: typeof import('./src/components/builtin/Store.vue')['default']
|
Store: typeof import('./src/components/store/Store.vue')['default']
|
||||||
Taskbar: typeof import('./src/components/taskbar/Taskbar.vue')['default']
|
Taskbar: typeof import('./src/components/taskbar/Taskbar.vue')['default']
|
||||||
UpPopover: typeof import('./src/components/computer/UpPopover.vue')['default']
|
UpPopover: typeof import('./src/components/computer/UpPopover.vue')['default']
|
||||||
UrlBrowser: typeof import('./src/components/builtin/UrlBrowser.vue')['default']
|
UrlBrowser: typeof import('./src/components/builtin/UrlBrowser.vue')['default']
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
7d93ddef64f0624cd1fa203b3d0350ee
|
0427c64c40c111c3bee3a5dd4c0d87ed
|
||||||
59
frontend/src/components/store/AddApp.vue
Normal file
59
frontend/src/components/store/AddApp.vue
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
const formData = ref({
|
||||||
|
importType: 'remote'
|
||||||
|
})
|
||||||
|
const addType = [
|
||||||
|
{
|
||||||
|
'name' : '远程下载',
|
||||||
|
'type' : 'remote'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name' : '本地导入',
|
||||||
|
'type' : 'local'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name' : '开发模式',
|
||||||
|
'type' : 'dev'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-item">
|
||||||
|
<label>添加方式</label>
|
||||||
|
<el-select v-model="formData.importType" style="width: 180px;">
|
||||||
|
<el-option
|
||||||
|
v-for="item in addType"
|
||||||
|
:key="item.type"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.type"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.setting-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-item label {
|
||||||
|
display: block;
|
||||||
|
width: 100px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,30 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="outer">
|
<div class="outer">
|
||||||
<div class="uper">
|
|
||||||
<div class="up-text">应用商店</div>
|
|
||||||
</div>
|
|
||||||
<div class="store-handle" v-dragable>
|
|
||||||
<div v-if="!closing" @click="closeWin" class="close-button">×</div>
|
|
||||||
</div>
|
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="left-icon">
|
<div class="left-icon" v-for="(item, key) in categoryList" @click="changeCate(key, item)">
|
||||||
<div class="icon-derc"></div>
|
<div class="icon-derc" v-if="key == currentCateId"></div>
|
||||||
<svg
|
<el-tooltip class="box-item" effect="dark" :content="t('store.' + item)" placement="right">
|
||||||
t="1694613650127"
|
<el-icon size="22">
|
||||||
class="icon"
|
<component :is="categoryIcon[key]" />
|
||||||
viewBox="0 0 1024 1024"
|
</el-icon>
|
||||||
version="1.1"
|
</el-tooltip>
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
p-id="10617"
|
|
||||||
width="200"
|
|
||||||
height="200"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M511.813 92.188L92.188 428.844v502.5h295.406V647.469h248.344v283.875h295.406v-502.5z"
|
|
||||||
p-id="10618"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="store">
|
<div class="store">
|
||||||
|
|
@ -32,9 +16,9 @@
|
||||||
<!-- <div class="left-bar"></div> -->
|
<!-- <div class="left-bar"></div> -->
|
||||||
<div class="right-main">
|
<div class="right-main">
|
||||||
<div class="main-title">
|
<div class="main-title">
|
||||||
<!-- <span class="sub-title">热门应用 </span> -->
|
<span class="sub-title">{{ currentTitle }} </span>
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper">
|
<!-- <div class="swiper">
|
||||||
<div class="swiper-txt">主页</div>
|
<div class="swiper-txt">主页</div>
|
||||||
<div class="swiper-inner">
|
<div class="swiper-inner">
|
||||||
<div class="swiper-tab">
|
<div class="swiper-tab">
|
||||||
|
|
@ -46,20 +30,14 @@
|
||||||
<div class="swiper-tab">
|
<div class="swiper-tab">
|
||||||
<img src="/image/store/banner3.jpg" />
|
<img src="/image/store/banner3.jpg" />
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-tab">
|
|
||||||
<img src="/image/store/banner2.jpg" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div> -->
|
||||||
<div class="main-app">
|
<div class="main-app">
|
||||||
<div v-for="item in storeList" class="store-item" :key="item.name">
|
<div v-for="item in storeList" v-if="currentTitle != t('store.add')" class="store-item" :key="item.name">
|
||||||
<AppItem
|
<AppItem :item="item" :installed-list="installedList" :install="install" :uninstall="uninstall" />
|
||||||
:item="item"
|
|
||||||
:installed-list="installedList"
|
|
||||||
:install="install"
|
|
||||||
:uninstall="uninstall"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<AddApp v-else/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -77,23 +55,19 @@
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { inject, onMounted, ref } from "vue";
|
import { inject, onMounted, ref } from "vue";
|
||||||
import { BrowserWindow, System, Dialog, vDragable } from "@/system";
|
import { System, Dialog } from "@/system";
|
||||||
import { t } from "@/i18n";
|
import { t } from "@/i18n";
|
||||||
import storeList from "@/assets/store.json";
|
//import storeList from "@/assets/store.json";
|
||||||
const browserWindow: BrowserWindow = inject("browserWindow")!;
|
|
||||||
import { getSystemKey, setSystemKey } from "@/system/config";
|
import { getSystemKey, setSystemKey } from "@/system/config";
|
||||||
const sys: any = inject<System>("system");
|
const sys: any = inject<System>("system");
|
||||||
console.log(storeList);
|
const currentCateId = ref(0)
|
||||||
|
const currentTitle = ref(t("store.hots"))
|
||||||
|
const categoryList = ['hots', 'work', 'development', 'games', 'education', 'news', 'shopping', 'social', 'utilities', 'others', 'add']
|
||||||
|
const categoryIcon = ['HomeFilled', 'Odometer', 'Postcard', 'TrendCharts', 'School', 'HelpFilled', 'ShoppingCart', 'ChatLineRound', 'MessageBox', 'Ticket', 'CirclePlusFilled']
|
||||||
const isready = ref(false);
|
const isready = ref(false);
|
||||||
const installed = getSystemKey("intstalledPlugins");
|
const installed = getSystemKey("intstalledPlugins");
|
||||||
const installedList: any = ref(installed);
|
const installedList: any = ref(installed);
|
||||||
const closing = ref(false);
|
const storeList: any = ref([])
|
||||||
function closeWin() {
|
|
||||||
closing.value = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
browserWindow.close();
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!isready.value) {
|
if (!isready.value) {
|
||||||
|
|
@ -101,6 +75,10 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
function changeCate(index: number, item: string) {
|
||||||
|
currentCateId.value = index
|
||||||
|
currentTitle.value = t("store." + item)
|
||||||
|
}
|
||||||
function setCache() {
|
function setCache() {
|
||||||
setSystemKey("intstalledPlugins", installedList.value);
|
setSystemKey("intstalledPlugins", installedList.value);
|
||||||
//localStorage.setItem("godoOS_installedApp", JSON.stringify(installedList.value))
|
//localStorage.setItem("godoOS_installedApp", JSON.stringify(installedList.value))
|
||||||
|
|
@ -143,6 +121,7 @@ function uninstall(item: any) {
|
||||||
height: 16px;
|
height: 16px;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*定义滚动条轨道
|
/*定义滚动条轨道
|
||||||
内阴影+圆角*/
|
内阴影+圆角*/
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
|
|
@ -150,6 +129,7 @@ function uninstall(item: any) {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*定义滑块
|
/*定义滑块
|
||||||
内阴影+圆角*/
|
内阴影+圆角*/
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
|
|
@ -164,6 +144,7 @@ function uninstall(item: any) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.uper {
|
.uper {
|
||||||
padding: 0px 20px;
|
padding: 0px 20px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
@ -173,6 +154,7 @@ function uninstall(item: any) {
|
||||||
color: rgb(134, 134, 134);
|
color: rgb(134, 134, 134);
|
||||||
background-color: rgb(243, 243, 243);
|
background-color: rgb(243, 243, 243);
|
||||||
}
|
}
|
||||||
|
|
||||||
.store-handle {
|
.store-handle {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
@ -192,9 +174,10 @@ function uninstall(item: any) {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: rgb(243, 243, 243);
|
background-color: rgb(243, 243, 243);
|
||||||
}
|
}
|
||||||
|
|
||||||
.left {
|
.left {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 60px;
|
height: auto;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
background-color: rgb(243, 243, 243);
|
background-color: rgb(243, 243, 243);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -202,6 +185,7 @@ function uninstall(item: any) {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-icon {
|
.left-icon {
|
||||||
width: 56px;
|
width: 56px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
|
@ -209,9 +193,14 @@ function uninstall(item: any) {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
border-radius: 6px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(243, 243, 243);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-derc {
|
.icon-derc {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
width: 4px;
|
width: 4px;
|
||||||
|
|
@ -220,12 +209,14 @@ function uninstall(item: any) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 2px;
|
left: 2px;
|
||||||
}
|
}
|
||||||
.left-icon svg {
|
|
||||||
|
.left-icon .ep_icon {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
color: #363533;
|
color: #363533;
|
||||||
stroke: #363533;
|
stroke: #363533;
|
||||||
}
|
}
|
||||||
|
|
||||||
.store {
|
.store {
|
||||||
/* width: 100%; */
|
/* width: 100%; */
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
@ -242,10 +233,12 @@ function uninstall(item: any) {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-bar {
|
.left-bar {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-main {
|
.right-main {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -264,6 +257,7 @@ function uninstall(item: any) {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub-title {
|
.sub-title {
|
||||||
padding-top: 30px;
|
padding-top: 30px;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
|
@ -273,12 +267,14 @@ function uninstall(item: any) {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub-tip {
|
.sub-tip {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: rgb(11, 31, 111);
|
color: rgb(11, 31, 111);
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.swiper {
|
.swiper {
|
||||||
width: max-content;
|
width: max-content;
|
||||||
height: 300px;
|
height: 300px;
|
||||||
|
|
@ -287,7 +283,9 @@ function uninstall(item: any) {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes swiperAni {
|
@keyframes swiperAni {
|
||||||
|
|
||||||
0%,
|
0%,
|
||||||
33% {
|
33% {
|
||||||
transform: translateX(0px);
|
transform: translateX(0px);
|
||||||
|
|
@ -302,10 +300,12 @@ function uninstall(item: any) {
|
||||||
96% {
|
96% {
|
||||||
transform: translateX(-1200px);
|
transform: translateX(-1200px);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: translateX(0px);
|
transform: translateX(0px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.swiper-inner {
|
.swiper-inner {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
|
@ -313,6 +313,7 @@ function uninstall(item: any) {
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
animation: swiperAni 20s ease-in-out infinite;
|
animation: swiperAni 20s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.swiper-tab {
|
.swiper-tab {
|
||||||
width: 600px;
|
width: 600px;
|
||||||
height: 300px;
|
height: 300px;
|
||||||
|
|
@ -320,12 +321,14 @@ function uninstall(item: any) {
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
box-shadow: 0px 10px 20px 1px #2524241f;
|
box-shadow: 0px 10px 20px 1px #2524241f;
|
||||||
}
|
}
|
||||||
|
|
||||||
.swiper-tab img {
|
.swiper-tab img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.swiper-txt {
|
.swiper-txt {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
|
|
@ -335,6 +338,7 @@ function uninstall(item: any) {
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
text-shadow: 0px 0px 5px #00000058;
|
text-shadow: 0px 0px 5px #00000058;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-app {
|
.main-app {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
/* height: 100%; */
|
/* height: 100%; */
|
||||||
|
|
@ -347,6 +351,7 @@ function uninstall(item: any) {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.store-noready {
|
.store-noready {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -130,5 +130,18 @@
|
||||||
"black": "Black",
|
"black": "Black",
|
||||||
"cannot.create.shortcut": "Cannot Create Shortcut",
|
"cannot.create.shortcut": "Cannot Create Shortcut",
|
||||||
"shortcut.has.been.created": "Shortcut Has Been Created",
|
"shortcut.has.been.created": "Shortcut Has Been Created",
|
||||||
"system.message": "System Message"
|
"system.message": "System Message",
|
||||||
|
"store" : {
|
||||||
|
"hots":"Popular",
|
||||||
|
"work": "Work",
|
||||||
|
"development": "Development",
|
||||||
|
"games": "Games",
|
||||||
|
"education": "Education",
|
||||||
|
"news": "News",
|
||||||
|
"shopping":"Shopping",
|
||||||
|
"social": "Social Networking",
|
||||||
|
"utilities": "Utilities",
|
||||||
|
"others": "Others",
|
||||||
|
"add":"Add"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -130,5 +130,18 @@
|
||||||
"black": "黑色",
|
"black": "黑色",
|
||||||
"cannot.create.shortcut": "无法创建快捷方式",
|
"cannot.create.shortcut": "无法创建快捷方式",
|
||||||
"shortcut.has.been.created": "快捷方式已创建",
|
"shortcut.has.been.created": "快捷方式已创建",
|
||||||
"system.message": "系统消息"
|
"system.message": "系统消息",
|
||||||
|
"store" : {
|
||||||
|
"hots":"热门",
|
||||||
|
"work": "办公",
|
||||||
|
"development": "开发工具",
|
||||||
|
"games": "游戏",
|
||||||
|
"education": "教育",
|
||||||
|
"news": "新闻",
|
||||||
|
"shopping":"购物",
|
||||||
|
"social": "社交",
|
||||||
|
"utilities": "实用工具",
|
||||||
|
"others": "其他",
|
||||||
|
"add":"添加应用"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -34,13 +34,13 @@ export const appList = [
|
||||||
multiple: false,
|
multiple: false,
|
||||||
appIcon: "store",
|
appIcon: "store",
|
||||||
content: "Store",
|
content: "Store",
|
||||||
frame: false,
|
frame: true,
|
||||||
width: 900,
|
width: 900,
|
||||||
height: 630,
|
height: 600,
|
||||||
center: true,
|
center: true,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
backgroundColor: '#ffffff00',
|
backgroundColor: '#ffffff00',
|
||||||
isDeskTop: false,
|
isDeskTop: true,
|
||||||
isMagnet: true,
|
isMagnet: true,
|
||||||
isMenuList: true,
|
isMenuList: true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
14
frontend/wailsjs/go/app/App.d.ts
vendored
14
frontend/wailsjs/go/app/App.d.ts
vendored
|
|
@ -1,22 +1,8 @@
|
||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
export function AddToDownloadList(arg1:string,arg2:string):Promise<void>;
|
|
||||||
|
|
||||||
export function ContinueDownload(arg1:string):Promise<void>;
|
|
||||||
|
|
||||||
export function DownloadFile(arg1:string,arg2:string):Promise<void>;
|
|
||||||
|
|
||||||
export function DownloadLoop():Promise<void>;
|
|
||||||
|
|
||||||
export function GetAbsPath(arg1:string):Promise<string>;
|
|
||||||
|
|
||||||
export function GetPlatform():Promise<string>;
|
|
||||||
|
|
||||||
export function OpenDirDialog():Promise<string>;
|
export function OpenDirDialog():Promise<string>;
|
||||||
|
|
||||||
export function PauseDownload(arg1:string):Promise<void>;
|
|
||||||
|
|
||||||
export function RestartApp():Promise<void>;
|
export function RestartApp():Promise<void>;
|
||||||
|
|
||||||
export function UpdateApp(arg1:string):Promise<boolean>;
|
export function UpdateApp(arg1:string):Promise<boolean>;
|
||||||
|
|
|
||||||
|
|
@ -2,38 +2,10 @@
|
||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
export function AddToDownloadList(arg1, arg2) {
|
|
||||||
return window['go']['app']['App']['AddToDownloadList'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ContinueDownload(arg1) {
|
|
||||||
return window['go']['app']['App']['ContinueDownload'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DownloadFile(arg1, arg2) {
|
|
||||||
return window['go']['app']['App']['DownloadFile'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DownloadLoop() {
|
|
||||||
return window['go']['app']['App']['DownloadLoop']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetAbsPath(arg1) {
|
|
||||||
return window['go']['app']['App']['GetAbsPath'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetPlatform() {
|
|
||||||
return window['go']['app']['App']['GetPlatform']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OpenDirDialog() {
|
export function OpenDirDialog() {
|
||||||
return window['go']['app']['App']['OpenDirDialog']();
|
return window['go']['app']['App']['OpenDirDialog']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PauseDownload(arg1) {
|
|
||||||
return window['go']['app']['App']['PauseDownload'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RestartApp() {
|
export function RestartApp() {
|
||||||
return window['go']['app']['App']['RestartApp']();
|
return window['go']['app']['App']['RestartApp']();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
go.mod
16
go.mod
|
|
@ -1,19 +1,17 @@
|
||||||
module godoos
|
module godoos
|
||||||
|
|
||||||
go 1.21
|
go 1.22.5
|
||||||
|
|
||||||
toolchain go1.22.5
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cavaliergopher/grab/v3 v3.0.1
|
|
||||||
github.com/fsnotify/fsnotify v1.4.9
|
|
||||||
github.com/minio/selfupdate v0.6.0
|
github.com/minio/selfupdate v0.6.0
|
||||||
github.com/shirou/gopsutil v2.21.11+incompatible
|
|
||||||
github.com/wailsapp/wails/v2 v2.9.1
|
github.com/wailsapp/wails/v2 v2.9.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
aead.dev/minisign v0.2.0 // indirect
|
aead.dev/minisign v0.2.0 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||||
github.com/tklauser/numcpus v0.8.0 // indirect
|
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
|
|
@ -24,7 +22,6 @@ require (
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/gorilla/mux v1.8.1
|
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||||
github.com/labstack/echo/v4 v4.10.2 // indirect
|
github.com/labstack/echo/v4 v4.10.2 // indirect
|
||||||
github.com/labstack/gommon v0.4.0 // indirect
|
github.com/labstack/gommon v0.4.0 // indirect
|
||||||
|
|
@ -35,7 +32,7 @@ require (
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/rivo/uniseg v0.4.4 // indirect
|
||||||
github.com/samber/lo v1.38.1 // indirect
|
github.com/samber/lo v1.38.1 // indirect
|
||||||
github.com/tkrajina/go-reflector v0.5.6 // indirect
|
github.com/tkrajina/go-reflector v0.5.6 // indirect
|
||||||
|
|
@ -43,6 +40,7 @@ require (
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/wailsapp/go-webview2 v1.0.10 // indirect
|
github.com/wailsapp/go-webview2 v1.0.10 // indirect
|
||||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||||
|
godo v0.0.1
|
||||||
golang.org/x/crypto v0.23.0 // indirect
|
golang.org/x/crypto v0.23.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||||
golang.org/x/net v0.25.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
|
|
@ -50,4 +48,6 @@ require (
|
||||||
golang.org/x/text v0.15.0 // indirect
|
golang.org/x/text v0.15.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace godo v0.0.1 => ./godo
|
||||||
|
|
||||||
// replace github.com/wailsapp/wails/v2 v2.9.1 => /home/ruitao/go/pkg/mod
|
// replace github.com/wailsapp/wails/v2 v2.9.1 => /home/ruitao/go/pkg/mod
|
||||||
|
|
|
||||||
15
go.sum
15
go.sum
|
|
@ -2,13 +2,11 @@ aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
|
||||||
aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
|
aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
|
||||||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
|
||||||
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
|
||||||
github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4=
|
|
||||||
github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
|
|
@ -56,12 +54,12 @@ github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||||
github.com/shirou/gopsutil v2.21.11+incompatible h1:lOGOyCG67a5dv2hq5Z1BLDUqqKp3HkbjPcz5j6XMS0U=
|
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||||
github.com/shirou/gopsutil v2.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||||
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||||
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||||
|
|
@ -95,7 +93,6 @@ golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"godoos/libs"
|
"godo/files"
|
||||||
"godoos/localchat"
|
"godo/libs"
|
||||||
"godoos/progress"
|
"godo/localchat"
|
||||||
|
"godo/progress"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -22,6 +23,8 @@ func OsStart() {
|
||||||
router.Use(corsMiddleware())
|
router.Use(corsMiddleware())
|
||||||
// 使用带有日志装饰的处理器注册路由
|
// 使用带有日志装饰的处理器注册路由
|
||||||
router.Use(loggingMiddleware{}.Middleware)
|
router.Use(loggingMiddleware{}.Middleware)
|
||||||
|
staticDir := libs.GetStaticDir()
|
||||||
|
router.PathPrefix("/static").Handler(http.StripPrefix("/static", http.FileServer(http.Dir(staticDir))))
|
||||||
progressRouter := router.PathPrefix("/progress").Subrouter()
|
progressRouter := router.PathPrefix("/progress").Subrouter()
|
||||||
progressRouter.HandleFunc("/start/{name}", progress.StartProcess).Methods(http.MethodGet)
|
progressRouter.HandleFunc("/start/{name}", progress.StartProcess).Methods(http.MethodGet)
|
||||||
progressRouter.HandleFunc("/stop/{name}", progress.StopProcess).Methods(http.MethodGet)
|
progressRouter.HandleFunc("/stop/{name}", progress.StopProcess).Methods(http.MethodGet)
|
||||||
|
|
@ -35,22 +38,22 @@ func OsStart() {
|
||||||
progressRouter.HandleFunc("/app/{name}/{subpath:.*}", progress.ForwardRequest).Methods(http.MethodGet, http.MethodPost)
|
progressRouter.HandleFunc("/app/{name}/{subpath:.*}", progress.ForwardRequest).Methods(http.MethodGet, http.MethodPost)
|
||||||
router.HandleFunc("/ping", progress.Ping).Methods(http.MethodGet)
|
router.HandleFunc("/ping", progress.Ping).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/", progress.Ping).Methods(http.MethodGet)
|
router.HandleFunc("/", progress.Ping).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/system/info", HandleSystemInfo).Methods(http.MethodGet)
|
router.HandleFunc("/system/info", files.HandleSystemInfo).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/system/setting", HandleSetConfig).Methods(http.MethodPost)
|
router.HandleFunc("/system/setting", HandleSetConfig).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/file/read", HandleReadDir).Methods(http.MethodGet)
|
router.HandleFunc("/file/read", files.HandleReadDir).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/file/stat", HandleStat).Methods(http.MethodGet)
|
router.HandleFunc("/file/stat", files.HandleStat).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/file/chmod", HandleChmod).Methods(http.MethodPost)
|
router.HandleFunc("/file/chmod", files.HandleChmod).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/file/exists", HandleExists).Methods(http.MethodGet)
|
router.HandleFunc("/file/exists", files.HandleExists).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/file/readfile", HandleReadFile).Methods(http.MethodGet)
|
router.HandleFunc("/file/readfile", files.HandleReadFile).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/file/unlink", HandleUnlink).Methods(http.MethodGet)
|
router.HandleFunc("/file/unlink", files.HandleUnlink).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/file/clear", HandleClear).Methods(http.MethodGet)
|
router.HandleFunc("/file/clear", files.HandleClear).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/file/rename", HandleRename).Methods(http.MethodGet)
|
router.HandleFunc("/file/rename", files.HandleRename).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/file/mkdir", HandleMkdir).Methods(http.MethodPost)
|
router.HandleFunc("/file/mkdir", files.HandleMkdir).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/file/rmdir", HandleRmdir).Methods(http.MethodGet)
|
router.HandleFunc("/file/rmdir", files.HandleRmdir).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/file/copyfile", HandleCopyFile).Methods(http.MethodGet)
|
router.HandleFunc("/file/copyfile", files.HandleCopyFile).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/file/writefile", HandleWriteFile).Methods(http.MethodPost)
|
router.HandleFunc("/file/writefile", files.HandleWriteFile).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/file/appendfile", HandleAppendFile).Methods(http.MethodPost)
|
router.HandleFunc("/file/appendfile", files.HandleAppendFile).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/file/watch", WatchHandler).Methods(http.MethodGet)
|
router.HandleFunc("/file/watch", files.WatchHandler).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/localchat/sse", localchat.SseHandler).Methods(http.MethodGet)
|
router.HandleFunc("/localchat/sse", localchat.SseHandler).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/localchat/message", localchat.HandleMessage).Methods(http.MethodPost)
|
router.HandleFunc("/localchat/message", localchat.HandleMessage).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/localchat/upload", localchat.MultiUploadHandler).Methods(http.MethodPost)
|
router.HandleFunc("/localchat/upload", localchat.MultiUploadHandler).Methods(http.MethodPost)
|
||||||
|
|
@ -2,44 +2,48 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"godoos/libs"
|
"godo/libs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func GetOsPath() string {
|
||||||
|
osInfo, _ := libs.GetConfig("osInfo")
|
||||||
|
return osInfo.Value
|
||||||
|
}
|
||||||
func HandleSetConfig(w http.ResponseWriter, r *http.Request) {
|
func HandleSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
var req libs.ReqBody
|
var req libs.ReqBody
|
||||||
err := json.NewDecoder(r.Body).Decode(&req)
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorMsg(w, "The params is error!")
|
libs.ErrorMsg(w, "The params is error!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.Name == "osInfo" {
|
if req.Name == "osInfo" && req.Value != "" {
|
||||||
osInfo, _ := libs.GetConfig("osInfo")
|
osInfo, _ := libs.GetConfig("osInfo")
|
||||||
if req.Value != "" {
|
if osInfo.Value != req.Value {
|
||||||
if !libs.PathExists(req.Value) {
|
if !libs.PathExists(req.Value) {
|
||||||
ErrorMsg(w, "The Path is not exists!")
|
libs.ErrorMsg(w, "The Path is not exists!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = os.Chmod(req.Value, 0755)
|
err = os.Chmod(req.Value, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorMsg(w, "The Path chmod is error!")
|
libs.ErrorMsg(w, "The Path chmod is error!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
osInfo.Value = req.Value
|
osInfo.Value = req.Value
|
||||||
}
|
|
||||||
|
|
||||||
osInfo.Type = req.Type
|
osInfo.Type = req.Type
|
||||||
libs.SetConfig(osInfo)
|
libs.SetConfig(osInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
if req.Name == "userInfo" ||
|
if req.Name == "userInfo" ||
|
||||||
req.Name == "dbInfo" {
|
req.Name == "dbInfo" {
|
||||||
libs.SetConfig(req)
|
libs.SetConfig(req)
|
||||||
}
|
}
|
||||||
err = libs.LoadConfig()
|
err = libs.LoadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorMsg(w, "The config load error!")
|
libs.ErrorMsg(w, "The config load error!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
SuccessMsg(w, "success", "The config set success!")
|
libs.SuccessMsg(w, "success", "The config set success!")
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package cmd
|
package files
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"godoos/libs"
|
"godo/libs"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -18,12 +18,12 @@ import (
|
||||||
func HandleSystemInfo(w http.ResponseWriter, r *http.Request) {
|
func HandleSystemInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
info := libs.GetSystemInfo()
|
info := libs.GetSystemInfo()
|
||||||
|
|
||||||
// res := APIResponse{
|
// res := libs.APIResponse{
|
||||||
// Message: "File information retrieved successfully.",
|
// Message: "File information retrieved successfully.",
|
||||||
// Data: info,
|
// Data: info,
|
||||||
// }
|
// }
|
||||||
//json.NewEncoder(w).Encode(res)
|
//json.NewEncoder(w).Encode(res)
|
||||||
SuccessMsg(w, info, "File information retrieved successfully.")
|
libs.SuccessMsg(w, info, "File information retrieved successfully.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleReadDir handles reading a directory
|
// HandleReadDir handles reading a directory
|
||||||
|
|
@ -31,13 +31,13 @@ func HandleReadDir(w http.ResponseWriter, r *http.Request) {
|
||||||
path := r.URL.Query().Get("path")
|
path := r.URL.Query().Get("path")
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
files, err := ReadDir(basePath, path)
|
files, err := ReadDir(basePath, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ func HandleReadDir(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
osFileInfo, err := GetFileInfo(entry, basePath, path)
|
osFileInfo, err := GetFileInfo(entry, basePath, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,14 +57,14 @@ func HandleReadDir(w http.ResponseWriter, r *http.Request) {
|
||||||
if osFileInfo.IsFile {
|
if osFileInfo.IsFile {
|
||||||
file, err := os.Open(filepath.Join(basePath, osFileInfo.Path))
|
file, err := os.Open(filepath.Join(basePath, osFileInfo.Path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to open file: %v", err))
|
libs.HTTPError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to open file: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
content, err := io.ReadAll(file)
|
content, err := io.ReadAll(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to read file content: %v", err))
|
libs.HTTPError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to read file content: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
osFileInfo.Content = string(content)
|
osFileInfo.Content = string(content)
|
||||||
|
|
@ -83,7 +83,7 @@ func HandleReadDir(w http.ResponseWriter, r *http.Request) {
|
||||||
sort.Slice(osFileInfos, func(i, j int) bool {
|
sort.Slice(osFileInfos, func(i, j int) bool {
|
||||||
return osFileInfos[i].ModTime.Before(osFileInfos[j].ModTime)
|
return osFileInfos[i].ModTime.Before(osFileInfos[j].ModTime)
|
||||||
})
|
})
|
||||||
res := APIResponse{
|
res := libs.APIResponse{
|
||||||
Message: "Directory read successfully.",
|
Message: "Directory read successfully.",
|
||||||
Data: osFileInfos,
|
Data: osFileInfos,
|
||||||
}
|
}
|
||||||
|
|
@ -94,23 +94,23 @@ func HandleReadDir(w http.ResponseWriter, r *http.Request) {
|
||||||
func HandleStat(w http.ResponseWriter, r *http.Request) {
|
func HandleStat(w http.ResponseWriter, r *http.Request) {
|
||||||
path := r.URL.Query().Get("path")
|
path := r.URL.Query().Get("path")
|
||||||
if err := validateFilePath(path); err != nil {
|
if err := validateFilePath(path); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用GetFileInfo,传入路径而不是fs.DirEntry
|
// 调用GetFileInfo,传入路径而不是fs.DirEntry
|
||||||
osFileInfo, err := GetFileInfo(path, basePath, "")
|
osFileInfo, err := GetFileInfo(path, basePath, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusNotFound, err.Error())
|
libs.HTTPError(w, http.StatusNotFound, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res := APIResponse{
|
res := libs.APIResponse{
|
||||||
Message: "File information retrieved successfully.",
|
Message: "File information retrieved successfully.",
|
||||||
Data: osFileInfo,
|
Data: osFileInfo,
|
||||||
}
|
}
|
||||||
|
|
@ -121,12 +121,12 @@ func HandleStat(w http.ResponseWriter, r *http.Request) {
|
||||||
func HandleExists(w http.ResponseWriter, r *http.Request) {
|
func HandleExists(w http.ResponseWriter, r *http.Request) {
|
||||||
path := r.URL.Query().Get("path")
|
path := r.URL.Query().Get("path")
|
||||||
if err := validateFilePath(path); err != nil {
|
if err := validateFilePath(path); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
exists := Exists(basePath, path)
|
exists := Exists(basePath, path)
|
||||||
|
|
@ -134,7 +134,7 @@ func HandleExists(w http.ResponseWriter, r *http.Request) {
|
||||||
if exists {
|
if exists {
|
||||||
message = "File exists."
|
message = "File exists."
|
||||||
}
|
}
|
||||||
res := APIResponse{
|
res := libs.APIResponse{
|
||||||
Message: message,
|
Message: message,
|
||||||
Data: exists,
|
Data: exists,
|
||||||
}
|
}
|
||||||
|
|
@ -145,17 +145,17 @@ func HandleExists(w http.ResponseWriter, r *http.Request) {
|
||||||
func HandleReadFile(w http.ResponseWriter, r *http.Request) {
|
func HandleReadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
path := r.URL.Query().Get("path")
|
path := r.URL.Query().Get("path")
|
||||||
if err := validateFilePath(path); err != nil {
|
if err := validateFilePath(path); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fileContent, err := ReadFile(basePath, path)
|
fileContent, err := ReadFile(basePath, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusNotFound, err.Error())
|
libs.HTTPError(w, http.StatusNotFound, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
content := string(fileContent)
|
content := string(fileContent)
|
||||||
|
|
@ -163,7 +163,7 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
if !strings.HasPrefix(content, "link::") {
|
if !strings.HasPrefix(content, "link::") {
|
||||||
content = base64.StdEncoding.EncodeToString(fileContent)
|
content = base64.StdEncoding.EncodeToString(fileContent)
|
||||||
}
|
}
|
||||||
res := APIResponse{
|
res := libs.APIResponse{
|
||||||
Message: fmt.Sprintf("File '%s' read successfully.", path),
|
Message: fmt.Sprintf("File '%s' read successfully.", path),
|
||||||
Data: content, // Optionally, encode content as base64 for transmission
|
Data: content, // Optionally, encode content as base64 for transmission
|
||||||
//Data: string(fileContent),
|
//Data: string(fileContent),
|
||||||
|
|
@ -175,20 +175,20 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
func HandleUnlink(w http.ResponseWriter, r *http.Request) {
|
func HandleUnlink(w http.ResponseWriter, r *http.Request) {
|
||||||
path := r.URL.Query().Get("path")
|
path := r.URL.Query().Get("path")
|
||||||
if err := validateFilePath(path); err != nil {
|
if err := validateFilePath(path); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = Unlink(basePath, path)
|
err = Unlink(basePath, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusConflict, err.Error())
|
libs.HTTPError(w, http.StatusConflict, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := APIResponse{Message: fmt.Sprintf("File '%s' successfully removed.", path)}
|
res := libs.APIResponse{Message: fmt.Sprintf("File '%s' successfully removed.", path)}
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,15 +196,15 @@ func HandleUnlink(w http.ResponseWriter, r *http.Request) {
|
||||||
func HandleClear(w http.ResponseWriter, r *http.Request) {
|
func HandleClear(w http.ResponseWriter, r *http.Request) {
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = Clear(basePath)
|
err = Clear(basePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusConflict, err.Error())
|
libs.HTTPError(w, http.StatusConflict, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := APIResponse{Message: "FileSystem successfully cleared."}
|
res := libs.APIResponse{Message: "FileSystem successfully cleared."}
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,21 +213,21 @@ func HandleRename(w http.ResponseWriter, r *http.Request) {
|
||||||
oldPath := r.URL.Query().Get("oldPath")
|
oldPath := r.URL.Query().Get("oldPath")
|
||||||
newPath := r.URL.Query().Get("newPath")
|
newPath := r.URL.Query().Get("newPath")
|
||||||
if err := validateFilePathPair(oldPath, newPath); err != nil {
|
if err := validateFilePathPair(oldPath, newPath); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = Rename(basePath, oldPath, newPath)
|
err = Rename(basePath, oldPath, newPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error renaming file: %s", err.Error())
|
log.Printf("Error renaming file: %s", err.Error())
|
||||||
HTTPError(w, http.StatusConflict, err.Error())
|
libs.HTTPError(w, http.StatusConflict, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := APIResponse{Message: fmt.Sprintf("File '%s' successfully renamed to '%s'.", oldPath, newPath)}
|
res := libs.APIResponse{Message: fmt.Sprintf("File '%s' successfully renamed to '%s'.", oldPath, newPath)}
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,20 +235,20 @@ func HandleRename(w http.ResponseWriter, r *http.Request) {
|
||||||
func HandleMkdir(w http.ResponseWriter, r *http.Request) {
|
func HandleMkdir(w http.ResponseWriter, r *http.Request) {
|
||||||
dirPath := r.URL.Query().Get("dirPath")
|
dirPath := r.URL.Query().Get("dirPath")
|
||||||
if err := validateFilePath(dirPath); err != nil {
|
if err := validateFilePath(dirPath); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = Mkdir(basePath, dirPath)
|
err = Mkdir(basePath, dirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusConflict, err.Error())
|
libs.HTTPError(w, http.StatusConflict, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := APIResponse{Message: fmt.Sprintf("Directory '%s' created successfully.", dirPath)}
|
res := libs.APIResponse{Message: fmt.Sprintf("Directory '%s' created successfully.", dirPath)}
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,20 +256,20 @@ func HandleMkdir(w http.ResponseWriter, r *http.Request) {
|
||||||
func HandleRmdir(w http.ResponseWriter, r *http.Request) {
|
func HandleRmdir(w http.ResponseWriter, r *http.Request) {
|
||||||
dirPath := r.URL.Query().Get("dirPath")
|
dirPath := r.URL.Query().Get("dirPath")
|
||||||
if err := validateFilePath(dirPath); err != nil {
|
if err := validateFilePath(dirPath); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = Rmdir(basePath, dirPath)
|
err = Rmdir(basePath, dirPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusConflict, err.Error())
|
libs.HTTPError(w, http.StatusConflict, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := APIResponse{Message: fmt.Sprintf("Directory '%s' successfully removed.", dirPath)}
|
res := libs.APIResponse{Message: fmt.Sprintf("Directory '%s' successfully removed.", dirPath)}
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,20 +278,20 @@ func HandleCopyFile(w http.ResponseWriter, r *http.Request) {
|
||||||
srcPath := r.URL.Query().Get("srcPath")
|
srcPath := r.URL.Query().Get("srcPath")
|
||||||
dstPath := r.URL.Query().Get("dstPath")
|
dstPath := r.URL.Query().Get("dstPath")
|
||||||
if err := validateFilePathPair(srcPath, dstPath); err != nil {
|
if err := validateFilePathPair(srcPath, dstPath); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = CopyFile(filepath.Join(basePath, srcPath), filepath.Join(basePath, dstPath))
|
err = CopyFile(filepath.Join(basePath, srcPath), filepath.Join(basePath, dstPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusConflict, err.Error())
|
libs.HTTPError(w, http.StatusConflict, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := APIResponse{Message: fmt.Sprintf("File '%s' successfully copied to '%s'.", srcPath, dstPath)}
|
res := libs.APIResponse{Message: fmt.Sprintf("File '%s' successfully copied to '%s'.", srcPath, dstPath)}
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,7 +300,7 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
|
||||||
filePath := r.URL.Query().Get("filePath")
|
filePath := r.URL.Query().Get("filePath")
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 获取文件内容
|
// 获取文件内容
|
||||||
|
|
@ -324,7 +324,7 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusConflict)
|
http.Error(w, err.Error(), http.StatusConflict)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := APIResponse{Message: fmt.Sprintf("File '%s' successfully written.", filePath)}
|
res := libs.APIResponse{Message: fmt.Sprintf("File '%s' successfully written.", filePath)}
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,25 +332,25 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
|
||||||
func HandleAppendFile(w http.ResponseWriter, r *http.Request) {
|
func HandleAppendFile(w http.ResponseWriter, r *http.Request) {
|
||||||
filePath := r.URL.Query().Get("filePath")
|
filePath := r.URL.Query().Get("filePath")
|
||||||
if err := validateFilePath(filePath); err != nil {
|
if err := validateFilePath(filePath); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
content, _, err := r.FormFile("content")
|
content, _, err := r.FormFile("content")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = AppendToFile(filepath.Join(basePath, filePath), content)
|
err = AppendToFile(filepath.Join(basePath, filePath), content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusConflict, err.Error())
|
libs.HTTPError(w, http.StatusConflict, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res := APIResponse{Message: fmt.Sprintf("Content appended to file '%s'.", filePath)}
|
res := libs.APIResponse{Message: fmt.Sprintf("Content appended to file '%s'.", filePath)}
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,7 +364,7 @@ func HandleChmod(w http.ResponseWriter, r *http.Request) {
|
||||||
// 解析请求体
|
// 解析请求体
|
||||||
err := json.NewDecoder(r.Body).Decode(&reqData)
|
err := json.NewDecoder(r.Body).Decode(&reqData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, "Failed to parse request body")
|
libs.HTTPError(w, http.StatusBadRequest, "Failed to parse request body")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,29 +373,29 @@ func HandleChmod(w http.ResponseWriter, r *http.Request) {
|
||||||
modeStr := reqData.Mode
|
modeStr := reqData.Mode
|
||||||
|
|
||||||
if err := validateFilePath(path); err != nil {
|
if err := validateFilePath(path); err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, err.Error())
|
libs.HTTPError(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mode, err := parseMode(modeStr)
|
mode, err := parseMode(modeStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusBadRequest, fmt.Sprintf("Invalid mode: %s", err.Error()))
|
libs.HTTPError(w, http.StatusBadRequest, fmt.Sprintf("Invalid mode: %s", err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = Chmod(basePath, path, mode)
|
err = Chmod(basePath, path, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusConflict, err.Error())
|
libs.HTTPError(w, http.StatusConflict, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res := APIResponse{Message: fmt.Sprintf("Permissions of file '%s' successfully changed to %o.", path, mode)}
|
res := libs.APIResponse{Message: fmt.Sprintf("Permissions of file '%s' successfully changed to %o.", path, mode)}
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
package cmd
|
package files
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"godoos/libs"
|
"godo/libs"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -14,12 +12,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common response structure
|
// Common response structure
|
||||||
type APIResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Code int `json:"code"`
|
|
||||||
Data any `json:"data,omitempty"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OsFileInfo struct {
|
type OsFileInfo struct {
|
||||||
IsFile bool `json:"isFile"`
|
IsFile bool `json:"isFile"`
|
||||||
|
|
@ -40,23 +32,6 @@ type OsFileInfo struct {
|
||||||
ID int `json:"id,omitempty"` // 文件ID(可选)
|
ID int `json:"id,omitempty"` // 文件ID(可选)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeJSONResponse(w http.ResponseWriter, res APIResponse, status int) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(status)
|
|
||||||
json.NewEncoder(w).Encode(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPError 返回带有JSON错误消息的HTTP错误
|
|
||||||
func HTTPError(w http.ResponseWriter, status int, message string) {
|
|
||||||
writeJSONResponse(w, APIResponse{Message: message, Code: -1}, status)
|
|
||||||
}
|
|
||||||
func ErrorMsg(w http.ResponseWriter, message string) {
|
|
||||||
writeJSONResponse(w, APIResponse{Message: message, Code: -1}, 200)
|
|
||||||
}
|
|
||||||
func SuccessMsg(w http.ResponseWriter, data any, message string) {
|
|
||||||
writeJSONResponse(w, APIResponse{Message: message, Data: data, Code: 0}, 200)
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateFilePath 验证路径不为空
|
// validateFilePath 验证路径不为空
|
||||||
func validateFilePath(path string) error {
|
func validateFilePath(path string) error {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package cmd
|
package files
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"godoos/libs"
|
"godo/libs"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -117,12 +117,12 @@ func WatchHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
dirToWatch := r.URL.Query().Get("filePath")
|
dirToWatch := r.URL.Query().Get("filePath")
|
||||||
basePath, err := libs.GetOsDir()
|
basePath, err := libs.GetOsDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
HTTPError(w, http.StatusInternalServerError, err.Error())
|
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
filePath := filepath.Join(basePath, dirToWatch)
|
filePath := filepath.Join(basePath, dirToWatch)
|
||||||
if !libs.PathExists(filePath) {
|
if !libs.PathExists(filePath) {
|
||||||
HTTPError(w, http.StatusNotFound, "filepath is not exist!")
|
libs.HTTPError(w, http.StatusNotFound, "filepath is not exist!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
StartSSEStream(w, r, filePath)
|
StartSSEStream(w, r, filePath)
|
||||||
20
godo/go.mod
Normal file
20
godo/go.mod
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
module godo
|
||||||
|
|
||||||
|
go 1.22.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0
|
||||||
|
github.com/gorilla/mux v1.8.1
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cavaliergopher/grab/v3 v3.0.1 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
|
github.com/stretchr/testify v1.9.0 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.14 // indirect
|
||||||
|
github.com/tklauser/numcpus v0.8.0 // indirect
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
|
golang.org/x/sys v0.19.0 // indirect
|
||||||
|
)
|
||||||
29
godo/go.sum
Normal file
29
godo/go.sum
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4=
|
||||||
|
github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
|
||||||
|
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
|
||||||
|
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||||
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
@ -15,7 +15,6 @@ type ReqBody struct {
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Info map[string]string `json:"info"`
|
Info map[string]string `json:"info"`
|
||||||
Plugins map[string]interface{} `json:"plugins"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetConfigFile() (string, error) {
|
func GetConfigFile() (string, error) {
|
||||||
|
|
@ -56,14 +56,7 @@ func GetAppDir() (string, error) {
|
||||||
return filepath.Join(homeDir, ".godoos"), nil
|
return filepath.Join(homeDir, ".godoos"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// func OllamaModelsDir() string {
|
func GetRunDir() string {
|
||||||
// homeDir, err := os.UserHomeDir()
|
|
||||||
// if err != nil {
|
|
||||||
// return ".godoos"
|
|
||||||
// }
|
|
||||||
// return filepath.Join(homeDir, ".godoos", "models")
|
|
||||||
// }
|
|
||||||
func GetExeDir() string {
|
|
||||||
// 获取当前用户主目录
|
// 获取当前用户主目录
|
||||||
homeDir, err := GetAppDir()
|
homeDir, err := GetAppDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -80,6 +73,28 @@ func GetExeDir() string {
|
||||||
}
|
}
|
||||||
return filepath.Join(homeDir, "run", osType)
|
return filepath.Join(homeDir, "run", osType)
|
||||||
}
|
}
|
||||||
|
func GetStaticDir() string {
|
||||||
|
homeDir, err := GetAppDir()
|
||||||
|
if err != nil {
|
||||||
|
return "static"
|
||||||
|
}
|
||||||
|
staticPath := filepath.Join(homeDir, "static")
|
||||||
|
if !PathExists(staticPath) {
|
||||||
|
os.MkdirAll(staticPath, 0755)
|
||||||
|
}
|
||||||
|
return staticPath
|
||||||
|
}
|
||||||
|
func GetCacheDir() string {
|
||||||
|
homeDir, err := GetAppDir()
|
||||||
|
if err != nil {
|
||||||
|
return "cache"
|
||||||
|
}
|
||||||
|
cachePath := filepath.Join(homeDir, "cache")
|
||||||
|
if !PathExists(cachePath) {
|
||||||
|
os.MkdirAll(cachePath, 0755)
|
||||||
|
}
|
||||||
|
return cachePath
|
||||||
|
}
|
||||||
func PathExists(dir string) bool {
|
func PathExists(dir string) bool {
|
||||||
_, err := os.Stat(dir)
|
_, err := os.Stat(dir)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
30
godo/libs/msg.go
Normal file
30
godo/libs/msg.go
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
package libs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type APIResponse struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
Data any `json:"data,omitempty"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeJSONResponse(w http.ResponseWriter, res APIResponse, status int) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(status)
|
||||||
|
json.NewEncoder(w).Encode(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPError 返回带有JSON错误消息的HTTP错误
|
||||||
|
func HTTPError(w http.ResponseWriter, status int, message string) {
|
||||||
|
writeJSONResponse(w, APIResponse{Message: message, Code: -1}, status)
|
||||||
|
}
|
||||||
|
func ErrorMsg(w http.ResponseWriter, message string) {
|
||||||
|
writeJSONResponse(w, APIResponse{Message: message, Code: -1}, 200)
|
||||||
|
}
|
||||||
|
func SuccessMsg(w http.ResponseWriter, data any, message string) {
|
||||||
|
writeJSONResponse(w, APIResponse{Message: message, Data: data, Code: 0}, 200)
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package localchat
|
package localchat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"godoos/libs"
|
"godo/libs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -71,7 +71,7 @@ func SseHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
Message: time.Now().Format("2006-01-02 15:04:05"),
|
Message: time.Now().Format("2006-01-02 15:04:05"),
|
||||||
}
|
}
|
||||||
userList = append(userList, myMsg)
|
userList = append(userList, myMsg)
|
||||||
log.Printf("Online users: %v", OnlineUsers)
|
//log.Printf("Online users: %v", OnlineUsers)
|
||||||
for ip, info := range OnlineUsers {
|
for ip, info := range OnlineUsers {
|
||||||
if ip != myIP { // 确保不重复添加自己
|
if ip != myIP { // 确保不重复添加自己
|
||||||
userList = append(userList, info)
|
userList = append(userList, info)
|
||||||
|
|
@ -105,7 +105,7 @@ func HandleMessage(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
// 将消息放入messageChan
|
// 将消息放入messageChan
|
||||||
messageChan <- msg
|
messageChan <- msg
|
||||||
log.Printf("Received text message from %s: %s", msg.SenderInfo.IP, msg.Content)
|
//log.Printf("Received text message from %s: %s", msg.SenderInfo.IP, msg.Content)
|
||||||
// 这里可以添加存储文本消息到数据库或其他处理逻辑
|
// 这里可以添加存储文本消息到数据库或其他处理逻辑
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprintln(w, "Text message send successfully")
|
fmt.Fprintln(w, "Text message send successfully")
|
||||||
|
|
@ -56,6 +56,8 @@ var (
|
||||||
var uploadStatus = UploadStatus{Status: make(map[string]int)}
|
var uploadStatus = UploadStatus{Status: make(map[string]int)}
|
||||||
var broadcartTime = 3 * time.Second
|
var broadcartTime = 3 * time.Second
|
||||||
|
|
||||||
var broadcastAddr = "224.0.0.1:1679" // 多播地址
|
// var broadcastAddr = "224.0.0.1:1679" // 多播地址
|
||||||
|
var broadcastAddr = "224.0.0.251:1234"
|
||||||
|
|
||||||
// var broadcastAddr = "255.255.255.255:1769" // 广播地址
|
// var broadcastAddr = "255.255.255.255:1769" // 广播地址
|
||||||
var OnlineUsers = make(map[string]UdpMessage) // 全局map,key为IP,value为主机名
|
var OnlineUsers = make(map[string]UdpMessage) // 全局map,key为IP,value为主机名
|
||||||
|
|
@ -3,7 +3,7 @@ package localchat
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"godoos/libs"
|
"godo/libs"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -25,13 +25,6 @@ func StartServiceDiscovery() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
// 设置组播通信的网路接口
|
|
||||||
// intf,err := net.InterfaceByName("eth0")
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Println("Error getting network interface:", err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// conn.setMulticastInterface(intf)
|
|
||||||
|
|
||||||
buffer := make([]byte, 1024)
|
buffer := make([]byte, 1024)
|
||||||
for {
|
for {
|
||||||
7
godo/main.go
Normal file
7
godo/main.go
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "godo/cmd"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.OsStart()
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ package progress
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"godoos/libs"
|
"godo/libs"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -44,7 +44,7 @@ func StartProcess(w http.ResponseWriter, r *http.Request) {
|
||||||
func ExecuteStartAll() error {
|
func ExecuteStartAll() error {
|
||||||
log.Println("Starting all processes...")
|
log.Println("Starting all processes...")
|
||||||
|
|
||||||
userExeDir := libs.GetExeDir()
|
userExeDir := libs.GetRunDir()
|
||||||
|
|
||||||
userFis, err := os.ReadDir(userExeDir)
|
userFis, err := os.ReadDir(userExeDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -105,7 +105,7 @@ func ExecuteScript(name string) error {
|
||||||
binaryExt = ".exe"
|
binaryExt = ".exe"
|
||||||
}
|
}
|
||||||
scriptName := name + binaryExt
|
scriptName := name + binaryExt
|
||||||
exeDir := libs.GetExeDir() // 获取执行程序的目录
|
exeDir := libs.GetRunDir() // 获取执行程序的目录
|
||||||
scriptPath := filepath.Join(exeDir, name, scriptName) // 拼接脚本的完整路径
|
scriptPath := filepath.Join(exeDir, name, scriptName) // 拼接脚本的完整路径
|
||||||
// 检查脚本文件的存在性
|
// 检查脚本文件的存在性
|
||||||
if !PathExists(scriptPath) {
|
if !PathExists(scriptPath) {
|
||||||
159
godo/store/download.go
Normal file
159
godo/store/download.go
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"godo/libs"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cavaliergopher/grab/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DownloadStatus struct {
|
||||||
|
resp *grab.Response
|
||||||
|
cancel context.CancelFunc
|
||||||
|
Name string `json:"name"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
Current int64 `json:"current"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Speed float64 `json:"speed"`
|
||||||
|
Progress float64 `json:"progress"`
|
||||||
|
Downloading bool `json:"downloading"`
|
||||||
|
Done bool `json:"done"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
concurrency = 6 // 并发下载数
|
||||||
|
)
|
||||||
|
|
||||||
|
// var downloads = make(map[string]*grab.Response)
|
||||||
|
var downloadsMutex sync.Mutex
|
||||||
|
var downloadList map[string]*DownloadStatus
|
||||||
|
|
||||||
|
func existsInDownloadList(url string) bool {
|
||||||
|
_, ok := downloadList[url]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func PauseDownload(url string) {
|
||||||
|
downloadsMutex.Lock()
|
||||||
|
defer downloadsMutex.Unlock()
|
||||||
|
ds, ok := downloadList[url]
|
||||||
|
if ds.Url == url && ok {
|
||||||
|
if ds.cancel != nil {
|
||||||
|
ds.cancel()
|
||||||
|
}
|
||||||
|
ds.resp = nil
|
||||||
|
ds.Downloading = false
|
||||||
|
ds.Speed = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContinueDownload(url string) {
|
||||||
|
ds, ok := downloadList[url]
|
||||||
|
if ds.Url == url && ok {
|
||||||
|
if !ds.Downloading && ds.resp == nil && !ds.Done {
|
||||||
|
ds.Downloading = true
|
||||||
|
|
||||||
|
req, err := grab.NewRequest(ds.Path, ds.Url)
|
||||||
|
if err != nil {
|
||||||
|
ds.Downloading = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
ds.cancel = cancel
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
client := grab.NewClient()
|
||||||
|
client.HTTPClient = &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
MaxIdleConnsPerHost: concurrency, // 设置并发连接数
|
||||||
|
},
|
||||||
|
}
|
||||||
|
//resp := grab.DefaultClient.Do(req)
|
||||||
|
resp := client.Do(req)
|
||||||
|
|
||||||
|
if resp != nil && resp.HTTPResponse != nil &&
|
||||||
|
resp.HTTPResponse.StatusCode >= 200 && resp.HTTPResponse.StatusCode < 300 {
|
||||||
|
ds.resp = resp
|
||||||
|
} else {
|
||||||
|
ds.Downloading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Download(url string) {
|
||||||
|
chacheDir := libs.GetCacheDir()
|
||||||
|
absPath := filepath.Join(chacheDir, filepath.Base(url))
|
||||||
|
if !existsInDownloadList(url) {
|
||||||
|
downloadList[url] = &DownloadStatus{
|
||||||
|
resp: nil,
|
||||||
|
Name: filepath.Base(url),
|
||||||
|
Path: absPath,
|
||||||
|
Url: url,
|
||||||
|
Downloading: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ContinueDownload(url)
|
||||||
|
}
|
||||||
|
func GetDownload(url string) *DownloadStatus {
|
||||||
|
downloadsMutex.Lock()
|
||||||
|
defer downloadsMutex.Unlock()
|
||||||
|
ds, ok := downloadList[url]
|
||||||
|
if ds.resp != nil && ok {
|
||||||
|
ds.Current = ds.resp.BytesComplete()
|
||||||
|
ds.Size = ds.resp.Size()
|
||||||
|
ds.Speed = ds.resp.BytesPerSecond()
|
||||||
|
ds.Progress = 100 * ds.resp.Progress()
|
||||||
|
ds.Downloading = !ds.resp.IsComplete()
|
||||||
|
ds.Done = ds.resp.Progress() == 1
|
||||||
|
if !ds.Downloading {
|
||||||
|
ds.resp = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ds.Done {
|
||||||
|
delete(downloadList, url)
|
||||||
|
}
|
||||||
|
return ds
|
||||||
|
}
|
||||||
|
func DownloadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
url := r.URL.Query().Get("url")
|
||||||
|
Download(url)
|
||||||
|
ticker := time.NewTicker(500 * time.Millisecond)
|
||||||
|
defer ticker.Stop()
|
||||||
|
flusher, ok := w.(http.Flusher)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("Streaming unsupported")
|
||||||
|
http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
<-ticker.C
|
||||||
|
ds := GetDownload(url)
|
||||||
|
jsonBytes, err := json.Marshal(ds)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error marshaling FileProgress to JSON: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if w != nil {
|
||||||
|
io.WriteString(w, string(jsonBytes))
|
||||||
|
w.Write([]byte("\n"))
|
||||||
|
flusher.Flush()
|
||||||
|
} else {
|
||||||
|
log.Println("ResponseWriter is nil, cannot send progress")
|
||||||
|
}
|
||||||
|
if ds.Done {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
3
plugins/clock/README.md
Normal file
3
plugins/clock/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# 番茄钟
|
||||||
|
|
||||||
|
- godoos应用商店Demo
|
||||||
BIN
plugins/clock/frontend/audio/rest.mp3
Normal file
BIN
plugins/clock/frontend/audio/rest.mp3
Normal file
Binary file not shown.
BIN
plugins/clock/frontend/audio/tick.mp3
Normal file
BIN
plugins/clock/frontend/audio/tick.mp3
Normal file
Binary file not shown.
BIN
plugins/clock/frontend/audio/work.mp3
Normal file
BIN
plugins/clock/frontend/audio/work.mp3
Normal file
Binary file not shown.
BIN
plugins/clock/frontend/audio/work2.mp3
Normal file
BIN
plugins/clock/frontend/audio/work2.mp3
Normal file
Binary file not shown.
206
plugins/clock/frontend/css/index.css
Normal file
206
plugins/clock/frontend/css/index.css
Normal file
|
|
@ -0,0 +1,206 @@
|
||||||
|
|
||||||
|
/* 设置字体 */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'lcd';
|
||||||
|
src: url('../font/lcd.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'icon';
|
||||||
|
src: url('../font/iconfont.ttf') format('truetype');
|
||||||
|
}
|
||||||
|
/*css 初始化 */
|
||||||
|
html, body, ul, li, ol, dl, dd, dt, p, h1, h2, h3, h4, h5, h6, form, fieldset, legend, img { margin:0; padding:0; }
|
||||||
|
fieldset, img,input,button { font-family:"Times New Roman","Microsoft YaHei","SimSun"; ;border:none; padding:0;margin:0;outline-style:none; } /*去掉边框、去掉轮廓(比如输入框外面的蓝边框)*/
|
||||||
|
/*去掉列表前面的圆点*/
|
||||||
|
ul, ol {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
/* 设置隐藏 */
|
||||||
|
.none {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
/* 设置版心并居中 */
|
||||||
|
.w {
|
||||||
|
position: absolute;
|
||||||
|
top:50%;
|
||||||
|
left:50%;
|
||||||
|
transform: translate(-50%,-50%);
|
||||||
|
width: 95vw;
|
||||||
|
}
|
||||||
|
/* 设置字体 */
|
||||||
|
.iconfont {
|
||||||
|
font-family:"icon" !important;
|
||||||
|
font-style:normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-webkit-text-stroke-width: 0.2px;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
#n1,#n2,#n4,#n5{
|
||||||
|
width: 23%;
|
||||||
|
}
|
||||||
|
#n3 {
|
||||||
|
width: 8%;
|
||||||
|
transform: translate(20%,-25%);
|
||||||
|
}
|
||||||
|
.lcd {
|
||||||
|
font-family:"lcd" !important;
|
||||||
|
font-size:45vw;font-style:normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-webkit-text-stroke-width: 0.2px;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
/* 帮助界面 */
|
||||||
|
.p0 {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 14vw;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: -7vw;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
font-size: 4vw;
|
||||||
|
}
|
||||||
|
.tip {
|
||||||
|
border: 1px solid #999;
|
||||||
|
}
|
||||||
|
.p0 p {
|
||||||
|
margin: 2vw 0 ;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 3vw;
|
||||||
|
}
|
||||||
|
/* 开始第一页 */
|
||||||
|
.top {
|
||||||
|
position: relative;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
.top div{
|
||||||
|
width: 33.3%;
|
||||||
|
font-size: 3vw;
|
||||||
|
}
|
||||||
|
.top-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.top-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.top-right {
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.footer div{
|
||||||
|
width: 33.3%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
margin: 1.5vw 0 2.5vw;
|
||||||
|
padding: 1vw 3vw;
|
||||||
|
border-top: 1px solid black;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 开始第二页 */
|
||||||
|
ol {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 50vw;
|
||||||
|
}
|
||||||
|
ol li {
|
||||||
|
text-align: center;
|
||||||
|
line-height: 7.4vw;
|
||||||
|
font-size: 4vw;
|
||||||
|
border-bottom: 1px solid #e1e1e1;
|
||||||
|
}
|
||||||
|
ol li:nth-last-child(1){
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 开始第三页 */
|
||||||
|
.p3 {
|
||||||
|
font-size: 4vw;
|
||||||
|
padding: 0 20%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
button{
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid black;
|
||||||
|
font-size: 4vw;
|
||||||
|
padding: 0.2vw 0.7vw;
|
||||||
|
}
|
||||||
|
.line1,.line2 {
|
||||||
|
margin: 5vw auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.line1 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.p3 input{
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 4vw;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.p3-main span{
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.p3-bottom {
|
||||||
|
padding: 0 2vw;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.p3-bottom button{
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
/* 第四页 */
|
||||||
|
.p4 {
|
||||||
|
font-size: 4vw;
|
||||||
|
padding: 0 20%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p4 input{
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 4vw;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
.p4-main span{
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.p4-bottom {
|
||||||
|
padding: 0 2vw;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.p4-bottom button{
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
.p5 {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.p5 .back {
|
||||||
|
position: absolute;
|
||||||
|
right: 10%;
|
||||||
|
bottom: 2vw;
|
||||||
|
font-size: 2vw;
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 0.5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全屏 */
|
||||||
|
::backdrop {
|
||||||
|
z-index:0;
|
||||||
|
background-color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, *:fullscreen, *:-webkit-full-screen, *:-moz-full-screen {
|
||||||
|
background-color: white !important;
|
||||||
|
z-index:1;
|
||||||
|
}
|
||||||
BIN
plugins/clock/frontend/font/iconfont.ttf
Normal file
BIN
plugins/clock/frontend/font/iconfont.ttf
Normal file
Binary file not shown.
BIN
plugins/clock/frontend/font/lcd.ttf
Normal file
BIN
plugins/clock/frontend/font/lcd.ttf
Normal file
Binary file not shown.
BIN
plugins/clock/frontend/img/favicon.ico
Normal file
BIN
plugins/clock/frontend/img/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
105
plugins/clock/frontend/index.html
Normal file
105
plugins/clock/frontend/index.html
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh_CN" >
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
|
||||||
|
<title>番茄钟</title>
|
||||||
|
<link rel="stylesheet" href="css/index.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="js/NoSleep.min.js"></script>
|
||||||
|
<script src="js/jquery-3.6.0.min.js"></script>
|
||||||
|
<script src="js/echarts.min.js"></script>
|
||||||
|
<script src="js/tools.js"></script>
|
||||||
|
<script src="js/index.js"></script>
|
||||||
|
<!-- 版心 -->
|
||||||
|
<div class="w">
|
||||||
|
<!-- 帮助界面 -->
|
||||||
|
<div class="class page p0 ">
|
||||||
|
<h3>提示(点击进入主页)</h3>
|
||||||
|
<div class="tip">
|
||||||
|
<p>点击屏幕中间进入/退出全屏</p>
|
||||||
|
<p>点击左上角的番茄钟获取提示</p>
|
||||||
|
<p>点击中上角的时间电量切换钟表模式</p>
|
||||||
|
<p>点击右上角的已工作时间切换显示计划时间</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 第一页:主界面 -->
|
||||||
|
<div class="page p1 none">
|
||||||
|
<div class="top flex">
|
||||||
|
<!-- 顶部状态栏 -->
|
||||||
|
<div class="top-left iconfont">番茄钟</div>
|
||||||
|
<div class="top-center"><span class="now-time">00:00:00</span></div>
|
||||||
|
<div class="top-right">好好学习,天天向上</div>
|
||||||
|
</div>
|
||||||
|
<div class="main flex ">
|
||||||
|
<!-- 主要的时钟部分 -->
|
||||||
|
<div class="lcd" id="n1">4</div>
|
||||||
|
<div class="lcd" id="n2">5</div>
|
||||||
|
<div class="lcd" id="n3">:</div>
|
||||||
|
<div class="lcd" id="n4">0</div>
|
||||||
|
<div class="lcd" id="n5">0</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer flex">
|
||||||
|
<!-- 底部 -->
|
||||||
|
<div class="footer-left play iconfont"></div>
|
||||||
|
<div class="footer-center reset iconfont"></div>
|
||||||
|
<div class="footer-right setting iconfont"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 第二页:设置界面 -->
|
||||||
|
<div class="page p2 none">
|
||||||
|
<ol>
|
||||||
|
<li class="option">设置工作/休息时间</li>
|
||||||
|
<li class="option">设置计划倒计时</li>
|
||||||
|
<li class="option">查看工作历史</li>
|
||||||
|
<li class="option">清除本地数据</li>
|
||||||
|
<li class="option">返回</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
<!-- 第三页:设置工作/休息时间 -->
|
||||||
|
<div class="page p3 none">
|
||||||
|
<div class="p3-main">
|
||||||
|
<div class="line1">
|
||||||
|
<span>工作时间(分):</span>
|
||||||
|
<span><input type="text" name="study-time" id="input-study-time" value="45"></span>
|
||||||
|
</div>
|
||||||
|
<div class="line2">
|
||||||
|
<span>休息时间(分):</span>
|
||||||
|
<span ><input type="text" name="rest-time" id="input-rest-time" value="5"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p3-bottom">
|
||||||
|
<button>应用</button>
|
||||||
|
<button>返回</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 第四页:设置计划倒计时 -->
|
||||||
|
<div class="page p4 none">
|
||||||
|
<div class="p4-main">
|
||||||
|
<div class="line1">
|
||||||
|
<span>计划名称:</span>
|
||||||
|
<span><input type="text" name="plan-name" id="input-plan-name" value=""></span>
|
||||||
|
</div>
|
||||||
|
<div class="line2">
|
||||||
|
<span>截止日期:</span>
|
||||||
|
<span ><input type="text" name="plan-time" id="input-plan-time" value="2021/12/31"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p4-bottom">
|
||||||
|
<button>应用</button>
|
||||||
|
<button>返回</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 第五页:展示历史工作时间 -->
|
||||||
|
<div class="page p5 none ">
|
||||||
|
<div id="echarts" style="width:85vw;height: 50vw; margin: 0 auto;">
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
2
plugins/clock/frontend/js/NoSleep.min.js
vendored
Normal file
2
plugins/clock/frontend/js/NoSleep.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
45
plugins/clock/frontend/js/echarts.min.js
vendored
Normal file
45
plugins/clock/frontend/js/echarts.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
182
plugins/clock/frontend/js/index.js
Normal file
182
plugins/clock/frontend/js/index.js
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
|
||||||
|
|
||||||
|
// 入口函数
|
||||||
|
$(()=>{
|
||||||
|
let myChart ;
|
||||||
|
let isFullScreen = false;
|
||||||
|
//屏幕常量!
|
||||||
|
let noSleep = new NoSleep();
|
||||||
|
let playSound = (src) => {
|
||||||
|
au = document.createElement("audio");
|
||||||
|
au.preload="auto";
|
||||||
|
au.src = '/admin/tools/clock/audio/' + src + '.mp3';
|
||||||
|
au.play();
|
||||||
|
}
|
||||||
|
//绑定事件
|
||||||
|
// 全屏
|
||||||
|
$(".main").on("click",()=>{
|
||||||
|
if(isFullScreen){
|
||||||
|
document.exitFullscreen();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
document.body.requestFullscreen();
|
||||||
|
}
|
||||||
|
isFullScreen = !isFullScreen;
|
||||||
|
});
|
||||||
|
//绑定提示取消
|
||||||
|
$(".p0").on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p1").show();
|
||||||
|
noSleep.enable();
|
||||||
|
});
|
||||||
|
$(".top-left").on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p0").show();
|
||||||
|
});
|
||||||
|
//切换工作时间/计划倒计时
|
||||||
|
$(".top-right").on("click",()=>{
|
||||||
|
isShowPlan = !isShowPlan;
|
||||||
|
});
|
||||||
|
//切换时钟
|
||||||
|
$(".top-center").on("click",()=>{
|
||||||
|
isClock = !isClock;
|
||||||
|
showNowTime();
|
||||||
|
});
|
||||||
|
//播放按钮
|
||||||
|
$(".play").on("click",()=>{
|
||||||
|
//如果没播放并且在休息,按两下直接开始工作
|
||||||
|
if (!isPlay && isRest){
|
||||||
|
res_time = t_study;
|
||||||
|
isRest = false;
|
||||||
|
}
|
||||||
|
if (!isPlay){
|
||||||
|
$(".play").html(icon_stop);
|
||||||
|
playSound('tick');
|
||||||
|
}
|
||||||
|
if (isPlay){
|
||||||
|
$(".play").html(icon_play);
|
||||||
|
}
|
||||||
|
|
||||||
|
isPlay = !isPlay;
|
||||||
|
});
|
||||||
|
//重置时间
|
||||||
|
$(".reset").on("click",()=>{
|
||||||
|
if (isRest){
|
||||||
|
res_time = t_rest ;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res_time = t_study ;
|
||||||
|
}
|
||||||
|
showRestTime();
|
||||||
|
});
|
||||||
|
//设置
|
||||||
|
$(".setting").on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p2").show();
|
||||||
|
});
|
||||||
|
//设置工作/休息时间
|
||||||
|
$(".p2 .option").eq(0).on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p3").show();
|
||||||
|
});
|
||||||
|
//设置计划倒计时
|
||||||
|
$(".p2 .option").eq(1).on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p4").show();
|
||||||
|
});
|
||||||
|
//查看工作历史
|
||||||
|
$(".p2 .option").eq(2).on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p5").show();
|
||||||
|
myChart = showEcharts();
|
||||||
|
});
|
||||||
|
//清除本地数据
|
||||||
|
$(".p2 .option").eq(3).on("click",()=>{
|
||||||
|
window.localStorage.clear();
|
||||||
|
localData = [];
|
||||||
|
|
||||||
|
|
||||||
|
alert("已清除!");
|
||||||
|
});
|
||||||
|
//返回
|
||||||
|
$(".p2 .option").eq(4).on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p1").show();
|
||||||
|
});
|
||||||
|
//第三页设置工作/休息时间
|
||||||
|
$(".p3-bottom button").eq(0).on("click",()=>{
|
||||||
|
t_study = $(".p3 input").eq(0).val() * 60;
|
||||||
|
t_rest = $(".p3 input").eq(1).val() * 60;
|
||||||
|
if(isRest){
|
||||||
|
res_time = t_rest;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res_time = t_study;
|
||||||
|
}
|
||||||
|
showRestTime();
|
||||||
|
saveSetting();
|
||||||
|
// alert("完成!");
|
||||||
|
// console.log(t_study);
|
||||||
|
});
|
||||||
|
$(".p3-bottom button").eq(1).on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p2").show();
|
||||||
|
});
|
||||||
|
//第四页 设置计划倒计时
|
||||||
|
$(".p4-bottom button").eq(0).on("click",()=>{
|
||||||
|
plan_name = $(".p4 input").eq(0).val();
|
||||||
|
plan_time = $(".p4 input").eq(1).val() + " " + "08:00:00";
|
||||||
|
if(isShowPlan){
|
||||||
|
showPlan();
|
||||||
|
}
|
||||||
|
saveSetting();
|
||||||
|
// alert("完成!");
|
||||||
|
// console.log(plan_name);
|
||||||
|
});
|
||||||
|
$(".p4-bottom button").eq(1).on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p2").show();
|
||||||
|
});
|
||||||
|
//第五页返回
|
||||||
|
$(".p5").on("click",()=>{
|
||||||
|
$(".page").hide();
|
||||||
|
$(".p2").show();
|
||||||
|
myChart.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//开始初始化,设置计时器
|
||||||
|
|
||||||
|
loadLocalData();
|
||||||
|
|
||||||
|
setInterval(()=>{
|
||||||
|
showTopBar();
|
||||||
|
//如果倒计时归零
|
||||||
|
if(!res_time){
|
||||||
|
isRest = !isRest;
|
||||||
|
//该休息了
|
||||||
|
if(isRest){
|
||||||
|
$(".top-left").html(icon_rest+"休息中");
|
||||||
|
playSound('rest');
|
||||||
|
res_time = t_rest;
|
||||||
|
}
|
||||||
|
//该工作了
|
||||||
|
else{
|
||||||
|
$(".top-left").html(icon_study+"工作中");
|
||||||
|
playSound('work');
|
||||||
|
res_time = t_study;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//如果在播放
|
||||||
|
if (isPlay && !isClock){
|
||||||
|
if(!isRest){
|
||||||
|
$(".top-left").html(icon_study+"工作中");
|
||||||
|
study_time++;
|
||||||
|
}
|
||||||
|
res_time--;
|
||||||
|
saveStudyTime();
|
||||||
|
showRestTime();
|
||||||
|
}
|
||||||
|
},1000);
|
||||||
|
});
|
||||||
2
plugins/clock/frontend/js/jquery-3.6.0.min.js
vendored
Normal file
2
plugins/clock/frontend/js/jquery-3.6.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
304
plugins/clock/frontend/js/tools.js
Normal file
304
plugins/clock/frontend/js/tools.js
Normal file
|
|
@ -0,0 +1,304 @@
|
||||||
|
// 初始化变量和常量
|
||||||
|
const icon_play = "";
|
||||||
|
const icon_stop = "";
|
||||||
|
const icon_study = "";
|
||||||
|
const icon_rest = "";
|
||||||
|
let t_study = 45*60;
|
||||||
|
let t_rest = 5*60;
|
||||||
|
let plan_name = "godo发布";
|
||||||
|
let plan_time = "2021/12/31 18:00:00";
|
||||||
|
let isPlay = false;
|
||||||
|
let isRest = false;
|
||||||
|
let isShowPlan = false;
|
||||||
|
let isClock = false;
|
||||||
|
let localData = {};
|
||||||
|
let today = null;
|
||||||
|
let res_time = t_study;
|
||||||
|
let study_time = 0;
|
||||||
|
//获取现在的日期并返回
|
||||||
|
function getToday(){
|
||||||
|
let t = new Date();
|
||||||
|
let day = t.getDate();
|
||||||
|
let month = t.getMonth() +1 ;
|
||||||
|
let year = t.getFullYear();
|
||||||
|
let tmp = year +
|
||||||
|
(month < 10 ? "0" + month : month) +
|
||||||
|
(day < 10 ? "0" + day : day);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
//更新today变量为最新的当前日期
|
||||||
|
function updateToday(){
|
||||||
|
today = getToday();
|
||||||
|
}
|
||||||
|
|
||||||
|
//读取本地的存储,放到localDate对象中
|
||||||
|
function loadLocalData(){
|
||||||
|
updateToday();
|
||||||
|
//如果存在本地数据
|
||||||
|
if(window.localStorage && window.localStorage.length){
|
||||||
|
for (let i=0;i<window.localStorage.length;i++){
|
||||||
|
let date = window.localStorage.key(i);
|
||||||
|
let data = window.localStorage.getItem(date);
|
||||||
|
localData[date] = data;
|
||||||
|
}
|
||||||
|
//console.log('本地数据读取完成:'+JSON.stringify(localData));
|
||||||
|
//如果有今天的数据,那今天的工作时间叠加
|
||||||
|
if(localData[today]){
|
||||||
|
study_time+=localData[today];
|
||||||
|
}
|
||||||
|
if(localData['plan-name']){
|
||||||
|
plan_name = localData['plan-name'];
|
||||||
|
$(".p4 input").eq(0).val(plan_name);
|
||||||
|
}
|
||||||
|
if(localData['plan-time']){
|
||||||
|
plan_time = localData['plan-time'];
|
||||||
|
$(".p4 input").eq(1).val(plan_time.substr(0,10));
|
||||||
|
}
|
||||||
|
if(localData['t_rest']){
|
||||||
|
t_rest = localData['t_rest'];
|
||||||
|
$(".p3 input").eq(1).val(t_rest/60);
|
||||||
|
}
|
||||||
|
if(localData['t_study']){
|
||||||
|
t_study = localData['t_study'];
|
||||||
|
$(".p3 input").eq(0).val(t_study/60);
|
||||||
|
res_time = t_study;
|
||||||
|
showRestTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
study_time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//把剩余的秒数计算成四个要显示的数字并返回
|
||||||
|
function calTime(t){
|
||||||
|
let min = Math.floor(t/60);
|
||||||
|
let sec = t %60;
|
||||||
|
return [Math.floor(min/10) , min%10 , Math.floor(sec/10) , sec %10];
|
||||||
|
}
|
||||||
|
//更新计数器时间
|
||||||
|
function showRestTime(){
|
||||||
|
let arr = calTime(res_time);
|
||||||
|
$("#n1").text(arr[0]);
|
||||||
|
if(arr[0]==1){
|
||||||
|
$("#n1").css("transform","translate(30%)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#n1").css("transform","none");
|
||||||
|
}
|
||||||
|
$("#n2").text(arr[1]);
|
||||||
|
if(arr[1]==1){
|
||||||
|
$("#n2").css("transform","translate(30%)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#n2").css("transform","none");
|
||||||
|
}
|
||||||
|
$("#n4").text(arr[2]);
|
||||||
|
if(arr[2]==1){
|
||||||
|
$("#n4").css("transform","translate(30%)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#n4").css("transform","none");
|
||||||
|
}
|
||||||
|
$("#n5").text(arr[3]);
|
||||||
|
if(arr[3]==1){
|
||||||
|
$("#n5").css("transform","translate(30%)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#n5").css("transform","none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//更新现在的时间和电量
|
||||||
|
function showNowTime(){
|
||||||
|
let t = new Date();
|
||||||
|
let h = t.getHours();
|
||||||
|
h = h < 10 ? "0" + h : h;
|
||||||
|
let m = t.getMinutes();
|
||||||
|
m = m < 10 ? "0" + m : m;
|
||||||
|
let s = t.getSeconds();
|
||||||
|
s = s < 10 ? "0" + s : s;
|
||||||
|
if(navigator.getBattery){
|
||||||
|
navigator.getBattery().then((result)=>{
|
||||||
|
$(".now-time").text(h + ":" + m + ":" + s +" 电量:"+parseInt(result.level*100)+"%") ;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$(".now-time").text(h + ":" + m + ":" + s);
|
||||||
|
}
|
||||||
|
//是否开启钟表模式
|
||||||
|
if(isClock){
|
||||||
|
//console.log(h+m);
|
||||||
|
let arr = [h.toString()[0],h.toString()[1],m.toString()[0],m.toString()[1]]
|
||||||
|
$("#n1").text(arr[0]);
|
||||||
|
$("#n2").text(arr[1]);
|
||||||
|
$("#n4").text(arr[2]);
|
||||||
|
$("#n5").text(arr[3]);
|
||||||
|
if(arr[0]==1){
|
||||||
|
$("#n1").css("transform","translate(30%)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#n1").css("transform","none");
|
||||||
|
}
|
||||||
|
$("#n2").text(arr[1]);
|
||||||
|
if(arr[1]==1){
|
||||||
|
$("#n2").css("transform","translate(30%)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#n2").css("transform","none");
|
||||||
|
}
|
||||||
|
$("#n4").text(arr[2]);
|
||||||
|
if(arr[2]==1){
|
||||||
|
$("#n4").css("transform","translate(30%)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#n4").css("transform","none");
|
||||||
|
}
|
||||||
|
$("#n5").text(arr[3]);
|
||||||
|
if(arr[3]==1){
|
||||||
|
$("#n5").css("transform","translate(30%)");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$("#n5").css("transform","none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
showRestTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//更新计划倒计时
|
||||||
|
function showPlan(){
|
||||||
|
let t = new Date();
|
||||||
|
let t0 = new Date(plan_time);
|
||||||
|
let ss = t0.getTime() - t.getTime();
|
||||||
|
let r_plan_days = parseInt(ss / 1000/60/60/24);
|
||||||
|
let r_plan_hours = parseInt((ss / 1000/60/60)%24);
|
||||||
|
$(".top-right").text("距" + plan_name+"还有:" + r_plan_days + "天" + r_plan_hours + "小时");
|
||||||
|
}
|
||||||
|
//存储工作时间
|
||||||
|
function saveStudyTime(){
|
||||||
|
console.log('存储数据');
|
||||||
|
if (getToday()!==today){
|
||||||
|
study_time = 0 ;
|
||||||
|
updateToday();
|
||||||
|
}
|
||||||
|
localData[today]=study_time.toFixed(2);
|
||||||
|
window.localStorage.setItem(today,study_time);
|
||||||
|
}
|
||||||
|
//更新今天已工作时间
|
||||||
|
function showStudyTime(){
|
||||||
|
$(".top-right").text("今天已工作:" +
|
||||||
|
String(Math.floor(study_time / 60)) +
|
||||||
|
"分钟" +
|
||||||
|
String(study_time % 60) +
|
||||||
|
"秒");
|
||||||
|
}
|
||||||
|
|
||||||
|
//更新最上面一栏
|
||||||
|
function showTopBar(){
|
||||||
|
showNowTime();
|
||||||
|
if(isShowPlan){
|
||||||
|
showPlan();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
showStudyTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//保存数据
|
||||||
|
function saveSetting (){
|
||||||
|
localData['plan-name'] = plan_name;
|
||||||
|
localData['plan-time'] = plan_name;
|
||||||
|
localData['t_study'] = t_study;
|
||||||
|
localData['t_rest'] = t_rest;
|
||||||
|
window.localStorage.setItem('plan-name',plan_name);
|
||||||
|
window.localStorage.setItem('plan-time',plan_time);
|
||||||
|
window.localStorage.setItem('t_study',t_study);
|
||||||
|
window.localStorage.setItem('t_rest',t_rest);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//展示图表
|
||||||
|
function showEcharts(){
|
||||||
|
//console.log("缓存数据:"+ window.localStorage);
|
||||||
|
//console.log('localData'+localData);
|
||||||
|
let myChart = echarts.init(document.getElementById('echarts'));
|
||||||
|
let dateArr = [];
|
||||||
|
let timeArr = [];
|
||||||
|
let re = /^20[0-9]{2}/;
|
||||||
|
for (let i in localData){
|
||||||
|
if(re.test(i)){
|
||||||
|
timeArr.push((localData[i]/60).toFixed(2));
|
||||||
|
//处理原来的数据
|
||||||
|
let re1 = /^0/;
|
||||||
|
if (re1.test(i.substr(4,4))){
|
||||||
|
dateArr.push(i[5]+'/'+i[6]+i[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//处理数据补0
|
||||||
|
if (dateArr.length<4){
|
||||||
|
let n = 4 - dateArr.length;
|
||||||
|
if (dateArr.length==0){
|
||||||
|
let t = new Date();
|
||||||
|
t = t.getMonth()+1 + '/'+t.getDate();
|
||||||
|
dateArr.push(t);
|
||||||
|
timeArr.push(0);
|
||||||
|
}
|
||||||
|
for (let j=0;j<n;j++){
|
||||||
|
let t = new Date();
|
||||||
|
t=t.setDate(t.getDate()+j+1);
|
||||||
|
t = new Date(t);
|
||||||
|
dateArr.push(t.getMonth()+1+'/'+t.getDate());
|
||||||
|
timeArr.push(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// console.log(dateArr);
|
||||||
|
// console.log(timeArr);
|
||||||
|
let option = {
|
||||||
|
title: {
|
||||||
|
text: '工作记录',
|
||||||
|
subtext: '任意点击返回',
|
||||||
|
subtextStyle: {
|
||||||
|
align: 'right'
|
||||||
|
},
|
||||||
|
left: 'center',
|
||||||
|
icon : 'none',
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 26
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
xAxis: {
|
||||||
|
data: dateArr,
|
||||||
|
name: '日期'
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
name: '工作时间/分钟',
|
||||||
|
max: function(value){
|
||||||
|
return value.max<30?30:value.max;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: '时间(分)',
|
||||||
|
type: 'bar',
|
||||||
|
data: timeArr,
|
||||||
|
barMaxWidth: '40%',
|
||||||
|
itemStyle:{
|
||||||
|
color: '#555',
|
||||||
|
normal: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'top',
|
||||||
|
formatter: '{c}分钟'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
myChart.setOption(option);
|
||||||
|
return myChart;
|
||||||
|
}
|
||||||
18
plugins/clock/info.json
Normal file
18
plugins/clock/info.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "todo",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "todo worker",
|
||||||
|
"main": "frontend/index.html",
|
||||||
|
"icon":"",
|
||||||
|
"position":["desktop","magnet"],
|
||||||
|
"width":800,
|
||||||
|
"height":600,
|
||||||
|
"usetype":["person","member","compony"],
|
||||||
|
"category":["work","life","productivity"],
|
||||||
|
"releases":[""],
|
||||||
|
"platform": "any",
|
||||||
|
"arch": "any",
|
||||||
|
"author": "aiok",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {}
|
||||||
|
}
|
||||||
10
plugins/serverAndFront/info.json
Normal file
10
plugins/serverAndFront/info.json
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"name" : "godoos",
|
||||||
|
"version" : "0.0.1",
|
||||||
|
"description" : "godoos",
|
||||||
|
"main" : "frontend",
|
||||||
|
"platform" : ["windows","darwin","linux"],
|
||||||
|
"author" : "aiok",
|
||||||
|
"license" : "MIT",
|
||||||
|
"dependencies" : {}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue