Replies: 19 comments 4 replies
-
| 关于启动器的想法,主要是整理一些常用的资源,提供对应的下载和访问链接,并且兼具启动软件的功能 | 
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
| 一个不错的GPT的c++提问模板:  | 
Beta Was this translation helpful? Give feedback.
-
| 后端应该弃用Carbon(Chaiscript),目前没有能力维护如此复杂的脚本,而且运行效率和编译速度太糟糕了。改为使用pocketpy和atomscript | 
Beta Was this translation helpful? Give feedback.
        
          
            
              This comment has been hidden.
            
          
            
        
      
    
            
              This comment has been hidden.
            
          
            
        
        
          
            
              This comment has been hidden.
            
          
            
        
      
    
            
              This comment has been hidden.
            
          
            
        
        
          
            
              This comment has been hidden.
            
          
            
        
      
    
            
              This comment has been hidden.
            
          
            
        
        
          
            
              This comment has been hidden.
            
          
            
        
      
    
            
              This comment has been hidden.
            
          
            
        
        
          
            
              This comment has been hidden.
            
          
            
        
      
    
            
              This comment has been hidden.
            
          
            
        
        
          
            
              This comment has been hidden.
            
          
            
        
      
    
            
              This comment has been hidden.
            
          
            
        -
| 对基于FFI的DLL封装的简化,即使封装到ModuleLoader中 #include <iostream>
#include <string>
#include <stdexcept>
#include <functional>
#include <memory>
// Determine the platform
#if defined(_WIN32) || defined(_WIN64)
#define PLATFORM_WINDOWS
#include <windows.h>
#elif defined(__linux__)
#define PLATFORM_LINUX
#include <dlfcn.h>
#elif defined(__APPLE__)
#define PLATFORM_MACOS
#include <dlfcn.h>
#endif
class DynamicLibrary {
public:
    explicit DynamicLibrary(const std::string& dllName) {
#ifdef PLATFORM_WINDOWS
        hModule = LoadLibraryA(dllName.c_str());
        if (!hModule) {
            std::cerr << "Failed to load the DLL: " << dllName << std::endl;
            throw std::runtime_error("Failed to load the DLL");
        }
#else
        hModule = dlopen(dllName.c_str(), RTLD_LAZY);
        if (!hModule) {
            std::cerr << "Failed to load the shared library: " << dllName << std::endl;
            throw std::runtime_error("Failed to load the shared library");
        }
#endif
        std::cout << "Library loaded successfully: " << dllName << std::endl;
    }
    ~DynamicLibrary() {
#ifdef PLATFORM_WINDOWS
        if (hModule) {
            FreeLibrary(static_cast<HMODULE>(hModule));
            std::cout << "DLL unloaded successfully." << std::endl;
        }
#else
        if (hModule) {
            dlclose(hModule);
            std::cout << "Shared library unloaded successfully." << std::endl;
        }
#endif
    }
    // Function to get a function pointer of any type using template and variadic arguments
    template <typename Func>
    std::function<Func> getFunction(const std::string& funcName) {
#ifdef PLATFORM_WINDOWS
        FARPROC proc = GetProcAddress(static_cast<HMODULE>(hModule), funcName.c_str());
#else
        void* proc = dlsym(hModule, funcName.c_str());
#endif
        if (!proc) {
            std::cerr << "Failed to get the function address: " << funcName << std::endl;
            throw std::runtime_error("Failed to get the function address");
        }
        std::cout << "Function loaded successfully: " << funcName << std::endl;
        // We use std::function to wrap the raw function pointer.
        return std::function<Func>(reinterpret_cast<Func*>(proc));
    }
private:
#ifdef PLATFORM_WINDOWS
    HMODULE hModule = nullptr;
#else
    void* hModule = nullptr;
#endif
};
// Example usage
int main() {
    try {
        // Adjust the library name based on the platform
#ifdef PLATFORM_WINDOWS
        DynamicLibrary lib("example.dll");
#elif defined(PLATFORM_LINUX)
        DynamicLibrary lib("./libexample.so");
#elif defined(PLATFORM_MACOS)
        DynamicLibrary lib("./libexample.dylib");
#endif
        // Define the function signature using auto and std::function
        auto add = lib.getFunction<int(int, int)>("add");
        auto subtract = lib.getFunction<int(int, int)>("subtract");
        // Call the functions
        std::cout << "add(5, 3): " << add(5, 3) << std::endl;
        std::cout << "subtract(5, 3): " << subtract(5, 3) << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "An error occurred: " << e.what() << std::endl;
        return 1;
    }
    return 0;
} | 
Beta Was this translation helpful? Give feedback.
-
| 很多时候,还没想好就干的效率是很低的 | 
Beta Was this translation helpful? Give feedback.
-
| PHD2和TCP2WS的python实现 import asyncio
import json
import subprocess
import signal
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException, Depends
from loguru import logger
from typing import List, Optional
import uvicorn
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from fastapi.responses import FileResponse
# 初始化FastAPI应用
app = FastAPI()
security = HTTPBasic()
# 配置loguru日志记录
logger.add("server.log", rotation="1 MB")
# 全局变量存储PHD2进程
phd2_process: Optional[asyncio.subprocess.Process] = None
# 模拟用户验证(实际应用中应使用数据库或其他方式)
def verify_credentials(credentials: HTTPBasicCredentials):
    if credentials.username == "admin" and credentials.password == "secret":
        return True
    else:
        raise HTTPException(status_code=401, detail="Unauthorized")
