Skip to content

Commit

Permalink
新增布局、全局插件和路由 (#7)
Browse files Browse the repository at this point in the history
* 新增静态资源和全局组件

Signed-off-by: 25hours886 <[email protected]>
  • Loading branch information
25hours886 authored Sep 29, 2023
1 parent b86ec38 commit 530e106
Show file tree
Hide file tree
Showing 135 changed files with 7,548 additions and 0 deletions.
147 changes: 147 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
const express = require("express")
const fs = require("fs/promises")
const path = require("path")
const cors = require("cors")
const bodyParser = require("body-parser")
const app = express()
const port = 8086

// 设置当前工作目录为与src目录同级的目录
const currentDirectory = path.join(__dirname, "etc/openGemini.conf")

app.use(
cors({
origin: ["http://localhost:3333", "http://192.168.128.1:3333", "http://172.22.49.211:3333"]
})
)

app.use(bodyParser.json()) //使用 body-parser 解析请求体

app.post("/start-server", async (req, res) => {
try {
// 启动服务器的代码
const { spawn } = require("child_process")
const serverProcess = spawn("node", ["server.js"])

serverProcess.stdout.on("data", (data) => {
console.log(`Server stdout: ${data}`)
})

serverProcess.stderr.on("data", (data) => {
console.error(`Server stderr: ${data}`)
})

serverProcess.on("close", (code) => {
console.log(`Server process exited with code ${code}`)
})

res.status(200).json({ success: true, message: "Server started successfully." })
} catch (error) {
res.status(500).json({ success: false, error: error.message })
}
})

app.get("/get-config-file-content", async (req, res) => {
try {
// 在这里编写代码以读取配置文件的内容
const configFileContent = await fs.readFile(currentDirectory, "utf-8")
res.send(configFileContent)
} catch (error) {
res.status(500).json({ success: false, error: error.message })
}
})

app.post("/save-config-file-content", async (req, res) => {
try {
const {
metaJoinInCommon1,
metaJoinInCommon2,
metaJoinInCommon3,

bindAddressInMeta,
httpBindAddressInMeta,
rpcBindAddressInMeta,
dirInMeta,

bindAddressInHttp,

storeIngestAddrInData,
storeSelectAddrInData,
storeDataDirInData,
storeWalDirInData,
storeMetaDirInData,

bindAddressInGossip,
storeBindPortInGossip,
metaBindPortInGossip,
membersInGossip1,
membersInGossip2,
membersInGossip3
} = req.body

//读配置文件内容
const contentInCommon = await fs.readFile(currentDirectory, "utf-8")

const updatedConfigInCommon = contentInCommon.replace(
/(\[common\][\s\S]*?meta-join\s*=\s*\[")([^"]*)(",\s*")([^"]*)(",\s*")([^"]*)("\])/,
(match, group1, group2, group3, group4, group5, group6, group7) =>
`${group1}${metaJoinInCommon1}${group3}${metaJoinInCommon2}${group5}${metaJoinInCommon3}${group7}`
)
//将更新后的配置写回文件
await fs.writeFile(currentDirectory, updatedConfigInCommon, "utf-8")

const contentInMeta = await fs.readFile(currentDirectory, "utf-8")
const updatedConfigInMeta = contentInMeta.replace(
/(\[meta\][\s\S]*?bind-address\s*=\s*")([^"]*)("\s*http-bind-address\s*=\s*")([^"]*)("\s*rpc-bind-address\s*=\s*")([^"]*)("\s*dir\s*=\s*")([^"]*)(")/,
(match, group1, group2, group3, group4, group5, group6, group7, group8, group9) =>
`${group1}${bindAddressInMeta}${group3}${httpBindAddressInMeta}${group5}${rpcBindAddressInMeta}${group7}${dirInMeta}${group9}`
)
await fs.writeFile(currentDirectory, updatedConfigInMeta, "utf-8")

const contentInHttp = await fs.readFile(currentDirectory, "utf-8")
const updatedConfigInHttp = contentInHttp.replace(
/(\[http\][\s\S]*?bind-address\s*=\s*")([^"]*)(")/,
(match, group1, group2, group3) => `${group1}${bindAddressInHttp}${group3}`
)
await fs.writeFile(currentDirectory, updatedConfigInHttp, "utf-8")

const contentInData = await fs.readFile(currentDirectory, "utf-8")
const updatedConfigInData = contentInData.replace(
/(\[data\][\s\S]*?store-ingest-addr\s*=\s*")([^"]*)("\s*store-select-addr\s*=\s*")([^"]*)("\s*store-data-dir\s*=\s*")([^"]*)("\s*store-wal-dir\s*=\s*")([^"]*)("\s*store-meta-dir\s*=\s*")([^"]*)(")/,
(match, group1, group2, group3, group4, group5, group6, group7, group8, group9, group10, group11) =>
`${group1}${storeIngestAddrInData}${group3}${storeSelectAddrInData}${group5}${storeDataDirInData}${group7}${storeWalDirInData}${group9}${storeMetaDirInData}${group11}`
)
await fs.writeFile(currentDirectory, updatedConfigInData, "utf-8")

const contentInGossip = await fs.readFile(currentDirectory, "utf-8")
const updatedConfigInGossip = contentInGossip.replace(
/(\[gossip\][\s\S]*?bind-address\s*=\s*")([^"]*)("\s*store-bind-port\s*=\s*)(\S*)(\s*meta-bind-port\s*=\s*)(\S*)([\s\S]*?members\s*=\s*\[")([^"]*)(",\s*")([^"]*)(",\s*")([^"]*)("\])/,
(
match,
group1,
group2,
group3,
group4,
group5,
group6,
group7,
group8,
group9,
group10,
group11,
group12,
group13
) =>
`${group1}${bindAddressInGossip}${group3}${storeBindPortInGossip}${group5}${metaBindPortInGossip}${group7}${membersInGossip1}${group9}${membersInGossip2}${group11}${membersInGossip3}${group13}`
)
await fs.writeFile(currentDirectory, updatedConfigInGossip, "utf-8")

res.status(200).json({ success: true, message: "Configuration file([meta]) saved successfully" })
} catch (error) {
res.status(500).json({ success: false, error: error.message })
}
})

app.listen(port, () => {
console.log(`Server is listening at http://localhost:${port}`)
})
16 changes: 16 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<script lang="ts" setup>
import { useTheme } from "@/hooks/useTheme"
// 将 Element Plus 的语言设置为中文
import zhCn from "element-plus/es/locale/lang/zh-cn"
const { initTheme } = useTheme()
/** 初始化主题 */
initTheme()
</script>

<template>
<el-config-provider :locale="zhCn">
<router-view />
</el-config-provider>
</template>
27 changes: 27 additions & 0 deletions src/api/login/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { request } from "@/utils/service"
import type * as Login from "./types/login"

/** 获取登录验证码 */
export function getLoginCodeApi() {
return request<Login.LoginCodeResponseData>({
url: "login/code",
method: "get"
})
}

/** 登录并返回 Token */
export function loginApi(data: Login.LoginRequestData) {
return request<Login.LoginResponseData>({
url: "users/login",
method: "post",
data
})
}

/** 获取用户详情 */
export function getUserInfoApi() {
return request<Login.UserInfoResponseData>({
url: "users/info",
method: "get"
})
}
2 changes: 2 additions & 0 deletions src/api/login/types/login.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions src/api/login/types/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface LoginRequestData {
/** admin 或 editor */
username: "admin" | "editor"
/** 密码 */
password: string
/** 验证码 */
code: string
}

export type LoginCodeResponseData = ApiResponseData<string>

export type LoginResponseData = ApiResponseData<{ token: string }>

export type UserInfoResponseData = ApiResponseData<{ username: string; roles: string[] }>
37 changes: 37 additions & 0 deletions src/api/table/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { request } from "@/utils/service"
import type * as Table from "./types/table"

/** 增 */
export function createTableDataApi(data: Table.CreateTableRequestData) {
return request({
url: "table",
method: "post",
data
})
}

/** 删 */
export function deleteTableDataApi(id: string) {
return request({
url: `table/${id}`,
method: "delete"
})
}

/** 改 */
export function updateTableDataApi(data: Table.UpdateTableRequestData) {
return request({
url: "table",
method: "put",
data
})
}

/** 查 */
export function getTableDataApi(params: Table.GetTableRequestData) {
return request<Table.GetTableResponseData>({
url: "table",
method: "get",
params
})
}
36 changes: 36 additions & 0 deletions src/api/table/types/table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export interface CreateTableRequestData {
username: string
password: string
}

export interface UpdateTableRequestData {
id: string
username: string
password?: string
}

export interface GetTableRequestData {
/** 当前页码 */
currentPage: number
/** 查询条数 */
size: number
/** 查询参数:用户名 */
username?: string
/** 查询参数:手机号 */
phone?: string
}

export interface GetTableData {
createTime: string
email: string
id: string
phone: string
roles: string
status: boolean
username: string
}

export type GetTableResponseData = ApiResponseData<{
list: GetTableData[]
total: number
}>
1 change: 1 addition & 0 deletions src/assets/error-page/403.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/error-page/404.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/layouts/logo-text-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/layouts/logo-text-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/layouts/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
92 changes: 92 additions & 0 deletions src/components/Screenfull/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<script lang="ts" setup>
import { computed, ref, watchEffect } from "vue"
import { ElMessage } from "element-plus"
import screenfull from "screenfull"
interface Props {
/** 全屏的元素,默认是 html */
element?: string
/** 打开全屏提示语 */
openTips?: string
/** 关闭全屏提示语 */
exitTips?: string
/** 是否只针对内容区 */
content?: boolean
}
const props = withDefaults(defineProps<Props>(), {
element: "html",
openTips: "全屏",
exitTips: "退出全屏",
content: false
})
//#region 全屏
const isFullscreen = ref<boolean>(false)
const fullscreenTips = computed(() => {
return isFullscreen.value ? props.exitTips : props.openTips
})
const fullscreenSvgName = computed(() => {
return isFullscreen.value ? "fullscreen-exit" : "fullscreen"
})
const handleFullscreenClick = () => {
const dom = document.querySelector(props.element) || undefined
screenfull.isEnabled ? screenfull.toggle(dom) : ElMessage.warning("您的浏览器无法工作")
}
const handleFullscreenChange = () => {
isFullscreen.value = screenfull.isFullscreen
}
watchEffect((onCleanup) => {
// 挂载组件时自动执行
screenfull.on("change", handleFullscreenChange)
// 卸载组件时自动执行
onCleanup(() => {
screenfull.isEnabled && screenfull.off("change", handleFullscreenChange)
})
})
//#endregion
//#region 内容区
const isContentLarge = ref<boolean>(false)
const contentLargeTips = computed(() => {
return isContentLarge.value ? "内容区复原" : "内容区放大"
})
const contentLargeSvgName = computed(() => {
return isContentLarge.value ? "fullscreen-exit" : "fullscreen"
})
const handleContentLargeClick = () => {
document.body.className = !isContentLarge.value ? "content-large" : ""
isContentLarge.value = !isContentLarge.value
}
//#endregion
</script>

<template>
<div>
<!-- 全屏 -->
<el-tooltip v-if="!content" effect="dark" :content="fullscreenTips" placement="bottom">
<SvgIcon :name="fullscreenSvgName" @click="handleFullscreenClick" />
</el-tooltip>
<!-- 内容区 -->
<el-dropdown v-else>
<SvgIcon :name="contentLargeSvgName" />
<template #dropdown>
<el-dropdown-menu>
<!-- 内容区放大 -->
<el-dropdown-item @click="handleContentLargeClick">{{ contentLargeTips }}</el-dropdown-item>
<!-- 内容区全屏 -->
<el-dropdown-item @click="handleFullscreenClick" :disabled="isFullscreen">内容区全屏</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>

<style lang="scss" scoped>
.svg-icon {
font-size: 20px;
&:focus {
outline: none;
}
}
</style>
Loading

0 comments on commit 530e106

Please sign in to comment.