# 连接管理器类,管理多个WebSocket客户端
class ConnectionManager:
    def __init__(self):
        self.active_connections: List[WebSocket] = []
    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)
        logger.info(f"Client connected: {websocket.client}")
    def disconnect(self, websocket: WebSocket):
        self.active_connections.remove(websocket)
        logger.info(f"Client disconnected: {websocket.client}")
    async def broadcast(self, message: str):
        for connection in self.active_connections:
            await connection.send_text(message)
manager = ConnectionManager()
async def tcp_client_handler(tcp_reader, tcp_writer, websocket: WebSocket):
    try:
        while True:
            data = await tcp_reader.read(100)
            if not data:
                break
            await websocket.send_bytes(data)
    except Exception as e:
        logger.error(f"TCP client handler exception: {e}")
    finally:
        tcp_writer.close()
        await tcp_writer.wait_closed()
async def handle_phd2_messages(message: dict):
    # 在这里处理PHD2特定的消息
    if message.get('Event') == 'GuideStep':
        logger.info(f"PHD2 GuideStep event: {message}")
    elif message.get('Event') == 'StartGuiding':
        logger.info("PHD2 StartGuiding event")
    elif message.get('Event') == 'StopGuiding':
        logger.info("PHD2 StopGuiding event")
async def handle_websocket(websocket: WebSocket):
    await manager.connect(websocket)
    while True:
        try:
            tcp_reader, tcp_writer = await asyncio.wait_for(
                asyncio.open_connection('localhost', 4400), timeout=5.0)
            break
        except (asyncio.TimeoutError, ConnectionRefusedError) as e:
            logger.error(f"Failed to connect to TCP server: {e}")
            await asyncio.sleep(5)  # Wait before retrying
    try:
        asyncio.create_task(tcp_client_handler(tcp_reader, tcp_writer, websocket))
        while True:
            data = await asyncio.wait_for(websocket.receive_text(), timeout=30.0)
            message = json.loads(data)
            logger.info(f"Received message from {websocket.client}: {message}")
            await handle_phd2_messages(message)
            tcp_writer.write(json.dumps(message).encode('utf-8'))
            await tcp_writer.drain()
    except asyncio.TimeoutError:
        logger.warning(f"WebSocket connection timed out: {websocket.client}")
    except WebSocketDisconnect:
        logger.info(f"WebSocket disconnected: {websocket.client}")
    except Exception as e:
        logger.error(f"WebSocket exception: {e}")
    finally:
        manager.disconnect(websocket)
        tcp_writer.close()
        await tcp_writer.wait_closed()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await handle_websocket(websocket)
async def start_phd2():
    logger.info("Starting PHD2 process...")
    process = await asyncio.create_subprocess_exec(
        'phd2', '--server', 'localhost:4400',
        stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
    logger.info(f"PHD2 started with PID: {process.pid}")
    return process
async def monitor_phd2(process):
    try:
        while True:
            return_code = await process.wait()
            if return_code is not None:
                logger.error(f"PHD2 process exited with code {return_code}. Restarting...")
                process = await start_phd2()
            await asyncio.sleep(5)
    except asyncio.CancelledError:
        process.terminate()
        await process.wait()
        logger.info("PHD2 process terminated.")
@app.on_event("startup")
async def startup_event():
    global phd2_process
    phd2_process = await start_phd2()
    asyncio.ensure_future(monitor_phd2(phd2_process))
@app.on_event("shutdown")
async def shutdown_event():
    global phd2_process
    phd2_process.terminate()
    await phd2_process.wait()
    logger.info("PHD2 process terminated on shutdown.")
@app.get("/phd2/status")
async def get_phd2_status(credentials: HTTPBasicCredentials = Depends(security)):
    verify_credentials(credentials)
    global phd2_process
    if phd2_process is None or phd2_process.returncode is not None:
        raise HTTPException(status_code=503, detail="PHD2 is not running")
    # 这里可以添加更多PHD2内部状态的获取逻辑
    return {"status": "running", "pid": phd2_process.pid}
@app.post("/phd2/start")
async def start_phd2_endpoint(credentials: HTTPBasicCredentials = Depends(security)):
    verify_credentials(credentials)
    global phd2_process
    if phd2_process is not None and phd2_process.returncode is None:
        raise HTTPException(status_code=400, detail="PHD2 is already running")
    phd2_process = await start_phd2()
    asyncio.ensure_future(monitor_phd2(phd2_process))
    return {"status": "started", "pid": phd2_process.pid}
@app.post("/phd2/stop")
async def stop_phd2_endpoint(credentials: HTTPBasicCredentials = Depends(security)):
    verify_credentials(credentials)
    global phd2_process
    if phd2_process is None or phd2_process.returncode is not None:
        raise HTTPException(status_code=400, detail="PHD2 is not running")
    phd2_process.terminate()
    await phd2_process.wait()
    return {"status": "stopped"}
@app.post("/phd2/restart")
async def restart_phd2_endpoint(credentials: HTTPBasicCredentials = Depends(security)):
    verify_credentials(credentials)
    global phd2_process
    if phd2_process is not None and phd2_process.returncode is None:
        phd2_process.terminate()
        await phd2_process.wait()
    phd2_process = await start_phd2()
    asyncio.ensure_future(monitor_phd2(phd2_process))
    return {"status": "restarted", "pid": phd2_process.pid}
@app.get("/logs")
async def get_logs(credentials: HTTPBasicCredentials = Depends(security)):
    verify_credentials(credentials)
    return FileResponse("server.log")
@app.post("/phd2/config")
async def set_phd2_config(config: dict, credentials: HTTPBasicCredentials = Depends(security)):
    verify_credentials(credentials)
    with open("phd2_config.json", "w") as f:
        json.dump(config, f)
    return {"status": "config updated"}
@app.get("/phd2/config")
async def get_phd2_config(credentials: HTTPBasicCredentials = Depends(security)):
    verify_credentials(credentials)
    try:
        with open("phd2_config.json", "r") as f:
            config = json.load(f)
        return config
    except FileNotFoundError:
        raise HTTPException(status_code=404, detail="Config file not found")
if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000) | 
Beta Was this translation helpful? Give feedback.
-
| ini与json的相互转化 import configparser
import json
from typing import Dict, Any
def ini_to_dict(ini_file: str) -> Dict[str, Any]:
    config = configparser.ConfigParser()
    config.read(ini_file)
    return {section: dict(config.items(section)) for section in config.sections()}
def dict_to_ini(data: Dict[str, Any], ini_file: str):
    config = configparser.ConfigParser()
    for section, params in data.items():
        config[section] = params
    with open(ini_file, 'w') as file:
        config.write(file)
def json_to_dict(json_file: str) -> Dict[str, Any]:
    with open(json_file, 'r') as file:
        return json.load(file)
def dict_to_json(data: Dict[str, Any], json_file: str):
    with open(json_file, 'w') as file:
        json.dump(data, file, indent=4)
def ini_to_json(ini_file: str, json_file: str):
    data = ini_to_dict(ini_file)
    dict_to_json(data, json_file)
def json_to_ini(json_file: str, ini_file: str):
    data = json_to_dict(json_file)
    dict_to_ini(data, ini_file)
# 示例用法
ini_to_json('example.ini', 'example_converted.json')
json_to_ini('example.json', 'example_converted.ini') | 
Beta Was this translation helpful? Give feedback.
-
| components/SearchBar.vue <template>
  <n-input v-model:value="searchQuery" placeholder="Search..." clearable @clear="onClear" @input="onInput" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  name: 'SearchBar',
  props: {
    searchQuery: {
      type: String,
      required: true
    }
  },
  emits: ['update:searchQuery'],
  methods: {
    onClear() {
      this.$emit('update:searchQuery', '');
    },
    onInput(value: string) {
      this.$emit('update:searchQuery', value);
    }
  }
});
</script>components/GroupMenu.vue <template>
  <n-menu :options="groupOptions" @update:value="onSelectGroup" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { MenuOption } from 'naive-ui';
export default defineComponent({
  name: 'GroupMenu',
  props: {
    groupOptions: {
      type: Array as () => MenuOption[],
      required: true
    },
    selectedGroup: {
      type: String,
      default: null
    }
  },
  emits: ['update:selectedGroup'],
  methods: {
    onSelectGroup(key: string) {
      this.$emit('update:selectedGroup', key);
    }
  }
});
</script>components/ConfigTable.vue components/ConfigModal.vue <template>
  <n-modal v-model:show="visible" title="Detail" size="large">
    <n-form :model="config" ref="formRef">
      <n-form-item label="Key">
        <n-input v-model:value="config.key" :readonly="isReadOnly" />
      </n-form-item>
      <n-form-item label="Value">
        <n-input v-model:value="config.value" />
      </n-form-item>
      <n-form-item label="Description">
        <n-input v-model:value="config.description" type="textarea" />
      </n-form-item>
    </n-form>
    <template #footer>
      <n-button @click="$emit('update:visible', false)">Close</n-button>
      <n-button type="primary" @click="onSave">Save</n-button>
    </template>
  </n-modal>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
interface ConfigItem {
  group: string;
  key: string;
  value: string;
  description: string;
}
export default defineComponent({
  name: 'ConfigModal',
  props: {
    visible: {
      type: Boolean,
      required: true
    },
    config: {
      type: Object as PropType<ConfigItem>,
      required: true
    },
    isReadOnly: {
      type: Boolean,
      default: true
    }
  },
  emits: ['update:visible', 'save'],
  methods: {
    onSave() {
      this.$emit('save', { ...this.config });
    }
  }
});
</script>App.vue <template>
  <n-layout>
    <n-layout-header>
      <search-bar v-model:searchQuery="searchQuery" />
    </n-layout-header>
    <n-layout>
      <n-layout-sider>
        <group-menu :groupOptions="groupOptions" v-model:selectedGroup="selectedGroup" />
      </n-layout-sider>
      <n-layout-content>
        <n-card>
          <n-button type="success" @click="addNewConfig">Add New</n-button>
          <n-button type="warning" @click="exportConfig">Export</n-button>
          <n-upload :on-change="importConfig" accept=".json">
            <n-button type="info">Import</n-button>
          </n-upload>
          <config-table :data="filteredData" @row-click="showDetailModal" @delete="deleteConfig">
            <template #action="{ row }">
              <n-button type="error" @click.stop="deleteConfig(row)">Delete</n-button>
            </template>
          </config-table>
          <config-modal v-model:visible="detailModalVisible" :config="selectedConfig" :isReadOnly="isReadOnly" @save="saveConfig" />
        </n-card>
      </n-layout-content>
    </n-layout>
  </n-layout>
</template>
<script lang="ts">
import { defineComponent, ref, reactive, computed } from 'vue';
import { useMessage } from 'naive-ui';
import SearchBar from './components/SearchBar.vue';
import GroupMenu from './components/GroupMenu.vue';
import ConfigTable from './components/ConfigTable.vue';
import ConfigModal from './components/ConfigModal.vue';
interface ConfigItem {
  group: string;
  key: string;
  value: string;
  description: string;
}
export default defineComponent({
  name: 'App',
  components: { SearchBar, GroupMenu, ConfigTable, ConfigModal },
  setup() {
    const message = useMessage();
    // Sample data
    const configData = reactive<ConfigItem[]>([
      { group: 'Group 1', key: 'Key1', value: 'Value1', description: 'Description for Key1' },
      { group: 'Group 1', key: 'Key2', value: 'Value2', description: 'Description for Key2' },
      { group: 'Group 2', key: 'Key3', value: 'Value3', description: 'Description for Key3' },
      { group: 'Group 2', key: 'Key4', value: 'Value4', description: 'Description for Key4' }
    ]);
    const searchQuery = ref('');
    const selectedGroup = ref<string | null>(null);
    const detailModalVisible = ref(false);
    const selectedConfig = reactive<Partial<ConfigItem>>({});
    const isReadOnly = ref(true);
    const groupOptions = computed(() => {
      const groups = [...new Set(configData.map(item => item.group))];
      return groups.map(group => ({ label: group, key: group }));
    });
    const filteredData = computed(() => {
      return configData.filter(item => {
        const matchesGroup = selectedGroup.value ? item.group === selectedGroup.value : true;
        const matchesQuery = item.key.toLowerCase().includes(searchQuery.value.toLowerCase()) || 
                             item.value.toLowerCase().includes(searchQuery.value.toLowerCase()) || 
                             item.description.toLowerCase().includes(searchQuery.value.toLowerCase());
        return matchesGroup && matchesQuery;
      });
    });
    const fetchConfigData = () => {
      // Fetch and update configData here based on searchQuery and selectedGroup
    };
    const selectGroup = (key: string) => {
      selectedGroup.value = key;
      fetchConfigData();
    };
    const showDetailModal = (row: ConfigItem) => {
      Object.assign(selectedConfig, row);
      detailModalVisible.value = true;
      isReadOnly.value = true;
    };
    const addNewConfig = () => {
      Object.assign(selectedConfig, { group: selectedGroup.value, key: '', value: '', description: '' });
      detailModalVisible.value = true;
      isReadOnly.value = false;
    };
    const saveConfig = (config: ConfigItem) => {
      const index = configData.findIndex(item => item.key === config.key);
      if (index !== -1) {
        Object.assign(configData[index], config);
      } else {
        configData.push(config);
      }
      message.success('Configuration saved successfully');
      detailModalVisible.value = false;
    };
    const deleteConfig = (row: ConfigItem) => {
      const index = configData.findIndex(item => item.key === row.key);
      if (index !== -1) {
        configData.splice(index, 1);
        message.success('Configuration deleted successfully');
      }
    };
    const exportConfig = () => {
      const dataStr = JSON.stringify(configData, null, 2);
      const blob = new Blob([dataStr], { type: 'application/json' });
      const url = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = 'config.json';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    };
    const importConfig = (file: File) => {
      const reader = new FileReader();
      reader.onload = (event: ProgressEvent<FileReader>) => {
        if (event.target && event.target.result) {
          const data = JSON.parse(event.target.result as string);
          data.forEach((item: ConfigItem) => {
            const index = configData.findIndex(existingItem => existingItem.key === item.key);
            if (index !== -1) {
              Object.assign(configData[index], item);
            } else {
              configData.push(item);
            }
          });
          message.success('Configuration imported successfully');
        }
      };
      reader.readAsText(file);
    };
    return {
      searchQuery,
      groupOptions,
      selectedGroup,
      columns,
      filteredData,
      detailModalVisible,
      selectedConfig,
      isReadOnly,
      fetchConfigData,
      selectGroup,
      showDetailModal,
      addNewConfig,
      saveConfig,
      deleteConfig,
      exportConfig,
      importConfig
    };
  }
});
</script>
<style>
body {
  margin: 0;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
</style> | 
Beta Was this translation helpful? Give feedback.
-
| INDIWebClone <template>
  <n-layout-header class="header">
    <n-space align="center" justify="space-between" style="width: 100%">
      <n-space align="center">
        <n-avatar size="medium" src="https://via.placeholder.com/40" />
        <n-h1>INDIWeb Clone</n-h1>
      </n-space>
      <n-space>
        <n-button type="primary">Login</n-button>
      </n-space>
    </n-space>
  </n-layout-header>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  name: 'Header'
});
</script>
<style scoped>
.header {
  background-color: #3eaf7c;
  color: white;
  padding: 0 20px;
}
</style>components/Sidebar.vue <template>
  <n-layout-sider bordered class="sidebar">
    <n-menu :options="menuOptions" @update:value="onSelect" />
  </n-layout-sider>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  name: 'Sidebar',
  emits: ['select'],
  data() {
    return {
      menuOptions: [
        { label: 'All Devices', key: 'all' },
        { label: 'Category 1', key: 'category1', children: [
            { label: 'Device 1', key: 'device1' },
            { label: 'Device 2', key: 'device2' }
          ] 
        },
        { label: 'Category 2', key: 'category2', children: [
            { label: 'Device 3', key: 'device3' },
            { label: 'Device 4', key: 'device4' }
          ] 
        }
      ]
    };
  },
  methods: {
    onSelect(key: string) {
      this.$emit('select', key);
    }
  }
});
</script>
<style scoped>
.sidebar {
  background-color: #f0f0f0;
  padding: 20px;
}
</style>components/DeviceList.vue <template>
  <n-card title="Device List" class="device-list">
    <n-list :bordered="false">
      <n-list-item v-for="device in devices" :key="device.id" @click="onSelect(device)">
        <n-avatar :src="device.icon" size="small" />
        <span>{{ device.name }}</span>
      </n-list-item>
    </n-list>
  </n-card>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  name: 'DeviceList',
  props: {
    devices: {
      type: Array,
      required: true
    }
  },
  emits: ['select'],
  methods: {
    onSelect(device: any) {
      this.$emit('select', device);
    }
  }
});
</script>
<style scoped>
.device-list {
  margin: 20px;
}
</style>components/DeviceControl.vue <template>
  <n-card v-if="device" title="Device Control" class="device-control">
    <n-form :model="deviceData" ref="formRef">
      <n-form-item label="Property 1">
        <n-input v-model:value="deviceData.property1" />
      </n-form-item>
      <n-form-item label="Property 2">
        <n-input v-model:value="deviceData.property2" />
      </n-form-item>
      <n-form-item label="Property 3">
        <n-input v-model:value="deviceData.property3" />
      </n-form-item>
      <n-form-item>
        <n-button type="primary" @click="saveDevice">Save</n-button>
      </n-form-item>
    </n-form>
  </n-card>
  <div v-else class="no-device">
    <n-empty description="No device selected." />
  </div>
</template>
<script lang="ts">
import { defineComponent, reactive, watch } from 'vue';
export default defineComponent({
  name: 'DeviceControl',
  props: {
    device: {
      type: Object,
      default: null
    }
  },
  setup(props) {
    const deviceData = reactive({
      property1: '',
      property2: '',
      property3: ''
    });
    watch(() => props.device, (newDevice) => {
      if (newDevice) {
        deviceData.property1 = newDevice.property1;
        deviceData.property2 = newDevice.property2;
        deviceData.property3 = newDevice.property3;
      }
    }, { immediate: true });
    const saveDevice = () => {
      console.log('Device data saved:', deviceData);
      // Here you can save the device data to the backend or perform any other action
    };
    return {
      deviceData,
      saveDevice
    };
  }
});
</script>
<style scoped>
.device-control {
  margin: 20px;
}
.no-device {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
}
</style>components/AddDeviceModal.vue <template>
  <n-modal v-model:show="visible" title="Add Device" size="large">
    <n-form :model="deviceData" ref="formRef">
      <n-form-item label="Name">
        <n-input v-model:value="deviceData.name" />
      </n-form-item>
      <n-form-item label="Category">
        <n-select v-model:value="deviceData.category" :options="categoryOptions" />
      </n-form-item>
      <n-form-item label="Property 1">
        <n-input v-model:value="deviceData.property1" />
      </n-form-item>
      <n-form-item label="Property 2">
        <n-input v-model:value="deviceData.property2" />
      </n-form-item>
      <n-form-item label="Property 3">
        <n-input v-model:value="deviceData.property3" />
      </n-form-item>
      <n-form-item>
        <n-button type="primary" @click="addDevice">Add</n-button>
      </n-form-item>
    </n-form>
  </n-modal>
</template>
<script lang="ts">
import { defineComponent, reactive } from 'vue';
export default defineComponent({
  name: 'AddDeviceModal',
  props: {
    visible: {
      type: Boolean,
      required: true
    },
    categories: {
      type: Array,
      required: true
    }
  },
  emits: ['update:visible', 'add'],
  setup(props) {
    const deviceData = reactive({
      name: '',
      category: '',
      property1: '',
      property2: '',
      property3: ''
    });
    const addDevice = () => {
      if (!deviceData.name || !deviceData.category) {
        alert('Please fill out all required fields.');
        return;
      }
      console.log('Adding device:', deviceData);
      props.$emit('add', { ...deviceData });
      props.$emit('update:visible', false);
    };
    const categoryOptions = props.categories.map(category => ({ label: category, value: category }));
    return {
      deviceData,
      addDevice,
      categoryOptions
    };
  }
});
</script>App.vue <template>
  <n-layout>
    <Header />
    <n-layout has-sider>
      <Sidebar @select="selectDevice" />
      <n-layout-content>
        <n-card title="Devices">
          <n-button type="success" @click="showAddDeviceModal">Add Device</n-button>
          <DeviceList :devices="filteredDevices" @select="selectDevice" />
        </n-card>
        <DeviceControl :device="selectedDevice" />
        <AddDeviceModal v-model:visible="addDeviceModalVisible" :categories="categories" @add="addDevice" />
      </n-layout-content>
    </n-layout>
  </n-layout>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import Header from './components/Header.vue';
import Sidebar from './components/Sidebar.vue';
import DeviceList from './components/DeviceList.vue';
import DeviceControl from './components/DeviceControl.vue';
import AddDeviceModal from './components/AddDeviceModal.vue';
interface Device {
  id: string;
name: string;
  icon: string;
  category: string;
  property1: string;
  property2: string;
  property3: string;
}
export default defineComponent({
  name: 'App',
  components: { Header, Sidebar, DeviceList, DeviceControl, AddDeviceModal },
  setup() {
    const devices = ref<Device[]>([
      { id: '1', name: 'Device 1', icon: 'https://via.placeholder.com/40', category: 'Category 1', property1: 'value1', property2: 'value2', property3: 'value3' },
      { id: '2', name: 'Device 2', icon: 'https://via.placeholder.com/40', category: 'Category 1', property1: 'value1', property2: 'value2', property3: 'value3' },
      { id: '3', name: 'Device 3', icon: 'https://via.placeholder.com/40', category: 'Category 2', property1: 'value1', property2: 'value2', property3: 'value3' },
      { id: '4', name: 'Device 4', icon: 'https://via.placeholder.com/40', category: 'Category 2', property1: 'value1', property2: 'value2', property3: 'value3' }
    ]);
    const selectedDevice = ref<Device | null>(null);
    const selectedCategory = ref<string>('all');
    const addDeviceModalVisible = ref(false);
    const categories = ref<string[]>(['Category 1', 'Category 2']);
    const filteredDevices = computed(() => {
      if (selectedCategory.value === 'all') {
        return devices.value;
      }
      return devices.value.filter(device => device.category === selectedCategory.value);
    });
    const selectDevice = (device: Device) => {
      selectedDevice.value = device;
    };
    const showAddDeviceModal = () => {
      addDeviceModalVisible.value = true;
    };
    const addDevice = (device: Device) => {
      device.id = String(devices.value.length + 1);
      devices.value.push(device);
      
      if (!categories.value.includes(device.category)) {
        categories.value.push(device.category);
      }
    };
    return {
      devices,
      selectedDevice,
      selectedCategory,
      addDeviceModalVisible,
      categories,
      filteredDevices,
      selectDevice,
      showAddDeviceModal,
      addDevice
    };
  }
});
</script>
<style>
body {
  margin: 0;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
</style> | 
Beta Was this translation helpful? Give feedback.
-
| LogPanel components/Header.vue <template>
  <n-layout-header class="header">
    <n-space align="center" justify="space-between" style="width: 100%">
      <n-space align="center">
        <n-h1>Log Dashboard</n-h1>
      </n-space>
      <n-space>
        <n-select v-model:value="selectedLevel" :options="levelOptions" placeholder="Select Level" clearable />
        <n-input v-model:value="filterText" placeholder="Filter logs..." clearable @clear="onClear" @input="onInput" />
      </n-space>
    </n-space>
  </n-layout-header>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  name: 'Header',
  props: {
    filterText: {
      type: String,
      required: true
    },
    selectedLevel: {
      type: String,
      required: true
    }
  },
  emits: ['update:filterText', 'update:selectedLevel'],
  data() {
    return {
      levelOptions: [
        { label: 'INFO', value: 'INFO' },
        { label: 'WARN', value: 'WARN' },
        { label: 'ERROR', value: 'ERROR' }
      ]
    };
  },
  methods: {
    onClear() {
      this.$emit('update:filterText', '');
    },
    onInput(value: string) {
      this.$emit('update:filterText', value);
    }
  }
});
</script>
<style scoped>
.header {
  background-color: #3eaf7c;
  color: white;
  padding: 0 20px;
}
</style>components/LogTable.vue <template>
  <n-card title="Logs" class="log-table">
    <n-data-table :columns="columns" :data="filteredLogs" />
  </n-card>
</template>
<script lang="ts">
import { defineComponent, computed, h, TransitionGroup } from 'vue';
import { DataTableColumn } from 'naive-ui';
import { LogEntry } from '@/types';
export default defineComponent({
  name: 'LogTable',
  props: {
    logs: {
      type: Array as () => LogEntry[],
      required: true
    },
    filterText: {
      type: String,
      required: true
    },
    selectedLevel: {
      type: String,
      required: true
    }
  },
  emits: ['copy-log'],
  setup(props, { emit }) {
    const columns = computed<DataTableColumn[]>(() => [
      {
        title: 'Timestamp',
        key: 'timestamp',
        align: 'center'
      },
      {
        title: 'Level',
        key: 'level',
        align: 'center'
      },
      {
        title: 'Message',
        key: 'message',
        align: 'left',
        render(rowData) {
          const highlightText = (text: string, highlight: string) => {
            if (!highlight) return text;
            const regex = new RegExp(`(${highlight})`, 'gi');
            return text.replace(regex, '<mark>$1</mark>');
          };
          return h('div', { innerHTML: highlightText(rowData.message, props.filterText) });
        }
      },
      {
        title: 'Action',
        key: 'action',
        align: 'center',
        render(rowData) {
          return h(
            'div',
            [
              h('n-button', {
                text: true,
                onClick: () => {
                  navigator.clipboard.writeText(rowData.message);
                  emit('copy-log', rowData.message);
                }
              }, 'Copy')
            ]
          );
        }
      }
    ]);
    const filteredLogs = computed(() => {
      return props.logs.filter(log => {
        const matchesLevel = props.selectedLevel ? log.level === props.selectedLevel : true;
        const matchesText = props.filterText ? log.message.toLowerCase().includes(props.filterText.toLowerCase()) : true;
        return matchesLevel && matchesText;
      });
    });
    return {
      columns,
      filteredLogs
    };
  }
});
</script>
<style scoped>
.log-table {
  margin: 20px;
}
</style>App.vue <template>
  <n-layout>
    <Header v-model:filterText="filterText" v-model:selectedLevel="selectedLevel" />
    <n-layout-content>
      <LogTable :logs="logs" :filterText="filterText" :selectedLevel="selectedLevel" @copy-log="onCopyLog" />
    </n-layout-content>
  </n-layout>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, onUnmounted } from 'vue';
import Header from './components/Header.vue';
import LogTable from './components/LogTable.vue';
import { LogEntry } from '@/types';
export default defineComponent({
  name: 'App',
  components: { Header, LogTable },
  setup() {
    const filterText = ref<string>('');
    const selectedLevel = ref<string>('');
    const logs = ref<LogEntry[]>([
      { timestamp: '2023-06-01 12:00:00', level: 'INFO', message: 'System started successfully' },
      { timestamp: '2023-06-01 12:05:00', level: 'WARN', message: 'Low disk space' },
      { timestamp: '2023-06-01 12:10:00', level: 'ERROR', message: 'Failed to connect to database' },
      // ... more logs
    ]);
    const fetchLogs = () => {
      // Fetch logs from server and update `logs` state
      // This is a placeholder implementation
      logs.value.push({ timestamp: new Date().toISOString(), level: 'INFO', message: 'New log entry' });
    };
    const onCopyLog = (message: string) => {
      console.log(`Log copied: ${message}`);
    };
    let intervalId: number;
    onMounted(() => {
      intervalId = setInterval(fetchLogs, 5000); // Auto-refresh every 5 seconds
    });
    onUnmounted(() => {
      clearInterval(intervalId);
    });
    return {
      filterText,
      selectedLevel,
      logs,
      onCopyLog
    };
  }
});
</script>
<style>
body {
  margin: 0;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
</style> | 
Beta Was this translation helpful? Give feedback.
-
| #include  enum class ScopeGuardStrategy { template <typename Func, ScopeGuardStrategy Strategy = ScopeGuardStrategy::Always> public: private: template  template  template  template  | 
Beta Was this translation helpful? Give feedback.
-
| #include  class FocusStrategy { class HillClimbingStrategy : public FocusStrategy { }; class BinarySearchStrategy : public FocusStrategy { }; class AutoFocus { public: }; // 模拟从相机获取对焦评分 int main() { } | 
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
这里是一些开发时的想法或者代码片段,仅仅作为心路历程的记录
Beta Was this translation helpful? Give feedback.
All reactions